上一篇lcdservice中,会将带有lvds_parameter=8_800_480类似的屏幕标志写入misc分区指定位置,重启系统后uboot会从misc分区中读出lvds_parameter=8_800_480标志,然后在设备树中查找与标志对应的lvds屏幕配置节点,并配置相应的节点。
1、uboot读取misc分区指定数据
u-boot/drivers/video/rockchip_display.c
#if 1
extern const disk_partition_t* get_disk_partition(const char *name);
extern int StorageReadLba(uint32 LBA, void *pbuf, uint32 nSec);
#define CUSTOM_PARTITION_NAME "misc"
#define LCD_PARAM_MAX_COUNT 25
int lcdParam[LCD_PARAM_MAX_COUNT];
char param_buf_temp[100] = {0};
int get_lcdparam_info_from_custom_partition()
{
const disk_partition_t *ptn1 = get_disk_partition(CUSTOM_PARTITION_NAME);
int i;
if (!ptn1) {
printf("OEM partition not found!\n");
return -1;
}
printf("block num: %lu, name %s ,type %s,block size :%lu\n",ptn1->size,ptn1->name,ptn1->type,ptn1->blksz);
if (StorageReadLba(ptn1->start+2, param_buf_temp, DIV_ROUND_UP(sizeof(param_buf_temp), RK_BLK_SIZE)) != 0) {
printf("failed to read oem!\n");
return -1;
}
printf("%s \n",param_buf_temp);
return 0;
}
#endif
需要注意ptn1->start指针一次偏移512个字节。
2、校验屏幕标志,获取设备树屏幕节点
u-boot/drivers/video/rockchip_display.c
static char *get_screen_para(void *blob, int parent_node, char *screen_buf,int len)
{
if((screen_buf == NULL) || (len <= 0) || (parent_node <= 0))
return NULL;
memset(screen_buf,'\0',len);
if(strstr(param_buf_temp, "7_800_480_18") || strstr(param_buf_temp, "7_800_480_24")) {
strcpy(screen_buf,"inch8rgb");
} else if(strstr(param_buf_temp, "10_4_1024_768")) {
strcpy(screen_buf,"g104x1-l04");
} else if(strstr(param_buf_temp, "15_1024_768")) {
strcpy(screen_buf,"ldb15xga");
} else if(strstr(param_buf_temp, "17_1280_1024")) {
strcpy(screen_buf,"M170ETN01");
} else if(strstr(param_buf_temp, "19_1440_900")) {
strcpy(screen_buf,"M190PW01");
} else if(strstr(param_buf_temp, "21_5_1920_1080")) {
strcpy(screen_buf,"t215hvn01");
} else if(strstr(param_buf_temp, "32_1920_1080")) {
strcpy(screen_buf,"LD320DUE");
} else if(strstr(param_buf_temp, "10_1_1280_800")) {
strcpy(screen_buf,"g101ice");
} else {
printf("no find screen\n");
return NULL;
}
int i = 0,ret = 0;
char *output = NULL;
for (i=parent_node;i>=0;i++)
{
output = (char *)fdt_getprop_by_offset(blob, i, NULL, &ret);
if (output != NULL) {
if((strncmp(output, "duallvds", 8)==0) || (strncmp(output, "lvds", 4)==0)) {
printf("****output: %s -- offset : %d\n",output,i);
break;
}
}
}
return screen_buf;
}
3、查找设备树中屏幕配置节点,并修改为新设置的节点
u-boot/drivers/video/rockchip_display.c
static int fdt_fixup_display_sub_route(void *blob, const char *name,
enum fdt_status status)
{
int route, phandle, connect, connector, panel, dt, timing;
char path[64];
int ret;
int offset = 0;
int len;
char *screen_node = NULL;
char screen_buf[20] = {0};
char *screen_name = NULL;
sprintf(path, "/display-subsystem/route/route-%s", name);
route = fdt_path_offset(blob, path);
if (route < 0)
return route;
/* fixup route status */
ret = fdt_fixup_node_status(blob, route, status);
if (ret < 0)
return ret;
phandle = fdt_getprop_u32_default_node(blob, route, 0, "connect", -1);
if (phandle < 0)
return phandle;
connect = fdt_node_offset_by_phandle(blob, phandle);
if (connect < 0)
return connect;
connector = find_connector_node(blob, connect);
if (connector < 0)
return connector;
/* fixup connector status */
ret = fdt_fixup_node_status(blob, connector, status);
if (ret < 0)
return ret;
if (status != FDT_STATUS_OKAY)
return 0;
panel = get_panel_node(blob, connector);
if (panel < 0)
return panel;
dt = fdt_subnode_offset(blob, panel, "display-timings");
if (dt < 0)
return dt;
timing = fdt_subnode_offset(blob, dt, "timing");
if (timing < 0) {
phandle = fdt_getprop_u32_default_node(blob, dt, 0, "native-mode", -1);
if (phandle < 0)
return phandle;
timing = fdt_node_offset_by_phandle_node(blob, dt, phandle);
if (timing < 0)
return timing;
}
screen_name = get_screen_para(blob,panel,screen_buf,sizeof(screen_buf));
if(screen_name == NULL) {
return -1;
} else{
ret = fdt_set_phandle(blob,timing,0);
}
for(offset = dt;(offset >=0);(offset = fdt_next_node(blob, offset,&len))) {
screen_node = fdt_get_name(blob,offset,&len);
printf("name = %s -- offset = %d\n",screen_node,offset);
if (screen_node != NULL) {
if(strncmp(screen_buf,screen_node,strlen(screen_node)) == 0) {
printf("offset = %d -- name = %s\n", offset, fdt_get_name(blob,offset,&len));
break;
}
}
}
fdt_set_phandle(blob,offset,phandle);
uint32_t screen_7_18 = 18;
uint32_t screen_7_24 = 24;
if(strstr(param_buf_temp, "7_800_480_18")) {
fdt_setprop_u32(blob,panel,"rockchip,data-width",screen_7_18);
} else {
fdt_setprop_u32(blob,panel,"rockchip,data-width",screen_7_24);
}
if((strcmp(screen_buf,"inch8rgb")==0) || (strcmp(screen_buf,"g104x1-l04")==0) || (strcmp(screen_buf,"g101ice")==0) || (strcmp(screen_buf,"ldb15xga")==0)) {
fdt_setprop_string(blob,panel,"rockchip,output","lvds");
} else if ((strcmp(screen_buf,"M170ETN01")==0) || (strcmp(screen_buf,"M190PW01")==0) || (strcmp(screen_buf,"t215hvn01")==0) || (strcmp(screen_buf,"LD320DUE")==0)) {
fdt_setprop_string(blob,panel,"rockchip,output","duallvds");
}
int i = 0;
char *output = NULL;
for (i=panel;i>=0;i++)
{
output = (char *)fdt_getprop_by_offset(blob, i, NULL, &ret);
if (output != NULL) {
if((strncmp(output, "duallvds", 8)==0) || (strncmp(output, "lvds", 4)==0)) {
printf("output: %s -- offset : %d\n",output,i);
break;
}
}
}
return 0;
}
设备树修改完成后,uboot正常引导内核启动,内核加载新的设备树,启动后会按照新的屏幕显示。
注意事项:lvds屏幕默认电压不一致,有时可能会出现电压过高烧屏问题,建议在修改屏幕参数时接hdmi屏幕或使用adb投屏方式
adb投屏软件:
链接:https://pan.baidu.com/s/1fYxbAhyBsM-ugB6WqiIeww
提取码:xite