board: rockchip: Convert Anbernic RGxx3 to OF_UPSTREAM

Refactor the board detection logic (again) to make it compatible with
the upstream device-trees, and switch to OF_UPSTREAM.

Now the device boots with the device-tree for the 353P, and then
loads the correct device tree (of 10) in the later stages of SPL.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
This commit is contained in:
Chris Morgan
2024-09-19 09:00:19 -05:00
committed by Kever Yang
parent 609e71e68e
commit 7344fa41a2
6 changed files with 195 additions and 147 deletions

View File

@@ -4,6 +4,4 @@ S: Maintained
F: board/anbernic/rgxx3_rk3566
F: include/configs/anbernic-rgxx3-rk3566.h
F: configs/anbernic-rgxx3-rk3566_defconfig
F: arch/arm/dts/rk3566-anbernic-rgxx3.dts
F: arch/arm/dts/rk3566-anbernic-rgxx3.dtsi
F: arch/arm/dts/rk3566-anbernic-rgxx3-u-boot.dtsi
F: arch/arm/dts/rk3566-anbernic-rg353p-u-boot.dtsi

View File

@@ -11,6 +11,7 @@
#include <dm/lists.h>
#include <env.h>
#include <fdt_support.h>
#include <i2c.h>
#include <linux/delay.h>
#include <mipi_dsi.h>
#include <mmc.h>
@@ -19,6 +20,8 @@
#include <stdlib.h>
#include <video_bridge.h>
DECLARE_GLOBAL_DATA_PTR;
#define GPIO0_BASE 0xfdd60000
#define GPIO4_BASE 0xfe770000
#define GPIO_SWPORT_DR_L 0x0000
@@ -40,10 +43,11 @@ struct rg3xx_model {
const char *board_name;
const char *fdtfile;
const bool detect_panel;
const bool uart_con;
};
enum rgxx3_device_id {
RG353M,
RG353M = 1,
RG353P,
RG353V,
RG503,
@@ -61,45 +65,51 @@ static const struct rg3xx_model rg3xx_model_details[] = {
[RG353M] = {
.adc_value = 517, /* Observed average from device */
.board = "rk3566-anbernic-rg353m",
.board_name = "RG353M",
.board_name = "Anbernic RG353M",
/* Device is identical to RG353P. */
.fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb",
.detect_panel = 1,
.uart_con = 1,
},
[RG353P] = {
.adc_value = 860, /* Documented value of 860 */
.board = "rk3566-anbernic-rg353p",
.board_name = "RG353P",
.board_name = "Anbernic RG353P",
.fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb",
.detect_panel = 1,
.uart_con = 1,
},
[RG353V] = {
.adc_value = 695, /* Observed average from device */
.board = "rk3566-anbernic-rg353v",
.board_name = "RG353V",
.board_name = "Anbernic RG353V",
.fdtfile = DTB_DIR "rk3566-anbernic-rg353v.dtb",
.detect_panel = 1,
.uart_con = 1,
},
[RG503] = {
.adc_value = 1023, /* Observed average from device */
.board = "rk3566-anbernic-rg503",
.board_name = "RG503",
.board_name = "Anbernic RG503",
.fdtfile = DTB_DIR "rk3566-anbernic-rg503.dtb",
.detect_panel = 0,
.uart_con = 1,
},
[RGB30] = {
.adc_value = 383, /* Gathered from second hand information */
.board = "rk3566-powkiddy-rgb30",
.board_name = "RGB30",
.board_name = "Powkiddy RGB30",
.fdtfile = DTB_DIR "rk3566-powkiddy-rgb30.dtb",
.detect_panel = 0,
.uart_con = 0,
},
[RK2023] = {
.adc_value = 635, /* Observed average from device */
.board = "rk3566-powkiddy-rk2023",
.board_name = "RK2023",
.board_name = "Powkiddy RK2023",
.fdtfile = DTB_DIR "rk3566-powkiddy-rk2023.dtb",
.detect_panel = 0,
.uart_con = 0,
},
[RGARCD] = {
.adc_value = 183, /* Observed average from device */
@@ -107,6 +117,7 @@ static const struct rg3xx_model rg3xx_model_details[] = {
.board_name = "Anbernic RG ARC-D",
.fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-d.dtb",
.detect_panel = 0,
.uart_con = 1,
},
[RGB10MAX3] = {
.adc_value = 765, /* Observed average from device */
@@ -114,21 +125,24 @@ static const struct rg3xx_model rg3xx_model_details[] = {
.board_name = "Powkiddy RGB10MAX3",
.fdtfile = DTB_DIR "rk3566-powkiddy-rgb10max3.dtb",
.detect_panel = 0,
.uart_con = 0,
},
/* Devices with duplicate ADC value */
[RG353PS] = {
.adc_value = 860, /* Observed average from device */
.board = "rk3566-anbernic-rg353ps",
.board_name = "RG353PS",
.board_name = "Anbernic RG353PS",
.fdtfile = DTB_DIR "rk3566-anbernic-rg353ps.dtb",
.detect_panel = 1,
.uart_con = 1,
},
[RG353VS] = {
.adc_value = 695, /* Gathered from second hand information */
.board = "rk3566-anbernic-rg353vs",
.board_name = "RG353VS",
.board_name = "Anbernic RG353VS",
.fdtfile = DTB_DIR "rk3566-anbernic-rg353vs.dtb",
.detect_panel = 1,
.uart_con = 1,
},
[RGARCS] = {
.adc_value = 183, /* Observed average from device */
@@ -136,6 +150,7 @@ static const struct rg3xx_model rg3xx_model_details[] = {
.board_name = "Anbernic RG ARC-S",
.fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-s.dtb",
.detect_panel = 0,
.uart_con = 1,
},
};
@@ -164,7 +179,7 @@ static const struct rg353_panel rg353_panel_details[] = {
void spl_board_init(void)
{
/* Set GPIO0_C5, GPIO0_C6, and GPIO0_C7 to output. */
writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | \
writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) |
(GPIO_C7 | GPIO_C6 | GPIO_C5),
(GPIO0_BASE + GPIO_SWPORT_DDR_H));
/* Set GPIO0_C5 and GPIO_C6 to 0 and GPIO0_C7 to 1. */
@@ -174,16 +189,22 @@ void spl_board_init(void)
/*
* Buzz the buzzer so the user knows something is going on. Make it
* optional in case PWM is disabled.
* optional in case PWM is disabled or if CONFIG_DM_PWM is not
* enabled.
*/
void __maybe_unused startup_buzz(void)
{
struct udevice *dev;
int err;
err = uclass_get_device(UCLASS_PWM, 0, &dev);
if (!IS_ENABLED(CONFIG_DM_PWM))
return;
/* Probe the PWM controller. */
err = uclass_get_device_by_name(UCLASS_PWM,
"pwm@fe6e0010", &dev);
if (err)
printf("pwm not found\n");
return;
pwm_set_enable(dev, 0, 1);
mdelay(200);
@@ -245,6 +266,13 @@ U_BOOT_DRIVER(anbernic_rg353_panel) = {
.plat_auto = sizeof(struct mipi_dsi_panel_plat),
};
/*
* The Anbernic 353 series shipped with 2 distinct displays requiring
* 2 distinct drivers, with no way for a user to know which panel is
* which. This function queries the DSI panel for the panel ID to
* determine which panel is present so the device-tree can be corrected
* automatically.
*/
int rgxx3_detect_display(void)
{
struct udevice *dev;
@@ -333,17 +361,10 @@ int rgxx3_detect_display(void)
return 0;
}
/* Detect which Anbernic RGXX3 device we are using so as to load the
* correct devicetree for Linux. Set an environment variable once
* found. The detection depends on the value of ADC channel 1, the
* presence of an eMMC on mmc0, and querying the DSI panel.
*/
int rgxx3_detect_device(void)
int rgxx3_read_board_id(void)
{
u32 adc_info;
int ret, i;
int board_id = -ENXIO;
struct mmc *mmc;
int ret;
ret = adc_channel_single_shot("saradc@fe720000", 1, &adc_info);
if (ret) {
@@ -357,16 +378,32 @@ int rgxx3_detect_device(void)
* design calls for no more than a 1% variance on the
* resistor, so assume a +- value of 15 should be enough.
*/
for (i = 0; i < ARRAY_SIZE(rg3xx_model_details); i++) {
for (int i = 0; i < ARRAY_SIZE(rg3xx_model_details); i++) {
u32 adc_min = rg3xx_model_details[i].adc_value - 15;
u32 adc_max = rg3xx_model_details[i].adc_value + 15;
if (adc_min < adc_info && adc_max > adc_info) {
board_id = i;
break;
}
if (adc_min < adc_info && adc_max > adc_info)
return i;
}
return -ENODEV;
}
/* Detect which Anbernic RGXX3 device we are using so as to load the
* correct devicetree for Linux. Set an environment variable once
* found. The detection depends on the value of ADC channel 1 and the
* presence of an eMMC on mmc0.
*/
int rgxx3_detect_device(void)
{
int ret;
int board_id;
struct mmc *mmc;
board_id = rgxx3_read_board_id();
if (board_id < 0)
return board_id;
/*
* Try to access the eMMC on an RG353V, RG353P, or RG Arc D.
* If it's missing, it's an RG353VS, RG353PS, or RG Arc S.
@@ -387,67 +424,87 @@ int rgxx3_detect_device(void)
}
}
if (board_id < 0)
return board_id;
return board_id;
}
env_set("board", rg3xx_model_details[board_id].board);
env_set("board_name",
rg3xx_model_details[board_id].board_name);
env_set("fdtfile", rg3xx_model_details[board_id].fdtfile);
/*
* Check the loaded device tree to set the correct gd->board_type.
* Disable the console if the board doesn't support a console.
*/
int set_gd_value(void)
{
const char *model;
/* Skip panel detection for when it is not needed. */
if (!rg3xx_model_details[board_id].detect_panel)
return 0;
model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
/* Warn but don't fail for errors in auto-detection of the panel. */
ret = rgxx3_detect_display();
if (ret)
printf("Failed to detect panel type\n");
for (int i = 0; i < ARRAY_SIZE(rg3xx_model_details); i++) {
if (strcmp(rg3xx_model_details[i].board_name, model) == 0) {
gd->board_type = i;
if (!rg3xx_model_details[i].uart_con)
gd->flags |= GD_FLG_SILENT |
GD_FLG_DISABLE_CONSOLE;
return 0;
}
}
return 0;
return -ENODEV;
}
int rk_board_late_init(void)
{
int ret;
ret = rgxx3_detect_device();
ret = set_gd_value();
if (ret) {
printf("Unable to detect device type: %d\n", ret);
return ret;
printf("Unable to auto-detect device\n");
goto end;
}
/*
* Change the model number on the RG353M since it uses the same
* tree as the RG353P.
*/
if (gd->board_type == RG353P) {
ret = rgxx3_read_board_id();
if (ret > 0)
gd->board_type = ret;
}
env_set("board", rg3xx_model_details[gd->board_type].board);
env_set("board_name",
rg3xx_model_details[gd->board_type].board_name);
env_set("fdtfile", rg3xx_model_details[gd->board_type].fdtfile);
/*
* Skip panel detection if not needed. Warn but don't fail for
* errors in auto-detection of the panel.
*/
if (rg3xx_model_details[gd->board_type].detect_panel) {
ret = rgxx3_detect_display();
if (ret)
printf("Failed to detect panel type\n");
}
end:
/* Turn off red LED and turn on orange LED. */
writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | GPIO_C6,
(GPIO0_BASE + GPIO_SWPORT_DR_H));
if (IS_ENABLED(CONFIG_DM_PWM))
startup_buzz();
startup_buzz();
return 0;
}
int ft_board_setup(void *blob, struct bd_info *bd)
int rgxx3_panel_fixup(void *blob)
{
const struct rg353_panel *panel = NULL;
int node, ret, i;
int node, ret;
char *env;
/* No fixups necessary for the RG503 */
env = env_get("board_name");
if (env && (!strcmp(env, rg3xx_model_details[RG503].board_name)))
return 0;
/* Change the model name of the RG353M */
if (env && (!strcmp(env, rg3xx_model_details[RG353M].board_name)))
fdt_setprop(blob, 0, "model",
rg3xx_model_details[RG353M].board_name,
sizeof(rg3xx_model_details[RG353M].board_name));
env = env_get("panel");
if (!env) {
printf("Can't get panel env\n");
return 0;
return -EINVAL;
}
/*
@@ -469,7 +526,7 @@ int ft_board_setup(void *blob, struct bd_info *bd)
return 0;
/* Panels don't match, search by first compatible value. */
for (i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) {
for (int i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) {
if (!strcmp(env, rg353_panel_details[i].panel_compat[0])) {
panel = &rg353_panel_details[i];
break;
@@ -489,3 +546,38 @@ int ft_board_setup(void *blob, struct bd_info *bd)
return 0;
}
int ft_board_setup(void *blob, struct bd_info *bd)
{
int ret;
if (gd->board_type == RG353M)
fdt_setprop(blob, 0, "model",
rg3xx_model_details[RG353M].board_name,
sizeof(rg3xx_model_details[RG353M].board_name));
if (rg3xx_model_details[gd->board_type].detect_panel) {
ret = rgxx3_panel_fixup(blob);
if (ret)
printf("Unable to update panel compat\n");
}
return 0;
}
int board_fit_config_name_match(const char *name)
{
int ret;
if (gd->board_type == 0) {
ret = rgxx3_detect_device();
if (ret < 0)
return ret;
gd->board_type = ret;
}
if (strcmp(name, rg3xx_model_details[gd->board_type].fdtfile) == 0)
return 0;
return -ENXIO;
}