/*
|
* (C) Copyright 2019 Rockchip Electronics Co., Ltd
|
*
|
* SPDX-License-Identifier: GPL-2.0+
|
*/
|
#include <common.h>
|
#include <boot_rkimg.h>
|
#include <dm.h>
|
#include <malloc.h>
|
#include <of_live.h>
|
#include <dm/device-internal.h>
|
#include <dm/root.h>
|
#include <dm/uclass-internal.h>
|
#include <asm/arch/hotkey.h>
|
#include <asm/arch/resource_img.h>
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
#if 1
|
struct display_fixup_data {
|
int type;
|
|
int delay_prepare;
|
int delay_enable;
|
int delay_disable;
|
int delay_unprepare;
|
int delay_reset;
|
int delay_init;
|
int size_width;
|
int size_height;
|
|
int clock_frequency;
|
int hactive;
|
int hfront_porch;
|
int hsync_len;
|
int hback_porch;
|
int vactive;
|
int vfront_porch;
|
int vsync_len;
|
int vback_porch;
|
int hsync_active;
|
int vsync_active;
|
int de_active;
|
int pixelclk_active;
|
|
/* for DSI Panel */
|
int flags;
|
int format;
|
int lanes;
|
int init_cmd_length;
|
u8 *init_cmd;
|
|
int nodka_lvds;
|
};
|
enum {
|
PANEL_TYPE_DSI,
|
PANEL_TYPE_EDP,
|
PANEL_TYPE_LVDS,
|
};
|
|
#define CUSTOM_PARTITION_NAME "baseparameter"
|
#define LCD_PARAM_MAX_COUNT 27
|
|
int lcdParam[LCD_PARAM_MAX_COUNT];
|
char param_buf_temp[4*1024] = {0};
|
|
void set_lcdparam_test_edp(struct display_fixup_data *data)
|
{
|
|
data->type = PANEL_TYPE_DSI;
|
data->delay_prepare = 100;
|
data->delay_enable = 100;
|
data->delay_disable = 100;
|
data->delay_unprepare = 100;
|
data->delay_reset = 100;
|
data->delay_init = 100;
|
data->size_width = 240;
|
data->size_height = 300;
|
data->clock_frequency = 60000000;
|
data->hactive = 1024;
|
data->hfront_porch = 12;
|
data->hsync_len = 16;
|
data->hback_porch = 48;
|
data->vactive = 600;
|
data->vfront_porch = 8;
|
data->vsync_len = 4;
|
data->vback_porch = 8;
|
data->hsync_active = 0;
|
data->vsync_active = 0;
|
data->de_active = 0;
|
data->pixelclk_active = 0;
|
data->flags = 0;
|
data->format = 0;
|
data->lanes = 4;
|
*(data->init_cmd + 0) = 0x05;
|
*(data->init_cmd + 1) = 0x00;
|
*(data->init_cmd + 2) = 0x01;
|
*(data->init_cmd + 3) = 0x01;
|
|
*(data->init_cmd + 4) = 0x05;
|
*(data->init_cmd + 5) = 0x00;
|
*(data->init_cmd + 6) = 0x01;
|
*(data->init_cmd + 7) = 0x02;
|
|
*(data->init_cmd + 8) = 0x05;
|
*(data->init_cmd + 9) = 0x00;
|
*(data->init_cmd + 10) = 0x01;
|
*(data->init_cmd + 11) = 0x03;
|
|
*(data->init_cmd + 12) = 0x05;
|
*(data->init_cmd + 13) = 0x00;
|
*(data->init_cmd + 14) = 0x01;
|
*(data->init_cmd + 15) = 0x05;
|
|
}
|
|
int get_lcdparam_info_from_custom_partition(struct display_fixup_data *data)
|
{
|
|
struct blk_desc *dev_desc;
|
disk_partition_t part_info;
|
char *boot_partname = CUSTOM_PARTITION_NAME;
|
int ret,i;
|
|
dev_desc = rockchip_get_bootdev();
|
if (!dev_desc) {
|
printf("%s: dev_desc is NULL!\n", __func__);
|
return -ENODEV;
|
}
|
|
ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
|
if (ret < 0) {
|
printf("%s: failed to get %s part, ret=%d\n",
|
__func__, boot_partname, ret);
|
/* RKIMG can support part table without 'boot' */
|
return -1;
|
}
|
|
printf("block num: %lu, name %s ,type %s,block size :%lu\n",part_info.size,part_info.name,part_info.type,part_info.blksz);
|
|
ret = blk_dread(dev_desc, part_info.start + 512, 1, param_buf_temp);
|
if (ret != 1) {
|
printf("%s: failed to read screen parameter, ret=%d\n",
|
__func__, ret);
|
return -1;
|
}
|
|
for (i = 0; i < LCD_PARAM_MAX_COUNT; i++) {
|
lcdParam[i] = param_buf_temp[i * 4];
|
lcdParam[i] = (lcdParam[i] << 8) + param_buf_temp[i * 4 + 1];
|
lcdParam[i] = (lcdParam[i] << 8) + param_buf_temp[i * 4 + 2];
|
lcdParam[i] = (lcdParam[i] << 8) + param_buf_temp[i * 4 + 3];
|
if(lcdParam[i] < 0){
|
lcdParam[i] = -lcdParam[i];
|
}
|
if(lcdParam[i] > 100000 && i != 9){
|
lcdParam[i] = 0;
|
}
|
printf("--get-- lcd_param %d\n",lcdParam[i]);
|
}
|
|
if(lcdParam[14] == 0 || lcdParam[10] == 0){
|
return -1;
|
}
|
printf("-get- crc32 = 0X%02X%02X%02X%02X\n",
|
param_buf_temp[LCD_PARAM_MAX_COUNT * 4], param_buf_temp[LCD_PARAM_MAX_COUNT * 4 + 1],
|
param_buf_temp[LCD_PARAM_MAX_COUNT * 4 + 2], param_buf_temp[LCD_PARAM_MAX_COUNT * 4 + 3]);
|
|
data->type = lcdParam[0];
|
data->delay_prepare = lcdParam[4];
|
data->delay_enable = lcdParam[2];
|
data->delay_disable = lcdParam[3];
|
data->delay_unprepare = lcdParam[1];
|
data->delay_reset = lcdParam[5];
|
data->delay_init = lcdParam[6];
|
data->size_width = lcdParam[7];
|
data->size_height = lcdParam[8];
|
data->clock_frequency = lcdParam[9];
|
data->hactive = lcdParam[10];
|
data->hfront_porch = lcdParam[11];
|
data->hsync_len = lcdParam[12];
|
data->hback_porch = lcdParam[13];
|
data->vactive = lcdParam[14];
|
data->vfront_porch = lcdParam[15];
|
data->vsync_len = lcdParam[16];
|
data->vback_porch = lcdParam[17];
|
data->hsync_active = lcdParam[18];
|
data->vsync_active = lcdParam[19];
|
data->de_active = lcdParam[20];
|
data->pixelclk_active = lcdParam[21];
|
data->flags = lcdParam[22];
|
data->format = lcdParam[23];
|
data->lanes = lcdParam[24];
|
data->init_cmd_length = lcdParam[25] = 16;
|
data->nodka_lvds = lcdParam[26];
|
data->init_cmd = malloc(sizeof(*(data->init_cmd)) * data->init_cmd_length);
|
for(i = 0; i < data->init_cmd_length; i++){
|
*(data->init_cmd + i) = param_buf_temp[100 + i];
|
// printf("init cmd = %x\n",param_buf_temp[100 + i]);
|
|
}
|
|
// set_lcdparam_test_edp(data);
|
|
return 0;
|
}
|
|
#endif
|
|
|
static int find_connector_node(const void *blob, int node)
|
{
|
int phandle, remote;
|
int nodedepth;
|
|
phandle = fdt_getprop_u32_default_node(blob, node, 0,
|
"remote-endpoint", -1);
|
remote = fdt_node_offset_by_phandle(blob, phandle);
|
nodedepth = fdt_node_depth(blob, remote);
|
|
return fdt_supernode_atdepth_offset(blob, remote,
|
nodedepth - 3, NULL);
|
}
|
|
static int get_panel_node(const void *blob, int conn_node)
|
{
|
int panel, ports, port, ep, remote, ph, nodedepth;
|
|
panel = fdt_subnode_offset(blob, conn_node, "panel");
|
printf("panel_1=%d\n",panel);
|
if (panel > 0) {
|
return panel;
|
}
|
|
ports = fdt_subnode_offset(blob, conn_node, "ports");
|
if (ports < 0)
|
{
|
return -ENODEV;
|
}
|
|
fdt_for_each_subnode(port, blob, ports) {
|
fdt_for_each_subnode(ep, blob, port) {
|
ph = fdt_getprop_u32_default_node(blob, ep, 0,
|
"remote-endpoint", 0);
|
if (!ph)
|
continue;
|
|
remote = fdt_node_offset_by_phandle(blob, ph);
|
|
nodedepth = fdt_node_depth(blob, remote);
|
if (nodedepth < 2)
|
continue;
|
|
panel = fdt_supernode_atdepth_offset(blob, remote,
|
nodedepth - 2,
|
NULL);
|
break;
|
}
|
}
|
printf("panel_2=%d\n",panel);
|
return panel;
|
}
|
|
static int fdt_fixup_node_status(void *blob, int node, enum fdt_status status)
|
{
|
int ret;
|
|
// printf("My fixup %s %d\n", fdt_get_name(blob, node, NULL), status);
|
|
set_status:
|
ret = fdt_set_node_status(blob, node, status, 0);
|
if (ret == -FDT_ERR_NOSPACE) {
|
ret = fdt_increase_size(blob, 512);
|
if (!ret)
|
goto set_status;
|
else
|
goto err_size;
|
} else if (ret < 0) {
|
printf("Can't set node status: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
|
return 0;
|
|
err_size:
|
printf("Can't increase blob size: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
#if 0
|
static int fdt_fixup_panel_init_sequence(void *fdt, int node,const struct display_fixup_data *data)
|
{
|
#if 0
|
u8 init_buf[] = {0x05, 0x00, 0x01, 0x78, 0x15, 0x01, 0x02, 0x03, 0x04, 0x05, 0x05, 0x01, 0x14,0x39, 0x01, 0x03, 0x02, 0x29, 0x11};
|
u8 exit_buf[] = {0x05, 0x64, 0x01, 0x29, 0x05, 0x64, 0x01, 0x11};
|
#endif
|
int ret;
|
|
add_seq:
|
ret = fdt_setprop(fdt, node, "panel-init-sequence", data->init_cmd, data->init_cmd_length);
|
if (ret == -FDT_ERR_NOSPACE) {
|
printf(" init sequence FDT_ERR_NOSPACE\n");
|
ret = fdt_increase_size(fdt, data->init_cmd_length * 4);//gln the length needs precision
|
if (!ret)
|
goto add_seq;
|
else
|
goto err_size;
|
} else if (ret < 0) {
|
printf("Can't add property: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
|
#if 0
|
add_init_seq:
|
ret = fdt_setprop(fdt, node, "panel-init-sequence", init_buf, sizeof(init_buf));
|
if (ret == -FDT_ERR_NOSPACE) {
|
printf(" init sequence FDT_ERR_NOSPACE\n");
|
ret = fdt_increase_size(fdt, 512);//gln the length needs precision
|
if (!ret)
|
goto add_init_seq;
|
else
|
goto err_size;
|
} else if (ret < 0) {
|
printf("Can't add property: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
add_exit_seq:
|
ret = fdt_setprop(fdt, node, "panel-exit-sequence", exit_buf, sizeof(exit_buf));
|
if (ret == -FDT_ERR_NOSPACE) {
|
printf(" init sequence FDT_ERR_NOSPACE\n");
|
ret = fdt_increase_size(fdt, 512);//gln the length needs precision
|
if (!ret)
|
goto add_exit_seq;
|
else
|
goto err_size;
|
} else if (ret < 0) {
|
printf("Can't add property: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
#endif
|
|
return 0;
|
|
err_size:
|
printf("Can't increase blob size: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
#endif
|
|
static int fdt_fixup_setprop_u32(void *fdt, int node, const char *name, u32 data)
|
{
|
int ret;
|
|
set_prop:
|
ret = fdt_setprop_u32(fdt, node, name, data);
|
if (ret == -FDT_ERR_NOSPACE) {
|
ret = fdt_increase_size(fdt, 512);
|
if (!ret)
|
goto set_prop;
|
else
|
goto err_size;
|
} else if (ret < 0) {
|
printf("Can't add property: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
|
return 0;
|
|
err_size:
|
printf("Can't increase blob size: %s\n", fdt_strerror(ret));
|
return ret;
|
}
|
|
static void fdt_fixup_display_timing(void *blob, int node,
|
const struct display_fixup_data *data)
|
{
|
fdt_fixup_setprop_u32(blob, node, "clock-frequency", data->clock_frequency);
|
fdt_fixup_setprop_u32(blob, node, "hactive", data->hactive);
|
fdt_fixup_setprop_u32(blob, node, "hfront-porch", data->hfront_porch);
|
fdt_fixup_setprop_u32(blob, node, "hsync-len", data->hsync_len);
|
fdt_fixup_setprop_u32(blob, node, "hback-porch", data->hback_porch);
|
fdt_fixup_setprop_u32(blob, node, "vactive", data->vactive);
|
fdt_fixup_setprop_u32(blob, node, "vfront-porch", data->vfront_porch);
|
fdt_fixup_setprop_u32(blob, node, "vsync-len", data->vsync_len);
|
fdt_fixup_setprop_u32(blob, node, "vback-porch", data->vback_porch);
|
fdt_fixup_setprop_u32(blob, node, "hsync-active", data->hsync_active);
|
fdt_fixup_setprop_u32(blob, node, "vsync-active", data->vsync_active);
|
fdt_fixup_setprop_u32(blob, node, "de-active", data->de_active);
|
fdt_fixup_setprop_u32(blob, node, "pixelclk-active", data->pixelclk_active);
|
}
|
|
static void fdt_fixup_panel_node(void *blob, int node, const char *name,
|
const struct display_fixup_data *data)
|
{
|
/*
|
if (!strcmp(name, "dsi")) {
|
fdt_setprop_u32(blob, node, "dsi,flags", data->flags);
|
fdt_setprop_u32(blob, node, "dsi,format", data->format);
|
fdt_setprop_u32(blob, node, "dsi,lanes", data->lanes);
|
fdt_fixup_panel_init_sequence(blob, node,data);
|
}
|
*/
|
fdt_fixup_setprop_u32(blob, node, "prepare-delay-ms", data->delay_prepare);
|
fdt_fixup_setprop_u32(blob, node, "enable-delay-ms", data->delay_enable);
|
fdt_fixup_setprop_u32(blob, node, "disable-delay-ms", data->delay_disable);
|
fdt_fixup_setprop_u32(blob, node, "unprepare-delay-ms", data->delay_unprepare);
|
fdt_fixup_setprop_u32(blob, node, "reset-delay-ms", data->delay_reset);
|
fdt_fixup_setprop_u32(blob, node, "init-delay-ms", data->delay_init);
|
fdt_fixup_setprop_u32(blob, node, "width-mm", data->size_width);
|
fdt_fixup_setprop_u32(blob, node, "height-mm", data->size_height);
|
|
}
|
static void fdt_fixup_nodka_lvds(void *blob, int node,
|
const struct display_fixup_data *data)
|
{
|
if ( data->nodka_lvds != 0 )
|
fdt_fixup_setprop_u32(blob, node, "nodka-lvds", data->nodka_lvds);
|
}
|
|
|
static int fdt_fixup_display_sub_route(void *blob, const char *name,
|
enum fdt_status status,
|
const struct display_fixup_data *data)
|
{
|
int route, phandle, connect, connector, panel, dt, timing, route_lvds;
|
char path[64];
|
char path_lvds[16] = "/panel";
|
int ret;
|
sprintf(path, "/display-subsystem/route/route-%s", name);
|
|
|
route = fdt_path_offset(blob, path);
|
printf("route : %d \n",route);
|
if (route < 0)
|
return route;
|
|
route_lvds = fdt_path_offset(blob, path_lvds);
|
if (route_lvds < 0)
|
{
|
printf("can not get route_lvds = %d\n",route_lvds);
|
return route_lvds;
|
}
|
/* fixup lvds gpio channel*/
|
fdt_fixup_nodka_lvds(blob, route_lvds, data);
|
|
/* 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;
|
/* fixup panel info */
|
fdt_fixup_panel_node(blob, panel, name, data);
|
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(blob, phandle);
|
if (timing < 0)
|
return timing;
|
}
|
|
/* fixup panel display timing */
|
fdt_fixup_display_timing(blob, timing, data);
|
return 0;
|
}
|
|
static void fdt_fixup_display_route(void *blob, const struct display_fixup_data *data)
|
{
|
if (data->type == PANEL_TYPE_DSI) {
|
fdt_fixup_display_sub_route(blob, "dsi0", FDT_STATUS_OKAY, data);
|
fdt_fixup_display_sub_route(blob, "edp1", FDT_STATUS_DISABLED, data);
|
fdt_fixup_display_sub_route(blob, "lvds", FDT_STATUS_DISABLED, data);
|
} else if (data->type == PANEL_TYPE_EDP) {
|
fdt_fixup_display_sub_route(blob, "dsi0", FDT_STATUS_DISABLED, data);
|
fdt_fixup_display_sub_route(blob, "edp1", FDT_STATUS_OKAY, data);
|
fdt_fixup_display_sub_route(blob, "lvds", FDT_STATUS_DISABLED, data);
|
} else if (data->type == PANEL_TYPE_LVDS) {
|
fdt_fixup_display_sub_route(blob, "lvds", FDT_STATUS_OKAY, data);
|
fdt_fixup_display_sub_route(blob, "dsi0", FDT_STATUS_DISABLED, data);
|
fdt_fixup_display_sub_route(blob, "edp1", FDT_STATUS_DISABLED, data);
|
}
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_USING_KERNEL_DTB_V2
|
static int dm_rm_kernel_dev(void)
|
{
|
struct udevice *dev, *rec[10];
|
u32 uclass[] = { UCLASS_CRYPTO };
|
int i, j, k;
|
|
for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) {
|
for (uclass_find_first_device(uclass[i], &dev); dev;
|
uclass_find_next_device(&dev)) {
|
if (dev->flags & DM_FLAG_KNRL_DTB)
|
rec[j++] = dev;
|
}
|
|
for (k = 0; k < j; k++) {
|
device_remove(rec[k], DM_REMOVE_NORMAL);
|
device_unbind(rec[k]);
|
}
|
}
|
|
return 0;
|
}
|
|
static int dm_rm_u_boot_dev(void)
|
{
|
struct udevice *dev, *rec[10];
|
u32 uclass[] = { UCLASS_ETH };
|
int del = 0;
|
int i, j, k;
|
|
for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) {
|
for (uclass_find_first_device(uclass[i], &dev); dev;
|
uclass_find_next_device(&dev)) {
|
if (dev->flags & DM_FLAG_KNRL_DTB)
|
del = 1;
|
else
|
rec[j++] = dev;
|
}
|
|
/* remove u-boot dev if there is someone from kernel */
|
if (del) {
|
for (k = 0; k < j; k++) {
|
device_remove(rec[k], DM_REMOVE_NORMAL);
|
device_unbind(rec[k]);
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
#else
|
/* Here, only fixup cru phandle, pmucru is not included */
|
static int phandles_fixup_cru(const void *fdt)
|
{
|
const char *props[] = { "clocks", "assigned-clocks", "resets"};
|
struct udevice *dev;
|
struct uclass *uc;
|
const char *comp;
|
u32 id, nclocks;
|
u32 *clocks;
|
int phandle, ncells;
|
int off, offset;
|
int ret, length;
|
int i, j;
|
int first_phandle = -1;
|
|
phandle = -ENODATA;
|
ncells = -ENODATA;
|
|
/* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */
|
for (offset = fdt_next_node(fdt, 0, NULL);
|
offset >= 0;
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
comp = fdt_getprop(fdt, offset, "compatible", NULL);
|
if (!comp)
|
continue;
|
|
/* Actually, this is not a good method to get cru node */
|
off = strlen(comp) - strlen("-cru");
|
if (off > 0 && !strncmp(comp + off, "-cru", 4)) {
|
phandle = fdt_get_phandle(fdt, offset);
|
ncells = fdtdec_get_int(fdt, offset,
|
"#clock-cells", -ENODATA);
|
break;
|
}
|
}
|
|
if (phandle == -ENODATA || ncells == -ENODATA)
|
return 0;
|
|
debug("%s: target cru: clock-cells:%d, phandle:0x%x\n",
|
__func__, ncells, fdt32_to_cpu(phandle));
|
|
/* Try to fixup all cru phandle from U-Boot dtb nodes */
|
for (id = 0; id < UCLASS_COUNT; id++) {
|
ret = uclass_get(id, &uc);
|
if (ret)
|
continue;
|
|
if (list_empty(&uc->dev_head))
|
continue;
|
|
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
|
/* Only U-Boot node go further */
|
if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") &&
|
!dev_read_bool(dev, "u-boot,dm-spl"))
|
continue;
|
|
for (i = 0; i < ARRAY_SIZE(props); i++) {
|
if (!dev_read_prop(dev, props[i], &length))
|
continue;
|
|
clocks = malloc(length);
|
if (!clocks)
|
return -ENOMEM;
|
|
/* Read "props[]" which contains cru phandle */
|
nclocks = length / sizeof(u32);
|
if (dev_read_u32_array(dev, props[i],
|
clocks, nclocks)) {
|
free(clocks);
|
continue;
|
}
|
|
/* Fixup with kernel cru phandle */
|
for (j = 0; j < nclocks; j += (ncells + 1)) {
|
/*
|
* Check: update pmucru phandle with cru
|
* phandle by mistake.
|
*/
|
if (first_phandle == -1)
|
first_phandle = clocks[j];
|
|
if (clocks[j] != first_phandle) {
|
debug("WARN: %s: first cru phandle=%d, this=%d\n",
|
dev_read_name(dev),
|
first_phandle, clocks[j]);
|
continue;
|
}
|
|
clocks[j] = phandle;
|
}
|
|
/*
|
* Override live dt nodes but not fdt nodes,
|
* because all U-Boot nodes has been imported
|
* to live dt nodes, should use "dev_xxx()".
|
*/
|
dev_write_u32_array(dev, props[i],
|
clocks, nclocks);
|
free(clocks);
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
static int phandles_fixup_gpio(const void *fdt, void *ufdt)
|
{
|
struct udevice *dev;
|
struct uclass *uc;
|
const char *prop = "gpios";
|
const char *comp;
|
char *gpio_name[10];
|
int gpio_off[10];
|
int pinctrl;
|
int offset;
|
int i = 0;
|
int n = 0;
|
|
pinctrl = fdt_path_offset(fdt, "/pinctrl");
|
if (pinctrl < 0)
|
return 0;
|
|
memset(gpio_name, 0, sizeof(gpio_name));
|
for (offset = fdt_first_subnode(fdt, pinctrl);
|
offset >= 0;
|
offset = fdt_next_subnode(fdt, offset)) {
|
/* assume the font nodes are gpio node */
|
if (++i >= ARRAY_SIZE(gpio_name))
|
break;
|
|
comp = fdt_getprop(fdt, offset, "compatible", NULL);
|
if (!comp)
|
continue;
|
|
if (!strcmp(comp, "rockchip,gpio-bank")) {
|
gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL);
|
gpio_off[n] = offset;
|
n++;
|
}
|
}
|
|
if (!gpio_name[0])
|
return 0;
|
|
if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head))
|
return 0;
|
|
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
|
u32 new_phd, phd_old;
|
char *name;
|
ofnode ofn;
|
|
if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") &&
|
!dev_read_bool(dev, "u-boot,dm-spl"))
|
continue;
|
|
if (dev_read_u32_array(dev, prop, &phd_old, 1))
|
continue;
|
|
ofn = ofnode_get_by_phandle(phd_old);
|
if (!ofnode_valid(ofn))
|
continue;
|
|
name = (char *)ofnode_get_name(ofn);
|
if (!name)
|
continue;
|
|
for (i = 0; i < ARRAY_SIZE(gpio_name); i++) {
|
if (gpio_name[i] && !strcmp(name, gpio_name[i])) {
|
new_phd = fdt_get_phandle(fdt, gpio_off[i]);
|
dev_write_u32_array(dev, prop, &new_phd, 1);
|
break;
|
}
|
}
|
}
|
|
return 0;
|
}
|
#endif
|
|
__weak int board_mmc_dm_reinit(struct udevice *dev)
|
{
|
return 0;
|
}
|
|
static int mmc_dm_reinit(void)
|
{
|
struct udevice *dev;
|
struct uclass *uc;
|
int ret;
|
|
if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head))
|
return 0;
|
|
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
|
ret = board_mmc_dm_reinit(dev);
|
if (ret)
|
return ret;
|
}
|
|
return 0;
|
}
|
|
/* Check by property: "/compatible" */
|
static int dtb_check_ok(void *kfdt, void *ufdt)
|
{
|
const char *compat;
|
int index;
|
|
/* TODO */
|
return 1;
|
|
for (index = 0;
|
compat = fdt_stringlist_get(ufdt, 0, "compatible",
|
index, NULL), compat;
|
index++) {
|
debug("u-compat: %s\n", compat);
|
if (!fdt_node_check_compatible(kfdt, 0, compat))
|
return 1;
|
}
|
|
return 0;
|
}
|
|
int init_kernel_dtb(void)
|
{
|
#ifndef CONFIG_USING_KERNEL_DTB_V2
|
void *ufdt_blob = (void *)gd->fdt_blob;
|
#endif
|
ulong fdt_addr = 0;
|
int ret = -ENODEV;
|
struct display_fixup_data fix_data;
|
|
printf("DM: v%d\n", IS_ENABLED(CONFIG_USING_KERNEL_DTB_V2) ? 2 : 1);
|
|
/*
|
* If memory size <= 128MB, we firstly try to get "fdt_addr1_r".
|
*/
|
if (gd->ram_size <= SZ_128M)
|
fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0);
|
|
if (!fdt_addr)
|
fdt_addr = env_get_ulong("fdt_addr_r", 16, 0);
|
if (!fdt_addr) {
|
printf("No Found FDT Load Address.\n");
|
return -ENODEV;
|
}
|
|
#ifdef CONFIG_EMBED_KERNEL_DTB_ALWAYS
|
printf("Always embed kernel dtb\n");
|
goto dtb_embed;
|
#endif
|
ret = rockchip_read_dtb_file((void *)fdt_addr);
|
if (!ret) {
|
if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) {
|
ret = -EINVAL;
|
printf("Kernel dtb mismatch this platform!\n");
|
} else {
|
goto dtb_okay;
|
}
|
}
|
|
#ifdef CONFIG_EMBED_KERNEL_DTB
|
#ifdef CONFIG_EMBED_KERNEL_DTB_ALWAYS
|
dtb_embed:
|
#endif
|
if (gd->fdt_blob_kern) {
|
if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) {
|
printf("Embedded kernel dtb mismatch this platform!\n");
|
return -EINVAL;
|
}
|
|
fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN,
|
fdt_totalsize(gd->fdt_blob_kern));
|
if (!fdt_addr)
|
return -ENOMEM;
|
|
/*
|
* Alloc another space for this embed kernel dtb.
|
* Because "fdt_addr_r" *MUST* be the fdt passed to kernel.
|
*/
|
memcpy((void *)fdt_addr, gd->fdt_blob_kern,
|
fdt_totalsize(gd->fdt_blob_kern));
|
printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH);
|
} else
|
#endif
|
{
|
printf("Failed to get kernel dtb, ret=%d\n", ret);
|
return -ENOENT;
|
}
|
|
dtb_okay:
|
gd->fdt_blob = (void *)fdt_addr;
|
hotkey_run(HK_FDT);
|
|
#ifndef CONFIG_USING_KERNEL_DTB_V2
|
/*
|
* There is a phandle miss match between U-Boot and kernel dtb node,
|
* we fixup it in U-Boot live dt nodes.
|
*
|
* CRU: all nodes.
|
* GPIO: key nodes.
|
*/
|
phandles_fixup_cru((void *)gd->fdt_blob);
|
phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob);
|
#endif
|
if (!get_lcdparam_info_from_custom_partition(&fix_data))
|
fdt_fixup_display_route((void *)fdt_addr, &fix_data);
|
|
gd->flags |= GD_FLG_KDTB_READY;
|
gd->of_root_f = gd->of_root;
|
of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root);
|
dm_scan_fdt((void *)gd->fdt_blob, false);
|
|
#ifdef CONFIG_USING_KERNEL_DTB_V2
|
dm_rm_kernel_dev();
|
dm_rm_u_boot_dev();
|
#endif
|
/*
|
* There maybe something for the mmc devices to do after kernel dtb
|
* dm setup, eg: regain the clock device binding from kernel dtb.
|
*/
|
mmc_dm_reinit();
|
|
/* Reserve 'reserved-memory' */
|
ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob);
|
if (ret)
|
return ret;
|
|
return 0;
|
}
|