Skip to content

Commit

Permalink
lk2nd: Introduce mainline panel selection
Browse files Browse the repository at this point in the history
Some devices have multiple possible panels. In that case, we need
to load different panel drivers. On downstream this is implemented
directly in the kernel, but this is difficult to implement cleanly
in mainline.

Instead, it's easier to do this as part of lk2nd. The mainline device
tree only contains a generic compatible (e.g. "motorola,harpia-panel")
with all required properties for it (e.g. GPIOs, regulators, ...).
We assume that the panels are similar enough that they all need exactly
the same properties.

The lk2nd device tree then contains a list of possible panels with
their mainline compatibles (e.g. "motorola,harpia-panel-tianma").
We can identify the panel using the "mdss_mdp.panel" parameter passed
by the primary bootloader.

When mainline is booted, we search for the "generic" compatible,
and replace it with the real one. The kernel will then probe the
correct panel. Yay!
  • Loading branch information
stephan-gh committed Jan 6, 2021
1 parent 0e502bc commit 8c15100
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 6 deletions.
83 changes: 80 additions & 3 deletions app/aboot/lk2nd-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,14 @@ static void parse_boot_args(void)
parse_arg(aboot, "carrier=", &lk2nd_dev.carrier);
parse_arg(aboot, "radio=", &lk2nd_dev.radio);
} else {
parse_arg(arg, "mdss_mdp.panel=", &lk2nd_dev.panel);
parse_arg(arg, "mdss_mdp.panel=", &lk2nd_dev.panel.name);
}

arg = strtok_r(NULL, " ", &saveptr);
}
free(args);

lk2nd_dev.panel = parse_panel(lk2nd_dev.panel);
lk2nd_dev.panel.name = parse_panel(lk2nd_dev.panel.name);
}

static const char *fdt_copyprop_str(const void *fdt, int offset, const char *prop)
Expand All @@ -134,7 +134,7 @@ static const char *fdt_copyprop_str(const void *fdt, int offset, const char *pro

val = fdt_getprop(fdt, offset, prop, &len);
if (val && len > 0) {
result = (char*) malloc(sizeof(char) * len);
result = malloc(len);
ASSERT(result);
strlcpy(result, val, len);
}
Expand Down Expand Up @@ -205,6 +205,52 @@ static int lk2nd_find_device_offset(const void *fdt)
return offset;
}

static const char *fdt_getprop_str(const void *fdt, int offset, const char *prop, int *len)
{
const char *val;

val = fdt_getprop(fdt, offset, prop, len);
if (!val || *len < 1)
return NULL;
*len = strnlen(val, *len);
return val;
}

static void lk2nd_parse_panels(const void *fdt, int offset)
{
struct lk2nd_panel *panel = &lk2nd_dev.panel;
const char *old, *new;
int old_len, new_len;

offset = fdt_subnode_offset(fdt, offset, "panel");
if (offset < 0)
return;

old = fdt_getprop_str(fdt, offset, "compatible", &old_len);
if (!old || old_len < 1)
return;

offset = fdt_subnode_offset(fdt, offset, panel->name);
if (offset < 0) {
dprintf(CRITICAL, "Unsupported panel: %s\n", panel->name);
return;
}

new = fdt_getprop_str(fdt, offset, "compatible", &new_len);
if (!new || new_len < 1)
return;

/* Include space required for null-terminators */
panel->compatible_size = ++new_len + ++old_len;

panel->compatible = malloc(panel->compatible_size);
ASSERT(panel->compatible);
panel->old_compatible = panel->compatible + new_len;

strlcpy((char*) panel->compatible, new, new_len);
strlcpy((char*) panel->old_compatible, old, old_len);
}

static void lk2nd_parse_device_node(const void *fdt)
{
int offset = lk2nd_find_device_offset(fdt);
Expand All @@ -226,6 +272,9 @@ static void lk2nd_parse_device_node(const void *fdt)

if (dev_tree_get_board_id(fdt, offset, &lk2nd_dev.board_id) == 0)
update_board_id(&lk2nd_dev.board_id);

if (lk2nd_dev.panel.name)
lk2nd_parse_panels(fdt, offset);
}


Expand Down Expand Up @@ -283,3 +332,31 @@ void lk2nd_init(void)
dump_board();
lk2nd_fdt_parse();
}

static void lk2nd_update_panel_compatible(void *fdt)
{
struct lk2nd_panel *panel = &lk2nd_dev.panel;
int offset, ret;

/* Try to find panel node */
offset = fdt_node_offset_by_compatible(fdt, -1, panel->old_compatible);
if (offset < 0) {
dprintf(CRITICAL, "Failed to find panel node with compatible: %s\n",
panel->old_compatible);
return;
}

ret = fdt_setprop(fdt, offset, "compatible", panel->compatible, panel->compatible_size);
if (ret)
dprintf(CRITICAL, "Failed to update panel compatible: %d\n", ret);
}

void lk2nd_update_device_tree(void *fdt, const char *cmdline)
{
/* Don't touch lk2nd/downstream dtb */
if (strstr(cmdline, "lk2nd"))
return;

if (lk2nd_dev.panel.compatible)
lk2nd_update_panel_compatible(fdt);
}
12 changes: 11 additions & 1 deletion app/aboot/lk2nd-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

#include <dev_tree.h>

struct lk2nd_panel {
const char *name;
const char *old_compatible;
const char *compatible;
int compatible_size;
};

struct lk2nd_device {
void *fdt;
struct board_id board_id;
Expand All @@ -17,7 +24,8 @@ struct lk2nd_device {
const char *serialno;
const char *carrier;
const char *radio;
const char *panel;

struct lk2nd_panel panel;
};

extern struct lk2nd_device lk2nd_dev;
Expand All @@ -28,4 +36,6 @@ int lk2nd_fdt_parse_early_uart(void);
void lk2nd_samsung_muic_reset(const void *fdt, int offset);
void lk2nd_motorola_smem_write_unit_info(const void *fdt, int offset);

void lk2nd_update_device_tree(void *fdt, const char *cmdline);

#endif
2 changes: 2 additions & 0 deletions platform/msm_shared/dev_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <board.h>
#include <list.h>
#include <kernel/thread.h>
#include <lk2nd-device.h>

struct dt_entry_v1
{
Expand Down Expand Up @@ -1441,6 +1442,7 @@ int update_device_tree(void *fdt, const char *cmdline,
}
}

lk2nd_update_device_tree(fdt, cmdline);
fdt_pack(fdt);

return ret;
Expand Down
4 changes: 2 additions & 2 deletions platform/msm_shared/display_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ void display_fastboot_menu_renew(struct select_msg_info *fastboot_msg_info)
msg_buf);
display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);

if (lk2nd_dev.panel) {
snprintf(msg, sizeof(msg), "PANEL - %s\n", lk2nd_dev.panel);
if (lk2nd_dev.panel.name) {
snprintf(msg, sizeof(msg), "PANEL - %s\n", lk2nd_dev.panel.name);
display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
}

Expand Down

0 comments on commit 8c15100

Please sign in to comment.