From b40a034a637fef883de033fe40009afa0807fd3c Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 2 Jun 2021 19:08:23 +0200 Subject: [PATCH 01/19] arm: dts: stm32mp157c-odyssey-som: fix the basic SDMMC2 properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDMMC2 interface hosts an eMMC. Replace the interface properties that would only apply to SD cards—“broken-cd” and “disable-wp”—with relevant ones: “non-removable”, “no-sd” and “no-sdio”. Signed-off-by: Grzegorz Szymaszek Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157c-odyssey-som.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi index e367a311c4..ed399c00d1 100644 --- a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi +++ b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi @@ -267,8 +267,9 @@ pinctrl-0 = <&sdmmc2_b4_pins_a>; pinctrl-1 = <&sdmmc2_b4_od_pins_a>; pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; - broken-cd; - disable-wp; + non-removable; + no-sd; + no-sdio; st,neg-edge; bus-width = <4>; vmmc-supply = <&v3v3>; From b1c8ad53f5df284b7ba989cb9e2cda52c15277c4 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 2 Jun 2021 19:09:03 +0200 Subject: [PATCH 02/19] arm: dts: stm32mp157c-odyssey-som: enable all SDMMC2 data lanes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the “sdmmc2_d47_pins_d” pins to the SDMMC2 pinctrls. Increase the bus width from four to eight. Signed-off-by: Grzegorz Szymaszek Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157c-odyssey-som.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi index ed399c00d1..7323325e60 100644 --- a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi +++ b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi @@ -264,14 +264,14 @@ &sdmmc2 { pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc2_b4_pins_a>; - pinctrl-1 = <&sdmmc2_b4_od_pins_a>; - pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; + pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_d>; + pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_d>; + pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_d>; non-removable; no-sd; no-sdio; st,neg-edge; - bus-width = <4>; + bus-width = <8>; vmmc-supply = <&v3v3>; status = "okay"; }; From 51a2ac966e2ce45ae3b6d43975977db84759ed91 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 2 Jun 2021 19:09:08 +0200 Subject: [PATCH 03/19] arm: dts: stm32mp157c-odyssey-som: set the SDMMC2 VQMMC supply Set the SDMMC2 VQMMC supply to vdd (buck3). Note that in the corresponding Linux kernel device tree, the supply is set to v3v3 (buck4), which is wrong. Signed-off-by: Grzegorz Szymaszek Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157c-odyssey-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi index 7323325e60..583812f137 100644 --- a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi +++ b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi @@ -273,6 +273,7 @@ st,neg-edge; bus-width = <8>; vmmc-supply = <&v3v3>; + vqmmc-supply = <&vdd>; status = "okay"; }; From 7db3307848f2d4734861fda45320345e688ccdac Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 2 Jun 2021 19:09:13 +0200 Subject: [PATCH 04/19] arm: dts: stm32mp157c-odyssey-som: enable the SDMMC2 eMMC HS DDR mode Enable the SDMMC2 eMMC high-speed DDR mode as it is done in the corresponding Linux kernel device tree. Signed-off-by: Grzegorz Szymaszek Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157c-odyssey-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi index 583812f137..1510a5b364 100644 --- a/arch/arm/dts/stm32mp157c-odyssey-som.dtsi +++ b/arch/arm/dts/stm32mp157c-odyssey-som.dtsi @@ -274,6 +274,7 @@ bus-width = <8>; vmmc-supply = <&v3v3>; vqmmc-supply = <&vdd>; + mmc-ddr-3_3v; status = "okay"; }; From 95a34eb42ec1319afaf5e27012744570588e034b Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 2 Jun 2021 19:09:18 +0200 Subject: [PATCH 05/19] arm: dts: stm32mp157c-odyssey-som: enable SDMMC2 in SPL Enable the SDMMC2 device tree node, as well as the pins it uses, in U-Boot SPL. Signed-off-by: Grzegorz Szymaszek Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Patrice Chotard --- .../dts/stm32mp157c-odyssey-som-u-boot.dtsi | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/dts/stm32mp157c-odyssey-som-u-boot.dtsi b/arch/arm/dts/stm32mp157c-odyssey-som-u-boot.dtsi index 6be728846e..4ff848350d 100644 --- a/arch/arm/dts/stm32mp157c-odyssey-som-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157c-odyssey-som-u-boot.dtsi @@ -123,3 +123,24 @@ u-boot,dm-pre-reloc; }; }; + +&sdmmc2 { + u-boot,dm-spl; +}; + +&sdmmc2_b4_pins_a { + u-boot,dm-spl; + pins1 { + u-boot,dm-spl; + }; + pins2 { + u-boot,dm-spl; + }; +}; + +&sdmmc2_d47_pins_d { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; From 88f7ca03b4a2dca45c33ae360c99f6dbe3fe394d Mon Sep 17 00:00:00 2001 From: Daniil Stas Date: Sun, 23 May 2021 22:24:49 +0000 Subject: [PATCH 06/19] spi: stm32_qspi: Fix short data write operation TCF flag only means that all data was sent to FIFO. To check if the data was sent out of FIFO we should also wait for the BUSY flag to be cleared. Otherwise there is a race condition which can lead to inability to write short (one byte long) data. Signed-off-by: Daniil Stas Cc: Patrick Delaunay Cc: Patrice Chotard Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay --- drivers/spi/stm32_qspi.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 4acc9047b9..8f4aabc3d1 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -148,23 +148,24 @@ static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, const struct spi_mem_op *op) { u32 sr; - int ret; + int ret = 0; - if (!op->data.nbytes) - return _stm32_qspi_wait_for_not_busy(priv); - - ret = readl_poll_timeout(&priv->regs->sr, sr, - sr & STM32_QSPI_SR_TCF, - STM32_QSPI_CMD_TIMEOUT_US); - if (ret) { - log_err("cmd timeout (stat:%#x)\n", sr); - } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { - log_err("transfer error (stat:%#x)\n", sr); - ret = -EIO; + if (op->data.nbytes) { + ret = readl_poll_timeout(&priv->regs->sr, sr, + sr & STM32_QSPI_SR_TCF, + STM32_QSPI_CMD_TIMEOUT_US); + if (ret) { + log_err("cmd timeout (stat:%#x)\n", sr); + } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { + log_err("transfer error (stat:%#x)\n", sr); + ret = -EIO; + } + /* clear flags */ + writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); } - /* clear flags */ - writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + if (!ret) + ret = _stm32_qspi_wait_for_not_busy(priv); return ret; } From 2dc41fccf347e8acba980d7bad1507cfadf11476 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 4 Mar 2021 17:47:56 +0100 Subject: [PATCH 07/19] dfu: dfu_mtd: set max_buf_size to erasesize also for NOR devices For NOR devices the logical DFU buffer size is the sector_size, as it is done in dfu_sf.c or in spi/sf_mtd.c (sf_mtd_info.erasesize = flash->sector_size) For NAND the DFU size was already limited to erasesize as has_pages = true. So the mtd dfu backend can use this erasesize for all the MTD devices, NOR and NAND with dfu->max_buf_size = mtd->erasesize This difference was initially copied from MTD command, where data is fully available in RAM without size limitation. This patch avoids to have many sector write in dfu_mtd.c at the end of the DFU transfer and avoids issues with USB timeout or WATCHDOG. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/dfu/dfu_mtd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index ec40b8f6bb..894b570875 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -254,7 +254,6 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s) { char *st; struct mtd_info *mtd; - bool has_pages; int ret, part; mtd = get_mtd_device_nm(devstr); @@ -264,9 +263,7 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s) dfu->dev_type = DFU_DEV_MTD; dfu->data.mtd.info = mtd; - - has_pages = mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH; - dfu->max_buf_size = has_pages ? mtd->erasesize : 0; + dfu->max_buf_size = mtd->erasesize; st = strsep(&s, " "); if (!strcmp(st, "raw")) { From 486808e354fc0e1982950817d6d54a601463f82e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 4 Jun 2021 18:25:55 +0200 Subject: [PATCH 08/19] board: stm32mp1: correct the property name for eth Use the correct name for STMicroelectronics phys config properties, replace '_' by '-': "st,eth_clk_sel" => "st,eth-clk-sel" "st,eth-ref-clk-sel" => st,eth-clk-sel" These property name are aligned with the upstreamed Linux kernel binding: linux/Documentation/devicetree/bindings/net/stm32-dwmac.yaml See Linux kernel commit "dt-bindings: net: stmmac: add phys config properties" merged in v5.1-rc1. This patch allow to reuse the kernel device tree directly in U-Boot. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- board/dhelectronics/dh_stm32mp1/board.c | 4 ++-- board/st/stm32mp1/stm32mp1.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/board/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c index ac1af718d4..d7c1857c16 100644 --- a/board/dhelectronics/dh_stm32mp1/board.c +++ b/board/dhelectronics/dh_stm32mp1/board.c @@ -660,11 +660,11 @@ int board_interface_eth_init(struct udevice *dev, bool eth_ref_clk_sel_reg = false; /* Gigabit Ethernet 125MHz clock selection. */ - eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel"); + eth_clk_sel_reg = dev_read_bool(dev, "st,eth-clk-sel"); /* Ethernet 50Mhz RMII clock selection */ eth_ref_clk_sel_reg = - dev_read_bool(dev, "st,eth_ref_clk_sel"); + dev_read_bool(dev, "st,eth-ref-clk-sel"); syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG); diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 261ec15e1b..18b8870269 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -733,11 +733,11 @@ int board_interface_eth_init(struct udevice *dev, bool eth_ref_clk_sel_reg = false; /* Gigabit Ethernet 125MHz clock selection. */ - eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel"); + eth_clk_sel_reg = dev_read_bool(dev, "st,eth-clk-sel"); /* Ethernet 50Mhz RMII clock selection */ eth_ref_clk_sel_reg = - dev_read_bool(dev, "st,eth_ref_clk_sel"); + dev_read_bool(dev, "st,eth-ref-clk-sel"); syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG); From 5f14e2fe9d70afac8aa6e87319e826c7b9daa489 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:04 +0200 Subject: [PATCH 09/19] stm32mp: stm32prog: remove all the header check for UART download This patch removes the header check for UART download; the check of checksum is not mandatory with even parity and chuck checksum for each 256 received bytes and it is only done for STM32 image (FSBL = TF-A BL2), not for FIT image. This patch solve issue of duplicated 0x100 byte written with FIP header. Fixes: 4fb7b3e10891 ("stm32mp: stm32prog: add FIP header support") Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 14 +- .../mach-stm32mp/cmd_stm32prog/stm32prog.h | 5 - .../cmd_stm32prog/stm32prog_serial.c | 153 ++---------------- 3 files changed, 23 insertions(+), 149 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index 4c4d8a7a69..84b880261a 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -369,23 +369,24 @@ static int parse_flash_layout(struct stm32prog_data *data, bool end_of_line, eof; char *p, *start, *last, *col; struct stm32prog_part_t *part; + struct image_header_s header; int part_list_size; int i; data->part_nb = 0; /* check if STM32image is detected */ - stm32prog_header_check((struct raw_header_s *)addr, &data->header); - if (data->header.type == HEADER_STM32IMAGE) { + stm32prog_header_check((struct raw_header_s *)addr, &header); + if (header.type == HEADER_STM32IMAGE) { u32 checksum; addr = addr + BL_HEADER_SIZE; - size = data->header.image_length; + size = header.image_length; - checksum = stm32prog_header_checksum(addr, &data->header); - if (checksum != data->header.image_checksum) { + checksum = stm32prog_header_checksum(addr, &header); + if (checksum != header.image_checksum) { stm32prog_err("Layout: invalid checksum : 0x%x expected 0x%x", - checksum, data->header.image_checksum); + checksum, header.image_checksum); return -EIO; } } @@ -1727,7 +1728,6 @@ void stm32prog_clean(struct stm32prog_data *data) free(data->part_array); free(data->otp_part); free(data->buffer); - free(data->header_data); } /* DFU callback: used after serial and direct DFU USB access */ diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h index 581b10d0ac..ad404879a7 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h @@ -132,14 +132,9 @@ struct stm32prog_data { u32 *otp_part; u8 pmic_part[PMIC_SIZE]; - /* STM32 header information */ - struct raw_header_s *header_data; - struct image_header_s header; - /* SERIAL information */ u32 cursor; u32 packet_number; - u32 checksum; u8 *buffer; /* size = USART_RAM_BUFFER_SIZE*/ int dfu_seq; u8 read_phase; diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 2b92e3b149..7eca86c11b 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -292,56 +292,6 @@ static void stm32prog_serial_putc(u8 w_byte) } /* Helper function ************************************************/ - -static u8 stm32prog_header(struct stm32prog_data *data) -{ - u8 ret; - u8 boot = 0; - struct dfu_entity *dfu_entity; - u64 size = 0; - - dfu_entity = stm32prog_get_entity(data); - if (!dfu_entity) - return -ENODEV; - - printf("\nSTM32 download write %s\n", dfu_entity->name); - - /* force cleanup to avoid issue with previous read */ - dfu_transaction_cleanup(dfu_entity); - - stm32prog_header_check(data->header_data, &data->header); - - /* no stm32 image header : max size is partition size */ - if (data->header.type != HEADER_STM32IMAGE) { - dfu_entity->get_medium_size(dfu_entity, &size); - data->header.image_length = size; - } - - /**** Flash the header if necessary for boot partition */ - if (data->phase < PHASE_FIRST_USER) - boot = 1; - - /* write header if boot partition */ - if (boot) { - if (ret) { - stm32prog_err("invalid header (error %d)", ret); - } else { - ret = stm32prog_write(data, - (u8 *)data->header_data, - BL_HEADER_SIZE); - } - } else { - if (ret) - printf(" partition without checksum\n"); - ret = 0; - } - - free(data->header_data); - data->header_data = NULL; - - return ret; -} - static u8 stm32prog_start(struct stm32prog_data *data, u32 address) { u8 ret = 0; @@ -388,23 +338,6 @@ static u8 stm32prog_start(struct stm32prog_data *data, u32 address) data->dfu_seq = 0; printf("\n received length = 0x%x\n", data->cursor); - if (data->header.type == HEADER_STM32IMAGE) { - if (data->cursor != - (data->header.image_length + BL_HEADER_SIZE)) { - stm32prog_err("transmission interrupted (length=0x%x expected=0x%x)", - data->cursor, - data->header.image_length + - BL_HEADER_SIZE); - return -EIO; - } - if (data->header.image_checksum != data->checksum) { - stm32prog_err("invalid checksum received (0x%x expected 0x%x)", - data->checksum, - data->header.image_checksum); - return -EIO; - } - printf("\n checksum OK (0x%x)\n", data->checksum); - } /* update DFU with received flashlayout */ if (data->phase == PHASE_FLASHLAYOUT) @@ -627,14 +560,12 @@ static void download_command(struct stm32prog_data *data) u32 counter = 0x0, codesize = 0x0; u8 *ramaddress = 0; u8 rcv_data = 0x0; - struct image_header_s *image_header = &data->header; u32 cursor = data->cursor; long size = 0; u8 operation; u32 packet_number; u32 result = ACK_BYTE; u8 ret; - unsigned int i; bool error; int rcv; @@ -668,13 +599,8 @@ static void download_command(struct stm32prog_data *data) if (packet_number == 0) { /* erase: re-initialize the image_header struct */ data->packet_number = 0; - if (data->header_data) - memset(data->header_data, 0, BL_HEADER_SIZE); - else - data->header_data = calloc(1, BL_HEADER_SIZE); cursor = 0; data->cursor = 0; - data->checksum = 0; /*idx = cursor;*/ } else { data->packet_number++; @@ -746,74 +672,27 @@ static void download_command(struct stm32prog_data *data) goto end; } - /* Update current position in buffer */ - data->cursor += codesize; + switch (operation) { + case PHASE_OTP: + size = codesize; + ret = stm32prog_otp_write(data, cursor, data->buffer, &size); + break; - if (operation == PHASE_OTP) { - size = data->cursor - cursor; - /* no header for OTP */ - if (stm32prog_otp_write(data, cursor, - data->buffer, &size)) - result = ABORT_BYTE; - goto end; + case PHASE_PMIC: + size = codesize; + ret = stm32prog_pmic_write(data, cursor, data->buffer, &size); + break; + + default: + ret = stm32prog_write(data, data->buffer, codesize); + break; } - if (operation == PHASE_PMIC) { - size = data->cursor - cursor; - /* no header for PMIC */ - if (stm32prog_pmic_write(data, cursor, - data->buffer, &size)) - result = ABORT_BYTE; - goto end; - } - - if (cursor < BL_HEADER_SIZE) { - /* size = portion of header in this chunck */ - if (data->cursor >= BL_HEADER_SIZE) - size = BL_HEADER_SIZE - cursor; - else - size = data->cursor - cursor; - memcpy((void *)((u32)(data->header_data) + cursor), - data->buffer, size); - cursor += size; - - if (cursor == BL_HEADER_SIZE) { - /* Check and Write the header */ - if (stm32prog_header(data)) { - result = ABORT_BYTE; - goto end; - } - } else { - goto end; - } - } - - if (data->header.type == HEADER_STM32IMAGE) { - if (data->cursor <= BL_HEADER_SIZE) - goto end; - /* compute checksum on payload */ - for (i = (unsigned long)size; i < codesize; i++) - data->checksum += data->buffer[i]; - - if (data->cursor > - image_header->image_length + BL_HEADER_SIZE) { - log_err("expected size exceeded\n"); - result = ABORT_BYTE; - goto end; - } - - /* write data (payload) */ - ret = stm32prog_write(data, - &data->buffer[size], - codesize - size); - } else { - /* write all */ - ret = stm32prog_write(data, - data->buffer, - codesize); - } if (ret) result = ABORT_BYTE; + else + /* Update current position in buffer */ + data->cursor += codesize; end: stm32prog_serial_result(result); From d4358a648c5a785e708dbf23f0a67290ac22cf70 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:05 +0200 Subject: [PATCH 10/19] stm32mp: stm32prog: add timeout in stm32prog_serial_get_buffer Handle timeout in stm32prog_serial_get_buffer to sent NACK to STM32CubeProgrammer when the buffer is not fully received. This patch avoids to reach the STM32CubeProgrammer timeout and the associated unrecoverable error. Timeout error occurred while waiting for acknowledgment. Error: Write Operation fails at packet number 4165 at address 0x1044FF Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- .../mach-stm32mp/cmd_stm32prog/stm32prog_serial.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 7eca86c11b..2550ae6a2b 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -60,6 +60,9 @@ const u8 cmd_id[] = { #define NB_CMD sizeof(cmd_id) +/* with 115200 bauds, 20 ms allow to receive the 256 bytes buffer */ +#define TIMEOUT_SERIAL_BUFFER 30 + /* DFU support for serial *********************************************/ static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) { @@ -264,6 +267,7 @@ static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count) { struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); int err; + ulong start = get_timer(0); do { err = ops->getc(down_serial_dev); @@ -273,6 +277,10 @@ static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count) } else if (err == -EAGAIN) { ctrlc(); WATCHDOG_RESET(); + if (get_timer(start) > TIMEOUT_SERIAL_BUFFER) { + err = -ETIMEDOUT; + break; + } } else { break; } @@ -648,7 +656,7 @@ static void download_command(struct stm32prog_data *data) printf("transmission error on packet %d, byte %d\n", packet_number, codesize - counter); /* waiting end of packet before flush & NACK */ - mdelay(30); + mdelay(TIMEOUT_SERIAL_BUFFER); data->packet_number--; result = NACK_BYTE; goto end; @@ -666,7 +674,7 @@ static void download_command(struct stm32prog_data *data) /* wait to be sure that all data are received * in the FIFO before flush */ - mdelay(30); + mdelay(TIMEOUT_SERIAL_BUFFER); data->packet_number--; result = NACK_BYTE; goto end; From d68e53b2798962f7c53a9c11c9bf518b600a03af Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:06 +0200 Subject: [PATCH 11/19] stm32mp: stm32prog: add support of initrd in flashlayout Add the support in command stm32prog of kernel load and start with initrd file, identify by the partition Type "Binary" in the flashlayout.tsv, for example: - 0x01 fsbl Binary none 0x0 tfa.stm32 - 0x03 fip Binary none 0x0 fip.bin P 0x10 kernel System ram0 0xC2000000 uImage.bin P 0x11 dtb FileSystem ram0 0xC4000000 board.dtb P 0x12 initrd Binary ram0 0xC4400000 The file can be a legacy image "uInitrd", generated with mkimage, or a RAW initrd image "initrd.gz". After a DFU detach the bootm command with be executed with the associated address, for example: $> bootm 0xC2000000 0xC4400000: 0xC4000000 When the "Binary" partition type is absent, the 'bootm' command starts the kernel without ramdisk, for example: $> bootm 0xC2000000 - 0xC4000000 With this paths, it is no more mandatory to generate FIT including the kernel, DT and initrd: - 0x01 fsbl Binary none 0x0 tfa.stm32 - 0x03 fip Binary none 0x0 fip.bin P 0x10 fit System ram0 0xC2000000 fit.bin Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- .../cmd_stm32prog/cmd_stm32prog.c | 22 +++++++++++++------ .../mach-stm32mp/cmd_stm32prog/stm32prog.c | 10 ++++++--- .../mach-stm32mp/cmd_stm32prog/stm32prog.h | 2 ++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c index e36501a86b..e584bb52bd 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c @@ -45,7 +45,6 @@ static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, bool reset = false; struct image_header_s header; struct stm32prog_data *data; - u32 uimage, dtb; if (argc < 3 || argc > 5) return CMD_RET_USAGE; @@ -119,21 +118,23 @@ static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, goto cleanup; } - uimage = data->uimage; - dtb = data->dtb; - stm32prog_clean(data); free(stm32prog_data); stm32prog_data = NULL; puts("Download done\n"); - if (uimage) { + if (data->uimage) { char boot_addr_start[20]; char dtb_addr[20]; + char initrd_addr[40]; char *bootm_argv[5] = { "bootm", boot_addr_start, "-", dtb_addr, NULL }; + u32 uimage = data->uimage; + u32 dtb = data->dtb; + u32 initrd = data->initrd; + if (!dtb) bootm_argv[3] = env_get("fdtcontroladdr"); else @@ -142,8 +143,15 @@ static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, snprintf(boot_addr_start, sizeof(boot_addr_start) - 1, "0x%x", uimage); - printf("Booting kernel at %s - %s...\n\n\n", - boot_addr_start, bootm_argv[3]); + + if (initrd) { + snprintf(initrd_addr, sizeof(initrd_addr) - 1, "0x%x:0x%x", + initrd, data->initrd_size); + bootm_argv[2] = initrd_addr; + } + + printf("Booting kernel at %s %s %s...\n\n\n", + boot_addr_start, bootm_argv[2], bootm_argv[3]); /* Try bootm for legacy and FIT format image */ if (genimg_get_format((void *)uimage) != IMAGE_FORMAT_INVALID) do_bootm(cmdtp, 0, 4, bootm_argv); diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index 84b880261a..ea69d5dd16 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -1473,7 +1473,7 @@ error: return ret; } -static void stm32prog_end_phase(struct stm32prog_data *data) +static void stm32prog_end_phase(struct stm32prog_data *data, u64 offset) { if (data->phase == PHASE_FLASHLAYOUT) { if (parse_flash_layout(data, STM32_DDR_BASE, 0)) @@ -1489,6 +1489,10 @@ static void stm32prog_end_phase(struct stm32prog_data *data) data->uimage = data->cur_part->addr; if (data->cur_part->part_type == PART_FILESYSTEM) data->dtb = data->cur_part->addr; + if (data->cur_part->part_type == PART_BINARY) { + data->initrd = data->cur_part->addr; + data->initrd_size = offset; + } } if (CONFIG_IS_ENABLED(MMC) && @@ -1747,7 +1751,7 @@ void dfu_flush_callback(struct dfu_entity *dfu) if (dfu->dev_type == DFU_DEV_RAM) { if (dfu->alt == 0 && stm32prog_data->phase == PHASE_FLASHLAYOUT) { - stm32prog_end_phase(stm32prog_data); + stm32prog_end_phase(stm32prog_data, dfu->offset); /* waiting DFU DETACH for reenumeration */ } } @@ -1756,7 +1760,7 @@ void dfu_flush_callback(struct dfu_entity *dfu) return; if (dfu->alt == stm32prog_data->cur_part->alt_id) { - stm32prog_end_phase(stm32prog_data); + stm32prog_end_phase(stm32prog_data, dfu->offset); stm32prog_next_phase(stm32prog_data); } } diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h index ad404879a7..efb51a3022 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h @@ -142,6 +142,8 @@ struct stm32prog_data { /* bootm information */ u32 uimage; u32 dtb; + u32 initrd; + u32 initrd_size; }; extern struct stm32prog_data *stm32prog_data; From 90ed215dd5d3fb4240fe3149eaf23530b6c37420 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:07 +0200 Subject: [PATCH 12/19] stm32mp: stm32prog: solve compilation with CONFIG_FIT_SIGNATURE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_FIT_SIGNATURE is activated, CONFIG_LEGACY_IMAGE_FORMAT is deactivated and the define IMAGE_FORMAT_LEGACY don't exist with include/image.h: #if defined(CONFIG_LEGACY_IMAGE_FORMAT) #define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */ #endif This patch adds the needed check on compilation flag CONFIG_LEGACY_IMAGE_FORMAT to avoid the compilation error for command stm32prog: cmd_stm32prog.c:81:8: error: ‘IMAGE_FORMAT_LEGACY’ undeclared (first use in this function); did you mean ‘IMAGE_FORMAT_FIT’? 81 | if (IMAGE_FORMAT_LEGACY == | ^~~~~~~~~~~~~~~~~~~ | IMAGE_FORMAT_FIT Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c index e584bb52bd..f3790f900f 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c @@ -77,10 +77,12 @@ static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, if (header.type == HEADER_STM32IMAGE) { size = header.image_length + BL_HEADER_SIZE; +#if defined(CONFIG_LEGACY_IMAGE_FORMAT) /* uImage detected in STM32IMAGE, execute the script */ if (IMAGE_FORMAT_LEGACY == genimg_get_format((void *)(addr + BL_HEADER_SIZE))) return image_source_script(addr + BL_HEADER_SIZE, "script@1"); +#endif } } From be4182bf23a73b29eb07496057f346e07534259c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:08 +0200 Subject: [PATCH 13/19] stm32mp: stm32prog: handle the next phase after USB re-enumeration Handle the second USB enumeration only when the flashlayout is received and when phase is PHASE_FLASHLAYOUT. This patch removes the call of stm32prog_next_phase as it is already done in stm32prog_dfu_init(). Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c index bc44d9fc8f..d4a3f7ea16 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c @@ -207,13 +207,10 @@ bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) if (stm32prog_data->phase == PHASE_FLASHLAYOUT) { ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu"); - if (ret || stm32prog_data->phase == PHASE_DO_RESET) + if (ret || stm32prog_data->phase != PHASE_FLASHLAYOUT) return ret; /* prepare the second enumeration with the FlashLayout */ - if (stm32prog_data->phase == PHASE_FLASHLAYOUT) - stm32prog_dfu_init(data); - /* found next selected partition */ - stm32prog_next_phase(data); + stm32prog_dfu_init(data); } ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu"); From b57efb24c9d05c04732f96b1330b2229769114e4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:09 +0200 Subject: [PATCH 14/19] stm32mp: stm32prog: correctly handle DM_PMIC Correctly handle number of alternate when DM_PMIC is not activated. This patch remove the last UNKNOWN partition in this case. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard Acked-by: Jaehoon Chung --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index ea69d5dd16..ab687c272d 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -1150,7 +1150,10 @@ static int dfu_init_entities(struct stm32prog_data *data) struct dfu_entity *dfu; int alt_nb; - alt_nb = 3; /* number of virtual = CMD, OTP, PMIC*/ + alt_nb = 2; /* number of virtual = CMD, OTP*/ + if (CONFIG_IS_ENABLED(DM_PMIC)) + alt_nb++; /* PMIC NVMEM*/ + if (data->part_nb == 0) alt_nb++; /* +1 for FlashLayout */ else From 69446dee3759e09dfaeb99673ad70d1556ed5972 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:10 +0200 Subject: [PATCH 15/19] stm32mp: stm32prog: use get_cpu_dev for GetID command Use get_cpu_dev() in uart getID command and remove the defines DEVICE_ID_BYTE1 and 2 defines. This patch prepare the support for new SOC family. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c index 2550ae6a2b..7de62668fe 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,8 +20,7 @@ /* - configuration part -----------------------------*/ #define USART_BL_VERSION 0x40 /* USART bootloader version V4.0*/ #define UBOOT_BL_VERSION 0x03 /* bootloader version V0.3*/ -#define DEVICE_ID_BYTE1 0x05 /* MSB byte of device ID*/ -#define DEVICE_ID_BYTE2 0x00 /* LSB byte of device ID*/ + #define USART_RAM_BUFFER_SIZE 256 /* Size of USART_RAM_Buf buffer*/ /* - Commands -----------------------------*/ @@ -436,10 +436,12 @@ static void get_version_command(struct stm32prog_data *data) */ static void get_id_command(struct stm32prog_data *data) { + u32 cpu = get_cpu_dev(); + /* Send Device IDCode */ stm32prog_serial_putc(0x1); - stm32prog_serial_putc(DEVICE_ID_BYTE1); - stm32prog_serial_putc(DEVICE_ID_BYTE2); + stm32prog_serial_putc((cpu >> 8) & 0xFF); + stm32prog_serial_putc(cpu & 0xFF); stm32prog_serial_result(ACK_BYTE); } From d4cb4025771e74dbf42c3aa0b6daa734f855928d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:11 +0200 Subject: [PATCH 16/19] stm32mp: stm32prog: change one message level to debug Move the message "Invalid or missing layout file." to debug level as it is a normal behavior and not an error and add the missing '\n'. This patch avoids the strange trace : Boot over usb0! Invalid or missing layout file.DFU alt info setting: done Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c index f3790f900f..feff73c79e 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c @@ -99,7 +99,7 @@ static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, ret = stm32prog_init(data, addr, size); if (ret) - printf("Invalid or missing layout file."); + log_debug("Invalid or missing layout file at 0x%lx.\n", addr); /* prepare DFU for device read/write */ ret = stm32prog_dfu_init(data); From d4710326c814ffbf84eab87dce8f8fd789b0da18 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:12 +0200 Subject: [PATCH 17/19] dfu: add error callback Add error callback in dfu stack to manage some board specific behavior on DFU targets. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/dfu/dfu.c | 12 ++++++++++++ include/dfu.h | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 213a20e7bc..ff1859d946 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -44,6 +44,14 @@ __weak void dfu_initiated_callback(struct dfu_entity *dfu) { } +/* + * The purpose of the dfu_error_callback() function is to + * provide callback for dfu user + */ +__weak void dfu_error_callback(struct dfu_entity *dfu, const char *msg) +{ +} + /* * The purpose of the dfu_usb_get_reset() function is to * provide information if after USB_DETACH request @@ -342,6 +350,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) printf("%s: Wrong sequence number! [%d] [%d]\n", __func__, dfu->i_blk_seq_num, blk_seq_num); dfu_transaction_cleanup(dfu); + dfu_error_callback(dfu, "Wrong sequence number"); return -1; } @@ -366,6 +375,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) ret = dfu_write_buffer_drain(dfu); if (ret) { dfu_transaction_cleanup(dfu); + dfu_error_callback(dfu, "DFU write error"); return ret; } } @@ -375,6 +385,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) pr_err("Buffer overflow! (0x%p + 0x%x > 0x%p)\n", dfu->i_buf, size, dfu->i_buf_end); dfu_transaction_cleanup(dfu); + dfu_error_callback(dfu, "Buffer overflow"); return -1; } @@ -386,6 +397,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) ret = dfu_write_buffer_drain(dfu); if (ret) { dfu_transaction_cleanup(dfu); + dfu_error_callback(dfu, "DFU write error"); return ret; } } diff --git a/include/dfu.h b/include/dfu.h index afada3959b..f6868982df 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -377,6 +377,17 @@ void dfu_initiated_callback(struct dfu_entity *dfu); */ void dfu_flush_callback(struct dfu_entity *dfu); +/** + * dfu_error_callback() - weak callback called at the DFU write error + * + * It is a callback function called by DFU stack after DFU write error. + * This function allows to manage some board specific behavior on DFU targets + * + * @dfu: pointer to the dfu_entity which cause the error + * @msg: the message of the error + */ +void dfu_error_callback(struct dfu_entity *dfu, const char *msg); + int dfu_transaction_initiate(struct dfu_entity *dfu, bool read); void dfu_transaction_cleanup(struct dfu_entity *dfu); From 1f2e3d5599704ea927453ac76a8675b607f32304 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 18 May 2021 15:12:13 +0200 Subject: [PATCH 18/19] stm32mp: stm32prog: handle dfu error Handle DFU stack error in STM32CubeProgrammer protocol. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c index ab687c272d..f7c93a1298 100644 --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c @@ -1783,3 +1783,17 @@ void dfu_initiated_callback(struct dfu_entity *dfu) log_debug("dfu offset = 0x%llx\n", dfu->offset); } } + +void dfu_error_callback(struct dfu_entity *dfu, const char *msg) +{ + struct stm32prog_data *data = stm32prog_data; + + if (!stm32prog_data) + return; + + if (!stm32prog_data->cur_part) + return; + + if (dfu->alt == stm32prog_data->cur_part->alt_id) + stm32prog_err(msg); +} From c262522fd4ed453c079b09eb738ec4cbe4812478 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 27 Apr 2021 10:57:54 +0200 Subject: [PATCH 19/19] clk: cosmetic change in uclass Remove the tab in clk_get_bulk to respect the coding rules. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/clk/clk-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index cac0f6a012..14254212ca 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -160,7 +160,7 @@ int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk) int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk) { int i, ret, err, count; - + bulk->count = 0; count = dev_count_phandle_with_args(dev, "clocks", "#clock-cells", 0);