6903 lines
209 KiB
Diff
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(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset,
|
|
+ int value)
|
|
+{
|
|
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
+ struct stm32_gpio_regs *regs = priv->regs;
|
|
+ int bits_index;
|
|
+ int mask;
|
|
+ int idx;
|
|
+
|
|
+ idx = stm32_offset_to_index(dev, offset);
|
|
+ if (idx < 0)
|
|
+ return idx;
|
|
+
|
|
+ bits_index = MODE_BITS(idx);
|
|
+ mask = MODE_BITS_MASK << bits_index;
|
|
+
|
|
+ clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
|
|
+
|
|
+ writel(BSRR_BIT(idx, value), ®s->bsrr);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_gpio_get_value(struct udevice *dev, unsigned offset)
|
|
+{
|
|
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
+ struct stm32_gpio_regs *regs = priv->regs;
|
|
+ int idx;
|
|
+
|
|
+ idx = stm32_offset_to_index(dev, offset);
|
|
+ if (idx < 0)
|
|
+ return idx;
|
|
+
|
|
+ return readl(®s->idr) & BIT(idx) ? 1 : 0;
|
|
+}
|
|
+
|
|
+static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
|
|
+{
|
|
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
+ struct stm32_gpio_regs *regs = priv->regs;
|
|
+ int idx;
|
|
+
|
|
+ idx = stm32_offset_to_index(dev, offset);
|
|
+ if (idx < 0)
|
|
+ return idx;
|
|
+
|
|
+ writel(BSRR_BIT(idx, value), ®s->bsrr);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
|
|
+{
|
|
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
+ struct stm32_gpio_regs *regs = priv->regs;
|
|
+ int bits_index;
|
|
+ int mask;
|
|
+ int idx;
|
|
+ u32 mode;
|
|
+
|
|
+ idx = stm32_offset_to_index(dev, offset);
|
|
+ if (idx < 0)
|
|
+ return idx;
|
|
+
|
|
+ bits_index = MODE_BITS(idx);
|
|
+ mask = MODE_BITS_MASK << bits_index;
|
|
+
|
|
+ mode = (readl(®s->moder) & mask) >> bits_index;
|
|
+ if (mode == STM32_GPIO_MODE_OUT)
|
|
+ return GPIOF_OUTPUT;
|
|
+ if (mode == STM32_GPIO_MODE_IN)
|
|
+ return GPIOF_INPUT;
|
|
+ if (mode == STM32_GPIO_MODE_AN)
|
|
+ return GPIOF_UNUSED;
|
|
+
|
|
+ return GPIOF_FUNC;
|
|
+}
|
|
+
|
|
+static const struct dm_gpio_ops gpio_stm32_ops = {
|
|
+ .direction_input = stm32_gpio_direction_input,
|
|
+ .direction_output = stm32_gpio_direction_output,
|
|
+ .get_value = stm32_gpio_get_value,
|
|
+ .set_value = stm32_gpio_set_value,
|
|
+ .get_function = stm32_gpio_get_function,
|
|
+};
|
|
+
|
|
+static int gpio_stm32_probe(struct udevice *dev)
|
|
+{
|
|
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
|
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
+ struct ofnode_phandle_args args;
|
|
+ struct clk clk;
|
|
+ fdt_addr_t addr;
|
|
+ const char *name;
|
|
+ int ret;
|
|
+ int i;
|
|
+
|
|
+ addr = dev_read_addr(dev);
|
|
+ if (addr == FDT_ADDR_T_NONE)
|
|
+ return -EINVAL;
|
|
+
|
|
+ priv->regs = (struct stm32_gpio_regs *)addr;
|
|
+ name = dev_read_string(dev, "st,bank-name");
|
|
+ if (!name)
|
|
+ return -EINVAL;
|
|
+ uc_priv->bank_name = name;
|
|
+
|
|
+ i = 0;
|
|
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges",
|
|
+ NULL, 3, i, &args);
|
|
+
|
|
+ while (ret != -ENOENT) {
|
|
+ priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1,
|
|
+ args.args[0]);
|
|
+
|
|
+ uc_priv->gpio_count += args.args[2];
|
|
+
|
|
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
|
|
+ ++i, &args);
|
|
+ }
|
|
+
|
|
+ dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n",
|
|
+ (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count,
|
|
+ priv->gpio_range);
|
|
+
|
|
+ ret = clk_get_by_index(dev, 0, &clk);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = clk_enable(&clk);
|
|
+
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to enable clock\n");
|
|
+ return ret;
|
|
+ }
|
|
+ debug("clock enabled for device %s\n", dev->name);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+U_BOOT_DRIVER(gpio_stm32) = {
|
|
+ .name = "gpio_stm32",
|
|
+ .id = UCLASS_GPIO,
|
|
+ .probe = gpio_stm32_probe,
|
|
+ .ops = &gpio_stm32_ops,
|
|
+ .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS,
|
|
+ .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
|
|
+};
|
|
diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c
|
|
deleted file mode 100644
|
|
index 7fff64e..0000000
|
|
--- a/drivers/gpio/stm32f7_gpio.c
|
|
+++ /dev/null
|
|
@@ -1,216 +0,0 @@
|
|
-// SPDX-License-Identifier: GPL-2.0+
|
|
-/*
|
|
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
|
|
- * Author(s): Vikas Manocha, <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(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset,
|
|
- int value)
|
|
-{
|
|
- struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
- struct stm32_gpio_regs *regs = priv->regs;
|
|
- int bits_index;
|
|
- int mask;
|
|
- int idx;
|
|
-
|
|
- idx = stm32_offset_to_index(dev, offset);
|
|
- if (idx < 0)
|
|
- return idx;
|
|
-
|
|
- bits_index = MODE_BITS(idx);
|
|
- mask = MODE_BITS_MASK << bits_index;
|
|
-
|
|
- clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
|
|
-
|
|
- writel(BSRR_BIT(idx, value), ®s->bsrr);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int stm32_gpio_get_value(struct udevice *dev, unsigned offset)
|
|
-{
|
|
- struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
- struct stm32_gpio_regs *regs = priv->regs;
|
|
- int idx;
|
|
-
|
|
- idx = stm32_offset_to_index(dev, offset);
|
|
- if (idx < 0)
|
|
- return idx;
|
|
-
|
|
- return readl(®s->idr) & BIT(idx) ? 1 : 0;
|
|
-}
|
|
-
|
|
-static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value)
|
|
-{
|
|
- struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
- struct stm32_gpio_regs *regs = priv->regs;
|
|
- int idx;
|
|
-
|
|
- idx = stm32_offset_to_index(dev, offset);
|
|
- if (idx < 0)
|
|
- return idx;
|
|
-
|
|
- writel(BSRR_BIT(idx, value), ®s->bsrr);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
|
|
-{
|
|
- struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
- struct stm32_gpio_regs *regs = priv->regs;
|
|
- int bits_index;
|
|
- int mask;
|
|
- int idx;
|
|
- u32 mode;
|
|
-
|
|
- idx = stm32_offset_to_index(dev, offset);
|
|
- if (idx < 0)
|
|
- return idx;
|
|
-
|
|
- bits_index = MODE_BITS(idx);
|
|
- mask = MODE_BITS_MASK << bits_index;
|
|
-
|
|
- mode = (readl(®s->moder) & mask) >> bits_index;
|
|
- if (mode == STM32_GPIO_MODE_OUT)
|
|
- return GPIOF_OUTPUT;
|
|
- if (mode == STM32_GPIO_MODE_IN)
|
|
- return GPIOF_INPUT;
|
|
- if (mode == STM32_GPIO_MODE_AN)
|
|
- return GPIOF_UNUSED;
|
|
-
|
|
- return GPIOF_FUNC;
|
|
-}
|
|
-
|
|
-static const struct dm_gpio_ops gpio_stm32_ops = {
|
|
- .direction_input = stm32_gpio_direction_input,
|
|
- .direction_output = stm32_gpio_direction_output,
|
|
- .get_value = stm32_gpio_get_value,
|
|
- .set_value = stm32_gpio_set_value,
|
|
- .get_function = stm32_gpio_get_function,
|
|
-};
|
|
-
|
|
-static int gpio_stm32_probe(struct udevice *dev)
|
|
-{
|
|
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
|
- struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
|
- struct ofnode_phandle_args args;
|
|
- struct clk clk;
|
|
- fdt_addr_t addr;
|
|
- const char *name;
|
|
- int ret;
|
|
- int i;
|
|
-
|
|
- addr = dev_read_addr(dev);
|
|
- if (addr == FDT_ADDR_T_NONE)
|
|
- return -EINVAL;
|
|
-
|
|
- priv->regs = (struct stm32_gpio_regs *)addr;
|
|
- name = dev_read_string(dev, "st,bank-name");
|
|
- if (!name)
|
|
- return -EINVAL;
|
|
- uc_priv->bank_name = name;
|
|
-
|
|
- i = 0;
|
|
- ret = dev_read_phandle_with_args(dev, "gpio-ranges",
|
|
- NULL, 3, i, &args);
|
|
-
|
|
- while (ret != -ENOENT) {
|
|
- priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1,
|
|
- args.args[0]);
|
|
-
|
|
- uc_priv->gpio_count += args.args[2];
|
|
-
|
|
- ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
|
|
- ++i, &args);
|
|
- }
|
|
-
|
|
- dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n",
|
|
- (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count,
|
|
- priv->gpio_range);
|
|
-
|
|
- ret = clk_get_by_index(dev, 0, &clk);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- ret = clk_enable(&clk);
|
|
-
|
|
- if (ret) {
|
|
- dev_err(dev, "failed to enable clock\n");
|
|
- return ret;
|
|
- }
|
|
- debug("clock enabled for device %s\n", dev->name);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static const struct udevice_id stm32_gpio_ids[] = {
|
|
- { .compatible = "st,stm32-gpio" },
|
|
- { }
|
|
-};
|
|
-
|
|
-U_BOOT_DRIVER(gpio_stm32) = {
|
|
- .name = "gpio_stm32",
|
|
- .id = UCLASS_GPIO,
|
|
- .of_match = stm32_gpio_ids,
|
|
- .probe = gpio_stm32_probe,
|
|
- .ops = &gpio_stm32_ops,
|
|
- .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS,
|
|
- .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
|
|
-};
|
|
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
|
|
index b8f3b16..a32bde4 100644
|
|
--- a/drivers/hwspinlock/stm32_hwspinlock.c
|
|
+++ b/drivers/hwspinlock/stm32_hwspinlock.c
|
|
@@ -6,8 +6,6 @@
|
|
#include <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(®s->otyper, OTYPE_MSK << index, ctl->otype << index);
|
|
|
|
- hwspinlock_unlock(&pinctrl_priv->hws);
|
|
+ hwspinlock_unlock(&ctrl_priv->hws);
|
|
|
|
return 0;
|
|
}
|
|
@@ -327,8 +328,8 @@ static int stm32_pinctrl_config(int offset)
|
|
int rv, len;
|
|
|
|
/*
|
|
- * check for "pinmux" property in each subnode of pin controller
|
|
- * phandle "pinctrl-0" (e.g. pins1 and pins2 for usart1)
|
|
+ * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
|
|
+ * usart1) of pin controller phandle "pinctrl-0"
|
|
*/
|
|
fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
|
|
struct stm32_gpio_dsc gpio_dsc;
|
|
@@ -363,6 +364,35 @@ static int stm32_pinctrl_config(int offset)
|
|
return 0;
|
|
}
|
|
|
|
+static int stm32_pinctrl_bind(struct udevice *dev)
|
|
+{
|
|
+ ofnode node;
|
|
+ const char *name;
|
|
+ int ret;
|
|
+
|
|
+ dev_for_each_subnode(node, dev) {
|
|
+ debug("%s: bind %s\n", __func__, ofnode_get_name(node));
|
|
+
|
|
+ ofnode_get_property(node, "gpio-controller", &ret);
|
|
+ if (ret < 0)
|
|
+ continue;
|
|
+ /* Get the name of each gpio node */
|
|
+ name = ofnode_get_name(node);
|
|
+ if (!name)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Bind each gpio node */
|
|
+ ret = device_bind_driver_to_node(dev, "gpio_stm32",
|
|
+ name, node, NULL);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ debug("%s: bind %s\n", __func__, name);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
|
|
static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config)
|
|
{
|
|
@@ -431,7 +461,7 @@ U_BOOT_DRIVER(pinctrl_stm32) = {
|
|
.id = UCLASS_PINCTRL,
|
|
.of_match = stm32_pinctrl_ids,
|
|
.ops = &stm32_pinctrl_ops,
|
|
- .bind = dm_scan_fdt_dev,
|
|
+ .bind = stm32_pinctrl_bind,
|
|
.probe = stm32_pinctrl_probe,
|
|
.priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv),
|
|
};
|
|
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
|
|
index 4511625..39e4627 100644
|
|
--- a/drivers/power/regulator/regulator-uclass.c
|
|
+++ b/drivers/power/regulator/regulator-uclass.c
|
|
@@ -113,7 +113,7 @@ int regulator_set_enable(struct udevice *dev, bool enable)
|
|
|
|
uc_pdata = dev_get_uclass_platdata(dev);
|
|
if (!enable && uc_pdata->always_on)
|
|
- return -EACCES;
|
|
+ return 0;
|
|
|
|
return ops->set_enable(dev, enable);
|
|
}
|
|
diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c
|
|
index 0ad6833..645528e 100644
|
|
--- a/drivers/power/regulator/stm32-vrefbuf.c
|
|
+++ b/drivers/power/regulator/stm32-vrefbuf.c
|
|
@@ -30,7 +30,7 @@ struct stm32_vrefbuf {
|
|
struct udevice *vdda_supply;
|
|
};
|
|
|
|
-static const unsigned int stm32_vrefbuf_voltages[] = {
|
|
+static const int stm32_vrefbuf_voltages[] = {
|
|
/* Matches resp. VRS = 000b, 001b, 010b, 011b */
|
|
2500000, 2048000, 1800000, 1500000,
|
|
};
|
|
diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig
|
|
index 761de09..2fd8c7b 100644
|
|
--- a/drivers/ram/stm32mp1/Kconfig
|
|
+++ b/drivers/ram/stm32mp1/Kconfig
|
|
@@ -30,9 +30,17 @@ config STM32MP1_DDR_INTERACTIVE_FORCE
|
|
useful when SPL is loaded in sysram
|
|
directly by programmer
|
|
|
|
+config STM32MP1_DDR_TESTS
|
|
+ bool "STM32MP1 DDR driver : tests support"
|
|
+ depends on STM32MP1_DDR_INTERACTIVE
|
|
+ default y
|
|
+ help
|
|
+ activate test support for interactive support in
|
|
+ STM32MP1 DDR controller driver: command test
|
|
+
|
|
config STM32MP1_DDR_TUNING
|
|
bool "STM32MP1 DDR driver : support of tuning"
|
|
- depends on SPL && STM32MP1_DDR_INTERACTIVE
|
|
+ depends on STM32MP1_DDR_INTERACTIVE
|
|
default y
|
|
help
|
|
activate tuning command in STM32MP1 DDR interactive mode
|
|
diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile
|
|
index bc292d1..e1e9135 100644
|
|
--- a/drivers/ram/stm32mp1/Makefile
|
|
+++ b/drivers/ram/stm32mp1/Makefile
|
|
@@ -6,7 +6,8 @@
|
|
obj-y += stm32mp1_ram.o
|
|
obj-y += stm32mp1_ddr.o
|
|
|
|
-obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o stm32mp1_tests.o
|
|
+obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o
|
|
+obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o
|
|
obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o
|
|
|
|
ifneq ($(DDR_INTERACTIVE),)
|
|
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
index a83ea39..f6484da 100644
|
|
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
|
|
@@ -41,8 +41,32 @@ struct reg_desc {
|
|
offsetof(struct stm32mp1_ddrphy, x),\
|
|
offsetof(struct y, x)}
|
|
|
|
+#define DDR_REG_DYN(x) \
|
|
+ {#x,\
|
|
+ offsetof(struct stm32mp1_ddrctl, x),\
|
|
+ INVALID_OFFSET}
|
|
+
|
|
+#define DDRPHY_REG_DYN(x) \
|
|
+ {#x,\
|
|
+ offsetof(struct stm32mp1_ddrphy, x),\
|
|
+ INVALID_OFFSET}
|
|
+
|
|
+/***********************************************************
|
|
+ * PARAMETERS: value get from device tree :
|
|
+ * size / order need to be aligned with binding
|
|
+ * modification NOT ALLOWED !!!
|
|
+ ***********************************************************/
|
|
+#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
|
|
+#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
|
|
+#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
|
|
+#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
|
|
+
|
|
+#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
|
|
+#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
|
|
+#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */
|
|
+
|
|
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
|
|
-static const struct reg_desc ddr_reg[] = {
|
|
+static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
|
|
DDRCTL_REG_REG(mstr),
|
|
DDRCTL_REG_REG(mrctrl0),
|
|
DDRCTL_REG_REG(mrctrl1),
|
|
@@ -71,7 +95,7 @@ static const struct reg_desc ddr_reg[] = {
|
|
};
|
|
|
|
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
|
|
-static const struct reg_desc ddr_timing[] = {
|
|
+static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
|
|
DDRCTL_REG_TIMING(rfshtmg),
|
|
DDRCTL_REG_TIMING(dramtmg0),
|
|
DDRCTL_REG_TIMING(dramtmg1),
|
|
@@ -87,7 +111,7 @@ static const struct reg_desc ddr_timing[] = {
|
|
};
|
|
|
|
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
|
|
-static const struct reg_desc ddr_map[] = {
|
|
+static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
|
|
DDRCTL_REG_MAP(addrmap1),
|
|
DDRCTL_REG_MAP(addrmap2),
|
|
DDRCTL_REG_MAP(addrmap3),
|
|
@@ -100,7 +124,7 @@ static const struct reg_desc ddr_map[] = {
|
|
};
|
|
|
|
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
|
|
-static const struct reg_desc ddr_perf[] = {
|
|
+static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
|
|
DDRCTL_REG_PERF(sched),
|
|
DDRCTL_REG_PERF(sched1),
|
|
DDRCTL_REG_PERF(perfhpr1),
|
|
@@ -121,7 +145,7 @@ static const struct reg_desc ddr_perf[] = {
|
|
};
|
|
|
|
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
|
|
-static const struct reg_desc ddrphy_reg[] = {
|
|
+static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
|
|
DDRPHY_REG_REG(pgcr),
|
|
DDRPHY_REG_REG(aciocr),
|
|
DDRPHY_REG_REG(dxccr),
|
|
@@ -136,7 +160,7 @@ static const struct reg_desc ddrphy_reg[] = {
|
|
};
|
|
|
|
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
|
|
-static const struct reg_desc ddrphy_timing[] = {
|
|
+static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
|
|
DDRPHY_REG_TIMING(ptr0),
|
|
DDRPHY_REG_TIMING(ptr1),
|
|
DDRPHY_REG_TIMING(ptr2),
|
|
@@ -150,7 +174,7 @@ static const struct reg_desc ddrphy_timing[] = {
|
|
};
|
|
|
|
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
|
|
-static const struct reg_desc ddrphy_cal[] = {
|
|
+static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = {
|
|
DDRPHY_REG_CAL(dx0dllcr),
|
|
DDRPHY_REG_CAL(dx0dqtr),
|
|
DDRPHY_REG_CAL(dx0dqstr),
|
|
@@ -165,11 +189,10 @@ static const struct reg_desc ddrphy_cal[] = {
|
|
DDRPHY_REG_CAL(dx3dqstr),
|
|
};
|
|
|
|
-#define DDR_REG_DYN(x) \
|
|
- {#x,\
|
|
- offsetof(struct stm32mp1_ddrctl, x),\
|
|
- INVALID_OFFSET}
|
|
-
|
|
+/**************************************************************
|
|
+ * DYNAMIC REGISTERS: only used for debug purpose (read/modify)
|
|
+ **************************************************************/
|
|
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
|
|
static const struct reg_desc ddr_dyn[] = {
|
|
DDR_REG_DYN(stat),
|
|
DDR_REG_DYN(init0),
|
|
@@ -181,16 +204,30 @@ static const struct reg_desc ddr_dyn[] = {
|
|
DDR_REG_DYN(pctrl_1),
|
|
};
|
|
|
|
-#define DDRPHY_REG_DYN(x) \
|
|
- {#x,\
|
|
- offsetof(struct stm32mp1_ddrphy, x),\
|
|
- INVALID_OFFSET}
|
|
+#define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn)
|
|
|
|
static const struct reg_desc ddrphy_dyn[] = {
|
|
DDRPHY_REG_DYN(pir),
|
|
DDRPHY_REG_DYN(pgsr),
|
|
+ DDRPHY_REG_DYN(zq0sr0),
|
|
+ DDRPHY_REG_DYN(zq0sr1),
|
|
+ DDRPHY_REG_DYN(dx0gsr0),
|
|
+ DDRPHY_REG_DYN(dx0gsr1),
|
|
+ DDRPHY_REG_DYN(dx1gsr0),
|
|
+ DDRPHY_REG_DYN(dx1gsr1),
|
|
+ DDRPHY_REG_DYN(dx2gsr0),
|
|
+ DDRPHY_REG_DYN(dx2gsr1),
|
|
+ DDRPHY_REG_DYN(dx3gsr0),
|
|
+ DDRPHY_REG_DYN(dx3gsr1),
|
|
};
|
|
|
|
+#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn)
|
|
+
|
|
+#endif
|
|
+
|
|
+/*****************************************************************
|
|
+ * REGISTERS ARRAY: used to parse device tree and interactive mode
|
|
+ *****************************************************************/
|
|
enum reg_type {
|
|
REG_REG,
|
|
REG_TIMING,
|
|
@@ -199,11 +236,13 @@ enum reg_type {
|
|
REGPHY_REG,
|
|
REGPHY_TIMING,
|
|
REGPHY_CAL,
|
|
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
|
|
/* dynamic registers => managed in driver or not changed,
|
|
* can be dumped in interactive mode
|
|
*/
|
|
REG_DYN,
|
|
REGPHY_DYN,
|
|
+#endif
|
|
REG_TYPE_NB
|
|
};
|
|
|
|
@@ -224,23 +263,25 @@ struct ddr_reg_info {
|
|
|
|
const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
|
|
[REG_REG] = {
|
|
- "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE},
|
|
+ "static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE},
|
|
[REG_TIMING] = {
|
|
- "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE},
|
|
+ "timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE},
|
|
[REG_PERF] = {
|
|
- "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE},
|
|
+ "perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE},
|
|
[REG_MAP] = {
|
|
- "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE},
|
|
+ "map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE},
|
|
[REGPHY_REG] = {
|
|
- "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE},
|
|
+ "static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE},
|
|
[REGPHY_TIMING] = {
|
|
- "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE},
|
|
+ "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE},
|
|
[REGPHY_CAL] = {
|
|
- "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE},
|
|
+ "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE},
|
|
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
|
|
[REG_DYN] = {
|
|
- "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE},
|
|
+ "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE},
|
|
[REGPHY_DYN] = {
|
|
- "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE},
|
|
+ "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE},
|
|
+#endif
|
|
};
|
|
|
|
const char *base_name[] = {
|
|
@@ -281,37 +322,6 @@ static void set_reg(const struct ddr_info *priv,
|
|
}
|
|
}
|
|
|
|
-static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
|
|
-{
|
|
- u32 pgsr;
|
|
- int ret;
|
|
-
|
|
- ret = readl_poll_timeout(&phy->pgsr, pgsr,
|
|
- pgsr & (DDRPHYC_PGSR_IDONE |
|
|
- DDRPHYC_PGSR_DTERR |
|
|
- DDRPHYC_PGSR_DTIERR |
|
|
- DDRPHYC_PGSR_DFTERR |
|
|
- DDRPHYC_PGSR_RVERR |
|
|
- DDRPHYC_PGSR_RVEIRR),
|
|
- 1000000);
|
|
- debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n",
|
|
- (u32)&phy->pgsr, pgsr, ret);
|
|
-}
|
|
-
|
|
-void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
|
|
-{
|
|
- pir |= DDRPHYC_PIR_INIT;
|
|
- writel(pir, &phy->pir);
|
|
- debug("[0x%08x] pir = 0x%08x -> 0x%08x\n",
|
|
- (u32)&phy->pir, pir, readl(&phy->pir));
|
|
-
|
|
- /* need to wait 10 configuration clock before start polling */
|
|
- udelay(10);
|
|
-
|
|
- /* Wait DRAM initialization and Gate Training Evaluation complete */
|
|
- ddrphy_idone_wait(phy);
|
|
-}
|
|
-
|
|
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
|
|
static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc)
|
|
{
|
|
@@ -410,7 +420,7 @@ void stm32mp1_edit_reg(const struct ddr_info *priv,
|
|
printf("%s not found\n", name);
|
|
return;
|
|
}
|
|
- if (strict_strtoul(string, 16, &value) < 0) {
|
|
+ if (strict_strtoul(string, 16, &value) < 0) {
|
|
printf("invalid value %s\n", string);
|
|
return;
|
|
}
|
|
@@ -605,7 +615,7 @@ static void wait_operating_mode(struct ddr_info *priv, int mode)
|
|
}
|
|
|
|
/* Mode Register Writes (MRW or MRS) */
|
|
-void mode_register_write(struct ddr_info *priv, u8 addr, u16 data)
|
|
+static void mode_register_write(struct ddr_info *priv, u8 addr, u16 data)
|
|
{
|
|
u32 mrctrl0;
|
|
|
|
@@ -780,6 +790,37 @@ static void ddr3_dll_off(struct ddr_info *priv)
|
|
debug("%s: exit\n", __func__);
|
|
}
|
|
|
|
+static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
|
|
+{
|
|
+ u32 pgsr;
|
|
+ int ret;
|
|
+
|
|
+ ret = readl_poll_timeout(&phy->pgsr, pgsr,
|
|
+ pgsr & (DDRPHYC_PGSR_IDONE |
|
|
+ DDRPHYC_PGSR_DTERR |
|
|
+ DDRPHYC_PGSR_DTIERR |
|
|
+ DDRPHYC_PGSR_DFTERR |
|
|
+ DDRPHYC_PGSR_RVERR |
|
|
+ DDRPHYC_PGSR_RVEIRR),
|
|
+ 1000000);
|
|
+ debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n",
|
|
+ (u32)&phy->pgsr, pgsr, ret);
|
|
+}
|
|
+
|
|
+void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
|
|
+{
|
|
+ pir |= DDRPHYC_PIR_INIT;
|
|
+ writel(pir, &phy->pir);
|
|
+ debug("[0x%08x] pir = 0x%08x -> 0x%08x\n",
|
|
+ (u32)&phy->pir, pir, readl(&phy->pir));
|
|
+
|
|
+ /* need to wait 10 configuration clock before start polling */
|
|
+ udelay(10);
|
|
+
|
|
+ /* Wait DRAM initialization and Gate Training Evaluation complete */
|
|
+ ddrphy_idone_wait(phy);
|
|
+}
|
|
+
|
|
void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
|
|
{
|
|
start_sw_done(ctl);
|
|
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
|
|
index 90b4a4b..52b748f 100644
|
|
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
|
|
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
|
|
@@ -26,7 +26,6 @@ struct stm32mp1_ddrphy;
|
|
* @ctl: DDR controleur base address
|
|
* @clk: DDR clock
|
|
* @phy: DDR PHY base address
|
|
- * @pwr: pwr base address
|
|
* @rcc: rcc base address
|
|
*/
|
|
struct ddr_info {
|
|
@@ -35,7 +34,6 @@ struct ddr_info {
|
|
struct clk clk;
|
|
struct stm32mp1_ddrctl *ctl;
|
|
struct stm32mp1_ddrphy *phy;
|
|
- void *pwr;
|
|
u32 rcc;
|
|
};
|
|
|
|
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
index 3840af5..8df6a39 100644
|
|
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
/*
|
|
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <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, ®->grstctl);
|
|
uint32_t dflt_gusbcfg;
|
|
uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
|
|
+ u32 max_hw_ep;
|
|
+ int pdata_hw_ep;
|
|
|
|
debug("Reseting OTG controller\n");
|
|
|
|
@@ -486,10 +488,22 @@ static void reconfig_usbd(struct dwc2_udc *dev)
|
|
writel((np_tx_fifo_sz << 16) | rx_fifo_sz,
|
|
®->gnptxfsiz);
|
|
|
|
- for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++)
|
|
+ /* retrieve the number of TX fifo */
|
|
+ max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >>
|
|
+ GHWCFG4_NUM_IN_EPS_SHIFT;
|
|
+ pdata_hw_ep = dev->pdata->tx_fifo_sz_array[DWC2_SIZE_NB_OFFS];
|
|
+
|
|
+ if (pdata_hw_ep && max_hw_ep != pdata_hw_ep)
|
|
+ pr_err("Got %d hw endpoint and %d tx-fifo-size in array !!\n",
|
|
+ max_hw_ep, pdata_hw_ep);
|
|
+
|
|
+ for (i = 1; i <= max_hw_ep; i++) {
|
|
+ if (pdata_hw_ep)
|
|
+ tx_fifo_sz = dev->pdata->tx_fifo_sz_array[(i - 1) +
|
|
+ DWC2_SIZE_OFFS];
|
|
writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) |
|
|
tx_fifo_sz << 16, ®->dieptxf[i-1]);
|
|
-
|
|
+ }
|
|
/* Flush the RX FIFO */
|
|
writel(RX_FIFO_FLUSH, ®->grstctl);
|
|
while (readl(®->grstctl) & RX_FIFO_FLUSH)
|
|
diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h
|
|
index b64e222..a092f43 100644
|
|
--- a/drivers/usb/gadget/dwc2_udc_otg_priv.h
|
|
+++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h
|
|
@@ -24,7 +24,6 @@
|
|
#define EP_FIFO_SIZE2 1024
|
|
/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */
|
|
#define DWC2_MAX_ENDPOINTS 4
|
|
-#define DWC2_MAX_HW_ENDPOINTS 16
|
|
|
|
#define WAIT_FOR_SETUP 0
|
|
#define DATA_STATE_XMIT 1
|
|
diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
|
|
index a1829b3..449b208 100644
|
|
--- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
|
|
+++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
|
|
@@ -60,22 +60,24 @@ struct dwc2_usbotg_reg {
|
|
u32 grxstsp; /* Receive Status Debug Pop/Status Pop */
|
|
u32 grxfsiz; /* Receive FIFO Size */
|
|
u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
|
|
- u8 res1[216];
|
|
+ u8 res1[36];
|
|
+ u32 ghwcfg4; /* User HW Config4 */
|
|
+ u8 res2[176];
|
|
u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
|
|
- u8 res2[1728];
|
|
+ u8 res3[1728];
|
|
/* Device Configuration */
|
|
u32 dcfg; /* Device Configuration Register */
|
|
u32 dctl; /* Device Control */
|
|
u32 dsts; /* Device Status */
|
|
- u8 res3[4];
|
|
+ u8 res4[4];
|
|
u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
|
|
u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
|
|
u32 daint; /* Device All Endpoints Interrupt */
|
|
u32 daintmsk; /* Device All Endpoints Interrupt Mask */
|
|
- u8 res4[224];
|
|
+ u8 res5[224];
|
|
struct dwc2_dev_in_endp in_endp[16];
|
|
struct dwc2_dev_out_endp out_endp[16];
|
|
- u8 res5[768];
|
|
+ u8 res6[768];
|
|
struct ep_fifo ep[16];
|
|
};
|
|
|
|
@@ -86,6 +88,9 @@ struct dwc2_usbotg_reg {
|
|
#define B_SESSION_VALID (0x1<<19)
|
|
#define A_SESSION_VALID (0x1<<18)
|
|
|
|
+/* DWC2_UDC_OTG_GOTINT */
|
|
+#define GOTGINT_SES_END_DET (1<<2)
|
|
+
|
|
/* DWC2_UDC_OTG_GAHBCFG */
|
|
#define PTXFE_HALF (0<<8)
|
|
#define PTXFE_ZERO (1<<8)
|
|
@@ -118,6 +123,7 @@ struct dwc2_usbotg_reg {
|
|
#define INT_NP_TX_FIFO_EMPTY (0x1<<5)
|
|
#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
|
|
#define INT_SOF (0x1<<3)
|
|
+#define INT_OTG (0x1<<2)
|
|
#define INT_DEV_MODE (0x0<<0)
|
|
#define INT_HOST_MODE (0x1<<1)
|
|
#define INT_GOUTNakEff (0x01<<7)
|
|
@@ -246,7 +252,7 @@ struct dwc2_usbotg_reg {
|
|
|
|
/* Masks definitions */
|
|
#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
|
|
- | INT_RESET | INT_SUSPEND)
|
|
+ | INT_RESET | INT_SUSPEND | INT_OTG)
|
|
#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
|
|
#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
|
|
#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
|
|
@@ -269,4 +275,9 @@ struct dwc2_usbotg_reg {
|
|
/* Device ALL Endpoints Interrupt Register (DAINT) */
|
|
#define DAINT_IN_EP_INT(x) (x << 0)
|
|
#define DAINT_OUT_EP_INT(x) (x << 16)
|
|
+
|
|
+/* User HW Config4 */
|
|
+#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
|
|
+#define GHWCFG4_NUM_IN_EPS_SHIFT 26
|
|
+
|
|
#endif
|
|
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
|
|
index a75af49..7eb632d 100644
|
|
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
|
|
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
|
|
@@ -467,7 +467,7 @@ static void process_ep_out_intr(struct dwc2_udc *dev)
|
|
static int dwc2_udc_irq(int irq, void *_dev)
|
|
{
|
|
struct dwc2_udc *dev = _dev;
|
|
- u32 intr_status;
|
|
+ u32 intr_status, gotgint;
|
|
u32 usb_status, gintmsk;
|
|
unsigned long flags = 0;
|
|
|
|
@@ -521,14 +521,24 @@ static int dwc2_udc_irq(int irq, void *_dev)
|
|
&& dev->driver) {
|
|
if (dev->driver->suspend)
|
|
dev->driver->suspend(&dev->gadget);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (intr_status & INT_OTG) {
|
|
+ gotgint = readl(®->gotgint);
|
|
+ debug_cond(DEBUG_ISR,
|
|
+ "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint);
|
|
|
|
- /* HACK to let gadget detect disconnected state */
|
|
+ if (gotgint & GOTGINT_SES_END_DET) {
|
|
+ debug_cond(DEBUG_ISR, "\t\tSession End Detected\n");
|
|
+ /* Let gadget detect disconnected state */
|
|
if (dev->driver->disconnect) {
|
|
spin_unlock_irqrestore(&dev->lock, flags);
|
|
dev->driver->disconnect(&dev->gadget);
|
|
spin_lock_irqsave(&dev->lock, flags);
|
|
}
|
|
}
|
|
+ writel(gotgint, ®->gotgint);
|
|
}
|
|
|
|
if (intr_status & INT_RESUME) {
|
|
diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c
|
|
index ad1d6f0..41c4bef 100644
|
|
--- a/drivers/video/orisetech_otm8009a.c
|
|
+++ b/drivers/video/orisetech_otm8009a.c
|
|
@@ -302,10 +302,13 @@ static int otm8009a_panel_probe(struct udevice *dev)
|
|
int ret;
|
|
|
|
if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
|
|
- dev_err(dev, "enable regulator '%s'\n", priv->reg->name);
|
|
+ dev_dbg(dev, "enable regulator '%s'\n", priv->reg->name);
|
|
ret = regulator_set_enable(priv->reg, true);
|
|
- if (ret)
|
|
+ if (ret) {
|
|
+ dev_err(dev, "Regulator : '%s' - can't enable\n",
|
|
+ priv->reg->name);
|
|
return ret;
|
|
+ }
|
|
}
|
|
|
|
/* reset panel */
|
|
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
|
|
index 5fe49a5..367d811 100644
|
|
--- a/drivers/video/video-uclass.c
|
|
+++ b/drivers/video/video-uclass.c
|
|
@@ -277,7 +277,9 @@ static int video_post_bind(struct udevice *dev)
|
|
return 0;
|
|
size = alloc_fb(dev, &addr);
|
|
if (addr < gd->video_bottom) {
|
|
- /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */
|
|
+ /* Device tree node may need the 'u-boot,dm-pre-reloc' or
|
|
+ * 'u-boot,dm-pre-proper' tag
|
|
+ */
|
|
printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
|
|
dev->name);
|
|
return -ENOSPC;
|
|
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
|
|
index 705fc7d..5bae563 100644
|
|
--- a/drivers/watchdog/Kconfig
|
|
+++ b/drivers/watchdog/Kconfig
|
|
@@ -20,6 +20,13 @@ config BCM2835_WDT
|
|
This provides basic infrastructure to support BCM2835/2836 watchdog
|
|
hardware, with a max timeout of ~15secs.
|
|
|
|
+config IMX_WATCHDOG
|
|
+ bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
|
|
+ select HW_WATCHDOG
|
|
+ help
|
|
+ Select this to enable the IMX and LSCH2 of Layerscape watchdog
|
|
+ driver.
|
|
+
|
|
config OMAP_WATCHDOG
|
|
bool "TI OMAP watchdog driver"
|
|
depends on ARCH_OMAP2PLUS
|
|
@@ -52,14 +59,6 @@ config WDT
|
|
What exactly happens when the timer expires is up to a particular
|
|
device/driver.
|
|
|
|
-config WDT_SANDBOX
|
|
- bool "Enable Watchdog Timer support for Sandbox"
|
|
- depends on SANDBOX && WDT
|
|
- help
|
|
- Enable Watchdog Timer support in Sandbox. This is a dummy device that
|
|
- can be probed and supports all of the methods of WDT, but does not
|
|
- really do anything.
|
|
-
|
|
config WDT_ARMADA_37XX
|
|
bool "Marvell Armada 37xx watchdog timer support"
|
|
depends on WDT && ARMADA_3700
|
|
@@ -88,13 +87,6 @@ config WDT_BCM6345
|
|
The watchdog timer is stopped when initialized.
|
|
It performs full SoC reset.
|
|
|
|
-config WDT_ORION
|
|
- bool "Orion watchdog timer support"
|
|
- depends on WDT
|
|
- help
|
|
- Select this to enable Orion watchdog timer, which can be found on some
|
|
- Marvell Armada chips.
|
|
-
|
|
config WDT_CDNS
|
|
bool "Cadence watchdog timer support"
|
|
depends on WDT
|
|
@@ -103,20 +95,28 @@ config WDT_CDNS
|
|
Select this to enable Cadence watchdog timer, which can be found on some
|
|
Xilinx Microzed Platform.
|
|
|
|
-config STM32MP_WATCHDOG
|
|
- bool "Enable IWDG watchdog driver for STM32 MP's family"
|
|
- depends on ARCH_STM32MP
|
|
- select HW_WATCHDOG
|
|
+config WDT_ORION
|
|
+ bool "Orion watchdog timer support"
|
|
+ depends on WDT
|
|
help
|
|
- Enable the STM32 watchdog (IWDG) driver. Enable support to
|
|
- configure STM32's on-SoC watchdog.
|
|
+ Select this to enable Orion watchdog timer, which can be found on some
|
|
+ Marvell Armada chips.
|
|
+
|
|
+config WDT_SANDBOX
|
|
+ bool "Enable Watchdog Timer support for Sandbox"
|
|
+ depends on SANDBOX && WDT
|
|
+ help
|
|
+ Enable Watchdog Timer support in Sandbox. This is a dummy device that
|
|
+ can be probed and supports all of the methods of WDT, but does not
|
|
+ really do anything.
|
|
|
|
-config STM32MP_WATCHDOG_TIMEOUT_SECS
|
|
- int "IWDG watchdog timeout"
|
|
- depends on STM32MP_WATCHDOG
|
|
- default 32
|
|
+config WDT_STM32MP
|
|
+ bool "IWDG watchdog driver for STM32 MP's family"
|
|
+ depends on WDT
|
|
+ imply WATCHDOG
|
|
help
|
|
- Configure the timeout for IWDG (default: 32s).
|
|
+ Enable the STM32 watchdog (IWDG) driver. Enable support to
|
|
+ configure STM32's on-SoC watchdog.
|
|
|
|
config XILINX_TB_WATCHDOG
|
|
bool "Xilinx Axi watchdog timer support"
|
|
@@ -126,11 +126,4 @@ config XILINX_TB_WATCHDOG
|
|
Select this to enable Xilinx Axi watchdog timer, which can be found on some
|
|
Xilinx Microblaze Platforms.
|
|
|
|
-config IMX_WATCHDOG
|
|
- bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
|
|
- select HW_WATCHDOG
|
|
- help
|
|
- Select this to enable the IMX and LSCH2 of Layerscape watchdog
|
|
- driver.
|
|
-
|
|
endmenu
|
|
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
|
|
index 25491cf..6374b5b 100644
|
|
--- a/drivers/watchdog/Makefile
|
|
+++ b/drivers/watchdog/Makefile
|
|
@@ -23,4 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
|
|
obj-$(CONFIG_WDT_ORION) += orion_wdt.o
|
|
obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
|
|
obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o
|
|
-obj-$(CONFIG_STM32MP_WATCHDOG) += stm32mp_wdt.o
|
|
\ No newline at end of file
|
|
+obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
|
diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c
|
|
index 696be1b..ea85e41 100644
|
|
--- a/drivers/watchdog/stm32mp_wdt.c
|
|
+++ b/drivers/watchdog/stm32mp_wdt.c
|
|
@@ -1,16 +1,15 @@
|
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
/*
|
|
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <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
|
|
|