一、整体思路
手上的项目兼容了一款新mipi副屏,如果想了解,可以去看看
兼容副屏后,已经能正常点亮,休眠唤醒也正常了,还剩一个问题:显示为竖屏,要改为横屏。
我参考了同事的做法,就是先在dev下创建一个设备文件/dev/dsi-panel-id,上层open该设备文件后通过ioctl方式访问kernel层,将kernel层的储存屏id的变量传递给上层。最后在上层判断屏id区别是新旧屏,如果是新屏,就旋转。
二、代码分析
1、kernel层
drivers/gpu/drm/panel/panel-simple.c
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index db392b8..01dba51 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -40,6 +40,9 @@
#include <linux/of_graph.h>
#include <video/videomode.h>
+static char panel_id; //储存读取dts的panel id
+
+
struct cmd_ctrl_hdr {
u8 dtype; /* data type */
u8 wait; /* ms */
@@ -2351,6 +2354,106 @@ static const struct of_device_id dsi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dsi_of_match);
+/*---------------------------liyj ---------------------------------------------------------------------------*/
+
+static struct class *dsi_panel_class = NULL;
+static struct device *dsi_panel_device = NULL;
+static struct miscdevice dsi_pane_id_device;
+#define NO_PANEL_ID 0XFF
+#define DSI_PANEL_ID_MAGIC 0xFA
+#define DSI_PANEL_ID_GET _IOR(DSI_PANEL_ID_MAGIC, 0x01, char) //自定义一个ioctl命令,用于上层与kernel层的交互
+
//下面会有一个函数在sys文件系统下创建/sys/class/panel/dsi-panel节点,在控制台下使用cat id会回调id_show函数
+static ssize_t id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d",panel_id);
+}
+
+static DEVICE_ATTR_RO(id);
//在sys文件系统下创建/sys/class/panel/dsi-panel节点
+static int telpo_create_panel_sysfs_dir(void)
+{
+ printk("---liyj--- FILE : %s enter func : %s LINE : %d\n",__FILE__,__func__,__LINE__);
+ dsi_panel_class = class_create(THIS_MODULE, "panel");
+ if (IS_ERR(dsi_panel_class))
+ return PTR_ERR(dsi_panel_class);
+
+ dsi_panel_device = device_create(dsi_panel_class, NULL, MKDEV(0, 0), NULL, "dsi-panel");
+ if (IS_ERR(dsi_panel_device)) {
+ class_destroy(dsi_panel_class);
+ return PTR_ERR(dsi_panel_device);
+ }
+
+ return device_create_file(dsi_panel_device, &dev_attr_id);
+}
+static int dsi_panel_id_dev_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+
//上层与kernel层交互的通道
+static long dsi_panel_id_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case DSI_PANEL_ID_GET:
+ printk("***liyj***copy_to_user start\n");
+ if(copy_to_user((void * __user)arg,&panel_id,sizeof(panel_id)))
+ {
+ printk("***liyj***copy_to_user failed\n");
+ }
+ break;
+ default:
+ printk("get dsi panel id err\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations dsi_panel_id_dev_fops =
+{
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = dsi_panel_id_dev_open,
+ .unlocked_ioctl = dsi_panel_id_dev_ioctl,
+ .compat_ioctl = dsi_panel_id_dev_ioctl,
+};
//在dev下创建一个设备节点,用于上层跟kernel层的交互
+static int telpo_create_panel_misc_dev(void)
+{
+ int ret;
+
+ printk("---liyj--- FILE : %s enter func : %s LINE : %d\n",__FILE__,__func__,__LINE__);
+ dsi_pane_id_device.minor = MISC_DYNAMIC_MINOR;
+ dsi_pane_id_device.name = "dsi-panel-id";
+ dsi_pane_id_device.fops = &dsi_panel_id_dev_fops;
+
+ ret = misc_register(&dsi_pane_id_device);
+ if (ret) {
+ pr_err("%s :dsi panel is misc register failed\n", __FILE__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+
+static char get_panel_id(struct device *dev)
+{
+ char g_panel_id ;
+ int len;
+ int ret;
+ struct device_node *np = dev->of_node;
+ //g_panel_id = of_get_property(np,"id",&len);
+ of_property_read_u8(np,"id",&g_panel_id); //读取dts中panel节点的id
+ printk("---liyj--- g_panel_id = %x\n",g_panel_id);
+ return g_panel_id;
+}
+/*---------------------------liyj ---------------------------------------------------------------------------*/
+
static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
{
struct panel_simple *panel;
@@ -2360,6 +2463,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
int err;
u32 val;
+
id = of_match_node(dsi_of_match, dsi->dev.of_node);
if (!id)
return -ENODEV;
@@ -2390,6 +2494,14 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
if (!of_property_read_u32(dsi->dev.of_node, "dsi,lanes", &val))
dsi->lanes = val;
+//liyj add start
+ panel_id = get_panel_id(&dsi->dev);
+ if (panel_id != NO_PANEL_ID) {
+ telpo_create_panel_sysfs_dir();
+ telpo_create_panel_misc_dev();
+ }
+
+//liyj add end
return mipi_dsi_attach(dsi);
}
dts中新屏节点的配置
&dsi {
status = "okay";
rockchip,lane-rate = <528>;
enable-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
panel@0 {
compatible = "simple-panel-dsi";
reg = <0>;
............
............
num = <0>;
id = [93]; //新屏的id
id-reg = <0xda>; //要读取的id寄存器
............
............
}
............
}
2、上层
system/core/drmservice/drmservice.c
diff --git a/system/core/drmservice/drmservice.c b/system/core/drmservice/drmservice.c
index 4640716..61cd86d 100755
--- a/system/core/drmservice/drmservice.c
+++ b/system/core/drmservice/drmservice.c
@@ -1074,6 +1074,59 @@ void copy_dir(const char *old_path,const char *new_path)
}
+#define DSI_PANEL_ID_MAGIC 0xFA
+#define DSI_PANEL_ID_GET _IOR(DSI_PANEL_ID_MAGIC, 0x01,char)
+#define DSI_PANEL_ID_DEV_PATH "/dev/dsi-panel-id"
+#define NO_PANEL_ID 0xff
+#define PANEL_OLD 0 //old panel
+#define PANEL_NEW 147 //new panel 新屏id,我的新屏id是0x93,十进制就是147
+static void get_dsi_panel_id(void)
+{
+ int fd = -1;
+ char id = NO_PANEL_ID;
+ int ret;
+ char model_value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.internal.model", model_value, "");
+
+ fd = open(DSI_PANEL_ID_DEV_PATH, O_RDONLY); //1、打开设备文件
+ if (fd > 0) {
+ SLOGE("---liyj--- fd > 0");
+ ret = ioctl(fd, DSI_PANEL_ID_GET, &id); //2、通过自定义的cmd跟kernel交互,获取panel id
+ if(ret <0)
+ {
+ SLOGE("---liyj--- ioctl failed\n");
+ }
+ SLOGE("---liyj--- id = %d\n",id);
+ close(fd);
+ }
+ if (id == NO_PANEL_ID)
+ return;
+
+ if (!(strcmp(model_value, "TPS680C"))) {
+ ALOGE("set TPS680C panel");
+ switch (id) {
+ case PANEL_OLD:
+ ALOGE("set panel as PANEL_OLD");
+ property_set("persist.sys.rotation.efull-1", "true");
+ property_set("persist.sys.rotation.einit", "0");
+ break;
+ case PANEL_NEW: //新屏
+ ALOGE("set panel as PANEL_NEW");
+ property_set("persist.sys.rotation.efull-1", "false");
+ property_set("persist.sys.rotation.einit", "3"); //旋转270度
+ break;
+ default:
+ SLOGD("not support panel id, set PANEL_NEW as default");
+ property_set("persist.sys.rotation.efull-1", "false");
+ property_set("persist.sys.rotation.einit", "3");
+ break;
+ }
+ } else {
+ ALOGE("no model panel set");
+ }
+}
+
/** * Program entry pointer */
@@ -1091,6 +1144,8 @@ int main( int argc, char *argv[] )
SLOGE("get prop_board_platform,prop_board_platform = %s , diff=%d",prop_board_platform,
strcmp(prop_board_platform,"rk3399"));
+ get_dsi_panel_id(); //函数调用,获取panel id
+
//get hid data
rknand_sys_storage_test_hid();
SLOGE("Get HID data:%s", hid_buf_idb);