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) 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 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 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 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 */ 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 */ 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 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