2890 lines
69 KiB
C
2890 lines
69 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/seq_file.h>
|
|
#include <drm/drm_atomic.h>
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_atomic_uapi.h>
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_modeset_lock.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include "meson_sysfs.h"
|
|
#include "meson_crtc.h"
|
|
#include "meson_plane.h"
|
|
#include "meson_hdmi.h"
|
|
#include "meson_vpu_pipeline.h"
|
|
#include "meson_gem.h"
|
|
|
|
static const char vpu_group_name[] = "vpu";
|
|
static const char module_param_group_name[] = "module_param";
|
|
static const char osd0_group_name[] = "osd0";
|
|
static const char osd1_group_name[] = "osd1";
|
|
static const char osd2_group_name[] = "osd2";
|
|
static const char osd3_group_name[] = "osd3";
|
|
static const char osd4_group_name[] = "osd4";
|
|
int osd_index[MESON_MAX_OSDS] = {0, 1, 2, 3, 4};
|
|
static const char video0_group_name[] = "video0";
|
|
static const char video1_group_name[] = "video1";
|
|
static const char video2_group_name[] = "video2";
|
|
int video_index[MESON_MAX_VIDEOS] = {0, 1, 2};
|
|
static const char crtc0_group_name[] = "crtc0";
|
|
static const char crtc1_group_name[] = "crtc1";
|
|
static const char crtc2_group_name[] = "crtc2";
|
|
int crtc_index[MESON_MAX_POSTBLEND] = {0, 1, 2};
|
|
u32 pages;
|
|
u32 *overwrite_reg;
|
|
u32 *overwrite_val;
|
|
u8 *overwrite_crtc_idx;
|
|
int overwrite_enable;
|
|
int reg_num;
|
|
|
|
#define AM_BIN_ATTR_MOD_PARAM_W_DEF(_name) \
|
|
static ssize_t _name##_store(struct file *filp, struct kobject *kobj, \
|
|
struct bin_attribute *attr, char *buf, loff_t off, \
|
|
size_t count) \
|
|
{\
|
|
struct device *dev = kobj_to_dev(kobj); \
|
|
struct drm_minor *minor = dev_get_drvdata(dev); \
|
|
struct meson_drm *priv; \
|
|
int val; \
|
|
\
|
|
if (!minor || !minor->dev) \
|
|
return -EINVAL; \
|
|
\
|
|
priv = minor->dev->dev_private; \
|
|
\
|
|
if (kstrtouint(buf, 10, &val) < 0) \
|
|
return -EINVAL; \
|
|
\
|
|
am_drm_param._name = val; \
|
|
\
|
|
return count; \
|
|
}
|
|
|
|
#define AM_BIN_ATTR_MOD_PARAM_R_DEF(_name) \
|
|
static ssize_t _name##_show(struct file *filp, struct kobject *kobj, \
|
|
struct bin_attribute *attr, char *buf, loff_t off, \
|
|
size_t count) \
|
|
{\
|
|
struct device *dev = kobj_to_dev(kobj); \
|
|
struct drm_minor *minor = dev_get_drvdata(dev); \
|
|
struct meson_drm *priv; \
|
|
int pos = 0; \
|
|
\
|
|
if (!minor || !minor->dev) \
|
|
return -EINVAL; \
|
|
if (off > 0) \
|
|
return 0; \
|
|
\
|
|
priv = minor->dev->dev_private; \
|
|
\
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,\
|
|
__stringify(_name) ": %d\n", am_drm_param._name); \
|
|
\
|
|
return pos;\
|
|
}
|
|
|
|
#define _AM_BIN_ATTR(_name, _mode, _show, _store) \
|
|
{\
|
|
.attr = { .name = __stringify(_name), .mode = _mode },\
|
|
.read = _show, \
|
|
.write = _store, \
|
|
},
|
|
|
|
#define AM_BIN_ATTR_MOD_PARAM_RW(_name) \
|
|
_AM_BIN_ATTR(_name, 0644, _name##_show, _name##_store)
|
|
|
|
//EXPORT_SYMBOL_GPL(vpu_group_name);
|
|
|
|
static void am_meson_drm_unmap_phyaddr(u8 *vaddr)
|
|
{
|
|
void *addr = (void *)(PAGE_MASK & (ulong)vaddr);
|
|
|
|
DRM_DEBUG("unmap va(%p)\n", addr);
|
|
vunmap(addr);
|
|
}
|
|
|
|
static void parse_param(char *buf_orig, char **parm)
|
|
{
|
|
char *ps, *token;
|
|
unsigned int n = 0;
|
|
char delim1[3] = " ";
|
|
char delim2[2] = "\n";
|
|
|
|
ps = buf_orig;
|
|
strcat(delim1, delim2);
|
|
while (1) {
|
|
token = strsep(&ps, delim1);
|
|
if (!token)
|
|
break;
|
|
if (*token == '\0')
|
|
continue;
|
|
parm[n++] = token;
|
|
}
|
|
}
|
|
|
|
int init_overwrite(struct device *dev)
|
|
{
|
|
if (!overwrite_reg)
|
|
overwrite_reg = devm_kcalloc(dev, sizeof(u32),
|
|
MESON_MAX_OVERWRITE_REG, GFP_KERNEL);
|
|
|
|
if (!overwrite_val)
|
|
overwrite_val = devm_kcalloc(dev, sizeof(u32),
|
|
MESON_MAX_OVERWRITE_REG, GFP_KERNEL);
|
|
|
|
if (!overwrite_crtc_idx)
|
|
overwrite_crtc_idx = devm_kcalloc(dev, sizeof(u8),
|
|
MESON_MAX_OVERWRITE_REG, GFP_KERNEL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t debug_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int i, pos = 0;
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo rv reg > debug to read the register\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo wv reg val > debug to overwrite the register\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo wv reg val crtc_idx > debug to overwrite the reg on crtc\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo wvb reg val start lens > debug to overwrite the specific bits in register\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo ow 1 > debug to enable overwrite register\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"\noverwrote status: %s\n", overwrite_enable ? "on" : "off");
|
|
|
|
if (overwrite_enable) {
|
|
init_overwrite(dev);
|
|
|
|
for (i = 0; i < reg_num; i++)
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"reg[0x%04x]=0x%08x,crtc_idx:%d\n", overwrite_reg[i], overwrite_val[i],
|
|
overwrite_crtc_idx[i]);
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t debug_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t n)
|
|
{
|
|
char dst_buf[64];
|
|
long val;
|
|
int i;
|
|
unsigned int reg_addr, reg_val, crtc_idx = 0, tmp_val, read_val, start, len;
|
|
char *bufp, *parm[8] = {NULL};
|
|
int lens = strlen(buf);
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
if (strcmp(parm[0], "rv"))
|
|
init_overwrite(dev);
|
|
|
|
if (!strcmp(parm[0], "rv")) {
|
|
if (kstrtoul(parm[1], 16, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
reg_addr = val;
|
|
DRM_INFO("reg[0x%04x]=0x%08x\n", reg_addr, meson_drm_read_reg(reg_addr));
|
|
} else if (!strcmp(parm[0], "wv")) {
|
|
if (kstrtoul(parm[1], 16, &val) < 0)
|
|
return -EINVAL;
|
|
reg_addr = val;
|
|
|
|
if (kstrtoul(parm[2], 16, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
reg_val = val;
|
|
|
|
/*
|
|
* optional crtc index parameter
|
|
* default value: 0
|
|
*/
|
|
if (parm[3]) {
|
|
if (kstrtoul(parm[3], 16, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
crtc_idx = val;
|
|
if (crtc_idx >= MESON_MAX_CRTC) {
|
|
DRM_INFO("Invalid crtc index! Use default 0\n");
|
|
crtc_idx = 0;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < reg_num; i++) {
|
|
if (overwrite_reg[i] == reg_addr) {
|
|
overwrite_val[i] = reg_val;
|
|
overwrite_crtc_idx[i] = crtc_idx;
|
|
return lens;
|
|
}
|
|
}
|
|
|
|
if (i == reg_num) {
|
|
overwrite_reg[i] = reg_addr;
|
|
overwrite_val[i] = reg_val;
|
|
overwrite_crtc_idx[i] = crtc_idx;
|
|
reg_num++;
|
|
}
|
|
} else if (!strcmp(parm[0], "ow")) {
|
|
if (parm[1] && !strcmp(parm[1], "1")) {
|
|
overwrite_enable = 1;
|
|
} else if (parm[1] && !strcmp(parm[1], "0")) {
|
|
overwrite_enable = 0;
|
|
for (i = 0; i < reg_num; i++) {
|
|
overwrite_val[i] = 0;
|
|
overwrite_val[i] = 0;
|
|
overwrite_crtc_idx[i] = 0;
|
|
}
|
|
reg_num = 0;
|
|
}
|
|
} else if (!strcmp(parm[0], "wvb")) {
|
|
if (kstrtoul(parm[1], 16, &val) < 0)
|
|
return -EINVAL;
|
|
reg_addr = val;
|
|
|
|
if (kstrtouint(parm[2], 10, &tmp_val) < 0)
|
|
return -EINVAL;
|
|
if (kstrtouint(parm[3], 10, &start) < 0)
|
|
return -EINVAL;
|
|
if (kstrtouint(parm[4], 10, &len) < 0)
|
|
return -EINVAL;
|
|
|
|
read_val = meson_drm_read_reg(reg_addr);
|
|
reg_val = (read_val & ~(((1L << (len)) - 1) << (start))) |
|
|
((unsigned int)(tmp_val) << (start));
|
|
|
|
for (i = 0; i < reg_num; i++) {
|
|
if (overwrite_reg[i] == reg_addr) {
|
|
overwrite_val[i] = reg_val;
|
|
return lens;
|
|
}
|
|
}
|
|
|
|
if (i == reg_num) {
|
|
overwrite_reg[i] = reg_addr;
|
|
overwrite_val[i] = reg_val;
|
|
reg_num++;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(debug);
|
|
|
|
static struct attribute *vpu_attrs[] = {
|
|
&dev_attr_debug.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group vpu_attr_group = {
|
|
.name = vpu_group_name,
|
|
.attrs = vpu_attrs,
|
|
};
|
|
|
|
static int meson_drm_trigger_atomic_commit(struct drm_minor *minor)
|
|
{
|
|
struct drm_modeset_acquire_ctx ctx;
|
|
struct drm_atomic_state *state = ERR_PTR(-EINVAL);
|
|
struct drm_device *dev;
|
|
int err;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
dev = minor->dev;
|
|
|
|
DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
|
|
state = drm_atomic_helper_duplicate_state(dev, &ctx);
|
|
if (IS_ERR(state))
|
|
return -EFAULT;
|
|
err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
|
|
DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
|
|
if (IS_ERR(state))
|
|
return -EFAULT;
|
|
drm_atomic_state_put(state);
|
|
|
|
return err;
|
|
}
|
|
|
|
static ssize_t osd_pixel_blend_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"cat pixel_blend to show blend mask\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo <value> > pixel_blend to set blend mask\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"pixel blend mask: 0x%x\n", amp->pixel_blend_debug);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_pixel_blend_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int idx = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[idx];
|
|
|
|
if (kstrtou16(buf, 16, &->pixel_blend_debug) < 0)
|
|
return -EINVAL;
|
|
|
|
DRM_INFO("Set pixel blend mask to %s\n", buf);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_reverse_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1/2/3 > osd_reverse :reverse the osd xy/x/y\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > osd_reverse to un_reverse the osd plane\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd_reverse: %d\n", amp->osd_reverse);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_reverse_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int idx = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
int ret;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[idx];
|
|
|
|
if (sysfs_streq(buf, "0")) {
|
|
amp->osd_reverse = 0;
|
|
DRM_INFO("disable the osd reverse\n");
|
|
} else if (sysfs_streq(buf, "1")) {
|
|
amp->osd_reverse = DRM_MODE_REFLECT_MASK;
|
|
DRM_INFO("enable the osd reverse\n");
|
|
} else if (sysfs_streq(buf, "2")) {
|
|
amp->osd_reverse = DRM_MODE_REFLECT_X;
|
|
DRM_INFO("enable the osd reverse_x\n");
|
|
} else if (sysfs_streq(buf, "3")) {
|
|
amp->osd_reverse = DRM_MODE_REFLECT_Y;
|
|
DRM_INFO("enable the osd reverse_y\n");
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_blend_bypass_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1/0 > osd_blend_bypass :enable/disable\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd_blend_bypass: %d\n", amp->osd_blend_bypass);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_blend_bypass_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
if (sysfs_streq(buf, "1")) {
|
|
amp->osd_blend_bypass = 1;
|
|
DRM_INFO("enable the osd blend bypass\n");
|
|
} else if (sysfs_streq(buf, "0")) {
|
|
amp->osd_blend_bypass = 0;
|
|
DRM_INFO("disable the osd blend bypass\n");
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_read_port_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > enable read port setting\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > disable read port setting\n");
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"\nstatus: %d\n", (amp->osd_read_ports == 1) ? 1 : 0);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_read_port_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
long val;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amp = priv->osd_planes[*(int *)attr->private];
|
|
|
|
if (kstrtoul(buf, 16, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
val = val >= 1 ? 1 : 0;
|
|
amp->osd_read_ports = val;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_fbdump_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
struct am_osd_plane *amp;
|
|
bool bflg;
|
|
int crtc_index;
|
|
u32 fb_size;
|
|
u32 index;
|
|
u32 num_pages;
|
|
void *vir_addr;
|
|
u64 phy_addr;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
index = *(int *)attr->private;
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
amp = priv->osd_planes[index];
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[index];
|
|
if (!info->enable) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
phy_addr = info->phy_addr;
|
|
fb_size = info->fb_size;
|
|
bflg = false;
|
|
if (pages == 0 && off < fb_size) {
|
|
vir_addr = am_meson_drm_vmap(phy_addr, fb_size, &bflg);
|
|
amp->bflg = bflg;
|
|
amp->vir_addr = vir_addr;
|
|
amp->dump_size = fb_size;
|
|
}
|
|
if (!amp->vir_addr) {
|
|
DRM_INFO("vmap failed, vir_addr is null\n");
|
|
return -EINVAL;
|
|
}
|
|
num_pages = PAGE_ALIGN(amp->dump_size) / PAGE_SIZE;
|
|
pages++;
|
|
|
|
if (pages <= num_pages && off < amp->dump_size) {
|
|
memcpy(buf, amp->vir_addr + off, count);
|
|
if (pages == num_pages && amp->bflg)
|
|
am_meson_drm_unmap_phyaddr(amp->vir_addr);
|
|
return count;
|
|
}
|
|
|
|
if (off >= amp->dump_size)
|
|
pages = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t osd_fbdump_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_blank_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int osd_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > enable osd-%d blank\n", *(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > disable osd-%d blank\n", *(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d blank status is %d\n", *(int *)attr->private,
|
|
priv->osd_planes[osd_index]->osd_permanent_blank);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_blank_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
int ret;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (buf[0] == '1') {
|
|
priv->osd_planes[osd_index]->osd_permanent_blank = 1;
|
|
DRM_INFO("osd-%d enable blank\n", osd_index);
|
|
} else if (buf[0] == '0') {
|
|
priv->osd_planes[osd_index]->osd_permanent_blank = 0;
|
|
DRM_INFO("osd-%d disable blank\n", osd_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_resize_src_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int osd_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo src_x src_y src_w src_h > resize_source to enable osd-%d resize src\n",
|
|
osd_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo -1 -1 -1 -1 > resize_source to disable osd-%d resize src\n", osd_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_resize_src_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
unsigned int src_x, src_y, src_w, src_h;
|
|
char dst_buf[64];
|
|
char *bufp, *parm[8] = {NULL};
|
|
int ret;
|
|
int lens = strlen(buf);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (!(parm[0] && parm[1] && parm[2] && parm[3])) {
|
|
DRM_INFO("%s, parameters is incorrect.\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtoint(parm[0], 10, &src_x) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[1], 10, &src_y) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[2], 10, &src_w) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[3], 10, &src_h) < 0)
|
|
return -EINVAL;
|
|
|
|
priv->osd_planes[osd_index]->adjust_src.x1 = src_x;
|
|
priv->osd_planes[osd_index]->adjust_src.y1 = src_y;
|
|
priv->osd_planes[osd_index]->adjust_src.x2 = src_w;
|
|
priv->osd_planes[osd_index]->adjust_src.y2 = src_h;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_zorder_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int crtc_index;
|
|
u32 index;
|
|
int pos = 0;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
index = *(int *)attr->private;
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[index];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d zorder is %d\n", *(int *)attr->private, info->zorder);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_zorder_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
int new_zorder;
|
|
char dst_buf[64];
|
|
char *bufp, *parm[8] = {NULL};
|
|
int ret;
|
|
int lens = strlen(buf);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (!parm[0]) {
|
|
DRM_INFO("%s, parameters is incorrect.\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtouint(parm[0], 10, &new_zorder) < 0)
|
|
return -EINVAL;
|
|
|
|
priv->osd_planes[osd_index]->zorder = new_zorder;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_gfcd_hskip_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int osd_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
int crtc_index;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[osd_index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[osd_index];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > gfcd_hskip to enable osd-%d gfcd hskip\n",
|
|
osd_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > gfcd_hskip to disable osd-%d gfcd hskip\n", osd_index);
|
|
if (info->process_unit == GFCD_AFBC || info->process_unit == GFCD_AFRC)
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d gfcd enabled\n", osd_index);
|
|
else
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d gfcd disabled\n", osd_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_gfcd_hskip_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
int crtc_index;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[osd_index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd-%d: crtc is disconnected, cannot set gfcd skip\n",
|
|
osd_index);
|
|
return -ENODEV;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[osd_index];
|
|
|
|
if (buf[0] == '1') {
|
|
info->gfcd_hskip = 1;
|
|
DRM_INFO("osd-%d enable gfcd hskip\n", osd_index);
|
|
} else if (buf[0] == '0') {
|
|
info->gfcd_hskip = 0;
|
|
DRM_INFO("osd-%d disable gfcd hskip\n", osd_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_gfcd_vskip_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int osd_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
int crtc_index;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[osd_index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[osd_index];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > gfcd_vskip to enable osd-%d gfcd vskip\n",
|
|
osd_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > gfcd_vskip to disable osd-%d gfcd vskip\n", osd_index);
|
|
if (info->process_unit == GFCD_AFBC || info->process_unit == GFCD_AFRC)
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d gfcd enabled\n", osd_index);
|
|
else
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d gfcd disabled\n", osd_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_gfcd_vskip_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
int crtc_index;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[osd_index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd-%d: crtc is disconnected, cannot set gfcd skip\n",
|
|
osd_index);
|
|
return -ENODEV;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[osd_index];
|
|
|
|
if (buf[0] == '1') {
|
|
info->gfcd_vskip = 1;
|
|
DRM_INFO("osd-%d enable gfcd vskip\n", osd_index);
|
|
} else if (buf[0] == '0') {
|
|
info->gfcd_vskip = 0;
|
|
DRM_INFO("osd-%d disable gfcd vskip\n", osd_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_resize_dst_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int osd_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo dst_x dst_y dst_w dst_h > resize_destination to enable osd-%d resize dst\n",
|
|
osd_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo -1 -1 -1 -1 > resize_destination to disable osd-%d resize dst\n", osd_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_resize_dst_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
unsigned int dst_x, dst_y, dst_w, dst_h;
|
|
char dst_buf[64];
|
|
char *bufp, *parm[8] = {NULL};
|
|
int ret;
|
|
int lens = strlen(buf);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (!(parm[0] && parm[1] && parm[2] && parm[3])) {
|
|
DRM_INFO("%s, parameters is incorrect.\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtoint(parm[0], 10, &dst_x) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[1], 10, &dst_y) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[2], 10, &dst_w) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[3], 10, &dst_h) < 0)
|
|
return -EINVAL;
|
|
|
|
priv->osd_planes[osd_index]->adjust_dst.x1 = dst_x;
|
|
priv->osd_planes[osd_index]->adjust_dst.y1 = dst_y;
|
|
priv->osd_planes[osd_index]->adjust_dst.x2 = dst_w;
|
|
priv->osd_planes[osd_index]->adjust_dst.y2 = dst_h;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("ailed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t osd_dimm_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int crtc_index;
|
|
u32 index;
|
|
int pos = 0;
|
|
struct meson_vpu_osd_layer_info *info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
index = *(int *)attr->private;
|
|
priv = minor->dev->dev_private;
|
|
crtc_index = priv->pipeline->osd_crtc_index[index];
|
|
if (crtc_index == -1) {
|
|
DRM_INFO("osd is disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
mvps = priv_to_sub_pipeline_state(priv->pipeline->subs[crtc_index]->obj.state);
|
|
info = &mvps->plane_info[index];
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0x7ff00000 > osd_dimm to set osd-%d red dimm\n",
|
|
*(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0x400ffc00 > osd_dimm to set osd-%d green dimm\n",
|
|
*(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0x400003ff > osd_dimm to set osd-%d blue dimm\n",
|
|
*(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0x0 > osd_dimm to clear osd-%d dimm\n",
|
|
*(int *)attr->private);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"osd-%d current dimm flag %d value 0x%x\n",
|
|
*(int *)attr->private, info->osd_dimm.dimm_ctrl, info->osd_dimm.dimm_value);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t osd_dimm_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int osd_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
long osd_dimm;
|
|
int ret;
|
|
|
|
DRM_INFO("dimm IN!\n");
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (!buf[0]) {
|
|
DRM_ERROR("parameters is incorrect.\n");
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtoul(buf, 16, &osd_dimm) < 0) {
|
|
DRM_ERROR("osd-%d: invalid value\n", osd_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
priv = minor->dev->dev_private;
|
|
if (!priv) {
|
|
DRM_ERROR("priv is null\n");
|
|
return -EINVAL;
|
|
}
|
|
priv->osd_planes[osd_index]->osd_dimm.dimm_value = osd_dimm;
|
|
priv->osd_planes[osd_index]->osd_dimm.dimm_ctrl = 2;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t state_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_print_iterator iter;
|
|
struct drm_printer p;
|
|
ssize_t ret;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -ENODEV;
|
|
|
|
iter.data = buf;
|
|
iter.start = off;
|
|
iter.remain = count;
|
|
|
|
p = drm_coredump_printer(&iter);
|
|
drm_state_dump(minor->dev, &p);
|
|
ret = count - iter.remain;
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t reg_dump_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_print_iterator iter;
|
|
struct drm_printer p;
|
|
struct meson_drm *priv;
|
|
struct am_meson_crtc *amc;
|
|
struct meson_vpu_pipeline *mvp1;
|
|
struct meson_vpu_block *mvb;
|
|
int i;
|
|
ssize_t ret;
|
|
|
|
iter.data = buf;
|
|
iter.start = off;
|
|
iter.remain = count;
|
|
|
|
p = drm_coredump_printer(&iter);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
priv = minor->dev->dev_private;
|
|
amc = priv->crtcs[0];
|
|
mvp1 = amc->pipeline;
|
|
|
|
for (i = 0; i < MESON_MAX_BLOCKS; i++) {
|
|
mvb = mvp1->mvbs[i];
|
|
if (!mvb)
|
|
continue;
|
|
|
|
drm_printf(&p, "*************%s*************\n", mvb->name);
|
|
if (mvb->ops && mvb->ops->dump_register)
|
|
mvb->ops->dump_register(&p, mvb);
|
|
}
|
|
ret = count - iter.remain;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t crtc_blank_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *amc;
|
|
int crtc_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
amc = to_am_meson_crtc(crtc);
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > crtc_blank enable crtc-%d blank\n", crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > crtc_blank disable crtc-%d blank\n", crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"crtc-%d blank status is %d\n", crtc_index,
|
|
amc->blank_enable);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t crtc_blank_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *amc;
|
|
int crtc_index = *(int *)attr->private;
|
|
int ret;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
amc = to_am_meson_crtc(crtc);
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
if (buf[0] == '1') {
|
|
amc->blank_enable = 1;
|
|
DRM_INFO("crtc-%d enable blank\n", crtc_index);
|
|
} else if (buf[0] == '0') {
|
|
amc->blank_enable = 0;
|
|
DRM_INFO("crtc-%d disable blank\n", crtc_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
struct drm_atomic_state *
|
|
meson_drm_duplicate_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx,
|
|
struct drm_crtc *dst_crtc, struct drm_connector *dst_conn,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
struct drm_atomic_state *state;
|
|
struct drm_connector *conn;
|
|
struct drm_connector_state *conn_state;
|
|
struct drm_connector_list_iter conn_iter;
|
|
struct drm_plane *plane;
|
|
struct drm_plane_state *plane_state;
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc_state *crtc_state;
|
|
int hdisplay, vdisplay;
|
|
int ret, err = 0;
|
|
|
|
state = drm_atomic_state_alloc(dev);
|
|
if (!state)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
state->acquire_ctx = ctx;
|
|
state->duplicated = true;
|
|
|
|
drm_for_each_crtc(crtc, dev) {
|
|
if (crtc != dst_crtc)
|
|
continue;
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
if (IS_ERR(crtc_state)) {
|
|
DRM_ERROR("%d, get_crtc_state error\n", __LINE__);
|
|
err = PTR_ERR(crtc_state);
|
|
goto free;
|
|
}
|
|
|
|
ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
|
|
if (ret != 0) {
|
|
DRM_ERROR("%d, set_mode_for_crtc error\n", __LINE__);
|
|
goto free;
|
|
}
|
|
crtc_state->active = true;
|
|
}
|
|
|
|
drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
|
|
|
|
drm_for_each_plane(plane, dev) {
|
|
plane_state = drm_atomic_get_plane_state(state, plane);
|
|
if (IS_ERR(plane_state)) {
|
|
err = PTR_ERR(plane_state);
|
|
DRM_ERROR("%d, get_plane_state error\n", __LINE__);
|
|
goto free;
|
|
}
|
|
plane_state->crtc_x = 0;
|
|
plane_state->crtc_y = 0;
|
|
plane_state->crtc_w = hdisplay;
|
|
plane_state->crtc_h = vdisplay;
|
|
}
|
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
drm_for_each_connector_iter(conn, &conn_iter) {
|
|
if (conn != dst_conn)
|
|
continue;
|
|
|
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
if (IS_ERR(conn_state)) {
|
|
err = PTR_ERR(conn_state);
|
|
drm_connector_list_iter_end(&conn_iter);
|
|
DRM_ERROR("%d, get_conn_state error\n", __LINE__);
|
|
goto free;
|
|
}
|
|
ret = drm_atomic_set_crtc_for_connector(conn_state, dst_crtc);
|
|
if (ret != 0) {
|
|
DRM_ERROR("%d, set_crtc_for_connector error\n", __LINE__);
|
|
goto free;
|
|
}
|
|
}
|
|
drm_connector_list_iter_end(&conn_iter);
|
|
|
|
/* clear the acquire context so that it isn't accidentally reused */
|
|
state->acquire_ctx = NULL;
|
|
|
|
free:
|
|
if (err < 0) {
|
|
drm_atomic_state_put(state);
|
|
state = ERR_PTR(err);
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
static ssize_t crtc_mode_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
int found, num_modes, ret = 0;
|
|
char mode_name[DRM_DISPLAY_MODE_LEN];
|
|
struct drm_display_mode *mode = NULL;
|
|
struct drm_connector *connector;
|
|
struct drm_modeset_acquire_ctx *ctx;
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *am_crtc;
|
|
struct device *dev_ = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev_);
|
|
struct drm_device *dev;
|
|
struct meson_drm *private;
|
|
int crtc_index = *(int *)attr->private;
|
|
struct drm_atomic_state *state;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -ENODEV;
|
|
|
|
dev = minor->dev;
|
|
private = dev->dev_private;
|
|
|
|
crtc = &private->crtcs[crtc_index]->base;
|
|
am_crtc = to_am_meson_crtc(crtc);
|
|
|
|
memset(mode_name, 0, DRM_DISPLAY_MODE_LEN);
|
|
memcpy(mode_name, buf, (strlen(buf) < DRM_DISPLAY_MODE_LEN) ?
|
|
strlen(buf) - 1 : DRM_DISPLAY_MODE_LEN - 1);
|
|
|
|
DRM_INFO("drm set mode to %s\n", mode_name);
|
|
/*init all connector and found matched uboot mode.*/
|
|
found = 0;
|
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
|
drm_modeset_lock_all(dev);
|
|
if (drm_modeset_is_locked(&dev->mode_config.connection_mutex))
|
|
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
num_modes = connector->funcs->fill_modes(connector,
|
|
dev->mode_config.max_width,
|
|
dev->mode_config.max_height);
|
|
drm_modeset_unlock_all(dev);
|
|
|
|
if (num_modes) {
|
|
list_for_each_entry(mode, &connector->modes, head) {
|
|
if (!strcmp(mode->name, mode_name)) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
break;
|
|
}
|
|
|
|
DRM_DEBUG("Connector[%d] status[%d], %d\n",
|
|
connector->connector_type, connector->status, found);
|
|
}
|
|
|
|
if (!found) {
|
|
DRM_INFO("No Found mode[%s]\n", mode_name);
|
|
if (!strcmp("null", mode_name))
|
|
drm_atomic_helper_shutdown(dev);
|
|
|
|
return count;
|
|
}
|
|
|
|
DRM_INFO("Found Connector[%d] mode[%s]\n", connector->connector_type,
|
|
mode->name);
|
|
drm_modeset_lock_all(dev);
|
|
ctx = dev->mode_config.acquire_ctx;
|
|
state = meson_drm_duplicate_state(dev, ctx, crtc, connector, mode);
|
|
ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
|
|
drm_modeset_unlock_all(dev);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t crtc_mode_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
int pos = 0;
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *am_crtc;
|
|
struct drm_display_mode *mode;
|
|
struct device *dev_ = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev_);
|
|
struct drm_device *dev;
|
|
struct meson_drm *private;
|
|
int crtc_index = *(int *)attr->private;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -ENODEV;
|
|
|
|
dev = minor->dev;
|
|
private = dev->dev_private;
|
|
|
|
crtc = &private->crtcs[crtc_index]->base;
|
|
am_crtc = to_am_meson_crtc(crtc);
|
|
mode = &crtc->state->adjusted_mode;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos, "%s\n", mode->name);
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t hdmitx_attr_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
char attr_str[16];
|
|
int cs, cd;
|
|
struct drm_crtc *crtc;
|
|
struct drm_connector *conn;
|
|
struct drm_connector_list_iter conn_iter;
|
|
struct am_hdmitx_connector_state *am_conn_state;
|
|
struct device *dev_ = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev_);
|
|
struct drm_device *dev;
|
|
struct meson_drm *private;
|
|
int crtc_index = *(int *)attr->private;
|
|
bool found = false;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -ENODEV;
|
|
|
|
dev = minor->dev;
|
|
private = dev->dev_private;
|
|
|
|
crtc = &private->crtcs[crtc_index]->base;
|
|
memset(attr_str, 0, sizeof(attr_str));
|
|
memcpy(attr_str, buf, (strlen(buf) < sizeof(attr_str)) ?
|
|
strlen(buf) - 1 : sizeof(attr_str) - 1);
|
|
|
|
if (strstr(attr_str, "420"))
|
|
cs = HDMI_COLORSPACE_YUV420;
|
|
else if (strstr(attr_str, "422"))
|
|
cs = HDMI_COLORSPACE_YUV422;
|
|
else if (strstr(attr_str, "444"))
|
|
cs = HDMI_COLORSPACE_YUV444;
|
|
else if (strstr(attr_str, "rgb"))
|
|
cs = HDMI_COLORSPACE_RGB;
|
|
else
|
|
cs = HDMI_COLORSPACE_YUV444;
|
|
|
|
/*parse colorspace success*/
|
|
if (strstr(attr_str, "12bit"))
|
|
cd = 12;
|
|
else if (strstr(attr_str, "10bit"))
|
|
cd = 10;
|
|
else if (strstr(attr_str, "8bit"))
|
|
cd = 8;
|
|
else
|
|
cd = 8;
|
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
drm_for_each_connector_iter(conn, &conn_iter) {
|
|
if (conn->connector_type != DRM_MODE_CONNECTOR_HDMIA)
|
|
continue;
|
|
|
|
if (!conn->state)
|
|
continue;
|
|
|
|
if (conn->state->crtc == crtc) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
drm_connector_list_iter_end(&conn_iter);
|
|
|
|
if (found) {
|
|
am_conn_state = to_am_hdmitx_connector_state(conn->state);
|
|
am_conn_state->color_attr_para.colorformat = cs;
|
|
am_conn_state->color_attr_para.bitdepth = cd;
|
|
DRM_INFO("%s set cs-%d, cd-%d\n", __func__, cs, cd);
|
|
} else {
|
|
DRM_INFO("%s not found hdmi state\n", __func__);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t hdmitx_attr_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
int pos = 0;
|
|
const char *colorspace;
|
|
int cs, cd;
|
|
struct drm_crtc *crtc;
|
|
struct drm_connector *conn;
|
|
struct drm_connector_list_iter conn_iter;
|
|
struct am_hdmitx_connector_state *am_conn_state;
|
|
struct device *dev_ = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev_);
|
|
struct drm_device *dev;
|
|
struct meson_drm *private;
|
|
int crtc_index = *(int *)attr->private;
|
|
bool found = false;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -ENODEV;
|
|
|
|
dev = minor->dev;
|
|
private = dev->dev_private;
|
|
|
|
crtc = &private->crtcs[crtc_index]->base;
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
drm_for_each_connector_iter(conn, &conn_iter) {
|
|
if (conn->connector_type != DRM_MODE_CONNECTOR_HDMIA)
|
|
continue;
|
|
|
|
if (!conn->state)
|
|
continue;
|
|
|
|
if (conn->state->crtc == crtc) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
drm_connector_list_iter_end(&conn_iter);
|
|
|
|
if (!found) {
|
|
DRM_INFO("no hdmi connector or not connected!\n");
|
|
return pos;
|
|
}
|
|
|
|
am_conn_state = to_am_hdmitx_connector_state(conn->state);
|
|
cs = am_conn_state->color_attr_para.colorformat;
|
|
cd = am_conn_state->color_attr_para.bitdepth;
|
|
|
|
switch (cs) {
|
|
case HDMI_COLORSPACE_YUV420:
|
|
colorspace = "420";
|
|
break;
|
|
case HDMI_COLORSPACE_YUV422:
|
|
colorspace = "422";
|
|
break;
|
|
case HDMI_COLORSPACE_YUV444:
|
|
colorspace = "444";
|
|
break;
|
|
case HDMI_COLORSPACE_RGB:
|
|
colorspace = "rgb";
|
|
break;
|
|
default:
|
|
colorspace = "rgb";
|
|
DRM_ERROR("Unknown colospace value %d\n", cs);
|
|
break;
|
|
};
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos, "%s,%dbit\n", colorspace, cd);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t crtc_rdma_table_switch_show(struct file *filp,
|
|
struct kobject *kobj, struct bin_attribute *attr, char *buf,
|
|
loff_t off, size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
int crtc_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > rdma_table_switch enable crtc-%d drm rdma table\n", crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > rdma_table_switch disable crtc-%d drm rdma table\n", crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"crtc-%d drm rdma table status is %d\n", crtc_index,
|
|
rdma_tbl[crtc_index].flag);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t crtc_rdma_table_switch_store(struct file *filp,
|
|
struct kobject *kobj, struct bin_attribute *attr, char *buf,
|
|
loff_t off, size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *amcrtc;
|
|
int crtc_index = *(int *)attr->private;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
amcrtc = to_am_meson_crtc(crtc);
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
if (buf[0] == '1') {
|
|
amcrtc->rdma_table_enable = true;
|
|
DRM_INFO("crtc-%d enable drm rdma table\n", crtc_index);
|
|
} else if (buf[0] == '0') {
|
|
amcrtc->rdma_table_enable = false;
|
|
DRM_INFO("crtc-%d disable drm rdma table\n", crtc_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t crtc_target_vblank_disable_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *amc;
|
|
int crtc_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
amc = to_am_meson_crtc(crtc);
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 1 > target_vblank_disable disable target_vblank on crtc-%d\n",
|
|
crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo 0 > target_vblank_disable enable target_vblank on crtc-%d\n",
|
|
crtc_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"The feature on crtc-%d is %d\n", crtc_index, !amc->target_vblank_disable);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t crtc_target_vblank_disable_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct drm_crtc *crtc;
|
|
struct am_meson_crtc *amc;
|
|
int crtc_index = *(int *)attr->private;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
crtc = drm_crtc_from_index(minor->dev, crtc_index);
|
|
if (!crtc)
|
|
return -EINVAL;
|
|
|
|
amc = to_am_meson_crtc(crtc);
|
|
|
|
if (buf[0] != '0' && buf[0] != '1')
|
|
return -EINVAL;
|
|
|
|
if (buf[0] == '1') {
|
|
amc->target_vblank_disable = 1;
|
|
DRM_INFO("crtc-%d disabled target_vblank feature\n", crtc_index);
|
|
} else if (buf[0] == '0') {
|
|
amc->target_vblank_disable = 0;
|
|
DRM_INFO("crtc-%d enabled target_vblank feature\n", crtc_index);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
static ssize_t video_resize_src_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int video_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo src_x src_y src_w src_h > resize_source to enable video-%d resize src\n",
|
|
video_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo -1 -1 -1 -1 > resize_source to disable video-%d resize src\n", video_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t video_resize_src_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int video_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
unsigned int src_x, src_y, src_w, src_h;
|
|
char dst_buf[64];
|
|
char *bufp, *parm[8] = {NULL};
|
|
int ret;
|
|
int lens = strlen(buf);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (!(parm[0] && parm[1] && parm[2] && parm[3])) {
|
|
DRM_INFO("%s, parameters is incorrect.\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtoint(parm[0], 10, &src_x) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[1], 10, &src_y) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[2], 10, &src_w) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[3], 10, &src_h) < 0)
|
|
return -EINVAL;
|
|
|
|
priv->video_planes[video_index]->adjust_src.x1 = src_x;
|
|
priv->video_planes[video_index]->adjust_src.y1 = src_y;
|
|
priv->video_planes[video_index]->adjust_src.x2 = src_w;
|
|
priv->video_planes[video_index]->adjust_src.y2 = src_h;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t video_resize_dst_show(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
struct meson_drm *priv;
|
|
int video_index = *(int *)attr->private;
|
|
int pos = 0;
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (off > 0)
|
|
return 0;
|
|
|
|
priv = minor->dev->dev_private;
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo dst_x dst_y dst_w dst_h > resize_destination to enable video-%d resize dst\n",
|
|
video_index);
|
|
pos += snprintf(buf + pos, PAGE_SIZE - pos,
|
|
"echo -1 -1 -1 -1 > resize_destination to disable video-%d resize dst\n",
|
|
video_index);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t video_resize_dst_store(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *attr, char *buf, loff_t off,
|
|
size_t count)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct drm_minor *minor = dev_get_drvdata(dev);
|
|
int video_index = *(int *)attr->private;
|
|
struct meson_drm *priv;
|
|
unsigned int dst_x, dst_y, dst_w, dst_h;
|
|
char dst_buf[64];
|
|
char *bufp, *parm[8] = {NULL};
|
|
int ret;
|
|
int lens = strlen(buf);
|
|
|
|
if (!minor || !minor->dev)
|
|
return -EINVAL;
|
|
|
|
if (lens > sizeof(dst_buf) - 1)
|
|
return -EINVAL;
|
|
|
|
memcpy(dst_buf, buf, lens);
|
|
|
|
dst_buf[lens] = '\0';
|
|
bufp = dst_buf;
|
|
parse_param(bufp, (char **)&parm);
|
|
|
|
priv = minor->dev->dev_private;
|
|
|
|
if (!(parm[0] && parm[1] && parm[2] && parm[3])) {
|
|
DRM_INFO("%s, parameters is incorrect.\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (kstrtoint(parm[0], 10, &dst_x) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[1], 10, &dst_y) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[2], 10, &dst_w) < 0)
|
|
return -EINVAL;
|
|
if (kstrtoint(parm[3], 10, &dst_h) < 0)
|
|
return -EINVAL;
|
|
|
|
priv->video_planes[video_index]->adjust_dst.x1 = dst_x;
|
|
priv->video_planes[video_index]->adjust_dst.y1 = dst_y;
|
|
priv->video_planes[video_index]->adjust_dst.x2 = dst_w;
|
|
priv->video_planes[video_index]->adjust_dst.y2 = dst_h;
|
|
|
|
ret = meson_drm_trigger_atomic_commit(minor);
|
|
if (ret)
|
|
DRM_ERROR("failed, ret = %d\n", ret);
|
|
|
|
return count;
|
|
}
|
|
|
|
static struct bin_attribute osd0_attr[] = {
|
|
{
|
|
.attr.name = "osd_reverse",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_reverse_show,
|
|
.write = osd_reverse_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_blend_bypass",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_blend_bypass_show,
|
|
.write = osd_blend_bypass_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_read_port",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_read_port_show,
|
|
.write = osd_read_port_store,
|
|
},
|
|
{
|
|
.attr.name = "fbdump",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_fbdump_show,
|
|
.write = osd_fbdump_store,
|
|
.size = 36864000,
|
|
},
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_blank_show,
|
|
.write = osd_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "pixel_blend",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_pixel_blend_show,
|
|
.write = osd_pixel_blend_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_resize_src_show,
|
|
.write = osd_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_resize_dst_show,
|
|
.write = osd_resize_dst_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_hskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_gfcd_hskip_show,
|
|
.write = osd_gfcd_hskip_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_vskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_gfcd_vskip_show,
|
|
.write = osd_gfcd_vskip_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_zorder",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_zorder_show,
|
|
.write = osd_zorder_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_dimm",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[0],
|
|
.read = osd_dimm_show,
|
|
.write = osd_dimm_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *osd0_bin_attrs[] = {
|
|
&osd0_attr[0],
|
|
&osd0_attr[1],
|
|
&osd0_attr[2],
|
|
&osd0_attr[3],
|
|
&osd0_attr[4],
|
|
&osd0_attr[5],
|
|
&osd0_attr[6],
|
|
&osd0_attr[7],
|
|
&osd0_attr[8],
|
|
&osd0_attr[9],
|
|
&osd0_attr[10],
|
|
&osd0_attr[11],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute osd1_attr[] = {
|
|
{
|
|
.attr.name = "osd_reverse",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_reverse_show,
|
|
.write = osd_reverse_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_blend_bypass",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_blend_bypass_show,
|
|
.write = osd_blend_bypass_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_read_port",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_read_port_show,
|
|
.write = osd_read_port_store,
|
|
},
|
|
{
|
|
.attr.name = "fbdump",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_fbdump_show,
|
|
.write = osd_fbdump_store,
|
|
.size = 36864000,
|
|
},
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_blank_show,
|
|
.write = osd_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "pixel_blend",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_pixel_blend_show,
|
|
.write = osd_pixel_blend_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_resize_src_show,
|
|
.write = osd_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_resize_dst_show,
|
|
.write = osd_resize_dst_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_hskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_gfcd_hskip_show,
|
|
.write = osd_gfcd_hskip_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_vskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_gfcd_vskip_show,
|
|
.write = osd_gfcd_vskip_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_zorder",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_zorder_show,
|
|
.write = osd_zorder_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_dimm",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[1],
|
|
.read = osd_dimm_show,
|
|
.write = osd_dimm_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *osd1_bin_attrs[] = {
|
|
&osd1_attr[0],
|
|
&osd1_attr[1],
|
|
&osd1_attr[2],
|
|
&osd1_attr[3],
|
|
&osd1_attr[4],
|
|
&osd1_attr[5],
|
|
&osd1_attr[6],
|
|
&osd1_attr[7],
|
|
&osd1_attr[8],
|
|
&osd1_attr[9],
|
|
&osd1_attr[10],
|
|
&osd1_attr[11],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute osd2_attr[] = {
|
|
{
|
|
.attr.name = "osd_reverse",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_reverse_show,
|
|
.write = osd_reverse_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_blend_bypass",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_blend_bypass_show,
|
|
.write = osd_blend_bypass_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_read_port",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_read_port_show,
|
|
.write = osd_read_port_store,
|
|
},
|
|
{
|
|
.attr.name = "fbdump",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_fbdump_show,
|
|
.write = osd_fbdump_store,
|
|
.size = 36864000,
|
|
},
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_blank_show,
|
|
.write = osd_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "pixel_blend",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_pixel_blend_show,
|
|
.write = osd_pixel_blend_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_resize_src_show,
|
|
.write = osd_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_resize_dst_show,
|
|
.write = osd_resize_dst_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_hskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_gfcd_hskip_show,
|
|
.write = osd_gfcd_hskip_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_vskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_gfcd_vskip_show,
|
|
.write = osd_gfcd_vskip_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_zorder",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_zorder_show,
|
|
.write = osd_zorder_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_dimm",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[2],
|
|
.read = osd_dimm_show,
|
|
.write = osd_dimm_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *osd2_bin_attrs[] = {
|
|
&osd2_attr[0],
|
|
&osd2_attr[1],
|
|
&osd2_attr[2],
|
|
&osd2_attr[3],
|
|
&osd2_attr[4],
|
|
&osd2_attr[5],
|
|
&osd2_attr[6],
|
|
&osd2_attr[7],
|
|
&osd2_attr[8],
|
|
&osd2_attr[9],
|
|
&osd2_attr[10],
|
|
&osd2_attr[11],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute osd3_attr[] = {
|
|
{
|
|
.attr.name = "osd_reverse",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_reverse_show,
|
|
.write = osd_reverse_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_blend_bypass",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_blend_bypass_show,
|
|
.write = osd_blend_bypass_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_read_port",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_read_port_show,
|
|
.write = osd_read_port_store,
|
|
},
|
|
{
|
|
.attr.name = "fbdump",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_fbdump_show,
|
|
.write = osd_fbdump_store,
|
|
.size = 36864000,
|
|
},
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_blank_show,
|
|
.write = osd_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "pixel_blend",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_pixel_blend_show,
|
|
.write = osd_pixel_blend_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_resize_src_show,
|
|
.write = osd_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_resize_dst_show,
|
|
.write = osd_resize_dst_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_hskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_gfcd_hskip_show,
|
|
.write = osd_gfcd_hskip_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_vskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_gfcd_vskip_show,
|
|
.write = osd_gfcd_vskip_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_zorder",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_zorder_show,
|
|
.write = osd_zorder_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_dimm",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[3],
|
|
.read = osd_dimm_show,
|
|
.write = osd_dimm_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *osd3_bin_attrs[] = {
|
|
&osd3_attr[0],
|
|
&osd3_attr[1],
|
|
&osd3_attr[2],
|
|
&osd3_attr[3],
|
|
&osd3_attr[4],
|
|
&osd3_attr[5],
|
|
&osd3_attr[6],
|
|
&osd3_attr[7],
|
|
&osd3_attr[8],
|
|
&osd3_attr[9],
|
|
&osd3_attr[10],
|
|
&osd3_attr[11],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute osd4_attr[] = {
|
|
{
|
|
.attr.name = "osd_reverse",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_reverse_show,
|
|
.write = osd_reverse_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_blend_bypass",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_blend_bypass_show,
|
|
.write = osd_blend_bypass_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_read_port",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_read_port_show,
|
|
.write = osd_read_port_store,
|
|
},
|
|
{
|
|
.attr.name = "fbdump",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_fbdump_show,
|
|
.write = osd_fbdump_store,
|
|
.size = 36864000,
|
|
},
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_blank_show,
|
|
.write = osd_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "pixel_blend",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_pixel_blend_show,
|
|
.write = osd_pixel_blend_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_resize_src_show,
|
|
.write = osd_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_resize_dst_show,
|
|
.write = osd_resize_dst_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_hskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_gfcd_hskip_show,
|
|
.write = osd_gfcd_hskip_store,
|
|
},
|
|
{
|
|
.attr.name = "gfcd_vskip",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_gfcd_vskip_show,
|
|
.write = osd_gfcd_vskip_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_zorder",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_zorder_show,
|
|
.write = osd_zorder_store,
|
|
},
|
|
{
|
|
.attr.name = "osd_dimm",
|
|
.attr.mode = 0664,
|
|
.private = &osd_index[4],
|
|
.read = osd_dimm_show,
|
|
.write = osd_dimm_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *osd4_bin_attrs[] = {
|
|
&osd4_attr[0],
|
|
&osd4_attr[1],
|
|
&osd4_attr[2],
|
|
&osd4_attr[3],
|
|
&osd4_attr[4],
|
|
&osd4_attr[5],
|
|
&osd4_attr[6],
|
|
&osd4_attr[7],
|
|
&osd4_attr[8],
|
|
&osd4_attr[9],
|
|
&osd4_attr[10],
|
|
&osd4_attr[11],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute video0_attr[] = {
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[0],
|
|
.read = video_resize_src_show,
|
|
.write = video_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[0],
|
|
.read = video_resize_dst_show,
|
|
.write = video_resize_dst_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *video0_bin_attrs[] = {
|
|
&video0_attr[0],
|
|
&video0_attr[1],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute video1_attr[] = {
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[1],
|
|
.read = video_resize_src_show,
|
|
.write = video_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[1],
|
|
.read = video_resize_dst_show,
|
|
.write = video_resize_dst_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *video1_bin_attrs[] = {
|
|
&video1_attr[0],
|
|
&video1_attr[1],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute video2_attr[] = {
|
|
{
|
|
.attr.name = "resize_source",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[2],
|
|
.read = video_resize_src_show,
|
|
.write = video_resize_src_store,
|
|
},
|
|
{
|
|
.attr.name = "resize_destination",
|
|
.attr.mode = 0664,
|
|
.private = &video_index[2],
|
|
.read = video_resize_dst_show,
|
|
.write = video_resize_dst_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *video2_bin_attrs[] = {
|
|
&video2_attr[0],
|
|
&video2_attr[1],
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group osd_attr_group[MESON_MAX_OSDS] = {
|
|
{
|
|
.name = osd0_group_name,
|
|
.bin_attrs = osd0_bin_attrs,
|
|
},
|
|
{
|
|
.name = osd1_group_name,
|
|
.bin_attrs = osd1_bin_attrs,
|
|
},
|
|
{
|
|
.name = osd2_group_name,
|
|
.bin_attrs = osd2_bin_attrs,
|
|
},
|
|
{
|
|
.name = osd3_group_name,
|
|
.bin_attrs = osd3_bin_attrs,
|
|
},
|
|
{
|
|
.name = osd4_group_name,
|
|
.bin_attrs = osd4_bin_attrs,
|
|
},
|
|
};
|
|
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(crtc_force_hint)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(crtc_force_hint)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(flush_time)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(flush_time)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osd_slice_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osd_slice_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(afbc_order_conf)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(afbc_order_conf)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osdscaler_force_update)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osdscaler_force_update)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osdscaler_v_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osdscaler_v_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osdscaler_h_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osdscaler_h_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osd_hold_line)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osd_hold_line)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(force_mali_afbc_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(force_mali_afbc_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(async_commit_ioctl_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(async_commit_ioctl_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(fbdev_pan_display_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(fbdev_pan_display_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_R_DEF(osdscaler_safety_factor)
|
|
AM_BIN_ATTR_MOD_PARAM_W_DEF(osdscaler_safety_factor)
|
|
|
|
static struct bin_attribute module_param_attr[] = {
|
|
AM_BIN_ATTR_MOD_PARAM_RW(crtc_force_hint)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(flush_time)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osd_slice_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(afbc_order_conf)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osdscaler_force_update)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osdscaler_v_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osdscaler_h_filter_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osd_hold_line)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(force_mali_afbc_mode)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(async_commit_ioctl_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(fbdev_pan_display_threshold)
|
|
AM_BIN_ATTR_MOD_PARAM_RW(osdscaler_safety_factor)
|
|
};
|
|
|
|
static struct attribute_group module_param_group = {
|
|
.name = module_param_group_name,
|
|
};
|
|
|
|
static const struct attribute_group video_attr_group[MESON_MAX_VIDEOS] = {
|
|
{
|
|
.name = video0_group_name,
|
|
.bin_attrs = video0_bin_attrs,
|
|
},
|
|
{
|
|
.name = video1_group_name,
|
|
.bin_attrs = video1_bin_attrs,
|
|
},
|
|
{
|
|
.name = video2_group_name,
|
|
.bin_attrs = video2_bin_attrs,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute crtc0_attr[] = {
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[0],
|
|
.read = crtc_blank_show,
|
|
.write = crtc_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "mode",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[0],
|
|
.read = crtc_mode_show,
|
|
.write = crtc_mode_store,
|
|
},
|
|
{
|
|
.attr.name = "attr",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[0],
|
|
.read = hdmitx_attr_show,
|
|
.write = hdmitx_attr_store,
|
|
},
|
|
{
|
|
.attr.name = "rdma_table_switch",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[0],
|
|
.read = crtc_rdma_table_switch_show,
|
|
.write = crtc_rdma_table_switch_store,
|
|
},
|
|
{
|
|
.attr.name = "target_vblank_disable",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[0],
|
|
.read = crtc_target_vblank_disable_show,
|
|
.write = crtc_target_vblank_disable_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *crtc0_bin_attrs[] = {
|
|
&crtc0_attr[0],
|
|
&crtc0_attr[1],
|
|
&crtc0_attr[2],
|
|
&crtc0_attr[3],
|
|
&crtc0_attr[4],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute crtc1_attr[] = {
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[1],
|
|
.read = crtc_blank_show,
|
|
.write = crtc_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "mode",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[1],
|
|
.read = crtc_mode_show,
|
|
.write = crtc_mode_store,
|
|
},
|
|
{
|
|
.attr.name = "attr",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[1],
|
|
.read = hdmitx_attr_show,
|
|
.write = hdmitx_attr_store,
|
|
},
|
|
{
|
|
.attr.name = "rdma_table_switch",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[1],
|
|
.read = crtc_rdma_table_switch_show,
|
|
.write = crtc_rdma_table_switch_store,
|
|
},
|
|
{
|
|
.attr.name = "target_vblank_disable",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[1],
|
|
.read = crtc_target_vblank_disable_show,
|
|
.write = crtc_target_vblank_disable_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *crtc1_bin_attrs[] = {
|
|
&crtc1_attr[0],
|
|
&crtc1_attr[1],
|
|
&crtc1_attr[2],
|
|
&crtc1_attr[3],
|
|
&crtc1_attr[4],
|
|
NULL,
|
|
};
|
|
|
|
static struct bin_attribute crtc2_attr[] = {
|
|
{
|
|
.attr.name = "blank",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[2],
|
|
.read = crtc_blank_show,
|
|
.write = crtc_blank_store,
|
|
},
|
|
{
|
|
.attr.name = "mode",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[2],
|
|
.read = crtc_mode_show,
|
|
.write = crtc_mode_store,
|
|
},
|
|
{
|
|
.attr.name = "attr",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[2],
|
|
.read = hdmitx_attr_show,
|
|
.write = hdmitx_attr_store,
|
|
},
|
|
{
|
|
.attr.name = "rdma_table_switch",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[2],
|
|
.read = crtc_rdma_table_switch_show,
|
|
.write = crtc_rdma_table_switch_store,
|
|
},
|
|
{
|
|
.attr.name = "target_vblank_disable",
|
|
.attr.mode = 0664,
|
|
.private = &crtc_index[2],
|
|
.read = crtc_target_vblank_disable_show,
|
|
.write = crtc_target_vblank_disable_store,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute *crtc2_bin_attrs[] = {
|
|
&crtc2_attr[0],
|
|
&crtc2_attr[1],
|
|
&crtc2_attr[2],
|
|
&crtc2_attr[3],
|
|
&crtc2_attr[4],
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group crtc_attr_group[MESON_MAX_POSTBLEND] = {
|
|
{
|
|
.name = crtc0_group_name,
|
|
.bin_attrs = crtc0_bin_attrs,
|
|
},
|
|
{
|
|
.name = crtc1_group_name,
|
|
.bin_attrs = crtc1_bin_attrs,
|
|
},
|
|
{
|
|
.name = crtc2_group_name,
|
|
.bin_attrs = crtc2_bin_attrs,
|
|
},
|
|
};
|
|
|
|
static struct bin_attribute state_attr = {
|
|
.attr.name = "state",
|
|
.attr.mode = 0664,
|
|
.read = state_show,
|
|
};
|
|
|
|
static struct bin_attribute reg_dump_attr = {
|
|
.attr.name = "reg_dump",
|
|
.attr.mode = 0664,
|
|
.read = reg_dump_show,
|
|
};
|
|
|
|
int meson_drm_sysfs_register(struct drm_device *drm_dev)
|
|
{
|
|
int rc, i;
|
|
struct device *dev;
|
|
struct meson_drm *priv = drm_dev->dev_private;
|
|
struct bin_attribute **module_param_bin_attrs;
|
|
|
|
if (!drm_dev->primary || !drm_dev->primary->kdev)
|
|
return -ENODEV;
|
|
|
|
dev = drm_dev->primary->kdev;
|
|
|
|
rc = sysfs_create_group(&dev->kobj, &vpu_attr_group);
|
|
|
|
rc = sysfs_create_bin_file(&dev->kobj, &state_attr);
|
|
rc = sysfs_create_bin_file(&dev->kobj, ®_dump_attr);
|
|
|
|
module_param_bin_attrs = devm_kcalloc(dev, sizeof(struct bin_attribute *),
|
|
ARRAY_SIZE(module_param_attr) + 1, GFP_KERNEL); /* Zeroed */
|
|
if (module_param_bin_attrs) {
|
|
for (i = 0; i < ARRAY_SIZE(module_param_attr); i++)
|
|
module_param_bin_attrs[i] = &module_param_attr[i];
|
|
|
|
module_param_group.bin_attrs = module_param_bin_attrs;
|
|
rc = sysfs_create_group(&dev->kobj, &module_param_group);
|
|
} else {
|
|
DRM_ERROR("Failed to calloc param bin attrs!\n");
|
|
}
|
|
|
|
for (i = 0; i < MESON_MAX_OSDS; i++) {
|
|
if (!priv->pipeline->osds[i])
|
|
continue;
|
|
rc = sysfs_create_group(&dev->kobj, &osd_attr_group[i]);
|
|
}
|
|
for (i = 0; i < MESON_MAX_VIDEOS; i++) {
|
|
if (!priv->pipeline->video[i])
|
|
continue;
|
|
rc = sysfs_create_group(&dev->kobj, &video_attr_group[i]);
|
|
}
|
|
|
|
for (i = 0; i < MESON_MAX_POSTBLEND; i++) {
|
|
if (!priv->pipeline->postblends[i])
|
|
continue;
|
|
rc = sysfs_create_group(&dev->kobj, &crtc_attr_group[i]);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void meson_drm_sysfs_unregister(struct drm_device *drm_dev)
|
|
{
|
|
int i;
|
|
struct device *dev;
|
|
struct meson_drm *priv = drm_dev->dev_private;
|
|
|
|
if (!drm_dev->primary || !drm_dev->primary->kdev)
|
|
return;
|
|
|
|
dev = drm_dev->primary->kdev;
|
|
|
|
sysfs_remove_group(&dev->kobj, &vpu_attr_group);
|
|
sysfs_remove_bin_file(&dev->kobj, &state_attr);
|
|
sysfs_remove_bin_file(&dev->kobj, ®_dump_attr);
|
|
|
|
if (module_param_group.bin_attrs) {
|
|
sysfs_remove_group(&dev->kobj, &module_param_group);
|
|
module_param_group.bin_attrs = NULL;
|
|
}
|
|
|
|
for (i = 0; i < MESON_MAX_OSDS; i++) {
|
|
if (!priv->pipeline->osds[i])
|
|
continue;
|
|
sysfs_remove_group(&dev->kobj, &osd_attr_group[i]);
|
|
}
|
|
for (i = 0; i < MESON_MAX_VIDEOS; i++) {
|
|
if (!priv->pipeline->video[i])
|
|
continue;
|
|
sysfs_remove_group(&dev->kobj, &video_attr_group[i]);
|
|
}
|
|
for (i = 0; i < MESON_MAX_POSTBLEND; i++) {
|
|
if (!priv->pipeline->postblends[i])
|
|
continue;
|
|
sysfs_remove_group(&dev->kobj, &crtc_attr_group[i]);
|
|
}
|
|
}
|
|
|