meta-st-stm32mp/recipes-bsp/u-boot/u-boot-stm32mp/0013-ARM-v2018.11-stm32mp-r...

6903 lines
209 KiB
Diff

From a827cb0a8ffbd388b225f0b523e08f19dbcfd614 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
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"
" <addr>: image address in RAM, in hex\n"
" <index>: index of desired FDT in the image\n"
- " <varname>: name of variable where to store size of FDT"
+ " <varname>: name of variable where to store size of FDT\n"
+ "dtimg getindex <addr> <board_id> <board_rev> [varname]\n"
+ " - get index of FDT in the image, by board identifier and revision\n"
+ " <addr>: image address in RAM, in hex\n"
+ " <board_id>: board identifier\n"
+ " <board_rev>: 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 <fastboot.h>
#include <net.h>
#include <usb.h>
+#include <watchdog.h>
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 <interface> <dev> <part> <varname>\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 <interface> <dev> <part> <varname>\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 <cli.h>
#include <watchdog.h>
+#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 = &<phandle> <offset> <mask>;
+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 <linux/printk.h>
#include <linux/psci.h>
-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, <vikas.manocha@st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/stm32.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#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(&regs->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(&regs->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
+
+ writel(BSRR_BIT(idx, value), &regs->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(&regs->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), &regs->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(&regs->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, <vikas.manocha@st.com> for STMicroelectronics.
- */
-
-#include <common.h>
-#include <clk.h>
-#include <dm.h>
-#include <fdtdec.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/stm32.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-
-#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(&regs->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(&regs->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
-
- writel(BSRR_BIT(idx, value), &regs->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(&regs->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), &regs->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(&regs->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 <common.h>
#include <clk.h>
#include <dm.h>
-#include <fdtdec.h>
-#include <linux/libfdt.h>
#include <hwspinlock.h>
#include <asm/io.h>
@@ -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 <common.h>
#include <command.h>
+#include <fuse.h>
#include <misc.h>
#include <errno.h>
#include <dm/device.h>
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 <asm/io.h>
#include <asm/gpio.h>
#include <linux/iopoll.h>
+#include <watchdog.h>
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 <asm/arch/gpio.h>
#include <asm/gpio.h>
#include <asm/io.h>
+#include <dm/lists.h>
#include <dm/pinctrl.h>
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(&regs->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 <common.h>
@@ -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 [<param> <val>] display/change DDR information\n"
- "freq [freq] display/change the DDR frequency\n"
- "param [type|reg] print input parameters\n"
- "param <reg> <val> edit parameters in step 0\n"
- "print [type|reg] dump register\n"
- "edit <reg> <val> modify register\n"
- " all registers if [type|reg] is absent\n"
- " <type> = ctl, phy\n"
- " or one category (static, timing, map, perf, cal, dyn)\n"
- " <reg> = name of the register\n"
- "step [n] list the step / go to the step <n>\n"
- "next go to the next step\n"
- "go continue SPL execution\n"
- "reset reboot machine\n"
- "test [help] | <n> [...] list (with help) or execute test <n>\n"
+ "help displays help\n"
+ "info displays DDR information\n"
+ "info <param> <val> changes DDR information\n"
+ " with <param> = step, name, size or speed\n"
+ "freq displays the DDR PHY frequency in kHz\n"
+ "freq <freq> changes the DDR PHY frequency\n"
+ "param [type|reg] prints input parameters\n"
+ "param <reg> <val> edits parameters in step 0\n"
+ "print [type|reg] dumps registers\n"
+ "edit <reg> <val> modifies one register\n"
+ "step lists the available step\n"
+ "step <n> go to the step <n>\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] | <n> [...] lists (with help) or executes test <n>\n"
+#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
- "tuning [help] | <n> [...] list (with help) or execute test <n>\n"
+ "tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
#endif
+ "\nwith for [type|reg]:\n"
+ " all registers if absent\n"
+ " <type> = ctl, phy\n"
+ " or one category (static, timing, map, perf, cal, dyn)\n"
+ " <reg> = 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 <asm/io.h>
#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 <common.h>
#include <console.h>
+#include <watchdog.h>
#include <asm/io.h>
#include <linux/log2.h>
#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 <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+
+#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 <reset.h>
#include <spi.h>
#include <spi_flash.h>
+#include <spi-mem.h>
#include <asm/io.h>
#include <asm/arch/stm32.h>
#include <linux/ioport.h>
+#include <linux/iopoll.h>
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 <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset.h>
+#include <spi.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+
+/* 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, &reg->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,
&reg->gnptxfsiz);
- for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++)
+ /* retrieve the number of TX fifo */
+ max_hw_ep = (readl(&reg->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, &reg->dieptxf[i-1]);
-
+ }
/* Flush the RX FIFO */
writel(RX_FIFO_FLUSH, &reg->grstctl);
while (readl(&reg->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(&reg->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, &reg->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 <common.h>
#include <clk.h>
#include <dm.h>
-#include <regmap.h>
#include <syscon.h>
-#include <watchdog.h>
+#include <wdt.h>
#include <asm/io.h>
-#include <asm/arch/stm32.h>
+#include <linux/iopoll.h>
/* 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 <ext4fs.h>
#include <mmc.h>
+__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 <config_distro_bootcmd.h>
+/*
+ * 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 <config_distro_bootcmd.h>
#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