1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2023 Chris Morgan <macromorgan@hotmail.com> 4 */ 5 6#include <abuf.h> 7#include <adc.h> 8#include <asm/io.h> 9#include <command.h> 10#include <display.h> 11#include <dm.h> 12#include <dm/lists.h> 13#include <env.h> 14#include <fdt_support.h> 15#include <linux/delay.h> 16#include <linux/iopoll.h> 17#include <mipi_dsi.h> 18#include <mmc.h> 19#include <panel.h> 20#include <pwm.h> 21#include <stdlib.h> 22#include <video_bridge.h> 23 24#define BOOT_BROM_DOWNLOAD 0xef08a53c 25 26#define GPIO0_BASE 0xfdd60000 27#define GPIO4_BASE 0xfe770000 28#define GPIO_SWPORT_DR_L 0x0000 29#define GPIO_SWPORT_DR_H 0x0004 30#define GPIO_SWPORT_DDR_L 0x0008 31#define GPIO_SWPORT_DDR_H 0x000c 32#define GPIO_A0 BIT(0) 33#define GPIO_C5 BIT(5) 34#define GPIO_C6 BIT(6) 35#define GPIO_C7 BIT(7) 36 37#define GPIO_WRITEMASK(bits) ((bits) << 16) 38 39#define SARADC_BASE 0xfe720000 40#define SARADC_DATA 0x0000 41#define SARADC_STAS 0x0004 42#define SARADC_ADC_STATUS BIT(0) 43#define SARADC_CTRL 0x0008 44#define SARADC_INPUT_SRC_MSK 0x7 45#define SARADC_POWER_CTRL BIT(3) 46 47#define DTB_DIR "rockchip/" 48 49struct rg3xx_model { 50 const u16 adc_value; 51 const char *board; 52 const char *board_name; 53 const char *fdtfile; 54 const bool detect_panel; 55}; 56 57enum rgxx3_device_id { 58 RG353M, 59 RG353P, 60 RG353V, 61 RG503, 62 RGB30, 63 RK2023, 64 RGARCD, 65 RGB10MAX3, 66 /* Devices with duplicate ADC value */ 67 RG353PS, 68 RG353VS, 69 RGARCS, 70}; 71 72static const struct rg3xx_model rg3xx_model_details[] = { 73 [RG353M] = { 74 .adc_value = 517, /* Observed average from device */ 75 .board = "rk3566-anbernic-rg353m", 76 .board_name = "RG353M", 77 /* Device is identical to RG353P. */ 78 .fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb", 79 .detect_panel = 1, 80 }, 81 [RG353P] = { 82 .adc_value = 860, /* Documented value of 860 */ 83 .board = "rk3566-anbernic-rg353p", 84 .board_name = "RG353P", 85 .fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb", 86 .detect_panel = 1, 87 }, 88 [RG353V] = { 89 .adc_value = 695, /* Observed average from device */ 90 .board = "rk3566-anbernic-rg353v", 91 .board_name = "RG353V", 92 .fdtfile = DTB_DIR "rk3566-anbernic-rg353v.dtb", 93 .detect_panel = 1, 94 }, 95 [RG503] = { 96 .adc_value = 1023, /* Observed average from device */ 97 .board = "rk3566-anbernic-rg503", 98 .board_name = "RG503", 99 .fdtfile = DTB_DIR "rk3566-anbernic-rg503.dtb", 100 .detect_panel = 0, 101 }, 102 [RGB30] = { 103 .adc_value = 383, /* Gathered from second hand information */ 104 .board = "rk3566-powkiddy-rgb30", 105 .board_name = "RGB30", 106 .fdtfile = DTB_DIR "rk3566-powkiddy-rgb30.dtb", 107 .detect_panel = 0, 108 }, 109 [RK2023] = { 110 .adc_value = 635, /* Observed average from device */ 111 .board = "rk3566-powkiddy-rk2023", 112 .board_name = "RK2023", 113 .fdtfile = DTB_DIR "rk3566-powkiddy-rk2023.dtb", 114 .detect_panel = 0, 115 }, 116 [RGARCD] = { 117 .adc_value = 183, /* Observed average from device */ 118 .board = "rk3566-anbernic-rg-arc-d", 119 .board_name = "Anbernic RG ARC-D", 120 .fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-d.dtb", 121 .detect_panel = 0, 122 }, 123 [RGB10MAX3] = { 124 .adc_value = 765, /* Observed average from device */ 125 .board = "rk3566-powkiddy-rgb10max3", 126 .board_name = "Powkiddy RGB10MAX3", 127 .fdtfile = DTB_DIR "rk3566-powkiddy-rgb10max3.dtb", 128 .detect_panel = 0, 129 }, 130 /* Devices with duplicate ADC value */ 131 [RG353PS] = { 132 .adc_value = 860, /* Observed average from device */ 133 .board = "rk3566-anbernic-rg353ps", 134 .board_name = "RG353PS", 135 .fdtfile = DTB_DIR "rk3566-anbernic-rg353ps.dtb", 136 .detect_panel = 1, 137 }, 138 [RG353VS] = { 139 .adc_value = 695, /* Gathered from second hand information */ 140 .board = "rk3566-anbernic-rg353vs", 141 .board_name = "RG353VS", 142 .fdtfile = DTB_DIR "rk3566-anbernic-rg353vs.dtb", 143 .detect_panel = 1, 144 }, 145 [RGARCS] = { 146 .adc_value = 183, /* Observed average from device */ 147 .board = "rk3566-anbernic-rg-arc-s", 148 .board_name = "Anbernic RG ARC-S", 149 .fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-s.dtb", 150 .detect_panel = 0, 151 }, 152}; 153 154struct rg353_panel { 155 const u16 id; 156 const char *panel_compat[2]; 157}; 158 159static const struct rg353_panel rg353_panel_details[] = { 160 { 161 .id = 0x3052, 162 .panel_compat[0] = "anbernic,rg353p-panel", 163 .panel_compat[1] = "newvision,nv3051d", 164 }, 165 { 166 .id = 0x3821, 167 .panel_compat[0] = "anbernic,rg353v-panel-v2", 168 .panel_compat[1] = NULL, 169 }, 170}; 171 172/* 173 * The device has internal eMMC, and while some devices have an exposed 174 * clk pin you can ground to force a bypass not all devices do. As a 175 * result it may be possible for some devices to become a perma-brick 176 * if a corrupted TPL or SPL stage with a valid header is flashed to 177 * the internal eMMC. Add functionality to read ADC channel 0 (the func 178 * button) as early as possible in the boot process to provide some 179 * protection against this. If we ever get an open TPL stage, we should 180 * consider moving this function there. 181 */ 182void read_func_button(void) 183{ 184 int ret; 185 u32 reg; 186 187 /* Turn off SARADC to reset it. */ 188 writel(0, (SARADC_BASE + SARADC_CTRL)); 189 190 /* Enable channel 0 and power on SARADC. */ 191 writel(((0 & SARADC_INPUT_SRC_MSK) | SARADC_POWER_CTRL), 192 (SARADC_BASE + SARADC_CTRL)); 193 194 /* 195 * Wait for data to be ready. Use timeout of 20000us from 196 * rockchip_saradc driver. 197 */ 198 ret = readl_poll_timeout((SARADC_BASE + SARADC_STAS), reg, 199 !(reg & SARADC_ADC_STATUS), 20000); 200 if (ret) { 201 printf("ADC Timeout"); 202 return; 203 } 204 205 /* Read the data from the SARADC. */ 206 reg = readl((SARADC_BASE + SARADC_DATA)); 207 208 /* Turn the SARADC back off so it's ready to be used again. */ 209 writel(0, (SARADC_BASE + SARADC_CTRL)); 210 211 /* 212 * If the value is less than 30 the button is being pressed. 213 * Reset the device back into Rockchip download mode. 214 */ 215 if (reg <= 30) { 216 printf("download key pressed, entering download mode..."); 217 writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG); 218 do_reset(NULL, 0, 0, NULL); 219 } 220}; 221 222/* 223 * Start LED very early so user knows device is on. Set color 224 * to red. 225 */ 226void spl_board_init(void) 227{ 228 read_func_button(); 229 230 /* Set GPIO0_C5, GPIO0_C6, and GPIO0_C7 to output. */ 231 writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | \ 232 (GPIO_C7 | GPIO_C6 | GPIO_C5), 233 (GPIO0_BASE + GPIO_SWPORT_DDR_H)); 234 /* Set GPIO0_C5 and GPIO_C6 to 0 and GPIO0_C7 to 1. */ 235 writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | GPIO_C7, 236 (GPIO0_BASE + GPIO_SWPORT_DR_H)); 237} 238 239/* 240 * Buzz the buzzer so the user knows something is going on. Make it 241 * optional in case PWM is disabled. 242 */ 243void __maybe_unused startup_buzz(void) 244{ 245 struct udevice *dev; 246 int err; 247 248 err = uclass_get_device(UCLASS_PWM, 0, &dev); 249 if (err) 250 printf("pwm not found\n"); 251 252 pwm_set_enable(dev, 0, 1); 253 mdelay(200); 254 pwm_set_enable(dev, 0, 0); 255} 256 257/* 258 * Provide the bare minimum to identify the panel for the RG353 259 * series. Since we don't have a working framebuffer device, no 260 * need to init the panel; just identify it and provide the 261 * clocks so we know what to set the different clock values to. 262 */ 263 264static const struct display_timing rg353_default_timing = { 265 .pixelclock.typ = 24150000, 266 .hactive.typ = 640, 267 .hfront_porch.typ = 40, 268 .hback_porch.typ = 80, 269 .hsync_len.typ = 2, 270 .vactive.typ = 480, 271 .vfront_porch.typ = 18, 272 .vback_porch.typ = 28, 273 .vsync_len.typ = 2, 274 .flags = DISPLAY_FLAGS_HSYNC_HIGH | 275 DISPLAY_FLAGS_VSYNC_HIGH, 276}; 277 278static int anbernic_rg353_panel_get_timing(struct udevice *dev, 279 struct display_timing *timings) 280{ 281 memcpy(timings, &rg353_default_timing, sizeof(*timings)); 282 283 return 0; 284} 285 286static int anbernic_rg353_panel_probe(struct udevice *dev) 287{ 288 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); 289 290 plat->lanes = 4; 291 plat->format = MIPI_DSI_FMT_RGB888; 292 plat->mode_flags = MIPI_DSI_MODE_VIDEO | 293 MIPI_DSI_MODE_VIDEO_BURST | 294 MIPI_DSI_MODE_EOT_PACKET | 295 MIPI_DSI_MODE_LPM; 296 297 return 0; 298} 299 300static const struct panel_ops anbernic_rg353_panel_ops = { 301 .get_display_timing = anbernic_rg353_panel_get_timing, 302}; 303 304U_BOOT_DRIVER(anbernic_rg353_panel) = { 305 .name = "anbernic_rg353_panel", 306 .id = UCLASS_PANEL, 307 .ops = &anbernic_rg353_panel_ops, 308 .probe = anbernic_rg353_panel_probe, 309 .plat_auto = sizeof(struct mipi_dsi_panel_plat), 310}; 311 312int rgxx3_detect_display(void) 313{ 314 struct udevice *dev; 315 struct mipi_dsi_device *dsi; 316 struct mipi_dsi_panel_plat *mplat; 317 const struct rg353_panel *panel; 318 int ret = 0; 319 int i; 320 u8 panel_id[2]; 321 322 /* 323 * Take panel out of reset status. 324 * Set GPIO4_A0 to output. 325 */ 326 writel(GPIO_WRITEMASK(GPIO_A0) | GPIO_A0, 327 (GPIO4_BASE + GPIO_SWPORT_DDR_L)); 328 /* Set GPIO4_A0 to 1. */ 329 writel(GPIO_WRITEMASK(GPIO_A0) | GPIO_A0, 330 (GPIO4_BASE + GPIO_SWPORT_DR_L)); 331 332 /* Probe the DSI controller. */ 333 ret = uclass_get_device_by_name(UCLASS_VIDEO_BRIDGE, 334 "dsi@fe060000", &dev); 335 if (ret) { 336 printf("DSI host not probed: %d\n", ret); 337 return ret; 338 } 339 340 /* Probe the DSI panel. */ 341 ret = device_bind_driver_to_node(dev, "anbernic_rg353_panel", 342 "anbernic_rg353_panel", 343 dev_ofnode(dev), NULL); 344 if (ret) { 345 printf("Failed to probe RG353 panel: %d\n", ret); 346 return ret; 347 } 348 349 /* 350 * Attach the DSI controller which will also probe and attach 351 * the DSIDPHY. 352 */ 353 ret = video_bridge_attach(dev); 354 if (ret) { 355 printf("Failed to attach DSI controller: %d\n", ret); 356 return ret; 357 } 358 359 /* 360 * Get the panel which should have already been probed by the 361 * video_bridge_attach() function. 362 */ 363 ret = uclass_first_device_err(UCLASS_PANEL, &dev); 364 if (ret) { 365 printf("Panel device error: %d\n", ret); 366 return ret; 367 } 368 369 /* Now call the panel via DSI commands to get the panel ID. */ 370 mplat = dev_get_plat(dev); 371 dsi = mplat->device; 372 mipi_dsi_set_maximum_return_packet_size(dsi, sizeof(panel_id)); 373 ret = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_ID, &panel_id, 374 sizeof(panel_id)); 375 if (ret < 0) { 376 printf("Unable to read panel ID: %d\n", ret); 377 return ret; 378 } 379 380 /* Get the correct panel compatible from the table. */ 381 for (i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) { 382 if (rg353_panel_details[i].id == ((panel_id[0] << 8) | 383 panel_id[1])) { 384 panel = &rg353_panel_details[i]; 385 break; 386 } 387 } 388 389 if (!panel) { 390 printf("Unable to identify panel_id %x\n", 391 (panel_id[0] << 8) | panel_id[1]); 392 return -EINVAL; 393 } 394 395 env_set("panel", panel->panel_compat[0]); 396 397 return 0; 398} 399 400/* Detect which Anbernic RGXX3 device we are using so as to load the 401 * correct devicetree for Linux. Set an environment variable once 402 * found. The detection depends on the value of ADC channel 1, the 403 * presence of an eMMC on mmc0, and querying the DSI panel. 404 */ 405int rgxx3_detect_device(void) 406{ 407 u32 adc_info; 408 int ret, i; 409 int board_id = -ENXIO; 410 struct mmc *mmc; 411 412 ret = adc_channel_single_shot("saradc@fe720000", 1, &adc_info); 413 if (ret) { 414 printf("Read SARADC failed with error %d\n", ret); 415 return ret; 416 } 417 418 /* 419 * Get the correct device from the table. The ADC value is 420 * determined by a resistor on ADC channel 0. The hardware 421 * design calls for no more than a 1% variance on the 422 * resistor, so assume a +- value of 15 should be enough. 423 */ 424 for (i = 0; i < ARRAY_SIZE(rg3xx_model_details); i++) { 425 u32 adc_min = rg3xx_model_details[i].adc_value - 15; 426 u32 adc_max = rg3xx_model_details[i].adc_value + 15; 427 428 if (adc_min < adc_info && adc_max > adc_info) { 429 board_id = i; 430 break; 431 } 432 } 433 434 /* 435 * Try to access the eMMC on an RG353V, RG353P, or RG Arc D. 436 * If it's missing, it's an RG353VS, RG353PS, or RG Arc S. 437 * Note we could also check for a touchscreen at 0x1a on i2c2. 438 */ 439 if (board_id == RG353V || board_id == RG353P || board_id == RGARCD) { 440 mmc = find_mmc_device(0); 441 if (mmc) { 442 ret = mmc_init(mmc); 443 if (ret) { 444 if (board_id == RG353V) 445 board_id = RG353VS; 446 else if (board_id == RG353P) 447 board_id = RG353PS; 448 else 449 board_id = RGARCS; 450 } 451 } 452 } 453 454 if (board_id < 0) 455 return board_id; 456 457 env_set("board", rg3xx_model_details[board_id].board); 458 env_set("board_name", 459 rg3xx_model_details[board_id].board_name); 460 env_set("fdtfile", rg3xx_model_details[board_id].fdtfile); 461 462 /* Skip panel detection for when it is not needed. */ 463 if (!rg3xx_model_details[board_id].detect_panel) 464 return 0; 465 466 /* Warn but don't fail for errors in auto-detection of the panel. */ 467 ret = rgxx3_detect_display(); 468 if (ret) 469 printf("Failed to detect panel type\n"); 470 471 return 0; 472} 473 474int rk_board_late_init(void) 475{ 476 int ret; 477 478 ret = rgxx3_detect_device(); 479 if (ret) { 480 printf("Unable to detect device type: %d\n", ret); 481 return ret; 482 } 483 484 /* Turn off red LED and turn on orange LED. */ 485 writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | GPIO_C6, 486 (GPIO0_BASE + GPIO_SWPORT_DR_H)); 487 488 if (IS_ENABLED(CONFIG_DM_PWM)) 489 startup_buzz(); 490 491 return 0; 492} 493 494int ft_board_setup(void *blob, struct bd_info *bd) 495{ 496 const struct rg353_panel *panel = NULL; 497 int node, ret, i; 498 char *env; 499 500 /* No fixups necessary for the RG503 */ 501 env = env_get("board_name"); 502 if (env && (!strcmp(env, rg3xx_model_details[RG503].board_name))) 503 return 0; 504 505 /* Change the model name of the RG353M */ 506 if (env && (!strcmp(env, rg3xx_model_details[RG353M].board_name))) 507 fdt_setprop(blob, 0, "model", 508 rg3xx_model_details[RG353M].board_name, 509 sizeof(rg3xx_model_details[RG353M].board_name)); 510 511 env = env_get("panel"); 512 if (!env) { 513 printf("Can't get panel env\n"); 514 return 0; 515 } 516 517 /* 518 * Check if the environment variable doesn't equal the panel. 519 * If it doesn't, update the devicetree to the correct panel. 520 */ 521 node = fdt_path_offset(blob, "/dsi@fe060000/panel@0"); 522 if (!(node > 0)) { 523 printf("Can't find the DSI node\n"); 524 return -ENODEV; 525 } 526 527 ret = fdt_node_check_compatible(blob, node, env); 528 if (ret < 0) 529 return -ENODEV; 530 531 /* Panels match, return 0. */ 532 if (!ret) 533 return 0; 534 535 /* Panels don't match, search by first compatible value. */ 536 for (i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) { 537 if (!strcmp(env, rg353_panel_details[i].panel_compat[0])) { 538 panel = &rg353_panel_details[i]; 539 break; 540 } 541 } 542 543 if (!panel) { 544 printf("Unable to identify panel by compat string\n"); 545 return -ENODEV; 546 } 547 548 /* Set the compatible with the auto-detected values */ 549 fdt_setprop_string(blob, node, "compatible", panel->panel_compat[0]); 550 if (panel->panel_compat[1]) 551 fdt_appendprop_string(blob, node, "compatible", 552 panel->panel_compat[1]); 553 554 return 0; 555} 556