blob: af607c5874985dd9ff75a5211c4c269d026bbe53 [file] [log] [blame]
Tom Rini8b0c8a12018-05-06 18:27:01 -04001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +01002/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +01004 */
Patrice Chotard879cde52019-02-12 16:50:40 +01005#include <common.h>
6#include <adc.h>
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +01007#include <config.h>
Patrice Chotard204079b2018-08-10 17:12:14 +02008#include <clk.h>
9#include <dm.h>
Patrice Chotard34320372019-05-02 18:28:05 +020010#include <environment.h>
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +010011#include <g_dnl.h>
Patrice Chotard204079b2018-08-10 17:12:14 +020012#include <generic-phy.h>
Patrick Delaunay7f3384d2019-03-29 15:42:24 +010013#include <i2c.h>
Patrick Delaunay92dc1022019-02-12 11:44:41 +010014#include <led.h>
15#include <misc.h>
Patrice Chotard204079b2018-08-10 17:12:14 +020016#include <phy.h>
17#include <reset.h>
Patrick Delaunay4ace1d12019-02-27 17:01:24 +010018#include <syscon.h>
Patrick Delaunay7f3384d2019-03-29 15:42:24 +010019#include <usb.h>
Patrice Chotard204079b2018-08-10 17:12:14 +020020#include <asm/io.h>
Patrick Delaunayf2a7b872019-02-27 17:01:18 +010021#include <asm/gpio.h>
Patrick Delaunay4ace1d12019-02-27 17:01:24 +010022#include <asm/arch/stm32.h>
Patrice Chotarddad97bf2019-05-02 18:36:01 +020023#include <asm/arch/sys_proto.h>
Patrice Chotard204079b2018-08-10 17:12:14 +020024#include <power/regulator.h>
Patrick Delaunay7f3384d2019-03-29 15:42:24 +010025#include <usb/dwc2_udc.h>
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +010026
Patrick Delaunay4ace1d12019-02-27 17:01:24 +010027/* SYSCFG registers */
28#define SYSCFG_BOOTR 0x00
29#define SYSCFG_PMCSETR 0x04
30#define SYSCFG_IOCTRLSETR 0x18
31#define SYSCFG_ICNR 0x1C
32#define SYSCFG_CMPCR 0x20
33#define SYSCFG_CMPENSETR 0x24
34#define SYSCFG_PMCCLRR 0x44
35
36#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0)
37#define SYSCFG_BOOTR_BOOTPD_SHIFT 4
38
39#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0)
40#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1)
41#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2)
42#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3)
43#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4)
44
45#define SYSCFG_CMPCR_SW_CTRL BIT(1)
46#define SYSCFG_CMPCR_READY BIT(8)
47
48#define SYSCFG_CMPENSETR_MPU_EN BIT(0)
49
50#define SYSCFG_PMCSETR_ETH_CLK_SEL BIT(16)
51#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL BIT(17)
52
53#define SYSCFG_PMCSETR_ETH_SELMII BIT(20)
54
55#define SYSCFG_PMCSETR_ETH_SEL_MASK GENMASK(23, 21)
56#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII (0 << 21)
57#define SYSCFG_PMCSETR_ETH_SEL_RGMII (1 << 21)
58#define SYSCFG_PMCSETR_ETH_SEL_RMII (4 << 21)
59
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +010060/*
61 * Get a global data pointer
62 */
63DECLARE_GLOBAL_DATA_PTR;
64
Patrice Chotard879cde52019-02-12 16:50:40 +010065#define USB_WARNING_LOW_THRESHOLD_UV 660000
66#define USB_START_LOW_THRESHOLD_UV 1230000
67#define USB_START_HIGH_THRESHOLD_UV 2100000
68
Patrick Delaunay92dc1022019-02-12 11:44:41 +010069int checkboard(void)
70{
71 int ret;
72 char *mode;
73 u32 otp;
74 struct udevice *dev;
75 const char *fdt_compat;
76 int fdt_compat_len;
77
78 if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
79 mode = "trusted";
80 else
81 mode = "basic";
82
83 printf("Board: stm32mp1 in %s mode", mode);
84 fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
85 &fdt_compat_len);
86 if (fdt_compat && fdt_compat_len)
87 printf(" (%s)", fdt_compat);
88 puts("\n");
89
90 ret = uclass_get_device_by_driver(UCLASS_MISC,
91 DM_GET_DRIVER(stm32mp_bsec),
92 &dev);
93
94 if (!ret)
95 ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
96 &otp, sizeof(otp));
97 if (!ret && otp) {
98 printf("Board: MB%04x Var%d Rev.%c-%02d\n",
99 otp >> 16,
100 (otp >> 12) & 0xF,
101 ((otp >> 8) & 0xF) - 1 + 'A',
102 otp & 0xF);
103 }
104
105 return 0;
106}
107
Patrick Delaunay008d3c32019-02-27 17:01:20 +0100108static void board_key_check(void)
109{
110#if defined(CONFIG_FASTBOOT) || defined(CONFIG_CMD_STM32PROG)
111 ofnode node;
112 struct gpio_desc gpio;
113 enum forced_boot_mode boot_mode = BOOT_NORMAL;
114
115 node = ofnode_path("/config");
116 if (!ofnode_valid(node)) {
117 debug("%s: no /config node?\n", __func__);
118 return;
119 }
120#ifdef CONFIG_FASTBOOT
121 if (gpio_request_by_name_nodev(node, "st,fastboot-gpios", 0,
122 &gpio, GPIOD_IS_IN)) {
123 debug("%s: could not find a /config/st,fastboot-gpios\n",
124 __func__);
125 } else {
126 if (dm_gpio_get_value(&gpio)) {
127 puts("Fastboot key pressed, ");
128 boot_mode = BOOT_FASTBOOT;
129 }
130
131 dm_gpio_free(NULL, &gpio);
132 }
133#endif
134#ifdef CONFIG_CMD_STM32PROG
135 if (gpio_request_by_name_nodev(node, "st,stm32prog-gpios", 0,
136 &gpio, GPIOD_IS_IN)) {
137 debug("%s: could not find a /config/st,stm32prog-gpios\n",
138 __func__);
139 } else {
140 if (dm_gpio_get_value(&gpio)) {
141 puts("STM32Programmer key pressed, ");
142 boot_mode = BOOT_STM32PROG;
143 }
144 dm_gpio_free(NULL, &gpio);
145 }
146#endif
147
148 if (boot_mode != BOOT_NORMAL) {
149 puts("entering download mode...\n");
150 clrsetbits_le32(TAMP_BOOT_CONTEXT,
151 TAMP_BOOT_FORCED_MASK,
152 boot_mode);
153 }
154#endif
155}
156
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100157#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
Patrice Chotard204079b2018-08-10 17:12:14 +0200158
Patrick Delaunay7f3384d2019-03-29 15:42:24 +0100159/* STMicroelectronics STUSB1600 Type-C controller */
160#define STUSB1600_CC_CONNECTION_STATUS 0x0E
161
162/* STUSB1600_CC_CONNECTION_STATUS bitfields */
163#define STUSB1600_CC_ATTACH BIT(0)
164
165static int stusb1600_init(struct udevice **dev_stusb1600)
166{
167 ofnode node;
168 struct udevice *dev, *bus;
169 int ret;
170 u32 chip_addr;
171
172 *dev_stusb1600 = NULL;
173
174 /* if node stusb1600 is present, means DK1 or DK2 board */
175 node = ofnode_by_compatible(ofnode_null(), "st,stusb1600");
176 if (!ofnode_valid(node))
177 return -ENODEV;
178
179 ret = ofnode_read_u32(node, "reg", &chip_addr);
180 if (ret)
181 return -EINVAL;
182
183 ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node),
184 &bus);
185 if (ret) {
186 printf("bus for stusb1600 not found\n");
187 return -ENODEV;
188 }
189
190 ret = dm_i2c_probe(bus, chip_addr, 0, &dev);
191 if (!ret)
192 *dev_stusb1600 = dev;
193
194 return ret;
195}
196
197static int stusb1600_cable_connected(struct udevice *dev)
198{
199 u8 status;
200
201 if (dm_i2c_read(dev, STUSB1600_CC_CONNECTION_STATUS, &status, 1))
202 return 0;
203
204 return status & STUSB1600_CC_ATTACH;
205}
206
207#include <usb/dwc2_udc.h>
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100208int g_dnl_board_usb_cable_connected(void)
Patrice Chotard204079b2018-08-10 17:12:14 +0200209{
Patrick Delaunay7f3384d2019-03-29 15:42:24 +0100210 struct udevice *stusb1600;
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100211 struct udevice *dwc2_udc_otg;
Patrice Chotard204079b2018-08-10 17:12:14 +0200212 int ret;
213
Patrick Delaunay7f3384d2019-03-29 15:42:24 +0100214 if (!stusb1600_init(&stusb1600))
215 return stusb1600_cable_connected(stusb1600);
216
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100217 ret = uclass_get_device_by_driver(UCLASS_USB_GADGET_GENERIC,
218 DM_GET_DRIVER(dwc2_udc_otg),
219 &dwc2_udc_otg);
220 if (!ret)
221 debug("dwc2_udc_otg init failed\n");
Patrice Chotard204079b2018-08-10 17:12:14 +0200222
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100223 return dwc2_udc_B_session_valid(dwc2_udc_otg);
Patrice Chotard879cde52019-02-12 16:50:40 +0100224}
Patrick Delaunay58bc0cd2019-03-29 15:42:23 +0100225#endif /* CONFIG_USB_GADGET */
Patrice Chotard879cde52019-02-12 16:50:40 +0100226
227static int get_led(struct udevice **dev, char *led_string)
228{
229 char *led_name;
230 int ret;
231
232 led_name = fdtdec_get_config_string(gd->fdt_blob, led_string);
233 if (!led_name) {
234 pr_debug("%s: could not find %s config string\n",
235 __func__, led_string);
236 return -ENOENT;
237 }
238 ret = led_get_by_label(led_name, dev);
239 if (ret) {
240 debug("%s: get=%d\n", __func__, ret);
241 return ret;
242 }
243
244 return 0;
245}
246
247static int setup_led(enum led_state_t cmd)
248{
249 struct udevice *dev;
250 int ret;
251
252 ret = get_led(&dev, "u-boot,boot-led");
253 if (ret)
254 return ret;
255
256 ret = led_set_state(dev, cmd);
Patrice Chotard204079b2018-08-10 17:12:14 +0200257 return ret;
258}
259
Patrice Chotard879cde52019-02-12 16:50:40 +0100260static int board_check_usb_power(void)
261{
262 struct ofnode_phandle_args adc_args;
263 struct udevice *adc;
264 struct udevice *led;
265 ofnode node;
266 unsigned int raw;
267 int max_uV = 0;
268 int ret, uV, adc_count;
269 u8 i, nb_blink;
270
271 node = ofnode_path("/config");
272 if (!ofnode_valid(node)) {
273 debug("%s: no /config node?\n", __func__);
274 return -ENOENT;
275 }
276
277 /*
278 * Retrieve the ADC channels devices and get measurement
279 * for each of them
280 */
281 adc_count = ofnode_count_phandle_with_args(node, "st,adc_usb_pd",
282 "#io-channel-cells");
283 if (adc_count < 0) {
284 if (adc_count == -ENOENT)
285 return 0;
286
287 pr_err("%s: can't find adc channel (%d)\n", __func__,
288 adc_count);
289
290 return adc_count;
291 }
292
293 for (i = 0; i < adc_count; i++) {
294 if (ofnode_parse_phandle_with_args(node, "st,adc_usb_pd",
295 "#io-channel-cells", 0, i,
296 &adc_args)) {
297 pr_debug("%s: can't find /config/st,adc_usb_pd\n",
298 __func__);
299 return 0;
300 }
301
302 ret = uclass_get_device_by_ofnode(UCLASS_ADC, adc_args.node,
303 &adc);
304
305 if (ret) {
306 pr_err("%s: Can't get adc device(%d)\n", __func__,
307 ret);
308 return ret;
309 }
310
311 ret = adc_channel_single_shot(adc->name, adc_args.args[0],
312 &raw);
313 if (ret) {
314 pr_err("%s: single shot failed for %s[%d]!\n",
315 __func__, adc->name, adc_args.args[0]);
316 return ret;
317 }
318 /* Convert to uV */
319 if (!adc_raw_to_uV(adc, raw, &uV)) {
320 if (uV > max_uV)
321 max_uV = uV;
322 pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__,
323 adc->name, adc_args.args[0], raw, uV);
324 } else {
325 pr_err("%s: Can't get uV value for %s[%d]\n",
326 __func__, adc->name, adc_args.args[0]);
327 }
328 }
329
330 /*
331 * If highest value is inside 1.23 Volts and 2.10 Volts, that means
332 * board is plugged on an USB-C 3A power supply and boot process can
333 * continue.
334 */
335 if (max_uV > USB_START_LOW_THRESHOLD_UV &&
336 max_uV < USB_START_HIGH_THRESHOLD_UV)
337 return 0;
338
339 /* Display warning message and make u-boot,error-led blinking */
340 pr_err("\n*******************************************\n");
341
342 if (max_uV < USB_WARNING_LOW_THRESHOLD_UV) {
343 pr_err("* WARNING 500mA power supply detected *\n");
344 nb_blink = 2;
345 } else {
346 pr_err("* WARNING 1.5A power supply detected *\n");
347 nb_blink = 3;
348 }
349
350 pr_err("* Current too low, use a 3A power supply! *\n");
351 pr_err("*******************************************\n\n");
352
353 ret = get_led(&led, "u-boot,error-led");
354 if (ret)
355 return ret;
356
357 for (i = 0; i < nb_blink * 2; i++) {
358 led_set_state(led, LEDST_TOGGLE);
359 mdelay(125);
360 }
361 led_set_state(led, LEDST_ON);
362
363 return 0;
364}
365
Patrick Delaunay4ace1d12019-02-27 17:01:24 +0100366static void sysconf_init(void)
367{
368#ifndef CONFIG_STM32MP1_TRUSTED
369 u8 *syscfg;
370#ifdef CONFIG_DM_REGULATOR
371 struct udevice *pwr_dev;
372 struct udevice *pwr_reg;
373 struct udevice *dev;
374 int ret;
375 u32 otp = 0;
376#endif
377 u32 bootr;
378
379 syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
380
381 /* interconnect update : select master using the port 1 */
382 /* LTDC = AXI_M9 */
383 /* GPU = AXI_M8 */
384 /* today information is hardcoded in U-Boot */
385 writel(BIT(9), syscfg + SYSCFG_ICNR);
386
387 /* disable Pull-Down for boot pin connected to VDD */
388 bootr = readl(syscfg + SYSCFG_BOOTR);
389 bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT);
390 bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT;
391 writel(bootr, syscfg + SYSCFG_BOOTR);
392
393#ifdef CONFIG_DM_REGULATOR
394 /* High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
395 * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection.
396 * The customer will have to disable this for low frequencies
397 * or if AFMUX is selected but the function not used, typically for
398 * TRACE. Otherwise, impact on power consumption.
399 *
400 * WARNING:
401 * enabling High Speed mode while VDD>2.7V
402 * with the OTP product_below_2v5 (OTP 18, BIT 13)
403 * erroneously set to 1 can damage the IC!
404 * => U-Boot set the register only if VDD < 2.7V (in DT)
405 * but this value need to be consistent with board design
406 */
407 ret = syscon_get_by_driver_data(STM32MP_SYSCON_PWR, &pwr_dev);
408 if (!ret) {
409 ret = uclass_get_device_by_driver(UCLASS_MISC,
410 DM_GET_DRIVER(stm32mp_bsec),
411 &dev);
412 if (ret) {
413 pr_err("Can't find stm32mp_bsec driver\n");
414 return;
415 }
416
417 ret = misc_read(dev, STM32_BSEC_SHADOW(18), &otp, 4);
418 if (!ret)
419 otp = otp & BIT(13);
420
421 /* get VDD = pwr-supply */
422 ret = device_get_supply_regulator(pwr_dev, "pwr-supply",
423 &pwr_reg);
424
425 /* check if VDD is Low Voltage */
426 if (!ret) {
427 if (regulator_get_value(pwr_reg) < 2700000) {
428 writel(SYSCFG_IOCTRLSETR_HSLVEN_TRACE |
429 SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI |
430 SYSCFG_IOCTRLSETR_HSLVEN_ETH |
431 SYSCFG_IOCTRLSETR_HSLVEN_SDMMC |
432 SYSCFG_IOCTRLSETR_HSLVEN_SPI,
433 syscfg + SYSCFG_IOCTRLSETR);
434
435 if (!otp)
436 pr_err("product_below_2v5=0: HSLVEN protected by HW\n");
437 } else {
438 if (otp)
439 pr_err("product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n");
440 }
441 } else {
442 debug("VDD unknown");
443 }
444 }
445#endif
446
447 /* activate automatic I/O compensation
448 * warning: need to ensure CSI enabled and ready in clock driver
449 */
450 writel(SYSCFG_CMPENSETR_MPU_EN, syscfg + SYSCFG_CMPENSETR);
451
452 while (!(readl(syscfg + SYSCFG_CMPCR) & SYSCFG_CMPCR_READY))
453 ;
454 clrbits_le32(syscfg + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
455#endif
456}
457
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +0100458/* board dependent setup after realloc */
459int board_init(void)
460{
Patrice Chotard972723a2019-03-11 11:13:17 +0100461 struct udevice *dev;
462
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +0100463 /* address of boot parameters */
464 gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100;
465
Patrice Chotard972723a2019-03-11 11:13:17 +0100466 /* probe all PINCTRL for hog */
467 for (uclass_first_device(UCLASS_PINCTRL, &dev);
468 dev;
469 uclass_next_device(&dev)) {
470 pr_debug("probe pincontrol = %s\n", dev->name);
471 }
472
Patrick Delaunay008d3c32019-02-27 17:01:20 +0100473 board_key_check();
474
Patrick Delaunay4ace1d12019-02-27 17:01:24 +0100475 sysconf_init();
476
Patrick Delaunay36e3d112018-07-27 16:37:08 +0200477 if (IS_ENABLED(CONFIG_LED))
478 led_default_state();
479
Patrick Delaunay8eb3b1e2018-03-12 10:46:18 +0100480 return 0;
481}
Patrick Delaunayd70e3f82019-02-27 17:01:11 +0100482
483int board_late_init(void)
484{
485#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
486 const void *fdt_compat;
487 int fdt_compat_len;
488
489 fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
490 &fdt_compat_len);
491 if (fdt_compat && fdt_compat_len) {
492 if (strncmp(fdt_compat, "st,", 3) != 0)
493 env_set("board_name", fdt_compat);
494 else
495 env_set("board_name", fdt_compat + 3);
496 }
497#endif
498
Patrice Chotard879cde52019-02-12 16:50:40 +0100499 /* for DK1/DK2 boards */
500 board_check_usb_power();
501
Patrick Delaunayd70e3f82019-02-27 17:01:11 +0100502 return 0;
503}
Patrice Chotard879cde52019-02-12 16:50:40 +0100504
505void board_quiesce_devices(void)
506{
507 setup_led(LEDST_OFF);
508}
Patrice Chotard41443cf2019-05-02 18:07:14 +0200509
Patrice Chotard34320372019-05-02 18:28:05 +0200510enum env_location env_get_location(enum env_operation op, int prio)
511{
512 u32 bootmode = get_bootmode();
513
514 if (prio)
515 return ENVL_UNKNOWN;
516
517 switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
518#ifdef CONFIG_ENV_IS_IN_EXT4
519 case BOOT_FLASH_SD:
520 case BOOT_FLASH_EMMC:
521 return ENVL_EXT4;
522#endif
523#ifdef CONFIG_ENV_IS_IN_UBI
524 case BOOT_FLASH_NAND:
525 return ENVL_UBI;
526#endif
Patrice Chotard2c461ec2019-05-09 14:25:36 +0200527#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
528 case BOOT_FLASH_NOR:
529 return ENVL_SPI_FLASH;
530#endif
Patrice Chotard34320372019-05-02 18:28:05 +0200531 default:
532 return ENVL_NOWHERE;
533 }
534}
535
Patrice Chotarddad97bf2019-05-02 18:36:01 +0200536#if defined(CONFIG_ENV_IS_IN_EXT4)
537const char *env_ext4_get_intf(void)
538{
539 u32 bootmode = get_bootmode();
540
541 switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
542 case BOOT_FLASH_SD:
543 case BOOT_FLASH_EMMC:
544 return "mmc";
545 default:
546 return "";
547 }
548}
549
550const char *env_ext4_get_dev_part(void)
551{
552 static char *const dev_part[] = {"0:auto", "1:auto", "2:auto"};
553 u32 bootmode = get_bootmode();
554
555 return dev_part[(bootmode & TAMP_BOOT_INSTANCE_MASK) - 1];
556}
557#endif
558
Patrice Chotard41443cf2019-05-02 18:07:14 +0200559#ifdef CONFIG_SYS_MTDPARTS_RUNTIME
560
561#define MTDPARTS_LEN 256
562#define MTDIDS_LEN 128
563
564/**
565 * The mtdparts_nand0 and mtdparts_nor0 variable tends to be long.
566 * If we need to access it before the env is relocated, then we need
567 * to use our own stack buffer. gd->env_buf will be too small.
568 *
569 * @param buf temporary buffer pointer MTDPARTS_LEN long
570 * @return mtdparts variable string, NULL if not found
571 */
572static const char *env_get_mtdparts(const char *str, char *buf)
573{
574 if (gd->flags & GD_FLG_ENV_READY)
575 return env_get(str);
576 if (env_get_f(str, buf, MTDPARTS_LEN) != -1)
577 return buf;
578
579 return NULL;
580}
581
582/**
583 * update the variables "mtdids" and "mtdparts" with content of mtdparts_<dev>
584 */
585static void board_get_mtdparts(const char *dev,
586 char *mtdids,
587 char *mtdparts)
588{
589 char env_name[32] = "mtdparts_";
590 char tmp_mtdparts[MTDPARTS_LEN];
591 const char *tmp;
592
593 /* name of env variable to read = mtdparts_<dev> */
594 strcat(env_name, dev);
595 tmp = env_get_mtdparts(env_name, tmp_mtdparts);
596 if (tmp) {
597 /* mtdids: "<dev>=<dev>, ...." */
598 if (mtdids[0] != '\0')
599 strcat(mtdids, ",");
600 strcat(mtdids, dev);
601 strcat(mtdids, "=");
602 strcat(mtdids, dev);
603
604 /* mtdparts: "mtdparts=<dev>:<mtdparts_<dev>>;..." */
605 if (mtdparts[0] != '\0')
606 strncat(mtdparts, ";", MTDPARTS_LEN);
607 else
608 strcat(mtdparts, "mtdparts=");
609 strncat(mtdparts, dev, MTDPARTS_LEN);
610 strncat(mtdparts, ":", MTDPARTS_LEN);
611 strncat(mtdparts, tmp, MTDPARTS_LEN);
612 }
613}
614
615void board_mtdparts_default(const char **mtdids, const char **mtdparts)
616{
617 struct udevice *dev;
618 static char parts[2 * MTDPARTS_LEN + 1];
619 static char ids[MTDIDS_LEN + 1];
620 static bool mtd_initialized;
621
622 if (mtd_initialized) {
623 *mtdids = ids;
624 *mtdparts = parts;
625 return;
626 }
627
628 memset(parts, 0, sizeof(parts));
629 memset(ids, 0, sizeof(ids));
630
631 if (!uclass_get_device(UCLASS_MTD, 0, &dev))
632 board_get_mtdparts("nand0", ids, parts);
633
634 if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev))
635 board_get_mtdparts("nor0", ids, parts);
636
637 mtd_initialized = true;
638 *mtdids = ids;
639 *mtdparts = parts;
640 debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts);
641}
642#endif