From a827cb0a8ffbd388b225f0b523e08f19dbcfd614 Mon Sep 17 00:00:00 2001 From: Romuald JEANNE Date: Tue, 17 Sep 2019 13:56:28 +0200 Subject: [PATCH 13/13] ARM v2018.11 stm32mp r3 MISC --- Makefile | 2 +- README | 3 + cmd/bootefi.c | 6 +- cmd/dtimg.c | 50 +- cmd/fastboot.c | 2 + cmd/nvedit.c | 36 +- cmd/part.c | 16 +- cmd/pinmux.c | 1 + cmd/sf.c | 3 +- common/board_f.c | 2 +- common/cli_readline.c | 6 + common/console.c | 47 +- common/image-android-dt.c | 42 ++ common/spl/spl_spi.c | 2 + doc/device-tree-bindings/clock/st,stm32mp1.txt | 4 +- doc/device-tree-bindings/i2c/i2c-stm32.txt | 61 +- doc/device-tree-bindings/net/stm32-dwmac.txt | 6 +- doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt | 2 +- .../regulator/st,stm32mp1-pwr-reg.txt | 11 + doc/device-tree-bindings/spi/spi-stm32-qspi.txt | 69 +-- drivers/adc/adc-uclass.c | 17 +- drivers/adc/stm32-adc-core.c | 3 +- drivers/adc/stm32-adc.c | 13 +- drivers/clk/clk_stm32mp1.c | 53 +- drivers/core/root.c | 3 +- drivers/core/util.c | 2 + drivers/firmware/psci.c | 2 +- drivers/gpio/Kconfig | 4 +- drivers/gpio/Makefile | 2 +- drivers/gpio/stm32_gpio.c | 210 +++++++ drivers/gpio/stm32f7_gpio.c | 216 -------- drivers/hwspinlock/stm32_hwspinlock.c | 26 +- drivers/i2c/stm32f7_i2c.c | 12 +- drivers/mailbox/stm32-ipcc.c | 2 +- drivers/misc/stm32mp_fuse.c | 1 + drivers/mmc/mmc_write.c | 2 +- drivers/mmc/stm32_sdmmc2.c | 8 +- drivers/mtd/mtd_uboot.c | 5 +- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 95 ++-- drivers/net/dwc_eth_qos.c | 85 +-- drivers/phy/phy-stm32-usbphyc.c | 3 +- drivers/pinctrl/pinctrl-stmfx.c | 38 +- drivers/pinctrl/pinctrl_stm32.c | 62 ++- drivers/power/regulator/regulator-uclass.c | 2 +- drivers/power/regulator/stm32-vrefbuf.c | 2 +- drivers/ram/stm32mp1/Kconfig | 10 +- drivers/ram/stm32mp1/Makefile | 3 +- drivers/ram/stm32mp1/stm32mp1_ddr.c | 157 ++++-- drivers/ram/stm32mp1/stm32mp1_ddr.h | 2 - drivers/ram/stm32mp1/stm32mp1_interactive.c | 51 +- drivers/ram/stm32mp1/stm32mp1_ram.c | 18 +- drivers/ram/stm32mp1/stm32mp1_tests.c | 388 ++++++++----- drivers/ram/stm32mp1/stm32mp1_tuning.c | 276 +++++---- drivers/ram/stm32mp1/stm32mp1_tuning.h | 54 -- drivers/remoteproc/rproc-uclass.c | 12 +- drivers/remoteproc/stm32_copro.c | 6 +- drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/stm32_rtc.c | 308 +++++++++++ drivers/serial/serial_stm32.c | 11 +- drivers/serial/serial_stm32.h | 2 + drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/spi-mem.c | 41 +- drivers/spi/spi-uclass.c | 4 +- drivers/spi/stm32_qspi.c | 375 +++++++++---- drivers/spi/stm32_spi.c | 616 +++++++++++++++++++++ drivers/usb/gadget/dwc2_udc_otg.c | 18 +- drivers/usb/gadget/dwc2_udc_otg_priv.h | 1 - drivers/usb/gadget/dwc2_udc_otg_regs.h | 23 +- drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 +- drivers/video/orisetech_otm8009a.c | 7 +- drivers/video/video-uclass.c | 4 +- drivers/watchdog/Kconfig | 59 +- drivers/watchdog/Makefile | 2 +- drivers/watchdog/stm32mp_wdt.c | 120 ++-- env/Kconfig | 18 +- env/ext4.c | 34 +- fs/ext4/ext4_write.c | 6 + include/configs/stm32mp1.h | 123 +++- include/dfu.h | 1 + include/environment.h | 9 + include/ext4fs.h | 1 + include/image-android-dt.h | 2 + include/linux/mtd/mtd.h | 1 + include/netdev.h | 2 + include/spi.h | 9 +- include/usb/dwc2_udc.h | 6 + test/py/tests/test_pinmux.py | 4 + 89 files changed, 2850 insertions(+), 1204 deletions(-) create mode 100644 drivers/gpio/stm32_gpio.c delete mode 100644 drivers/gpio/stm32f7_gpio.c delete mode 100644 drivers/ram/stm32mp1/stm32mp1_tuning.h create mode 100644 drivers/rtc/stm32_rtc.c create mode 100644 drivers/spi/stm32_spi.c diff --git a/Makefile b/Makefile index 693ffae..b9579b2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2018 PATCHLEVEL = 11 SUBLEVEL = -EXTRAVERSION = -stm32mp-r2 +EXTRAVERSION = -stm32mp-r3 NAME = # *DOCUMENTATION* diff --git a/README b/README index a46c7c6..788858c 100644 --- a/README +++ b/README @@ -2192,6 +2192,9 @@ The following options need to be configured: CONFIG_SF_DEFAULT_MODE (see include/spi.h) CONFIG_SF_DEFAULT_SPEED in Hz + In case of DT boot, SPI don't read default speed and mode + from CONFIG_*, but from platdata values computed from available + DT node - TFTP Fixed UDP Port: CONFIG_TFTP_PORT diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 4d68d80..595dbdd 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -190,13 +190,13 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) /* Safe fdt location is at 127MB */ new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, + EFI_BOOT_SERVICES_DATA, fdt_pages, &new_fdt_addr); if (ret != EFI_SUCCESS) { /* If we can't put it there, put it somewhere */ new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size); ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, + EFI_BOOT_SERVICES_DATA, fdt_pages, &new_fdt_addr); if (ret != EFI_SUCCESS) { printf("ERROR: Failed to reserve space for FDT\n"); @@ -625,7 +625,7 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); - if (part < 0) + if (part < 0 || !desc) return; bootefi_device_path = efi_dp_from_part(desc, part); diff --git a/cmd/dtimg.c b/cmd/dtimg.c index 65c8d10..eca6a23 100644 --- a/cmd/dtimg.c +++ b/cmd/dtimg.c @@ -98,10 +98,52 @@ static int do_dtimg_size(cmd_tbl_t *cmdtp, int flag, int argc, return dtimg_get_fdt(argc, argv, CMD_DTIMG_SIZE); } +static int do_dtimg_getindex(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *endp; + ulong hdr_addr; + int index; + char buf[512] = { 0 }; + + if (argc < 4) + return CMD_RET_USAGE; + + hdr_addr = simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0') { + printf("Error: Wrong image address\n"); + return CMD_RET_FAILURE; + } + + if (!android_dt_check_header(hdr_addr)) { + printf("Error: DT image header is incorrect\n"); + return CMD_RET_FAILURE; + } + + index = android_dt_get_index(hdr_addr, strtoul(argv[2], NULL, 0), + strtoul(argv[3], NULL, 0)); + + if (index < 0) { + printf("Error: board id %04lx not found in DT table\n", + strtoul(argv[2], NULL, 0)); + return CMD_RET_FAILURE; + } + + snprintf(buf, sizeof(buf), "%i", index); + + if (argc == 5) + env_set(argv[4], buf); + else + printf("%s\n", buf); + + return CMD_RET_SUCCESS; +} + static cmd_tbl_t cmd_dtimg_sub[] = { U_BOOT_CMD_MKENT(dump, 2, 0, do_dtimg_dump, "", ""), U_BOOT_CMD_MKENT(start, 4, 0, do_dtimg_start, "", ""), U_BOOT_CMD_MKENT(size, 4, 0, do_dtimg_size, "", ""), + U_BOOT_CMD_MKENT(getindex, 5, 0, do_dtimg_getindex, "", ""), }; static int do_dtimg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -137,5 +179,11 @@ U_BOOT_CMD( " - get size (hex, bytes) of FDT in the image, by index\n" " : image address in RAM, in hex\n" " : index of desired FDT in the image\n" - " : name of variable where to store size of FDT" + " : name of variable where to store size of FDT\n" + "dtimg getindex [varname]\n" + " - get index of FDT in the image, by board identifier and revision\n" + " : image address in RAM, in hex\n" + " : board identifier\n" + " : board revision (0 if not used)\n" + " [varname]: name of variable where to store index of FDT" ); diff --git a/cmd/fastboot.c b/cmd/fastboot.c index ae3a5f6..e3d67b2 100644 --- a/cmd/fastboot.c +++ b/cmd/fastboot.c @@ -13,6 +13,7 @@ #include #include #include +#include static int do_fastboot_udp(int argc, char *const argv[], uintptr_t buf_addr, size_t buf_size) @@ -74,6 +75,7 @@ static int do_fastboot_usb(int argc, char *const argv[], break; if (ctrlc()) break; + WATCHDOG_RESET(); usb_gadget_handle_interrupts(controller_index); } diff --git a/cmd/nvedit.c b/cmd/nvedit.c index de16c72..767e824 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -39,18 +39,24 @@ DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \ - !defined(CONFIG_ENV_IS_IN_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_MMC) && \ - !defined(CONFIG_ENV_IS_IN_FAT) && \ - !defined(CONFIG_ENV_IS_IN_EXT4) && \ - !defined(CONFIG_ENV_IS_IN_NAND) && \ - !defined(CONFIG_ENV_IS_IN_NVRAM) && \ - !defined(CONFIG_ENV_IS_IN_ONENAND) && \ - !defined(CONFIG_ENV_IS_IN_SATA) && \ - !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_REMOTE) && \ - !defined(CONFIG_ENV_IS_IN_UBI) && \ +#if defined(CONFIG_ENV_IS_IN_EEPROM) || \ + defined(CONFIG_ENV_IS_IN_FLASH) || \ + defined(CONFIG_ENV_IS_IN_MMC) || \ + defined(CONFIG_ENV_IS_IN_FAT) || \ + defined(CONFIG_ENV_IS_IN_EXT4) || \ + defined(CONFIG_ENV_IS_IN_NAND) || \ + defined(CONFIG_ENV_IS_IN_NVRAM) || \ + defined(CONFIG_ENV_IS_IN_ONENAND) || \ + defined(CONFIG_ENV_IS_IN_SATA) || \ + defined(CONFIG_ENV_IS_IN_SPI_FLASH) || \ + defined(CONFIG_ENV_IS_IN_REMOTE) || \ + defined(CONFIG_ENV_IS_IN_UBI) + +#define ENV_IS_IN_DEVICE + +#endif + +#if !defined(ENV_IS_IN_DEVICE) && \ !defined(CONFIG_ENV_IS_NOWHERE) # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE @@ -738,7 +744,7 @@ ulong env_get_ulong(const char *name, int base, ulong default_val) } #ifndef CONFIG_SPL_BUILD -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -1194,7 +1200,7 @@ static cmd_tbl_t cmd_env_sub[] = { #if defined(CONFIG_CMD_RUN) U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""), #endif U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""), @@ -1266,7 +1272,7 @@ static char env_help_text[] = #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) "env save - save environment\n" #endif "env set [-f] name [arg ...]\n"; diff --git a/cmd/part.c b/cmd/part.c index bfb6488..6a75856 100644 --- a/cmd/part.c +++ b/cmd/part.c @@ -24,6 +24,7 @@ enum cmd_part_info { CMD_PART_INFO_START = 0, CMD_PART_INFO_SIZE, + CMD_PART_INFO_NB, }; static int do_part_uuid(int argc, char * const argv[]) @@ -149,6 +150,9 @@ static int do_part_info(int argc, char * const argv[], enum cmd_part_info param) case CMD_PART_INFO_SIZE: snprintf(buf, sizeof(buf), LBAF, info.size); break; + case CMD_PART_INFO_NB: + snprintf(buf, sizeof(buf), "%i", part); + break; default: printf("** Unknown cmd_part_info value: %d\n", param); return 1; @@ -172,6 +176,11 @@ static int do_part_size(int argc, char * const argv[]) return do_part_info(argc, argv, CMD_PART_INFO_SIZE); } +static int do_part_nb(int argc, char * const argv[]) +{ + return do_part_info(argc, argv, CMD_PART_INFO_NB); +} + static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) @@ -185,6 +194,8 @@ static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_part_start(argc - 2, argv + 2); else if (!strcmp(argv[1], "size")) return do_part_size(argc - 2, argv + 2); + else if (!strcmp(argv[1], "nb")) + return do_part_nb(argc - 2, argv + 2); return CMD_RET_USAGE; } @@ -206,5 +217,8 @@ U_BOOT_CMD( " part can be either partition number or partition name\n" "part size \n" " - set environment variable to the size of the partition (in blocks)\n" - " part can be either partition number or partition name" + " part can be either partition number or partition name\n" + "part nb \n" + " - set environment variable to the number of the partition\n" + " part shall be the partition name" ); diff --git a/cmd/pinmux.c b/cmd/pinmux.c index 6c8ec51..de909a1 100644 --- a/cmd/pinmux.c +++ b/cmd/pinmux.c @@ -27,6 +27,7 @@ static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Can't get the pin-controller: %s!\n", name); return CMD_RET_FAILURE; } + /* fall through */ case 1: if (!currdev) { printf("Pin-controller device is not set!\n"); diff --git a/cmd/sf.c b/cmd/sf.c index 84bb057..f1811d2 100644 --- a/cmd/sf.c +++ b/cmd/sf.c @@ -81,14 +81,13 @@ static int do_spi_flash_probe(int argc, char * const argv[]) { unsigned int bus = CONFIG_SF_DEFAULT_BUS; unsigned int cs = CONFIG_SF_DEFAULT_CS; + /* In DM mode, defaults speed and mode will be taken from DT */ unsigned int speed = CONFIG_SF_DEFAULT_SPEED; unsigned int mode = CONFIG_SF_DEFAULT_MODE; char *endp; #ifdef CONFIG_DM_SPI_FLASH struct udevice *new, *bus_dev; int ret; - /* In DM mode defaults will be taken from DT */ - speed = 0, mode = 0; #else struct spi_flash *new; #endif diff --git a/common/board_f.c b/common/board_f.c index 59745d5..1a3b1c7 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -92,7 +92,7 @@ static int init_func_watchdog_init(void) (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ - defined(CONFIG_IMX_WATCHDOG) || defined(CONFIG_STM32MP_WATCHDOG)) + defined(CONFIG_IMX_WATCHDOG)) hw_watchdog_init(); puts(" Watchdog enabled\n"); # endif diff --git a/common/cli_readline.c b/common/cli_readline.c index 99b6317..a6dc79b 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -13,6 +13,12 @@ #include #include +#ifdef CONFIG_SPL_BUILD +#undef CONFIG_CMDLINE_EDITING +#undef CONFIG_AUTO_COMPLETE +#undef CONFIG_SHOW_ACTIVITY +#endif + DECLARE_GLOBAL_DATA_PTR; static const char erase_seq[] = "\b \b"; /* erase sequence */ diff --git a/common/console.c b/common/console.c index 9a94f32..d0f2793 100644 --- a/common/console.c +++ b/common/console.c @@ -463,6 +463,11 @@ static void print_pre_console_buffer(int flushpoint) char buf_out[CONFIG_PRE_CON_BUF_SZ + 1]; char *buf_in; +#ifdef CONFIG_SILENT_CONSOLE + if (gd->flags & GD_FLG_SILENT) + return; +#endif + buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ; @@ -511,8 +516,11 @@ void putc(const char c) membuff_putbyte(&gd->console_out, c); #endif #ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) + if (gd->flags & GD_FLG_SILENT) { + if (!(gd->flags & GD_FLG_DEVINIT)) + pre_console_putc(c); return; + } #endif #ifdef CONFIG_DISABLE_CONSOLE @@ -552,8 +560,11 @@ void puts(const char *s) membuff_put(&gd->console_out, s, strlen(s)); #endif #ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) + if (gd->flags & GD_FLG_SILENT) { + if (!(gd->flags & GD_FLG_DEVINIT)) + pre_console_puts(s); return; + } #endif #ifdef CONFIG_DISABLE_CONSOLE @@ -713,14 +724,22 @@ int console_assign(int file, const char *devname) return -1; } -static void console_update_silent(void) +/* return true if the 'silent' flag is removed */ +static bool console_update_silent(void) { #ifdef CONFIG_SILENT_CONSOLE - if (env_get("silent") != NULL) + if (env_get("silent") != NULL) { gd->flags |= GD_FLG_SILENT; - else + } else { + unsigned long flags = gd->flags; + gd->flags &= ~GD_FLG_SILENT; + + return !!(flags & GD_FLG_SILENT); + } #endif + + return false; } int console_announce_r(void) @@ -785,6 +804,13 @@ int console_init_r(void) #if CONFIG_IS_ENABLED(CONSOLE_MUX) int iomux_err = 0; #endif + int flushpoint; + + /* update silent for env loaded from flash (initr_env) */ + if (console_update_silent()) + flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; + else + flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; /* set default handlers at first */ gd->jt->getc = serial_getc; @@ -862,7 +888,7 @@ done: if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) return 0; #endif - print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL); + print_pre_console_buffer(flushpoint); return 0; } @@ -876,8 +902,13 @@ int console_init_r(void) struct list_head *list = stdio_get_list(); struct list_head *pos; struct stdio_dev *dev; + int flushpoint; - console_update_silent(); + /* update silent for env loaded from flash (initr_env) */ + if (console_update_silent()) + flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; + else + flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; #ifdef CONFIG_SPLASH_SCREEN /* @@ -940,7 +971,7 @@ int console_init_r(void) if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) return 0; #endif - print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL); + print_pre_console_buffer(flushpoint); return 0; } diff --git a/common/image-android-dt.c b/common/image-android-dt.c index c0683ee..90499d7 100644 --- a/common/image-android-dt.c +++ b/common/image-android-dt.c @@ -153,4 +153,46 @@ void android_dt_print_contents(ulong hdr_addr) unmap_sysmem(fdt); } } + #endif + +/** + * Get dtb index based on board identifier and revision. + * + * @param hdr_addr Start address of DT image + * @param board_id board identifier + * @param board_rev board revision (0 if not used) + * + * @return index in dt table + */ +int android_dt_get_index(ulong hdr_addr, u32 board_id, u32 board_rev) +{ + const struct dt_table_header *hdr; + u32 entry_count, entries_offset, entry_size; + u32 i; + int ret = -1; + + hdr = map_sysmem(hdr_addr, sizeof(*hdr)); + entry_count = fdt32_to_cpu(hdr->dt_entry_count); + entries_offset = fdt32_to_cpu(hdr->dt_entries_offset); + entry_size = fdt32_to_cpu(hdr->dt_entry_size); + unmap_sysmem(hdr); + + for (i = 0; i < entry_count; ++i) { + const ulong e_addr = hdr_addr + entries_offset + i * entry_size; + const struct dt_table_entry *e; + + e = map_sysmem(e_addr, sizeof(*e)); + + if ((fdt32_to_cpu(e->id) == board_id) && + (board_rev == 0 || fdt32_to_cpu(e->rev) == board_rev)) { + ret = i; + unmap_sysmem(e); + break; + } + + unmap_sysmem(e); + } + + return ret; +} diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index 3cefc9a..3d21110 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -77,6 +77,8 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, /* * Load U-Boot image from SPI flash into RAM + * In DM mode: defaults speed and mode will be + * taken from DT when available */ #ifdef CONFIG_DM_SPI_FLASH /* In DM mode defaults will be taken from DT */ diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt index 02e1460..ec1d703 100644 --- a/doc/device-tree-bindings/clock/st,stm32mp1.txt +++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt @@ -164,8 +164,10 @@ used to define the state of associated ST32MP1 oscillators: - clk-csi At boot the clock tree initialization will - - enable oscillators present in device tree + - enable oscillators present in device tree and not disabled + (node with status="disabled"), - disable HSI oscillator if the node is absent (always activated by bootrom) + and not disabled (node with status="disabled"). Optional properties : diff --git a/doc/device-tree-bindings/i2c/i2c-stm32.txt b/doc/device-tree-bindings/i2c/i2c-stm32.txt index 352dba5..7f7686e 100644 --- a/doc/device-tree-bindings/i2c/i2c-stm32.txt +++ b/doc/device-tree-bindings/i2c/i2c-stm32.txt @@ -7,6 +7,7 @@ Required properties : - reg : Offset and length of the register set for the device - interrupts : Must contain the interrupt id for I2C event and then the interrupt id for I2C error. + Optionnaly a wakeup interrupt may be specified. - resets: Must contain the phandle to the reset controller. - clocks: Must contain the input clock of the I2C instance. - A pinctrl state named "default" must be defined to set pins in mode of @@ -20,18 +21,25 @@ Optional properties : the default 100 kHz frequency will be used. For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are 100000 and 400000. - For STM32F7 SoC, Standard-mode, Fast-mode and Fast-mode Plus are supported, - possible values are 100000, 400000 and 1000000. -- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board - (default: 25) -- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board - (default: 10) + For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode, Fast-mode and Fast-mode + Plus are supported, possible values are 100000, 400000 and 1000000. +- i2c-scl-rising-time-ns: I2C SCL Rising time for the board (default: 25) + For STM32F7, STM32H7 and STM32MP1 only. +- i2c-scl-falling-time-ns: I2C SCL Falling time for the board (default: 10) + For STM32F7, STM32H7 and STM32MP1 only. I2C Timings are derived from these 2 values -- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG - whether Fast Mode Plus speed is selected by slave. +- st,syscfg-fmp: Use to set Fast Mode Plus bit within SYSCFG when Fast Mode + Plus speed is selected by slave. 1st cell : phandle to syscfg 2nd cell : register offset within SYSCFG 3rd cell : register bitmask for FMP bit + For STM32F7, STM32H7 and STM32MP1 only. +- st,syscfg-fmp-clr: Use to clear Fast Mode Plus bit within SYSCFG when Fast + Mode Plus speed is selected by slave. + 1st cell: phandle to syscfg + 2nd cell: clear register offset within SYSCFG + 3rd cell: register bitmask for FMP clear bit + For STM32MP1 family only. Example : @@ -61,8 +69,25 @@ Example : pinctrl-1 = <&i2c1_sda_pin_sleep>, <&i2c1_scl_pin_sleep>; pinctrl-names = "default", "sleep"; st,syscfg-fmp = <&syscfg 0x4 0x1>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x1>; }; + i2c@40013000 { + compatible = "st,stm32f7-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40013000 0x400>; + interrupt-names = "event", "error", "wakeup"; + interrupts-extended = <&intc GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>, + <&exti 22 1>; + clocks = <&rcc I2C2_K>; + resets = <&rcc I2C2_R>; + st,syscfg-fmp = <&syscfg 0x4 0x2>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x2>; + }; + + * I2C Devices An I2C device connected onto STM32 I2C controller must use a format described by @@ -75,28 +100,10 @@ Required properties : I2C slave addresses (see i2c.txt for more details) Optional properties : -- wakeup-source - device can be used as a wakeup source. Valid only if device is a - master. -- interrupt-names - should be set as "wakeup" if a dedicated wakeup source is used. - Imply "wakeup-source" property -- interrupts - defined dedicated IRQ wakeup source from controller. - i2c@40005400 { + i2c@40013000 { camera@3c { compatible = "ovti,ov5640"; reg = <0x3c>; }; }; - - i2c@40005400 { - eeprom@64 { - compatible = "linux,slave-24c02"; - reg = <0x40000064>; - wakeup-source; - interrupt-names = "wakeup"; - interrupts-extended = <&exti 25 1>; - }; - }; diff --git a/doc/device-tree-bindings/net/stm32-dwmac.txt b/doc/device-tree-bindings/net/stm32-dwmac.txt index 73773ec..e675803 100644 --- a/doc/device-tree-bindings/net/stm32-dwmac.txt +++ b/doc/device-tree-bindings/net/stm32-dwmac.txt @@ -14,8 +14,7 @@ Required properties: - clock-names: Should be "stmmaceth" for the host clock. Should be "mac-clk-tx" for the MAC TX clock. Should be "mac-clk-rx" for the MAC RX clock. - For MPU family need to add also "ethstp" for power mode clock and, - "syscfg-clk" for SYSCFG clock. + For MPU family need to add also "ethstp" for power mode clock. - interrupt-names: Should contain a list of interrupt names corresponding to the interrupts in the interrupts property, if available. Should be "macirq" for the main MAC IRQ @@ -24,7 +23,8 @@ Required properties: encompases the glue register, and the offset of the control register. Optional properties: -- clock-names: For MPU family "mac-clk-ck" for PHY without quartz +- clock-names: For MPU family "eth-ck" for PHY without quartz + "syscfg-clk" for SYSCFG clock. - st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz - st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz diff --git a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt index e5b1bb5..ee708ce 100644 --- a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt +++ b/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt @@ -102,7 +102,7 @@ controlleur attributes: phyc attributes: ---------------- - st,phy-reg : phy values depending of the DDR type (DDR3/LPDDR2/LPDDR3) - for STM32MP15x: 10 values are requested in this order + for STM32MP15x: 11 values are requested in this order PGCR ACIOCR DXCCR diff --git a/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt index cee27d5..12acf9d 100644 --- a/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt +++ b/doc/device-tree-bindings/regulator/st,stm32mp1-pwr-reg.txt @@ -10,12 +10,17 @@ Required properties: - st,tzcr: syscon of Trust Zone Configuration Register. Usefull to know if we are in secure mode. st,tzcr = & ; +Optional properties: +- vdd-supply: phandle to the parent supply/regulator node for vdd input +- vdd_3v3_usbfs-supply: phandle to the parent supply/regulator node for usb33 Example: pwr-regulators@c { compatible = "st,stm32mp1,pwr-reg"; st,tzcr = <&rcc 0x0 0x1>; + vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; reg11: reg11 { regulator-name = "reg11"; @@ -28,4 +33,10 @@ Example: regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; + + usb33: usb33 { + regulator-name = "usb33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; }; diff --git a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt index 6c7da1d..551a8d6 100644 --- a/doc/device-tree-bindings/spi/spi-stm32-qspi.txt +++ b/doc/device-tree-bindings/spi/spi-stm32-qspi.txt @@ -1,39 +1,44 @@ -STM32 QSPI controller device tree bindings --------------------------------------------- +* STMicroelectronics Quad Serial Peripheral Interface(QSPI) Required properties: -- compatible : should be "st,stm32-qspi". -- reg : 1. Physical base address and size of SPI registers map. - 2. Physical base address & size of mapped NOR Flash. -- spi-max-frequency : Max supported spi frequency. -- status : enable in requried dts. - -Connected flash properties --------------------------- -- spi-max-frequency : Max supported spi frequency. -- spi-tx-bus-width : Bus width (number of lines) for writing (1-4) -- spi-rx-bus-width : Bus width (number of lines) for reading (1-4) -- memory-map : Address and size for memory-mapping the flash +- compatible: should be "st,stm32f469-qspi" +- reg: the first contains the register location and length. + the second contains the memory mapping address and length +- reg-names: should contain the reg names "qspi" "qspi_mm" +- interrupts: should contain the interrupt for the device +- clocks: the phandle of the clock needed by the QSPI controller +- A pinctrl must be defined to set pins in mode of operation for QSPI transfer + +Optional properties: +- resets: must contain the phandle to the reset controller. + +A spi flash (NOR/NAND) must be a child of spi node and could have some +properties. Also see jedec,spi-nor.txt. + +Required properties: +- reg: chip-Select number (QSPI controller may connect 2 flashes) +- spi-max-frequency: max frequency of spi bus + +Optional property: +- spi-rx-bus-width: see ./spi-bus.txt for the description Example: - qspi: quadspi@A0001000 { - compatible = "st,stm32-qspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>; - reg-names = "QuadSPI", "QuadSPI-memory"; - interrupts = <92>; - spi-max-frequency = <108000000>; - status = "okay"; - - qflash0: n25q128a { - #address-cells = <1>; - #size-cells = <1>; - compatible = "micron,n25q128a13", "spi-flash"; - spi-max-frequency = <108000000>; - spi-tx-bus-width = <4>; - spi-rx-bus-width = <4>; - memory-map = <0x90000000 0x1000000>; + +qspi: spi@a0001000 { + compatible = "st,stm32f469-qspi"; + reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = <91>; + resets = <&rcc STM32F4_AHB3_RESET(QSPI)>; + clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0>; + + flash@0 { + compatible = "jedec,spi-nor"; reg = <0>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; + ... }; }; diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index 27b2654..0a492eb 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -277,13 +277,8 @@ static int adc_vdd_platdata_update(struct udevice *dev) * will bind before its supply regulator device, then the below 'get' * will return an error. */ - if (!uc_pdata->vdd_supply) { - /* Only get vdd_supply once */ - ret = device_get_supply_regulator(dev, "vdd-supply", - &uc_pdata->vdd_supply); - if (ret) - return ret; - } + if (!uc_pdata->vdd_supply) + return 0; ret = regulator_get_value(uc_pdata->vdd_supply); if (ret < 0) @@ -299,12 +294,8 @@ static int adc_vss_platdata_update(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); int ret; - if (!uc_pdata->vss_supply) { - ret = device_get_supply_regulator(dev, "vss-supply", - &uc_pdata->vss_supply); - if (ret) - return ret; - } + if (!uc_pdata->vss_supply) + return 0; ret = regulator_get_value(uc_pdata->vss_supply); if (ret < 0) diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index a9aa143..04b6a8a 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -60,7 +60,8 @@ static int stm32h7_adc_clk_sel(struct udevice *dev, { u32 ckmode, presc; unsigned long rate; - int i, div; + unsigned int i; + int div; /* stm32h7 bus clock is common for all ADC instances (mandatory) */ if (!clk_valid(&common->bclk)) { diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index e108062..029338e 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -163,15 +163,16 @@ static int stm32_adc_chan_of_init(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); struct stm32_adc *adc = dev_get_priv(dev); u32 chans[STM32_ADC_CH_MAX]; - int i, num_channels, ret; + unsigned int i, num_channels; + int ret; /* Retrieve single ended channels listed in device tree */ - num_channels = dev_read_size(dev, "st,adc-channels"); - if (num_channels < 0) { - dev_err(dev, "can't get st,adc-channels: %d\n", num_channels); - return num_channels; + ret = dev_read_size(dev, "st,adc-channels"); + if (ret < 0) { + dev_err(dev, "can't get st,adc-channels: %d\n", ret); + return ret; } - num_channels /= sizeof(u32); + num_channels = ret / sizeof(u32); if (num_channels > adc->cfg->max_channels) { dev_err(dev, "too many st,adc-channels: %d\n", num_channels); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 79f834b..2d7b185 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -94,6 +94,7 @@ DECLARE_GLOBAL_DATA_PTR; #define RCC_PLL4CSGR 0x8A4 #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 +#define RCC_SPI2S1CKSELR 0x8D8 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 #define RCC_UART35CKSELR 0x8EC @@ -171,6 +172,7 @@ DECLARE_GLOBAL_DATA_PTR; /* used for ALL PLLNCR registers */ #define RCC_PLLNCR_PLLON BIT(0) #define RCC_PLLNCR_PLLRDY BIT(1) +#define RCC_PLLNCR_SSCG_CTRL BIT(2) #define RCC_PLLNCR_DIVPEN BIT(4) #define RCC_PLLNCR_DIVQEN BIT(5) #define RCC_PLLNCR_DIVREN BIT(6) @@ -301,6 +303,8 @@ enum stm32mp1_parent_sel { _STGEN_SEL, _DSI_SEL, _ADC12_SEL, + _SPI1_SEL, + _RTC_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -538,6 +542,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), @@ -550,6 +555,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), + STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2), @@ -574,7 +580,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK, _ETH_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK_K, _ETH_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 9, ETHRX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK), @@ -585,6 +591,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), + + STM32MP1_CLK(RCC_BDCR, 20, RTC, _RTC_SEL), }; static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER}; @@ -608,6 +616,9 @@ static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48}; static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER}; static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; +static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, + _PLL3_R}; +static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), @@ -625,13 +636,17 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), STM32MP1_CLK_PARENT(_ETH_SEL, RCC_ETHCKSELR, 0, 0x3, eth_parents), - STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), - STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), + STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0x3, qspi_parents), + STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0x3, fmc_parents), STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), - STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), + STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents), + STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), + STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT, + (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT), + rtc_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT @@ -746,6 +761,8 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_STGEN_SEL] = "STGEN", [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", + [_SPI1_SEL] = "SPI1", + [_RTC_SEL] = "RTC", }; static const struct stm32mp1_clk_data stm32mp1_data = { @@ -814,10 +831,11 @@ static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, const struct stm32mp1_clk_sel *sel = priv->data->sel; int i; int s, p; + unsigned int idx; - for (i = 0; i < ARRAY_SIZE(stm32mp1_clks); i++) - if (stm32mp1_clks[i][0] == id) - return stm32mp1_clks[i][1]; + for (idx = 0; idx < ARRAY_SIZE(stm32mp1_clks); idx++) + if (stm32mp1_clks[idx][0] == id) + return stm32mp1_clks[idx][1]; i = stm32mp1_clk_get_id(priv, id); if (i < 0) @@ -1340,7 +1358,10 @@ static void pll_start(struct stm32mp1_clk_priv *priv, int pll_id) { const struct stm32mp1_clk_pll *pll = priv->data->pll; - writel(RCC_PLLNCR_PLLON, priv->base + pll[pll_id].pllxcr); + clrsetbits_le32(priv->base + pll[pll_id].pllxcr, + RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | + RCC_PLLNCR_DIVREN, + RCC_PLLNCR_PLLON); } static int pll_output(struct stm32mp1_clk_priv *priv, int pll_id, int output) @@ -1459,6 +1480,8 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg) RCC_PLLNCSGR_SSCG_MODE_MASK); writel(pllxcsg, priv->base + pll[pll_id].pllxcsgr); + + setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL); } static __maybe_unused int pll_set_rate(struct udevice *dev, @@ -2052,22 +2075,22 @@ static int stm32mp1_clk_probe(struct udevice *dev) stm32mp1_clk_dump(priv); #endif + gd->cpu_clk = stm32mp1_clk_get(priv, _CK_MPU); + gd->bus_clk = stm32mp1_clk_get(priv, _ACLK); + /* DDRPHYC father */ + gd->mem_clk = stm32mp1_clk_get(priv, _PLL2_R); #if defined(CONFIG_DISPLAY_CPUINFO) if (gd->flags & GD_FLG_RELOC) { char buf[32]; printf("Clocks:\n"); - printf("- MPU : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _CK_MPU))); + printf("- MPU : %s MHz\n", strmhz(buf, gd->cpu_clk)); printf("- MCU : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_MCU))); - printf("- AXI : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _ACLK))); + printf("- AXI : %s MHz\n", strmhz(buf, gd->bus_clk)); printf("- PER : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_PER))); - /* DDRPHYC father */ - printf("- DDR : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _PLL2_R))); + printf("- DDR : %s MHz\n", strmhz(buf, gd->mem_clk)); } #endif /* CONFIG_DISPLAY_CPUINFO */ #endif diff --git a/drivers/core/root.c b/drivers/core/root.c index b54bf5b..ab63bc0 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -223,7 +223,8 @@ static int dm_scan_fdt_live(struct udevice *parent, for (np = node_parent->child; np; np = np->sibling) { if (pre_reloc_only && - !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) + !of_find_property(np, "u-boot,dm-pre-reloc", NULL) && + !of_find_property(np, "u-boot,dm-pre-proper", NULL)) continue; if (!of_device_is_available(np)) { pr_debug(" - ignoring disabled device\n"); diff --git a/drivers/core/util.c b/drivers/core/util.c index 451d476..0db01eb 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -34,6 +34,8 @@ bool dm_fdt_pre_reloc(const void *blob, int offset) { if (fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) return true; + if (fdt_getprop(blob, offset, "u-boot,dm-pre-proper", NULL)) + return true; #ifdef CONFIG_TPL_BUILD if (fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL)) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 2cb35f3..5609b69 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -15,7 +15,7 @@ #include #include -psci_fn *invoke_psci_fn; +psci_fn *invoke_psci_fn __attribute__((section(".data"))); static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, unsigned long arg0, unsigned long arg1, diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cd8b34..9e9cfd6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -238,13 +238,13 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. -config STM32F7_GPIO +config STM32_GPIO bool "ST STM32 GPIO driver" depends on DM_GPIO && (STM32 || ARCH_STM32MP) default y help Device model driver support for STM32 GPIO controller. It should be - usable on many stm32 families like stm32f4 & stm32H7. + usable on many stm32 families like stm32f4/f7/h7 and stm32mp1. Tested on STM32F7. config MVEBU_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f186120..c7cab28 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o obj-$(CONFIG_TCA642X) += tca642x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o -obj-$(CONFIG_STM32F7_GPIO) += stm32f7_gpio.o +obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c new file mode 100644 index 0000000..4eea8ae --- /dev/null +++ b/drivers/gpio/stm32_gpio.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Vikas Manocha, for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODE_BITS(gpio_pin) (gpio_pin * 2) +#define MODE_BITS_MASK 3 +#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) + +/* + * convert gpio offset to gpio index due to potential gpio + * holes into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + unsigned int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } + } + /* shouldn't happen */ + return -EINVAL; +} + +static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); + + return 0; +} + +static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); + + writel(BSRR_BIT(idx, value), ®s->bsrr); + + return 0; +} + +static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + return readl(®s->idr) & BIT(idx) ? 1 : 0; +} + +static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + writel(BSRR_BIT(idx, value), ®s->bsrr); + + return 0; +} + +static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index; + int mask; + int idx; + u32 mode; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + + mode = (readl(®s->moder) & mask) >> bits_index; + if (mode == STM32_GPIO_MODE_OUT) + return GPIOF_OUTPUT; + if (mode == STM32_GPIO_MODE_IN) + return GPIOF_INPUT; + if (mode == STM32_GPIO_MODE_AN) + return GPIOF_UNUSED; + + return GPIOF_FUNC; +} + +static const struct dm_gpio_ops gpio_stm32_ops = { + .direction_input = stm32_gpio_direction_input, + .direction_output = stm32_gpio_direction_output, + .get_value = stm32_gpio_get_value, + .set_value = stm32_gpio_set_value, + .get_function = stm32_gpio_get_function, +}; + +static int gpio_stm32_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + struct clk clk; + fdt_addr_t addr; + const char *name; + int ret; + int i; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = (struct stm32_gpio_regs *)addr; + name = dev_read_string(dev, "st,bank-name"); + if (!name) + return -EINVAL; + uc_priv->bank_name = name; + + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); + + uc_priv->gpio_count += args.args[2]; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } + + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + debug("clock enabled for device %s\n", dev->name); + + return 0; +} + +U_BOOT_DRIVER(gpio_stm32) = { + .name = "gpio_stm32", + .id = UCLASS_GPIO, + .probe = gpio_stm32_probe, + .ops = &gpio_stm32_ops, + .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS, + .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv), +}; diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c deleted file mode 100644 index 7fff64e..0000000 --- a/drivers/gpio/stm32f7_gpio.c +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author(s): Vikas Manocha, for STMicroelectronics. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MODE_BITS(gpio_pin) (gpio_pin * 2) -#define MODE_BITS_MASK 3 -#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) - -/* - * convert gpio offset to gpio index due to potential gpio - * holes into gpio bank - */ -int stm32_offset_to_index(struct udevice *dev, unsigned int offset) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - int idx = 0; - int i; - - for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { - if (priv->gpio_range & BIT(i)) { - if (idx == offset) - return idx; - idx++; - } - } - /* shouldn't happen */ - return -EINVAL; -} - -static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct stm32_gpio_regs *regs = priv->regs; - int bits_index; - int mask; - int idx; - - idx = stm32_offset_to_index(dev, offset); - if (idx < 0) - return idx; - - bits_index = MODE_BITS(idx); - mask = MODE_BITS_MASK << bits_index; - - clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); - - return 0; -} - -static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, - int value) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct stm32_gpio_regs *regs = priv->regs; - int bits_index; - int mask; - int idx; - - idx = stm32_offset_to_index(dev, offset); - if (idx < 0) - return idx; - - bits_index = MODE_BITS(idx); - mask = MODE_BITS_MASK << bits_index; - - clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); - - writel(BSRR_BIT(idx, value), ®s->bsrr); - - return 0; -} - -static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct stm32_gpio_regs *regs = priv->regs; - int idx; - - idx = stm32_offset_to_index(dev, offset); - if (idx < 0) - return idx; - - return readl(®s->idr) & BIT(idx) ? 1 : 0; -} - -static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct stm32_gpio_regs *regs = priv->regs; - int idx; - - idx = stm32_offset_to_index(dev, offset); - if (idx < 0) - return idx; - - writel(BSRR_BIT(idx, value), ®s->bsrr); - - return 0; -} - -static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) -{ - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct stm32_gpio_regs *regs = priv->regs; - int bits_index; - int mask; - int idx; - u32 mode; - - idx = stm32_offset_to_index(dev, offset); - if (idx < 0) - return idx; - - bits_index = MODE_BITS(idx); - mask = MODE_BITS_MASK << bits_index; - - mode = (readl(®s->moder) & mask) >> bits_index; - if (mode == STM32_GPIO_MODE_OUT) - return GPIOF_OUTPUT; - if (mode == STM32_GPIO_MODE_IN) - return GPIOF_INPUT; - if (mode == STM32_GPIO_MODE_AN) - return GPIOF_UNUSED; - - return GPIOF_FUNC; -} - -static const struct dm_gpio_ops gpio_stm32_ops = { - .direction_input = stm32_gpio_direction_input, - .direction_output = stm32_gpio_direction_output, - .get_value = stm32_gpio_get_value, - .set_value = stm32_gpio_set_value, - .get_function = stm32_gpio_get_function, -}; - -static int gpio_stm32_probe(struct udevice *dev) -{ - struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - struct stm32_gpio_priv *priv = dev_get_priv(dev); - struct ofnode_phandle_args args; - struct clk clk; - fdt_addr_t addr; - const char *name; - int ret; - int i; - - addr = dev_read_addr(dev); - if (addr == FDT_ADDR_T_NONE) - return -EINVAL; - - priv->regs = (struct stm32_gpio_regs *)addr; - name = dev_read_string(dev, "st,bank-name"); - if (!name) - return -EINVAL; - uc_priv->bank_name = name; - - i = 0; - ret = dev_read_phandle_with_args(dev, "gpio-ranges", - NULL, 3, i, &args); - - while (ret != -ENOENT) { - priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, - args.args[0]); - - uc_priv->gpio_count += args.args[2]; - - ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, - ++i, &args); - } - - dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", - (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, - priv->gpio_range); - - ret = clk_get_by_index(dev, 0, &clk); - if (ret < 0) - return ret; - - ret = clk_enable(&clk); - - if (ret) { - dev_err(dev, "failed to enable clock\n"); - return ret; - } - debug("clock enabled for device %s\n", dev->name); - - return 0; -} - -static const struct udevice_id stm32_gpio_ids[] = { - { .compatible = "st,stm32-gpio" }, - { } -}; - -U_BOOT_DRIVER(gpio_stm32) = { - .name = "gpio_stm32", - .id = UCLASS_GPIO, - .of_match = stm32_gpio_ids, - .probe = gpio_stm32_probe, - .ops = &gpio_stm32_ops, - .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS, - .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv), -}; diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c index b8f3b16..a32bde4 100644 --- a/drivers/hwspinlock/stm32_hwspinlock.c +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include @@ -15,22 +13,26 @@ #define STM32_MUTEX_LOCK_BIT BIT(31) #define STM32_MUTEX_NUM_LOCKS 32 +struct stm32mp1_hws_priv { + fdt_addr_t base; +}; + static int stm32mp1_lock(struct udevice *dev, int index) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); u32 status; if (index >= STM32_MUTEX_NUM_LOCKS) return -EINVAL; - status = readl(*base + index * sizeof(u32)); + status = readl(priv->base + index * sizeof(u32)); if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) return -EBUSY; writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, - *base + index * sizeof(u32)); + priv->base + index * sizeof(u32)); - status = readl(*base + index * sizeof(u32)); + status = readl(priv->base + index * sizeof(u32)); if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) return -EINVAL; @@ -39,24 +41,24 @@ static int stm32mp1_lock(struct udevice *dev, int index) static int stm32mp1_unlock(struct udevice *dev, int index) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); if (index >= STM32_MUTEX_NUM_LOCKS) return -EINVAL; - writel(STM32_MUTEX_COREID, *base + index * sizeof(u32)); + writel(STM32_MUTEX_COREID, priv->base + index * sizeof(u32)); return 0; } static int stm32mp1_hwspinlock_probe(struct udevice *dev) { - fdt_addr_t *base = dev_get_priv(dev); + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); struct clk clk; int ret; - *base = dev_read_addr(dev); - if (*base == FDT_ADDR_T_NONE) + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; ret = clk_get_by_index(dev, 0, &clk); @@ -86,5 +88,5 @@ U_BOOT_DRIVER(hwspinlock_stm32mp1) = { .of_match = stm32mp1_hwspinlock_ids, .ops = &stm32mp1_hwspinlock_ops, .probe = stm32mp1_hwspinlock_probe, - .priv_auto_alloc_size = sizeof(fdt_addr_t), + .priv_auto_alloc_size = sizeof(struct stm32mp1_hws_priv), }; diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 50c4fd0..2b18735 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -519,13 +519,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, /* Compute possible values for PRESC, SCLDEL and SDADEL */ for (p = 0; p < STM32_PRESC_MAX; p++) { for (l = 0; l < STM32_SCLDEL_MAX; l++) { - u32 scldel = (l + 1) * (p + 1) * i2cclk; + int scldel = (l + 1) * (p + 1) * i2cclk; if (scldel < scldel_min) continue; for (a = 0; a < STM32_SDADEL_MAX; a++) { - u32 sdadel = (a * (p + 1) + 1) * i2cclk; + int sdadel = (a * (p + 1) + 1) * i2cclk; if (((sdadel >= sdadel_min) && (sdadel <= sdadel_max)) && @@ -613,10 +613,12 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= i2c_specs[setup->speed].h_min) && (i2cclk < tscl_h)) { - int clk_error = tscl - i2cbus; + u32 clk_error; - if (clk_error < 0) - clk_error = -clk_error; + if (tscl > i2cbus) + clk_error = tscl - i2cbus; + else + clk_error = i2cbus - tscl; if (clk_error < clk_error_prev) { clk_error_prev = clk_error; diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index dfcea91..4ebec15 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -127,7 +127,7 @@ static int stm32_ipcc_probe(struct udevice *dev) /* proc_id */ cell = dev_read_prop(dev, "st,proc_id", &len); - if (len < sizeof(fdt32_t)) { + if (sizeof(fdt32_t) - len > 0) { dev_dbg(dev, "Missing st,proc_id\n"); return -EINVAL; } diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 842871f..e199abe 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 1a3f561..b8acc33 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -79,7 +79,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) u32 start_rem, blkcnt_rem; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; - int timeout = 2000; + int timeout = 1000; if (!mmc) return -1; diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index ed31ca1..32434a4 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -14,6 +14,7 @@ #include #include #include +#include struct stm32_sdmmc2_plat { struct mmc_config cfg; @@ -190,7 +191,7 @@ struct stm32_sdmmc2_ctx { #define SDMMC_IDMACTRL_IDMAEN BIT(0) #define SDMMC_CMD_TIMEOUT 0xFFFFFFFF -#define SDMMC_BUSYD0END_TIMEOUT_US 1000000 +#define SDMMC_BUSYD0END_TIMEOUT_US 2000000 static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, struct mmc_data *data, @@ -432,6 +433,8 @@ static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0; int ret, retry = 3; + WATCHDOG_RESET(); + retry_cmd: ctx.data_length = 0; ctx.dpsm_abort = false; @@ -669,6 +672,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev) switch (dev_read_u32_default(dev, "bus-width", 1)) { case 8: cfg->host_caps |= MMC_MODE_8BIT; + /* fall through */ case 4: cfg->host_caps |= MMC_MODE_4BIT; break; @@ -692,7 +696,7 @@ clk_free: return ret; } -int stm32_sdmmc_bind(struct udevice *dev) +static int stm32_sdmmc_bind(struct udevice *dev) { struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index 5ca560c..6c11810 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -123,7 +123,6 @@ static const char *get_mtdparts(void) { __maybe_unused const char *mtdids = NULL; static char tmp_parts[MTDPARTS_MAXLEN]; - static bool use_defaults = true; const char *mtdparts = NULL; if (gd->flags & GD_FLG_ENV_READY) @@ -131,7 +130,7 @@ static const char *get_mtdparts(void) else if (env_get_f("mtdparts", tmp_parts, sizeof(tmp_parts)) != -1) mtdparts = tmp_parts; - if (mtdparts || !use_defaults) + if (mtdparts) return mtdparts; #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) @@ -145,8 +144,6 @@ static const char *get_mtdparts(void) if (mtdparts) env_set("mtdparts", mtdparts); - use_defaults = false; - return mtdparts; } diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 6f6f5e6..a54af94 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -627,21 +627,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, struct stm32_fmc2_timings *tims = &nand->timings; unsigned long hclk = clk_get_rate(&fmc2->clk); unsigned long hclkp = FMC2_NSEC_PER_SEC / (hclk / 1000); - int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; - - tar = hclkp; - if (tar < sdrt->tAR_min) - tar = sdrt->tAR_min; - tims->tar = DIV_ROUND_UP(tar, hclkp) - 1; - if (tims->tar > FMC2_PCR_TIMING_MASK) - tims->tar = FMC2_PCR_TIMING_MASK; - - tclr = hclkp; - if (tclr < sdrt->tCLR_min) - tclr = sdrt->tCLR_min; - tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1; - if (tims->tclr > FMC2_PCR_TIMING_MASK) - tims->tclr = FMC2_PCR_TIMING_MASK; + unsigned long timing, tar, tclr, thiz, twait; + unsigned long tset_mem, tset_att, thold_mem, thold_att; + + tar = max_t(unsigned long, hclkp, sdrt->tAR_min); + timing = DIV_ROUND_UP(tar, hclkp) - 1; + tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); + + tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min); + timing = DIV_ROUND_UP(tclr, hclkp) - 1; + tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); tims->thiz = FMC2_THIZ; thiz = (tims->thiz + 1) * hclkp; @@ -651,18 +646,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * tWAIT > tWP * tWAIT > tREA + tIO */ - twait = hclkp; - if (twait < sdrt->tRP_min) - twait = sdrt->tRP_min; - if (twait < sdrt->tWP_min) - twait = sdrt->tWP_min; - if (twait < sdrt->tREA_max + FMC2_TIO) - twait = sdrt->tREA_max + FMC2_TIO; - tims->twait = DIV_ROUND_UP(twait, hclkp); - if (tims->twait == 0) - tims->twait = 1; - else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK) - tims->twait = FMC2_PMEM_PATT_TIMING_MASK; + twait = max_t(unsigned long, hclkp, sdrt->tRP_min); + twait = max_t(unsigned long, twait, sdrt->tWP_min); + twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO); + timing = DIV_ROUND_UP(twait, hclkp); + tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_MEM > tCS - tWAIT @@ -677,20 +665,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if (twait > thiz && (sdrt->tDS_min > twait - thiz) && (tset_mem < sdrt->tDS_min - (twait - thiz))) tset_mem = sdrt->tDS_min - (twait - thiz); - tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp); - if (tims->tset_mem == 0) - tims->tset_mem = 1; - else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK) - tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(tset_mem, hclkp); + tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tHOLD_MEM > tCH * tHOLD_MEM > tREH - tSETUP_MEM * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) */ - thold_mem = hclkp; - if (thold_mem < sdrt->tCH_min) - thold_mem = sdrt->tCH_min; + thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min); if (sdrt->tREH_min > tset_mem && (thold_mem < sdrt->tREH_min - tset_mem)) thold_mem = sdrt->tREH_min - tset_mem; @@ -700,11 +683,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if ((sdrt->tWC_min > tset_mem + twait) && (thold_mem < sdrt->tWC_min - (tset_mem + twait))) thold_mem = sdrt->tWC_min - (tset_mem + twait); - tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp); - if (tims->thold_mem == 0) - tims->thold_mem = 1; - else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK) - tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(thold_mem, hclkp); + tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_ATT > tCS - tWAIT @@ -726,11 +706,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if (twait > thiz && (sdrt->tDS_min > twait - thiz) && (tset_att < sdrt->tDS_min - (twait - thiz))) tset_att = sdrt->tDS_min - (twait - thiz); - tims->tset_att = DIV_ROUND_UP(tset_att, hclkp); - if (tims->tset_att == 0) - tims->tset_att = 1; - else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK) - tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(tset_att, hclkp); + tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tHOLD_ATT > tALH @@ -745,17 +722,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) */ - thold_att = hclkp; - if (thold_att < sdrt->tALH_min) - thold_att = sdrt->tALH_min; - if (thold_att < sdrt->tCH_min) - thold_att = sdrt->tCH_min; - if (thold_att < sdrt->tCLH_min) - thold_att = sdrt->tCLH_min; - if (thold_att < sdrt->tCOH_min) - thold_att = sdrt->tCOH_min; - if (thold_att < sdrt->tDH_min) - thold_att = sdrt->tDH_min; + thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min); if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; @@ -774,11 +745,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if ((sdrt->tWC_min > tset_att + twait) && (thold_att < sdrt->tWC_min - (tset_att + twait))) thold_att = sdrt->tWC_min - (tset_att + twait); - tims->thold_att = DIV_ROUND_UP(thold_att, hclkp); - if (tims->thold_att == 0) - tims->thold_att = 1; - else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK) - tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(thold_att, hclkp); + tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); } static int stm32_fmc2_setup_interface(struct mtd_info *mtd, int chipnr, @@ -932,7 +900,8 @@ static int stm32_fmc2_probe(struct udevice *dev) struct nand_ecclayout *ecclayout; struct resource resource; struct reset_ctl reset; - int oob_index, chip_cs, mem_region, ret, i; + int oob_index, chip_cs, mem_region, ret; + unsigned int i; spin_lock_init(&fmc2->controller.lock); init_waitqueue_head(&fmc2->controller.wq); @@ -1049,7 +1018,7 @@ static int stm32_fmc2_probe(struct udevice *dev) oob_index = FMC2_BBM_LEN; for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) ecclayout->eccpos[i] = oob_index; - ecclayout->oobfree->offset = oob_index + 1; + ecclayout->oobfree->offset = oob_index; ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; chip->ecc.layout = ecclayout; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 072b8c8..5b933fb 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -262,6 +262,7 @@ struct eqos_desc { struct eqos_config { bool reg_access_always_ok; int mdio_wait; + int swr_wait; int config_mac; int config_mac_mdio; int (*interface)(struct udevice *); @@ -620,7 +621,7 @@ err: return ret; } -void eqos_stop_clks_tegra186(struct udevice *dev) +static void eqos_stop_clks_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -635,7 +636,7 @@ void eqos_stop_clks_tegra186(struct udevice *dev) debug("%s: OK\n", __func__); } -void eqos_stop_clks_stm32(struct udevice *dev) +static void eqos_stop_clks_stm32(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1004,10 +1005,16 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; + ret = eqos->config->ops->eqos_start_clks(dev); + if (ret < 0) { + pr_err("eqos_start_clks() failed: %d", ret); + goto err; + } + ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { pr_err("eqos_start_resets() failed: %d", ret); - goto err; + goto err_stop_clks; } udelay(10); @@ -1015,7 +1022,8 @@ static int eqos_start(struct udevice *dev) eqos->reg_access_ok = true; ret = wait_for_bit_le32(&eqos->dma_regs->mode, - EQOS_DMA_MODE_SWR, false, 10, false); + EQOS_DMA_MODE_SWR, false, + eqos->config->swr_wait, false); if (ret) { pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; @@ -1031,6 +1039,24 @@ static int eqos_start(struct udevice *dev) val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); + /* + * if PHY was already connected and configured, + * don't need to reconnect/reconfigure again + */ + if (!eqos->phy) { + eqos->phy = phy_connect(eqos->mii, 0, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } + } + ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -1255,15 +1281,16 @@ static int eqos_start(struct udevice *dev) err_shutdown_phy: phy_shutdown(eqos->phy); - eqos->phy = NULL; err_stop_resets: eqos->config->ops->eqos_stop_resets(dev); +err_stop_clks: + eqos->config->ops->eqos_stop_clks(dev); err: pr_err("FAILED: %d", ret); return ret; } -void eqos_stop(struct udevice *dev) +static void eqos_stop(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); int i; @@ -1308,12 +1335,16 @@ void eqos_stop(struct udevice *dev) clrbits_le32(&eqos->dma_regs->ch0_rx_control, EQOS_DMA_CH0_RX_CONTROL_SR); + if (eqos->phy) { + phy_shutdown(eqos->phy); + } eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); debug("%s: OK\n", __func__); } -int eqos_send(struct udevice *dev, void *packet, int length) +static int eqos_send(struct udevice *dev, void *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *tx_desc; @@ -1354,7 +1385,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) return -ETIMEDOUT; } -int eqos_recv(struct udevice *dev, int flags, uchar **packetp) +static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *rx_desc; @@ -1378,7 +1409,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) return length; } -int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) +static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); uchar *packet_expected; @@ -1721,6 +1752,7 @@ static int eqos_probe(struct udevice *dev) eqos->mii = mdio_alloc(); if (!eqos->mii) { pr_err("mdio_alloc() failed"); + ret = -ENOMEM; goto err_remove_resources_tegra; } eqos->mii->read = eqos_mdio_read; @@ -1734,34 +1766,9 @@ static int eqos_probe(struct udevice *dev) goto err_free_mdio; } - // Bring up PHY - ret = eqos->config->ops->eqos_start_clks(dev); - if (ret < 0) { - pr_err("eqos_start_clks() failed: %d", ret); - goto err_free_mdio; - } - - eqos->phy = phy_connect(eqos->mii, 0, dev, - eqos->config->interface(dev)); - if (!eqos->phy) { - pr_err("phy_connect() failed"); - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; - } - debug("%s: OK\n", __func__); return 0; -err_shutdown_phy: - phy_shutdown(eqos->phy); - eqos->phy = NULL; -err_stop_resets: - eqos->config->ops->eqos_stop_resets(dev); - eqos->config->ops->eqos_stop_clks(dev); err_free_mdio: mdio_free(eqos->mii); err_remove_resources_tegra: @@ -1781,14 +1788,6 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); - - if (eqos->phy) { - phy_shutdown(eqos->phy); - eqos->phy = NULL; - } - - eqos->config->ops->eqos_stop_resets(dev); - eqos->config->ops->eqos_stop_clks(dev); eqos->config->ops->eqos_remove_resources(dev); eqos_probe_resources_core(dev); @@ -1826,6 +1825,7 @@ static struct eqos_ops eqos_tegra186_ops = { static const struct eqos_config eqos_tegra186_config = { .reg_access_always_ok = false, .mdio_wait = 10, + .swr_wait = 10, .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, .interface = eqos_get_interface_tegra186, @@ -1852,6 +1852,7 @@ static struct eqos_ops eqos_stm32_ops = { static const struct eqos_config eqos_stm32_config = { .reg_access_always_ok = false, .mdio_wait = 10000, + .swr_wait = 50, .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, .interface = eqos_get_interface_stm32, diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 22937d8..b6d3144 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -60,7 +60,8 @@ struct stm32_usbphyc { } phys[MAX_PHYS]; }; -void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) +static void stm32_usbphyc_get_pll_params(u32 clk_rate, + struct pll_params *pll_params) { unsigned long long fvco, ndiv, frac; diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 9b5009a..8bb215f 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -231,23 +231,23 @@ static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, switch (param) { case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_DRIVE_PUSH_PULL: + ret = stmfx_pinctrl_set_type(dev, pin, 0); + break; case PIN_CONFIG_BIAS_PULL_DOWN: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; ret = stmfx_pinctrl_set_pupd(dev, pin, 0); break; case PIN_CONFIG_BIAS_PULL_UP: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; ret = stmfx_pinctrl_set_pupd(dev, pin, 1); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - if (dir == GPIOF_OUTPUT) - ret = stmfx_pinctrl_set_type(dev, pin, 1); - else - ret = stmfx_pinctrl_set_type(dev, pin, 0); - break; - case PIN_CONFIG_DRIVE_PUSH_PULL: - if (dir == GPIOF_OUTPUT) - ret = stmfx_pinctrl_set_type(dev, pin, 0); - else - ret = stmfx_pinctrl_set_type(dev, pin, 1); + ret = stmfx_pinctrl_set_type(dev, pin, 1); break; case PIN_CONFIG_OUTPUT: ret = stmfx_gpio_direction_output(plat->gpio, pin, arg); @@ -286,6 +286,23 @@ static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev, return pin_name; } +static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct stmfx_pinctrl *plat = dev_get_platdata(dev); + int func; + + func = stmfx_gpio_get_function(plat->gpio, selector); + if (func < 0) + return func; + + snprintf(buf, size, "%s", func == GPIOF_INPUT ? "input" : "output"); + + return 0; +} + + static int stmfx_pinctrl_bind(struct udevice *dev) { struct stmfx_pinctrl *plat = dev_get_platdata(dev); @@ -306,6 +323,7 @@ const struct pinctrl_ops stmfx_pinctrl_ops = { .get_pins_count = stmfx_pinctrl_get_pins_count, .get_pin_name = stmfx_pinctrl_get_pin_name, .set_state = pinctrl_generic_set_state, + .get_pin_muxing = stmfx_pinctrl_get_pin_muxing, #if CONFIG_IS_ENABLED(PINCONF) .pinconf_set = stmfx_pinctrl_conf_set, .pinconf_num_params = ARRAY_SIZE(stmfx_pinctrl_conf_params), diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index eb7799d..e74139e 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -4,6 +4,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -135,7 +136,7 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, */ *idx = stm32_offset_to_index(gpio_bank->gpio_dev, selector - pin_count); - if (*idx < 0) + if (IS_ERR_VALUE(*idx)) return NULL; return gpio_bank->gpio_dev; @@ -211,20 +212,21 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, return 0; } + #endif -int stm32_pinctrl_probe(struct udevice *dev) +static int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); - int err; + int ret; + + INIT_LIST_HEAD(&priv->gpio_dev); /* hwspinlock property is optional, just log the error */ - err = hwspinlock_get_by_index(dev, 0, &priv->hws); - if (err) + ret = hwspinlock_get_by_index(dev, 0, &priv->hws); + if (ret) debug("%s: hwspinlock_get_by_index may have failed (%d)\n", - __func__, err); - - INIT_LIST_HEAD(&priv->gpio_dev); + __func__, ret); return 0; } @@ -234,7 +236,7 @@ static int stm32_gpio_config(struct gpio_desc *desc, { struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); struct stm32_gpio_regs *regs = priv->regs; - struct stm32_pinctrl_priv *pinctrl_priv; + struct stm32_pinctrl_priv *ctrl_priv; int ret; u32 index; @@ -242,9 +244,8 @@ static int stm32_gpio_config(struct gpio_desc *desc, ctl->pupd > 2 || ctl->speed > 3) return -EINVAL; - pinctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); - - ret = hwspinlock_lock_timeout(&pinctrl_priv->hws, 10); + ctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); + ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10); if (ret == -ETIME) { dev_err(desc->dev, "HWSpinlock timeout\n"); return ret; @@ -264,7 +265,7 @@ static int stm32_gpio_config(struct gpio_desc *desc, index = desc->offset; clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); - hwspinlock_unlock(&pinctrl_priv->hws); + hwspinlock_unlock(&ctrl_priv->hws); return 0; } @@ -327,8 +328,8 @@ static int stm32_pinctrl_config(int offset) int rv, len; /* - * check for "pinmux" property in each subnode of pin controller - * phandle "pinctrl-0" (e.g. pins1 and pins2 for usart1) + * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for + * usart1) of pin controller phandle "pinctrl-0" */ fdt_for_each_subnode(offset, gd->fdt_blob, offset) { struct stm32_gpio_dsc gpio_dsc; @@ -363,6 +364,35 @@ static int stm32_pinctrl_config(int offset) return 0; } +static int stm32_pinctrl_bind(struct udevice *dev) +{ + ofnode node; + const char *name; + int ret; + + dev_for_each_subnode(node, dev) { + debug("%s: bind %s\n", __func__, ofnode_get_name(node)); + + ofnode_get_property(node, "gpio-controller", &ret); + if (ret < 0) + continue; + /* Get the name of each gpio node */ + name = ofnode_get_name(node); + if (!name) + return -EINVAL; + + /* Bind each gpio node */ + ret = device_bind_driver_to_node(dev, "gpio_stm32", + name, node, NULL); + if (ret) + return ret; + + debug("%s: bind %s\n", __func__, name); + } + + return 0; +} + #if CONFIG_IS_ENABLED(PINCTRL_FULL) static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config) { @@ -431,7 +461,7 @@ U_BOOT_DRIVER(pinctrl_stm32) = { .id = UCLASS_PINCTRL, .of_match = stm32_pinctrl_ids, .ops = &stm32_pinctrl_ops, - .bind = dm_scan_fdt_dev, + .bind = stm32_pinctrl_bind, .probe = stm32_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), }; diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4511625..39e4627 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -113,7 +113,7 @@ int regulator_set_enable(struct udevice *dev, bool enable) uc_pdata = dev_get_uclass_platdata(dev); if (!enable && uc_pdata->always_on) - return -EACCES; + return 0; return ops->set_enable(dev, enable); } diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c index 0ad6833..645528e 100644 --- a/drivers/power/regulator/stm32-vrefbuf.c +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -30,7 +30,7 @@ struct stm32_vrefbuf { struct udevice *vdda_supply; }; -static const unsigned int stm32_vrefbuf_voltages[] = { +static const int stm32_vrefbuf_voltages[] = { /* Matches resp. VRS = 000b, 001b, 010b, 011b */ 2500000, 2048000, 1800000, 1500000, }; diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig index 761de09..2fd8c7b 100644 --- a/drivers/ram/stm32mp1/Kconfig +++ b/drivers/ram/stm32mp1/Kconfig @@ -30,9 +30,17 @@ config STM32MP1_DDR_INTERACTIVE_FORCE useful when SPL is loaded in sysram directly by programmer +config STM32MP1_DDR_TESTS + bool "STM32MP1 DDR driver : tests support" + depends on STM32MP1_DDR_INTERACTIVE + default y + help + activate test support for interactive support in + STM32MP1 DDR controller driver: command test + config STM32MP1_DDR_TUNING bool "STM32MP1 DDR driver : support of tuning" - depends on SPL && STM32MP1_DDR_INTERACTIVE + depends on STM32MP1_DDR_INTERACTIVE default y help activate tuning command in STM32MP1 DDR interactive mode diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile index bc292d1..e1e9135 100644 --- a/drivers/ram/stm32mp1/Makefile +++ b/drivers/ram/stm32mp1/Makefile @@ -6,7 +6,8 @@ obj-y += stm32mp1_ram.o obj-y += stm32mp1_ddr.o -obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o stm32mp1_tests.o +obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o +obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o ifneq ($(DDR_INTERACTIVE),) diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index a83ea39..f6484da 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -41,8 +41,32 @@ struct reg_desc { offsetof(struct stm32mp1_ddrphy, x),\ offsetof(struct y, x)} +#define DDR_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrctl, x),\ + INVALID_OFFSET} + +#define DDRPHY_REG_DYN(x) \ + {#x,\ + offsetof(struct stm32mp1_ddrphy, x),\ + INVALID_OFFSET} + +/*********************************************************** + * PARAMETERS: value get from device tree : + * size / order need to be aligned with binding + * modification NOT ALLOWED !!! + ***********************************************************/ +#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */ +#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */ +#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */ +#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */ + +#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */ +#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */ +#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */ + #define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg) -static const struct reg_desc ddr_reg[] = { +static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = { DDRCTL_REG_REG(mstr), DDRCTL_REG_REG(mrctrl0), DDRCTL_REG_REG(mrctrl1), @@ -71,7 +95,7 @@ static const struct reg_desc ddr_reg[] = { }; #define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing) -static const struct reg_desc ddr_timing[] = { +static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = { DDRCTL_REG_TIMING(rfshtmg), DDRCTL_REG_TIMING(dramtmg0), DDRCTL_REG_TIMING(dramtmg1), @@ -87,7 +111,7 @@ static const struct reg_desc ddr_timing[] = { }; #define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map) -static const struct reg_desc ddr_map[] = { +static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = { DDRCTL_REG_MAP(addrmap1), DDRCTL_REG_MAP(addrmap2), DDRCTL_REG_MAP(addrmap3), @@ -100,7 +124,7 @@ static const struct reg_desc ddr_map[] = { }; #define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf) -static const struct reg_desc ddr_perf[] = { +static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = { DDRCTL_REG_PERF(sched), DDRCTL_REG_PERF(sched1), DDRCTL_REG_PERF(perfhpr1), @@ -121,7 +145,7 @@ static const struct reg_desc ddr_perf[] = { }; #define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg) -static const struct reg_desc ddrphy_reg[] = { +static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = { DDRPHY_REG_REG(pgcr), DDRPHY_REG_REG(aciocr), DDRPHY_REG_REG(dxccr), @@ -136,7 +160,7 @@ static const struct reg_desc ddrphy_reg[] = { }; #define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing) -static const struct reg_desc ddrphy_timing[] = { +static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = { DDRPHY_REG_TIMING(ptr0), DDRPHY_REG_TIMING(ptr1), DDRPHY_REG_TIMING(ptr2), @@ -150,7 +174,7 @@ static const struct reg_desc ddrphy_timing[] = { }; #define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal) -static const struct reg_desc ddrphy_cal[] = { +static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = { DDRPHY_REG_CAL(dx0dllcr), DDRPHY_REG_CAL(dx0dqtr), DDRPHY_REG_CAL(dx0dqstr), @@ -165,11 +189,10 @@ static const struct reg_desc ddrphy_cal[] = { DDRPHY_REG_CAL(dx3dqstr), }; -#define DDR_REG_DYN(x) \ - {#x,\ - offsetof(struct stm32mp1_ddrctl, x),\ - INVALID_OFFSET} - +/************************************************************** + * DYNAMIC REGISTERS: only used for debug purpose (read/modify) + **************************************************************/ +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(stat), DDR_REG_DYN(init0), @@ -181,16 +204,30 @@ static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(pctrl_1), }; -#define DDRPHY_REG_DYN(x) \ - {#x,\ - offsetof(struct stm32mp1_ddrphy, x),\ - INVALID_OFFSET} +#define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn) static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(pir), DDRPHY_REG_DYN(pgsr), + DDRPHY_REG_DYN(zq0sr0), + DDRPHY_REG_DYN(zq0sr1), + DDRPHY_REG_DYN(dx0gsr0), + DDRPHY_REG_DYN(dx0gsr1), + DDRPHY_REG_DYN(dx1gsr0), + DDRPHY_REG_DYN(dx1gsr1), + DDRPHY_REG_DYN(dx2gsr0), + DDRPHY_REG_DYN(dx2gsr1), + DDRPHY_REG_DYN(dx3gsr0), + DDRPHY_REG_DYN(dx3gsr1), }; +#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn) + +#endif + +/***************************************************************** + * REGISTERS ARRAY: used to parse device tree and interactive mode + *****************************************************************/ enum reg_type { REG_REG, REG_TIMING, @@ -199,11 +236,13 @@ enum reg_type { REGPHY_REG, REGPHY_TIMING, REGPHY_CAL, +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE /* dynamic registers => managed in driver or not changed, * can be dumped in interactive mode */ REG_DYN, REGPHY_DYN, +#endif REG_TYPE_NB }; @@ -224,23 +263,25 @@ struct ddr_reg_info { const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { [REG_REG] = { - "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE}, + "static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE}, [REG_TIMING] = { - "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE}, + "timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE}, [REG_PERF] = { - "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE}, + "perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE}, [REG_MAP] = { - "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE}, + "map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE}, [REGPHY_REG] = { - "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE}, + "static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE}, [REGPHY_TIMING] = { - "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE}, + "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE}, [REGPHY_CAL] = { - "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE}, + "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE}, +#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE [REG_DYN] = { - "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE}, + "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE}, [REGPHY_DYN] = { - "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE}, + "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE}, +#endif }; const char *base_name[] = { @@ -281,37 +322,6 @@ static void set_reg(const struct ddr_info *priv, } } -static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) -{ - u32 pgsr; - int ret; - - ret = readl_poll_timeout(&phy->pgsr, pgsr, - pgsr & (DDRPHYC_PGSR_IDONE | - DDRPHYC_PGSR_DTERR | - DDRPHYC_PGSR_DTIERR | - DDRPHYC_PGSR_DFTERR | - DDRPHYC_PGSR_RVERR | - DDRPHYC_PGSR_RVEIRR), - 1000000); - debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n", - (u32)&phy->pgsr, pgsr, ret); -} - -void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) -{ - pir |= DDRPHYC_PIR_INIT; - writel(pir, &phy->pir); - debug("[0x%08x] pir = 0x%08x -> 0x%08x\n", - (u32)&phy->pir, pir, readl(&phy->pir)); - - /* need to wait 10 configuration clock before start polling */ - udelay(10); - - /* Wait DRAM initialization and Gate Training Evaluation complete */ - ddrphy_idone_wait(phy); -} - #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc) { @@ -410,7 +420,7 @@ void stm32mp1_edit_reg(const struct ddr_info *priv, printf("%s not found\n", name); return; } - if (strict_strtoul(string, 16, &value) < 0) { + if (strict_strtoul(string, 16, &value) < 0) { printf("invalid value %s\n", string); return; } @@ -605,7 +615,7 @@ static void wait_operating_mode(struct ddr_info *priv, int mode) } /* Mode Register Writes (MRW or MRS) */ -void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) +static void mode_register_write(struct ddr_info *priv, u8 addr, u16 data) { u32 mrctrl0; @@ -780,6 +790,37 @@ static void ddr3_dll_off(struct ddr_info *priv) debug("%s: exit\n", __func__); } +static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) +{ + u32 pgsr; + int ret; + + ret = readl_poll_timeout(&phy->pgsr, pgsr, + pgsr & (DDRPHYC_PGSR_IDONE | + DDRPHYC_PGSR_DTERR | + DDRPHYC_PGSR_DTIERR | + DDRPHYC_PGSR_DFTERR | + DDRPHYC_PGSR_RVERR | + DDRPHYC_PGSR_RVEIRR), + 1000000); + debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n", + (u32)&phy->pgsr, pgsr, ret); +} + +void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) +{ + pir |= DDRPHYC_PIR_INIT; + writel(pir, &phy->pir); + debug("[0x%08x] pir = 0x%08x -> 0x%08x\n", + (u32)&phy->pir, pir, readl(&phy->pir)); + + /* need to wait 10 configuration clock before start polling */ + udelay(10); + + /* Wait DRAM initialization and Gate Training Evaluation complete */ + ddrphy_idone_wait(phy); +} + void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) { start_sw_done(ctl); diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h index 90b4a4b..52b748f 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h @@ -26,7 +26,6 @@ struct stm32mp1_ddrphy; * @ctl: DDR controleur base address * @clk: DDR clock * @phy: DDR PHY base address - * @pwr: pwr base address * @rcc: rcc base address */ struct ddr_info { @@ -35,7 +34,6 @@ struct ddr_info { struct clk clk; struct stm32mp1_ddrctl *ctl; struct stm32mp1_ddrphy *phy; - void *pwr; u32 rcc; }; diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c index 3840af5..8df6a39 100644 --- a/drivers/ram/stm32mp1/stm32mp1_interactive.c +++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include @@ -52,7 +52,9 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc) [DDR_CMD_STEP] = "step", [DDR_CMD_NEXT] = "next", [DDR_CMD_GO] = "go", +#ifdef CONFIG_STM32MP1_DDR_TESTS [DDR_CMD_TEST] = "test", +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING [DDR_CMD_TUNING] = "tuning", #endif @@ -69,7 +71,9 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc) [DDR_CMD_STEP] = { 0, 1 }, [DDR_CMD_NEXT] = { 0, 0 }, [DDR_CMD_GO] = { 0, 0 }, +#ifdef CONFIG_STM32MP1_DDR_TESTS [DDR_CMD_TEST] = { 0, 255 }, +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING [DDR_CMD_TUNING] = { 0, 255 }, #endif @@ -99,25 +103,32 @@ static void stm32mp1_do_usage(void) { const char *usage = { "commands:\n\n" - "help this message\n" - "info [ ] display/change DDR information\n" - "freq [freq] display/change the DDR frequency\n" - "param [type|reg] print input parameters\n" - "param edit parameters in step 0\n" - "print [type|reg] dump register\n" - "edit modify register\n" - " all registers if [type|reg] is absent\n" - " = ctl, phy\n" - " or one category (static, timing, map, perf, cal, dyn)\n" - " = name of the register\n" - "step [n] list the step / go to the step \n" - "next go to the next step\n" - "go continue SPL execution\n" - "reset reboot machine\n" - "test [help] | [...] list (with help) or execute test \n" + "help displays help\n" + "info displays DDR information\n" + "info changes DDR information\n" + " with = step, name, size or speed\n" + "freq displays the DDR PHY frequency in kHz\n" + "freq changes the DDR PHY frequency\n" + "param [type|reg] prints input parameters\n" + "param edits parameters in step 0\n" + "print [type|reg] dumps registers\n" + "edit modifies one register\n" + "step lists the available step\n" + "step go to the step \n" + "next goes to the next step\n" + "go continues the U-Boot SPL execution\n" + "reset reboots machine\n" +#ifdef CONFIG_STM32MP1_DDR_TESTS + "test [help] | [...] lists (with help) or executes test \n" +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING - "tuning [help] | [...] list (with help) or execute test \n" + "tuning [help] | [...] lists (with help) or execute tuning \n" #endif + "\nwith for [type|reg]:\n" + " all registers if absent\n" + " = ctl, phy\n" + " or one category (static, timing, map, perf, cal, dyn)\n" + " = name of the register\n" }; puts(usage); @@ -295,6 +306,7 @@ end: return step; } +#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING) static const char * const s_result[] = { [TEST_PASSED] = "Pass", [TEST_FAILED] = "Failed", @@ -349,6 +361,7 @@ static void stm32mp1_ddr_subcmd(struct ddr_info *priv, end: printf("Result: %s [%s]\n", s_result[result], string); } +#endif bool stm32mp1_ddr_interactive(void *priv, enum stm32mp1_ddr_interact_step step, @@ -445,11 +458,13 @@ bool stm32mp1_ddr_interactive(void *priv, next_step = stm32mp1_do_step(step, argc, argv); break; +#ifdef CONFIG_STM32MP1_DDR_TESTS case DDR_CMD_TEST: if (!stm32mp1_check_step(step, STEP_DDR_READY)) continue; stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb); break; +#endif #ifdef CONFIG_STM32MP1_DDR_TUNING case DDR_CMD_TUNING: diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index 6245cb4..1da57ce 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -12,8 +12,6 @@ #include #include "stm32mp1_ddr.h" -DECLARE_GLOBAL_DATA_PTR; - static const char *const clkname[] = { "ddrc1", "ddrc2", @@ -28,7 +26,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) unsigned long ddr_clk; struct clk clk; int ret; - int idx; + unsigned int idx; for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) { ret = clk_get_by_name(priv->dev, clkname[idx], &clk); @@ -52,7 +50,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) if (ddr_clk > (mem_speed * 100)) { pr_err("DDR expected freq %d kHz, current is %d kHz\n", mem_speed, (u32)(ddrphy_clk / 1000)); - return -1; + return -EINVAL; } return 0; } @@ -60,7 +58,8 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) { struct ddr_info *priv = dev_get_priv(dev); - int ret, idx; + int ret; + unsigned int idx; struct clk axidcg; struct stm32mp1_ddr_config config; @@ -103,8 +102,8 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) debug("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret); if (ret) { - pr_err("%s: Cannot read %s\n", - __func__, param[idx].name); + pr_err("%s: Cannot read %s, error=%d\n", + __func__, param[idx].name, ret); return -EINVAL; } } @@ -155,11 +154,6 @@ static int stm32mp1_ddr_probe(struct udevice *dev) priv->ctl = regmap_get_range(map, 0); priv->phy = regmap_get_range(map, 1); - map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR); - if (IS_ERR(map)) - return PTR_ERR(map); - priv->pwr = regmap_get_range(map, 0); - priv->rcc = STM32_RCC_BASE; priv->info.base = STM32_DDR_BASE; diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index 5f2af4e..e09ca31 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include "stm32mp1_tests.h" @@ -154,6 +155,7 @@ static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress) return 1; } printf("loop #%d\n", *loop); + WATCHDOG_RESET(); return 0; } @@ -578,27 +580,29 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, u32 error = 0; unsigned int seed; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 8 * 1024)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; if (get_addr(string, argc, argv, 2, &addr)) return TEST_ERROR; - printf("running %d loops at 0x%x\n", nb_loop, addr); + bufsize /= 2; + printf("running %d loops copy from 0x%x to 0x%x (buffer size=0x%x)\n", + nb_loop, addr, addr + bufsize, bufsize); while (!error) { seed = rand(); - for (offset = addr; offset < addr + bufsize; offset += 4) - writel(rand(), offset); + for (offset = 0; offset < bufsize; offset += 4) + writel(rand(), addr + offset); memcpy((void *)addr + bufsize, (void *)addr, bufsize); srand(seed); - for (offset = addr; offset < addr + 2 * bufsize; offset += 4) { - if (offset == (addr + bufsize)) + for (offset = 0; offset < 2 * bufsize; offset += 4) { + if (offset == bufsize) srand(seed); value = rand(); - error = check_addr(offset, value); + error = check_addr(addr + offset, value); if (error) break; if (progress(offset)) @@ -607,6 +611,7 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, if (test_loop_end(&loop, nb_loop, 100)) break; } + putc('\n'); if (error) { sprintf(string, @@ -791,9 +796,9 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, int i; int j; enum test_result res = TEST_PASSED; - u32 *offset, testsize, remaining; + u32 offset, testsize, remaining; - offset = address; + offset = (u32)address; remaining = bufsize; while (remaining) { testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize; @@ -809,7 +814,7 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); - __asm__("subs r2, r2, #8"); + __asm__("subs r2, r2, #128"); __asm__("bge loop2"); __asm__("pop {R0-R10}"); @@ -993,24 +998,34 @@ static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr; + int i; u32 checkboard[2] = {0x55555555, 0xAAAAAAAA}; if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running test checkboard at 0x%08x length 0x%x\n", - STM32_DDR_BASE, bufsize); - - res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, - bufsize); - - checkboard[0] = ~checkboard[0]; - checkboard[1] = ~checkboard[1]; - - res = test_loop_size(checkboard, 2, (u32 *)STM32_DDR_BASE, - bufsize); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 2; i++) { + res = test_loop_size(checkboard, 2, (u32 *)addr, + bufsize); + if (res) + return res; + checkboard[0] = ~checkboard[0]; + checkboard[1] = ~checkboard[1]; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; + } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1020,23 +1035,31 @@ static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 256; i++) { - value = i | i << 8 | i << 16 | i << 24; - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 256; i++) { + value = i | i << 8 | i << 16 | i << 24; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1046,27 +1069,35 @@ static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 64; i++) { - if (i < 32) - value = 1 << i; - else - value = 1 << (63 - i); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 64; i++) { + if (i < 32) + value = 1 << i; + else + value = 1 << (63 - i); - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1076,27 +1107,35 @@ static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, value; int i; - u32 value; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 64; i++) { - if (i < 32) - value = ~(1 << i); - else - value = ~(1 << (63 - i)); + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 64; i++) { + if (i < 32) + value = ~(1 << i); + else + value = ~(1 << (63 - i)); - printf("pattern = %08x", value); - res = test_loop_size(&value, 1, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("pattern = %08x", value); + res = test_loop_size(&value, 1, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1110,34 +1149,42 @@ static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr, bitspread[4]; int i, j; - u32 bitspread[4]; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 1; i < 32; i++) { - for (j = 0; j < i; j++) { - if (i < 32) - bitspread[0] = (1 << i) | (1 << j); - else - bitspread[0] = (1 << (63 - i)) | - (1 << (63 - j)); - bitspread[1] = bitspread[0]; - bitspread[2] = ~bitspread[0]; - bitspread[3] = ~bitspread[0]; - printf("pattern = %08x", bitspread[0]); - - res = test_loop_size(bitspread, 4, - (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 1; i < 32; i++) { + for (j = 0; j < i; j++) { + if (i < 32) + bitspread[0] = (1 << i) | (1 << j); + else + bitspread[0] = (1 << (63 - i)) | + (1 << (63 - j)); + bitspread[1] = bitspread[0]; + bitspread[2] = ~bitspread[0]; + bitspread[3] = ~bitspread[0]; + printf("pattern = %08x", bitspread[0]); + + res = test_loop_size(bitspread, 4, (u32 *)addr, + bufsize); + if (res != TEST_PASSED) + return res; + } } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1147,27 +1194,37 @@ static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { enum test_result res = TEST_PASSED; - u32 bufsize; + u32 bufsize, nb_loop, loop = 0, addr; int i; u32 bitflip[4]; if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) return TEST_ERROR; + if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) + return TEST_ERROR; + if (get_addr(string, argc, argv, 2, &addr)) + return TEST_ERROR; + + printf("running %d loops at 0x%08x length 0x%x\n", + nb_loop, addr, bufsize); + while (1) { + for (i = 0; i < 32; i++) { + bitflip[0] = 1 << i; + bitflip[1] = bitflip[0]; + bitflip[2] = ~bitflip[0]; + bitflip[3] = bitflip[2]; + printf("pattern = %08x", bitflip[0]); - printf("running at 0x%08x length 0x%x\n", STM32_DDR_BASE, bufsize); - for (i = 0; i < 32; i++) { - bitflip[0] = 1 << i; - bitflip[1] = bitflip[0]; - bitflip[2] = ~bitflip[0]; - bitflip[3] = bitflip[2]; - printf("pattern = %08x", bitflip[0]); - - res = test_loop_size(bitflip, 4, (u32 *)STM32_DDR_BASE, - bufsize); - if (res != TEST_PASSED) - return res; + res = test_loop_size(bitflip, 4, (u32 *)addr, bufsize); + if (res != TEST_PASSED) + return res; + } + if (test_loop_end(&loop, nb_loop, 1)) + break; } + sprintf(string, "no error for %d loops at 0x%08x length 0x%x", + loop, addr, bufsize); return res; } @@ -1186,27 +1243,38 @@ static enum test_result test_read(struct stm32mp1_ddrctl *ctl, u32 *addr; u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern=0x%08x\n", + (u32)addr, data); + writel(data, addr); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { - if (random) - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = readl(addr); - if (test_loop_end(&loop, 0, 1000)) + for (i = 0; i < size; i++) { + if (random) + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = readl(addr); + } + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } @@ -1223,31 +1291,41 @@ static enum test_result test_write(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { u32 *addr; - u32 data = 0xA5A5AA55; + u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern 0x%08x\n", + (u32)addr, data); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { - if (random) { - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = rand(); + for (i = 0; i < size; i++) { + if (random) { + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = rand(); + } + writel(data, addr); } - writel(data, addr); - if (test_loop_end(&loop, 0, 1000)) + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } @@ -1259,24 +1337,38 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, { enum test_result res = TEST_PASSED, result; int i, nb_error = 0; + u32 loop = 0, nb_loop; - /* execute all the test except the lasts which are infinite */ - for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { - printf("execute %d:%s\n", (int)i, test[i].name); - result = test[i].fct(ctl, phy, string, 0, NULL); - printf("result %d:%s = ", (int)i, test[i].name); - if (result != TEST_PASSED) { - nb_error++; - res = TEST_FAILED; - puts("Failed"); - } else { - puts("Passed"); + if (get_nb_loop(string, argc, argv, 0, &nb_loop, 1)) + return TEST_ERROR; + + while (!nb_error) { + /* execute all the test except the lasts which are infinite */ + for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) { + printf("execute %d:%s\n", (int)i, test[i].name); + result = test[i].fct(ctl, phy, string, 0, NULL); + printf("result %d:%s = ", (int)i, test[i].name); + if (result != TEST_PASSED) { + nb_error++; + res = TEST_FAILED; + puts("Failed"); + } else { + puts("Passed"); + } + puts("\n\n"); } - puts("\n\n"); + printf("loop %d: %d/%d test failed\n\n\n", + loop + 1, nb_error, test_nb - NB_TEST_INFINITE); + if (test_loop_end(&loop, nb_loop, 1)) + break; + } + if (res != TEST_PASSED) { + sprintf(string, "loop %d: %d/%d test failed", loop, nb_error, + test_nb - NB_TEST_INFINITE); + } else { + sprintf(string, "loop %d: %d tests passed", loop, + test_nb - NB_TEST_INFINITE); } - sprintf(string, "%d/%d test failed", nb_error, - test_nb - NB_TEST_INFINITE); - return res; } @@ -1285,7 +1377,7 @@ static enum test_result test_all(struct stm32mp1_ddrctl *ctl, ****************************************************************/ const struct test_desc test[] = { - {test_all, "All", "", "Execute all tests", 0 }, + {test_all, "All", "[loop]", "Execute all tests", 1 }, {test_databus, "Simple DataBus", "[addr]", "Verifies each data line by walking 1 on fixed address", 1 @@ -1322,39 +1414,39 @@ const struct test_desc test[] = { "Verifies r/w and memcopy(burst for pseudo random value.", 3 }, - {test_freq_pattern, "FrequencySelectivePattern ", "[size]", + {test_freq_pattern, "FrequencySelectivePattern", "[size]", "write & test patterns: Mostly Zero, Mostly One and F/n", 1 }, - {test_blockseq, "BlockSequential", "[size]", + {test_blockseq, "BlockSequential", "[size] [loop] [addr]", "test incremental pattern", - 1 + 3 }, - {test_checkboard, "Checkerboard", "[size]", + {test_checkboard, "Checkerboard", "[size] [loop] [addr]", "test checker pattern", - 1 + 3 }, - {test_bitspread, "BitSpread", "[size]", + {test_bitspread, "BitSpread", "[size] [loop] [addr]", "test Bit Spread pattern", - 1 + 3 }, - {test_bitflip, "BitFlip", "[size]", + {test_bitflip, "BitFlip", "[size] [loop] [addr]", "test Bit Flip pattern", - 1 + 3 }, - {test_walkbit0, "WalkingOnes", "[size]", + {test_walkbit0, "WalkingOnes", "[size] [loop] [addr]", "test Walking Ones pattern", - 1 + 3 }, - {test_walkbit1, "WalkingZeroes", "[size]", + {test_walkbit1, "WalkingZeroes", "[size] [loop] [addr]", "test Walking Zeroes pattern", - 1 + 3 }, /* need to the the 2 last one (infinite) : skipped for test all */ - {test_read, "infinite read", "[addr]", - "basic test : infinite read access", 1}, - {test_write, "infinite write", "[addr]", - "basic test : infinite write access", 1}, + {test_read, "infinite read", "[addr] [pattern]", + "basic test : infinite read access (random: addr=0xFFFFFFFF)", 2}, + {test_write, "infinite write", "[addr] [pattern]", + "basic test : infinite write access (random: addr=0xFFFFFFFF)", 2}, }; const int test_nb = ARRAY_SIZE(test); diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c index 0778921..b928ac2 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.c +++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #if defined(DEBUG) @@ -17,30 +17,46 @@ #include "stm32mp1_ddr_regs.h" #include "stm32mp1_ddr.h" #include "stm32mp1_tests.h" -#include "stm32mp1_tuning.h" -/* TODO make enum for nominal_delay_m_1.... (for all arrays) */ - -/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */ -const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12}; - -/* New DQ delay value (index). These values are set during Deskew algo */ -u8 deskew_delay[NUM_BYTES][8]; - -/*If there is still skew on a bit, mark this bit. */ -u8 deskew_non_converge[NUM_BYTES][8]; - -/*Stores the DQS trim values (PHASE index, unit index) */ -u8 eye_training_val[NUM_BYTES][2]; +#define MAX_DQS_PHASE_IDX _144deg +#define MAX_DQS_UNIT_IDX 7 +#define MAX_GSL_IDX 5 +#define MAX_GPS_IDX 3 + +/* Number of bytes used in this SW. ( min 1--> max 4). */ +#define NUM_BYTES 4 + +enum dqs_phase_enum { + _36deg = 0, + _54deg = 1, + _72deg = 2, + _90deg = 3, + _108deg = 4, + _126deg = 5, + _144deg = 6 +}; -/* stores the log of pass/fail */ -u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1]; +/* BIST Result struct */ +struct BIST_result { + /* Overall test result: + * 0 Fail (any bit failed) , + * 1 Success (All bits success) + */ + bool test_result; + /* 1: true, all fail / 0: False, not all bits fail */ + bool all_bits_fail; + bool bit_i_test_result[8]; /* 0 fail / 1 success */ +}; -/* stores the dqs gate values (gsl index, gps index) */ -u8 dqs_gate_values[NUM_BYTES][2]; +/* a struct that defines tuning parameters of a byte. */ +struct tuning_position { + u8 phase; /* DQS phase */ + u8 unit; /* DQS unit delay */ + u32 bits_delay; /* Bits deskew in this byte */ +}; -static void itm_soft_reset(struct stm32mp1_ddrphy *phy); -static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte); +/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */ +const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12}; static u8 BIST_error_max = 1; static u32 BIST_seed = 0x1234ABCD; @@ -64,10 +80,16 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl) return nb_bytes; } +static void itm_soft_reset(struct stm32mp1_ddrphy *phy) +{ + stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); +} + +#ifdef UNUSED /* Read DQS PHASE delay register and provides the index of the retrieved * value in dx_dll_phase array. */ -u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDLLCR(phy, byte); u32 sdphase = 0; @@ -123,11 +145,13 @@ u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte) return index; } +#endif +#ifdef UNUSED /* Read DQS unit delay register and provides the index of the retrieved value * We are assuming that the delay on DQS and DQSN are equal */ -u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); u32 index; @@ -141,12 +165,13 @@ u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte) return index; } +#endif /* Read DQ unit delay register and provides the retrieved value for DQS * We are assuming that we have the same delay when clocking * by DQS and when clocking by DQSN */ -u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) +static u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) { u32 index; u32 addr = DXNDQTR(phy, byte); @@ -163,29 +188,33 @@ u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit) return index; } +#ifdef UNUSED /* read r0dgsl value */ -u8 get_r0dgsl_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 get_r0dgsl_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGSL_MASK) >> DDRPHYC_DXNDQSTR_R0DGSL_SHIFT; } +#endif +#ifdef UNUSED /*read r0dgsl value */ -u8 get_r0dgps_index(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 get_r0dgps_index(struct stm32mp1_ddrphy *phy, u8 byte) { u32 addr = DXNDQSTR(phy, byte); return (readl(addr) & DDRPHYC_DXNDQSTR_R0DGPS_MASK) >> DDRPHYC_DXNDQSTR_R0DGPS_SHIFT; } +#endif /* Sets the DQS phase delay for a byte lane. *phase delay is specified by giving the index of the desired delay * in the dx_dll_phase array. */ -void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) +static void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) { u8 sdphase_val = 0; @@ -200,8 +229,8 @@ void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx) * unit delay is specified by giving the index of the desired delay * for dgsdly and dqsndly (same value). */ -void DQS_unit_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 unit_dly_idx) +static void DQS_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 unit_dly_idx) { /* Write the same value in DXNDQSTR.DQSDLY and DXNDQSTR.DQSNDLY */ clrsetbits_le32(DXNDQSTR(phy, byte), @@ -219,9 +248,9 @@ void DQS_unit_delay(struct stm32mp1_ddrphy *phy, /* Sets the DQ unit delay for a bit line in particular byte lane. * unit delay is specified by giving the desired delay */ -void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 bit, - u8 dq_delay_index) +static void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 bit, + u8 dq_delay_index) { u8 dq_bit_delay_val = dq_delay_index | (dq_delay_index << 2); @@ -232,16 +261,16 @@ void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy, dq_bit_delay_val << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit)); } -void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 r0dgsl_idx) +static void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgsl_idx) { clrsetbits_le32(DXNDQSTR(phy, byte), DDRPHYC_DXNDQSTR_R0DGSL_MASK, r0dgsl_idx << DDRPHYC_DXNDQSTR_R0DGSL_SHIFT); } -void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, - u8 byte, u8 r0dgps_idx) +static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, + u8 byte, u8 r0dgps_idx) { clrsetbits_le32(DXNDQSTR(phy, byte), DDRPHYC_DXNDQSTR_R0DGPS_MASK, @@ -249,7 +278,7 @@ void set_r0dgps_delay(struct stm32mp1_ddrphy *phy, } /* Basic BIST configuration for data lane tests. */ -void config_BIST(struct stm32mp1_ddrphy *phy) +static void config_BIST(struct stm32mp1_ddrphy *phy) { /* Selects the SDRAM bank address to be used during BIST. */ u32 bbank = 0; @@ -309,7 +338,7 @@ void config_BIST(struct stm32mp1_ddrphy *phy) } /* Select the Byte lane to be tested by BIST. */ -void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) +static void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) { clrsetbits_le32(&phy->bistrr, DDRPHYC_BISTRR_BDXSEL_MASK, @@ -320,8 +349,8 @@ void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8) } /* Perform BIST Write_Read test on a byte lane and return test result. */ -void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, - struct BIST_result *bist) +static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, + struct BIST_result *bist) { bool result = true; /* BIST_SUCCESS */ u32 cnt = 0; @@ -405,8 +434,9 @@ run: #endif } +#ifdef UNUSED /* Init the Write_Read result struct. */ -void init_result_struct(struct BIST_result *result) +static void init_result_struct(struct BIST_result *result) { u8 i = 0; @@ -422,13 +452,16 @@ void init_result_struct(struct BIST_result *result) for (i = 0; i < 8; i++) result->bit_i_test_result[i] = true; } +#endif /* After running the deskew algo, this function applies the new DQ delays * by reading them from the array "deskew_delay"and writing in PHY registers. * The bits that are not deskewed parfectly (too much skew on them, * or data eye very wide) are marked in the array deskew_non_converge. */ -void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte) +static void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte, + u8 deskew_delay[NUM_BYTES][8], + u8 deskew_non_converge[NUM_BYTES][8]) { u8 bit_i; u8 index; @@ -464,6 +497,10 @@ void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte) static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, struct stm32mp1_ddrphy *phy, char *string) { + /* New DQ delay value (index), set during Deskew algo */ + u8 deskew_delay[NUM_BYTES][8]; + /*If there is still skew on a bit, mark this bit. */ + u8 deskew_non_converge[NUM_BYTES][8]; struct BIST_result result; s8 dqs_unit_delay_index = 0; u8 datx8 = 0; @@ -869,7 +906,8 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, pr_debug("The Deskew algorithm can't converge, there is too much margin in your design. Good job!\n"); } - apply_deskew_results(phy, datx8); + apply_deskew_results(phy, datx8, deskew_delay, + deskew_non_converge); /* Restore nominal value for DQS delay */ DQS_phase_delay(phy, datx8, 3); DQS_unit_delay(phy, datx8, 3); @@ -903,6 +941,8 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl, static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, struct stm32mp1_ddrphy *phy, char *string) { + /*Stores the DQS trim values (PHASE index, unit index) */ + u8 eye_training_val[NUM_BYTES][2]; u8 byte = 0; struct BIST_result result; s8 dqs_unit_delay_index = 0; @@ -1189,7 +1229,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl, return TEST_PASSED; } -void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) +static void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) { u8 i = 0; @@ -1211,79 +1251,14 @@ void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte) readl(DXNDQTR(phy, byte))); } -static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, - struct stm32mp1_ddrphy *phy, - char *string) -{ - u8 byte, gsl_idx, gps_idx = 0; - struct BIST_result result; - u8 success = 0; - u8 nb_bytes = get_nb_bytes(ctl); - - memset(dqs_gating, 0x0, sizeof(dqs_gating)); - - /*disable dqs drift compensation*/ - clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); - /*disable all bytes*/ - /* disable automatic power down of dll and ios when disabling a byte - * (to avoid having to add programming and delay - * for a dll re-lock when later re-enabling a disabled byte lane) - */ - clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); - - /* disable all data bytes */ - clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); - clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); - - /* config the bist block */ - config_BIST(phy); - - for (byte = 0; byte < nb_bytes; byte++) { - if (ctrlc()) { - sprintf(string, "interrupted at byte %d/%d", - byte + 1, nb_bytes); - return TEST_FAILED; - } - /* enable byte x (dxngcr, bit dxen) */ - setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); - - /* select the byte lane for comparison of read data */ - BIST_datx8_sel(phy, byte); - for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { - for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { - if (ctrlc()) { - sprintf(string, - "interrupted at byte %d/%d", - byte + 1, nb_bytes); - return TEST_FAILED; - } - /* write cfg to dxndqstr */ - set_r0dgsl_delay(phy, byte, gsl_idx); - set_r0dgps_delay(phy, byte, gps_idx); - - BIST_test(phy, byte, &result); - success = result.test_result; - if (success) - dqs_gating[byte][gsl_idx][gps_idx] = 1; - itm_soft_reset(phy); - } - } - set_midpoint_read_dqs_gating(phy, byte); - /* dummy reads */ - readl(0xc0000000); - readl(0xc0000000); - } - - /* re-enable drift compensation */ - /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */ - return TEST_PASSED; -} - /* analyse the dgs gating log table, and determine the midpoint.*/ -static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte) +static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte, + u8 dqs_gating[NUM_BYTES] + [MAX_GSL_IDX + 1] + [MAX_GPS_IDX + 1]) { + /* stores the dqs gate values (gsl index, gps index) */ + u8 dqs_gate_values[NUM_BYTES][2]; u8 gsl_idx, gps_idx = 0; u8 left_bound_idx[2] = {0, 0}; u8 right_bound_idx[2] = {0, 0}; @@ -1389,9 +1364,76 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte) return !(intermittent || (left_bound_found && right_bound_found)); } -static void itm_soft_reset(struct stm32mp1_ddrphy *phy) +static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl, + struct stm32mp1_ddrphy *phy, + char *string) { - stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST); + /* stores the log of pass/fail */ + u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1]; + u8 byte, gsl_idx, gps_idx = 0; + struct BIST_result result; + u8 success = 0; + u8 nb_bytes = get_nb_bytes(ctl); + + memset(dqs_gating, 0x0, sizeof(dqs_gating)); + + /*disable dqs drift compensation*/ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); + /*disable all bytes*/ + /* disable automatic power down of dll and ios when disabling a byte + * (to avoid having to add programming and delay + * for a dll re-lock when later re-enabling a disabled byte lane) + */ + clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX); + + /* disable all data bytes */ + clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN); + clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN); + + /* config the bist block */ + config_BIST(phy); + + for (byte = 0; byte < nb_bytes; byte++) { + if (ctrlc()) { + sprintf(string, "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* enable byte x (dxngcr, bit dxen) */ + setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN); + + /* select the byte lane for comparison of read data */ + BIST_datx8_sel(phy, byte); + for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) { + for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) { + if (ctrlc()) { + sprintf(string, + "interrupted at byte %d/%d", + byte + 1, nb_bytes); + return TEST_FAILED; + } + /* write cfg to dxndqstr */ + set_r0dgsl_delay(phy, byte, gsl_idx); + set_r0dgps_delay(phy, byte, gps_idx); + + BIST_test(phy, byte, &result); + success = result.test_result; + if (success) + dqs_gating[byte][gsl_idx][gps_idx] = 1; + itm_soft_reset(phy); + } + } + set_midpoint_read_dqs_gating(phy, byte, dqs_gating); + /* dummy reads */ + readl(0xc0000000); + readl(0xc0000000); + } + + /* re-enable drift compensation */ + /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */ + return TEST_PASSED; } /**************************************************************** diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.h b/drivers/ram/stm32mp1/stm32mp1_tuning.h deleted file mode 100644 index 964a050..0000000 --- a/drivers/ram/stm32mp1/stm32mp1_tuning.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ -/* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved - */ - -#ifndef _RAM_STM32MP1_TUNING_H_ -#define _RAM_STM32MP1_TUNING_H_ - -#define MAX_DQS_PHASE_IDX _144deg -#define MAX_DQS_UNIT_IDX 7 -#define MAX_GSL_IDX 5 -#define MAX_GPS_IDX 3 - -/* Number of bytes used in this SW. ( min 1--> max 4). */ -#define NUM_BYTES 4 - -enum dqs_phase_enum { - _36deg = 0, - _54deg = 1, - _72deg = 2, - _90deg = 3, - _108deg = 4, - _126deg = 5, - _144deg = 6 -}; - -/* BIST Result struct */ -struct BIST_result { - /* Overall test result: - * 0 Fail (any bit failed) , - * 1 Success (All bits success) - */ - bool test_result; - /* 1: true, all fail / 0: False, not all bits fail */ - bool all_bits_fail; - bool bit_i_test_result[8]; /* 0 fail / 1 success */ -}; - -u8 DQS_phase_index(struct stm32mp1_ddrphy *phy, u8 byte); -u8 DQS_unit_index(struct stm32mp1_ddrphy *phy, u8 byte); -u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit); - -void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte); -void init_result_struct(struct BIST_result *result); -void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte, - struct BIST_result *result); - -/* a struct that defines tuning parameters of a byte. */ -struct tuning_position { - u8 phase; /* DQS phase */ - u8 unit; /* DQS unit delay */ - u32 bits_delay; /* Bits deskew in this byte */ -}; -#endif diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index 204e6e8..36f1e97 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -449,10 +449,10 @@ static int rproc_load_elf_image(struct udevice *dev, unsigned long addr, if (phdr->p_filesz != phdr->p_memsz) memset(dst + phdr->p_filesz, 0x00, phdr->p_memsz - phdr->p_filesz); - flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), - roundup((int)dst + phdr->p_filesz, + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + phdr->p_filesz, ARCH_DMA_MINALIGN) - - rounddown((int)dst, ARCH_DMA_MINALIGN)); + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); ++phdr; } @@ -564,10 +564,10 @@ static int rproc_elf_find_load_rsc_table(struct udevice *dev, src = (void *)fw_addr + shdr->sh_offset; memcpy(dst, src, shdr->sh_size); - flush_cache(rounddown((int)dst, ARCH_DMA_MINALIGN), - roundup((int)dst + shdr->sh_size, + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + shdr->sh_size, ARCH_DMA_MINALIGN) - - rounddown((int)dst, ARCH_DMA_MINALIGN)); + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); return 0; } diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 44230ff..0a8b900 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -57,7 +57,7 @@ static int st_of_to_priv(struct udevice *dev, priv->hold_boot_regmap = regmap; cell = dev_read_prop(dev, "st,syscfg-holdboot", &len); - if (len < 3 * sizeof(fdt32_t)) { + if ((3 * sizeof(fdt32_t) - len) > 0) { dev_dbg(dev, "holdboot offset and mask not available\n"); return -EINVAL; } @@ -74,7 +74,7 @@ static int st_of_to_priv(struct udevice *dev, } cell = dev_read_prop(dev, "st,syscfg-tz", &len); - if (len < 3 * sizeof(fdt32_t)) { + if (3 * sizeof(fdt32_t) - len > 0) { dev_dbg(dev, "tz offset and mask not available\n"); return -EINVAL; } @@ -153,7 +153,7 @@ static ulong stm32_copro_da_to_pa(struct udevice *dev, ulong da) /* to update with address translate by DT range */ /* CM4 boot at address 0x0 = RETRAM alias, not available for CA7 load */ - if (da >= 0 && da < STM32_RETRAM_SIZE) + if (da < STM32_RETRAM_SIZE) return (da + STM32_RETRAM_BASE); return da; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bcc01b1..e6167c1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -94,4 +94,11 @@ config RTC_MC146818 clock with a wide array of features and 50 bytes of general-purpose, battery-backed RAM. The driver supports access to the clock and RAM. +config RTC_STM32 + bool "Enable STM32 RTC driver" + depends on DM_RTC + help + Enable STM32 RTC driver. This driver supports the rtc that is present + on some STM32 SoCs. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1724602..90e79fb 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -50,5 +50,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o obj-$(CONFIG_RTC_S35392A) += s35392a.o +obj-$(CONFIG_RTC_STM32) += stm32_rtc.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o diff --git a/drivers/rtc/stm32_rtc.c b/drivers/rtc/stm32_rtc.c new file mode 100644 index 0000000..c2c74ce --- /dev/null +++ b/drivers/rtc/stm32_rtc.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ +#include +#include +#include +#include +#include +#include + +#define STM32_RTC_TR 0x00 +#define STM32_RTC_DR 0x04 +#define STM32_RTC_ISR 0x0C +#define STM32_RTC_PRER 0x10 +#define STM32_RTC_CR 0x18 +#define STM32_RTC_WPR 0x24 + +/* STM32_RTC_TR bit fields */ +#define STM32_RTC_SEC_SHIFT 0 +#define STM32_RTC_SEC GENMASK(6, 0) +#define STM32_RTC_MIN_SHIFT 8 +#define STM32_RTC_MIN GENMASK(14, 8) +#define STM32_RTC_HOUR_SHIFT 16 +#define STM32_RTC_HOUR GENMASK(21, 16) + +/* STM32_RTC_DR bit fields */ +#define STM32_RTC_DATE_SHIFT 0 +#define STM32_RTC_DATE GENMASK(5, 0) +#define STM32_RTC_MONTH_SHIFT 8 +#define STM32_RTC_MONTH GENMASK(12, 8) +#define STM32_RTC_WDAY_SHIFT 13 +#define STM32_RTC_WDAY GENMASK(15, 13) +#define STM32_RTC_YEAR_SHIFT 16 +#define STM32_RTC_YEAR GENMASK(23, 16) + +/* STM32_RTC_CR bit fields */ +#define STM32_RTC_CR_FMT BIT(6) + +/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ +#define STM32_RTC_ISR_INITS BIT(4) +#define STM32_RTC_ISR_RSF BIT(5) +#define STM32_RTC_ISR_INITF BIT(6) +#define STM32_RTC_ISR_INIT BIT(7) + +/* STM32_RTC_PRER bit fields */ +#define STM32_RTC_PRER_PRED_S_SHIFT 0 +#define STM32_RTC_PRER_PRED_S GENMASK(14, 0) +#define STM32_RTC_PRER_PRED_A_SHIFT 16 +#define STM32_RTC_PRER_PRED_A GENMASK(22, 16) + +/* STM32_RTC_WPR key constants */ +#define RTC_WPR_1ST_KEY 0xCA +#define RTC_WPR_2ND_KEY 0x53 +#define RTC_WPR_WRONG_KEY 0xFF + +struct stm32_rtc_priv { + fdt_addr_t base; +}; + +static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 tr, dr; + + tr = readl(priv->base + STM32_RTC_TR); + dr = readl(priv->base + STM32_RTC_DR); + + tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT); + tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT); + tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT); + + tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT); + tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT); + tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT); + tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static void stm32_rtc_unlock(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + + writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR); + writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR); +} + +static void stm32_rtc_lock(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + + writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR); +} + +static int stm32_rtc_enter_init_mode(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + if (!(isr & STM32_RTC_ISR_INITF)) { + isr |= STM32_RTC_ISR_INIT; + writel(isr, priv->base + STM32_RTC_ISR); + + return readl_poll_timeout(priv->base + STM32_RTC_ISR, + isr, + (isr & STM32_RTC_ISR_INITF), + 100000); + } + + return 0; +} + +static int stm32_rtc_wait_sync(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + isr &= ~STM32_RTC_ISR_RSF; + writel(isr, priv->base + STM32_RTC_ISR); + + /* + * Wait for RSF to be set to ensure the calendar registers are + * synchronised, it takes around 2 rtc_ck clock cycles + */ + return readl_poll_timeout(priv->base + STM32_RTC_ISR, + isr, (isr & STM32_RTC_ISR_RSF), + 100000); +} + +static void stm32_rtc_exit_init_mode(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + u32 isr = readl(priv->base + STM32_RTC_ISR); + + isr &= ~STM32_RTC_ISR_INIT; + writel(isr, priv->base + STM32_RTC_ISR); +} + +static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + int ret; + + stm32_rtc_unlock(dev); + + ret = stm32_rtc_enter_init_mode(dev); + if (ret) + goto lock; + + writel(time, priv->base + STM32_RTC_TR); + writel(date, priv->base + STM32_RTC_DR); + + stm32_rtc_exit_init_mode(dev); + + ret = stm32_rtc_wait_sync(dev); + +lock: + stm32_rtc_lock(dev); + return ret; +} + +static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + u32 t, d; + + dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + /* Time in BCD format */ + t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC; + t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN; + t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR; + + /* Date in BCD format */ + d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE; + d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH; + d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR; + d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY; + + return stm32_rtc_set_time(dev, t, d); +} + +static int stm32_rtc_reset(struct udevice *dev) +{ + dev_dbg(dev, "Reset DATE\n"); + + return stm32_rtc_set_time(dev, 0, 0); +} + +static int stm32_rtc_init(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; + unsigned int rate; + struct clk clk; + int ret; + u32 isr = readl(priv->base + STM32_RTC_ISR); + + if (isr & STM32_RTC_ISR_INITS) + return 0; + + ret = clk_get_by_index(dev, 1, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + rate = clk_get_rate(&clk); + + /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */ + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; + + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + + /* + * Can't find a 1Hz, so give priority to RTC power consumption + * by choosing the higher possible value for prediv_a + */ + if (pred_s > pred_s_max || pred_a > pred_a_max) { + pred_a = pred_a_max; + pred_s = (rate / (pred_a + 1)) - 1; + } + + stm32_rtc_unlock(dev); + + ret = stm32_rtc_enter_init_mode(dev); + if (ret) { + dev_err(dev, + "Can't enter in init mode. Prescaler config failed.\n"); + goto unlock; + } + + prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; + prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; + writel(prer, priv->base + STM32_RTC_PRER); + + /* Force 24h time format */ + cr = readl(priv->base + STM32_RTC_CR); + cr &= ~STM32_RTC_CR_FMT; + writel(cr, priv->base + STM32_RTC_CR); + + stm32_rtc_exit_init_mode(dev); + + ret = stm32_rtc_wait_sync(dev); +unlock: + stm32_rtc_lock(dev); + + return ret; +} + +static int stm32_rtc_probe(struct udevice *dev) +{ + struct stm32_rtc_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + ret = stm32_rtc_init(dev); + + return ret; +} + +static const struct rtc_ops stm32_rtc_ops = { + .get = stm32_rtc_get, + .set = stm32_rtc_set, + .reset = stm32_rtc_reset, +}; + +static const struct udevice_id stm32_rtc_ids[] = { + { .compatible = "st,stm32mp1-rtc" }, + { } +}; + +U_BOOT_DRIVER(rtc_stm32) = { + .name = "rtc-stm32", + .id = UCLASS_RTC, + .probe = stm32_rtc_probe, + .of_match = stm32_rtc_ids, + .ops = &stm32_rtc_ops, + .priv_auto_alloc_size = sizeof(struct stm32_rtc_priv), +}; diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index d806057..0bde839 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -114,10 +114,11 @@ static int stm32_serial_getc(struct udevice *dev) if ((isr & USART_ISR_RXNE) == 0) return -EAGAIN; - if (isr & (USART_ISR_PE | USART_ISR_ORE)) { + if (isr & (USART_ISR_PE | USART_ISR_ORE | USART_ISR_FE)) { if (!stm32f4) setbits_le32(base + ICR_OFFSET, - USART_ICR_PCECF | USART_ICR_ORECF); + USART_ICR_PCECF | USART_ICR_ORECF | + USART_ICR_FECF); else readl(base + RDR_OFFSET(stm32f4)); return -EIO; @@ -203,9 +204,9 @@ static int stm32_serial_probe(struct udevice *dev) } plat->clock_rate = clk_get_rate(&clk); - if (plat->clock_rate < 0) { + if (!plat->clock_rate) { clk_disable(&clk); - return plat->clock_rate; + return -EINVAL; }; _stm32_serial_init(plat->base, plat->uart_info); @@ -283,7 +284,7 @@ static inline void _debug_uart_putc(int c) struct stm32_uart_info *uart_info = _debug_uart_info(); while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN) - WATCHDOG_RESET(); + ; } DEBUG_UART_FUNCS diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h index 5549f8c..7b0c531 100644 --- a/drivers/serial/serial_stm32.h +++ b/drivers/serial/serial_stm32.h @@ -67,6 +67,7 @@ struct stm32x7_serial_platdata { #define USART_ISR_TXE BIT(7) #define USART_ISR_RXNE BIT(5) #define USART_ISR_ORE BIT(3) +#define USART_ISR_FE BIT(1) #define USART_ISR_PE BIT(0) #define USART_BRR_F_MASK GENMASK(7, 0) @@ -74,6 +75,7 @@ struct stm32x7_serial_platdata { #define USART_BRR_M_MASK GENMASK(15, 4) #define USART_ICR_ORECF BIT(3) +#define USART_ICR_FECF BIT(1) #define USART_ICR_PCECF BIT(0) #endif diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index da96754..62d6245 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -197,6 +197,14 @@ config STM32_QSPI used to access the SPI NOR flash chips on platforms embedding this ST IP core. +config STM32_SPI + bool "STM32 SPI driver" + depends on ARCH_STM32MP + help + Enable the STM32 Serial Peripheral Interface (SPI) driver for STM32MP + SoCs. This uses driver model and requires a device tree binding to + operate. + config SUN4I_SPI bool "Allwinner A10 SoCs SPI controller" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7242ea7..2f984d9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o obj-$(CONFIG_SH_SPI) += sh_spi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o +obj-$(CONFIG_STM32_SPI) += stm32_spi.o obj-$(CONFIG_SUN4I_SPI) += sun4i_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index af9aef0..1bb0987 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -210,6 +210,10 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) if (!spi_mem_supports_op(slave, op)) return -ENOTSUPP; + ret = spi_claim_bus(slave); + if (ret < 0) + return ret; + if (ops->mem_ops) { #ifndef __UBOOT__ /* @@ -232,6 +236,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) mutex_lock(&ctlr->io_mutex); #endif ret = ops->mem_ops->exec_op(slave, op); + #ifndef __UBOOT__ mutex_unlock(&ctlr->io_mutex); mutex_unlock(&ctlr->bus_lock_mutex); @@ -245,8 +250,10 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) * read path) and expect the core to use the regular SPI * interface in other cases. */ - if (!ret || ret != -ENOTSUPP) + if (!ret || ret != -ENOTSUPP) { + spi_release_bus(slave); return ret; + } } #ifndef __UBOOT__ @@ -323,15 +330,6 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) return -EIO; #else - /* U-Boot does not support parallel SPI data lanes */ - if ((op->cmd.buswidth != 1) || - (op->addr.nbytes && op->addr.buswidth != 1) || - (op->dummy.nbytes && op->dummy.buswidth != 1) || - (op->data.nbytes && op->data.buswidth != 1)) { - printf("Dual/Quad raw SPI transfers not supported\n"); - return -ENOTSUPP; - } - if (op->data.nbytes) { if (op->data.dir == SPI_MEM_DATA_IN) rx_buf = op->data.buf.in; @@ -342,10 +340,6 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; op_buf = calloc(1, op_len); - ret = spi_claim_bus(slave); - if (ret < 0) - return ret; - op_buf[pos++] = op->cmd.opcode; if (op->addr.nbytes) { @@ -421,6 +415,25 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) if (ops->mem_ops && ops->mem_ops->adjust_op_size) return ops->mem_ops->adjust_op_size(slave, op); + if (!ops->mem_ops || !ops->mem_ops->exec_op) { + unsigned int len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + + op->dummy.nbytes; + if (slave->max_write_size && len > slave->max_write_size) + return -EINVAL; + + if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_read_size); + else if (slave->max_write_size) + op->data.nbytes = min(op->data.nbytes, + slave->max_write_size - len); + + if (!op->data.nbytes) + return -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index b84255b..856c533 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -320,7 +320,9 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, } plat = dev_get_parent_platdata(dev); - if (!speed) { + + /* get speed and mode from platdata when available */ + if (plat->max_hz) { speed = plat->max_hz; mode = plat->mode; } diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 3b92254..39e95c2 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include struct stm32_qspi_regs { u32 cr; /* 0x00 */ @@ -45,7 +47,6 @@ struct stm32_qspi_regs { #define STM32_QSPI_CR_SSHIFT BIT(4) #define STM32_QSPI_CR_DFM BIT(6) #define STM32_QSPI_CR_FSEL BIT(7) -#define STM32_QSPI_CR_FTHRES_MASK GENMASK(4, 0) #define STM32_QSPI_CR_FTHRES_SHIFT (8) #define STM32_QSPI_CR_TEIE BIT(16) #define STM32_QSPI_CR_TCIE BIT(17) @@ -155,7 +156,12 @@ enum STM32_QSPI_CCR_FMODE { /* default SCK frequency, unit: HZ */ #define STM32_QSPI_DEFAULT_SCK_FREQ 108000000 -#define STM32_MAX_NORCHIP 2 +#define STM32_QSPI_MAX_CHIP 2 + +#define STM32_QSPI_FIFO_TIMEOUT_US 30000 +#define STM32_QSPI_CMD_TIMEOUT_US 1000000 +#define STM32_BUSY_TIMEOUT_US 100000 +#define STM32_ABT_TIMEOUT_US 100000 struct stm32_qspi_platdata { u32 base; @@ -163,11 +169,20 @@ struct stm32_qspi_platdata { u32 max_hz; }; +struct stm32_qspi_flash { + u32 cr; + u32 dcr; + u32 mode; + bool initialized; +}; + struct stm32_qspi_priv { struct stm32_qspi_regs *regs; + struct stm32_qspi_flash flash[STM32_QSPI_MAX_CHIP]; ulong clock_rate; u32 max_hz; u32 mode; + int cs_used; u32 command; u32 address; @@ -177,47 +192,18 @@ struct stm32_qspi_priv { #define CMD_HAS_DATA BIT(26) }; -static void _stm32_qspi_disable(struct stm32_qspi_priv *priv) -{ - clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} - -static void _stm32_qspi_enable(struct stm32_qspi_priv *priv) +static int _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) { - setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); -} - -static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) -{ - while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) - ; -} - -static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) -{ - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF)) - ; -} - -static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) -{ - while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF)) - ; -} + u32 sr; + int ret; -static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size) -{ - u32 fsize = fls(size) - 1; + ret = readl_poll_timeout(&priv->regs->sr, sr, + !(sr & STM32_QSPI_SR_BUSY), + STM32_BUSY_TIMEOUT_US); + if (ret) + pr_err("busy timeout (stat:%#x)\n", sr); - clrsetbits_le32(&priv->regs->dcr, - STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT, - fsize << STM32_QSPI_DCR_FSIZE_SHIFT); -} - -static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs) -{ - clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, - cs ? STM32_QSPI_CR_FSEL : 0); + return ret; } static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode) @@ -303,13 +289,79 @@ static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) writel(priv->address, &priv->regs->ar); } +static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, bool wait_nobusy) +{ + u32 sr; + int ret; + + if (wait_nobusy) + 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) { + pr_err("cmd timeout (stat:%#x)\n", sr); + } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { + pr_err("transfer error (stat:%#x)\n", sr); + ret = -EIO; + } + + /* clear flags */ + writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + + return ret; +} + +static void _stm32_qspi_read_fifo(u8 *val, void __iomem *addr) +{ + *val = readb(addr); +} + +static void _stm32_qspi_write_fifo(u8 *val, void __iomem *addr) +{ + writeb(*val, addr); +} + +static int _stm32_qspi_poll(struct stm32_qspi_priv *priv, + const u8 *dout, u8 *din, u32 len) +{ + void (*fifo)(u8 *val, void __iomem *addr); + u32 sr; + u8 *buf; + int ret; + + if (din) { + fifo = _stm32_qspi_read_fifo; + buf = din; + + } else { + fifo = _stm32_qspi_write_fifo; + buf = (u8 *)dout; + } + + while (len--) { + ret = readl_poll_timeout(&priv->regs->sr, sr, + sr & STM32_QSPI_SR_FTF, + STM32_QSPI_FIFO_TIMEOUT_US); + if (ret) { + pr_err("fifo timeout (len:%d stat:%#x)\n", len, sr); + return ret; + } + + fifo(buf++, &priv->regs->dr); + } + + return 0; +} + static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, struct spi_flash *flash, unsigned int bitlen, const u8 *dout, u8 *din, unsigned long flags) { unsigned int words = bitlen / 8; u32 ccr_reg; - int i; + int ret; if (flags & SPI_XFER_MMAP) { _stm32_qspi_enable_mmap(priv, flash); @@ -361,12 +413,16 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, } if (flags & SPI_XFER_END) { + bool cmd_has_data = priv->command & CMD_HAS_DATA; + ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_WRITE); - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; - if (priv->command & CMD_HAS_DATA) + if (cmd_has_data) _stm32_qspi_set_xfer_length(priv, words); _stm32_qspi_start_xfer(priv, ccr_reg); @@ -374,28 +430,22 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, debug("%s: write: ccr:0x%08x adr:0x%08x\n", __func__, priv->regs->ccr, priv->regs->ar); - if (priv->command & CMD_HAS_DATA) { - _stm32_qspi_wait_for_ftf(priv); - - debug("%s: words:%d data:", __func__, words); - - i = 0; - while (words > i) { - writeb(dout[i], &priv->regs->dr); - debug("%02x ", dout[i]); - i++; - } - debug("\n"); - - _stm32_qspi_wait_for_complete(priv); - } else { - _stm32_qspi_wait_for_not_busy(priv); + if (cmd_has_data) { + ret = _stm32_qspi_poll(priv, dout, NULL, words); + if (ret) + return ret; } + + ret = _stm32_qspi_wait_cmd(priv, !cmd_has_data); + if (ret) + return ret; } } else if (din) { ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ); - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; _stm32_qspi_set_xfer_length(priv, words); @@ -404,20 +454,112 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, priv->regs->ccr, priv->regs->ar, priv->regs->dlr); - debug("%s: data:", __func__); + ret = _stm32_qspi_poll(priv, NULL, din, words); + if (ret) + return ret; - i = 0; - while (words > i) { - din[i] = readb(&priv->regs->dr); - debug("%02x ", din[i]); - i++; - } - debug("\n"); + ret = _stm32_qspi_wait_cmd(priv, false); + if (ret) + return ret; } return 0; } +static int _stm32_qspi_tx(struct stm32_qspi_priv *priv, + const struct spi_mem_op *op) +{ + if (!op->data.nbytes) + return 0; + + if (op->data.dir == SPI_MEM_DATA_IN) + return _stm32_qspi_poll(priv, NULL, op->data.buf.in, + op->data.nbytes); + + return _stm32_qspi_poll(priv, op->data.buf.out, NULL, op->data.nbytes); +} + +static int _stm32_qspi_get_mode(u8 buswidth) +{ + if (buswidth == 4) + return 3; + + return buswidth; +} + +static int stm32_qspi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct stm32_qspi_priv *priv = dev_get_priv(slave->dev->parent); + u32 cr, ccr; + int timeout, ret; + + debug("%s: cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", + __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + op->dummy.buswidth, op->data.buswidth, + op->addr.val, op->data.nbytes); + + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; + + ccr = (STM32_QSPI_CCR_IND_WRITE << STM32_QSPI_CCR_FMODE_SHIFT); + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) + ccr = (STM32_QSPI_CCR_IND_READ << STM32_QSPI_CCR_FMODE_SHIFT); + + if (op->data.nbytes) + _stm32_qspi_set_xfer_length(priv, op->data.nbytes); + + ccr |= op->cmd.opcode; + ccr |= (_stm32_qspi_get_mode(op->cmd.buswidth) + << STM32_QSPI_CCR_IMODE_SHIFT); + + if (op->addr.nbytes) { + ccr |= ((op->addr.nbytes - 1) << STM32_QSPI_CCR_ADSIZE_SHIFT); + ccr |= (_stm32_qspi_get_mode(op->addr.buswidth) + << STM32_QSPI_CCR_ADMODE_SHIFT); + } + + if (op->dummy.buswidth && op->dummy.nbytes) + ccr |= (op->dummy.nbytes * 8 / op->dummy.buswidth + << STM32_QSPI_CCR_DCYC_SHIFT); + + if (op->data.nbytes) + ccr |= (_stm32_qspi_get_mode(op->data.buswidth) + << STM32_QSPI_CCR_DMODE_SHIFT); + + writel(ccr, &priv->regs->ccr); + + if (op->addr.nbytes) + writel(op->addr.val, &priv->regs->ar); + + ret = _stm32_qspi_tx(priv, op); + if (ret) + goto abort; + + /* wait end of tx in indirect mode */ + ret = _stm32_qspi_wait_cmd(priv, !op->data.nbytes); + if (ret) + goto abort; + + return 0; + +abort: + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); + + /* wait clear of abort bit by hw */ + timeout = readl_poll_timeout(&priv->regs->cr, cr, + !(cr & STM32_QSPI_CR_ABORT), + STM32_ABT_TIMEOUT_US); + + writel(STM32_QSPI_FCR_CTCF, &priv->regs->fcr); + + if (ret || timeout) + debug("%s ret:%d abort timeout:%d\n", __func__, ret, timeout); + + return ret; +} + static int stm32_qspi_ofdata_to_platdata(struct udevice *bus) { struct resource res_regs, res_mem; @@ -455,17 +597,15 @@ static int stm32_qspi_probe(struct udevice *bus) { struct stm32_qspi_platdata *plat = dev_get_platdata(bus); struct stm32_qspi_priv *priv = dev_get_priv(bus); - struct dm_spi_bus *dm_spi_bus; + struct dm_spi_bus *dm_spi_bus = bus->uclass_priv; struct clk clk; struct reset_ctl reset_ctl; int ret; - dm_spi_bus = bus->uclass_priv; - dm_spi_bus->max_hz = plat->max_hz; priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; - + priv->cs_used = -1; priv->max_hz = plat->max_hz; ret = clk_get_by_index(bus, 0, &clk); @@ -480,9 +620,9 @@ static int stm32_qspi_probe(struct udevice *bus) } priv->clock_rate = clk_get_rate(&clk); - if (priv->clock_rate < 0) { + if (!priv->clock_rate) { clk_disable(&clk); - return priv->clock_rate; + return -EINVAL; } ret = reset_get_by_index(bus, 0, &reset_ctl); @@ -501,6 +641,10 @@ static int stm32_qspi_probe(struct udevice *bus) setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); + /* Set dcr fsize to max address */ + setbits_le32(&priv->regs->dcr, + STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT); + return 0; } @@ -511,37 +655,47 @@ static int stm32_qspi_remove(struct udevice *bus) static int stm32_qspi_claim_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct spi_flash *flash; - struct dm_spi_slave_platdata *slave_plat; - - bus = dev->parent; - priv = dev_get_priv(bus); - flash = dev_get_uclass_priv(dev); - slave_plat = dev_get_parent_platdata(dev); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + int slave_cs = slave_plat->cs; - if (slave_plat->cs >= STM32_MAX_NORCHIP) + if (slave_cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; - _stm32_qspi_set_cs(priv, slave_plat->cs); + if (priv->cs_used != slave_cs) { + struct stm32_qspi_flash *flash = &priv->flash[slave_cs]; + + priv->cs_used = slave_cs; + + if (flash->initialized) { + /* Set the configuration: speed + mode + cs */ + writel(flash->cr, &priv->regs->cr); + writel(flash->dcr, &priv->regs->dcr); + priv->mode = flash->mode; + } else { + /* Set chip select */ + clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL, + priv->cs_used ? STM32_QSPI_CR_FSEL : 0); + + /* Save the configuration: speed + mode + cs */ + flash->cr = readl(&priv->regs->cr); + flash->dcr = readl(&priv->regs->dcr); + flash->mode = priv->mode; - _stm32_qspi_set_flash_size(priv, flash->size); + flash->initialized = true; + } + } - _stm32_qspi_enable(priv); + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); return 0; } static int stm32_qspi_release_bus(struct udevice *dev) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - - bus = dev->parent; - priv = dev_get_priv(bus); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); - _stm32_qspi_disable(priv); + clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); return 0; } @@ -549,13 +703,8 @@ static int stm32_qspi_release_bus(struct udevice *dev) static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - struct stm32_qspi_priv *priv; - struct udevice *bus; - struct spi_flash *flash; - - bus = dev->parent; - priv = dev_get_priv(bus); - flash = dev_get_uclass_priv(dev); + struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); + struct spi_flash *flash = dev_get_uclass_priv(dev); return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout, (u8 *)din, flags); @@ -568,22 +717,26 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) u32 qspi_clk = priv->clock_rate; u32 prescaler = 255; u32 csht; + int ret; if (speed > plat->max_hz) speed = plat->max_hz; if (speed > 0) { - prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; - if (prescaler > 255) - prescaler = 255; - else if (prescaler < 0) - prescaler = 0; + prescaler = 0; + if (qspi_clk) { + prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; + if (prescaler > 255) + prescaler = 255; + } } csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK; - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_PRESCALER_MASK << @@ -603,8 +756,11 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) static int stm32_qspi_set_mode(struct udevice *bus, uint mode) { struct stm32_qspi_priv *priv = dev_get_priv(bus); + int ret; - _stm32_qspi_wait_for_not_busy(priv); + ret = _stm32_qspi_wait_for_not_busy(priv); + if (ret) + return ret; if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); @@ -649,12 +805,17 @@ static int stm32_qspi_set_mode(struct udevice *bus, uint mode) return 0; } +static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { + .exec_op = stm32_qspi_exec_op, +}; + static const struct dm_spi_ops stm32_qspi_ops = { .claim_bus = stm32_qspi_claim_bus, .release_bus = stm32_qspi_release_bus, .xfer = stm32_qspi_xfer, .set_speed = stm32_qspi_set_speed, .set_mode = stm32_qspi_set_mode, + .mem_ops = &stm32_qspi_mem_ops, }; static const struct udevice_id stm32_qspi_ids[] = { diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c new file mode 100644 index 0000000..75b6006 --- /dev/null +++ b/drivers/spi/stm32_spi.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Serial peripheral interface (SPI) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* STM32 SPI registers */ +#define STM32_SPI_CR1 0x00 +#define STM32_SPI_CR2 0x04 +#define STM32_SPI_CFG1 0x08 +#define STM32_SPI_CFG2 0x0C +#define STM32_SPI_SR 0x14 +#define STM32_SPI_IFCR 0x18 +#define STM32_SPI_TXDR 0x20 +#define STM32_SPI_RXDR 0x30 +#define STM32_SPI_I2SCFGR 0x50 + +/* STM32_SPI_CR1 bit fields */ +#define SPI_CR1_SPE BIT(0) +#define SPI_CR1_MASRX BIT(8) +#define SPI_CR1_CSTART BIT(9) +#define SPI_CR1_CSUSP BIT(10) +#define SPI_CR1_HDDIR BIT(11) +#define SPI_CR1_SSI BIT(12) + +/* STM32_SPI_CR2 bit fields */ +#define SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32_SPI_CFG1 bit fields */ +#define SPI_CFG1_DSIZE GENMASK(4, 0) +#define SPI_CFG1_DSIZE_MIN 3 +#define SPI_CFG1_FTHLV_SHIFT 5 +#define SPI_CFG1_FTHLV GENMASK(8, 5) +#define SPI_CFG1_MBR_SHIFT 28 +#define SPI_CFG1_MBR GENMASK(30, 28) +#define SPI_CFG1_MBR_MIN 0 +#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) + +/* STM32_SPI_CFG2 bit fields */ +#define SPI_CFG2_COMM_SHIFT 17 +#define SPI_CFG2_COMM GENMASK(18, 17) +#define SPI_CFG2_MASTER BIT(22) +#define SPI_CFG2_LSBFRST BIT(23) +#define SPI_CFG2_CPHA BIT(24) +#define SPI_CFG2_CPOL BIT(25) +#define SPI_CFG2_SSM BIT(26) +#define SPI_CFG2_AFCNTR BIT(31) + +/* STM32_SPI_SR bit fields */ +#define SPI_SR_RXP BIT(0) +#define SPI_SR_TXP BIT(1) +#define SPI_SR_EOT BIT(3) +#define SPI_SR_TXTF BIT(4) +#define SPI_SR_OVR BIT(6) +#define SPI_SR_SUSP BIT(11) +#define SPI_SR_RXPLVL_SHIFT 13 +#define SPI_SR_RXPLVL GENMASK(14, 13) +#define SPI_SR_RXWNE BIT(15) + +/* STM32_SPI_IFCR bit fields */ +#define SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32_SPI_I2SCFGR bit fields */ +#define SPI_I2SCFGR_I2SMOD BIT(0) + +#define MAX_CS_COUNT 4 + +/* SPI Master Baud Rate min/max divisor */ +#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) +#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) + +#define STM32_SPI_TIMEOUT_US 100000 + +/* SPI Communication mode */ +#define SPI_FULL_DUPLEX 0 +#define SPI_SIMPLEX_TX 1 +#define SPI_SIMPLEX_RX 2 +#define SPI_HALF_DUPLEX 3 + +struct stm32_spi_priv { + void __iomem *base; + struct clk clk; + struct reset_ctl rst_ctl; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; + ulong bus_clk_rate; + unsigned int fifo_size; + unsigned int cur_bpw; + unsigned int cur_hz; + unsigned int cur_xferlen; /* current transfer length in bytes */ + unsigned int tx_len; /* number of data to be written in bytes */ + unsigned int rx_len; /* number of data to be read in bytes */ + const void *tx_buf; /* data to be written, or NULL */ + void *rx_buf; /* data to be read, or NULL */ + u32 cur_mode; + bool cs_high; +}; + +static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +{ + while ((priv->tx_len > 0) && + (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + u32 offs = priv->cur_xferlen - priv->tx_len; + + if (priv->tx_len >= sizeof(u32) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { + const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); + + writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u32); + } else if (priv->tx_len >= sizeof(u16) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { + const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); + + writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); + + writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u8); + } + } + + debug("%s: %d bytes left\n", __func__, priv->tx_len); +} + +static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +{ + u32 sr = readl(priv->base + STM32_SPI_SR); + u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + + while ((priv->rx_len > 0) && + ((sr & SPI_SR_RXP) || + ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = priv->cur_xferlen - priv->rx_len; + + if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) && + (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { + u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); + + *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u32); + } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && + (priv->rx_len >= sizeof(u16) || + (!(sr & SPI_SR_RXWNE) && + (rxplvl >= 2 || priv->cur_bpw > 8)))) { + u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); + + *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); + + *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u8); + } + + sr = readl(priv->base + STM32_SPI_SR); + rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + } + + debug("%s: %d bytes left\n", __func__, priv->rx_len); +} + +static int stm32_spi_enable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_disable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_claim_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + return stm32_spi_enable(priv); +} + +static int stm32_spi_release_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + return stm32_spi_disable(priv); +} + +static void stm32_spi_stopxfer(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 cr1, sr; + int ret; + + debug("%s\n", __func__); + + cr1 = readl(priv->base + STM32_SPI_CR1); + + if (!(cr1 & SPI_CR1_SPE)) + return; + + /* Wait on EOT or suspend the flow */ + ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + !(sr & SPI_SR_EOT), 100000); + if (ret < 0) { + if (cr1 & SPI_CR1_CSTART) { + writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); + if (readl_poll_timeout(priv->base + STM32_SPI_SR, + sr, !(sr & SPI_SR_SUSP), + 100000) < 0) + dev_err(dev, "Suspend request timeout\n"); + } + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); +} + +static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + + debug("%s: cs=%d enable=%d\n", __func__, cs, enable); + + if (cs >= MAX_CS_COUNT) + return -ENODEV; + + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return -EINVAL; + + if (priv->cs_high) + enable = !enable; + + return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0); +} + +static int stm32_spi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 cfg2_clrb = 0, cfg2_setb = 0; + + debug("%s: mode=%d\n", __func__, mode); + + if (mode & SPI_CPOL) + cfg2_setb |= SPI_CFG2_CPOL; + else + cfg2_clrb |= SPI_CFG2_CPOL; + + if (mode & SPI_CPHA) + cfg2_setb |= SPI_CFG2_CPHA; + else + cfg2_clrb |= SPI_CFG2_CPHA; + + if (mode & SPI_LSB_FIRST) + cfg2_setb |= SPI_CFG2_LSBFRST; + else + cfg2_clrb |= SPI_CFG2_LSBFRST; + + if (cfg2_clrb || cfg2_setb) + clrsetbits_le32(priv->base + STM32_SPI_CFG2, + cfg2_clrb, cfg2_setb); + + if (mode & SPI_CS_HIGH) + priv->cs_high = true; + else + priv->cs_high = false; + return 0; +} + +static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 fthlv, half_fifo; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (priv->fifo_size / 2); + + /* data_packet should not exceed transfer length */ + fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo; + + /* align packet size with data registers access */ + fthlv -= (fthlv % 4); + + if (!fthlv) + fthlv = 1; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); + + return 0; +} + +static int stm32_spi_set_speed(struct udevice *bus, uint hz) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 mbrdiv; + long div; + + debug("%s: hz=%d\n", __func__, hz); + + if (priv->cur_hz == hz) + return 0; + + div = DIV_ROUND_UP(priv->bus_clk_rate, hz); + + if (div < STM32_MBR_DIV_MIN || + div > STM32_MBR_DIV_MAX) + return -EINVAL; + + /* Determine the first power of 2 greater than or equal to div */ + if (div & (div - 1)) + mbrdiv = fls(div); + else + mbrdiv = fls(div) - 1; + + if (!mbrdiv) + return -EINVAL; + + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); + + priv->cur_hz = hz; + + return 0; +} + +static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(slave); + struct dm_spi_slave_platdata *slave_plat; + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 sr; + u32 ifcr = 0; + u32 xferlen; + u32 mode; + int xfer_status = 0; + + xferlen = bitlen / 8; + + if (xferlen <= SPI_CR2_TSIZE) + writel(xferlen, priv->base + STM32_SPI_CR2); + else + return -EMSGSIZE; + + priv->tx_buf = dout; + priv->rx_buf = din; + priv->tx_len = priv->tx_buf ? bitlen / 8 : 0; + priv->rx_len = priv->rx_buf ? bitlen / 8 : 0; + + mode = SPI_FULL_DUPLEX; + if (!priv->tx_buf) + mode = SPI_SIMPLEX_RX; + else if (!priv->rx_buf) + mode = SPI_SIMPLEX_TX; + + if (priv->cur_xferlen != xferlen || priv->cur_mode != mode) { + priv->cur_mode = mode; + priv->cur_xferlen = xferlen; + + /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ + stm32_spi_disable(priv); + + clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + mode << SPI_CFG2_COMM_SHIFT); + + stm32_spi_set_fthlv(bus, xferlen); + + /* Enable the SPI hardware */ + stm32_spi_enable(priv); + } + + debug("%s: priv->tx_len=%d priv->rx_len=%d\n", __func__, + priv->tx_len, priv->rx_len); + + slave_plat = dev_get_parent_platdata(slave); + if (flags & SPI_XFER_BEGIN) + stm32_spi_set_cs(bus, slave_plat->cs, false); + + /* Be sure to have data in fifo before starting data transfer */ + if (priv->tx_buf) + stm32_spi_write_txfifo(priv); + + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + + while (1) { + sr = readl(priv->base + STM32_SPI_SR); + + if (sr & SPI_SR_OVR) { + dev_err(bus, "Overrun: RX data lost\n"); + xfer_status = -EIO; + break; + } + + if (sr & SPI_SR_SUSP) { + dev_warn(bus, "System too slow is limiting data throughput\n"); + + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + ifcr |= SPI_SR_SUSP; + } + + if (sr & SPI_SR_TXTF) + ifcr |= SPI_SR_TXTF; + + if (sr & SPI_SR_TXP) + if (priv->tx_buf && priv->tx_len > 0) + stm32_spi_write_txfifo(priv); + + if (sr & SPI_SR_RXP) + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + if (sr & SPI_SR_EOT) { + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + break; + } + + writel(ifcr, priv->base + STM32_SPI_IFCR); + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + stm32_spi_stopxfer(bus); + + if (flags & SPI_XFER_END) + stm32_spi_set_cs(bus, slave_plat->cs, true); + + return xfer_status; +} + +static int stm32_spi_get_fifo_size(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 count = 0; + + stm32_spi_enable(priv); + + while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, priv->base + STM32_SPI_TXDR); + + stm32_spi_disable(priv); + + debug("%s %d x 8-bit fifo size\n", __func__, count); + + return count; +} + +static int stm32_spi_probe(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + unsigned long clk_rate; + int ret; + unsigned int i; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + /* enable clock */ + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret < 0) + return ret; + + clk_rate = clk_get_rate(&priv->clk); + if (!clk_rate) { + ret = -EINVAL; + goto clk_err; + } + + priv->bus_clk_rate = clk_rate; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &priv->rst_ctl); + if (ret < 0) + goto clk_err; + + reset_assert(&priv->rst_ctl); + udelay(2); + reset_deassert(&priv->rst_ctl); + + ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios, + ARRAY_SIZE(priv->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s cs gpios: %d", dev->name, ret); + goto reset_err; + } + + priv->fifo_size = stm32_spi_get_fifo_size(dev); + + priv->cur_mode = SPI_FULL_DUPLEX; + priv->cur_xferlen = 0; + priv->cur_bpw = SPI_DEFAULT_WORDLEN; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { + if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + continue; + + dm_gpio_set_dir_flags(&priv->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + + /* Ensure I2SMOD bit is kept cleared */ + clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - automatic communication suspend when RX-Fifo is full + */ + setbits_le32(priv->base + STM32_SPI_CR1, + SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); + + /* + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + * - keep control of all associated GPIOs + */ + setbits_le32(priv->base + STM32_SPI_CFG2, + SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); + + return 0; + +reset_err: + reset_free(&priv->rst_ctl); + +clk_err: + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return ret; +}; + +static int stm32_spi_remove(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + int ret; + + stm32_spi_stopxfer(dev); + stm32_spi_disable(priv); + + ret = reset_assert(&priv->rst_ctl); + if (ret < 0) + return ret; + + reset_free(&priv->rst_ctl); + + ret = clk_disable(&priv->clk); + if (ret < 0) + return ret; + + clk_free(&priv->clk); + + return ret; +}; + +static const struct dm_spi_ops stm32_spi_ops = { + .claim_bus = stm32_spi_claim_bus, + .release_bus = stm32_spi_release_bus, + .set_mode = stm32_spi_set_mode, + .set_speed = stm32_spi_set_speed, + .xfer = stm32_spi_xfer, +}; + +static const struct udevice_id stm32_spi_ids[] = { + { .compatible = "st,stm32h7-spi", }, + { } +}; + +U_BOOT_DRIVER(stm32_spi) = { + .name = "stm32_spi", + .id = UCLASS_SPI, + .of_match = stm32_spi_ids, + .ops = &stm32_spi_ops, + .priv_auto_alloc_size = sizeof(struct stm32_spi_priv), + .probe = stm32_spi_probe, + .remove = stm32_spi_remove, +}; diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 6552a5b..520eb65 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -401,6 +401,8 @@ static void reconfig_usbd(struct dwc2_udc *dev) unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); uint32_t dflt_gusbcfg; uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; + u32 max_hw_ep; + int pdata_hw_ep; debug("Reseting OTG controller\n"); @@ -486,10 +488,22 @@ static void reconfig_usbd(struct dwc2_udc *dev) writel((np_tx_fifo_sz << 16) | rx_fifo_sz, ®->gnptxfsiz); - for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++) + /* retrieve the number of TX fifo */ + max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> + GHWCFG4_NUM_IN_EPS_SHIFT; + pdata_hw_ep = dev->pdata->tx_fifo_sz_array[DWC2_SIZE_NB_OFFS]; + + if (pdata_hw_ep && max_hw_ep != pdata_hw_ep) + pr_err("Got %d hw endpoint and %d tx-fifo-size in array !!\n", + max_hw_ep, pdata_hw_ep); + + for (i = 1; i <= max_hw_ep; i++) { + if (pdata_hw_ep) + tx_fifo_sz = dev->pdata->tx_fifo_sz_array[(i - 1) + + DWC2_SIZE_OFFS]; writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) | tx_fifo_sz << 16, ®->dieptxf[i-1]); - + } /* Flush the RX FIFO */ writel(RX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & RX_FIFO_FLUSH) diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h index b64e222..a092f43 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_priv.h +++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h @@ -24,7 +24,6 @@ #define EP_FIFO_SIZE2 1024 /* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */ #define DWC2_MAX_ENDPOINTS 4 -#define DWC2_MAX_HW_ENDPOINTS 16 #define WAIT_FOR_SETUP 0 #define DATA_STATE_XMIT 1 diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index a1829b3..449b208 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -60,22 +60,24 @@ struct dwc2_usbotg_reg { u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ u32 grxfsiz; /* Receive FIFO Size */ u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - u8 res1[216]; + u8 res1[36]; + u32 ghwcfg4; /* User HW Config4 */ + u8 res2[176]; u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ - u8 res2[1728]; + u8 res3[1728]; /* Device Configuration */ u32 dcfg; /* Device Configuration Register */ u32 dctl; /* Device Control */ u32 dsts; /* Device Status */ - u8 res3[4]; + u8 res4[4]; u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */ u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */ u32 daint; /* Device All Endpoints Interrupt */ u32 daintmsk; /* Device All Endpoints Interrupt Mask */ - u8 res4[224]; + u8 res5[224]; struct dwc2_dev_in_endp in_endp[16]; struct dwc2_dev_out_endp out_endp[16]; - u8 res5[768]; + u8 res6[768]; struct ep_fifo ep[16]; }; @@ -86,6 +88,9 @@ struct dwc2_usbotg_reg { #define B_SESSION_VALID (0x1<<19) #define A_SESSION_VALID (0x1<<18) +/* DWC2_UDC_OTG_GOTINT */ +#define GOTGINT_SES_END_DET (1<<2) + /* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) #define PTXFE_ZERO (1<<8) @@ -118,6 +123,7 @@ struct dwc2_usbotg_reg { #define INT_NP_TX_FIFO_EMPTY (0x1<<5) #define INT_RX_FIFO_NOT_EMPTY (0x1<<4) #define INT_SOF (0x1<<3) +#define INT_OTG (0x1<<2) #define INT_DEV_MODE (0x0<<0) #define INT_HOST_MODE (0x1<<1) #define INT_GOUTNakEff (0x01<<7) @@ -246,7 +252,7 @@ struct dwc2_usbotg_reg { /* Masks definitions */ #define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\ - | INT_RESET | INT_SUSPEND) + | INT_RESET | INT_SUSPEND | INT_OTG) #define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) #define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) #define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ @@ -269,4 +275,9 @@ struct dwc2_usbotg_reg { /* Device ALL Endpoints Interrupt Register (DAINT) */ #define DAINT_IN_EP_INT(x) (x << 0) #define DAINT_OUT_EP_INT(x) (x << 16) + +/* User HW Config4 */ +#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT 26 + #endif diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index a75af49..7eb632d 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -467,7 +467,7 @@ static void process_ep_out_intr(struct dwc2_udc *dev) static int dwc2_udc_irq(int irq, void *_dev) { struct dwc2_udc *dev = _dev; - u32 intr_status; + u32 intr_status, gotgint; u32 usb_status, gintmsk; unsigned long flags = 0; @@ -521,14 +521,24 @@ static int dwc2_udc_irq(int irq, void *_dev) && dev->driver) { if (dev->driver->suspend) dev->driver->suspend(&dev->gadget); + } + } + + if (intr_status & INT_OTG) { + gotgint = readl(®->gotgint); + debug_cond(DEBUG_ISR, + "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint); - /* HACK to let gadget detect disconnected state */ + if (gotgint & GOTGINT_SES_END_DET) { + debug_cond(DEBUG_ISR, "\t\tSession End Detected\n"); + /* Let gadget detect disconnected state */ if (dev->driver->disconnect) { spin_unlock_irqrestore(&dev->lock, flags); dev->driver->disconnect(&dev->gadget); spin_lock_irqsave(&dev->lock, flags); } } + writel(gotgint, ®->gotgint); } if (intr_status & INT_RESUME) { diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c index ad1d6f0..41c4bef 100644 --- a/drivers/video/orisetech_otm8009a.c +++ b/drivers/video/orisetech_otm8009a.c @@ -302,10 +302,13 @@ static int otm8009a_panel_probe(struct udevice *dev) int ret; if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) { - dev_err(dev, "enable regulator '%s'\n", priv->reg->name); + dev_dbg(dev, "enable regulator '%s'\n", priv->reg->name); ret = regulator_set_enable(priv->reg, true); - if (ret) + if (ret) { + dev_err(dev, "Regulator : '%s' - can't enable\n", + priv->reg->name); return ret; + } } /* reset panel */ diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 5fe49a5..367d811 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -277,7 +277,9 @@ static int video_post_bind(struct udevice *dev) return 0; size = alloc_fb(dev, &addr); if (addr < gd->video_bottom) { - /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */ + /* Device tree node may need the 'u-boot,dm-pre-reloc' or + * 'u-boot,dm-pre-proper' tag + */ printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n", dev->name); return -ENOSPC; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 705fc7d..5bae563 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -20,6 +20,13 @@ config BCM2835_WDT This provides basic infrastructure to support BCM2835/2836 watchdog hardware, with a max timeout of ~15secs. +config IMX_WATCHDOG + bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + select HW_WATCHDOG + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver. + config OMAP_WATCHDOG bool "TI OMAP watchdog driver" depends on ARCH_OMAP2PLUS @@ -52,14 +59,6 @@ config WDT What exactly happens when the timer expires is up to a particular device/driver. -config WDT_SANDBOX - bool "Enable Watchdog Timer support for Sandbox" - depends on SANDBOX && WDT - help - Enable Watchdog Timer support in Sandbox. This is a dummy device that - can be probed and supports all of the methods of WDT, but does not - really do anything. - config WDT_ARMADA_37XX bool "Marvell Armada 37xx watchdog timer support" depends on WDT && ARMADA_3700 @@ -88,13 +87,6 @@ config WDT_BCM6345 The watchdog timer is stopped when initialized. It performs full SoC reset. -config WDT_ORION - bool "Orion watchdog timer support" - depends on WDT - help - Select this to enable Orion watchdog timer, which can be found on some - Marvell Armada chips. - config WDT_CDNS bool "Cadence watchdog timer support" depends on WDT @@ -103,20 +95,28 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. -config STM32MP_WATCHDOG - bool "Enable IWDG watchdog driver for STM32 MP's family" - depends on ARCH_STM32MP - select HW_WATCHDOG +config WDT_ORION + bool "Orion watchdog timer support" + depends on WDT help - Enable the STM32 watchdog (IWDG) driver. Enable support to - configure STM32's on-SoC watchdog. + Select this to enable Orion watchdog timer, which can be found on some + Marvell Armada chips. + +config WDT_SANDBOX + bool "Enable Watchdog Timer support for Sandbox" + depends on SANDBOX && WDT + help + Enable Watchdog Timer support in Sandbox. This is a dummy device that + can be probed and supports all of the methods of WDT, but does not + really do anything. -config STM32MP_WATCHDOG_TIMEOUT_SECS - int "IWDG watchdog timeout" - depends on STM32MP_WATCHDOG - default 32 +config WDT_STM32MP + bool "IWDG watchdog driver for STM32 MP's family" + depends on WDT + imply WATCHDOG help - Configure the timeout for IWDG (default: 32s). + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" @@ -126,11 +126,4 @@ config XILINX_TB_WATCHDOG Select this to enable Xilinx Axi watchdog timer, which can be found on some Xilinx Microblaze Platforms. -config IMX_WATCHDOG - bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" - select HW_WATCHDOG - help - Select this to enable the IMX and LSCH2 of Layerscape watchdog - driver. - endmenu diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 25491cf..6374b5b 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -23,4 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o -obj-$(CONFIG_STM32MP_WATCHDOG) += stm32mp_wdt.o \ No newline at end of file +obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c index 696be1b..ea85e41 100644 --- a/drivers/watchdog/stm32mp_wdt.c +++ b/drivers/watchdog/stm32mp_wdt.c @@ -1,16 +1,15 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved */ #include #include #include -#include #include -#include +#include #include -#include +#include /* IWDG registers */ #define IWDG_KR 0x00 /* Key register */ @@ -29,36 +28,78 @@ /* IWDG_RLR register values */ #define RLR_MAX 0xFFF /* Max value supported by reload register */ -static fdt_addr_t stm32mp_wdt_base - __attribute__((section(".data"))) = FDT_ADDR_T_NONE; +/* IWDG_SR register bit values */ +#define SR_PVU BIT(0) /* Watchdog prescaler value update */ +#define SR_RVU BIT(1) /* Watchdog counter reload value update */ -void hw_watchdog_reset(void) +#define DEFAULT_TIMEOUT_SECS 32 /* default timeout */ + +struct stm32mp_wdt_priv { + fdt_addr_t base; /* registers addr in physical memory */ + u32 timeout; /* timeout in seconds */ + unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ +}; + +static int stm32mp_wdt_reset(struct udevice *dev) { - if (stm32mp_wdt_base != FDT_ADDR_T_NONE) - writel(KR_KEY_RELOAD, stm32mp_wdt_base + IWDG_KR); + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + + writel(KR_KEY_RELOAD, priv->base + IWDG_KR); + + return 0; } -void hw_watchdog_init(void) +static int stm32mp_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { - struct regmap *map; + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + int reload; + u32 val; + int ret; + + /* Prescaler fixed to 256 */ + reload = (priv->timeout * 1000) * priv->wdt_clk_rate / 256; + if (reload > RLR_MAX + 1) + /* Force to max watchdog counter reload value */ + reload = RLR_MAX + 1; + else if (!reload) + /* Force to min watchdog counter reload value */ + reload = priv->wdt_clk_rate / 256; + + /* Set prescaler & reload registers */ + writel(KR_KEY_EWA, priv->base + IWDG_KR); + writel(PR_256, priv->base + IWDG_PR); + writel(reload - 1, priv->base + IWDG_RLR); - map = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_IWDG); - if (!IS_ERR(map)) - stm32mp_wdt_base = map->ranges[0].start; - else - printf("%s: iwdg init error", __func__); + /* Enable watchdog */ + writel(KR_KEY_ENABLE, priv->base + IWDG_KR); + + /* Wait for the registers to be updated */ + ret = readl_poll_timeout(priv->base + IWDG_SR, val, + val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ); + + if (ret < 0) { + pr_err("Updating IWDG registers timeout"); + return -ETIMEDOUT; + } + + return 0; } static int stm32mp_wdt_probe(struct udevice *dev) { - struct regmap *map = syscon_get_regmap(dev); + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); struct clk clk; - int ret, reload; - u32 time_start; - ulong regmap_base = map->ranges[0].start; + int ret; debug("IWDG init\n"); + priv->base = devfdt_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->timeout = dev_read_u32_default(dev, "timeout-sec", + DEFAULT_TIMEOUT_SECS); + /* Enable clock */ ret = clk_get_by_name(dev, "pclk", &clk); if (ret) @@ -73,47 +114,28 @@ static int stm32mp_wdt_probe(struct udevice *dev) if (ret) return ret; - /* Prescaler fixed to 256 */ - reload = CONFIG_STM32MP_WATCHDOG_TIMEOUT_SECS * - clk_get_rate(&clk) / 256; - if (reload > RLR_MAX + 1) - /* Force to max watchdog counter reload value */ - reload = RLR_MAX + 1; - else if (!reload) - /* Force to min watchdog counter reload value */ - reload = clk_get_rate(&clk) / 256; - - /* Enable watchdog */ - writel(KR_KEY_ENABLE, regmap_base + IWDG_KR); - - /* Set prescaler & reload registers */ - writel(KR_KEY_EWA, regmap_base + IWDG_KR); - writel(PR_256, regmap_base + IWDG_PR); - writel(reload - 1, regmap_base + IWDG_RLR); - - /* Wait for the registers to be updated */ - time_start = get_timer(0); - while (readl(regmap_base + IWDG_SR)) { - if (get_timer(time_start) > CONFIG_SYS_HZ) { - pr_err("Updating IWDG registers timeout"); - return -ETIMEDOUT; - } - } + priv->wdt_clk_rate = clk_get_rate(&clk); debug("IWDG init done\n"); return 0; } +static const struct wdt_ops stm32mp_wdt_ops = { + .start = stm32mp_wdt_start, + .reset = stm32mp_wdt_reset, +}; + static const struct udevice_id stm32mp_wdt_match[] = { - { .compatible = "st,stm32mp1-iwdg", - .data = STM32MP_SYSCON_IWDG }, + { .compatible = "st,stm32mp1-iwdg" }, { /* sentinel */ } }; U_BOOT_DRIVER(stm32mp_wdt) = { .name = "stm32mp-wdt", - .id = UCLASS_SYSCON, + .id = UCLASS_WDT, .of_match = stm32mp_wdt_match, + .priv_auto_alloc_size = sizeof(struct stm32mp_wdt_priv), .probe = stm32mp_wdt_probe, + .ops = &stm32mp_wdt_ops, }; diff --git a/env/Kconfig b/env/Kconfig index 9011109..b304451 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -2,18 +2,12 @@ menu "Environment" config ENV_IS_NOWHERE bool "Environment is not stored" - depends on !ENV_IS_IN_EEPROM - depends on !ENV_IS_IN_EXT4 - depends on !ENV_IS_IN_FAT - depends on !ENV_IS_IN_FLASH - depends on !ENV_IS_IN_MMC - depends on !ENV_IS_IN_NAND - depends on !ENV_IS_IN_NVRAM - depends on !ENV_IS_IN_ONENAND - depends on !ENV_IS_IN_REMOTE - depends on !ENV_IS_IN_SPI_FLASH - depends on !ENV_IS_IN_UBI - default y + default y if !ENV_IS_IN_EEPROM && !ENV_IS_IN_EXT4 && \ + !ENV_IS_IN_FAT && !ENV_IS_IN_FLASH && \ + !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \ + !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \ + !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \ + !ENV_IS_IN_UBI help Define this if you don't want to or can't have an environment stored on a storage medium. In this case the environment will still exist diff --git a/env/ext4.c b/env/ext4.c index 09c5e4a..d027a70 100644 --- a/env/ext4.c +++ b/env/ext4.c @@ -30,6 +30,16 @@ #include #include +__weak const char *env_ext4_get_intf(void) +{ + return (const char *)CONFIG_ENV_EXT4_INTERFACE; +} + +__weak const char *env_ext4_get_dev_part(void) +{ + return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; +} + #ifdef CONFIG_CMD_SAVEENV static int env_ext4_save(void) { @@ -38,13 +48,14 @@ static int env_ext4_save(void) disk_partition_t info; int dev, part; int err; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); err = env_export(&env_new); if (err) return err; - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) return 1; @@ -54,8 +65,7 @@ static int env_ext4_save(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for saveenv **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); return 1; } @@ -65,8 +75,7 @@ static int env_ext4_save(void) if (err == -1) { printf("\n** Unable to write \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); return 1; } @@ -83,14 +92,15 @@ static int env_ext4_load(void) int dev, part; int err; loff_t off; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); #ifdef CONFIG_MMC - if (!strcmp(CONFIG_ENV_EXT4_INTERFACE, "mmc")) + if (!strcmp(ifname, "mmc")) mmc_initialize(NULL); #endif - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) goto err_env_relocate; @@ -100,8 +110,7 @@ static int env_ext4_load(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for loading the env **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); goto err_env_relocate; } @@ -111,8 +120,7 @@ static int env_ext4_load(void) if (err == -1) { printf("\n** Unable to read \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); goto err_env_relocate; } diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index a7f543f..4eb77c3 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -864,6 +864,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer, printf("error in File System init\n"); return -1; } + + if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { + printf("Unsupported feature metadata_csum found, not writing.\n"); + return -1; + } + inodes_per_block = fs->blksz / fs->inodesz; parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); if (parent_inodeno == -1) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index b4beaa7..1501845 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -48,7 +48,19 @@ /* * Env parameters */ -#define CONFIG_ENV_SIZE SZ_4K +#define CONFIG_ENV_OVERWRITE +#define CONFIG_ENV_SIZE SZ_8K + +#if defined(CONFIG_ENV_IS_IN_UBI) +#define CONFIG_ENV_UBI_PART "UBI" +#define CONFIG_ENV_UBI_VOLUME "uboot_config" +#define CONFIG_ENV_UBI_VOLUME_REDUND "uboot_config_r" +#endif + +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH) +#define CONFIG_ENV_SECT_SIZE SZ_256K +#define CONFIG_ENV_OFFSET 0x00280000 +#endif /* ATAGs */ #define CONFIG_CMDLINE_TAG @@ -90,9 +102,6 @@ #define CONFIG_SYS_NAND_ONFI_DETECTION #define CONFIG_SYS_MAX_NAND_DEVICE 1 -/* SPI nand */ -#define CONFIG_SYS_MAX_NAND_DEVICE 1 - /* SPI FLASH support */ #if defined(CONFIG_SPL_BUILD) #define CONFIG_SYS_SPI_U_BOOT_OFFS 0x80000 @@ -130,33 +139,102 @@ func(MMC, mmc, 2) \ func(PXE, pxe, na) -#include +/* + * bootcmd for stm32mp1: + * CONFIG_BOOTCOMMAND="run bootcmd_stm32mp" + * for serial/usb: execute the stm32prog command + * for mmc boot (eMMC, SD card), boot only on the same device + * for nand boot, boot with on ubifs partition on nand + * for nor boot, use the default order + */ +#define CONFIG_PREBOOT -#define CONFIG_PREBOOT \ - "echo \"Boot over ${boot_device}${boot_instance}!\"; " \ - "if test ${boot_device} = serial; then " \ - "stm32prog serial ${boot_instance}; " \ - "else if test ${boot_device} = usb; then " \ - "stm32prog usb ${boot_instance}; " \ +#define STM32MP_BOOTCMD "bootcmd_stm32mp=" \ + "echo \"Boot over ${boot_device}${boot_instance}!\";" \ + "if test ${boot_device} = serial || test ${boot_device} = usb;" \ + "then stm32prog ${boot_device} ${boot_instance}; " \ "else " \ - "if test ${boot_device} = mmc; then " \ - "env set boot_targets \"mmc${boot_instance}\"; "\ - "else if test ${boot_device} = nand; then " \ - "env set boot_targets \"ubifs0\"; "\ - "fi; fi; fi; fi;" + "run env_check;" \ + "if test ${boot_device} = mmc;" \ + "then env set boot_targets \"mmc${boot_instance}\"; fi;" \ + "if test ${boot_device} = nand;" \ + "then env set boot_targets ubifs0; fi;" \ + "run distro_bootcmd;" \ + "fi;\0" + +/* DTIMG command added only for Android distribution */ +#ifdef CONFIG_CMD_DTIMG +/* + * bootcmd for android on MMC: + * CONFIG_BOOTCOMMAND="run bootcmd_android" + * overidde DISTRO script "mmc_boot" to boot android on mmc + * using system_${suffix} partition (with "_a") by default + * - display splash screen + * - load device tree form dtimg + * - load kernel and set bootargs + * - start kernel + */ + +#define STM32MP_ANDROID \ + "suffix=a\0" \ + "dtimg_addr=0xc4500000\0" \ + "android_mmc_splash="\ + "if part start mmc ${devnum} splash splash_start && " \ + "part size mmc ${devnum} splash splash_size;"\ + "then " \ + "mmc read ${splashimage} ${splash_start} ${splash_size};" \ + "cls; bmp display ${splashimage} m m;" \ + "fi\0" \ + "android_mmc_fdt="\ + "if part start mmc ${devnum} dt_${suffix} dt_start &&" \ + "part size mmc ${devnum} dt_${suffix} dt_size;"\ + "then " \ + "mmc read ${dtimg_addr} ${dt_start} ${dt_size};" \ + "dtimg getindex ${dtimg_addr} ${board_id} ${board_rev}" \ + " dt_index;" \ + "dtimg start ${dtimg_addr} ${dt_index} fdt_addr_r;"\ + "fi\0" \ + "android_mmc_kernel="\ + "if part start mmc ${devnum} boot_${suffix} boot_start &&" \ + "part size mmc ${devnum} boot_${suffix} boot_size;"\ + "then " \ + "mmc read ${kernel_addr_r} ${boot_start} ${boot_size};" \ + "part nb mmc ${devnum} system_${suffix} rootpart_nb;" \ + "env set bootargs" \ + "root=/dev/mmcblk${devnum}p${rootpart_nb} " \ + "androidboot.serialno=${serial#} " \ + "androidboot.slot_suffix=_${suffix};"\ + "fi\0" \ + "android_mmc_boot="\ + "mmc dev ${devnum};"\ + "run android_mmc_splash;" \ + "run android_mmc_fdt;" \ + "run android_mmc_kernel;" \ + "bootm ${kernel_addr_r} - ${fdt_addr_r};\0" \ + "bootcmd_android=" \ + "env set mmc_boot run android_mmc_boot;" \ + "run bootcmd_stm32mp\0" + +#else +#define STM32MP_ANDROID +#endif/* CONFIG_CMD_DTIMG */ + +#include #ifdef CONFIG_STM32MP1_OPTEE #define CONFIG_SYS_MEM_TOP_HIDE SZ_32M /* with OPTEE: define specific MTD partitions = teeh, teed, teex */ #define STM32MP_MTDPARTS \ - "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ - "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI);\0" + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \ + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" \ + "mtdparts_spi-nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),512k(teeh),512k(teed),512k(teex),-(UBI)\0" \ #else /* CONFIG_STM32MP1_OPTEE */ #define STM32MP_MTDPARTS \ - "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),-(nor_user)\0" \ - "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),-(nor_user)\0" \ + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" \ + "mtdparts_spi-nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" #endif /* CONFIG_STM32MP1_OPTEE */ @@ -181,7 +259,12 @@ "bootlimit=0\0" \ "altbootcmd=run bootcmd\0" \ "usb_pgood_delay=2000\0" \ + "env_default=1\0" \ + "env_check=if test $env_default -eq 1;"\ + " then env set env_default 0;env save;fi\0" \ + STM32MP_BOOTCMD \ STM32MP_MTDPARTS \ + STM32MP_ANDROID \ BOOTENV \ "boot_net_usb_start=true\0" diff --git a/include/dfu.h b/include/dfu.h index 36304c7..64fdba3 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -167,6 +167,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu); unsigned char *dfu_free_buf(void); unsigned long dfu_get_buf_size(void); bool dfu_usb_get_reset(void); +void dfu_initiated_callback(struct dfu_entity *dfu); int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num); int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num); diff --git a/include/environment.h b/include/environment.h index 5e90f15..e5d4811 100644 --- a/include/environment.h +++ b/include/environment.h @@ -268,9 +268,18 @@ extern struct hsearch_data env_htab; /* Function that updates CRC of the enironment */ void env_crc_update(void); +/* allows to set ext4 interface */ +const char *env_ext4_get_intf(void); + +/* allows to set ext4 device and partition */ +const char *env_ext4_get_dev_part(void); + /* Look up the variable from the default environment */ char *env_get_default(const char *name); +/* Returns the best env location for a board */ +enum env_location env_get_location(enum env_operation op, int prio); + /* [re]set to the default environment */ void set_default_env(const char *s, int flags); diff --git a/include/ext4fs.h b/include/ext4fs.h index bb55639..2421011 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -32,6 +32,7 @@ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_EXT_MAGIC 0xf30a #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 #define EXT4_INDIRECT_BLOCKS 12 diff --git a/include/image-android-dt.h b/include/image-android-dt.h index 9a3aa8f..f9abe85 100644 --- a/include/image-android-dt.h +++ b/include/image-android-dt.h @@ -17,4 +17,6 @@ bool android_dt_get_fdt_by_index(ulong hdr_addr, u32 index, ulong *addr, void android_dt_print_contents(ulong hdr_addr); #endif +int android_dt_get_index(ulong hdr_addr, u32 board_id, u32 board_rev); + #endif /* IMAGE_ANDROID_DT_H */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 68e5915..9cb0e43 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -586,5 +586,6 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset, int mtd_search_alternate_name(const char *mtdname, char *altname, unsigned int max_len); +void board_mtdparts_default(const char **mtdids, const char **mtdparts); #endif #endif /* __MTD_MTD_H__ */ diff --git a/include/netdev.h b/include/netdev.h index 5500162..2b1028c 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -21,6 +21,8 @@ */ int board_eth_init(bd_t *bis); +int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, + bool eth_ref_clk_sel_reg); int cpu_eth_init(bd_t *bis); /* Driver initialization prototypes */ diff --git a/include/spi.h b/include/spi.h index 938627b..7c8abc0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -503,14 +503,15 @@ int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, * device and slave device. * * If no such slave exists, and drv_name is not NULL, then a new slave device - * is automatically bound on this chip select. + * is automatically bound on this chip select with requested speed and mode. * - * Ths new slave device is probed ready for use with the given speed and mode. + * Ths new slave device is probed ready for use with the speed and mode + * from platdata, when available, or the requested value. * * @busnum: SPI bus number * @cs: Chip select to look for - * @speed: SPI speed to use for this slave - * @mode: SPI mode to use for this slave + * @speed: SPI speed to use for this slave when not available in platdata + * @mode: SPI mode to use for this slave when not available in platdata * @drv_name: Name of driver to attach to this chip select * @dev_name: Name of the new device thus created * @busp: Returns bus device diff --git a/include/usb/dwc2_udc.h b/include/usb/dwc2_udc.h index 3bd05fa..a0f7103 100644 --- a/include/usb/dwc2_udc.h +++ b/include/usb/dwc2_udc.h @@ -10,6 +10,10 @@ #define PHY0_SLEEP (1 << 5) +#define DWC2_MAX_HW_ENDPOINTS 16 +#define DWC2_SIZE_NB_OFFS 0 +#define DWC2_SIZE_OFFS 1 + struct dwc2_plat_otg_data { void *priv; int phy_of_node; @@ -23,6 +27,8 @@ struct dwc2_plat_otg_data { unsigned int rx_fifo_sz; unsigned int np_tx_fifo_sz; unsigned int tx_fifo_sz; + /* [0] number of element, [1..17] tx_fifo_sz (max 16 endpoints)*/ + unsigned int tx_fifo_sz_array[DWC2_MAX_HW_ENDPOINTS + 1]; }; int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata); diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py index f04a279..25394f1 100644 --- a/test/py/tests/test_pinmux.py +++ b/test/py/tests/test_pinmux.py @@ -18,6 +18,7 @@ def test_pinmux_usage_2(u_boot_console): assert 'Usage:' in output @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_status_all(u_boot_console): """Test that 'pinmux status -a' displays pin's muxing.""" output = u_boot_console.run_command('pinmux status -a') @@ -28,6 +29,7 @@ def test_pinmux_status_all(u_boot_console): assert ('W1 : 1-wire gpio' in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_list(u_boot_console): """Test that 'pinmux list' returns the pin-controller list.""" output = u_boot_console.run_command('pinmux list') @@ -43,6 +45,7 @@ def test_pinmux_dev_bad(u_boot_console): assert (expected_output in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_dev(u_boot_console): """Test that 'pinmux dev' select the wanted pin controller.""" pincontroller = 'pinctrl' @@ -51,6 +54,7 @@ def test_pinmux_dev(u_boot_console): assert (expected_output in output) @pytest.mark.buildconfigspec('cmd_pinmux') +@pytest.mark.boardspec('sandbox') def test_pinmux_status(u_boot_console): """Test that 'pinmux status' displays selected pincontroller's pin muxing descriptions.""" -- 2.7.4