展锐Android-Q LCD调试

冷暖自知 提交于 2020-01-20 03:07:42

模块功能描述

LCD模块功能主要是LCD液晶显示

LCD移植准备

以 skyworth ili9881c hd为例,首先需要准备东西如下:
1、屏IC Data Sheet
2、初始化代码 —>获得初始化屏幕ic的命令,用于编写u-boot初始化文件和.dtsi文件(kernel)

首先从Data Sheet或者初始化代码中可以获得以下一些信息:
1、水平脉冲宽度(qcom,mdss-dsi-h-pulse-width,Hsync)为68
2、水平后沿值(qcom,mdss-dsi-h-back-porch,HBP)为120
3、水平前沿值(qcom,mdss-dsi-h-front-porch,HFP)为88
4、垂直脉冲宽度(qcom,mdss-dsi-v-pulse-width,Vsync)为8
5、垂直后沿值(qcom,mdss-dsi-v-back-porch,VBP)为24
6、垂直前沿值(qcom,mdss-dsi-v-front-porch,VFP)为16
7、面板高度(qcom,mdss-dsi-panel-height,VAdr)为1280
8、面板宽度(qcom,mdss-dsi-panel-width,HAdr)为720

u-boot移植

增加LCD驱动文件

参考已有lcd驱动文件,添加要增加lcd的驱动文件,命名规则panel_ic_vendor_platform_res_mod.c

从原理图中获取gpio LCM_GPIO_VCC和LCM_GPIO_POWER

#include "sprd_panel.h"
#include "sprd_dsi.h"
#include "dsi/mipi_dsi_api.h"
#include "sprd_dphy.h"

static uint8_t init_data[] = {
				0x39,0x00,0x00,0x04, 0xFF,0x98,0x81,0x03,
				0x23,0x00,0x00,0x02, 0x01,0x00,              
				0x23,0x00,0x00,0x02, 0x02,0x00,              
				......
				0x39,0x00,0x00,0x04, 0xFF,0x98,0x81,0x00,
				0x23,0x00,0x00,0x02, 0x35,0x00,
				0x39,0x00,0x00,0x03, 0x51,0xff,0xff,
				0x23,0x00,0x00,0x02, 0x53,0x2c,	
				0x23,0x78,0x00,0x02, 0x11,0x00,
				0x23,0x0A,0x00,0x02, 0x29,0x00,
				CMD_END
};
//发送命令
static int mipi_dsi_send_cmds(struct sprd_dsi *dsi, void *data)
{
	uint16_t len;
	struct dsi_cmd_desc *cmds = data;
	if ((cmds == NULL) || (dsi == NULL))
		return -1;
	for (; cmds->data_type != CMD_END;) {
		len = (cmds->wc_h << 8) | cmds->wc_l;
		mipi_dsi_gen_write(dsi, cmds->payload, len);
		if (cmds->wait)
			msleep(cmds->wait);
		cmds = (struct dsi_cmd_desc *)(cmds->payload + len);
	}
	return 0;
}
static int ili9881c_init(void)
{
	struct sprd_dsi *dsi = &dsi_device;
	struct sprd_dphy *dphy = &dphy_device;
	mipi_dsi_lp_cmd_enable(dsi, true);
	mipi_dsi_send_cmds(dsi, init_data);
	mipi_dsi_set_work_mode(dsi, SPRD_MIPI_MODE_VIDEO);
	mipi_dsi_state_reset(dsi);
	mipi_dphy_hs_clk_en(dphy, true);
	return 0;
}
//读取LCD屏id
static int ili9881c_readid(void)
{
	struct sprd_dsi *dsi = &dsi_device;
	uint8_t cmd[] = {0xFF, 0x98, 0x81, 0x00};
	uint8_t read_buf[4] = {0};
	mipi_dsi_lp_cmd_enable(dsi, true);
	mipi_dsi_gen_write(dsi, cmd, ARRAY_SIZE(cmd));
	mipi_dsi_set_max_return_size(dsi, 1);
	mipi_dsi_dcs_read(dsi, 0xda, &read_buf[0], 1);
	//mipi_dsi_dcs_read(dsi, 0x01, &read_buf[1], 1);	
	printk("lcd_ili9881c_mipi read id 0xda value is 0x%x !\n", read_buf[0]);
	if((0x05 == read_buf[0])) {
		pr_info("ili9881c read id success!\n");
		return 0;
	}
	pr_err("ili9881c read id failed!\n");
	return -1;
}
static int ili9881c_power(int on)
{
	sprd_gpio_request(NULL, LCM_GPIO_VCC);
	sprd_gpio_request(NULL, LCM_GPIO_POWER);
	sprd_gpio_request(NULL, CONFIG_LCM_GPIO_RSTN);
	printk("lcd_ili9881c_hd_mipi reset  vcc=%d power=%d rst=%d !\n", LCM_GPIO_VCC, LCM_GPIO_POWER, CONFIG_LCM_GPIO_RSTN);
	sprd_gpio_direction_output(NULL, LCM_GPIO_VCC, 1);
	mdelay(5);
	sprd_gpio_direction_output(NULL, LCM_GPIO_POWER, 1);
	mdelay(5);
	if (on) {
		sprd_gpio_request(NULL, CONFIG_LCM_GPIO_RSTN);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 1);
		mdelay(5);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 0);
		mdelay(5);
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 1);
		mdelay(20);
	} else {
		sprd_gpio_direction_output(NULL, CONFIG_LCM_GPIO_RSTN, 0);
		mdelay(5);
	}
	return 0;
}
/*
static int ili9881c_set_brightness(int brightness)
{
	unsigned char set_bl_seq[] = {0x51, 0x0F,0xFF};
	struct sprd_dsi *dsi = &dsi_device;
	set_bl_seq[1] = brightness >> 4 & 0x0F;
	set_bl_seq[2] = brightness;
	mipi_dsi_gen_write(dsi,&set_bl_seq[0], 3);
	return 0;
}
*/
static struct panel_ops ili9881c_ops = {
	.init = ili9881c_init,
	.read_id = ili9881c_readid,
	.power = ili9881c_power,
	//.set_brightness = ili9881c_set_brightness,
};
static struct panel_info ili9881c_info = {
	/* common parameters */
	.lcd_name = "lcd_ili9881c_skyworth_hd_mipi_hd",
	.type = SPRD_PANEL_TYPE_MIPI,
	.bpp = 24,
	.width = 720,
	.height = 1280,
	/* DPI specific parameters */
	.pixel_clk = 64000000,
	.rgb_timing = {
			.hfp = 88,  /* unit: pixel */
			.hbp = 120,
			.hsync = 64,
			.vfp = 16, /*unit: line*/
			.vbp = 24,
			.vsync = 8,
	},
	/* MIPI DSI specific parameters */
	.phy_freq = 552*1000,
	.lane_num = 4,
	.work_mode = SPRD_MIPI_MODE_VIDEO,
	.burst_mode = PANEL_VIDEO_BURST_MODE,
	.nc_clk_en = false,
};

struct panel_driver lcd_ili9881c_skyworth_hd_mipi_driver = {
	.info = &ili9881c_info,
	.ops = &ili9881c_ops,
};

添加编译规则

在bsp/bootloader/u-boot15/drivers/video/sprd/lcd/Makefile中添加

obj-$(CONFIG_FB_LCD_ILI9881C_SKYWORTH_HD_MIPI)  += lcd_ili9881c_skyworth_hd_mipi.o

配置LCD编译选项

在bsp//bootloader/u-boot15/include/configs/8541e_1h10.h

#define LCM_GPIO_VCC 72
#define LCM_GPIO_POWER 73
#define CONFIG_FB_LCD_ILI9881C_SKYWORTH_HD_MIPI

关联到内核

在bsp/bootloader/u-boot15/drivers/video/sprd/lcd/panel_cfg.h中修改

extern struct panel_driver lcd_ili9881c_skyworth_hd_mipi_driver;

static struct panel_cfg supported_panel[] = {
#ifdef CONFIG_FB_LCD_ILI9881C_SKYWORTH_HD_MIPI
	{
 		.lcd_id = 0x988105,
 		.drv = &lcd_ili9881c_skyworth_hd_mipi_driver,
	}
}

配置LCD电源LDO

在bsp/bootloader/u-boot15/board/spreadtrum/8541e_1h10/ldo_sleep.c是能ldo

void DCDC_ldo_power_on()
{
	regulator_enable("vddgen");
	regulator_enable("vdd28");
}

在bspbootloader/u-boot15/board/spreadtrum/8541e_1h10/regulator_init.c中设置ldo电流强度

static int power_on_voltage_init(void)
{
	regulator_set_voltage("vddgen",1800);
	regulator_set_voltage("vdd28",2800);
}

编译uboot并烧录,查看LCD是否被点亮。如果没有,添加适当log查看,同时查看porch值、clk、freq是否配置正确。

配置kernel

参考已有lcd,添加dtsi文件

arch/arm/boot/dts/lcd/lcd_ili9881c_mipi_skyworth_hd.dtsi

/ { lcds {
   lcd_ili9881c_skyworth_hd_mipi_hd: lcd_ili9881c_skyworth_hd_mipi_hd {

   	sprd,dsi-work-mode = <1>;
   	sprd,dsi-lane-number = <4>;
   	sprd,dsi-color-format = "rgb888";
   	sprd,phy-bit-clock = <552000>;
   	sprd,phy-escape-clock = <20000>;
   	sprd,width-mm = <68>;
   	sprd,height-mm = <121>;
   	sprd,esd-check-enable = <0>;
   	sprd,esd-check-mode = <1>;
   	sprd,esd-check-period = <1000>;
   	sprd,reset-on-sequence = <1 5>, <0 5>, <1 20>;
   	sprd,reset-off-sequence = <0 20>;
   	sprd,initial-command = [
   				39 00 00 04 FF 98 81 03
   				23 00 00 02 01 00
   				23 00 00 02 02 00
   				......
   				13 78 00 01 11
   				13 14 00 01 29
   			];
   	sprd,sleep-in-command = [
   		13 0A 00 01 28
   		13 78 00 01 10
   		];
   	sprd,sleep-out-command = [
   		13 78 00 01 11
   		13 64 00 01 29
   		];
   	display-timings {
   		timing0 {
   			clock-frequency = <64000000>;
   			hactive = <720>;
   			vactive = <1280>;
   			hback-porch = <120>;
   			hfront-porch = <88>;
   			vback-porch = <24>;
   			vfront-porch = <16>;
   			hsync-len = <68>;
   			vsync-len = <8>;
   		};
   	};
   	oled-backlight {
   		default-brightness = <25>;
   		max-level = <255>;
   		brightness-levels = [
   			39 14 00 03 51 00 00
   			39 00 00 03 51 00 10
   			......	
   			39 00 00 03 51 0F E0
   			39 00 00 03 51 0F F0
   		];
   	};
   };
};
};

引用dtsi文件

在bsp/kernel/kernel4.14/arch/arm/boot/dts/8541e-1h10.dts中添加

#include "lcd/lcd_ili9881c_mipi_skyworth_hd.dtsi"

编译kernel并烧录,查看LCD是否被点亮。如果没有,添加适当log查看,同时查看porch值、clk、freq是否配置正确。

问题总结

问题1:u-boot阶段lcd未被点亮
解决方法:
1、添加log,查看lcd id是否读取正常,保证走正常的init流程
2、查看porch值、clk、freq是否正常,

phy_feq 理论计算
(pixelclk * 24 * 1.2)/lane_num

pixelclk理论计算
(width+hfp +hbp +hsync )*(height +vfp +vbp +vsync )*fps

问题2:kernel阶段lcd未被点亮
解决方案:
查看porch值、clk、freq是否正常,

phy_feq 理论计算
(pixelclk * 24 * 1.2)/lane_num

pixelclk理论计算
(width+hfp +hbp +hsync )*(height +vfp +vbp +vsync )*fps

问题3:背光调节有问题
解决方案
1、现有lcd背光调节方式为发命令给ic,ic自己调节,展锐默认背光调节为pwm调节,
2、修改kernel/kernel4.14/arch/arm/boot/dts/8541e-1h10-overlay.dts
将 pwm_backlight: sprd_backlight 修改为 pwm_backlight: sprd_pwm_backlight

问题3:调节背光值到最大,死机
解决方案:
背光调节时,调用的为/kernel/kernel4.14/drivers/gpu/drm/sprd/sprd_panel.c中的static int sprd_oled_set_brightness(struct backlight_device *bdev)函数,添加log发现,背光为最大值时,数据溢出,查看,发现背光brightness-levels个数为255,而struct sprd_oled中定义struct dsi_cmd_desc *cmds[255],当背光为255时,确实溢出了,因此,修改struct dsi_cmd_desc *cmds[255]为struct dsi_cmd_desc *cmds[256].

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!