diff options
| author | Chris Morgan <[email protected]> | 2023-04-21 10:59:19 -0500 |
|---|---|---|
| committer | Kever Yang <[email protected]> | 2023-05-06 17:45:05 +0800 |
| commit | 6cf6fe25370c8d96e02488ef8779e295ecdb982d (patch) | |
| tree | 91e019def4aeca2ca6313ed37814c3ce05dc8cd9 /board | |
| parent | c2d5edff916379abd2da4590e8171c965d9a3e1d (diff) | |
board: rockchip: add Anbernic RGXX3 Series Devices
The Anbernic RGxx3 is a "pseudo-device" that encompasses the following
devices:
- Anbernic RG353M
- Anbernic RG353P
- Anbernic RG353V
- Anbernic RG353VS
- Anbernic RG503
The rk3566-anbernic-rgxx3.dtsi is synced with upstream Linux, but
rk3566-anbernic-rgxx3.dts is a U-Boot specific devicetree that
is used for all RGxx3 devices.
Via the board.c file, the bootloader automatically sets the correct
fdtfile, board, and board_name environment variables so that the
correct devicetree can be passed to Linux. It is also possible to
simply hard-code a single devicetree in the boot.scr file and use
that to load Linux as well.
The common specifications for each device are:
- Rockchip RK3566 SoC
- 2 external SDMMC slots
- 1 USB-C host port, 1 USB-C peripheral port
- 1 mini-HDMI output
- MIPI-DSI based display panel
- ADC controlled joysticks with a GPIO mux
- GPIO buttons
- A PWM controlled vibrator
- An ADC controlled button
All of the common features are defined in the devicetree synced from
upstream Linux.
TODO: DSI panel auto-detection for the RG353 devices (requires porting
of DSI controller driver and DSI-DPHY driver to send DSI commands to
the panel).
Signed-off-by: Chris Morgan <[email protected]>
Reviewed-by: Kever Yang <[email protected]>
Diffstat (limited to 'board')
| -rw-r--r-- | board/anbernic/rgxx3_rk3566/Kconfig | 15 | ||||
| -rw-r--r-- | board/anbernic/rgxx3_rk3566/MAINTAINERS | 6 | ||||
| -rw-r--r-- | board/anbernic/rgxx3_rk3566/Makefile | 6 | ||||
| -rw-r--r-- | board/anbernic/rgxx3_rk3566/rgxx3-rk3566.c | 203 |
4 files changed, 230 insertions, 0 deletions
diff --git a/board/anbernic/rgxx3_rk3566/Kconfig b/board/anbernic/rgxx3_rk3566/Kconfig new file mode 100644 index 00000000000..6743a28a2f5 --- /dev/null +++ b/board/anbernic/rgxx3_rk3566/Kconfig @@ -0,0 +1,15 @@ +if TARGET_ANBERNIC_RGXX3_RK3566 + +config SYS_BOARD + default "rgxx3_rk3566" + +config SYS_VENDOR + default "anbernic" + +config SYS_CONFIG_NAME + default "anbernic-rgxx3-rk3566" + +config BOARD_SPECIFIC_OPTIONS + def_bool y + +endif diff --git a/board/anbernic/rgxx3_rk3566/MAINTAINERS b/board/anbernic/rgxx3_rk3566/MAINTAINERS new file mode 100644 index 00000000000..647e49d28ab --- /dev/null +++ b/board/anbernic/rgxx3_rk3566/MAINTAINERS @@ -0,0 +1,6 @@ +RGXX3-RK3566 +M: Chris Morgan <[email protected]> +S: Maintained +F: board/anbernic/rgxx3-rk3566 +F: include/configs/anbernic-rgxx3-rk3566 +F: configs/anbernic-rgxx3_defconfig diff --git a/board/anbernic/rgxx3_rk3566/Makefile b/board/anbernic/rgxx3_rk3566/Makefile new file mode 100644 index 00000000000..afd3e0adf6f --- /dev/null +++ b/board/anbernic/rgxx3_rk3566/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2023 Chris Morgan <[email protected]> +# + +obj-y += rgxx3-rk3566.o diff --git a/board/anbernic/rgxx3_rk3566/rgxx3-rk3566.c b/board/anbernic/rgxx3_rk3566/rgxx3-rk3566.c new file mode 100644 index 00000000000..decc46db78e --- /dev/null +++ b/board/anbernic/rgxx3_rk3566/rgxx3-rk3566.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Chris Morgan <[email protected]> + */ + +#include <abuf.h> +#include <adc.h> +#include <asm/io.h> +#include <dm.h> +#include <linux/delay.h> +#include <pwm.h> +#include <rng.h> +#include <stdlib.h> +#include <mmc.h> +#include <env.h> + +#define GPIO0_BASE 0xfdd60000 +#define GPIO_SWPORT_DR_H 0x0004 +#define GPIO_SWPORT_DDR_H 0x000c +#define GPIO_A5 BIT(5) +#define GPIO_A6 BIT(6) + +#define GPIO_WRITEMASK(bits) ((bits) << 16) + +#define DTB_DIR "rockchip/" + +struct rg3xx_model { + const char *board; + const char *board_name; + const char *fdtfile; +}; + +enum rgxx3_device_id { + RG353M, + RG353P, + RG353V, + RG353VS, + RG503, +}; + +static const struct rg3xx_model rg3xx_model_details[] = { + [RG353M] = { + "rk3566-anbernic-rg353m", + "RG353M", + DTB_DIR "rk3566-anbernic-rg353m.dtb", + }, + [RG353P] = { + "rk3566-anbernic-rg353p", + "RG353P", + DTB_DIR "rk3566-anbernic-rg353p.dtb", + }, + [RG353V] = { + "rk3566-anbernic-rg353v", + "RG353V", + DTB_DIR "rk3566-anbernic-rg353v.dtb", + }, + [RG353VS] = { + "rk3566-anbernic-rg353vs", + "RG353VS", + DTB_DIR "rk3566-anbernic-rg353vs.dtb", + }, + [RG503] = { + "rk3566-anbernic-rg503", + "RG503", + DTB_DIR "rk3566-anbernic-rg503.dtb", + }, +}; + +/* + * Start LED very early so user knows device is on. Set color + * to amber. + */ +void spl_board_init(void) +{ + /* Set GPIO0_A5 and GPIO0_A6 to output. */ + writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | (GPIO_A6 | GPIO_A5), + (GPIO0_BASE + GPIO_SWPORT_DDR_H)); + /* Set GPIO0_A5 to 0 and GPIO0_A6 to 1. */ + writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | GPIO_A6, + (GPIO0_BASE + GPIO_SWPORT_DR_H)); +} + +/* Use hardware rng to seed Linux random. */ +int board_rng_seed(struct abuf *buf) +{ + struct udevice *dev; + size_t len = 0x8; + u64 *data; + + data = malloc(len); + if (!data) { + printf("Out of memory\n"); + return -ENOMEM; + } + + if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) { + printf("No RNG device\n"); + return -ENODEV; + } + + if (dm_rng_read(dev, data, len)) { + printf("Reading RNG failed\n"); + return -EIO; + } + + abuf_init_set(buf, data, len); + + return 0; +} + +/* + * Buzz the buzzer so the user knows something is going on. Make it + * optional in case PWM is disabled. + */ +void __maybe_unused startup_buzz(void) +{ + struct udevice *dev; + int err; + + err = uclass_get_device(UCLASS_PWM, 0, &dev); + if (err) + printf("pwm not found\n"); + + pwm_set_enable(dev, 0, 1); + mdelay(200); + pwm_set_enable(dev, 0, 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 (TODO). + */ +int rgxx3_detect_device(void) +{ + u32 adc_info; + int ret; + int board_id = -ENXIO; + struct mmc *mmc; + + ret = adc_channel_single_shot("saradc@fe720000", 1, &adc_info); + if (ret) { + printf("Read SARADC failed with error %d\n", ret); + return ret; + } + + /* Observed value 517. */ + if (adc_info > 505 && adc_info < 530) + board_id = RG353M; + /* Observed value 695. */ + if (adc_info > 680 && adc_info < 710) + board_id = RG353V; + /* Documented value 860. */ + if (adc_info > 850 && adc_info < 870) + board_id = RG353P; + /* Observed value 1023. */ + if (adc_info > 1010) + board_id = RG503; + + /* + * Try to access the eMMC on an RG353V. If it's missing, it's + * an RG353VS. Note we could also check for a touchscreen at + * 0x1a on i2c2. + */ + if (board_id == RG353V) { + mmc = find_mmc_device(0); + if (mmc) { + ret = mmc_init(mmc); + if (ret) + board_id = RG353VS; + } + } + + if (board_id < 0) + 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); + + return 0; +} + +int rk_board_late_init(void) +{ + int ret; + + /* Turn off orange LED and turn on green LED. */ + writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | GPIO_A5, + (GPIO0_BASE + GPIO_SWPORT_DR_H)); + + ret = rgxx3_detect_device(); + if (ret) { + printf("Unable to detect device type: %d\n", ret); + return ret; + } + + if (IS_ENABLED(CONFIG_DM_PWM)) + startup_buzz(); + + return 0; +} |
