1 /*
2 * (C) Copyright 2021 Rockchip Electronics Co., Ltd
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6 #include <common.h>
7 #include <adc.h>
8 #include <asm/io.h>
9 #include <dm/ofnode.h>
10 #include <asm/arch/rk_hwid.h>
11
12 #define is_digit(c) ((c) >= '0' && (c) <= '9')
13 #define is_abcd(c) ((c) >= 'a' && (c) <= 'd')
14 #if defined(CONFIG_SPL_ROCKCHIP_HWID_DTB)
15 /* ITB can't have "=" in node_name */
16 #define is_equal(c) ((c) == '_')
17 #else
18 #define is_equal(c) ((c) == '=')
19 #endif
20 #define MAX_ADC_CH_NR 10
21 #define MAX_GPIO_NR 10
22
23 static fdt_addr_t gpio_base_addr[MAX_GPIO_NR];
24 static uint32_t gpio_record[MAX_GPIO_NR];
25 static int adc_record[MAX_ADC_CH_NR];
26
27 #ifdef CONFIG_ROCKCHIP_GPIO_V2
28 #define GPIO_SWPORT_DDR 0x08
29 #define GPIO_EXT_PORT 0x70
30 #define WMSK_SETBIT(n) (n << 16 | n)
31 #define WMSK_CLRBIT(n) (n << 16)
32 #define REG_PLUS4(off, n) (off + (n >= BIT(16) ? 4 : 0))
33 #define BIT_SUB16(n) (n >= BIT(16) ? (n >> 16) : n)
gpio_read(fdt_addr_t gpio_addr,int gpio_bank,int gpio_pin)34 static int gpio_read(fdt_addr_t gpio_addr, int gpio_bank, int gpio_pin)
35 {
36 uint32_t off, bit;
37
38 bit = gpio_bank * 8 + gpio_pin;
39 off = REG_PLUS4(GPIO_SWPORT_DDR, bit);
40 bit = BIT_SUB16(bit);
41 writel(WMSK_CLRBIT(bit), gpio_addr + off);
42
43 return readl(gpio_addr + GPIO_EXT_PORT);
44 }
45
46 #else
47 #define GPIO_SWPORT_DDR 0x04
48 #define GPIO_EXT_PORT 0x50
gpio_read(fdt_addr_t gpio_addr,int gpio_bank,int gpio_pin)49 static int gpio_read(fdt_addr_t gpio_addr, int gpio_bank, int gpio_pin)
50 {
51 uint32_t val;
52
53 val = readl(gpio_addr + GPIO_SWPORT_DDR);
54 val &= ~(1 << (gpio_bank * 8 + gpio_pin));
55 writel(val, gpio_addr + GPIO_SWPORT_DDR);
56
57 return readl(gpio_addr + GPIO_EXT_PORT);
58 }
59 #endif
60
gpio_parse_base_address(fdt_addr_t * gpio_base_addr)61 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr)
62 {
63 static int initialized;
64 ofnode parent, node;
65 int idx = 0;
66
67 if (initialized)
68 return 0;
69
70 parent = ofnode_path("/pinctrl");
71 if (!ofnode_valid(parent)) {
72 debug(" - No pinctrl node\n");
73 return -EINVAL;
74 }
75
76 ofnode_for_each_subnode(node, parent) {
77 if (!ofnode_get_property(node, "gpio-controller", NULL)) {
78 debug(" - No gpio controller node\n");
79 continue;
80 }
81 gpio_base_addr[idx] = ofnode_get_addr(node);
82 debug(" - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]);
83 idx++;
84 }
85
86 if (idx == 0) {
87 debug(" - parse gpio address failed\n");
88 return -EINVAL;
89 }
90
91 initialized = 1;
92
93 return 0;
94 }
95
hwid_init_data(void)96 void hwid_init_data(void)
97 {
98 memset(adc_record, 0, sizeof(adc_record));
99 memset(gpio_record, 0, sizeof(gpio_record));
100 memset(gpio_base_addr, 0, sizeof(gpio_base_addr));
101 }
102
103 /*
104 * How to use ?
105 *
106 * 1. Pack dtbs into resource.img, dtb file name:
107 * - End with: ".dtb"
108 * - Pattern: ...#_[controller]_ch[channel]=[value]...dtb
109 * @controller: adc controller name in dts, eg. "saradc", ...;
110 * @channel: adc channel;
111 * @value: adc value;
112 * - Eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb
113 *
114 * 2. U-Boot dtsi about adc node:
115 * - Add "u-boot,dm-pre-reloc;"
116 * - Set node "okay"
117 */
hwid_adc_find_dtb(const char * file_name)118 static int hwid_adc_find_dtb(const char *file_name)
119 {
120 char *cell_name, *adc_tail, *adc_head, *p;
121 int prefix_len, chn_len, len;
122 int found = 0, margin = 30;
123 int ret, channel;
124 char dev_name[32];
125 char adc_val[10];
126 ulong dtb_adc;
127 u32 raw_adc;
128
129 debug("[HW-ADC]: %s\n", file_name);
130
131 chn_len = strlen(KEY_WORDS_ADC_CH);
132 prefix_len = strlen(KEY_WORDS_ADC_CTRL);
133 cell_name = strstr(file_name, KEY_WORDS_ADC_CTRL);
134 while (cell_name) {
135 /* Parse adc controller name */
136 adc_tail = strstr(cell_name, KEY_WORDS_ADC_CH);
137 adc_head = cell_name + prefix_len;
138 len = adc_tail - adc_head;
139 strlcpy(dev_name, adc_head, len + 1);
140
141 /* Parse adc channel */
142 p = adc_tail + chn_len;
143 if (is_digit(*p) && is_equal(*(p + 1))) {
144 channel = *p - '0';
145 } else {
146 debug(" - invalid format: %s\n", cell_name);
147 return 0;
148 }
149
150 /*
151 * Read raw adc value
152 *
153 * It doesn't need to read adc value every loop, reading once
154 * is enough. We use adc_record[] to save what we have read, zero
155 * means not read before.
156 */
157 if (adc_record[channel] == 0) {
158 ret = adc_channel_single_shot(dev_name, channel, &raw_adc);
159 if (ret)
160 ret = adc_channel_single_shot("adc", channel, &raw_adc);
161 if (ret) {
162 debug(" - failed to read adc, ret=%d\n", ret);
163 return 0;
164 }
165 adc_record[channel] = raw_adc;
166 }
167
168 /* Parse dtb adc value */
169 p = adc_tail + chn_len + 2; /* 2: channel and '=' */
170 while (*p && is_digit(*p)) {
171 len++;
172 p++;
173 }
174 strlcpy(adc_val, adc_tail + chn_len + 2, len + 1);
175 dtb_adc = simple_strtoul(adc_val, NULL, 10);
176 found = (abs(dtb_adc - adc_record[channel]) <= margin) ? 1 : 0;
177 debug(" - dev=%s, channel=%d, dtb_adc=%ld, read=%d, found=%d\n",
178 dev_name, channel, dtb_adc, adc_record[channel], found);
179 if (!found)
180 break;
181 cell_name = strstr(p, KEY_WORDS_ADC_CTRL);
182
183 }
184
185 return found;
186 }
187
188 /*
189 * How to use ?
190 *
191 * 1. Pack dtbs into resource.img, dtb file name:
192 * - End with: ".dtb"
193 * - Pattern: ...#gpio[pin]=[level]...dtb
194 * @pin: gpio name, eg. 0a2 means GPIO0A2
195 * @level: gpio level, 0 or 1
196 * - Eg: ...#gpio0a6=1#gpio1c2=0....dtb
197 *
198 * 2. U-Boot dtsi about gpio node:
199 * - Add "u-boot,dm-pre-reloc;" for [all] gpio node;
200 * - Set all gpio node "disabled" (We just want their property);
201 */
hwid_gpio_find_dtb(const char * file_name)202 static int hwid_gpio_find_dtb(const char *file_name)
203 {
204 uint8_t port, pin, bank, lvl, val;
205 char *cell_name, *p;
206 int ret, prefix_len;
207 int found = 0;
208 u32 bit;
209
210 debug("[HW-GPIO]: %s\n", file_name);
211
212 if (gpio_base_addr[0] == 0) {
213 ret = gpio_parse_base_address(gpio_base_addr);
214 if (ret) {
215 debug("[HW-GPIO]: Can't parse gpio base, ret=%d\n", ret);
216 return 0;
217 }
218 }
219
220 prefix_len = strlen(KEY_WORDS_GPIO);
221 cell_name = strstr(file_name, KEY_WORDS_GPIO);
222 while (cell_name) {
223 p = cell_name + prefix_len;
224
225 /* Invalid format ? */
226 if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) &&
227 is_digit(*(p + 2)) && is_equal(*(p + 3)) &&
228 is_digit(*(p + 4)))) {
229 debug(" - invalid format: %s\n", cell_name);
230 return 0;
231 }
232
233 /* Read gpio value */
234 port = *(p + 0) - '0';
235 bank = *(p + 1) - 'a';
236 pin = *(p + 2) - '0';
237 lvl = *(p + 4) - '0';
238
239 /*
240 * It doesn't need to read gpio value every loop, reading once
241 * is enough. We use gpio_record[] to save what we have read, zero
242 * means not read before.
243 */
244 if (gpio_record[port] == 0) {
245 if (!gpio_base_addr[port]) {
246 debug(" - can't find gpio%d base\n", port);
247 return 0;
248 }
249 gpio_record[port] =
250 gpio_read(gpio_base_addr[port], bank, pin);
251 }
252
253 /* Verify result */
254 bit = bank * 8 + pin;
255 val = gpio_record[port] & (1 << bit) ? 1 : 0;
256 found = (val == !!lvl) ? 1 : 0;
257 debug(" - gpio%d%c%d=%d, read=%d, found=%d\n",
258 port, bank + 'a', pin, lvl, val, found);
259 if (!found)
260 break;
261 cell_name = strstr(p, KEY_WORDS_GPIO);
262 }
263
264 return found;
265 }
266
hwid_dtb_is_available(const char * file_name)267 bool hwid_dtb_is_available(const char *file_name)
268 {
269 /*
270 * adc default form: #_[adc_controller_name]_ch[channel]_[adcval]
271 * like: #_saradc_ch0_800
272 *
273 * gpio default form: #gpio[pin_num]_[level]
274 * like: #gpio1a7_1
275 */
276 if (strstr(file_name, KEY_WORDS_ADC_CTRL) &&
277 strstr(file_name, KEY_WORDS_ADC_CH) &&
278 hwid_adc_find_dtb(file_name)) {
279 return 1;
280 } else if (strstr(file_name, KEY_WORDS_GPIO) &&
281 hwid_gpio_find_dtb(file_name)) {
282 return 1;
283 }
284
285 return 0;
286 }
287