blob: decc46db78e8fa529c49471dcf0f6a43a8d57ba3 [file] [log] [blame]
Chris Morgan6cf6fe22023-04-21 10:59:19 -05001// 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 <dm.h>
10#include <linux/delay.h>
11#include <pwm.h>
12#include <rng.h>
13#include <stdlib.h>
14#include <mmc.h>
15#include <env.h>
16
17#define GPIO0_BASE 0xfdd60000
18#define GPIO_SWPORT_DR_H 0x0004
19#define GPIO_SWPORT_DDR_H 0x000c
20#define GPIO_A5 BIT(5)
21#define GPIO_A6 BIT(6)
22
23#define GPIO_WRITEMASK(bits) ((bits) << 16)
24
25#define DTB_DIR "rockchip/"
26
27struct rg3xx_model {
28 const char *board;
29 const char *board_name;
30 const char *fdtfile;
31};
32
33enum rgxx3_device_id {
34 RG353M,
35 RG353P,
36 RG353V,
37 RG353VS,
38 RG503,
39};
40
41static const struct rg3xx_model rg3xx_model_details[] = {
42 [RG353M] = {
43 "rk3566-anbernic-rg353m",
44 "RG353M",
45 DTB_DIR "rk3566-anbernic-rg353m.dtb",
46 },
47 [RG353P] = {
48 "rk3566-anbernic-rg353p",
49 "RG353P",
50 DTB_DIR "rk3566-anbernic-rg353p.dtb",
51 },
52 [RG353V] = {
53 "rk3566-anbernic-rg353v",
54 "RG353V",
55 DTB_DIR "rk3566-anbernic-rg353v.dtb",
56 },
57 [RG353VS] = {
58 "rk3566-anbernic-rg353vs",
59 "RG353VS",
60 DTB_DIR "rk3566-anbernic-rg353vs.dtb",
61 },
62 [RG503] = {
63 "rk3566-anbernic-rg503",
64 "RG503",
65 DTB_DIR "rk3566-anbernic-rg503.dtb",
66 },
67};
68
69/*
70 * Start LED very early so user knows device is on. Set color
71 * to amber.
72 */
73void spl_board_init(void)
74{
75 /* Set GPIO0_A5 and GPIO0_A6 to output. */
76 writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | (GPIO_A6 | GPIO_A5),
77 (GPIO0_BASE + GPIO_SWPORT_DDR_H));
78 /* Set GPIO0_A5 to 0 and GPIO0_A6 to 1. */
79 writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | GPIO_A6,
80 (GPIO0_BASE + GPIO_SWPORT_DR_H));
81}
82
83/* Use hardware rng to seed Linux random. */
84int board_rng_seed(struct abuf *buf)
85{
86 struct udevice *dev;
87 size_t len = 0x8;
88 u64 *data;
89
90 data = malloc(len);
91 if (!data) {
92 printf("Out of memory\n");
93 return -ENOMEM;
94 }
95
96 if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) {
97 printf("No RNG device\n");
98 return -ENODEV;
99 }
100
101 if (dm_rng_read(dev, data, len)) {
102 printf("Reading RNG failed\n");
103 return -EIO;
104 }
105
106 abuf_init_set(buf, data, len);
107
108 return 0;
109}
110
111/*
112 * Buzz the buzzer so the user knows something is going on. Make it
113 * optional in case PWM is disabled.
114 */
115void __maybe_unused startup_buzz(void)
116{
117 struct udevice *dev;
118 int err;
119
120 err = uclass_get_device(UCLASS_PWM, 0, &dev);
121 if (err)
122 printf("pwm not found\n");
123
124 pwm_set_enable(dev, 0, 1);
125 mdelay(200);
126 pwm_set_enable(dev, 0, 0);
127}
128
129/* Detect which Anbernic RGXX3 device we are using so as to load the
130 * correct devicetree for Linux. Set an environment variable once
131 * found. The detection depends on the value of ADC channel 1, the
132 * presence of an eMMC on mmc0, and querying the DSI panel (TODO).
133 */
134int rgxx3_detect_device(void)
135{
136 u32 adc_info;
137 int ret;
138 int board_id = -ENXIO;
139 struct mmc *mmc;
140
141 ret = adc_channel_single_shot("saradc@fe720000", 1, &adc_info);
142 if (ret) {
143 printf("Read SARADC failed with error %d\n", ret);
144 return ret;
145 }
146
147 /* Observed value 517. */
148 if (adc_info > 505 && adc_info < 530)
149 board_id = RG353M;
150 /* Observed value 695. */
151 if (adc_info > 680 && adc_info < 710)
152 board_id = RG353V;
153 /* Documented value 860. */
154 if (adc_info > 850 && adc_info < 870)
155 board_id = RG353P;
156 /* Observed value 1023. */
157 if (adc_info > 1010)
158 board_id = RG503;
159
160 /*
161 * Try to access the eMMC on an RG353V. If it's missing, it's
162 * an RG353VS. Note we could also check for a touchscreen at
163 * 0x1a on i2c2.
164 */
165 if (board_id == RG353V) {
166 mmc = find_mmc_device(0);
167 if (mmc) {
168 ret = mmc_init(mmc);
169 if (ret)
170 board_id = RG353VS;
171 }
172 }
173
174 if (board_id < 0)
175 return board_id;
176
177 env_set("board", rg3xx_model_details[board_id].board);
178 env_set("board_name",
179 rg3xx_model_details[board_id].board_name);
180 env_set("fdtfile", rg3xx_model_details[board_id].fdtfile);
181
182 return 0;
183}
184
185int rk_board_late_init(void)
186{
187 int ret;
188
189 /* Turn off orange LED and turn on green LED. */
190 writel(GPIO_WRITEMASK(GPIO_A6 | GPIO_A5) | GPIO_A5,
191 (GPIO0_BASE + GPIO_SWPORT_DR_H));
192
193 ret = rgxx3_detect_device();
194 if (ret) {
195 printf("Unable to detect device type: %d\n", ret);
196 return ret;
197 }
198
199 if (IS_ENABLED(CONFIG_DM_PWM))
200 startup_buzz();
201
202 return 0;
203}