]>
Commit | Line | Data |
---|---|---|
466a9ea2 AA |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2018 NXP | |
4 | * Copyright 2021 Purism | |
5 | */ | |
6 | ||
d678a59d | 7 | #include <common.h> |
466a9ea2 AA |
8 | #include <malloc.h> |
9 | #include <errno.h> | |
10 | #include <asm/io.h> | |
11 | #include <miiphy.h> | |
12 | #include <asm/mach-imx/iomux-v3.h> | |
13 | #include <asm-generic/gpio.h> | |
14 | #include <asm/arch/sys_proto.h> | |
15 | #include <fsl_esdhc.h> | |
16 | #include <mmc.h> | |
17 | #include <asm/arch/imx8mq_pins.h> | |
18 | #include <asm/arch/sys_proto.h> | |
19 | #include <asm/mach-imx/gpio.h> | |
20 | #include <asm/mach-imx/mxc_i2c.h> | |
21 | #include <asm/arch/clock.h> | |
22 | #include <asm/mach-imx/video.h> | |
23 | #include <fuse.h> | |
24 | #include <i2c.h> | |
25 | #include <spl.h> | |
26 | #include <usb.h> | |
27 | #include <dwc3-uboot.h> | |
28 | #include <linux/delay.h> | |
29 | #include <linux/bitfield.h> | |
30 | #include <power/regulator.h> | |
31 | #include <usb/xhci.h> | |
32 | #include "librem5.h" | |
33 | ||
34 | DECLARE_GLOBAL_DATA_PTR; | |
35 | ||
36 | int board_early_init_f(void) | |
37 | { | |
38 | return 0; | |
39 | } | |
40 | ||
41 | #if IS_ENABLED(CONFIG_LOAD_ENV_FROM_MMC_BOOT_PARTITION) | |
42 | uint board_mmc_get_env_part(struct mmc *mmc) | |
43 | { | |
8b882066 | 44 | uint part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config); |
466a9ea2 AA |
45 | |
46 | if (part == 7) | |
47 | part = 0; | |
48 | return part; | |
49 | } | |
50 | #endif | |
51 | ||
52 | int tps65982_wait_for_app(int timeout, int timeout_step) | |
53 | { | |
54 | int ret; | |
55 | char response[6]; | |
56 | struct udevice *udev, *bus; | |
57 | ||
58 | log_debug("%s: starting\n", __func__); | |
59 | ||
60 | /* Set the i2c bus */ | |
61 | ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &bus); | |
62 | if (ret) { | |
63 | log_err("%s: No bus %d\n", __func__, 0); | |
64 | return 1; | |
65 | } | |
66 | ||
67 | ret = i2c_get_chip(bus, 0x3f, 1, &udev); | |
68 | if (ret) { | |
69 | log_err("%s: setting chip offset failed %d\n", __func__, ret); | |
70 | return 1; | |
71 | } | |
72 | ||
73 | while (timeout > 0) { | |
74 | ret = dm_i2c_read(udev, 0x03, (u8 *)response, 5); | |
75 | log_debug("tps65982 mode %s\n", response); | |
76 | if (response[1] == 'A') | |
77 | return 0; | |
78 | mdelay(timeout_step); | |
79 | timeout -= timeout_step; | |
80 | log_debug("tps65982 waited %d ms %c\n", timeout_step, response[1]); | |
81 | } | |
82 | ||
83 | return 1; | |
84 | } | |
85 | ||
86 | int tps65982_clear_dead_battery(void) | |
87 | { | |
88 | int ret; | |
89 | char cmd[5] = "\04DBfg"; | |
90 | struct udevice *udev, *bus; | |
91 | ||
92 | log_debug("%s: starting\n", __func__); | |
93 | ||
94 | /* Set the i2c bus */ | |
95 | ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &bus); | |
96 | if (ret) { | |
97 | log_err("%s: No bus %d\n", __func__, 0); | |
98 | return 1; | |
99 | } | |
100 | ||
101 | ret = i2c_get_chip(bus, 0x3f, 1, &udev); | |
102 | if (ret) { | |
103 | log_err("%s: setting chip offset failed %d\n", __func__, ret); | |
104 | return 1; | |
105 | } | |
106 | ||
107 | /* clearing the dead battery flag when not in dead battery condition | |
108 | * is a no-op, so there's no need to check if it's in effect | |
109 | */ | |
110 | ret = dm_i2c_write(udev, 0x08, cmd, 5); | |
111 | if (ret) { | |
112 | log_err("%s: writing 4CC command failed %d", __func__, ret); | |
113 | return 1; | |
114 | } | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | #define TPS_POWER_STATUS_PWROPMODE(x) FIELD_GET(GENMASK(3, 2), x) | |
120 | ||
121 | #define TPS_PDO_CONTRACT_TYPE(x) FIELD_GET(GENMASK(31, 30), x) | |
122 | #define TPS_PDO_CONTRACT_FIXED 0 | |
123 | #define TPS_PDO_CONTRACT_BATTERY 1 | |
124 | #define TPS_PDO_CONTRACT_VARIABLE 2 | |
125 | ||
126 | #define TPS_TYPEC_PWR_MODE_USB 0 | |
127 | #define TPS_TYPEC_PWR_MODE_1_5A 1 | |
128 | #define TPS_TYPEC_PWR_MODE_3_0A 2 | |
129 | #define TPS_TYPEC_PWR_MODE_PD 3 | |
130 | ||
131 | #define TPS_PDO_FIXED_CONTRACT_MAX_CURRENT(x) (FIELD_GET(GENMASK(9, 0), x) * 10) | |
132 | #define TPS_PDO_VAR_CONTRACT_MAX_CURRENT(x) (FIELD_GET(GENMASK(9, 0), x) * 10) | |
133 | #define TPS_PDO_BAT_CONTRACT_MAX_VOLTAGE(x) (FIELD_GET(GENMASK(29, 20), x) * 50) | |
134 | #define TPS_PDO_BAT_CONTRACT_MAX_POWER(x) (FIELD_GET(GENMASK(9, 0), x) * 250) | |
135 | ||
136 | int tps65982_get_max_current(void) | |
137 | { | |
138 | int ret; | |
139 | u8 buf[7]; | |
140 | u8 pwr_status; | |
141 | u32 contract; | |
142 | int type, mode; | |
143 | struct udevice *udev, *bus; | |
144 | ||
145 | log_debug("%s: starting\n", __func__); | |
146 | ||
147 | /* Set the i2c bus */ | |
148 | ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &bus); | |
149 | if (ret) { | |
150 | log_debug("%s: No bus %d\n", __func__, 0); | |
151 | return -1; | |
152 | } | |
153 | ||
154 | ret = i2c_get_chip(bus, 0x3f, 1, &udev); | |
155 | if (ret) { | |
156 | log_debug("%s: setting chip offset failed %d\n", __func__, ret); | |
157 | return -1; | |
158 | } | |
159 | ||
160 | ret = dm_i2c_read(udev, 0x3f, buf, 3); | |
161 | if (ret) { | |
162 | log_debug("%s: reading pwr_status failed %d\n", __func__, ret); | |
163 | return -1; | |
164 | } | |
165 | ||
166 | pwr_status = buf[1]; | |
167 | ||
168 | if (!(pwr_status & 1)) | |
169 | return 0; | |
170 | ||
171 | mode = TPS_POWER_STATUS_PWROPMODE(pwr_status); | |
172 | switch (mode) { | |
173 | case TPS_TYPEC_PWR_MODE_1_5A: | |
174 | return 1500; | |
175 | case TPS_TYPEC_PWR_MODE_3_0A: | |
176 | return 3000; | |
177 | case TPS_TYPEC_PWR_MODE_PD: | |
178 | ret = dm_i2c_read(udev, 0x34, buf, 7); | |
179 | if (ret) { | |
180 | log_debug("%s: reading active contract failed %d\n", __func__, ret); | |
181 | return -1; | |
182 | } | |
183 | ||
184 | contract = buf[1] + (buf[2] << 8) + (buf[3] << 16) + (buf[4] << 24); | |
185 | ||
186 | type = TPS_PDO_CONTRACT_TYPE(contract); | |
187 | ||
188 | switch (type) { | |
189 | case TPS_PDO_CONTRACT_FIXED: | |
190 | return TPS_PDO_FIXED_CONTRACT_MAX_CURRENT(contract); | |
191 | case TPS_PDO_CONTRACT_BATTERY: | |
192 | return 1000 * TPS_PDO_BAT_CONTRACT_MAX_POWER(contract) | |
193 | / TPS_PDO_BAT_CONTRACT_MAX_VOLTAGE(contract); | |
194 | case TPS_PDO_CONTRACT_VARIABLE: | |
195 | return TPS_PDO_VAR_CONTRACT_MAX_CURRENT(contract); | |
196 | default: | |
197 | log_debug("Unknown contract type: %d\n", type); | |
198 | return -1; | |
199 | } | |
200 | case TPS_TYPEC_PWR_MODE_USB: | |
201 | return 500; | |
202 | default: | |
203 | log_debug("Unknown power mode: %d\n", mode); | |
204 | return -1; | |
205 | } | |
206 | } | |
207 | ||
208 | int init_tps65982(void) | |
209 | { | |
210 | log_debug("%s: starting\n", __func__); | |
211 | ||
212 | if (tps65982_wait_for_app(500, 100)) { | |
213 | log_err("tps65982 APP boot failed\n"); | |
214 | return 1; | |
215 | } | |
216 | ||
217 | log_info("tps65982 boot successful\n"); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | int bq25895_set_iinlim(int current) | |
222 | { | |
223 | u8 val, iinlim; | |
224 | int ret; | |
225 | struct udevice *udev, *bus; | |
226 | ||
227 | /* Set the i2c bus */ | |
228 | ret = uclass_get_device_by_seq(UCLASS_I2C, 3, &bus); | |
229 | if (ret) { | |
230 | log_err("%s: No bus 3\n", __func__); | |
231 | return ret; | |
232 | } | |
233 | ||
234 | ret = i2c_get_chip(bus, 0x6a, 1, &udev); | |
235 | if (ret) { | |
236 | log_err("%s: setting chip offset failed %d\n", __func__, ret); | |
237 | return ret; | |
238 | } | |
239 | ||
240 | if (current > 3250) | |
241 | current = 3250; | |
242 | if (current < 100) | |
243 | current = 100; | |
244 | ||
245 | val = dm_i2c_reg_read(udev, 0x00); | |
246 | iinlim = ((current - 100) / 50) & 0x3f; | |
247 | val = (val & 0xc0) | iinlim; | |
248 | dm_i2c_reg_write(udev, 0x00, val); | |
249 | log_debug("REG00 0x%x\n", val); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | bool bq25895_battery_present(void) | |
255 | { | |
256 | u8 val; | |
257 | int ret; | |
258 | struct udevice *udev, *bus; | |
259 | ||
260 | /* Set the i2c bus */ | |
261 | ret = uclass_get_device_by_seq(UCLASS_I2C, 3, &bus); | |
262 | if (ret) { | |
263 | log_err("%s: No bus 3\n", __func__); | |
264 | return ret; | |
265 | } | |
266 | ||
267 | ret = i2c_get_chip(bus, 0x6a, 1, &udev); | |
268 | if (ret) { | |
269 | log_err("%s: setting chip offset failed %d\n", __func__, ret); | |
270 | return ret; | |
271 | } | |
272 | ||
273 | /* note that this may return false negatives when there's | |
274 | * no external power applied and the battery voltage is below | |
275 | * Vsys. this isn't a problem when used for clearing the dead | |
276 | * battery flag though, since it's certain that there's an external | |
277 | * power applied in this case | |
278 | */ | |
279 | val = dm_i2c_reg_read(udev, 0x0e) & 0x7f; | |
280 | if (val == 0x00 || val == 0x7f) | |
281 | return false; | |
282 | ||
283 | return true; | |
284 | } | |
285 | ||
286 | /* | |
287 | * set some safe defaults for the battery charger | |
288 | */ | |
289 | int init_charger_bq25895(void) | |
290 | { | |
291 | u8 val; | |
292 | int iinlim, ret; | |
293 | struct udevice *udev, *bus; | |
294 | ||
295 | /* Set the i2c bus */ | |
296 | ret = uclass_get_device_by_seq(UCLASS_I2C, 3, &bus); | |
297 | if (ret) { | |
298 | log_debug("%s: No bus 3\n", __func__); | |
299 | return ret; | |
300 | } | |
301 | ||
302 | ret = i2c_get_chip(bus, 0x6a, 1, &udev); | |
303 | if (ret) { | |
304 | log_debug("%s: setting chip offset failed %d\n", __func__, ret); | |
305 | return ret; | |
306 | } | |
307 | ||
308 | val = dm_i2c_reg_read(udev, 0x0b); | |
309 | log_debug("REG0B 0x%x\n", val); | |
310 | ||
311 | log_debug("VBUS_STAT 0x%x\n", val >> 5); | |
312 | switch (val >> 5) { | |
313 | case 0: | |
314 | log_debug("VBUS not detected\n"); | |
315 | break; | |
316 | case 1: | |
317 | log_debug("USB SDP IINLIM 500mA\n"); | |
318 | break; | |
319 | case 2: | |
320 | log_debug("USB CDP IINLIM 1500mA\n"); | |
321 | break; | |
322 | case 3: | |
323 | log_debug("USB DCP IINLIM 3500mA\n"); | |
324 | break; | |
325 | case 4: | |
326 | log_debug("MAXCHARGE IINLIM 1500mA\n"); | |
327 | break; | |
328 | case 5: | |
329 | log_debug("Unknown IINLIM 500mA\n"); | |
330 | break; | |
331 | case 6: | |
332 | log_debug("DIVIDER IINLIM > 1000mA\n"); | |
333 | break; | |
334 | case 7: | |
335 | log_debug("OTG\n"); | |
336 | break; | |
337 | }; | |
338 | ||
339 | log_debug("CHRG_STAT 0x%x\n", (val >> 3) & 0x3); | |
340 | log_debug("PG_STAT 0x%x\n", (val >> 2) & 1); | |
341 | log_debug("SDP_STAT 0x%x\n", (val >> 1) & 1); | |
342 | log_debug("VSYS_STAT 0x%x\n", val & 1); | |
343 | ||
344 | val = dm_i2c_reg_read(udev, 0x00); | |
345 | log_debug("REG00 0x%x\n", val); | |
346 | iinlim = 100 + (val & 0x3f) * 50; | |
347 | log_debug("IINLIM %d mA\n", iinlim); | |
348 | log_debug("EN_HIZ 0x%x\n", (val >> 7) & 1); | |
349 | log_debug("EN_ILIM 0x%x\n", (val >> 6) & 1); | |
350 | ||
351 | /* set 1.6A charge limit */ | |
352 | dm_i2c_reg_write(udev, 0x04, 0x19); | |
353 | ||
354 | /* re-enable charger */ | |
355 | val = dm_i2c_reg_read(udev, 0x03); | |
356 | val = val | 0x10; | |
357 | dm_i2c_reg_write(udev, 0x03, val); | |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
362 | int board_init(void) | |
363 | { | |
364 | struct udevice *dev; | |
365 | int tps_ret; | |
366 | ||
367 | if (IS_ENABLED(CONFIG_USB_DWC3) || IS_ENABLED(CONFIG_USB_XHCI_IMX8M)) { | |
368 | log_debug("%s: initializing USB clk\n", __func__); | |
369 | ||
370 | /* init_usb_clk won't enable the second clock if it's a USB boot */ | |
371 | if (is_usb_boot()) { | |
372 | clock_enable(CCGR_USB_CTRL2, 1); | |
373 | clock_enable(CCGR_USB_PHY2, 1); | |
374 | } | |
375 | ||
376 | printf("Enabling regulator-hub\n"); | |
377 | if (!regulator_get_by_devname("regulator-hub", &dev)) { | |
378 | if (regulator_set_enable(dev, true)) | |
379 | pr_err("Failed to enable regulator-hub\n"); | |
380 | } | |
381 | } | |
382 | ||
383 | tps_ret = init_tps65982(); | |
384 | init_charger_bq25895(); | |
385 | ||
386 | if (!tps_ret) { | |
387 | int current = tps65982_get_max_current(); | |
388 | ||
389 | if (current > 500) | |
390 | bq25895_set_iinlim(current); | |
391 | ||
392 | if (bq25895_battery_present()) | |
393 | tps65982_clear_dead_battery(); | |
394 | } | |
395 | ||
396 | return 0; | |
397 | } | |
398 | ||
399 | int board_late_init(void) | |
400 | { | |
401 | if (IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)) { | |
4ae3fcdf AF |
402 | /* |
403 | * Use the r4 dtb by default as those are the most | |
404 | * widespread devices. | |
405 | */ | |
406 | u32 rev, dtb_rev = 4; | |
466a9ea2 | 407 | char rev_str[3]; |
4ae3fcdf | 408 | char fdt_str[50]; |
466a9ea2 AA |
409 | |
410 | env_set("board_name", "librem5"); | |
411 | if (fuse_read(9, 0, &rev)) { | |
412 | env_set("board_rev", BOARD_REV_ERROR); | |
413 | } else if (rev == 0) { | |
4ae3fcdf AF |
414 | /* |
415 | * If the fuses aren't burnt we should use either the | |
416 | * r2 or r3 DTB. The latter makes more sense as there | |
417 | * are far more r3 devices out there. | |
418 | */ | |
419 | dtb_rev = 3; | |
466a9ea2 AA |
420 | env_set("board_rev", BOARD_REV_UNKNOWN); |
421 | } else if (rev > 0) { | |
4ae3fcdf AF |
422 | if (rev == 1) |
423 | dtb_rev = 2; | |
424 | else if (rev < dtb_rev) | |
425 | dtb_rev = rev; | |
426 | /* | |
427 | * FCC-approved devices report '5' as their board | |
428 | * revision but use the r4 DTB as the PCB's are | |
429 | * functionally identical. | |
430 | */ | |
431 | else if (rev == 5) | |
432 | dtb_rev = 4; | |
466a9ea2 AA |
433 | sprintf(rev_str, "%u", rev); |
434 | env_set("board_rev", rev_str); | |
435 | } | |
436 | ||
437 | printf("Board name: %s\n", env_get("board_name")); | |
438 | printf("Board rev: %s\n", env_get("board_rev")); | |
4ae3fcdf AF |
439 | |
440 | sprintf(fdt_str, "freescale/imx8mq-librem5-r%u.dtb", dtb_rev); | |
441 | env_set("fdtfile", fdt_str); | |
466a9ea2 AA |
442 | } |
443 | ||
444 | if (is_usb_boot()) { | |
445 | puts("USB Boot\n"); | |
446 | env_set("bootcmd", "fastboot 0"); | |
447 | } | |
448 | ||
449 | return 0; | |
450 | } |