meta-st-stm32mp/recipes-bsp/u-boot/u-boot-stm32mp/0003-ARM-v2020.01-stm32mp-r...

9970 lines
304 KiB
Diff

From b3ad756bcf4959e8ec4c2cfdcd8d0eeeca12a845 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 5 Jun 2020 13:45:13 +0200
Subject: [PATCH 3/5] ARM v2020.01-stm32mp-r1 MISC-DRIVERS
---
cmd/Kconfig | 1 +
cmd/dtimg.c | 50 ++-
cmd/mtd.c | 24 +-
cmd/nvedit.c | 39 ++-
common/board_f.c | 27 +-
common/cli_readline.c | 6 +
common/image-android-dt.c | 42 +++
configs/igep00x0_defconfig | 1 +
configs/mt8518_ap1_emmc_defconfig | 2 +
configs/odroid-xu3_defconfig | 1 +
configs/odroid_defconfig | 1 +
configs/sandbox64_defconfig | 1 +
configs/sandbox_defconfig | 1 +
configs/sandbox_flattree_defconfig | 1 +
configs/sandbox_spl_defconfig | 1 +
doc/README.gpio | 42 +++
doc/android/fastboot.txt | 3 +
doc/device-tree-bindings/clock/st,stm32-rcc.txt | 37 ++
doc/device-tree-bindings/clock/st,stm32mp1.txt | 36 +-
doc/device-tree-bindings/gpio/gpio.txt | 304 ++++++++++-------
doc/device-tree-bindings/i2c/i2c-stm32.txt | 105 +++++-
.../memory-controllers/st,stm32mp1-ddr.txt | 2 +
doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt | 6 +-
doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt | 55 ++-
drivers/ata/dwc_ahci.c | 4 +-
drivers/clk/Kconfig | 8 +
drivers/clk/Makefile | 1 +
drivers/clk/clk_scmi.c | 152 +++++++++
drivers/clk/clk_stm32mp1.c | 378 +++++++++++++++++----
drivers/core/of_access.c | 32 ++
drivers/core/ofnode.c | 48 +++
drivers/core/read.c | 16 +
drivers/core/root.c | 52 +--
drivers/dfu/Kconfig | 5 +
drivers/fastboot/Kconfig | 68 ++++
drivers/fastboot/fb_command.c | 72 ++++
drivers/fastboot/fb_mmc.c | 118 +++++++
drivers/gpio/gpio-uclass.c | 203 ++++++++---
drivers/gpio/mpc8xxx_gpio.c | 22 --
drivers/gpio/sandbox.c | 321 ++++++++++++++---
drivers/gpio/stm32_gpio.c | 152 ++++++++-
drivers/i2c/stm32f7_i2c.c | 128 +++----
drivers/mailbox/Kconfig | 7 +
drivers/mailbox/Makefile | 1 +
drivers/mailbox/arm-smc-mbox.c | 118 +++++++
drivers/misc/Kconfig | 12 +
drivers/misc/Makefile | 1 +
drivers/misc/scmi_agent.c | 337 ++++++++++++++++++
drivers/mmc/stm32_sdmmc2.c | 2 +-
drivers/mtd/Kconfig | 7 +
drivers/net/dwc_eth_qos.c | 73 +++-
drivers/phy/phy-stm32-usbphyc.c | 2 +-
drivers/phy/phy-uclass.c | 40 ++-
drivers/pinctrl/pinctrl-generic.c | 30 +-
drivers/pinctrl/pinctrl-sandbox.c | 44 ++-
drivers/pinctrl/pinctrl-single.c | 27 +-
drivers/pinctrl/pinctrl-stmfx.c | 232 +++++++++----
drivers/pinctrl/pinctrl_stm32.c | 27 +-
drivers/power/regulator/stm32-vrefbuf.c | 16 +-
drivers/ram/stm32mp1/stm32mp1_ddr.c | 54 ++-
drivers/ram/stm32mp1/stm32mp1_ddr.h | 1 +
drivers/ram/stm32mp1/stm32mp1_ddr_regs.h | 1 +
drivers/ram/stm32mp1/stm32mp1_interactive.c | 17 +-
drivers/ram/stm32mp1/stm32mp1_ram.c | 34 +-
drivers/ram/stm32mp1/stm32mp1_tests.c | 31 +-
drivers/ram/stm32mp1/stm32mp1_tuning.c | 223 ++++++++++--
drivers/remoteproc/rproc-elf-loader.c | 269 +++++++++++++++
drivers/remoteproc/stm32_copro.c | 61 +++-
drivers/reset/Kconfig | 8 +
drivers/reset/Makefile | 1 +
drivers/reset/reset-scmi.c | 86 +++++
drivers/tee/optee/core.c | 13 +-
drivers/usb/dwc3/core.c | 12 +-
drivers/usb/gadget/dwc2_udc_otg.c | 6 +-
drivers/usb/gadget/g_dnl.c | 8 +
drivers/usb/host/dwc2.c | 118 ++++++-
drivers/usb/host/ehci-hcd.c | 8 +-
drivers/usb/host/ohci-generic.c | 8 +-
drivers/usb/musb-new/sunxi.c | 8 +-
drivers/video/orisetech_otm8009a.c | 20 +-
drivers/video/raydium-rm68200.c | 20 +-
drivers/video/stm32/stm32_dsi.c | 15 +-
env/mmc.c | 26 +-
include/asm-generic/gpio.h | 102 +++---
include/clk.h | 104 +++++-
include/configs/odroid.h | 1 -
include/configs/odroid_xu3.h | 1 -
include/configs/omap3_igep00x0.h | 2 -
include/configs/stm32f429-evaluation.h | 15 +-
include/configs/stm32f469-discovery.h | 15 +-
include/configs/stm32f746-disco.h | 15 +-
include/configs/stm32h743-disco.h | 14 +-
include/configs/stm32h743-eval.h | 14 +-
include/configs/stm32mp1.h | 208 +++++++-----
include/dfu.h | 3 +
include/dm/of_access.h | 40 +++
include/dm/ofnode.h | 63 +++-
include/dm/read.h | 67 ++++
include/dt-bindings/clock/stm32mp1-clks.h | 33 ++
include/dt-bindings/gpio/gpio.h | 6 +
include/dt-bindings/gpio/sandbox-gpio.h | 24 ++
include/dt-bindings/mfd/stm32h7-rcc.h | 1 -
include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 +
include/dt-bindings/reset/stm32mp1-resets.h | 13 +
include/dt-bindings/rtc/rtc-stm32.h | 13 +
include/dt-bindings/soc/stm32-hdp.h | 108 ++++++
include/env_internal.h | 31 ++
include/fastboot.h | 6 +
include/g_dnl.h | 1 +
include/i2c.h | 26 ++
include/image-android-dt.h | 2 +
include/mipi_dsi.h | 6 +
include/mtd.h | 2 +
include/power/stpmic1.h | 1 +
include/remoteproc.h | 70 ++++
include/scmi_agent.h | 82 +++++
lib/libfdt/fdt_ro.c | 20 +-
lib/optee/optee.c | 2 +-
scripts/config_whitelist.txt | 2 -
scripts/dtc/libfdt/fdt_ro.c | 20 +-
scripts/dtc/libfdt/libfdt.h | 33 +-
test/dm/Makefile | 1 +
test/dm/gpio.c | 69 +++-
test/dm/ofread.c | 50 +++
test/dm/remoteproc.c | 91 ++++-
test/dm/test-fdt.c | 4 +-
test/py/tests/test_env.py | 44 +++
test/py/tests/test_pinmux.py | 38 ++-
tools/fdtgrep.c | 6 +-
tools/stm32image.c | 5 +-
130 files changed, 5029 insertions(+), 1038 deletions(-)
create mode 100644 doc/README.gpio
create mode 100644 drivers/clk/clk_scmi.c
create mode 100644 drivers/mailbox/arm-smc-mbox.c
create mode 100644 drivers/misc/scmi_agent.c
create mode 100644 drivers/reset/reset-scmi.c
create mode 100644 include/dt-bindings/gpio/sandbox-gpio.h
create mode 100644 include/dt-bindings/rtc/rtc-stm32.h
create mode 100644 include/dt-bindings/soc/stm32-hdp.h
create mode 100644 include/scmi_agent.h
create mode 100644 test/dm/ofread.c
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 1e4cf14..8a44461 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -551,6 +551,7 @@ config CMD_NVEDIT_INFO
This command can be optionally used for evaluation in scripts:
[-d] : evaluate whether default environment is used
[-p] : evaluate whether environment can be persisted
+ [-q] : quiet output
The result of multiple evaluations will be combined with AND.
endmenu
diff --git a/cmd/dtimg.c b/cmd/dtimg.c
index 6c5d53c..cd221b2 100644
--- a/cmd/dtimg.c
+++ b/cmd/dtimg.c
@@ -99,10 +99,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[])
@@ -138,5 +180,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/mtd.c b/cmd/mtd.c
index 1b6b8dd..a559b5a 100644
--- a/cmd/mtd.c
+++ b/cmd/mtd.c
@@ -387,7 +387,7 @@ static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc,
struct mtd_info *mtd;
u64 off, len;
bool scrub;
- int ret;
+ int ret = 0;
if (argc < 2)
return CMD_RET_USAGE;
@@ -423,22 +423,22 @@ static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc,
erase_op.mtd = mtd;
erase_op.addr = off;
- erase_op.len = len;
+ erase_op.len = mtd->erasesize;
erase_op.scrub = scrub;
- while (erase_op.len) {
+ while (len) {
ret = mtd_erase(mtd, &erase_op);
- /* Abort if its not a bad block error */
- if (ret != -EIO)
- break;
-
- printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
+ if (ret) {
+ /* Abort if its not a bad block error */
+ if (ret != -EIO)
+ break;
+ printf("Skipping bad block at 0x%08llx\n",
+ erase_op.addr);
+ }
- /* Skip bad block and continue behind it */
- erase_op.len -= erase_op.fail_addr - erase_op.addr;
- erase_op.len -= mtd->erasesize;
- erase_op.addr = erase_op.fail_addr + mtd->erasesize;
+ len -= mtd->erasesize;
+ erase_op.addr += mtd->erasesize;
}
if (ret && ret != -EIO)
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index 81d94cd..218fdfb 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -1219,12 +1219,18 @@ static int print_env_info(void)
* env info - display environment information
* env info [-d] - evaluate whether default environment is used
* env info [-p] - evaluate whether environment can be persisted
+ * Add [-q] - quiet mode, use only for command result, for test by example:
+ * test env info -p -d -q
*/
static int do_env_info(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int eval_flags = 0;
int eval_results = 0;
+ bool quiet = false;
+#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE)
+ enum env_location loc;
+#endif
/* display environment information */
if (argc <= 1)
@@ -1242,6 +1248,9 @@ static int do_env_info(cmd_tbl_t *cmdtp, int flag,
case 'p':
eval_flags |= ENV_INFO_IS_PERSISTED;
break;
+ case 'q':
+ quiet = true;
+ break;
default:
return CMD_RET_USAGE;
}
@@ -1251,20 +1260,30 @@ static int do_env_info(cmd_tbl_t *cmdtp, int flag,
/* evaluate whether default environment is used */
if (eval_flags & ENV_INFO_IS_DEFAULT) {
if (gd->flags & GD_FLG_ENV_DEFAULT) {
- printf("Default environment is used\n");
+ if (!quiet)
+ printf("Default environment is used\n");
eval_results |= ENV_INFO_IS_DEFAULT;
} else {
- printf("Environment was loaded from persistent storage\n");
+ if (!quiet)
+ printf("Environment was loaded from persistent storage\n");
}
}
/* evaluate whether environment can be persisted */
if (eval_flags & ENV_INFO_IS_PERSISTED) {
-#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
- printf("Environment can be persisted\n");
- eval_results |= ENV_INFO_IS_PERSISTED;
+#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE)
+ loc = env_get_location(ENVOP_SAVE, gd->env_load_prio);
+ if (ENVL_NOWHERE != loc && ENVL_UNKNOWN != loc) {
+ if (!quiet)
+ printf("Environment can be persisted\n");
+ eval_results |= ENV_INFO_IS_PERSISTED;
+ } else {
+ if (!quiet)
+ printf("Environment cannot be persisted\n");
+ }
#else
- printf("Environment cannot be persisted\n");
+ if (!quiet)
+ printf("Environment cannot be persisted\n");
#endif
}
@@ -1321,7 +1340,7 @@ static cmd_tbl_t cmd_env_sub[] = {
U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""),
#endif
#if defined(CONFIG_CMD_NVEDIT_INFO)
- U_BOOT_CMD_MKENT(info, 2, 0, do_env_info, "", ""),
+ U_BOOT_CMD_MKENT(info, 3, 0, do_env_info, "", ""),
#endif
U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""),
#if defined(CONFIG_CMD_RUN)
@@ -1400,8 +1419,10 @@ static char env_help_text[] =
#endif
#if defined(CONFIG_CMD_NVEDIT_INFO)
"env info - display environment information\n"
- "env info [-d] - whether default environment is used\n"
- "env info [-p] - whether environment can be persisted\n"
+ "env info [-d] [-p] [-q] - evaluate environment information\n"
+ " \"-d\": default environment is used\n"
+ " \"-p\": environment can be persisted\n"
+ " \"-q\": quiet output\n"
#endif
"env print [-a | name ...] - print environment\n"
#if defined(CONFIG_CMD_NVEDIT_EFI)
diff --git a/common/board_f.c b/common/board_f.c
index d66afb3..ef59630 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -470,6 +470,17 @@ static int reserve_uboot(void)
return 0;
}
+/*
+ * reserve after start_addr_sp the requested size and make the stack pointer
+ * 16-byte aligned, this alignment is needed for cast on the reserved memory
+ * ref = x86_64 ABI: https://reviews.llvm.org/D30049: 16 bytes
+ * = ARMv8 Instruction Set Overview: quad word, 16 bytes
+ */
+static unsigned long reserve_stack_aligned(size_t size)
+{
+ return ALIGN_DOWN(gd->start_addr_sp - size, 16);
+}
+
#ifdef CONFIG_SYS_NONCACHED_MEMORY
static int reserve_noncached(void)
{
@@ -495,7 +506,7 @@ static int reserve_noncached(void)
/* reserve memory for malloc() area */
static int reserve_malloc(void)
{
- gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
+ gd->start_addr_sp = reserve_stack_aligned(TOTAL_MALLOC_LEN);
debug("Reserving %dk for malloc() at: %08lx\n",
TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
#ifdef CONFIG_SYS_NONCACHED_MEMORY
@@ -509,7 +520,7 @@ static int reserve_malloc(void)
static int reserve_board(void)
{
if (!gd->bd) {
- gd->start_addr_sp -= sizeof(bd_t);
+ gd->start_addr_sp = reserve_stack_aligned(sizeof(bd_t));
gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
memset(gd->bd, '\0', sizeof(bd_t));
debug("Reserving %zu Bytes for Board Info at: %08lx\n",
@@ -528,7 +539,7 @@ static int setup_machine(void)
static int reserve_global_data(void)
{
- gd->start_addr_sp -= sizeof(gd_t);
+ gd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t));
gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
debug("Reserving %zu Bytes for Global Data at: %08lx\n",
sizeof(gd_t), gd->start_addr_sp);
@@ -546,7 +557,7 @@ static int reserve_fdt(void)
if (gd->fdt_blob) {
gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
- gd->start_addr_sp -= gd->fdt_size;
+ gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size);
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
debug("Reserving %lu Bytes for FDT at: %08lx\n",
gd->fdt_size, gd->start_addr_sp);
@@ -561,7 +572,7 @@ static int reserve_bootstage(void)
#ifdef CONFIG_BOOTSTAGE
int size = bootstage_get_size();
- gd->start_addr_sp -= size;
+ gd->start_addr_sp = reserve_stack_aligned(size);
gd->new_bootstage = map_sysmem(gd->start_addr_sp, size);
debug("Reserving %#x Bytes for bootstage at: %08lx\n", size,
gd->start_addr_sp);
@@ -578,8 +589,7 @@ __weak int arch_reserve_stacks(void)
static int reserve_stacks(void)
{
/* make stack pointer 16-byte aligned */
- gd->start_addr_sp -= 16;
- gd->start_addr_sp &= ~0xf;
+ gd->start_addr_sp = reserve_stack_aligned(16);
/*
* let the architecture-specific code tailor gd->start_addr_sp and
@@ -591,8 +601,7 @@ static int reserve_stacks(void)
static int reserve_bloblist(void)
{
#ifdef CONFIG_BLOBLIST
- gd->start_addr_sp &= ~0xf;
- gd->start_addr_sp -= CONFIG_BLOBLIST_SIZE;
+ gd->start_addr_sp = reserve_stack_aligned(CONFIG_BLOBLIST_SIZE);
gd->new_bloblist = map_sysmem(gd->start_addr_sp, CONFIG_BLOBLIST_SIZE);
#endif
diff --git a/common/cli_readline.c b/common/cli_readline.c
index 6ef7a3e..a0ae778 100644
--- a/common/cli_readline.c
+++ b/common/cli_readline.c
@@ -14,6 +14,12 @@
#include <time.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/image-android-dt.c b/common/image-android-dt.c
index a2d52df..a325e67 100644
--- a/common/image-android-dt.c
+++ b/common/image-android-dt.c
@@ -154,4 +154,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/configs/igep00x0_defconfig b/configs/igep00x0_defconfig
index cb72a01..483f37c 100644
--- a/configs/igep00x0_defconfig
+++ b/configs/igep00x0_defconfig
@@ -52,6 +52,7 @@ CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM_MMC=y
CONFIG_MMC_OMAP_HS=y
CONFIG_MTD=y
+CONFIG_SYS_MTDPARTS_RUNTIME=y
CONFIG_MTD_RAW_NAND=y
CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
CONFIG_SPL_NAND_SIMPLE=y
diff --git a/configs/mt8518_ap1_emmc_defconfig b/configs/mt8518_ap1_emmc_defconfig
index 6d824cc..be5ab64 100644
--- a/configs/mt8518_ap1_emmc_defconfig
+++ b/configs/mt8518_ap1_emmc_defconfig
@@ -16,6 +16,8 @@ CONFIG_DEFAULT_DEVICE_TREE="mt8518-ap1-emmc"
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_CLK=y
+CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
+CONFIG_FASTBOOT_MMC_USER_SUPPORT=y
CONFIG_DM_MMC=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_MTK=y
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig
index 20038d4..ff0bdc3 100644
--- a/configs/odroid-xu3_defconfig
+++ b/configs/odroid-xu3_defconfig
@@ -38,6 +38,7 @@ CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_ADC=y
CONFIG_ADC_EXYNOS=y
CONFIG_DFU_MMC=y
+CONFIG_SET_DFU_ALT_INFO=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_DW=y
CONFIG_MTD=y
diff --git a/configs/odroid_defconfig b/configs/odroid_defconfig
index be914e4..c77541c 100644
--- a/configs/odroid_defconfig
+++ b/configs/odroid_defconfig
@@ -39,6 +39,7 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_DFU_MMC=y
+CONFIG_SET_DFU_ALT_INFO=y
CONFIG_SYS_I2C_S3C24X0=y
CONFIG_MMC_DW=y
CONFIG_MMC_SDHCI=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index cc536ff..f3565a9 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -27,6 +27,7 @@ CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
CONFIG_CMD_ENV_CALLBACK=y
CONFIG_CMD_ENV_FLAGS=y
+CONFIG_CMD_NVEDIT_INFO=y
CONFIG_LOOPW=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 64245f7..8a2d397 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -30,6 +30,7 @@ CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
CONFIG_CMD_ENV_CALLBACK=y
CONFIG_CMD_ENV_FLAGS=y
+CONFIG_CMD_NVEDIT_INFO=y
CONFIG_LOOPW=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index bb31b00..ffd0dfa 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -22,6 +22,7 @@ CONFIG_CMD_BOOTZ=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
+CONFIG_CMD_NVEDIT_INFO=y
CONFIG_LOOPW=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 61a8ffd..ab2c29a 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -33,6 +33,7 @@ CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
CONFIG_CMD_ENV_CALLBACK=y
CONFIG_CMD_ENV_FLAGS=y
+CONFIG_CMD_NVEDIT_INFO=y
CONFIG_LOOPW=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
diff --git a/doc/README.gpio b/doc/README.gpio
new file mode 100644
index 0000000..548ff37
--- /dev/null
+++ b/doc/README.gpio
@@ -0,0 +1,42 @@
+
+GPIO hog (CONFIG_GPIO_HOG)
+--------
+
+All the GPIO hog are initialized in gpio_hog_probe_all() function called in
+board_r.c just before board_late_init() but you can also acces directly to
+the gpio with gpio_hog_lookup_name().
+
+
+Example, for the device tree:
+
+ tca6416@20 {
+ compatible = "ti,tca6416";
+ reg = <0x20>;
+ #gpio-cells = <2>;
+ gpio-controller;
+
+ env_reset {
+ gpio-hog;
+ input;
+ gpios = <6 GPIO_ACTIVE_LOW>;
+ };
+ boot_rescue {
+ gpio-hog;
+ input;
+ line-name = "foo-bar-gpio";
+ gpios = <7 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+You can than access the gpio in your board code with:
+
+ struct gpio_desc *desc;
+ int ret;
+
+ ret = gpio_hog_lookup_name("boot_rescue", &desc);
+ if (ret)
+ return;
+ if (dm_gpio_get_value(desc) == 1)
+ printf("\nBooting into Rescue System\n");
+ else if (dm_gpio_get_value(desc) == 0)
+ printf("\nBoot normal\n");
diff --git a/doc/android/fastboot.txt b/doc/android/fastboot.txt
index 9de1322..e01eec6 100644
--- a/doc/android/fastboot.txt
+++ b/doc/android/fastboot.txt
@@ -23,6 +23,9 @@ The current implementation supports the following standard commands:
The following OEM commands are supported (if enabled):
- oem format - this executes ``gpt write mmc %x $partitions``
+- oem partconf - this executes - ``mmc partconf %x <arg> 0`` to configure eMMC
+ with <arg> = boot_ack boot_partition
+- oem bootbus - this executes - ``mmc bootbus %x %s`` to configure eMMC
Support for both eMMC and NAND devices is included.
diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt
index 0532d81..b240121 100644
--- a/doc/device-tree-bindings/clock/st,stm32-rcc.txt
+++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt
@@ -10,6 +10,7 @@ Required properties:
- compatible: Should be:
"st,stm32f42xx-rcc"
"st,stm32f469-rcc"
+ "st,stm32f746-rcc"
- reg: should be register base and length as documented in the
datasheet
- #reset-cells: 1, see below
@@ -17,6 +18,9 @@ Required properties:
property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to
use.
+- clocks: External oscillator clock phandle
+ - high speed external clock signal (HSE)
+ - external I2S clock (I2S_CKIN)
Example:
@@ -25,6 +29,7 @@ Example:
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
+ clocks = <&clk_hse>, <&clk_i2s_ckin>;
};
Specifying gated clocks
@@ -66,6 +71,38 @@ The secondary index is bound with the following magic numbers:
0 SYSTICK
1 FCLK
+ 2 CLK_LSI (low-power clock source)
+ 3 CLK_LSE (generated from a 32.768 kHz low-speed external
+ crystal or ceramic resonator)
+ 4 CLK_HSE_RTC (HSE division factor for RTC clock)
+ 5 CLK_RTC (real-time clock)
+ 6 PLL_VCO_I2S (vco frequency of I2S pll)
+ 7 PLL_VCO_SAI (vco frequency of SAI pll)
+ 8 CLK_LCD (LCD-TFT)
+ 9 CLK_I2S (I2S clocks)
+ 10 CLK_SAI1 (audio clocks)
+ 11 CLK_SAI2
+ 12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor)
+ 13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor)
+
+ 14 CLK_HSI (Internal ocscillator clock)
+ 15 CLK_SYSCLK (System Clock)
+ 16 CLK_HDMI_CEC (HDMI-CEC clock)
+ 17 CLK_SPDIF (SPDIF-Rx clock)
+ 18 CLK_USART1 (U(s)arts clocks)
+ 19 CLK_USART2
+ 20 CLK_USART3
+ 21 CLK_UART4
+ 22 CLK_UART5
+ 23 CLK_USART6
+ 24 CLK_UART7
+ 25 CLK_UART8
+ 26 CLK_I2C1 (I2S clocks)
+ 27 CLK_I2C2
+ 28 CLK_I2C3
+ 29 CLK_I2C4
+ 30 CLK_LPTIMER (LPTimer1 clock)
+)
Example:
diff --git a/doc/device-tree-bindings/clock/st,stm32mp1.txt b/doc/device-tree-bindings/clock/st,stm32mp1.txt
index ec1d703..4d4136d 100644
--- a/doc/device-tree-bindings/clock/st,stm32mp1.txt
+++ b/doc/device-tree-bindings/clock/st,stm32mp1.txt
@@ -12,6 +12,9 @@ describes the fields added for clock tree initialization which are not present
in Linux binding for compatible "st,stm32mp1-rcc" defined in st,stm32mp1-rcc.txt
file.
+This parent node may optionally have additional children nodes which define
+specific init values for RCC elements.
+
The added properties for clock tree initialization are:
Required properties:
@@ -78,13 +81,20 @@ Required properties:
>;
Optional Properties:
-- st,pll : A specific PLL configuration, including frequency.
+- children for a PLL configuration with "st,stm32mp1-pll" compatible
+
+ each PLL children nodes for PLL1 to PLL4 (see ref manual for details)
+ are listed with associated reg 0 to 3.
+ PLLx is off when the associated node is absent or deactivated.
- PLL children nodes for PLL1 to PLL4 (see ref manual for details)
- are listed with associated index 0 to 3 (st,pll@0 to st,pll@3).
- PLLx is off when the associated node is absent.
+ For PLL1, when the node is absent, the frequency of the OPP node is used
+ to compute the PLL setting (see compatible "operating-points-v2" in
+ opp/opp.txt for details).
Here are the available properties for each PLL node:
+ - compatible: should be "st,stm32mp1-pll"
+
+ - reg: index of the pll instance
- cfg: The parameters for PLL configuration in the following order:
DIVM DIVN DIVP DIVQ DIVR Output.
@@ -118,18 +128,26 @@ Optional Properties:
Example:
st,pll@0 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
cfg = < 1 53 0 0 0 1 >;
frac = < 0x810 >;
};
st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
cfg = < 1 43 1 0 0 PQR(0,1,1) >;
csg = < 10 20 1 >;
};
st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
cfg = < 2 85 3 13 3 0 >;
csg = < 10 20 SSCG_MODE_CENTER_SPREAD >;
};
st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
cfg = < 2 78 4 7 9 3 >;
};
@@ -277,6 +295,8 @@ Example of clock tree initialization
u-boot,dm-pre-reloc;
compatible = "st,stm32mp1-rcc", "syscon";
reg = <0x50000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
#clock-cells = <1>;
#reset-cells = <1>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
@@ -347,6 +367,8 @@ Example of clock tree initialization
/* VCO = 1300.0 MHz => P = 650 (CPU) */
pll1: st,pll@0 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
cfg = < 2 80 0 0 0 PQR(1,0,0) >;
frac = < 0x800 >;
u-boot,dm-pre-reloc;
@@ -355,6 +377,8 @@ Example of clock tree initialization
/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU),
R = 533 (DDR) */
pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
cfg = < 2 65 1 0 0 PQR(1,1,1) >;
frac = < 0x1400 >;
u-boot,dm-pre-reloc;
@@ -362,6 +386,8 @@ Example of clock tree initialization
/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
cfg = < 1 33 1 16 36 PQR(1,1,1) >;
frac = < 0x1a04 >;
u-boot,dm-pre-reloc;
@@ -369,6 +395,8 @@ Example of clock tree initialization
/* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
cfg = < 3 98 5 7 7 PQR(1,1,1) >;
u-boot,dm-pre-reloc;
};
diff --git a/doc/device-tree-bindings/gpio/gpio.txt b/doc/device-tree-bindings/gpio/gpio.txt
index e146917..1481ed6 100644
--- a/doc/device-tree-bindings/gpio/gpio.txt
+++ b/doc/device-tree-bindings/gpio/gpio.txt
@@ -4,19 +4,12 @@ Specifying GPIO information for devices
1) gpios property
-----------------
-Nodes that makes use of GPIOs should specify them using one or more
-properties, each containing a 'gpio-list':
-
- gpio-list ::= <single-gpio> [gpio-list]
- single-gpio ::= <gpio-phandle> <gpio-specifier>
- gpio-phandle : phandle to gpio controller node
- gpio-specifier : Array of #gpio-cells specifying specific gpio
- (controller specific)
-
GPIO properties should be named "[<name>-]gpios", with <name> being the purpose
of this GPIO for the device. While a non-existent <name> is considered valid
for compatibility reasons (resolving to the "gpios" property), it is not allowed
-for new bindings.
+for new bindings. Also, GPIO properties named "[<name>-]gpio" are valid and old
+bindings use it, but are only supported for compatibility reasons and should not
+be used for newer bindings since it has been deprecated.
GPIO properties can contain one or more GPIO phandles, but only in exceptional
cases should they contain more than one. If your device uses several GPIOs with
@@ -31,30 +24,28 @@ The following example could be used to describe GPIO pins used as device enable
and bit-banged data signals:
gpio1: gpio1 {
- gpio-controller
- #gpio-cells = <2>;
- };
- gpio2: gpio2 {
- gpio-controller
- #gpio-cells = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
};
[...]
- enable-gpios = <&gpio2 2>;
data-gpios = <&gpio1 12 0>,
<&gpio1 13 0>,
<&gpio1 14 0>,
<&gpio1 15 0>;
-Note that gpio-specifier length is controller dependent. In the
-above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
-only uses one.
+In the above example, &gpio1 uses 2 cells to specify a gpio. The first cell is
+a local offset to the GPIO line and the second cell represent consumer flags,
+such as if the consumer desire the line to be active low (inverted) or open
+drain. This is the recommended practice.
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
-Exact meaning of each specifier cell is controller specific, and must
-be documented in the device tree binding for the device. Use the macros
-defined in include/dt-bindings/gpio/gpio.h whenever possible:
+The exact meaning of each specifier cell is controller specific, and must be
+documented in the device tree binding for the device, but it is strongly
+recommended to use the two-cell approach.
+
+Most controllers are specifying a generic flag bitfield in the last cell, so
+for these, use the macros defined in
+include/dt-bindings/gpio/gpio.h whenever possible:
Example of a node using GPIOs:
@@ -65,6 +56,30 @@ Example of a node using GPIOs:
GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes
GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+Optional standard bitfield specifiers for the last cell:
+
+- Bit 0: 0 means active high, 1 means active low
+- Bit 1: 0 mean push-pull wiring, see:
+ https://en.wikipedia.org/wiki/Push-pull_output
+ 1 means single-ended wiring, see:
+ https://en.wikipedia.org/wiki/Single-ended_triode
+- Bit 2: 0 means open-source, 1 means open drain, see:
+ https://en.wikipedia.org/wiki/Open_collector
+- Bit 3: 0 means the output should be maintained during sleep/low-power mode
+ 1 means the output state can be lost during sleep/low-power mode
+- Bit 4: 0 means no pull-up resistor should be enabled
+ 1 means a pull-up resistor should be enabled
+ This setting only applies to hardware with a simple on/off
+ control for pull-up configuration. If the hardware has more
+ elaborate pull-up configuration, it should be represented
+ using a pin control binding.
+- Bit 5: 0 means no pull-down resistor should be enabled
+ 1 means a pull-down resistor should be enabled
+ This setting only applies to hardware with a simple on/off
+ control for pull-down configuration. If the hardware has more
+ elaborate pull-down configuration, it should be represented
+ using a pin control binding.
+
1.1) GPIO specifier best practices
----------------------------------
@@ -116,6 +131,80 @@ Every GPIO controller node must contain both an empty "gpio-controller"
property, and a #gpio-cells integer property, which indicates the number of
cells in a gpio-specifier.
+Some system-on-chips (SoCs) use the concept of GPIO banks. A GPIO bank is an
+instance of a hardware IP core on a silicon die, usually exposed to the
+programmer as a coherent range of I/O addresses. Usually each such bank is
+exposed in the device tree as an individual gpio-controller node, reflecting
+the fact that the hardware was synthesized by reusing the same IP block a
+few times over.
+
+Optionally, a GPIO controller may have a "ngpios" property. This property
+indicates the number of in-use slots of available slots for GPIOs. The
+typical example is something like this: the hardware register is 32 bits
+wide, but only 18 of the bits have a physical counterpart. The driver is
+generally written so that all 32 bits can be used, but the IP block is reused
+in a lot of designs, some using all 32 bits, some using 18 and some using
+12. In this case, setting "ngpios = <18>;" informs the driver that only the
+first 18 GPIOs, at local offset 0 .. 17, are in use.
+
+If these GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an
+additional set of tuples is needed to specify which GPIOs are unusable, with
+the gpio-reserved-ranges binding. This property indicates the start and size
+of the GPIOs that can't be used.
+
+Optionally, a GPIO controller may have a "gpio-line-names" property. This is
+an array of strings defining the names of the GPIO lines going out of the
+GPIO controller. This name should be the most meaningful producer name
+for the system, such as a rail name indicating the usage. Package names
+such as pin name are discouraged: such lines have opaque names (since they
+are by definition generic purpose) and such names are usually not very
+helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are
+reasonable line names as they describe what the line is used for. "GPIO0"
+is not a good name to give to a GPIO line. Placeholders are discouraged:
+rather use the "" (blank string) if the use of the GPIO line is undefined
+in your design. The names are assigned starting from line offset 0 from
+left to right from the passed array. An incomplete array (where the number
+of passed named are less than ngpios) will still be used up until the last
+provided valid line index.
+
+Example:
+
+gpio-controller@00000000 {
+ compatible = "foo";
+ reg = <0x00000000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ ngpios = <18>;
+ gpio-reserved-ranges = <0 4>, <12 2>;
+ gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
+ "LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
+ "Row A", "Row B", "Row C", "Row D", "NMI button",
+ "poweroff", "reset";
+}
+
+The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism
+providing automatic GPIO request and configuration as part of the
+gpio-controller's driver probe function.
+
+Each GPIO hog definition is represented as a child node of the GPIO controller.
+Required properties:
+- gpio-hog: A property specifying that this child node represents a GPIO hog.
+- gpios: Store the GPIO information (id, flags, ...) for each GPIO to
+ affect. Shall contain an integer multiple of the number of cells
+ specified in its parent node (GPIO controller node).
+Only one of the following properties scanned in the order shown below.
+This means that when multiple properties are present they will be searched
+in the order presented below and the first match is taken as the intended
+configuration.
+- input: A property specifying to set the GPIO direction as input.
+- output-low A property specifying to set the GPIO direction as output with
+ the value low.
+- output-high A property specifying to set the GPIO direction as output with
+ the value high.
+
+Optional properties:
+- line-name: The GPIO label name. If not present the node name is used.
+
Example of two SOC GPIO banks defined as gpio-controller nodes:
qe_pio_a: gpio-controller@1400 {
@@ -137,46 +226,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
Some or all of the GPIOs provided by a GPIO controller may be routed to pins
on the package via a pin controller. This allows muxing those pins between
-GPIO and other functions.
+GPIO and other functions. It is a fairly common practice among silicon
+engineers.
+
+2.2) Ordinary (numerical) GPIO ranges
+-------------------------------------
It is useful to represent which GPIOs correspond to which pins on which pin
-controllers. The gpio-ranges property described below represents this, and
-contains information structures as follows:
-
- gpio-range-list ::= <single-gpio-range> [gpio-range-list]
- single-gpio-range ::= <numeric-gpio-range> | <named-gpio-range>
- numeric-gpio-range ::=
- <pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
- named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>'
- pinctrl-phandle : phandle to pin controller node
- gpio-base : Base GPIO ID in the GPIO controller
- pinctrl-base : Base pinctrl pin ID in the pin controller
- count : The number of GPIOs/pins in this range
-
-The "pin controller node" mentioned above must conform to the bindings
-described in ../pinctrl/pinctrl-bindings.txt.
-
-In case named gpio ranges are used (ranges with both <pinctrl-base> and
-<count> set to 0), the property gpio-ranges-group-names contains one string
-for every single-gpio-range in gpio-ranges:
- gpiorange-names-list ::= <gpiorange-name> [gpiorange-names-list]
- gpiorange-name : Name of the pingroup associated to the GPIO range in
- the respective pin controller.
-
-Elements of gpiorange-names-list corresponding to numeric ranges contain
-the empty string. Elements of gpiorange-names-list corresponding to named
-ranges contain the name of a pin group defined in the respective pin
-controller. The number of pins/GPIOs in the range is the number of pins in
-that pin group.
+controllers. The gpio-ranges property described below represents this with
+a discrete set of ranges mapping pins from the pin controller local number space
+to pins in the GPIO controller local number space.
-Previous versions of this binding required all pin controller nodes that
-were referenced by any gpio-ranges property to contain a property named
-#gpio-range-cells with value <3>. This requirement is now deprecated.
-However, that property may still exist in older device trees for
-compatibility reasons, and would still be required even in new device
-trees that need to be compatible with older software.
+The format is: <[pin controller phandle], [GPIO controller offset],
+ [pin controller offset], [number of pins]>;
+
+The GPIO controller offset pertains to the GPIO controller node containing the
+range definition.
+
+The pin controller node referenced by the phandle must conform to the bindings
+described in pinctrl/pinctrl-bindings.txt.
+
+Each offset runs from 0 to N. It is perfectly fine to pile any number of
+ranges with just one pin-to-GPIO line mapping if the ranges are concocted, but
+in practice these ranges are often lumped in discrete sets.
+
+Example:
+
+ gpio-ranges = <&foo 0 20 10>, <&bar 10 50 20>;
+
+This means:
+- pins 20..29 on pin controller "foo" is mapped to GPIO line 0..9 and
+- pins 50..69 on pin controller "bar" is mapped to GPIO line 10..29
-Example 1:
+
+Verbose example:
qe_pio_e: gpio-controller@1460 {
#gpio-cells = <2>;
@@ -187,12 +270,33 @@ Example 1:
};
Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
-pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's
-pins 50..59.
+pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's
+pins 50..69.
+
+
+2.3) GPIO ranges from named pin groups
+--------------------------------------
+
+It is also possible to use pin groups for gpio ranges when pin groups are the
+easiest and most convenient mapping.
+
+Both both <pinctrl-base> and <count> must set to 0 when using named pin groups
+names.
+
+The property gpio-ranges-group-names must contain exactly one string for each
+range.
+
+Elements of gpio-ranges-group-names must contain the name of a pin group
+defined in the respective pin controller. The number of pins/GPIO lines in the
+range is the number of pins in that pin group. The number of pins of that
+group is defined int the implementation and not in the device tree.
-Example 2:
+If numerical and named pin groups are mixed, the string corresponding to a
+numerical pin range in gpio-ranges-group-names must be empty.
- gpio_pio_i: gpio-controller@14B0 {
+Example:
+
+ gpio_pio_i: gpio-controller@14b0 {
#gpio-cells = <2>;
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
reg = <0x1480 0x18>;
@@ -207,66 +311,14 @@ Example 2:
"bar";
};
-Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO
-ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
-are named "foo" and "bar".
-
-3) GPIO hog definitions
------------------------
-
-The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism
-providing automatic GPIO request and configuration as part of the
-gpio-controller's driver probe function.
+Here, three GPIO ranges are defined referring to two pin controllers.
-Each GPIO hog definition is represented as a child node of the GPIO controller.
-Required properties:
-- gpio-hog: A property specifying that this child node represents a GPIO hog.
-- gpios: Store the GPIO information (id, flags) for the GPIO to
- affect.
+pinctrl1 GPIO ranges are defined using pin numbers whereas the GPIO ranges
+in pinctrl2 are defined using the pin groups named "foo" and "bar".
- ! Not yet support more than one gpio !
-
-Only one of the following properties scanned in the order shown below.
-- input: A property specifying to set the GPIO direction as input.
-- output-low A property specifying to set the GPIO direction as output with
- the value low.
-- output-high A property specifying to set the GPIO direction as output with
- the value high.
-
-Optional properties:
-- line-name: The GPIO label name. If not present the node name is used.
-
-Example:
-
- tca6416@20 {
- compatible = "ti,tca6416";
- reg = <0x20>;
- #gpio-cells = <2>;
- gpio-controller;
-
- env_reset {
- gpio-hog;
- input;
- gpios = <6 GPIO_ACTIVE_LOW>;
- };
- boot_rescue {
- gpio-hog;
- input;
- line-name = "foo-bar-gpio";
- gpios = <7 GPIO_ACTIVE_LOW>;
- };
- };
-
-For the above Example you can than access the gpio in your boardcode
-with:
-
- struct gpio_desc *desc;
- int ret;
-
- ret = gpio_hog_lookup_name("boot_rescue", &desc);
- if (ret)
- return;
- if (dm_gpio_get_value(desc) == 1)
- printf("\nBooting into Rescue System\n");
- else if (dm_gpio_get_value(desc) == 0)
- printf("\nBoot normal\n");
+Previous versions of this binding required all pin controller nodes that
+were referenced by any gpio-ranges property to contain a property named
+#gpio-range-cells with value <3>. This requirement is now deprecated.
+However, that property may still exist in older device trees for
+compatibility reasons, and would still be required even in new device
+trees that need to be compatible with older software.
diff --git a/doc/device-tree-bindings/i2c/i2c-stm32.txt b/doc/device-tree-bindings/i2c/i2c-stm32.txt
index df03743..7f7686e 100644
--- a/doc/device-tree-bindings/i2c/i2c-stm32.txt
+++ b/doc/device-tree-bindings/i2c/i2c-stm32.txt
@@ -1,30 +1,109 @@
-* I2C controller embedded in STMicroelectronis STM32 platforms
+* I2C controller embedded in STMicroelectronics STM32 I2C platform
Required properties :
-- compatible : Must be "st,stm32f7-i2c"
+- compatible : Must be one of the following
+ - "st,stm32f4-i2c"
+ - "st,stm32f7-i2c"
- reg : Offset and length of the register set for the device
-- resets: Must contain the phandle to the reset controller
-- clocks: Must contain the input clock of the I2C instance
+- 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
- operation for I2C transfer
+ operation for I2C transfer. An optional pinctrl state named "sleep" has to
+ be defined as well as to put I2C in low power mode in suspend mode.
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties :
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
- the default 100 kHz frequency will be used. As only Normal, Fast and Fast+
- modes are implemented, possible values are 100000, 400000 and 1000000.
+ 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, 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: 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 :
- i2c1: i2c@40005400 {
- compatible = "st,stm32f7-i2c";
+ i2c@40005400 {
+ compatible = "st,stm32f4-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0x40005400 0x400>;
- resets = <&rcc 181>;
- clocks = <&clk_pclk1>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc 277>;
+ clocks = <&rcc 0 149>;
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- clock-frequency = <400000>;
+ };
+
+ i2c@40005400 {
+ compatible = "st,stm32f7-i2c";
#address-cells = <1>;
#size-cells = <0>;
+ reg = <0x40005400 0x400>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc STM32F7_APB1_RESET(I2C1)>;
+ clocks = <&rcc 1 CLK_I2C1>;
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
+ 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
+i2c.txt file.
+
+Required properties :
+- compatible
+ Device driver compatible name
+- reg
+ I2C slave addresses (see i2c.txt for more details)
+
+Optional properties :
+
+ i2c@40013000 {
+ camera@3c {
+ compatible = "ovti,ov5640";
+ reg = <0x3c>;
+ };
};
diff --git a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
index ee708ce..ac6a7df 100644
--- a/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
+++ b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt
@@ -129,6 +129,8 @@ phyc attributes:
MR3
- st,phy-cal : phy cal depending of calibration or tuning of DDR
+ This parameter is optional; when it is absent the built-in PHY
+ calibration is done.
for STM32MP15x: 12 values are requested in this order
DX0DLLCR
DX0DQTR
diff --git a/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt b/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt
index 70e76be..ad2bef8 100644
--- a/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt
+++ b/doc/device-tree-bindings/mtd/stm32-fmc2-nand.txt
@@ -18,8 +18,10 @@ Optional properties:
- dmas: DMA specifiers (see: dma/stm32-mdma.txt)
- dma-names: Must be "tx", "rx" and "ecc"
-Optional children nodes:
-Children nodes represent the available NAND chips.
+* NAND device bindings:
+
+Required properties:
+- reg: describes the CS lines assigned to the NAND device.
Optional properties:
- nand-on-flash-bbt: see nand.txt
diff --git a/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt b/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt
index da98407..156229b 100644
--- a/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt
+++ b/doc/device-tree-bindings/phy/phy-stm32-usbphyc.txt
@@ -27,6 +27,7 @@ Required properties:
- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY
- #address-cells: number of address cells for phys sub-nodes, must be <1>
- #size-cells: number of size cells for phys sub-nodes, must be <0>
+- #clock-cells: number of clock cells for ck_usbo_48m consumer, must be <0>
Optional properties:
- assigned-clocks: phandle + clock specifier for the PLL phy clock
@@ -36,7 +37,7 @@ Optional properties:
Required nodes: one sub-node per port the controller provides.
Phy sub-nodes
-==============
+=============
Required properties:
- reg: phy port index
@@ -45,29 +46,73 @@ Required properties:
- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY
port#1 and must be <1> for PHY port#2, to select USB controller
+Optional properties:
+- st,phy-tuning : phandle to the usb phy tuning node, see Phy tuning node below
+
+Phy tuning node
+===============
+
+It may be necessary to adjust the phy settings to compensate parasitics, which
+can be due to USB connector/receptacle, routing, ESD protection component, ...
+
+Here is the list of all optional parameters to tune the interface of the phy
+(HS for High-Speed, FS for Full-Speed, LS for Low-Speed)
+
+Optional properties:
+- st,current-boost: <1> current boosting of 1mA
+ <2> current boosting of 2mA
+- st,no-lsfs-fb-cap: disables the LS/FS feedback capacitor
+- st,hs-slew-ctrl: slows the HS driver slew rate by 10%
+- st,hs-dc-level: <0> decreases the HS driver DC level by 5 to 7mV
+ <1> increases the HS driver DC level by 5 to 7mV
+ <2> increases the HS driver DC level by 10 to 14mV
+- st,fs-rftime-tuning: enables the FS rise/fall tuning option
+- st,hs-rftime-reduction: enables the HS rise/fall reduction feature
+- st,hs-current-trim: controls HS driver current trimming for choke
+- st,hs-impedance-trim: controls HS driver impedance tuning for choke
+- st,squelch-level: adjusts the squelch DC threshold value
+- st,hs-rx-gain-eq: enables the HS Rx gain equalizer
+- st,hs-rx-offset: adjusts the HS Rx offset
+- st,no-hs-ftime-ctrl: disables the HS fall time control of single
+ ended signals during pre-emphasis
+- st,no-lsfs-sc: disables the short circuit protection in LS/FS driver
+- st,hs-tx-staggering: enables the basic staggering in HS Tx mode
+
Example:
+ usb_phy_tuning: usb-phy-tuning {
+ st,current-boost = <2>;
+ st,no-lfs-fb-cap;
+ st,hs-dc-level = <2>;
+ st,hs-rftime-reduction;
+ st,hs-current-trim = <5>;
+ st,hs-impedance-trim = <0>;
+ st,squelch-level = <1>;
+ st,no-hs-ftime-ctrl;
+ st,hs-tx-staggering;
+ };
+
usbphyc: usb-phy@5a006000 {
compatible = "st,stm32mp1-usbphyc";
reg = <0x5a006000 0x1000>;
clocks = <&rcc_clk USBPHY_K>;
resets = <&rcc_rst USBPHY_R>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>;
#address-cells = <1>;
#size-cells = <0>;
+ #clock-cells = <0>;
usbphyc_port0: usb-phy@0 {
reg = <0>;
phy-supply = <&vdd_usb>;
- vdda1v1-supply = <&reg11>;
- vdda1v8-supply = <&reg18>
#phy-cells = <0>;
};
usbphyc_port1: usb-phy@1 {
reg = <1>;
phy-supply = <&vdd_usb>;
- vdda1v1-supply = <&reg11>;
- vdda1v8-supply = <&reg18>
#phy-cells = <1>;
+ st,phy-tuning = <&usb_phy_tuning>;
};
};
diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c
index 017650a..3c2a3ac 100644
--- a/drivers/ata/dwc_ahci.c
+++ b/drivers/ata/dwc_ahci.c
@@ -62,13 +62,13 @@ static int dwc_ahci_probe(struct udevice *dev)
ret = generic_phy_init(&phy);
if (ret) {
- pr_err("unable to initialize the sata phy\n");
+ pr_debug("unable to initialize the sata phy\n");
return ret;
}
ret = generic_phy_power_on(&phy);
if (ret) {
- pr_err("unable to power on the sata phy\n");
+ pr_debug("unable to power on the sata phy\n");
return ret;
}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 16d4237..322f02a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -141,6 +141,14 @@ config CLK_CDCE9XX
Enable the clock synthesizer driver for CDCE913/925/937/949
series of chips.
+config CLK_SCMI
+ bool "Enable SCMI clock driver"
+ select SCMI_AGENT
+ help
+ Enable this option if you want to support clock devices exposed
+ by a SCMI agent based on SCMI clock protocol communication
+ with a SCMI server.
+
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 06131ed..b732852 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
obj-$(CONFIG_CLK_OWL) += owl/
obj-$(CONFIG_CLK_RENESAS) += renesas/
+obj-$(CONFIG_CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
new file mode 100644
index 0000000..f24b8b0
--- /dev/null
+++ b/drivers/clk/clk_scmi.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Linaro Limited
+ */
+#include <asm/types.h>
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <scmi_agent.h>
+
+enum scmi_clock_message_id {
+ SCMI_CLOCK_RATE_SET = 0x5,
+ SCMI_CLOCK_RATE_GET = 0x6,
+ SCMI_CLOCK_CONFIG_SET = 0x7,
+};
+
+#define SCMI_CLK_RATE_ASYNC_NOTIFY BIT(0)
+#define SCMI_CLK_RATE_ASYNC_NORESP (BIT(0) | BIT(1))
+#define SCMI_CLK_RATE_ROUND_DOWN 0
+#define SCMI_CLK_RATE_ROUND_UP BIT(2)
+#define SCMI_CLK_RATE_ROUND_CLOSEST BIT(3)
+
+struct scmi_clk_state_in {
+ u32 clock_id;
+ u32 attributes;
+};
+
+struct scmi_clk_state_out {
+ s32 status;
+};
+
+static int scmi_clk_gate(struct clk *clk, int enable)
+{
+ struct scmi_clk_state_in in = {
+ .clock_id = clk->id,
+ .attributes = enable,
+ };
+ struct scmi_clk_state_out out;
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_CONFIG_SET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int rc;
+
+ rc = scmi_agent_process_msg(clk->dev->parent, &scmi_msg);
+ if (rc)
+ return rc;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_clk_enable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 1);
+}
+
+static int scmi_clk_disable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 0);
+}
+
+struct scmi_clk_rate_get_in {
+ u32 clock_id;
+};
+
+struct scmi_clk_rate_get_out {
+ s32 status;
+ u32 rate_lsb;
+ u32 rate_msb;
+};
+
+static ulong scmi_clk_get_rate(struct clk *clk)
+{
+ struct scmi_clk_rate_get_in in = {
+ .clock_id = clk->id,
+ };
+ struct scmi_clk_rate_get_out out;
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_RATE_GET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int rc;
+
+ rc = scmi_agent_process_msg(clk->dev->parent, &scmi_msg);
+ if (rc)
+ return 0;
+
+ rc = scmi_to_linux_errno(out.status);
+ if (rc)
+ return 0;
+
+ return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
+}
+
+struct scmi_clk_rate_set_in {
+ u32 clock_id;
+ u32 flags;
+ u32 rate_lsb;
+ u32 rate_msb;
+};
+
+struct scmi_clk_rate_set_out {
+ s32 status;
+};
+
+static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct scmi_clk_rate_set_in in = {
+ .clock_id = clk->id,
+ .flags = SCMI_CLK_RATE_ASYNC_NORESP |
+ SCMI_CLK_RATE_ROUND_CLOSEST,
+ .rate_lsb = (u32)rate,
+ .rate_msb = (u32)((u64)rate >> 32),
+ };
+ struct scmi_clk_rate_set_out out;
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_RATE_SET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int rc;
+
+ rc = scmi_agent_process_msg(clk->dev->parent, &scmi_msg);
+ if (rc)
+ return 0;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static const struct clk_ops scmi_clk_ops = {
+ .enable = scmi_clk_enable,
+ .disable = scmi_clk_disable,
+ .get_rate = scmi_clk_get_rate,
+ .set_rate = scmi_clk_set_rate,
+};
+
+U_BOOT_DRIVER(scmi_clock) = {
+ .name = "scmi_clk",
+ .id = UCLASS_CLK,
+ .ops = &scmi_clk_ops,
+};
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 3718970..76fddcc 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -14,6 +14,7 @@
#include <vsprintf.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <asm/arch/sys_proto.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/clock/stm32mp1-clksrc.h>
@@ -95,6 +96,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define RCC_I2C12CKSELR 0x8C0
#define RCC_I2C35CKSELR 0x8C4
#define RCC_SPI2S1CKSELR 0x8D8
+#define RCC_SPI45CKSELR 0x8E0
#define RCC_UART6CKSELR 0x8E4
#define RCC_UART24CKSELR 0x8E8
#define RCC_UART35CKSELR 0x8EC
@@ -241,7 +243,7 @@ DECLARE_GLOBAL_DATA_PTR;
enum stm32mp1_parent_id {
/*
* _HSI, _HSE, _CSI, _LSI, _LSE should not be moved
- * they are used as index in osc[] as entry point
+ * they are used as index in osc_clk[] as clock reference
*/
_HSI,
_HSE,
@@ -304,6 +306,7 @@ enum stm32mp1_parent_sel {
_DSI_SEL,
_ADC12_SEL,
_SPI1_SEL,
+ _SPI45_SEL,
_RTC_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
@@ -420,8 +423,7 @@ struct stm32mp1_clk_data {
struct stm32mp1_clk_priv {
fdt_addr_t base;
const struct stm32mp1_clk_data *data;
- ulong osc[NB_OSC];
- struct udevice *osc_dev[NB_OSC];
+ struct clk osc_clk[NB_OSC];
};
#define STM32MP1_CLK(off, b, idx, s) \
@@ -527,6 +529,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
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, 10, SPI5_K, _SPI45_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3),
@@ -602,6 +605,8 @@ 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 spi45_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
@@ -620,22 +625,33 @@ 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(_SPI45_SEL, RCC_SPI45CKSELR, 0, 0x7, spi45_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
+
/* define characteristic of PLL according type */
+#define DIVM_MIN 0
+#define DIVM_MAX 63
#define DIVN_MIN 24
+#define DIVP_MIN 0
+#define DIVP_MAX 127
+#define FRAC_MAX 8192
+
+#define PLL1600_VCO_MIN 800000000
+#define PLL1600_VCO_MAX 1600000000
+
static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
[PLL_800] = {
.refclk_min = 4,
@@ -746,6 +762,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
[_DSI_SEL] = "DSI",
[_ADC12_SEL] = "ADC12",
[_SPI1_SEL] = "SPI1",
+ [_SPI45_SEL] = "SPI45",
[_RTC_SEL] = "RTC",
};
@@ -763,7 +780,7 @@ static ulong stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, int idx)
return 0;
}
- return priv->osc[idx];
+ return clk_get_rate(&priv->osc_clk[idx]);
}
static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id)
@@ -946,10 +963,11 @@ static ulong stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
case RCC_MPCKSELR_PLL:
case RCC_MPCKSELR_PLL_MPUDIV:
clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
- if (p == RCC_MPCKSELR_PLL_MPUDIV) {
+ if ((reg & RCC_SELR_SRC_MASK) ==
+ RCC_MPCKSELR_PLL_MPUDIV) {
reg = readl(priv->base + RCC_MPCKDIVR);
- clock /= stm32mp1_mpu_div[reg &
- RCC_MPUDIV_MASK];
+ clock >>= stm32mp1_mpu_div[reg &
+ RCC_MPUDIV_MASK];
}
break;
}
@@ -1178,6 +1196,213 @@ static ulong stm32mp1_clk_get_rate(struct clk *clk)
}
#ifdef STM32MP1_CLOCK_TREE_INIT
+
+bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type)
+{
+ unsigned int id;
+
+ switch (opp_id) {
+ case 1:
+ case 2:
+ id = opp_id;
+ break;
+ default:
+ id = 1; /* default value */
+ break;
+ }
+
+ switch (cpu_type) {
+ case CPU_STM32MP157Fxx:
+ case CPU_STM32MP157Dxx:
+ case CPU_STM32MP153Fxx:
+ case CPU_STM32MP153Dxx:
+ case CPU_STM32MP151Fxx:
+ case CPU_STM32MP151Dxx:
+ return true;
+ default:
+ return id == 1;
+ }
+}
+
+__weak void board_vddcore_init(u32 voltage_mv)
+{
+}
+
+/*
+ * gets OPP parameters (frequency in KHz and voltage in mV) from
+ * an OPP table subnode. Platform HW support capabilities are also checked.
+ * Returns 0 on success and a negative FDT error code on failure.
+ */
+static int stm32mp1_get_opp(u32 cpu_type, ofnode subnode,
+ u32 *freq_khz, u32 *voltage_mv)
+{
+ u32 opp_hw;
+ u64 read_freq_64;
+ u32 read_voltage_32;
+
+ *freq_khz = 0;
+ *voltage_mv = 0;
+
+ opp_hw = ofnode_read_u32_default(subnode, "opp-supported-hw", 0);
+ if (opp_hw)
+ if (!stm32mp1_supports_opp(opp_hw, cpu_type))
+ return -FDT_ERR_BADVALUE;
+
+ read_freq_64 = ofnode_read_u64_default(subnode, "opp-hz", 0) /
+ 1000ULL;
+ read_voltage_32 = ofnode_read_u32_default(subnode, "opp-microvolt", 0) /
+ 1000U;
+
+ if (!read_voltage_32 || !read_freq_64)
+ return -FDT_ERR_NOTFOUND;
+
+ /* Frequency value expressed in KHz must fit on 32 bits */
+ if (read_freq_64 > U32_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ /* Millivolt value must fit on 16 bits */
+ if (read_voltage_32 > U16_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ *freq_khz = (u32)read_freq_64;
+ *voltage_mv = read_voltage_32;
+
+ return 0;
+}
+
+/*
+ * parses OPP table in DT and finds the parameters for the
+ * highest frequency supported by the HW platform.
+ * Returns 0 on success and a negative FDT error code on failure.
+ */
+int stm32mp1_get_max_opp_freq(struct stm32mp1_clk_priv *priv, u64 *freq_hz)
+{
+ ofnode node, subnode;
+ int ret;
+ u32 freq = 0U, voltage = 0U;
+ u32 cpu_type = get_cpu_type();
+
+ node = ofnode_by_compatible(ofnode_null(), "operating-points-v2");
+ if (!ofnode_valid(node))
+ return -FDT_ERR_NOTFOUND;
+
+ ofnode_for_each_subnode(subnode, node) {
+ unsigned int read_freq;
+ unsigned int read_voltage;
+
+ ret = stm32mp1_get_opp(cpu_type, subnode,
+ &read_freq, &read_voltage);
+ if (ret)
+ continue;
+
+ if (read_freq > freq) {
+ freq = read_freq;
+ voltage = read_voltage;
+ }
+ }
+
+ if (!freq || !voltage)
+ return -FDT_ERR_NOTFOUND;
+
+ *freq_hz = (u64)1000U * freq;
+ board_vddcore_init(voltage);
+
+ return 0;
+}
+
+static int stm32mp1_pll1_opp(struct stm32mp1_clk_priv *priv, int clksrc,
+ u32 *pllcfg, u32 *fracv)
+{
+ u32 post_divm;
+ u32 input_freq;
+ u64 output_freq;
+ u64 freq;
+ u64 vco;
+ u32 divm, divn, divp, frac;
+ int i, ret;
+ u32 diff;
+ u32 best_diff = U32_MAX;
+
+ /* PLL1 is 1600 */
+ const u32 DIVN_MAX = stm32mp1_pll[PLL_1600].divn_max;
+ const u32 POST_DIVM_MIN = stm32mp1_pll[PLL_1600].refclk_min * 1000000U;
+ const u32 POST_DIVM_MAX = stm32mp1_pll[PLL_1600].refclk_max * 1000000U;
+
+ ret = stm32mp1_get_max_opp_freq(priv, &output_freq);
+ if (ret) {
+ debug("PLL1 OPP configuraton not found (%d).\n", ret);
+ return ret;
+ }
+
+ switch (clksrc) {
+ case CLK_PLL12_HSI:
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case CLK_PLL12_HSE:
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ default:
+ return -EINTR;
+ }
+
+ /* Following parameters have always the same value */
+ pllcfg[PLLCFG_Q] = 0;
+ pllcfg[PLLCFG_R] = 0;
+ pllcfg[PLLCFG_O] = PQR(1, 0, 0);
+
+ for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) {
+ post_divm = (u32)(input_freq / (divm + 1));
+ if (post_divm < POST_DIVM_MIN || post_divm > POST_DIVM_MAX)
+ continue;
+
+ for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
+ freq = output_freq * (divm + 1) * (divp + 1);
+ divn = (u32)((freq / input_freq) - 1);
+ if (divn < DIVN_MIN || divn > DIVN_MAX)
+ continue;
+
+ frac = (u32)(((freq * FRAC_MAX) / input_freq) -
+ ((divn + 1) * FRAC_MAX));
+ /* 2 loops to refine the fractional part */
+ for (i = 2; i != 0; i--) {
+ if (frac > FRAC_MAX)
+ break;
+
+ vco = (post_divm * (divn + 1)) +
+ ((post_divm * (u64)frac) /
+ FRAC_MAX);
+ if (vco < (PLL1600_VCO_MIN / 2) ||
+ vco > (PLL1600_VCO_MAX / 2)) {
+ frac++;
+ continue;
+ }
+ freq = vco / (divp + 1);
+ if (output_freq < freq)
+ diff = (u32)(freq - output_freq);
+ else
+ diff = (u32)(output_freq - freq);
+ if (diff < best_diff) {
+ pllcfg[PLLCFG_M] = divm;
+ pllcfg[PLLCFG_N] = divn;
+ pllcfg[PLLCFG_P] = divp;
+ *fracv = frac;
+
+ if (diff == 0)
+ return 0;
+
+ best_diff = diff;
+ }
+ frac++;
+ }
+ }
+ }
+
+ if (best_diff == U32_MAX)
+ return -1;
+
+ return 0;
+}
+
static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset,
u32 mask_on)
{
@@ -1217,7 +1442,7 @@ static int stm32mp1_osc_wait(int enable, fdt_addr_t rcc, u32 offset,
}
static void stm32mp1_lse_enable(fdt_addr_t rcc, int bypass, int digbyp,
- int lsedrv)
+ u32 lsedrv)
{
u32 value;
@@ -1316,7 +1541,7 @@ static int stm32mp1_hsidiv(fdt_addr_t rcc, ulong hsifreq)
break;
if (hsidiv == 4) {
- pr_err("clk-hsi frequency invalid");
+ pr_err("hsi frequency invalid");
return -1;
}
@@ -1649,7 +1874,10 @@ static int stm32mp1_clktree(struct udevice *dev)
unsigned int clksrc[CLKSRC_NB];
unsigned int clkdiv[CLKDIV_NB];
unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
- ofnode plloff[_PLL_NB];
+ unsigned int pllfracv[_PLL_NB];
+ unsigned int pllcsg[_PLL_NB][PLLCSG_NB];
+ bool pllcfg_valid[_PLL_NB];
+ bool pllcsg_set[_PLL_NB];
int ret;
int i, len;
int lse_css = 0;
@@ -1671,16 +1899,43 @@ static int stm32mp1_clktree(struct udevice *dev)
/* check mandatory field in each pll */
for (i = 0; i < _PLL_NB; i++) {
char name[12];
+ ofnode node;
sprintf(name, "st,pll@%d", i);
- plloff[i] = dev_read_subnode(dev, name);
- if (!ofnode_valid(plloff[i]))
- continue;
- ret = ofnode_read_u32_array(plloff[i], "cfg",
- pllcfg[i], PLLCFG_NB);
- if (ret < 0) {
- debug("field cfg invalid: error %d\n", ret);
- return -FDT_ERR_NOTFOUND;
+ node = dev_read_subnode(dev, name);
+ pllcfg_valid[i] = ofnode_valid(node);
+ pllcsg_set[i] = false;
+ if (pllcfg_valid[i]) {
+ debug("DT for PLL %d @ %s\n", i, name);
+ ret = ofnode_read_u32_array(node, "cfg",
+ pllcfg[i], PLLCFG_NB);
+ if (ret < 0) {
+ debug("field cfg invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+ pllfracv[i] = ofnode_read_u32_default(node, "frac", 0);
+
+ ret = ofnode_read_u32_array(node, "csg", pllcsg[i],
+ PLLCSG_NB);
+ if (!ret) {
+ pllcsg_set[i] = true;
+ } else if (ret != -FDT_ERR_NOTFOUND) {
+ debug("invalid csg node for pll@%d res=%d\n",
+ i, ret);
+ return ret;
+ }
+ } else if (i == _PLL1) {
+ /* use OPP for PLL1 for A7 CPU */
+ debug("DT for PLL %d with OPP\n", i);
+ ret = stm32mp1_pll1_opp(priv,
+ clksrc[CLKSRC_PLL12],
+ pllcfg[i],
+ &pllfracv[i]);
+ if (ret) {
+ debug("PLL %d with OPP error = %d\n", i, ret);
+ return ret;
+ }
+ pllcfg_valid[i] = true;
}
}
@@ -1693,12 +1948,13 @@ static int stm32mp1_clktree(struct udevice *dev)
* switch ON oscillator found in device-tree,
* HSI already ON after bootrom
*/
- if (priv->osc[_LSI])
+ if (clk_valid(&priv->osc_clk[_LSI]))
stm32mp1_lsi_set(rcc, 1);
- if (priv->osc[_LSE]) {
- int bypass, digbyp, lsedrv;
- struct udevice *dev = priv->osc_dev[_LSE];
+ if (clk_valid(&priv->osc_clk[_LSE])) {
+ int bypass, digbyp;
+ u32 lsedrv;
+ struct udevice *dev = priv->osc_clk[_LSE].dev;
bypass = dev_read_bool(dev, "st,bypass");
digbyp = dev_read_bool(dev, "st,digbypass");
@@ -1709,9 +1965,9 @@ static int stm32mp1_clktree(struct udevice *dev)
stm32mp1_lse_enable(rcc, bypass, digbyp, lsedrv);
}
- if (priv->osc[_HSE]) {
+ if (clk_valid(&priv->osc_clk[_HSE])) {
int bypass, digbyp, css;
- struct udevice *dev = priv->osc_dev[_HSE];
+ struct udevice *dev = priv->osc_clk[_HSE].dev;
bypass = dev_read_bool(dev, "st,bypass");
digbyp = dev_read_bool(dev, "st,digbypass");
@@ -1736,8 +1992,8 @@ static int stm32mp1_clktree(struct udevice *dev)
/* configure HSIDIV */
debug("configure HSIDIV\n");
- if (priv->osc[_HSI]) {
- stm32mp1_hsidiv(rcc, priv->osc[_HSI]);
+ if (clk_valid(&priv->osc_clk[_HSI])) {
+ stm32mp1_hsidiv(rcc, clk_get_rate(&priv->osc_clk[_HSI]));
stgen_config(priv);
}
@@ -1765,36 +2021,25 @@ static int stm32mp1_clktree(struct udevice *dev)
/* configure and start PLLs */
debug("configure PLLs\n");
for (i = 0; i < _PLL_NB; i++) {
- u32 fracv;
- u32 csg[PLLCSG_NB];
-
- debug("configure PLL %d @ %d\n", i,
- ofnode_to_offset(plloff[i]));
- if (!ofnode_valid(plloff[i]))
+ if (!pllcfg_valid[i])
continue;
-
- fracv = ofnode_read_u32_default(plloff[i], "frac", 0);
- pll_config(priv, i, pllcfg[i], fracv);
- ret = ofnode_read_u32_array(plloff[i], "csg", csg, PLLCSG_NB);
- if (!ret) {
- pll_csg(priv, i, csg);
- } else if (ret != -FDT_ERR_NOTFOUND) {
- debug("invalid csg node for pll@%d res=%d\n", i, ret);
- return ret;
- }
+ debug("configure PLL %d\n", i);
+ pll_config(priv, i, pllcfg[i], pllfracv[i]);
+ if (pllcsg_set[i])
+ pll_csg(priv, i, pllcsg[i]);
pll_start(priv, i);
}
/* wait and start PLLs ouptut when ready */
for (i = 0; i < _PLL_NB; i++) {
- if (!ofnode_valid(plloff[i]))
+ if (!pllcfg_valid[i])
continue;
debug("output PLL %d\n", i);
pll_output(priv, i, pllcfg[i][PLLCFG_O]);
}
/* wait LSE ready before to use it */
- if (priv->osc[_LSE])
+ if (clk_valid(&priv->osc_clk[_LSE]))
stm32mp1_lse_wait(rcc);
/* configure with expected clock source */
@@ -1833,7 +2078,7 @@ static int stm32mp1_clktree(struct udevice *dev)
debug("oscillator off\n");
/* switch OFF HSI if not found in device-tree */
- if (!priv->osc[_HSI])
+ if (!clk_valid(&priv->osc_clk[_HSI]))
stm32mp1_hsi_set(rcc, 0);
/* Software Self-Refresh mode (SSR) during DDR initilialization */
@@ -1931,40 +2176,25 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
return -EINVAL;
}
-static void stm32mp1_osc_clk_init(const char *name,
- struct stm32mp1_clk_priv *priv,
- int index)
-{
- struct clk clk;
- struct udevice *dev = NULL;
-
- priv->osc[index] = 0;
- clk.id = 0;
- if (!uclass_get_device_by_name(UCLASS_CLK, name, &dev)) {
- if (clk_request(dev, &clk))
- pr_err("%s request", name);
- else
- priv->osc[index] = clk_get_rate(&clk);
- }
- priv->osc_dev[index] = dev;
-}
-
static void stm32mp1_osc_init(struct udevice *dev)
{
struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
int i;
const char *name[NB_OSC] = {
- [_LSI] = "clk-lsi",
- [_LSE] = "clk-lse",
- [_HSI] = "clk-hsi",
- [_HSE] = "clk-hse",
- [_CSI] = "clk-csi",
+ [_LSI] = "lsi",
+ [_LSE] = "lse",
+ [_HSI] = "hsi",
+ [_HSE] = "hse",
+ [_CSI] = "csi",
[_I2S_CKIN] = "i2s_ckin",
};
for (i = 0; i < NB_OSC; i++) {
- stm32mp1_osc_clk_init(name[i], priv, i);
- debug("%d: %s => %x\n", i, name[i], (u32)priv->osc[i]);
+ if (clk_get_by_name(dev, name[i], &priv->osc_clk[i]))
+ dev_dbg(dev, "No source clock \"%s\"", name[i]);
+ else
+ dev_dbg(dev, "%s clock rate: %luHz\n",
+ name[i], clk_get_rate(&priv->osc_clk[i]));
}
}
@@ -2037,6 +2267,8 @@ static int stm32mp1_clk_probe(struct udevice *dev)
/* clock tree init is done only one time, before relocation */
if (!(gd->flags & GD_FLG_RELOC))
result = stm32mp1_clktree(dev);
+ if (result)
+ printf("clock tree initialization failed (%d)\n", result);
#endif
#ifndef CONFIG_SPL_BUILD
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 945b814..86fe42a 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -170,6 +170,38 @@ const void *of_get_property(const struct device_node *np, const char *name,
return pp ? pp->value : NULL;
}
+const struct property *of_get_first_property(const struct device_node *np)
+{
+ if (!np)
+ return NULL;
+
+ return np->properties;
+}
+
+const struct property *of_get_next_property(const struct device_node *np,
+ const struct property *property)
+{
+ if (!np)
+ return NULL;
+
+ return property->next;
+}
+
+const void *of_get_property_by_prop(const struct device_node *np,
+ const struct property *property,
+ const char **name,
+ int *lenp)
+{
+ if (!np || !property)
+ return NULL;
+ if (name)
+ *name = property->name;
+ if (lenp)
+ *lenp = property->length;
+
+ return property->value;
+}
+
static const char *of_prop_next_string(struct property *prop, const char *cur)
{
const void *curv = cur;
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 8f0eab2..cb27562 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -536,6 +536,54 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
propname, lenp);
}
+int ofnode_get_first_property(ofnode node, struct ofprop *prop)
+{
+ prop->node = node;
+
+ if (ofnode_is_np(node)) {
+ prop->prop = of_get_first_property(ofnode_to_np(prop->node));
+ if (!prop->prop)
+ return -FDT_ERR_NOTFOUND;
+ } else {
+ prop->offset =
+ fdt_first_property_offset(gd->fdt_blob,
+ ofnode_to_offset(prop->node));
+ if (prop->offset < 0)
+ return prop->offset;
+ }
+
+ return 0;
+}
+
+int ofnode_get_next_property(struct ofprop *prop)
+{
+ if (ofnode_is_np(prop->node)) {
+ prop->prop = of_get_next_property(ofnode_to_np(prop->node),
+ prop->prop);
+ if (!prop->prop)
+ return -FDT_ERR_NOTFOUND;
+ } else {
+ prop->offset = fdt_next_property_offset(gd->fdt_blob,
+ prop->offset);
+ if (prop->offset < 0)
+ return prop->offset;
+ }
+
+ return 0;
+}
+
+const void *ofnode_get_property_by_prop(const struct ofprop *prop,
+ const char **propname, int *lenp)
+{
+ if (ofnode_is_np(prop->node))
+ return of_get_property_by_prop(ofnode_to_np(prop->node),
+ prop->prop, propname, lenp);
+ else
+ return fdt_getprop_by_offset(gd->fdt_blob,
+ prop->offset,
+ propname, lenp);
+}
+
bool ofnode_is_available(ofnode node)
{
if (ofnode_is_np(node))
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 9602e52..a9f5d14 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -238,6 +238,22 @@ const void *dev_read_prop(struct udevice *dev, const char *propname, int *lenp)
return ofnode_get_property(dev_ofnode(dev), propname, lenp);
}
+int dev_read_first_prop(struct udevice *dev, struct ofprop *prop)
+{
+ return ofnode_get_first_property(dev_ofnode(dev), prop);
+}
+
+int dev_read_next_prop(struct ofprop *prop)
+{
+ return ofnode_get_next_property(prop);
+}
+
+const void *dev_read_prop_by_prop(struct ofprop *prop,
+ const char **propname, int *lenp)
+{
+ return ofnode_get_property_by_prop(prop, propname, lenp);
+}
+
int dev_read_alias_seq(struct udevice *dev, int *devnump)
{
ofnode node = dev_ofnode(dev);
diff --git a/drivers/core/root.c b/drivers/core/root.c
index e856438..14df16c 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -203,15 +203,6 @@ static int dm_scan_fdt_live(struct udevice *parent,
int ret = 0, err;
for (np = node_parent->child; np; np = np->sibling) {
- /* "chosen" node isn't a device itself but may contain some: */
- if (!strcmp(np->name, "chosen")) {
- pr_debug("parsing subnodes of \"chosen\"\n");
-
- err = dm_scan_fdt_live(parent, np, pre_reloc_only);
- if (err && !ret)
- ret = err;
- continue;
- }
if (!of_device_is_available(np)) {
pr_debug(" - ignoring disabled device\n");
@@ -256,21 +247,6 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
offset = fdt_next_subnode(blob, offset)) {
const char *node_name = fdt_get_name(blob, offset, NULL);
- /*
- * The "chosen" and "firmware" nodes aren't devices
- * themselves but may contain some:
- */
- if (!strcmp(node_name, "chosen") ||
- !strcmp(node_name, "firmware")) {
- pr_debug("parsing subnodes of \"%s\"\n", node_name);
-
- err = dm_scan_fdt_node(parent, blob, offset,
- pre_reloc_only);
- if (err && !ret)
- ret = err;
- continue;
- }
-
if (!fdtdec_get_is_enabled(blob, offset)) {
pr_debug(" - ignoring disabled device\n");
continue;
@@ -315,7 +291,8 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only)
return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
}
-static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
+static int dm_scan_fdt_ofnode_path(const void *blob, const char *path,
+ bool pre_reloc_only)
{
ofnode node;
@@ -327,13 +304,18 @@ static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
if (of_live_active())
return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
#endif
- return dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset,
+ return dm_scan_fdt_node(gd->dm_root, blob, node.of_offset,
pre_reloc_only);
}
int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
{
- int ret;
+ int ret, i;
+ const char * const nodes[] = {
+ "/chosen",
+ "/clocks",
+ "/firmware"
+ };
ret = dm_scan_fdt(blob, pre_reloc_only);
if (ret) {
@@ -341,16 +323,16 @@ int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
return ret;
}
- ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only);
- if (ret) {
- debug("scan for /clocks failed: %d\n", ret);
- return ret;
+ /* Some nodes aren't devices themselves but may contain some */
+ for (i = 0; i < ARRAY_SIZE(nodes); i++) {
+ ret = dm_scan_fdt_ofnode_path(blob, nodes[i], pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_fdt() scan for %s failed: %d\n",
+ nodes[i], ret);
+ return ret;
+ }
}
- ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only);
- if (ret)
- debug("scan for /firmware failed: %d\n", ret);
-
return ret;
}
#endif
diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig
index 75fe0a1..1783656 100644
--- a/drivers/dfu/Kconfig
+++ b/drivers/dfu/Kconfig
@@ -68,5 +68,10 @@ config DFU_VIRT
used at board level to manage specific behavior
(OTP update for example).
+config SET_DFU_ALT_INFO
+ bool "Dynamic set of DFU alternate information"
+ help
+ This option allows to call the function set_dfu_alt_info to
+ dynamically build dfu_alt_info in board.
endif
endmenu
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 9f85054..a17e488 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -104,6 +104,60 @@ config FASTBOOT_FLASH_NAND_TRIMFFS
When flashing NAND enable the DROP_FFS flag to drop trailing all-0xff
pages.
+config FASTBOOT_MMC_BOOT_SUPPORT
+ bool "Enable EMMC_BOOT flash/erase"
+ depends on FASTBOOT_FLASH_MMC
+ help
+ The fastboot "flash" and "erase" commands normally does operations
+ on eMMC userdata. Define this to enable the special commands to
+ flash/erase eMMC boot partition.
+ The default target name for updating eMMC boot partition 1/2 is
+ CONFIG_FASTBOOT_MMC_BOOT1_NAME/CONFIG_FASTBOOT_MMC_BOOT2_NAME.
+
+config FASTBOOT_MMC_BOOT1_NAME
+ string "Target name for updating EMMC_BOOT1"
+ depends on FASTBOOT_MMC_BOOT_SUPPORT
+ default "mmc0boot0"
+ help
+ The fastboot "flash" and "erase" commands support operations on
+ EMMC_BOOT1. This occurs when the specified "EMMC_BOOT1 name" on
+ the "fastboot flash" and "fastboot erase" commands match the value
+ defined here.
+ The default target name for updating EMMC_BOOT1 is "mmc0boot0".
+
+config FASTBOOT_MMC_BOOT2_NAME
+ string "Target name for updating EMMC_BOOT2"
+ depends on FASTBOOT_MMC_BOOT_SUPPORT
+ default "mmc0boot1"
+ help
+ The fastboot "flash" and "erase" commands support operations on
+ EMMC_BOOT2. This occurs when the specified "EMMC_BOOT2 name" on
+ the "fastboot flash" and "fastboot erase" commands match the value
+ defined here.
+ The default target name for updating EMMC_BOOT2 is "mmc0boot1".
+
+config FASTBOOT_MMC_USER_SUPPORT
+ bool "Enable eMMC userdata partition flash/erase"
+ depends on FASTBOOT_FLASH_MMC
+ help
+ Define this to enable the support "flash" and "erase" command on
+ eMMC userdata. The "flash" command only update the MBR and GPT
+ header when CONFIG_EFI_PARTITION is supported.
+ The "erase" command erase all the userdata.
+ This occurs when the specified "partition name" on the
+ fastboot command line matches the value CONFIG_FASTBOOT_MMC_USER_NAME.
+
+config FASTBOOT_MMC_USER_NAME
+ string "Target name for updating EMMC_USER"
+ depends on FASTBOOT_MMC_USER_SUPPORT
+ default "mmc0"
+ help
+ The fastboot "flash" and "erase" command supports EMMC_USER.
+ This occurs when the specified "EMMC_USER name" on the
+ "fastboot flash" and the "fastboot erase" commands match the value
+ defined here.
+ The default target name for erasing EMMC_USER is "mmc0".
+
config FASTBOOT_GPT_NAME
string "Target name for updating GPT"
depends on FASTBOOT_FLASH_MMC && EFI_PARTITION
@@ -135,6 +189,20 @@ config FASTBOOT_CMD_OEM_FORMAT
relies on the env variable partitions to contain the list of
partitions as required by the gpt command.
+config FASTBOOT_CMD_OEM_PARTCONF
+ bool "Enable the 'oem partconf' command"
+ depends on FASTBOOT_FLASH_MMC && SUPPORT_EMMC_BOOT
+ help
+ Add support for the "oem partconf" command from a client. This set
+ the mmc boot-partition for the selecting eMMC device.
+
+config FASTBOOT_CMD_OEM_BOOTBUS
+ bool "Enable the 'oem bootbus' command"
+ depends on FASTBOOT_FLASH_MMC && SUPPORT_EMMC_BOOT
+ help
+ Add support for the "oem bootbus" command from a client. This set
+ the mmc boot configuration for the selecting eMMC device.
+
endif # FASTBOOT
endmenu
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
index 3c4acfe..842aa5e 100644
--- a/drivers/fastboot/fb_command.c
+++ b/drivers/fastboot/fb_command.c
@@ -39,6 +39,12 @@ static void reboot_bootloader(char *, char *);
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
static void oem_format(char *, char *);
#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
+static void oem_partconf(char *, char *);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
+static void oem_bootbus(char *, char *);
+#endif
static const struct {
const char *command;
@@ -88,6 +94,18 @@ static const struct {
.dispatch = oem_format,
},
#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
+ [FASTBOOT_COMMAND_OEM_PARTCONF] = {
+ .command = "oem partconf",
+ .dispatch = oem_partconf,
+ },
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
+ [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
+ .command = "oem bootbus",
+ .dispatch = oem_bootbus,
+ },
+#endif
};
/**
@@ -335,3 +353,57 @@ static void oem_format(char *cmd_parameter, char *response)
}
}
#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
+/**
+ * oem_partconf() - Execute the OEM partconf command
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void oem_partconf(char *cmd_parameter, char *response)
+{
+ char cmdbuf[32];
+
+ if (!cmd_parameter) {
+ fastboot_fail("Expected command parameter", response);
+ return;
+ }
+
+ /* execute 'mmc partconfg' command with cmd_parameter arguments*/
+ snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
+ CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
+ printf("Execute: %s\n", cmdbuf);
+ if (run_command(cmdbuf, 0))
+ fastboot_fail("Cannot set oem partconf", response);
+ else
+ fastboot_okay(NULL, response);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
+/**
+ * oem_bootbus() - Execute the OEM bootbus command
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void oem_bootbus(char *cmd_parameter, char *response)
+{
+ char cmdbuf[32];
+
+ if (!cmd_parameter) {
+ fastboot_fail("Expected command parameter", response);
+ return;
+ }
+
+ /* execute 'mmc bootbus' command with cmd_parameter arguments*/
+ snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
+ CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
+ printf("Execute: %s\n", cmdbuf);
+ if (run_command(cmdbuf, 0))
+ fastboot_fail("Cannot set oem bootbus", response);
+ else
+ fastboot_okay(NULL, response);
+}
+#endif
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index b0b19c5..09ba2f2 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -129,6 +129,82 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info,
fastboot_okay(NULL, response);
}
+#if defined(CONFIG_FASTBOOT_MMC_BOOT_SUPPORT) || \
+ defined(CONFIG_FASTBOOT_MMC_USER_SUPPORT)
+static int fb_mmc_erase_mmc_hwpart(struct blk_desc *dev_desc)
+{
+ lbaint_t blks;
+
+ debug("Start Erasing mmc hwpart[%u]...\n", dev_desc->hwpart);
+
+ blks = fb_mmc_blk_write(dev_desc, 0, dev_desc->lba, NULL);
+
+ if (blks != dev_desc->lba) {
+ pr_err("Failed to erase mmc hwpart[%u]\n", dev_desc->hwpart);
+ return 1;
+ }
+
+ printf("........ erased %lu bytes from mmc hwpart[%u]\n",
+ dev_desc->lba * dev_desc->blksz, dev_desc->hwpart);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
+static void fb_mmc_boot_ops(struct blk_desc *dev_desc, void *buffer,
+ int hwpart, u32 buff_sz, char *response)
+{
+ lbaint_t blkcnt;
+ lbaint_t blks;
+ unsigned long blksz;
+
+ // To operate on EMMC_BOOT1/2 (mmc0boot0/1) we first change the hwpart
+ if (blk_dselect_hwpart(dev_desc, hwpart)) {
+ pr_err("Failed to select hwpart\n");
+ fastboot_fail("Failed to select hwpart", response);
+ return;
+ }
+
+ if (buffer) { /* flash */
+
+ /* determine number of blocks to write */
+ blksz = dev_desc->blksz;
+ blkcnt = ((buff_sz + (blksz - 1)) & ~(blksz - 1));
+ blkcnt = lldiv(blkcnt, blksz);
+
+ if (blkcnt > dev_desc->lba) {
+ pr_err("Image size too large\n");
+ fastboot_fail("Image size too large", response);
+ return;
+ }
+
+ debug("Start Flashing Image to EMMC_BOOT%d...\n", hwpart);
+
+ blks = fb_mmc_blk_write(dev_desc, 0, blkcnt, buffer);
+
+ if (blks != blkcnt) {
+ pr_err("Failed to write EMMC_BOOT%d\n", hwpart);
+ fastboot_fail("Failed to write EMMC_BOOT part",
+ response);
+ return;
+ }
+
+ printf("........ wrote %lu bytes to EMMC_BOOT%d\n",
+ blkcnt * blksz, hwpart);
+ } else { /* erase */
+ if (fb_mmc_erase_mmc_hwpart(dev_desc)) {
+ pr_err("Failed to erase EMMC_BOOT%d\n", hwpart);
+ fastboot_fail("Failed to erase EMMC_BOOT part",
+ response);
+ return;
+ }
+ }
+
+ fastboot_okay(NULL, response);
+}
+#endif
+
#ifdef CONFIG_ANDROID_BOOT_IMAGE
/**
* Read Android boot image header from boot partition.
@@ -345,8 +421,26 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
return;
}
+#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
+ if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) {
+ fb_mmc_boot_ops(dev_desc, download_buffer, 1,
+ download_bytes, response);
+ return;
+ }
+ if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) {
+ fb_mmc_boot_ops(dev_desc, download_buffer, 2,
+ download_bytes, response);
+ return;
+ }
+#endif
+
#if CONFIG_IS_ENABLED(EFI_PARTITION)
+#ifndef CONFIG_FASTBOOT_MMC_USER_SUPPORT
if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) {
+#else
+ if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0 ||
+ strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) {
+#endif
printf("%s: updating MBR, Primary and Backup GPT(s)\n",
__func__);
if (is_valid_gpt_buf(dev_desc, download_buffer)) {
@@ -457,6 +551,30 @@ void fastboot_mmc_erase(const char *cmd, char *response)
return;
}
+#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
+ if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) {
+ /* erase EMMC boot1 */
+ fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response);
+ return;
+ }
+ if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) {
+ /* erase EMMC boot2 */
+ fb_mmc_boot_ops(dev_desc, NULL, 2, 0, response);
+ return;
+ }
+#endif
+
+#ifdef CONFIG_FASTBOOT_MMC_USER_SUPPORT
+ if (strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) {
+ /* erase EMMC userdata */
+ if (fb_mmc_erase_mmc_hwpart(dev_desc))
+ fastboot_fail("Failed to erase EMMC_USER", response);
+ else
+ fastboot_okay(NULL, response);
+ return;
+ }
+#endif
+
ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info);
if (ret < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 90fbed4..5da28e6 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -19,6 +19,22 @@
DECLARE_GLOBAL_DATA_PTR;
/**
+ * gpio_desc_init() - Initialize the GPIO descriptor
+ *
+ * @desc: GPIO descriptor to initialize
+ * @dev: GPIO device
+ * @offset: Offset of device GPIO
+ */
+static void gpio_desc_init(struct gpio_desc *desc,
+ struct udevice *dev,
+ uint offset)
+{
+ desc->dev = dev;
+ desc->offset = offset;
+ desc->flags = 0;
+}
+
+/**
* gpio_to_device() - Convert global GPIO number to device, number
*
* Convert the GPIO number to an entry in the list of GPIOs
@@ -41,9 +57,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
uc_priv = dev_get_uclass_priv(dev);
if (gpio >= uc_priv->gpio_base &&
gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
- desc->dev = dev;
- desc->offset = gpio - uc_priv->gpio_base;
- desc->flags = 0;
+ gpio_desc_init(desc, dev, gpio - uc_priv->gpio_base);
return 0;
}
}
@@ -85,8 +99,7 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
if (!dev)
return ret ? ret : -EINVAL;
- desc->dev = dev;
- desc->offset = offset;
+ gpio_desc_init(desc, dev, offset);
return 0;
}
@@ -127,8 +140,27 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
if (args->args_count < 2)
return 0;
+ desc->flags = 0;
if (args->args[1] & GPIO_ACTIVE_LOW)
- desc->flags = GPIOD_ACTIVE_LOW;
+ desc->flags |= GPIOD_ACTIVE_LOW;
+
+ /*
+ * need to test 2 bits for gpio output binding:
+ * OPEN_DRAIN (0x6) = SINGLE_ENDED (0x2) | LINE_OPEN_DRAIN (0x4)
+ * OPEN_SOURCE (0x2) = SINGLE_ENDED (0x2) | LINE_OPEN_SOURCE (0x0)
+ */
+ if (args->args[1] & GPIO_SINGLE_ENDED) {
+ if (args->args[1] & GPIO_LINE_OPEN_DRAIN)
+ desc->flags |= GPIOD_OPEN_DRAIN;
+ else
+ desc->flags |= GPIOD_OPEN_SOURCE;
+ }
+
+ if (args->args[1] & GPIO_PULL_UP)
+ desc->flags |= GPIOD_PULL_UP;
+
+ if (args->args[1] & GPIO_PULL_DOWN)
+ desc->flags |= GPIOD_PULL_DOWN;
return 0;
}
@@ -463,18 +495,24 @@ int gpio_direction_output(unsigned gpio, int value)
desc.offset, value);
}
-int dm_gpio_get_value(const struct gpio_desc *desc)
+static int _gpio_get_value(const struct gpio_desc *desc)
{
int value;
+
+ value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+
+ return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+}
+
+int dm_gpio_get_value(const struct gpio_desc *desc)
+{
int ret;
ret = check_reserved(desc, "get_value");
if (ret)
return ret;
- value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
-
- return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+ return _gpio_get_value(desc);
}
int dm_gpio_set_value(const struct gpio_desc *desc, int value)
@@ -491,71 +529,128 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
return 0;
}
-int dm_gpio_get_open_drain(struct gpio_desc *desc)
+/* check dir flags invalid configuration */
+static int check_dir_flags(ulong flags)
{
- struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
- int ret;
+ if ((flags & GPIOD_IS_OUT) && (flags & GPIOD_IS_IN)) {
+ log_debug("%s: flags 0x%lx has GPIOD_IS_OUT and GPIOD_IS_IN\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ if ((flags & GPIOD_PULL_UP) && (flags & GPIOD_PULL_DOWN)) {
+ log_debug("%s: flags 0x%lx has GPIOD_PULL_UP and GPIOD_PULL_DOWN\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ if ((flags & GPIOD_OPEN_DRAIN) && (flags & GPIOD_OPEN_SOURCE)) {
+ log_debug("%s: flags 0x%lx has GPIOD_OPEN_DRAIN and GPIOD_OPEN_SOURCE\n",
+ __func__, flags);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+ struct udevice *dev = desc->dev;
+ struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret = 0;
+
+ ret = check_dir_flags(flags);
+ if (ret) {
+ dev_dbg(dev,
+ "%s error: set_dir_flags for gpio %s%d has invalid dir flags 0x%lx\n",
+ desc->dev->name,
+ uc_priv->bank_name ? uc_priv->bank_name : "",
+ desc->offset, flags);
- ret = check_reserved(desc, "get_open_drain");
- if (ret)
return ret;
+ }
- if (ops->set_open_drain)
- return ops->get_open_drain(desc->dev, desc->offset);
- else
- return -ENOSYS;
+ /* GPIOD_ are directly managed by driver in set_dir_flags*/
+ if (ops->set_dir_flags) {
+ ret = ops->set_dir_flags(dev, desc->offset, flags);
+ } else {
+ if (flags & GPIOD_IS_OUT) {
+ ret = ops->direction_output(dev, desc->offset,
+ GPIOD_FLAGS_OUTPUT(flags));
+ } else if (flags & GPIOD_IS_IN) {
+ ret = ops->direction_input(dev, desc->offset);
+ }
+ }
+
+ return ret;
}
-int dm_gpio_set_open_drain(struct gpio_desc *desc, int value)
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
{
- struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
int ret;
- ret = check_reserved(desc, "set_open_drain");
+ ret = check_reserved(desc, "set_dir_flags");
if (ret)
return ret;
- if (ops->set_open_drain)
- ret = ops->set_open_drain(desc->dev, desc->offset, value);
- else
- return 0; /* feature not supported -> ignore setting */
+ /* combine the requested flags (for IN/OUT) and the descriptor flags */
+ flags |= desc->flags;
+ ret = _dm_gpio_set_dir_flags(desc, flags);
+
+ /* update the descriptor flags */
+ if (ret)
+ desc->flags = flags;
return ret;
}
-int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+int dm_gpio_set_dir(struct gpio_desc *desc)
{
- struct udevice *dev = desc->dev;
- struct dm_gpio_ops *ops = gpio_get_ops(dev);
int ret;
ret = check_reserved(desc, "set_dir");
if (ret)
return ret;
- if (flags & GPIOD_IS_OUT) {
- int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+ return _dm_gpio_set_dir_flags(desc, desc->flags);
+}
- if (flags & GPIOD_ACTIVE_LOW)
- value = !value;
- ret = ops->direction_output(dev, desc->offset, value);
- } else if (flags & GPIOD_IS_IN) {
- ret = ops->direction_input(dev, desc->offset);
- }
+int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags)
+{
+ struct udevice *dev = desc->dev;
+ int ret, value;
+ struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ ulong dir_flags;
+
+ ret = check_reserved(desc, "get_dir_flags");
if (ret)
return ret;
- /*
- * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
- * futures
- */
- desc->flags = flags;
- return 0;
-}
+ /* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */
+ if (ops->get_dir_flags) {
+ ret = ops->get_dir_flags(dev, desc->offset, &dir_flags);
+ if (ret)
+ return ret;
-int dm_gpio_set_dir(struct gpio_desc *desc)
-{
- return dm_gpio_set_dir_flags(desc, desc->flags);
+ /* GPIOD_ACTIVE_LOW is saved in desc->flags */
+ value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+ if (desc->flags & GPIOD_ACTIVE_LOW)
+ value = !value;
+ dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
+ dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW);
+ if (value)
+ dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ } else {
+ dir_flags = desc->flags;
+ /* only GPIOD_IS_OUT_ACTIVE is provided by uclass */
+ dir_flags &= ~GPIOD_IS_OUT_ACTIVE;
+ if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc))
+ dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ }
+ *flags = dir_flags;
+
+ return 0;
}
/**
@@ -804,9 +899,7 @@ static int gpio_request_tail(int ret, const char *nodename,
struct gpio_desc *desc, int flags,
bool add_index, struct udevice *gpio_dev)
{
- desc->dev = gpio_dev;
- desc->offset = 0;
- desc->flags = 0;
+ gpio_desc_init(desc, gpio_dev, 0);
if (ret)
goto err;
@@ -830,7 +923,7 @@ static int gpio_request_tail(int ret, const char *nodename,
debug("%s: dm_gpio_requestf failed\n", __func__);
goto err;
}
- ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
+ ret = dm_gpio_set_dir_flags(desc, flags);
if (ret) {
debug("%s: dm_gpio_set_dir failed\n", __func__);
goto err;
@@ -1053,14 +1146,14 @@ static int gpio_post_bind(struct udevice *dev)
ops->get_value += gd->reloc_off;
if (ops->set_value)
ops->set_value += gd->reloc_off;
- if (ops->get_open_drain)
- ops->get_open_drain += gd->reloc_off;
- if (ops->set_open_drain)
- ops->set_open_drain += gd->reloc_off;
if (ops->get_function)
ops->get_function += gd->reloc_off;
if (ops->xlate)
ops->xlate += gd->reloc_off;
+ if (ops->set_dir_flags)
+ ops->set_dir_flags += gd->reloc_off;
+ if (ops->get_dir_flags)
+ ops->get_dir_flags += gd->reloc_off;
reloc_done++;
}
diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c
index c273c2c..c23f5b5 100644
--- a/drivers/gpio/mpc8xxx_gpio.c
+++ b/drivers/gpio/mpc8xxx_gpio.c
@@ -144,26 +144,6 @@ static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio));
}
-static int mpc8xxx_gpio_get_open_drain(struct udevice *dev, uint gpio)
-{
- struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
-
- return !!mpc8xxx_gpio_open_drain_val(data->base, gpio_mask(gpio));
-}
-
-static int mpc8xxx_gpio_set_open_drain(struct udevice *dev, uint gpio,
- int value)
-{
- struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
-
- if (value)
- mpc8xxx_gpio_open_drain_on(data->base, gpio_mask(gpio));
- else
- mpc8xxx_gpio_open_drain_off(data->base, gpio_mask(gpio));
-
- return 0;
-}
-
static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
{
struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
@@ -240,8 +220,6 @@ static const struct dm_gpio_ops gpio_mpc8xxx_ops = {
.direction_output = mpc8xxx_gpio_direction_output,
.get_value = mpc8xxx_gpio_get_value,
.set_value = mpc8xxx_gpio_set_value,
- .get_open_drain = mpc8xxx_gpio_get_open_drain,
- .set_open_drain = mpc8xxx_gpio_set_open_drain,
.get_function = mpc8xxx_gpio_get_function,
};
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 2ef5c67..bf6287f 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -8,43 +8,43 @@
#include <fdtdec.h>
#include <malloc.h>
#include <asm/gpio.h>
+#include <dm/lists.h>
#include <dm/of.h>
+#include <dm/pinctrl.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/sandbox-gpio.h>
-/* Flags for each GPIO */
-#define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */
-#define GPIOF_HIGH (1 << 1) /* Currently set high */
-#define GPIOF_ODR (1 << 2) /* Currently set to open drain mode */
struct gpio_state {
const char *label; /* label given by requester */
- u8 flags; /* flags (GPIOF_...) */
+ ulong dir_flags; /* dir_flags (GPIOD_...) */
};
-/* Access routines for GPIO state */
-static u8 *get_gpio_flags(struct udevice *dev, unsigned offset)
+/* Access routines for GPIO dir flags */
+static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct gpio_state *state = dev_get_priv(dev);
if (offset >= uc_priv->gpio_count) {
- static u8 invalid_flags;
+ static ulong invalid_dir_flags;
printf("sandbox_gpio: error: invalid gpio %u\n", offset);
- return &invalid_flags;
+ return &invalid_dir_flags;
}
- return &state[offset].flags;
+ return &state[offset].dir_flags;
+
}
-static int get_gpio_flag(struct udevice *dev, unsigned offset, int flag)
+static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
{
- return (*get_gpio_flags(dev, offset) & flag) != 0;
+ return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
}
-static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag,
+static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
int value)
{
- u8 *gpio = get_gpio_flags(dev, offset);
+ ulong *gpio = get_gpio_dir_flags(dev, offset);
if (value)
*gpio |= flag;
@@ -60,34 +60,40 @@ static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag,
int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
{
- if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
+ if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
debug("sandbox_gpio: get_value on output gpio %u\n", offset);
- return get_gpio_flag(dev, offset, GPIOF_HIGH);
+ return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
}
int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
- return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
+ return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
}
-int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset)
+int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
{
- return get_gpio_flag(dev, offset, GPIOF_ODR);
+ return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
}
-int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
+int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
{
- return set_gpio_flag(dev, offset, GPIOF_ODR, value);
+ set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
+ set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
+
+ return 0;
}
-int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
+ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
{
- return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
+ return *get_gpio_dir_flags(dev, offset);
}
-int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
+int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
{
- return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output);
+ *get_gpio_dir_flags(dev, offset) = flags;
+
+ return 0;
}
/*
@@ -134,33 +140,14 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
return sandbox_gpio_set_value(dev, offset, value);
}
-/* read GPIO ODR value of port 'offset' */
-static int sb_gpio_get_open_drain(struct udevice *dev, unsigned offset)
-{
- debug("%s: offset:%u\n", __func__, offset);
-
- return sandbox_gpio_get_open_drain(dev, offset);
-}
-
-/* write GPIO ODR value to port 'offset' */
-static int sb_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
-{
- debug("%s: offset:%u, value = %d\n", __func__, offset, value);
-
- if (!sandbox_gpio_get_direction(dev, offset)) {
- printf("sandbox_gpio: error: set_open_drain on input gpio %u\n",
- offset);
- return -1;
- }
-
- return sandbox_gpio_set_open_drain(dev, offset, value);
-}
-
static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
{
- if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
+ if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
return GPIOF_OUTPUT;
- return GPIOF_INPUT;
+ if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
+ return GPIOF_INPUT;
+
+ return GPIOF_INPUT; /*GPIO is not configurated */
}
static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
@@ -169,27 +156,54 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
desc->offset = args->args[0];
if (args->args_count < 2)
return 0;
- if (args->args[1] & GPIO_ACTIVE_LOW)
- desc->flags |= GPIOD_ACTIVE_LOW;
- if (args->args[1] & 2)
+ /* treat generic binding with gpio uclass */
+ gpio_xlate_offs_flags(dev, desc, args);
+
+ /* sandbox test specific, not defined in gpio.h */
+ if (args->args[1] & GPIO_IN)
desc->flags |= GPIOD_IS_IN;
- if (args->args[1] & 4)
+
+ if (args->args[1] & GPIO_OUT)
desc->flags |= GPIOD_IS_OUT;
- if (args->args[1] & 8)
+
+ if (args->args[1] & GPIO_OUT_ACTIVE)
desc->flags |= GPIOD_IS_OUT_ACTIVE;
return 0;
}
+static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ ulong *dir_flags;
+
+ debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
+
+ dir_flags = get_gpio_dir_flags(dev, offset);
+
+ *dir_flags = flags;
+
+ return 0;
+}
+
+static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong *flags)
+{
+ debug("%s: offset:%u\n", __func__, offset);
+ *flags = *get_gpio_dir_flags(dev, offset);
+
+ return 0;
+}
+
static const struct dm_gpio_ops gpio_sandbox_ops = {
.direction_input = sb_gpio_direction_input,
.direction_output = sb_gpio_direction_output,
.get_value = sb_gpio_get_value,
.set_value = sb_gpio_set_value,
- .get_open_drain = sb_gpio_get_open_drain,
- .set_open_drain = sb_gpio_set_open_drain,
.get_function = sb_gpio_get_function,
.xlate = sb_gpio_xlate,
+ .set_dir_flags = sb_gpio_set_dir_flags,
+ .get_dir_flags = sb_gpio_get_dir_flags,
};
static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
@@ -237,3 +251,198 @@ U_BOOT_DRIVER(gpio_sandbox) = {
.remove = gpio_sandbox_remove,
.ops = &gpio_sandbox_ops,
};
+
+/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
+
+struct sb_pinctrl_priv {
+ int pinctrl_ngpios;
+ struct list_head gpio_dev;
+};
+
+struct sb_gpio_bank {
+ struct udevice *gpio_dev;
+ struct list_head list;
+};
+
+static int sb_populate_gpio_dev_list(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct udevice *gpio_dev;
+ struct udevice *child;
+ struct sb_gpio_bank *gpio_bank;
+ int ret;
+
+ /*
+ * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
+ * a list with all gpio device reference which belongs to the
+ * current pin-controller. This list is used to find pin_name and
+ * pin muxing
+ */
+ list_for_each_entry(child, &dev->child_head, sibling_node) {
+ ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
+ &gpio_dev);
+ if (ret < 0)
+ continue;
+
+ gpio_bank = malloc(sizeof(*gpio_bank));
+ if (!gpio_bank) {
+ dev_err(dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ gpio_bank->gpio_dev = gpio_dev;
+ list_add_tail(&gpio_bank->list, &priv->gpio_dev);
+ }
+
+ return 0;
+}
+
+static int sb_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv;
+ struct sb_gpio_bank *gpio_bank;
+
+ /*
+ * if get_pins_count has already been executed once on this
+ * pin-controller, no need to run it again
+ */
+ if (priv->pinctrl_ngpios)
+ return priv->pinctrl_ngpios;
+
+ if (list_empty(&priv->gpio_dev))
+ sb_populate_gpio_dev_list(dev);
+ /*
+ * walk through all banks to retrieve the pin-controller
+ * pins number
+ */
+ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
+ uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
+
+ priv->pinctrl_ngpios += uc_priv->gpio_count;
+ }
+
+ return priv->pinctrl_ngpios;
+}
+
+static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
+ unsigned int selector,
+ unsigned int *idx)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sb_gpio_bank *gpio_bank;
+ struct gpio_dev_priv *uc_priv;
+ int pin_count = 0;
+
+ if (list_empty(&priv->gpio_dev))
+ sb_populate_gpio_dev_list(dev);
+
+ /* look up for the bank which owns the requested pin */
+ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
+ uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
+
+ if (selector < (pin_count + uc_priv->gpio_count)) {
+ /*
+ * we found the bank, convert pin selector to
+ * gpio bank index
+ */
+ *idx = selector - pin_count;
+
+ return gpio_bank->gpio_dev;
+ }
+ pin_count += uc_priv->gpio_count;
+ }
+
+ return NULL;
+}
+
+static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct udevice *gpio_dev;
+ unsigned int gpio_idx;
+ static char pin_name[PINNAME_SIZE];
+
+ /* look up for the bank which owns the requested pin */
+ gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
+ if (!gpio_dev) {
+ snprintf(pin_name, PINNAME_SIZE, "Error");
+ } else {
+ uc_priv = dev_get_uclass_priv(gpio_dev);
+
+ snprintf(pin_name, PINNAME_SIZE, "%s%d",
+ uc_priv->bank_name,
+ gpio_idx);
+ }
+
+ return pin_name;
+}
+
+static char *get_dir_flags_string(ulong flags)
+{
+ if (flags & GPIOD_OPEN_DRAIN)
+ return "drive-open-drain";
+ if (flags & GPIOD_OPEN_SOURCE)
+ return "drive-open-source";
+ if (flags & GPIOD_PULL_UP)
+ return "bias-pull-up";
+ if (flags & GPIOD_PULL_DOWN)
+ return "bias-pull-down";
+ return ".";
+}
+
+static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
+ unsigned int selector,
+ char *buf, int size)
+{
+ struct udevice *gpio_dev;
+ unsigned int gpio_idx;
+ ulong dir_flags;
+ int function;
+
+ /* look up for the bank which owns the requested pin */
+ gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
+ if (!gpio_dev) {
+ snprintf(buf, size, "Error");
+ } else {
+ function = sb_gpio_get_function(gpio_dev, gpio_idx);
+ dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx);
+
+ snprintf(buf, size, "gpio %s %s",
+ function == GPIOF_OUTPUT ? "output" : "input",
+ get_dir_flags_string(dir_flags));
+ }
+
+ return 0;
+}
+
+static int sandbox_pinctrl_probe(struct udevice *dev)
+{
+ struct sb_pinctrl_priv *priv = dev_get_priv(dev);
+
+ INIT_LIST_HEAD(&priv->gpio_dev);
+
+ return 0;
+}
+
+static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
+ .get_pin_name = sb_pinctrl_get_pin_name,
+ .get_pins_count = sb_pinctrl_get_pins_count,
+ .get_pin_muxing = sb_pinctrl_get_pin_muxing,
+};
+
+static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
+ { .compatible = "sandbox,pinctrl-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
+ .name = "sandbox_pinctrl_gpio",
+ .id = UCLASS_PINCTRL,
+ .of_match = sandbox_pinctrl_gpio_match,
+ .ops = &sandbox_pinctrl_gpio_ops,
+ .bind = dm_scan_fdt_dev,
+ .probe = sandbox_pinctrl_probe,
+ .priv_auto_alloc_size = sizeof(struct sb_pinctrl_priv),
+};
diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c
index 302a434..a7c89a4 100644
--- a/drivers/gpio/stm32_gpio.c
+++ b/drivers/gpio/stm32_gpio.c
@@ -19,7 +19,62 @@
#define MODE_BITS_MASK 3
#define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16))
-#ifndef CONFIG_SPL_BUILD
+#define PUPD_BITS(gpio_pin) (gpio_pin * 2)
+#define PUPD_MASK 3
+
+#define OTYPE_BITS(gpio_pin) (gpio_pin)
+#define OTYPE_MSK 1
+
+static void stm32_gpio_set_moder(struct stm32_gpio_regs *regs,
+ int idx,
+ int mode)
+{
+ int bits_index;
+ int mask;
+
+ bits_index = MODE_BITS(idx);
+ mask = MODE_BITS_MASK << bits_index;
+
+ clrsetbits_le32(&regs->moder, mask, mode << bits_index);
+}
+
+static int stm32_gpio_get_moder(struct stm32_gpio_regs *regs, int idx)
+{
+ return (readl(&regs->moder) >> MODE_BITS(idx)) & MODE_BITS_MASK;
+}
+
+static void stm32_gpio_set_otype(struct stm32_gpio_regs *regs,
+ int idx,
+ enum stm32_gpio_otype otype)
+{
+ int bits;
+
+ bits = OTYPE_BITS(idx);
+ clrsetbits_le32(&regs->otyper, OTYPE_MSK << bits, otype << bits);
+}
+
+static enum stm32_gpio_otype stm32_gpio_get_otype(struct stm32_gpio_regs *regs,
+ int idx)
+{
+ return (readl(&regs->otyper) >> OTYPE_BITS(idx)) & OTYPE_MSK;
+}
+
+static void stm32_gpio_set_pupd(struct stm32_gpio_regs *regs,
+ int idx,
+ enum stm32_gpio_pupd pupd)
+{
+ int bits;
+
+ bits = PUPD_BITS(idx);
+ clrsetbits_le32(&regs->pupdr, PUPD_MASK << bits, pupd << bits);
+}
+
+static enum stm32_gpio_pupd stm32_gpio_get_pupd(struct stm32_gpio_regs *regs,
+ int idx)
+{
+ return (readl(&regs->pupdr) >> PUPD_BITS(idx)) & PUPD_MASK;
+}
+
/*
* convert gpio offset to gpio index taking into account gpio holes
* into gpio bank
@@ -45,18 +100,13 @@ static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
struct stm32_gpio_regs *regs = priv->regs;
- int bits_index;
- int mask;
int idx;
idx = stm32_offset_to_index(dev, offset);
if (idx < 0)
return idx;
- bits_index = MODE_BITS(idx);
- mask = MODE_BITS_MASK << bits_index;
-
- clrsetbits_le32(&regs->moder, mask, STM32_GPIO_MODE_IN << bits_index);
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN);
return 0;
}
@@ -66,18 +116,13 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset,
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
struct stm32_gpio_regs *regs = priv->regs;
- int bits_index;
- int mask;
int idx;
idx = stm32_offset_to_index(dev, offset);
if (idx < 0)
return idx;
- bits_index = MODE_BITS(idx);
- mask = MODE_BITS_MASK << bits_index;
-
- clrsetbits_le32(&regs->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
writel(BSRR_BIT(idx, value), &regs->bsrr);
@@ -139,14 +184,88 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
return GPIOF_FUNC;
}
+static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ 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;
+
+ if (flags & GPIOD_IS_OUT) {
+ int value = GPIOD_FLAGS_OUTPUT(flags);
+
+ if (flags & GPIOD_OPEN_DRAIN)
+ stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD);
+ else
+ stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP);
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
+ writel(BSRR_BIT(idx, value), &regs->bsrr);
+
+ } else if (flags & GPIOD_IS_IN) {
+ stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_IN);
+ if (flags & GPIOD_PULL_UP)
+ stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_UP);
+ else if (flags & GPIOD_PULL_DOWN)
+ stm32_gpio_set_pupd(regs, idx, STM32_GPIO_PUPD_DOWN);
+ }
+
+ return 0;
+}
+
+static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong *flags)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ int idx;
+ ulong dir_flags = 0;
+
+ idx = stm32_offset_to_index(dev, offset);
+ if (idx < 0)
+ return idx;
+
+ switch (stm32_gpio_get_moder(regs, idx)) {
+ case STM32_GPIO_MODE_OUT:
+ dir_flags |= GPIOD_IS_OUT;
+ if (stm32_gpio_get_otype(regs, idx) == STM32_GPIO_OTYPE_OD)
+ dir_flags |= GPIOD_OPEN_DRAIN;
+ if (readl(&regs->idr) & BIT(idx))
+ dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ break;
+ case STM32_GPIO_MODE_IN:
+ dir_flags |= GPIOD_IS_IN;
+ switch (stm32_gpio_get_pupd(regs, idx)) {
+ case STM32_GPIO_PUPD_UP:
+ dir_flags |= GPIOD_PULL_UP;
+ break;
+ case STM32_GPIO_PUPD_DOWN:
+ dir_flags |= GPIOD_PULL_DOWN;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ *flags = dir_flags;
+
+ return 0;
+}
+
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,
+ .set_dir_flags = stm32_gpio_set_dir_flags,
+ .get_dir_flags = stm32_gpio_get_dir_flags,
};
-#endif
static int gpio_stm32_probe(struct udevice *dev)
{
@@ -161,7 +280,6 @@ static int gpio_stm32_probe(struct udevice *dev)
priv->regs = (struct stm32_gpio_regs *)addr;
-#ifndef CONFIG_SPL_BUILD
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct ofnode_phandle_args args;
const char *name;
@@ -194,7 +312,7 @@ static int gpio_stm32_probe(struct udevice *dev)
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);
-#endif
+
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
@@ -214,9 +332,7 @@ U_BOOT_DRIVER(gpio_stm32) = {
.name = "gpio_stm32",
.id = UCLASS_GPIO,
.probe = gpio_stm32_probe,
-#ifndef CONFIG_SPL_BUILD
.ops = &gpio_stm32_ops,
-#endif
.flags = DM_UC_FLAG_SEQ_ALIAS,
.priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
};
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index 2b18735..7321f80 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -10,6 +10,7 @@
#include <reset.h>
#include <dm/device.h>
+#include <linux/err.h>
#include <linux/io.h>
/* STM32 I2C registers */
@@ -115,17 +116,6 @@ struct stm32_i2c_regs {
#define STM32_NSEC_PER_SEC 1000000000L
-#define STANDARD_RATE 100000
-#define FAST_RATE 400000
-#define FAST_PLUS_RATE 1000000
-
-enum stm32_i2c_speed {
- STM32_I2C_SPEED_STANDARD, /* 100 kHz */
- STM32_I2C_SPEED_FAST, /* 400 kHz */
- STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
- STM32_I2C_SPEED_END,
-};
-
/**
* struct stm32_i2c_spec - private i2c specification timing
* @rate: I2C bus speed (Hz)
@@ -155,7 +145,6 @@ struct stm32_i2c_spec {
/**
* struct stm32_i2c_setup - private I2C timing setup parameters
- * @speed: I2C speed mode (standard, Fast Plus)
* @speed_freq: I2C speed frequency (Hz)
* @clock_src: I2C clock source frequency (Hz)
* @rise_time: Rise time (ns)
@@ -164,7 +153,6 @@ struct stm32_i2c_spec {
* @analog_filter: Analog filter delay (On/Off)
*/
struct stm32_i2c_setup {
- enum stm32_i2c_speed speed;
u32 speed_freq;
u32 clock_src;
u32 rise_time;
@@ -194,12 +182,13 @@ struct stm32_i2c_priv {
struct stm32_i2c_regs *regs;
struct clk clk;
struct stm32_i2c_setup *setup;
- int speed;
+ u32 speed;
};
static const struct stm32_i2c_spec i2c_specs[] = {
- [STM32_I2C_SPEED_STANDARD] = {
- .rate = STANDARD_RATE,
+ /* Standard speed - 100 KHz */
+ [IC_SPEED_MODE_STANDARD] = {
+ .rate = I2C_SPEED_STANDARD_RATE,
.rate_min = 8000,
.rate_max = 120000,
.fall_max = 300,
@@ -210,8 +199,9 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 4700,
.h_min = 4000,
},
- [STM32_I2C_SPEED_FAST] = {
- .rate = FAST_RATE,
+ /* Fast speed - 400 KHz */
+ [IC_SPEED_MODE_FAST] = {
+ .rate = I2C_SPEED_FAST_RATE,
.rate_min = 320000,
.rate_max = 480000,
.fall_max = 300,
@@ -222,8 +212,9 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 1300,
.h_min = 600,
},
- [STM32_I2C_SPEED_FAST_PLUS] = {
- .rate = FAST_PLUS_RATE,
+ /* Fast Plus Speed - 1 MHz */
+ [IC_SPEED_MODE_FAST_PLUS] = {
+ .rate = I2C_SPEED_FAST_PLUS_RATE,
.rate_min = 800000,
.rate_max = 1200000,
.fall_max = 100,
@@ -484,6 +475,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
}
static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions)
{
struct stm32_i2c_timings *v;
@@ -500,13 +492,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
af_delay_max = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
- sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
+ sdadel_min = specs->hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
- sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
+ sdadel_max = specs->vddat_max - setup->rise_time -
af_delay_max - (setup->dnf + 4) * i2cclk;
- scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
+ scldel_min = setup->rise_time + specs->sudat_min;
if (sdadel_min < 0)
sdadel_min = 0;
@@ -558,6 +550,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
}
static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions,
struct stm32_i2c_timings *s)
{
@@ -580,8 +573,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
dnf_delay = setup->dnf * i2cclk;
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
- clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
- clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
+ clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
+ clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
/*
* Among Prescaler possibilities discovered above figures out SCL Low
@@ -599,7 +592,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
for (l = 0; l < STM32_SCLL_MAX; l++) {
u32 tscl_l = (l + 1) * prescaler + tsync;
- if ((tscl_l < i2c_specs[setup->speed].l_min) ||
+ if (tscl_l < specs->l_min ||
(i2cclk >=
((tscl_l - af_delay_min - dnf_delay) / 4))) {
continue;
@@ -611,7 +604,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
setup->rise_time + setup->fall_time;
if ((tscl >= clk_min) && (tscl <= clk_max) &&
- (tscl_h >= i2c_specs[setup->speed].h_min) &&
+ (tscl_h >= specs->h_min) &&
(i2cclk < tscl_h)) {
u32 clk_error;
@@ -640,26 +633,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
return ret;
}
+static const struct stm32_i2c_spec *get_specs(u32 rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
+ if (rate <= i2c_specs[i].rate)
+ return &i2c_specs[i];
+
+ /* NOT REACHED */
+ return ERR_PTR(-EINVAL);
+}
+
static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_setup *setup,
struct stm32_i2c_timings *output)
{
+ const struct stm32_i2c_spec *specs;
struct stm32_i2c_timings *v, *_v;
struct list_head solutions;
int ret;
- if (setup->speed >= STM32_I2C_SPEED_END) {
- pr_err("%s: speed out of bound {%d/%d}\n", __func__,
- setup->speed, STM32_I2C_SPEED_END - 1);
+ specs = get_specs(setup->speed_freq);
+ if (specs == ERR_PTR(-EINVAL)) {
+ pr_err("%s: speed out of bound {%d}\n", __func__,
+ setup->speed_freq);
return -EINVAL;
}
- if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
- (setup->fall_time > i2c_specs[setup->speed].fall_max)) {
+ if (setup->rise_time > specs->rise_max ||
+ setup->fall_time > specs->fall_max) {
pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
__func__,
- setup->rise_time, i2c_specs[setup->speed].rise_max,
- setup->fall_time, i2c_specs[setup->speed].fall_max);
+ setup->rise_time, specs->rise_max,
+ setup->fall_time, specs->fall_max);
return -EINVAL;
}
@@ -669,18 +676,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
return -EINVAL;
}
- if (setup->speed_freq > i2c_specs[setup->speed].rate) {
- pr_err("%s: Freq {%d/%d}\n", __func__,
- setup->speed_freq, i2c_specs[setup->speed].rate);
- return -EINVAL;
- }
-
INIT_LIST_HEAD(&solutions);
- ret = stm32_i2c_compute_solutions(setup, &solutions);
+ ret = stm32_i2c_compute_solutions(setup, specs, &solutions);
if (ret)
goto exit;
- ret = stm32_i2c_choose_solution(setup, &solutions, output);
+ ret = stm32_i2c_choose_solution(setup, specs, &solutions, output);
if (ret)
goto exit;
@@ -699,14 +700,24 @@ exit:
return ret;
}
+static u32 get_lower_rate(u32 rate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
+ if (rate > i2c_specs[i].rate)
+ return i2c_specs[i].rate;
+
+ return i2c_specs[0].rate;
+}
+
static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_timings *timing)
{
struct stm32_i2c_setup *setup = i2c_priv->setup;
int ret = 0;
- setup->speed = i2c_priv->speed;
- setup->speed_freq = i2c_specs[setup->speed].rate;
+ setup->speed_freq = i2c_priv->speed;
setup->clock_src = clk_get_rate(&i2c_priv->clk);
if (!setup->clock_src) {
@@ -719,13 +730,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
if (ret) {
debug("%s: failed to compute I2C timings.\n",
__func__);
- if (i2c_priv->speed > STM32_I2C_SPEED_STANDARD) {
- i2c_priv->speed--;
- setup->speed = i2c_priv->speed;
+ if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) {
setup->speed_freq =
- i2c_specs[setup->speed].rate;
+ get_lower_rate(setup->speed_freq);
debug("%s: downgrade I2C Speed Freq to (%i)\n",
- __func__, i2c_specs[setup->speed].rate);
+ __func__, setup->speed_freq);
} else {
break;
}
@@ -737,13 +746,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
return ret;
}
- debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__,
- setup->speed, setup->speed_freq, setup->clock_src);
+ debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__,
+ setup->speed_freq, setup->clock_src);
debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__,
setup->rise_time, setup->fall_time);
debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__,
setup->analog_filter ? "On" : "Off", setup->dnf);
+ i2c_priv->speed = setup->speed_freq;
+
return 0;
}
@@ -783,21 +794,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
- switch (speed) {
- case STANDARD_RATE:
- i2c_priv->speed = STM32_I2C_SPEED_STANDARD;
- break;
- case FAST_RATE:
- i2c_priv->speed = STM32_I2C_SPEED_FAST;
- break;
- case FAST_PLUS_RATE:
- i2c_priv->speed = STM32_I2C_SPEED_FAST_PLUS;
- break;
- default:
+ if (speed > I2C_SPEED_FAST_PLUS_RATE) {
debug("%s: Speed %d not supported\n", __func__, speed);
return -EINVAL;
}
+ i2c_priv->speed = speed;
+
return stm32_i2c_hw_config(i2c_priv);
}
@@ -867,6 +870,7 @@ static const struct dm_i2c_ops stm32_i2c_ops = {
static const struct udevice_id stm32_i2c_of_match[] = {
{ .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup },
+ { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32f7_setup },
{}
};
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 85c2a82..dbb3d81 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -47,4 +47,11 @@ config ZYNQMP_IPI
help
This enables support for the Xilinx ZynqMP Inter Processor Interrupt
communication controller.
+
+config ARM_SMC_MAILBOX
+ bool "Enable Arm SMC mailbox support"
+ depends on DM_MAILBOX && ARM_SMCCC
+ help
+ Mailbox notification through an Arm SMC or HVC calls.
+
endmenu
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index d2ace8c..7a56a45 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -3,6 +3,7 @@
# Copyright (c) 2016, NVIDIA CORPORATION.
#
+obj-$(CONFIG_ARM_SMC_MAILBOX) += arm-smc-mbox.o
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
diff --git a/drivers/mailbox/arm-smc-mbox.c b/drivers/mailbox/arm-smc-mbox.c
new file mode 100644
index 0000000..37f595a
--- /dev/null
+++ b/drivers/mailbox/arm-smc-mbox.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mailbox-uclass.h>
+#include <linux/arm-smccc.h>
+
+#define ARM_SMC_METHOD 0
+#define ARM_HVC_METHOD 1
+
+typedef void (invoke_fn_t)(unsigned long);
+
+struct smc_pdata {
+ unsigned long func_id;
+ invoke_fn_t *invoke_fn;
+};
+
+/* Simple wrapper functions to be able to use a function pointer */
+static void smccc_smc(unsigned long a0)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(a0, 0, 0, 0, 0, 0, 0, 0, &res);
+}
+
+static void smccc_hvc(unsigned long a0)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_hvc(a0, 0, 0, 0, 0, 0, 0, 0, &res);
+}
+
+static int smc_mbox_send(struct mbox_chan *chan, const void *data)
+{
+ struct smc_pdata *pdata = dev_get_platdata(chan->dev);
+
+ /*
+ * This mailbox invokes secure world for a channel event.
+ * Message is already in the channel's shared memory.
+ */
+ pdata->invoke_fn(pdata->func_id);
+
+ return 0;
+}
+
+static int smc_mbox_recv(struct mbox_chan *chan, void *data)
+{
+ /* Mbox owner already got the return message from shared memory */
+ return 0;
+}
+
+static int smc_mbox_request(struct mbox_chan *chan)
+{
+ return 0;
+}
+
+static int smc_mbox_free(struct mbox_chan *chan)
+{
+ return 0;
+}
+
+static int smc_mbox_of_xlate(struct mbox_chan *chan,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count)
+ dev_warn(chan->dev, "Expect no argument to smc-mbox cells\n");
+
+ chan->id = 0;
+
+ return 0;
+}
+
+static int smc_mbox_ofdata_to_platdata(struct udevice *dev)
+{
+ ulong compat_data = dev_get_driver_data(dev);
+ struct smc_pdata *pdata = dev_get_platdata(dev);
+ u32 func_id;
+
+ if (dev_read_u32(dev, "arm,func-id", &func_id)) {
+ dev_err(dev, "Missing property arm,func-id\n");
+ return -EINVAL;
+ }
+
+ pdata->func_id = func_id;
+
+ if (compat_data == ARM_SMC_METHOD)
+ pdata->invoke_fn = smccc_smc;
+ else
+ pdata->invoke_fn = smccc_hvc;
+
+ return 0;
+}
+
+static const struct udevice_id smc_mbox_ids[] = {
+ { .compatible = "arm,smc-mbox", .data = ARM_SMC_METHOD, },
+ { .compatible = "arm,hvc-mbox", .data = ARM_HVC_METHOD, },
+ { }
+};
+
+struct mbox_ops smc_mbox_ops = {
+ .of_xlate = smc_mbox_of_xlate,
+ .request = smc_mbox_request,
+ .free = smc_mbox_free,
+ .send = smc_mbox_send,
+ .recv = smc_mbox_recv,
+};
+
+U_BOOT_DRIVER(smc_mbox) = {
+ .name = "arm_smc_mbox",
+ .id = UCLASS_MAILBOX,
+ .of_match = smc_mbox_ids,
+ .ofdata_to_platdata = smc_mbox_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct smc_pdata),
+ .ops = &smc_mbox_ops,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 82bb093..547e144 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -439,4 +439,16 @@ config K3_AVS0
optimized voltage from the efuse, so that it can be programmed
to the PMIC on board.
+config SCMI_AGENT
+ bool "Enable SCMI support"
+ select OF_TRANSLATE
+ help
+ An SCMI agent communicates with a related SCMI server located
+ in another sub-system, as a companion micro controller or a
+ companion host in the CPU system.
+
+ Communications between agent (client) and the SCMI server are
+ based on message exchange, for example through a mailbox device
+ and some piece of identified shared memory.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 55976d6..df7b3ed 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
obj-$(CONFIG_K3_AVS0) += k3_avs.o
+obj-$(CONFIG_SCMI_AGENT) += scmi_agent.o
diff --git a/drivers/misc/scmi_agent.c b/drivers/misc/scmi_agent.c
new file mode 100644
index 0000000..d36e460
--- /dev/null
+++ b/drivers/misc/scmi_agent.c
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019 Linaro Limited.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <asm/system.h>
+#include <asm/types.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/ofnode.h>
+#include <errno.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <mailbox.h>
+#include <memalign.h>
+#include <scmi_agent.h>
+#include <tee.h>
+
+struct error_code {
+ int scmi;
+ int errno;
+};
+
+static const struct error_code scmi_linux_errmap[] = {
+ { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
+ { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
+ { .scmi = SCMI_DENIED, .errno = -EACCES, },
+ { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
+ { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
+ { .scmi = SCMI_BUSY, .errno = -EBUSY, },
+ { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
+ { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
+ { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
+ { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
+};
+
+int scmi_to_linux_errno(int32_t scmi_code)
+{
+ int n;
+
+ if (scmi_code == 0)
+ return 0;
+
+ for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
+ if (scmi_code == scmi_linux_errmap[n].scmi)
+ return scmi_linux_errmap[1].errno;
+
+ return -EPROTO;
+}
+
+struct method_ops {
+ int (*process_msg)(struct udevice *dev, struct scmi_msg *msg);
+ int (*remove_agent)(struct udevice *dev);
+};
+
+struct scmi_agent {
+ struct method_ops *method_ops;
+ void *method_priv;
+};
+
+/*
+ * Shared Memory based Transport (SMT) message buffer management
+ *
+ * SMT uses 28 byte header prior message payload to handle the state of
+ * the communication channel realized by the shared memory area and
+ * to define SCMI protocol information the payload relates to.
+ */
+struct scmi_smt_header {
+ __le32 reserved;
+ __le32 channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0)
+ __le32 reserved1[2];
+ __le32 flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0)
+ __le32 length;
+ __le32 msg_header;
+ u8 msg_payload[0];
+};
+
+#define SMT_HEADER_TOKEN(token) (((token) << 18) & GENMASK(31, 18))
+#define SMT_HEADER_PROTOCOL_ID(proto) (((proto) << 10) & GENMASK(17, 10))
+#define SMT_HEADER_MESSAGE_TYPE(type) (((type) << 18) & GENMASK(9, 8))
+#define SMT_HEADER_MESSAGE_ID(id) ((id) & GENMASK(7, 0))
+
+struct scmi_shm_buf {
+ u8 *buf;
+ size_t size;
+};
+
+static int get_shm_buffer(struct udevice *dev, struct scmi_shm_buf *shm)
+{
+ int rc;
+ struct ofnode_phandle_args args;
+ struct resource resource;
+ fdt32_t faddr;
+ phys_addr_t paddr;
+
+ rc = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
+ if (rc)
+ return rc;
+
+ rc = ofnode_read_resource(args.node, 0, &resource);
+ if (rc)
+ return rc;
+
+ faddr = cpu_to_fdt32(resource.start);
+ paddr = ofnode_translate_address(args.node, &faddr);
+
+ shm->size = resource_size(&resource);
+ if (shm->size < sizeof(struct scmi_smt_header)) {
+ dev_err(dev, "Shared memory buffer too small\n");
+ return -EINVAL;
+ }
+
+ shm->buf = devm_ioremap(dev, paddr, shm->size);
+ if (!shm->buf)
+ return -ENOMEM;
+
+ if (dcache_status())
+ mmu_set_region_dcache_behaviour((uintptr_t)shm->buf,
+ shm->size, DCACHE_OFF);
+
+ return 0;
+}
+
+/*
+ * Mailbox support
+ */
+struct scmi_mbox_channel {
+ struct scmi_shm_buf shm_buf;
+ struct mbox_chan mbox;
+ ulong timeout_us;
+};
+
+static int mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_mbox_channel *chan = agent->method_priv;
+ struct scmi_smt_header *hdr = (void *)chan->shm_buf.buf;
+ int rc;
+
+ /* Basic check-up */
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_dbg(dev, "Channel busy\n");
+ return -EBUSY;
+ }
+
+ if ((!msg->in_msg && msg->in_msg_sz) ||
+ (!msg->out_msg && msg->out_msg_sz))
+ return -EINVAL;
+
+ if (chan->shm_buf.size < (sizeof(*hdr) + msg->in_msg_sz) ||
+ chan->shm_buf.size < (sizeof(*hdr) + msg->out_msg_sz)) {
+ dev_dbg(dev, "Buffer too small\n");
+ return -ETOOSMALL;
+ }
+
+ /* Load message in shared memory */
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
+ hdr->msg_header = SMT_HEADER_TOKEN(0) |
+ SMT_HEADER_MESSAGE_TYPE(0) |
+ SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
+ SMT_HEADER_MESSAGE_ID(msg->message_id);
+
+ memcpy(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
+
+ /* Give shm addr to mbox in case it is meaningful */
+ rc = mbox_send(&chan->mbox, hdr);
+ if (rc) {
+ dev_err(dev, "Message send failed: %d\n", rc);
+ goto out;
+ }
+
+ /* Receive the response */
+ rc = mbox_recv(&chan->mbox, hdr, chan->timeout_us);
+ if (rc) {
+ dev_err(dev, "Response failed: %d, abort\n", rc);
+ goto out;
+ }
+
+ /* Check the statuses */
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_err(dev, "Channel unexpectedly busy, reset channel\n");
+ rc = -ECOMM;
+ goto out;
+ }
+
+ if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
+ dev_err(dev, "Channel error reported, reset channel\n");
+ rc = -ECOMM;
+ goto out;
+ }
+
+ if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
+ dev_err(dev, "Buffer to small\n");
+ rc = -ETOOSMALL;
+ goto out;
+ }
+
+ /* Get the data */
+ msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header);
+ memcpy(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
+
+out:
+ /* Free channel for further communication */
+ hdr->channel_status |= SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+
+ return rc;
+}
+
+struct method_ops mbox_channel_ops = {
+ .process_msg = mbox_process_msg,
+};
+
+static int probe_smc_mailbox_channel(struct udevice *dev)
+{
+ struct scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_mbox_channel *chan;
+ int rc;
+
+ chan = devm_kzalloc(dev, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ chan->timeout_us = 10000;
+
+ rc = mbox_get_by_index(dev, 0, &chan->mbox);
+ if (rc) {
+ dev_err(dev, "Failed to find mailbox: %d\n", rc);
+ goto out;
+ }
+
+ rc = get_shm_buffer(dev, &chan->shm_buf);
+ if (rc)
+ dev_err(dev, "Failed to get shm resources: %d\n", rc);
+
+out:
+ if (rc) {
+ devm_kfree(dev, chan);
+ } else {
+ agent->method_ops = &mbox_channel_ops;
+ agent->method_priv = (void *)chan;
+ }
+
+ return rc;
+}
+
+/*
+ * Exported functions by the SCMI agent
+ */
+
+int scmi_agent_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_agent *agent = dev_get_priv(dev);
+
+ return agent->method_ops->process_msg(dev, msg);
+}
+
+static int scmi_agent_remove(struct udevice *dev)
+{
+ struct scmi_agent *agent = dev_get_priv(dev);
+
+ if (agent->method_ops->remove_agent)
+ return agent->method_ops->remove_agent(dev);
+
+ return 0;
+}
+
+static int scmi_agent_probe(struct udevice *dev)
+{
+ /* Only mailbox method supported for now */
+ return probe_smc_mailbox_channel(dev);
+}
+
+static int scmi_agent_bind(struct udevice *dev)
+{
+ int rc = 0;
+ ofnode node;
+ struct driver *drv;
+
+ dev_for_each_subnode(node, dev) {
+ u32 protocol_id;
+
+ if (!ofnode_is_available(node))
+ continue;
+
+ if (ofnode_read_u32(node, "reg", &protocol_id))
+ continue;
+
+ switch (protocol_id) {
+ case SCMI_PROTOCOL_ID_CLOCK:
+ drv = DM_GET_DRIVER(scmi_clock);
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ drv = DM_GET_DRIVER(scmi_reset_domain);
+ break;
+ default:
+ dev_info(dev, "Ignore unsupported SCMI protocol %u\n",
+ protocol_id);
+ continue;
+ }
+
+ rc = device_bind_ofnode(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (rc)
+ break;
+ }
+
+ if (rc)
+ device_unbind(dev);
+
+ return rc;
+}
+
+static const struct udevice_id scmi_agent_ids[] = {
+ { .compatible = "arm,scmi", },
+ { }
+};
+
+U_BOOT_DRIVER(scmi_agent) = {
+ .name = "scmi-agent",
+ .id = UCLASS_NOP,
+ .of_match = scmi_agent_ids,
+ .priv_auto_alloc_size = sizeof(struct scmi_agent),
+ .bind = scmi_agent_bind,
+ .probe = scmi_agent_probe,
+ .remove = scmi_agent_remove,
+ .flags = DM_FLAG_OS_PREPARE,
+};
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index 0a7a2fe..9ad0504 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -673,7 +673,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
cfg->f_max = dev_read_u32_default(dev, "max-frequency", 52000000);
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
- cfg->name = "STM32 SDMMC2";
+ cfg->name = "STM32 SD/MMC";
cfg->host_caps = 0;
if (cfg->f_max > 25000000)
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 5e7571c..348b43e 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -22,6 +22,13 @@ config MTD_NOR_FLASH
help
Enable support for parallel NOR flash.
+config SYS_MTDPARTS_RUNTIME
+ bool "Allow MTDPARTS to be configured at runtime"
+ depends on MTD
+ help
+ This option allows to call the function board_mtdparts_default to
+ dynamically build the variables mtdids and mtdparts at runtime.
+
config FLASH_CFI_DRIVER
bool "Enable CFI Flash driver"
help
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 4632111..fad7810 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -305,6 +305,8 @@ struct eqos_priv {
struct clk clk_slave_bus;
struct mii_dev *mii;
struct phy_device *phy;
+ int phyaddr;
+ u32 max_speed;
void *descs;
struct eqos_desc *tx_descs;
struct eqos_desc *rx_descs;
@@ -693,6 +695,29 @@ static int eqos_start_resets_tegra186(struct udevice *dev)
static int eqos_start_resets_stm32(struct udevice *dev)
{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ int ret;
+
+ debug("%s(dev=%p):\n", __func__, dev);
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+ if (ret < 0) {
+ pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+ ret);
+ return ret;
+ }
+
+ udelay(2);
+
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
+ if (ret < 0) {
+ pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d",
+ ret);
+ return ret;
+ }
+ }
+ debug("%s: OK\n", __func__);
+
return 0;
}
@@ -708,6 +733,18 @@ static int eqos_stop_resets_tegra186(struct udevice *dev)
static int eqos_stop_resets_stm32(struct udevice *dev)
{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ int ret;
+
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+ if (ret < 0) {
+ pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+ ret);
+ return ret;
+ }
+ }
+
return 0;
}
@@ -1045,12 +1082,21 @@ static int eqos_start(struct udevice *dev)
* don't need to reconnect/reconfigure again
*/
if (!eqos->phy) {
- eqos->phy = phy_connect(eqos->mii, -1, dev,
+ eqos->phy = phy_connect(eqos->mii, eqos->phyaddr, dev,
eqos->config->interface(dev));
if (!eqos->phy) {
pr_err("phy_connect() failed");
goto err_stop_resets;
}
+
+ if (eqos->max_speed) {
+ ret = phy_set_supported(eqos->phy, eqos->max_speed);
+ if (ret) {
+ pr_err("phy_set_supported() failed: %d", ret);
+ goto err_shutdown_phy;
+ }
+ }
+
ret = phy_config(eqos->phy);
if (ret < 0) {
pr_err("phy_config() failed: %d", ret);
@@ -1603,6 +1649,9 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
struct eqos_priv *eqos = dev_get_priv(dev);
int ret;
phy_interface_t interface;
+ struct ofnode_phandle_args phandle_args;
+ /* Hardcode for now */
+ eqos->phyaddr = -1;
debug("%s(dev=%p):\n", __func__, dev);
@@ -1617,6 +1666,8 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
if (ret)
return -EINVAL;
+ eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
+
ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
if (ret) {
pr_err("clk_get_by_name(master_bus) failed: %d", ret);
@@ -1640,6 +1691,23 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
if (ret)
pr_warn("No phy clock provided %d", ret);
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+ &phandle_args);
+ if (!ret) {
+ /* search "reset-gpios" in phy node */
+ ret = gpio_request_by_name_nodev(phandle_args.node,
+ "reset-gpios", 0,
+ &eqos->phy_reset_gpio,
+ GPIOD_IS_OUT |
+ GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ pr_warn("gpio_request_by_name(phy reset) not provided %d",
+ ret);
+
+ eqos->phyaddr = ofnode_read_u32_default(phandle_args.node,
+ "reg", -1);
+ }
+
debug("%s: OK\n", __func__);
return 0;
@@ -1703,6 +1771,9 @@ static int eqos_remove_resources_stm32(struct udevice *dev)
if (clk_valid(&eqos->clk_ck))
clk_free(&eqos->clk_ck);
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
+ dm_gpio_free(dev, &eqos->phy_reset_gpio);
+
debug("%s: OK\n", __func__);
return 0;
}
diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c
index 6f11190..c122608 100644
--- a/drivers/phy/phy-stm32-usbphyc.c
+++ b/drivers/phy/phy-stm32-usbphyc.c
@@ -260,7 +260,7 @@ static int stm32_usbphyc_phy_power_off(struct phy *phy)
return 0;
if (usbphyc_phy->vdd) {
- ret = regulator_set_enable(usbphyc_phy->vdd, false);
+ ret = regulator_set_enable_if_allowed(usbphyc_phy->vdd, false);
if (ret)
return ret;
}
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
index e201a90..363985b 100644
--- a/drivers/phy/phy-uclass.c
+++ b/drivers/phy/phy-uclass.c
@@ -109,56 +109,86 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
int generic_phy_init(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!phy)
return 0;
ops = phy_dev_ops(phy->dev);
- return ops->init ? ops->init(phy) : 0;
+ ret = ops->init ? ops->init(phy) : 0;
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
}
int generic_phy_reset(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!phy)
return 0;
ops = phy_dev_ops(phy->dev);
- return ops->reset ? ops->reset(phy) : 0;
+ ret = ops->reset ? ops->reset(phy) : 0;
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
}
int generic_phy_exit(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!phy)
return 0;
ops = phy_dev_ops(phy->dev);
- return ops->exit ? ops->exit(phy) : 0;
+ ret = ops->exit ? ops->exit(phy) : 0;
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
}
int generic_phy_power_on(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!phy)
return 0;
ops = phy_dev_ops(phy->dev);
- return ops->power_on ? ops->power_on(phy) : 0;
+ ret = ops->power_on ? ops->power_on(phy) : 0;
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
}
int generic_phy_power_off(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!phy)
return 0;
ops = phy_dev_ops(phy->dev);
- return ops->power_off ? ops->power_off(phy) : 0;
+ ret = ops->power_off ? ops->power_off(phy) : 0;
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
+ phy->dev->name, ret);
+
+ return ret;
}
UCLASS_DRIVER(phy) = {
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
index eecf0f5..9c4f73b 100644
--- a/drivers/pinctrl/pinctrl-generic.c
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -8,8 +8,6 @@
#include <linux/compat.h>
#include <dm/pinctrl.h>
-DECLARE_GLOBAL_DATA_PTR;
-
/**
* pinctrl_pin_name_to_selector() - return the pin selector for a pin
*
@@ -243,18 +241,14 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
struct udevice *config,
bool is_group, unsigned selector)
{
- const void *fdt = gd->fdt_blob;
- int node_offset = dev_of_offset(config);
const char *propname;
const void *value;
- int prop_offset, len, func_selector, param, ret;
+ struct ofprop property;
+ int len, func_selector, param, ret;
u32 arg, default_val;
- for (prop_offset = fdt_first_property_offset(fdt, node_offset);
- prop_offset > 0;
- prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
- value = fdt_getprop_by_offset(fdt, prop_offset,
- &propname, &len);
+ dev_for_each_property(property, config) {
+ value = dev_read_prop_by_prop(&property, &propname, &len);
if (!value)
return -EINVAL;
@@ -298,19 +292,17 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
static int pinctrl_generic_set_state_subnode(struct udevice *dev,
struct udevice *config)
{
- const void *fdt = gd->fdt_blob;
- int node = dev_of_offset(config);
const char *subnode_target_type = "pins";
bool is_group = false;
const char *name;
int strings_count, selector, i, ret;
- strings_count = fdt_stringlist_count(fdt, node, subnode_target_type);
+ strings_count = dev_read_string_count(config, subnode_target_type);
if (strings_count < 0) {
subnode_target_type = "groups";
is_group = true;
- strings_count = fdt_stringlist_count(fdt, node,
- subnode_target_type);
+ strings_count = dev_read_string_count(config,
+ subnode_target_type);
if (strings_count < 0) {
/* skip this node; may contain config child nodes */
return 0;
@@ -318,10 +310,10 @@ static int pinctrl_generic_set_state_subnode(struct udevice *dev,
}
for (i = 0; i < strings_count; i++) {
- name = fdt_stringlist_get(fdt, node, subnode_target_type, i,
- NULL);
- if (!name)
- return -EINVAL;
+ ret = dev_read_string_index(config, subnode_target_type, i,
+ &name);
+ if (ret)
+ return ret;
if (is_group)
selector = pinctrl_group_name_to_selector(dev, name);
diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c
index 0786afe..3ee75fb 100644
--- a/drivers/pinctrl/pinctrl-sandbox.c
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -14,7 +14,11 @@ static const char * const sandbox_pins[] = {
"SDA",
"TX",
"RX",
- "W1"
+ "W1",
+ "GPIO0",
+ "GPIO1",
+ "GPIO2",
+ "GPIO3",
};
static const char * const sandbox_pins_muxing[] = {
@@ -23,6 +27,10 @@ static const char * const sandbox_pins_muxing[] = {
"Uart TX",
"Uart RX",
"1-wire gpio",
+ "gpio",
+ "gpio",
+ "gpio",
+ "gpio",
};
static const char * const sandbox_groups[] = {
@@ -38,6 +46,10 @@ static const char * const sandbox_functions[] = {
"serial",
"spi",
"w1",
+ "gpio",
+ "gpio",
+ "gpio",
+ "gpio",
};
static const struct pinconf_param sandbox_conf_params[] = {
@@ -54,6 +66,10 @@ static const struct pinconf_param sandbox_conf_params[] = {
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
};
+/* bitfield used to save param and value of each pin/selector */
+static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)];
+static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)];
+
static int sandbox_get_pins_count(struct udevice *dev)
{
return ARRAY_SIZE(sandbox_pins);
@@ -68,8 +84,25 @@ static int sandbox_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf, int size)
{
+ const struct pinconf_param *p;
+ int i;
+
snprintf(buf, size, "%s", sandbox_pins_muxing[selector]);
+ if (sandbox_pins_param[selector]) {
+ for (i = 0, p = sandbox_conf_params;
+ i < ARRAY_SIZE(sandbox_conf_params);
+ i++, p++) {
+ if ((sandbox_pins_param[selector] & BIT(p->param)) &&
+ (!!(sandbox_pins_value[selector] & BIT(p->param)) ==
+ p->default_value)) {
+ strncat(buf, " ", size);
+ strncat(buf, p->property, size);
+ }
+ }
+ }
+ strncat(buf, ".", size);
+
return 0;
}
@@ -102,6 +135,9 @@ static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
pin_selector, sandbox_get_pin_name(dev, pin_selector),
func_selector, sandbox_get_function_name(dev, func_selector));
+ sandbox_pins_param[pin_selector] = 0;
+ sandbox_pins_value[pin_selector] = 0;
+
return 0;
}
@@ -123,6 +159,12 @@ static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
pin_selector, sandbox_get_pin_name(dev, pin_selector),
param, argument);
+ sandbox_pins_param[pin_selector] |= BIT(param);
+ if (argument)
+ sandbox_pins_value[pin_selector] |= BIT(param);
+ else
+ sandbox_pins_value[pin_selector] &= ~BIT(param);
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 1dfc97d..6d8f989 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -9,8 +9,6 @@
#include <linux/libfdt.h>
#include <asm/io.h>
-DECLARE_GLOBAL_DATA_PTR;
-
struct single_pdata {
fdt_addr_t base; /* first configuration register */
int offset; /* index of last configuration register */
@@ -117,13 +115,11 @@ static int single_configure_bits(struct udevice *dev,
static int single_set_state(struct udevice *dev,
struct udevice *config)
{
- const void *fdt = gd->fdt_blob;
const struct single_fdt_pin_cfg *prop;
const struct single_fdt_bits_cfg *prop_bits;
int len;
- prop = fdt_getprop(fdt, dev_of_offset(config), "pinctrl-single,pins",
- &len);
+ prop = dev_read_prop(dev, "pinctrl-single,pins", &len);
if (prop) {
dev_dbg(dev, "configuring pins for %s\n", config->name);
@@ -136,9 +132,7 @@ static int single_set_state(struct udevice *dev,
}
/* pinctrl-single,pins not found so check for pinctrl-single,bits */
- prop_bits = fdt_getprop(fdt, dev_of_offset(config),
- "pinctrl-single,bits",
- &len);
+ prop_bits = dev_read_prop(dev, "pinctrl-single,bits", &len);
if (prop_bits) {
dev_dbg(dev, "configuring pins for %s\n", config->name);
if (len % sizeof(struct single_fdt_bits_cfg)) {
@@ -160,27 +154,24 @@ static int single_ofdata_to_platdata(struct udevice *dev)
int res;
struct single_pdata *pdata = dev->platdata;
- pdata->width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "pinctrl-single,register-width", 0);
+ pdata->width =
+ dev_read_u32_default(dev, "pinctrl-single,register-width", 0);
- res = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
- "reg", of_reg, 2);
+ res = dev_read_u32_array(dev, "reg", of_reg, 2);
if (res)
return res;
pdata->offset = of_reg[1] - pdata->width / 8;
- addr = devfdt_get_addr(dev);
+ addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE) {
dev_dbg(dev, "no valid base register address\n");
return -EINVAL;
}
pdata->base = addr;
- pdata->mask = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "pinctrl-single,function-mask",
- 0xffffffff);
- pdata->bits_per_mux = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
- "pinctrl-single,bit-per-mux");
+ pdata->mask = dev_read_u32_default(dev, "pinctrl-single,function-mask",
+ 0xffffffff);
+ pdata->bits_per_mux = dev_read_bool(dev, "pinctrl-single,bit-per-mux");
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index 0b5a043..b7987d5 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -71,17 +71,61 @@ static int stmfx_write(struct udevice *dev, uint offset, unsigned int val)
return dm_i2c_reg_write(dev_get_parent(dev), offset, val);
}
-static int stmfx_gpio_get(struct udevice *dev, unsigned int offset)
+static int stmfx_read_reg(struct udevice *dev, u8 reg_base, uint offset)
{
- u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset);
+ u8 reg = reg_base + get_reg(offset);
u32 mask = get_mask(offset);
int ret;
ret = stmfx_read(dev, reg);
+ if (ret < 0)
+ return ret;
return ret < 0 ? ret : !!(ret & mask);
}
+static int stmfx_write_reg(struct udevice *dev, u8 reg_base, uint offset,
+ uint val)
+{
+ u8 reg = reg_base + get_reg(offset);
+ u32 mask = get_mask(offset);
+ int ret;
+
+ ret = stmfx_read(dev, reg);
+ if (ret < 0)
+ return ret;
+ ret = (ret & ~mask) | (val ? mask : 0);
+
+ return stmfx_write(dev, reg, ret);
+}
+
+static int stmfx_conf_set_pupd(struct udevice *dev,
+ unsigned int offset, uint pupd)
+{
+ return stmfx_write_reg(dev, STMFX_REG_GPIO_PUPD, offset, pupd);
+}
+
+static int stmfx_conf_get_pupd(struct udevice *dev, unsigned int offset)
+{
+ return stmfx_read_reg(dev, STMFX_REG_GPIO_PUPD, offset);
+}
+
+static int stmfx_conf_set_type(struct udevice *dev,
+ unsigned int offset, uint type)
+{
+ return stmfx_write_reg(dev, STMFX_REG_GPIO_TYPE, offset, type);
+}
+
+static int stmfx_conf_get_type(struct udevice *dev, unsigned int offset)
+{
+ return stmfx_read_reg(dev, STMFX_REG_GPIO_TYPE, offset);
+}
+
+static int stmfx_gpio_get(struct udevice *dev, unsigned int offset)
+{
+ return stmfx_read_reg(dev, STMFX_REG_GPIO_STATE, offset);
+}
+
static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value)
{
u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR;
@@ -92,50 +136,103 @@ static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value)
static int stmfx_gpio_get_function(struct udevice *dev, unsigned int offset)
{
- u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
- u32 mask = get_mask(offset);
- int ret;
-
- ret = stmfx_read(dev, reg);
+ int ret = stmfx_read_reg(dev, STMFX_REG_GPIO_DIR, offset);
if (ret < 0)
return ret;
/* On stmfx, gpio pins direction is (0)input, (1)output. */
- return ret & mask ? GPIOF_OUTPUT : GPIOF_INPUT;
+ return ret ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static int stmfx_gpio_direction_input(struct udevice *dev, unsigned int offset)
{
- u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
- u32 mask = get_mask(offset);
- int ret;
+ return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 0);
+}
- ret = stmfx_read(dev, reg);
+static int stmfx_gpio_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ int ret = stmfx_gpio_set(dev, offset, value);
if (ret < 0)
return ret;
- ret &= ~mask;
+ return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1);
+}
- return stmfx_write(dev, reg, ret & ~mask);
+static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ int ret = -ENOTSUPP;
+
+ if (flags & GPIOD_IS_OUT) {
+ if (flags & GPIOD_OPEN_SOURCE)
+ return -ENOTSUPP;
+ if (flags & GPIOD_OPEN_DRAIN)
+ ret = stmfx_conf_set_type(dev, offset, 0);
+ else /* PUSH-PULL */
+ ret = stmfx_conf_set_type(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = stmfx_gpio_direction_output(dev, offset,
+ GPIOD_FLAGS_OUTPUT(flags));
+ } else if (flags & GPIOD_IS_IN) {
+ ret = stmfx_gpio_direction_input(dev, offset);
+ if (ret)
+ return ret;
+ if (flags & GPIOD_PULL_UP) {
+ ret = stmfx_conf_set_type(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = stmfx_conf_set_pupd(dev, offset, 1);
+ } else if (flags & GPIOD_PULL_DOWN) {
+ ret = stmfx_conf_set_type(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = stmfx_conf_set_pupd(dev, offset, 0);
+ }
+ }
+
+ return ret;
}
-static int stmfx_gpio_direction_output(struct udevice *dev,
- unsigned int offset, int value)
+static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
+ ulong *flags)
{
- u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
- u32 mask = get_mask(offset);
+ ulong dir_flags = 0;
int ret;
- ret = stmfx_gpio_set(dev, offset, value);
- if (ret < 0)
- return ret;
-
- ret = stmfx_read(dev, reg);
- if (ret < 0)
- return ret;
+ if (stmfx_gpio_get_function(dev, offset) == GPIOF_OUTPUT) {
+ dir_flags |= GPIOD_IS_OUT;
+ ret = stmfx_conf_get_type(dev, offset);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ dir_flags |= GPIOD_OPEN_DRAIN;
+ /* 1 = push-pull (default), open source not supported */
+ ret = stmfx_gpio_get(dev, offset);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ } else {
+ dir_flags |= GPIOD_IS_IN;
+ ret = stmfx_conf_get_type(dev, offset);
+ if (ret < 0)
+ return ret;
+ if (ret == 1) {
+ ret = stmfx_conf_get_pupd(dev, offset);
+ if (ret < 0)
+ return ret;
+ if (ret == 1)
+ dir_flags |= GPIOD_PULL_UP;
+ else
+ dir_flags |= GPIOD_PULL_DOWN;
+ }
+ }
+ *flags = dir_flags;
- return stmfx_write(dev, reg, ret | mask);
+ return 0;
}
static int stmfx_gpio_probe(struct udevice *dev)
@@ -166,6 +263,8 @@ static const struct dm_gpio_ops stmfx_gpio_ops = {
.get_function = stmfx_gpio_get_function,
.direction_input = stmfx_gpio_direction_input,
.direction_output = stmfx_gpio_direction_output,
+ .set_dir_flags = stmfx_gpio_set_dir_flags,
+ .get_dir_flags = stmfx_gpio_get_dir_flags,
};
U_BOOT_DRIVER(stmfx_gpio) = {
@@ -187,36 +286,6 @@ static const struct pinconf_param stmfx_pinctrl_conf_params[] = {
{ "output-low", PIN_CONFIG_OUTPUT, 0 },
};
-static int stmfx_pinctrl_set_pupd(struct udevice *dev,
- unsigned int pin, u32 pupd)
-{
- u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin);
- u32 mask = get_mask(pin);
- int ret;
-
- ret = stmfx_read(dev, reg);
- if (ret < 0)
- return ret;
- ret = (ret & ~mask) | (pupd ? mask : 0);
-
- return stmfx_write(dev, reg, ret);
-}
-
-static int stmfx_pinctrl_set_type(struct udevice *dev,
- unsigned int pin, u32 type)
-{
- u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin);
- u32 mask = get_mask(pin);
- int ret;
-
- ret = stmfx_read(dev, reg);
- if (ret < 0)
- return ret;
- ret = (ret & ~mask) | (type ? mask : 0);
-
- return stmfx_write(dev, reg, ret);
-}
-
static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg)
{
@@ -232,22 +301,22 @@ static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin,
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);
+ ret = stmfx_conf_set_type(dev, pin, 0);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- ret = stmfx_pinctrl_set_type(dev, pin, 1);
+ ret = stmfx_conf_set_type(dev, pin, 1);
if (ret)
return ret;
- ret = stmfx_pinctrl_set_pupd(dev, pin, 0);
+ ret = stmfx_conf_set_pupd(dev, pin, 0);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- ret = stmfx_pinctrl_set_type(dev, pin, 1);
+ ret = stmfx_conf_set_type(dev, pin, 1);
if (ret)
return ret;
- ret = stmfx_pinctrl_set_pupd(dev, pin, 1);
+ ret = stmfx_conf_set_pupd(dev, pin, 1);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- ret = stmfx_pinctrl_set_type(dev, pin, 1);
+ ret = stmfx_conf_set_type(dev, pin, 1);
break;
case PIN_CONFIG_OUTPUT:
ret = stmfx_gpio_direction_output(plat->gpio, pin, arg);
@@ -286,6 +355,34 @@ static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev,
return pin_name;
}
+static const char *stmfx_pinctrl_get_pin_conf(struct udevice *dev,
+ unsigned int pin, int func)
+{
+ int pupd, type;
+
+ type = stmfx_conf_get_type(dev, pin);
+ if (type < 0)
+ return "";
+
+ if (func == GPIOF_OUTPUT) {
+ if (type)
+ return "drive-open-drain";
+ else
+ return ""; /* default: push-pull*/
+ }
+ if (!type)
+ return ""; /* default: bias-disable*/
+
+ pupd = stmfx_conf_get_pupd(dev, pin);
+ if (pupd < 0)
+ return "";
+
+ if (pupd)
+ return "bias-pull-up";
+ else
+ return "bias-pull-down";
+}
+
static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf, int size)
@@ -297,7 +394,9 @@ static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev,
if (func < 0)
return func;
- snprintf(buf, size, "%s", func == GPIOF_INPUT ? "input" : "output");
+ snprintf(buf, size, "%s ", func == GPIOF_INPUT ? "input" : "output");
+
+ strncat(buf, stmfx_pinctrl_get_pin_conf(dev, selector, func), size);
return 0;
}
@@ -351,11 +450,12 @@ static int stmfx_chip_init(struct udevice *dev)
int ret;
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
- id = dm_i2c_reg_read(dev, STMFX_REG_CHIP_ID);
- if (id < 0) {
- dev_err(dev, "error reading chip id: %d\n", id);
+ ret = dm_i2c_reg_read(dev, STMFX_REG_CHIP_ID);
+ if (ret < 0) {
+ dev_err(dev, "error reading chip id: %d\n", ret);
return ret;
}
+ id = (u8)ret;
/*
* Check that ID is the complement of the I2C address:
* STMFX I2C address follows the 7-bit format (MSB), that's why
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
index 3a235ae..4511cd7 100644
--- a/drivers/pinctrl/pinctrl_stm32.c
+++ b/drivers/pinctrl/pinctrl_stm32.c
@@ -39,6 +39,17 @@ static const char * const pinmux_mode[PINMUX_MODE_COUNT] = {
"alt function",
};
+static const char * const pinmux_output[] = {
+ [STM32_GPIO_PUPD_NO] = "bias-disable",
+ [STM32_GPIO_PUPD_UP] = "bias-pull-up",
+ [STM32_GPIO_PUPD_DOWN] = "bias-pull-down",
+};
+
+static const char * const pinmux_input[] = {
+ [STM32_GPIO_OTYPE_PP] = "drive-push-pull",
+ [STM32_GPIO_OTYPE_OD] = "drive-open-drain",
+};
+
static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
@@ -176,10 +187,12 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev,
int size)
{
struct udevice *gpio_dev;
+ struct stm32_gpio_priv *priv;
const char *label;
int mode;
int af_num;
unsigned int gpio_idx;
+ u32 pupd, otype;
/* look up for the bank which owns the requested pin */
gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
@@ -188,9 +201,9 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev,
return -ENODEV;
mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label);
-
dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n",
selector, gpio_idx, mode);
+ priv = dev_get_priv(gpio_dev);
switch (mode) {
@@ -205,9 +218,17 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev,
snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num);
break;
case GPIOF_OUTPUT:
+ pupd = (readl(&priv->regs->pupdr) >> (gpio_idx * 2)) &
+ PUPD_MASK;
+ snprintf(buf, size, "%s %s %s",
+ pinmux_mode[mode], pinmux_output[pupd],
+ label ? label : "");
+ break;
case GPIOF_INPUT:
- snprintf(buf, size, "%s %s",
- pinmux_mode[mode], label ? label : "");
+ otype = (readl(&priv->regs->otyper) >> gpio_idx) & OTYPE_MSK;
+ snprintf(buf, size, "%s %s %s",
+ pinmux_mode[mode], pinmux_input[otype],
+ label ? label : "");
break;
}
diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c
index 645528e..c8ff6a1 100644
--- a/drivers/power/regulator/stm32-vrefbuf.c
+++ b/drivers/power/regulator/stm32-vrefbuf.c
@@ -41,8 +41,20 @@ static int stm32_vrefbuf_set_enable(struct udevice *dev, bool enable)
u32 val;
int ret;
- clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ | STM32_ENVR,
- enable ? STM32_ENVR : STM32_HIZ);
+ if (enable && !(readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR)) {
+ /*
+ * There maybe an overshoot:
+ * - when disabling, then re-enabling vrefbuf too quickly
+ * - or upon platform reset as external capacitor maybe slow
+ * discharging (VREFBUF is HiZ at reset by default).
+ * So force active discharge (HiZ=0) for 1ms before enabling.
+ */
+ clrbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ);
+ udelay(1000);
+ }
+
+ clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR,
+ enable ? STM32_ENVR : 0);
if (!enable)
return 0;
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
index d765a46..11b14ae 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -639,7 +639,8 @@ void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
start_sw_done(ctl);
/* quasi-dynamic register update*/
setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
- clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN |
+ DDRCTRL_PWRCTL_SELFREF_EN);
clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
@@ -652,6 +653,8 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN)
setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN))
+ setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN);
setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
@@ -668,14 +671,34 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
{
u32 pir;
int ret = -EINVAL;
+ char bus_width;
+
+ switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
+ bus_width = 8;
+ break;
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
+ bus_width = 16;
+ break;
+ default:
+ bus_width = 32;
+ break;
+ }
+
if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
ret = board_ddr_power_init(STM32MP_DDR3);
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2)
- ret = board_ddr_power_init(STM32MP_LPDDR2);
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3)
- ret = board_ddr_power_init(STM32MP_LPDDR3);
-
+ else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) {
+ if (bus_width == 32)
+ ret = board_ddr_power_init(STM32MP_LPDDR2_32);
+ else
+ ret = board_ddr_power_init(STM32MP_LPDDR2_16);
+ } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) {
+ if (bus_width == 32)
+ ret = board_ddr_power_init(STM32MP_LPDDR3_32);
+ else
+ ret = board_ddr_power_init(STM32MP_LPDDR3_16);
+ }
if (ret)
panic("ddr power init failed\n");
@@ -746,7 +769,8 @@ start:
*/
set_reg(priv, REGPHY_REG, &config->p_reg);
set_reg(priv, REGPHY_TIMING, &config->p_timing);
- set_reg(priv, REGPHY_CAL, &config->p_cal);
+ if (config->p_cal_present)
+ set_reg(priv, REGPHY_CAL, &config->p_cal);
if (INTERACTIVE(STEP_PHY_INIT))
goto start;
@@ -781,13 +805,16 @@ start:
wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
- debug("DDR DQS training : ");
+ if (config->p_cal_present) {
+ debug("DDR DQS training skipped.\n");
+ } else {
+ debug("DDR DQS training : ");
/* 8. Disable Auto refresh and power down by setting
* - RFSHCTL3.dis_au_refresh = 1
* - PWRCTL.powerdown_en = 0
* - DFIMISC.dfiinit_complete_en = 0
*/
- stm32mp1_refresh_disable(priv->ctl);
+ stm32mp1_refresh_disable(priv->ctl);
/* 9. Program PUBL PGCR to enable refresh during training and rank to train
* not done => keep the programed value in PGCR
@@ -795,14 +822,15 @@ start:
/* 10. configure PUBL PIR register to specify which training step to run */
/* warning : RVTRN is not supported by this PUBL */
- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
- ddrphy_idone_wait(priv->phy);
+ ddrphy_idone_wait(priv->phy);
/* 12. set back registers in step 8 to the orginal values if desidered */
- stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
- config->c_reg.pwrctl);
+ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+ config->c_reg.pwrctl);
+ } /* if (config->p_cal_present) */
/* enable uMCTL2 AXI port 0 and 1 */
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
index 52b748f..4998f04 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -170,6 +170,7 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrphy_reg p_reg;
struct stm32mp1_ddrphy_timing p_timing;
struct stm32mp1_ddrphy_cal p_cal;
+ bool p_cal_present;
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
index 9d33186..afd93c5 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
@@ -260,6 +260,7 @@ struct stm32mp1_ddrphy {
#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0)
+#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0)
#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
index cc9b2e7..805c9dd 100644
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -106,7 +106,7 @@ static void stm32mp1_do_usage(void)
"help displays help\n"
"info displays DDR information\n"
"info <param> <val> changes DDR information\n"
- " with <param> = step, name, size or speed\n"
+ " with <param> = step, name, size, speed or cal\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"
@@ -160,6 +160,7 @@ static void stm32mp1_do_info(struct ddr_info *priv,
printf("name = %s\n", config->info.name);
printf("size = 0x%x\n", config->info.size);
printf("speed = %d kHz\n", config->info.speed);
+ printf("cal = %d\n", config->p_cal_present);
return;
}
@@ -208,6 +209,16 @@ static void stm32mp1_do_info(struct ddr_info *priv,
}
return;
}
+ if (!strcmp(argv[1], "cal")) {
+ if (strict_strtoul(argv[2], 10, &value) < 0 ||
+ (value != 0 && value != 1)) {
+ printf("invalid value %s\n", argv[2]);
+ } else {
+ config->p_cal_present = value;
+ printf("cal = %d\n", config->p_cal_present);
+ }
+ return;
+ }
printf("argument %s invalid\n", argv[1]);
}
@@ -367,7 +378,6 @@ bool stm32mp1_ddr_interactive(void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config)
{
- const char *prompt = "DDR>";
char buffer[CONFIG_SYS_CBSIZE];
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
int argc;
@@ -403,13 +413,12 @@ bool stm32mp1_ddr_interactive(void *priv,
}
printf("%d:%s\n", step, step_str[step]);
- printf("%s\n", prompt);
if (next_step > step)
return false;
while (next_step == step) {
- cli_readline_into_buffer(prompt, buffer, 0);
+ cli_readline_into_buffer("DDR>", buffer, 0);
argc = cli_simple_parse_line(buffer, argv);
if (!argc)
continue;
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index a362cf9..c54f314 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -64,18 +64,22 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
struct clk axidcg;
struct stm32mp1_ddr_config config;
-#define PARAM(x, y) \
- { x,\
- offsetof(struct stm32mp1_ddr_config, y),\
- sizeof(config.y) / sizeof(u32)}
+#define PARAM(x, y, z) \
+ { .name = x, \
+ .offset = offsetof(struct stm32mp1_ddr_config, y), \
+ .size = sizeof(config.y) / sizeof(u32), \
+ .present = z, \
+ }
-#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
-#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
+#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
const struct {
const char *name; /* name in DT */
const u32 offset; /* offset in config struct */
const u32 size; /* size of parameters */
+ bool * const present; /* presence indication for opt */
} param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
@@ -83,7 +87,7 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
CTL_PARAM(perf),
PHY_PARAM(reg),
PHY_PARAM(timing),
- PHY_PARAM(cal)
+ PHY_PARAM_OPT(cal)
};
config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
@@ -102,11 +106,25 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
param[idx].size);
debug("%s: %s[0x%x] = %d\n", __func__,
param[idx].name, param[idx].size, ret);
- if (ret) {
+ if (ret &&
+ (ret != -FDT_ERR_NOTFOUND || !param[idx].present)) {
pr_err("%s: Cannot read %s, error=%d\n",
__func__, param[idx].name, ret);
return -EINVAL;
}
+ if (param[idx].present) {
+ /* save presence of optional parameters */
+ *param[idx].present = true;
+ if (ret == -FDT_ERR_NOTFOUND) {
+ *param[idx].present = false;
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+ /* reset values if used later */
+ memset((void *)((u32)&config +
+ param[idx].offset),
+ 0, param[idx].size * sizeof(u32));
+#endif
+ }
+ }
}
ret = clk_get_by_name(dev, "axidcg", &axidcg);
diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c
index 581ee48..cc7b429 100644
--- a/drivers/ram/stm32mp1/stm32mp1_tests.c
+++ b/drivers/ram/stm32mp1/stm32mp1_tests.c
@@ -14,7 +14,7 @@
DECLARE_GLOBAL_DATA_PTR;
static int get_bufsize(char *string, int argc, char *argv[], int arg_nb,
- size_t *bufsize, size_t default_size)
+ size_t *bufsize, size_t default_size, size_t min_size)
{
unsigned long value;
@@ -24,8 +24,9 @@ static int get_bufsize(char *string, int argc, char *argv[], int arg_nb,
arg_nb, argv[arg_nb]);
return -1;
}
- if (value > STM32_DDR_SIZE || value == 0) {
- sprintf(string, "invalid size %s", argv[arg_nb]);
+ if (value > STM32_DDR_SIZE || value < min_size) {
+ sprintf(string, "invalid size %s (min=%d)",
+ argv[arg_nb], min_size);
return -1;
}
if (value & 0x3) {
@@ -438,7 +439,7 @@ static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl,
u32 bufsize;
u32 error;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (!is_power_of_2(bufsize)) {
sprintf(string, "size 0x%x is not a power of 2",
@@ -467,7 +468,7 @@ static enum test_result test_memdevice(struct stm32mp1_ddrctl *ctl,
size_t bufsize;
u32 error;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (get_addr(string, argc, argv, 1, &addr))
return TEST_ERROR;
@@ -509,7 +510,7 @@ static enum test_result test_sso(struct stm32mp1_ddrctl *ctl,
u32 error = 0;
u32 data;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (get_addr(string, argc, argv, 1, &addr))
return TEST_ERROR;
@@ -581,7 +582,7 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl,
u32 error = 0;
unsigned int seed;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 8 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -741,7 +742,7 @@ static enum test_result test_noise_burst(struct stm32mp1_ddrctl *ctl,
int i;
enum test_result res = TEST_PASSED;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128))
return TEST_ERROR;
if (get_pattern(string, argc, argv, 1, &pattern, 0xFFFFFFFF))
return TEST_ERROR;
@@ -917,7 +918,7 @@ static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl,
const u32 **patterns;
u32 bufsize;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128))
return TEST_ERROR;
switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
@@ -1004,7 +1005,7 @@ static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl,
u32 checkboard[2] = {0x55555555, 0xAAAAAAAA};
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -1039,7 +1040,7 @@ static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl,
u32 bufsize, nb_loop, loop = 0, addr, value;
int i;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -1073,7 +1074,7 @@ static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl,
u32 bufsize, nb_loop, loop = 0, addr, value;
int i;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -1111,7 +1112,7 @@ static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl,
u32 bufsize, nb_loop, loop = 0, addr, value;
int i;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -1153,7 +1154,7 @@ static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl,
u32 bufsize, nb_loop, loop = 0, addr, bitspread[4];
int i, j;
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
@@ -1200,7 +1201,7 @@ static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl,
u32 bitflip[4];
- if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32))
return TEST_ERROR;
if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
return TEST_ERROR;
diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c
index 4e1c1fa..3013b7b 100644
--- a/drivers/ram/stm32mp1/stm32mp1_tuning.c
+++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c
@@ -8,6 +8,8 @@
#include <ram.h>
#include <reset.h>
#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
#include "stm32mp1_ddr_regs.h"
#include "stm32mp1_ddr.h"
@@ -75,6 +77,133 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl)
return nb_bytes;
}
+static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count bank address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap1);
+ /* addrmap1.addrmap_bank_b1 */
+ val = (reg & GENMASK(5, 0)) >> 0;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b2 */
+ val = (reg & GENMASK(13, 8)) >> 8;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b3 */
+ val = (reg & GENMASK(21, 16)) >> 16;
+ if (val <= 31)
+ bits++;
+
+ return bits;
+}
+
+static u8 get_nb_col(struct stm32mp1_ddrctl *ctl)
+{
+ u8 bits;
+ u32 reg, val;
+
+ /* Count column address bits, start at 2 for b0 and b1 (fixed) */
+ bits = 2;
+
+ reg = readl(&ctl->addrmap2);
+ /* addrmap2.addrmap_col_b2 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b3 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b4 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b5 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap3);
+ /* addrmap3.addrmap_col_b6 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b7 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b8 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b9 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap4);
+ /* addrmap4.addrmap_col_b10 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap4.addrmap_col_b11 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+
+ return bits;
+}
+
+static u8 get_nb_row(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count row address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap5);
+ /* addrmap5.addrmap_row_b0 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b1 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b2_10 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 11)
+ bits += 9;
+ else
+ printf("warning: addrmap5.addrmap_row_b2_10 not supported\n");
+ /* addrmap5.addrmap_row_b11 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 11)
+ bits++;
+
+ reg = readl(&ctl->addrmap6);
+ /* addrmap6.addrmap_row_b12 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b13 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b14 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b15 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ return bits;
+}
+
static void itm_soft_reset(struct stm32mp1_ddrphy *phy)
{
stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
@@ -169,8 +298,13 @@ static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy,
}
/* Basic BIST configuration for data lane tests. */
-static void config_BIST(struct stm32mp1_ddrphy *phy)
+static void config_BIST(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy)
{
+ u8 nb_bank = get_nb_bank(ctl);
+ u8 nb_row = get_nb_row(ctl);
+ u8 nb_col = get_nb_col(ctl);
+
/* Selects the SDRAM bank address to be used during BIST. */
u32 bbank = 0;
/* Selects the SDRAM row address to be used during BIST. */
@@ -190,18 +324,20 @@ static void config_BIST(struct stm32mp1_ddrphy *phy)
* must be 0 with single rank
*/
u32 brank = 0;
+
/* Specifies the maximum SDRAM bank address to be used during
* BIST before the address & increments to the next rank.
*/
- u32 bmbank = 1;
+ u32 bmbank = (1 << nb_bank) - 1;
/* Specifies the maximum SDRAM row address to be used during
* BIST before the address & increments to the next bank.
*/
- u32 bmrow = 0x7FFF; /* To check */
+ u32 bmrow = (1 << nb_row) - 1;
/* Specifies the maximum SDRAM column address to be used during
* BIST before the address & increments to the next row.
*/
- u32 bmcol = 0x3FF; /* To check */
+ u32 bmcol = (1 << nb_col) - 1;
+
u32 bmode_conf = 0x00000001; /* DRam mode */
u32 bdxen_conf = 0x00000001; /* BIST on Data byte */
u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */
@@ -223,8 +359,6 @@ static void config_BIST(struct stm32mp1_ddrphy *phy)
writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0);
writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1);
-
- /* To check this line : */
writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2);
}
@@ -246,6 +380,8 @@ static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte,
bool result = true; /* BIST_SUCCESS */
u32 cnt = 0;
u32 error = 0;
+ u32 val;
+ int ret;
bist->test_result = true;
@@ -266,7 +402,7 @@ run:
writel(rand(), &phy->bistlsr);
/* some delay to reset BIST */
- mdelay(1);
+ udelay(10);
/*Perform BIST Run*/
clrsetbits_le32(&phy->bistrr,
@@ -274,27 +410,29 @@ run:
0x00000001);
/* Write BISTRR.BINST = 3?b001; */
- /* Wait for a number of CTL clocks before reading BIST register*/
- /* Wait 300 ctl_clk cycles; ... IS it really needed?? */
- /* Perform BIST Instruction Stop*/
- /* Write BISTRR.BINST = 3?b010;*/
-
- /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */
- while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE))
- ;
-
- /*Check if received correct number of words*/
- /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
- if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) ==
- readl(&phy->bistwcr)) {
- /*Determine if there is a data comparison error*/
- /* if (Read BISTGSR.BDXERR = 1?b0) */
- if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
- result = false; /* BIST_FAIL; */
- else
- result = true; /* BIST_SUCCESS; */
- } else {
+ /* poll on BISTGSR.BDONE and wait max 1000 us */
+ ret = readl_poll_timeout(&phy->bistgsr, val,
+ val & DDRPHYC_BISTGSR_BDDONE, 1000);
+
+ if (ret < 0) {
+ printf("warning: BIST timeout\n");
result = false; /* BIST_FAIL; */
+ /*Perform BIST Stop */
+ clrsetbits_le32(&phy->bistrr, 0x00000007, 0x00000002);
+ } else {
+ /*Check if received correct number of words*/
+ /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
+ if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT)
+ == readl(&phy->bistwcr)) {
+ /*Determine if there is a data comparison error*/
+ /* if (Read BISTGSR.BDXERR = 1?b0) */
+ if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
+ result = false; /* BIST_FAIL; */
+ else
+ result = true; /* BIST_SUCCESS; */
+ } else {
+ result = false; /* BIST_FAIL; */
+ }
}
/* loop while success */
@@ -394,7 +532,7 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* Config the BIST block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
pr_debug("BIST Config done.\n");
/* Train each byte */
@@ -807,7 +945,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* Config the BIST block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
for (byte = 0; byte < nb_bytes; byte++) {
if (ctrlc()) {
@@ -1182,15 +1320,17 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte,
dqs_gate_values[byte][0],
dqs_gate_values[byte][1]);
pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n");
- set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
- set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
}
} else {
/* if intermitant, restore defaut values */
pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n");
- set_r0dgsl_delay(phy, byte, 0);
- set_r0dgps_delay(phy, byte, 2);
+ dqs_gate_values[byte][0] = 0;
+ dqs_gate_values[byte][1] = 2;
}
+ set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
+ set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
+ printf("Byte %d, R0DGSL = %d, R0DGPS = %d\n",
+ byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]);
/* return 0 if intermittent or if both left_bound
* and right_bound are not found
@@ -1227,7 +1367,7 @@ static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* config the bist block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
for (byte = 0; byte < nb_bytes; byte++) {
if (ctrlc()) {
@@ -1281,11 +1421,16 @@ static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = read_dqs_gating(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
@@ -1296,11 +1441,16 @@ static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = bit_deskew(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
@@ -1311,11 +1461,16 @@ static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = eye_training(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index e8026cd..5384812 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -8,6 +8,39 @@
#include <elf.h>
#include <remoteproc.h>
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * A resource table is essentially a list of system resources required
+ * by the remote processor. It may also include configuration entries.
+ * If needed, the remote processor firmware should contain this table
+ * as a dedicated ".resource_table" ELF section.
+ *
+ * Some resources entries are mere announcements, where the host is informed
+ * of specific remoteproc configuration. Other entries require the host to
+ * do something (e.g. allocate a system resource). Sometimes a negotiation
+ * is expected, where the firmware requests a resource, and once allocated,
+ * the host should provide back its details (e.g. address of an allocated
+ * memory region).
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ *
+ * Immediately following this header are the resource entries themselves.
+ */
+struct resource_table {
+ u32 ver;
+ u32 num;
+ u32 reserved[2];
+ u32 offset[0];
+} __packed;
+
/* Basic function to verify ELF32 image format */
int rproc_elf32_sanity_check(ulong addr, ulong size)
{
@@ -276,3 +309,239 @@ ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
else
return rproc_elf32_get_boot_addr(addr);
}
+
+/*
+ * Search for the resource table in an ELF32 image.
+ * Returns the address of the resource table section if found, NULL if there is
+ * no resource table section, or error pointer.
+ */
+static Elf32_Shdr *rproc_elf32_find_rsc_table(struct udevice *dev,
+ ulong fw_addr, ulong fw_size)
+{
+ int ret;
+ unsigned int i;
+ const char *name_table;
+ struct resource_table *table;
+ const u8 *elf_data = (void *)fw_addr;
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
+ Elf32_Shdr *shdr;
+
+ ret = rproc_elf32_sanity_check(fw_addr, fw_size);
+ if (ret) {
+ pr_debug("Invalid ELF32 Image %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ /* look for the resource table and handle it */
+ shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff);
+ name_table = (const char *)(elf_data +
+ shdr[ehdr->e_shstrndx].sh_offset);
+
+ for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+ u32 size = shdr->sh_size;
+ u32 offset = shdr->sh_offset;
+
+ if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+ continue;
+
+ table = (struct resource_table *)(elf_data + offset);
+
+ /* make sure we have the entire table */
+ if (offset + size > fw_size) {
+ pr_debug("resource table truncated\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* make sure table has at least the header */
+ if (sizeof(*table) > size) {
+ pr_debug("header-less resource table\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* we don't support any version beyond the first */
+ if (table->ver != 1) {
+ pr_debug("unsupported fw ver: %d\n", table->ver);
+ return ERR_PTR(-EPROTONOSUPPORT);
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (table->reserved[0] || table->reserved[1]) {
+ pr_debug("non zero reserved bytes\n");
+ return ERR_PTR(-EBADF);
+ }
+
+ /* make sure the offsets array isn't truncated */
+ if (table->num * sizeof(table->offset[0]) +
+ sizeof(*table) > size) {
+ pr_debug("resource table incomplete\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ return shdr;
+ }
+
+ return NULL;
+}
+
+/* Load the resource table from an ELF32 image */
+int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+{
+ const struct dm_rproc_ops *ops;
+ Elf32_Shdr *shdr;
+ void *src, *dst;
+
+ shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
+ if (!shdr)
+ return -ENODATA;
+ if (IS_ERR(shdr))
+ return PTR_ERR(shdr);
+
+ ops = rproc_get_ops(dev);
+ *rsc_addr = (ulong)shdr->sh_addr;
+ *rsc_size = (ulong)shdr->sh_size;
+
+ src = (void *)fw_addr + shdr->sh_offset;
+ if (ops->device_to_virt)
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ else
+ dst = (void *)rsc_addr;
+
+ dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
+ (ulong)dst, *rsc_size);
+
+ memcpy(dst, src, *rsc_size);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + *rsc_size,
+ ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+
+ return 0;
+}
+
+/*
+ * Search for the resource table in an ELF64 image.
+ * Returns the address of the resource table section if found, NULL if there is
+ * no resource table section, or error pointer.
+ */
+static Elf64_Shdr *rproc_elf64_find_rsc_table(struct udevice *dev,
+ ulong fw_addr, ulong fw_size)
+{
+ int ret;
+ unsigned int i;
+ const char *name_table;
+ struct resource_table *table;
+ const u8 *elf_data = (void *)fw_addr;
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)fw_addr;
+ Elf64_Shdr *shdr;
+
+ ret = rproc_elf64_sanity_check(fw_addr, fw_size);
+ if (ret) {
+ pr_debug("Invalid ELF64 Image %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ /* look for the resource table and handle it */
+ shdr = (Elf64_Shdr *)(elf_data + ehdr->e_shoff);
+ name_table = (const char *)(elf_data +
+ shdr[ehdr->e_shstrndx].sh_offset);
+
+ for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+ u64 size = shdr->sh_size;
+ u64 offset = shdr->sh_offset;
+
+ if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+ continue;
+
+ table = (struct resource_table *)(elf_data + offset);
+
+ /* make sure we have the entire table */
+ if (offset + size > fw_size) {
+ pr_debug("resource table truncated\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* make sure table has at least the header */
+ if (sizeof(*table) > size) {
+ pr_debug("header-less resource table\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ /* we don't support any version beyond the first */
+ if (table->ver != 1) {
+ pr_debug("unsupported fw ver: %d\n", table->ver);
+ return ERR_PTR(-EPROTONOSUPPORT);
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (table->reserved[0] || table->reserved[1]) {
+ pr_debug("non zero reserved bytes\n");
+ return ERR_PTR(-EBADF);
+ }
+
+ /* make sure the offsets array isn't truncated */
+ if (table->num * sizeof(table->offset[0]) +
+ sizeof(*table) > size) {
+ pr_debug("resource table incomplete\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ return shdr;
+ }
+
+ return NULL;
+}
+
+/* Load the resource table from an ELF64 image */
+int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+{
+ const struct dm_rproc_ops *ops;
+ Elf64_Shdr *shdr;
+ void *src, *dst;
+
+ shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size);
+ if (!shdr)
+ return -ENODATA;
+ if (IS_ERR(shdr))
+ return PTR_ERR(shdr);
+
+ ops = rproc_get_ops(dev);
+ *rsc_addr = (ulong)shdr->sh_addr;
+ *rsc_size = (ulong)shdr->sh_size;
+
+ src = (void *)fw_addr + shdr->sh_offset;
+ if (ops->device_to_virt)
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ else
+ dst = (void *)rsc_addr;
+
+ dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
+ (ulong)dst, *rsc_size);
+
+ memcpy(dst, src, *rsc_size);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + *rsc_size,
+ ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+
+ return 0;
+}
+
+/* Load the resource table from an ELF32 or ELF64 image */
+int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
+
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
+
+ if (!fw_addr)
+ return -EFAULT;
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ return rproc_elf64_load_rsc_table(dev, fw_addr, fw_size,
+ rsc_addr, rsc_size);
+ else
+ return rproc_elf32_load_rsc_table(dev, fw_addr, fw_size,
+ rsc_addr, rsc_size);
+}
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
index 40bba37..b8e62e5 100644
--- a/drivers/remoteproc/stm32_copro.c
+++ b/drivers/remoteproc/stm32_copro.c
@@ -12,6 +12,7 @@
#include <reset.h>
#include <syscon.h>
#include <asm/io.h>
+#include <asm/arch/stm32mp1_smc.h>
#define RCC_GCR_HOLD_BOOT 0
#define RCC_GCR_RELEASE_BOOT 1
@@ -22,14 +23,16 @@
* @hold_boot_regmap: regmap for remote processor reset hold boot
* @hold_boot_offset: offset of the register controlling the hold boot setting
* @hold_boot_mask: bitmask of the register for the hold boot field
- * @is_running: is the remote processor running
+ * @secured_soc: TZEN flag (register protection)
+ * @rsc_table_addr: resource table address
*/
struct stm32_copro_privdata {
struct reset_ctl reset_ctl;
struct regmap *hold_boot_regmap;
uint hold_boot_offset;
uint hold_boot_mask;
- bool is_running;
+ bool secured_soc;
+ ulong rsc_table_addr;
};
/**
@@ -42,6 +45,7 @@ static int stm32_copro_probe(struct udevice *dev)
struct stm32_copro_privdata *priv;
struct regmap *regmap;
const fdt32_t *cell;
+ uint tz_offset, tz_mask, tzen;
int len, ret;
priv = dev_get_priv(dev);
@@ -69,6 +73,31 @@ static int stm32_copro_probe(struct udevice *dev)
return ret;
}
+ regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-tz");
+ if (IS_ERR(regmap)) {
+ dev_dbg(dev, "unable to find tz regmap (%ld)\n",
+ PTR_ERR(regmap));
+ return -EINVAL;
+ }
+
+ cell = dev_read_prop(dev, "st,syscfg-tz", &len);
+ if (3 * sizeof(fdt32_t) - len > 0) {
+ dev_dbg(dev, "tz offset and mask not available\n");
+ return -EINVAL;
+ }
+
+ tz_offset = fdtdec_get_number(cell + 1, 1);
+
+ tz_mask = fdtdec_get_number(cell + 2, 1);
+
+ ret = regmap_read(regmap, tz_offset, &tzen);
+ if (ret) {
+ dev_dbg(dev, "failed to read soc secure state\n");
+ return ret;
+ }
+
+ priv->secured_soc = !!(tzen & tz_mask);
+
dev_dbg(dev, "probed\n");
return 0;
@@ -90,6 +119,11 @@ static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
+ if (priv->secured_soc) {
+ return stm32_smc_exec(STM32_SMC_RCC, STM32_SMC_REG_WRITE,
+ priv->hold_boot_offset, val);
+ }
+
/*
* Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
* To be updated when the code for this SMC service is available which
@@ -141,6 +175,7 @@ static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
{
struct stm32_copro_privdata *priv;
+ ulong rsc_table_size;
int ret;
priv = dev_get_priv(dev);
@@ -155,6 +190,12 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
return ret;
}
+ if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr,
+ &rsc_table_size)) {
+ priv->rsc_table_addr = 0;
+ dev_warn(dev, "No valid resource table for this firmware\n");
+ }
+
return rproc_elf32_load_image(dev, addr, size);
}
@@ -180,7 +221,12 @@ static int stm32_copro_start(struct udevice *dev)
* rebooting autonomously
*/
ret = stm32_copro_set_hold_boot(dev, true);
- priv->is_running = !ret;
+ writel(ret ? TAMP_COPRO_STATE_OFF : TAMP_COPRO_STATE_CRUN,
+ TAMP_COPRO_STATE);
+ if (!ret)
+ /* Store rsc_address in bkp register */
+ writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS);
+
return ret;
}
@@ -206,7 +252,7 @@ static int stm32_copro_reset(struct udevice *dev)
return ret;
}
- priv->is_running = false;
+ writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE);
return 0;
}
@@ -224,14 +270,11 @@ static int stm32_copro_stop(struct udevice *dev)
/**
* stm32_copro_is_running() - Is the STM32 remote processor running
* @dev: corresponding STM32 remote processor device
- * @return 1 if the remote processor is running, 0 otherwise
+ * @return 0 if the remote processor is running, 1 otherwise
*/
static int stm32_copro_is_running(struct udevice *dev)
{
- struct stm32_copro_privdata *priv;
-
- priv = dev_get_priv(dev);
- return priv->is_running;
+ return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF);
}
static const struct dm_rproc_ops stm32_copro_ops = {
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 75ccd65..4c92c49 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -148,4 +148,12 @@ config RESET_IMX7
help
Support for reset controller on i.MX7/8 SoCs.
+config RESET_SCMI
+ bool "Enable SCMI reset domain driver"
+ select SCMI_AGENT
+ help
+ Enable this option if you want to support reset controller
+ devices exposed by a SCMI agent based on SCMI reset domain
+ protocol communication with a SCMI server.
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 0a044d5..1ce9760 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
+obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
new file mode 100644
index 0000000..8f4c895
--- /dev/null
+++ b/drivers/reset/reset-scmi.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Linaro Limited
+ */
+#include <asm/types.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <scmi_agent.h>
+
+enum scmi_reset_domain_message_id {
+ SCMI_RESET_DOMAIN_RESET = 0x4,
+};
+
+#define SCMI_RD_RESET_FLAG_ASSERT BIT(1)
+#define SCMI_RD_RESET_FLAG_DEASSERT 0
+
+struct scmi_rd_reset_in {
+ u32 domain_id;
+ u32 flags;
+ u32 reset_state;
+};
+
+struct scmi_rd_reset_out {
+ s32 status;
+};
+
+static int scmi_reset_set_state(struct reset_ctl *rst, int assert_not_deassert)
+{
+ struct scmi_rd_reset_in in = {
+ .domain_id = rst->id,
+ .flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT :
+ SCMI_RD_RESET_FLAG_DEASSERT,
+ .reset_state = 0,
+ };
+ struct scmi_rd_reset_out out;
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ .message_id = SCMI_RESET_DOMAIN_RESET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int rc;
+
+ rc = scmi_agent_process_msg(rst->dev->parent, &scmi_msg);
+ if (rc)
+ return rc;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_reset_assert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_state(rst, SCMI_RD_RESET_FLAG_ASSERT);
+}
+
+static int scmi_reset_deassert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_state(rst, SCMI_RD_RESET_FLAG_DEASSERT);
+}
+
+static int scmi_reset_request(struct reset_ctl *reset_ctl)
+{
+ return 0;
+}
+
+static int scmi_reset_free(struct reset_ctl *reset_ctl)
+{
+ return 0;
+}
+
+static const struct reset_ops scmi_reset_domain_ops = {
+ .request = scmi_reset_request,
+ .free = scmi_reset_free,
+ .rst_assert = scmi_reset_assert,
+ .rst_deassert = scmi_reset_deassert,
+};
+
+U_BOOT_DRIVER(scmi_reset_domain) = {
+ .name = "scmi_reset_domain",
+ .id = UCLASS_RESET,
+ .ops = &scmi_reset_domain_ops,
+};
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 7f870f2..8a0009b 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -510,7 +510,7 @@ static bool is_optee_api(optee_invoke_fn *invoke_fn)
res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3;
}
-static void print_os_revision(optee_invoke_fn *invoke_fn)
+static void print_os_revision(struct udevice *dev, optee_invoke_fn *invoke_fn)
{
union {
struct arm_smccc_res smccc;
@@ -525,11 +525,12 @@ static void print_os_revision(optee_invoke_fn *invoke_fn)
&res.smccc);
if (res.result.build_id)
- debug("OP-TEE revision %lu.%lu (%08lx)\n", res.result.major,
- res.result.minor, res.result.build_id);
+ dev_info(dev, "OP-TEE: revision %lu.%lu (%08lx)\n",
+ res.result.major, res.result.minor,
+ res.result.build_id);
else
- debug("OP-TEE revision %lu.%lu\n", res.result.major,
- res.result.minor);
+ dev_info(dev, "OP-TEE: revision %lu.%lu\n",
+ res.result.major, res.result.minor);
}
static bool api_revision_is_compatible(optee_invoke_fn *invoke_fn)
@@ -624,7 +625,7 @@ static int optee_probe(struct udevice *dev)
return -ENOENT;
}
- print_os_revision(pdata->invoke_fn);
+ print_os_revision(dev, pdata->invoke_fn);
if (!api_revision_is_compatible(pdata->invoke_fn)) {
debug("%s: OP-TEE api revision mismatch\n", __func__);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 77c555e..988cf02 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -864,8 +864,8 @@ int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys)
for (i = 0; i < count; i++) {
ret = generic_phy_init(&usb_phys[i]);
if (ret) {
- pr_err("Can't init USB PHY%d for %s\n",
- i, dev->name);
+ pr_debug("Can't init USB PHY%d for %s\n",
+ i, dev->name);
goto phys_init_err;
}
}
@@ -873,8 +873,8 @@ int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys)
for (i = 0; i < count; i++) {
ret = generic_phy_power_on(&usb_phys[i]);
if (ret) {
- pr_err("Can't power USB PHY%d for %s\n",
- i, dev->name);
+ pr_debug("Can't power USB PHY%d for %s\n",
+ i, dev->name);
goto phys_poweron_err;
}
}
@@ -910,8 +910,8 @@ int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys)
ret = generic_phy_power_off(&usb_phys[i]);
ret |= generic_phy_exit(&usb_phys[i]);
if (ret) {
- pr_err("Can't shutdown USB PHY%d for %s\n",
- i, dev->name);
+ pr_debug("Can't shutdown USB PHY%d for %s\n",
+ i, dev->name);
}
}
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index 35f4147..35495e4 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -980,7 +980,7 @@ int dwc2_phy_setup(struct udevice *dev, struct phy **array, int *num_phys)
for (i = 0; i < count; i++) {
ret = generic_phy_init(&usb_phys[i]);
if (ret) {
- dev_err(dev, "Can't init USB PHY%d for %s\n",
+ dev_dbg(dev, "Can't init USB PHY%d for %s\n",
i, dev->name);
goto phys_init_err;
}
@@ -989,7 +989,7 @@ int dwc2_phy_setup(struct udevice *dev, struct phy **array, int *num_phys)
for (i = 0; i < count; i++) {
ret = generic_phy_power_on(&usb_phys[i]);
if (ret) {
- dev_err(dev, "Can't power USB PHY%d for %s\n",
+ dev_dbg(dev, "Can't power USB PHY%d for %s\n",
i, dev->name);
goto phys_poweron_err;
}
@@ -1027,7 +1027,7 @@ void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys)
ret = generic_phy_power_off(&usb_phys[i]);
ret |= generic_phy_exit(&usb_phys[i]);
if (ret) {
- dev_err(dev, "Can't shutdown USB PHY%d for %s\n",
+ dev_dbg(dev, "Can't shutdown USB PHY%d for %s\n",
i, dev->name);
}
}
diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index e9e1600..7a51b53 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -89,6 +89,14 @@ static struct usb_gadget_strings *g_dnl_composite_strings[] = {
NULL,
};
+void g_dnl_set_product(const char *s)
+{
+ if (s)
+ g_dnl_string_defs[1].s = s;
+ else
+ g_dnl_string_defs[1].s = product;
+}
+
static int g_dnl_unbind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index b9c56f7..2fbb8b8 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -5,13 +5,15 @@
*/
#include <common.h>
+#include <clk.h>
#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
-#include <usb.h>
+#include <generic-phy.h>
#include <malloc.h>
#include <memalign.h>
#include <phys2bus.h>
+#include <usb.h>
#include <usbroothubdes.h>
#include <wait_bit.h>
#include <asm/io.h>
@@ -36,6 +38,8 @@ struct dwc2_priv {
#ifdef CONFIG_DM_REGULATOR
struct udevice *vbus_supply;
#endif
+ struct phy phy;
+ struct clk_bulk clks;
#else
uint8_t *aligned_buffer;
uint8_t *status_buffer;
@@ -1146,6 +1150,8 @@ static int dwc2_reset(struct udevice *dev)
return ret;
}
+ /* force reset to clear all IP register */
+ reset_assert_bulk(&priv->resets);
ret = reset_deassert_bulk(&priv->resets);
if (ret) {
reset_release_bulk(&priv->resets);
@@ -1212,6 +1218,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
mdelay(1000);
+ printf("USB DWC2\n");
+
return 0;
}
@@ -1321,13 +1329,113 @@ static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
return 0;
}
+static int dwc2_setup_phy(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+ if (ret) {
+ if (ret == -ENOENT)
+ return 0; /* no PHY, nothing to do */
+ dev_err(dev, "Failed to get USB PHY: %d.\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_dbg(dev, "Failed to init USB PHY: %d.\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_dbg(dev, "Failed to power on USB PHY: %d.\n", ret);
+ generic_phy_exit(&priv->phy);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dwc2_shutdown_phy(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* PHY is not valid when generic_phy_get_by_index() = -ENOENT */
+ if (!generic_phy_valid(&priv->phy))
+ return 0; /* no PHY, nothing to do */
+
+ ret = generic_phy_power_off(&priv->phy);
+ if (ret) {
+ dev_dbg(dev, "Failed to power off USB PHY: %d.\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_exit(&priv->phy);
+ if (ret) {
+ dev_dbg(dev, "Failed to power off USB PHY: %d.\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dwc2_clk_init(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret == -ENOSYS || ret == -ENOENT)
+ return 0;
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret) {
+ clk_release_bulk(&priv->clks);
+ return ret;
+ }
+
+ return 0;
+}
+
static int dwc2_usb_probe(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
+ int ret;
bus_priv->desc_before_addr = true;
+ ret = dwc2_clk_init(dev);
+ if (ret)
+ return ret;
+
+ ret = dwc2_setup_phy(dev);
+ if (ret)
+ return ret;
+
+ if (CONFIG_IS_ENABLED(ARCH_STM32MP) &&
+ device_is_compatible(dev, "st,stm32mp1-hsotg")) {
+ struct udevice *usb33d_supply;
+
+ ret = device_get_supply_regulator(dev, "usb33d-supply",
+ &usb33d_supply);
+ if (ret) {
+ dev_err(dev,
+ "can't get voltage level detector supply\n");
+ } else {
+ ret = regulator_set_enable(usb33d_supply, true);
+ if (ret) {
+ dev_err(dev,
+ "can't enable voltage level detector supply\n");
+ }
+ }
+ }
+
return dwc2_init_common(dev, priv);
}
@@ -1340,9 +1448,17 @@ static int dwc2_usb_remove(struct udevice *dev)
if (ret)
return ret;
+ ret = dwc2_shutdown_phy(dev);
+ if (ret) {
+ dev_dbg(dev, "Failed to shutdown USB PHY: %d.\n", ret);
+ return ret;
+ }
+
dwc2_uninit_common(priv->regs);
reset_release_bulk(&priv->resets);
+ clk_disable_bulk(&priv->clks);
+ clk_release_bulk(&priv->clks);
return 0;
}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ef20c3c..0c31775 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1698,13 +1698,13 @@ int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index)
} else {
ret = generic_phy_init(phy);
if (ret) {
- dev_err(dev, "failed to init usb phy\n");
+ dev_dbg(dev, "failed to init usb phy\n");
return ret;
}
ret = generic_phy_power_on(phy);
if (ret) {
- dev_err(dev, "failed to power on usb phy\n");
+ dev_dbg(dev, "failed to power on usb phy\n");
return generic_phy_exit(phy);
}
}
@@ -1722,13 +1722,13 @@ int ehci_shutdown_phy(struct udevice *dev, struct phy *phy)
if (generic_phy_valid(phy)) {
ret = generic_phy_power_off(phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
ret = generic_phy_exit(phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c
index 916ea0b..e8cf26a 100644
--- a/drivers/usb/host/ohci-generic.c
+++ b/drivers/usb/host/ohci-generic.c
@@ -38,13 +38,13 @@ static int ohci_setup_phy(struct udevice *dev, int index)
} else {
ret = generic_phy_init(&priv->phy);
if (ret) {
- dev_err(dev, "failed to init usb phy\n");
+ dev_dbg(dev, "failed to init usb phy\n");
return ret;
}
ret = generic_phy_power_on(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power on usb phy\n");
+ dev_dbg(dev, "failed to power on usb phy\n");
return generic_phy_exit(&priv->phy);
}
}
@@ -60,13 +60,13 @@ static int ohci_shutdown_phy(struct udevice *dev)
if (generic_phy_valid(&priv->phy)) {
ret = generic_phy_power_off(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
ret = generic_phy_exit(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 45eecfe..3b36ab3 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -252,7 +252,7 @@ static int sunxi_musb_enable(struct musb *musb)
ret = generic_phy_power_on(&glue->phy);
if (ret) {
- pr_err("failed to power on USB PHY\n");
+ pr_debug("failed to power on USB PHY\n");
return ret;
}
}
@@ -276,7 +276,7 @@ static void sunxi_musb_disable(struct musb *musb)
if (is_host_enabled(musb)) {
ret = generic_phy_power_off(&glue->phy);
if (ret) {
- pr_err("failed to power off USB PHY\n");
+ pr_debug("failed to power off USB PHY\n");
return;
}
}
@@ -310,7 +310,7 @@ static int sunxi_musb_init(struct musb *musb)
ret = generic_phy_init(&glue->phy);
if (ret) {
- dev_err(dev, "failed to init USB PHY\n");
+ dev_dbg(dev, "failed to init USB PHY\n");
goto err_rst;
}
@@ -347,7 +347,7 @@ static int sunxi_musb_exit(struct musb *musb)
if (generic_phy_valid(&glue->phy)) {
ret = generic_phy_exit(&glue->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/video/orisetech_otm8009a.c b/drivers/video/orisetech_otm8009a.c
index 89d9cfd..629bf76 100644
--- a/drivers/video/orisetech_otm8009a.c
+++ b/drivers/video/orisetech_otm8009a.c
@@ -60,9 +60,6 @@
struct otm8009a_panel_priv {
struct udevice *reg;
struct gpio_desc reset;
- unsigned int lanes;
- enum mipi_dsi_pixel_format format;
- unsigned long mode_flags;
};
static const struct display_timing default_timing = {
@@ -291,17 +288,8 @@ static int otm8009a_panel_enable_backlight(struct udevice *dev)
static int otm8009a_panel_get_display_timing(struct udevice *dev,
struct display_timing *timings)
{
- struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
- struct mipi_dsi_device *device = plat->device;
- struct otm8009a_panel_priv *priv = dev_get_priv(dev);
-
memcpy(timings, &default_timing, sizeof(*timings));
- /* fill characteristics of DSI data link */
- device->lanes = priv->lanes;
- device->format = priv->format;
- device->mode_flags = priv->mode_flags;
-
return 0;
}
@@ -333,6 +321,7 @@ static int otm8009a_panel_ofdata_to_platdata(struct udevice *dev)
static int otm8009a_panel_probe(struct udevice *dev)
{
struct otm8009a_panel_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
int ret;
if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
@@ -348,9 +337,10 @@ static int otm8009a_panel_probe(struct udevice *dev)
dm_gpio_set_value(&priv->reset, false);
mdelay(10); /* >5ms */
- priv->lanes = 2;
- priv->format = MIPI_DSI_FMT_RGB888;
- priv->mode_flags = MIPI_DSI_MODE_VIDEO |
+ /* fill characteristics of DSI data link */
+ plat->lanes = 2;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM;
diff --git a/drivers/video/raydium-rm68200.c b/drivers/video/raydium-rm68200.c
index 91555e2..76b0ed2 100644
--- a/drivers/video/raydium-rm68200.c
+++ b/drivers/video/raydium-rm68200.c
@@ -73,9 +73,6 @@ struct rm68200_panel_priv {
struct udevice *reg;
struct udevice *backlight;
struct gpio_desc reset;
- unsigned int lanes;
- enum mipi_dsi_pixel_format format;
- unsigned long mode_flags;
};
static const struct display_timing default_timing = {
@@ -257,17 +254,8 @@ static int rm68200_panel_enable_backlight(struct udevice *dev)
static int rm68200_panel_get_display_timing(struct udevice *dev,
struct display_timing *timings)
{
- struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
- struct mipi_dsi_device *device = plat->device;
- struct rm68200_panel_priv *priv = dev_get_priv(dev);
-
memcpy(timings, &default_timing, sizeof(*timings));
- /* fill characteristics of DSI data link */
- device->lanes = priv->lanes;
- device->format = priv->format;
- device->mode_flags = priv->mode_flags;
-
return 0;
}
@@ -306,6 +294,7 @@ static int rm68200_panel_ofdata_to_platdata(struct udevice *dev)
static int rm68200_panel_probe(struct udevice *dev)
{
struct rm68200_panel_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
int ret;
if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
@@ -320,9 +309,10 @@ static int rm68200_panel_probe(struct udevice *dev)
dm_gpio_set_value(&priv->reset, false);
mdelay(10);
- priv->lanes = 2;
- priv->format = MIPI_DSI_FMT_RGB888;
- priv->mode_flags = MIPI_DSI_MODE_VIDEO |
+ /* fill characteristics of DSI data link */
+ plat->lanes = 2;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM;
diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c
index 12895a8..022ae96 100644
--- a/drivers/video/stm32/stm32_dsi.c
+++ b/drivers/video/stm32/stm32_dsi.c
@@ -268,7 +268,6 @@ static int dsi_get_lane_mbps(void *priv_data, struct display_timing *timings,
u32 val;
/* Update lane capabilities according to hw version */
- dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
dsi->lane_min_kbps = LANE_MIN_KBPS;
dsi->lane_max_kbps = LANE_MAX_KBPS;
if (dsi->hw_version == HWVER_131) {
@@ -351,6 +350,9 @@ static int stm32_dsi_attach(struct udevice *dev)
mplat = dev_get_platdata(priv->panel);
mplat->device = &priv->device;
+ device->lanes = mplat->lanes;
+ device->format = mplat->format;
+ device->mode_flags = mplat->mode_flags;
ret = panel_get_display_timing(priv->panel, &timings);
if (ret) {
@@ -472,6 +474,17 @@ static int stm32_dsi_probe(struct udevice *dev)
/* Reset */
reset_deassert(&rst);
+ /* check hardware version */
+ priv->hw_version = dsi_read(priv, DSI_VERSION) & VERSION;
+ if (priv->hw_version != HWVER_130 &&
+ priv->hw_version != HWVER_131) {
+ dev_err(dev, "bad dsi hardware version\n");
+ clk_disable(&clk);
+ if (IS_ENABLED(CONFIG_DM_REGULATOR))
+ regulator_set_enable(priv->vdd_reg, false);
+ return -ENODEV;
+ }
+
return 0;
err_clk:
clk_disable(&clk);
diff --git a/env/mmc.c b/env/mmc.c
index b24c35c..f64c993 100644
--- a/env/mmc.c
+++ b/env/mmc.c
@@ -24,14 +24,25 @@
DECLARE_GLOBAL_DATA_PTR;
+#if !defined(CONFIG_SYS_MMC_ENV_DEV)
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#endif
+
+__weak int mmc_get_env_dev(void)
+{
+ return CONFIG_SYS_MMC_ENV_DEV;
+}
+
#if CONFIG_IS_ENABLED(OF_CONTROL)
-static inline int mmc_offset_try_partition(const char *str, s64 *val)
+static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val)
{
disk_partition_t info;
struct blk_desc *desc;
int len, i, ret;
+ char dev_str[4];
- ret = blk_get_device_by_str("mmc", STR(CONFIG_SYS_MMC_ENV_DEV), &desc);
+ snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev());
+ ret = blk_get_device_by_str("mmc", dev_str, &desc);
if (ret < 0)
return (ret);
@@ -45,10 +56,10 @@ static inline int mmc_offset_try_partition(const char *str, s64 *val)
}
/* round up to info.blksz */
- len = (CONFIG_ENV_SIZE + info.blksz - 1) & ~(info.blksz - 1);
+ len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz);
/* use the top of the partion for the environment */
- *val = (info.start + info.size - 1) - len / info.blksz;
+ *val = (info.start + info.size - (1 + copy) * len) * info.blksz;
return 0;
}
@@ -73,7 +84,7 @@ static inline s64 mmc_offset(int copy)
str = fdtdec_get_config_string(gd->fdt_blob, dt_prop.partition);
if (str) {
/* try to place the environment at end of the partition */
- err = mmc_offset_try_partition(str, &val);
+ err = mmc_offset_try_partition(str, copy, &val);
if (!err)
return val;
}
@@ -114,11 +125,6 @@ __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
return 0;
}
-__weak int mmc_get_env_dev(void)
-{
- return CONFIG_SYS_MMC_ENV_DEV;
-}
-
#ifdef CONFIG_SYS_MMC_ENV_PART
__weak uint mmc_get_env_part(struct mmc *mmc)
{
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d6cf187..ec48770 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -117,11 +117,14 @@ struct udevice;
struct gpio_desc {
struct udevice *dev; /* Device, NULL for invalid GPIO */
unsigned long flags;
-#define GPIOD_REQUESTED (1 << 0) /* Requested/claimed */
-#define GPIOD_IS_OUT (1 << 1) /* GPIO is an output */
-#define GPIOD_IS_IN (1 << 2) /* GPIO is an input */
-#define GPIOD_ACTIVE_LOW (1 << 3) /* value has active low */
-#define GPIOD_IS_OUT_ACTIVE (1 << 4) /* set output active */
+#define GPIOD_IS_OUT BIT(1) /* GPIO is an output */
+#define GPIOD_IS_IN BIT(2) /* GPIO is an input */
+#define GPIOD_ACTIVE_LOW BIT(3) /* GPIO is active when value is low */
+#define GPIOD_IS_OUT_ACTIVE BIT(4) /* set output active */
+#define GPIOD_OPEN_DRAIN BIT(5) /* GPIO is open drain type */
+#define GPIOD_OPEN_SOURCE BIT(6) /* GPIO is open source type */
+#define GPIOD_PULL_UP BIT(7) /* GPIO has pull-up enabled */
+#define GPIOD_PULL_DOWN BIT(8) /* GPIO has pull-down enabled */
uint offset; /* GPIO offset within the device */
/*
@@ -130,6 +133,12 @@ struct gpio_desc {
*/
};
+/* helper to compute the value of the gpio output */
+#define GPIOD_FLAGS_OUTPUT_MASK (GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE)
+#define GPIOD_FLAGS_OUTPUT(flags) \
+ (((((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_IS_OUT_ACTIVE) || \
+ (((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_ACTIVE_LOW)))
+
/**
* dm_gpio_is_valid() - Check if a GPIO is valid
*
@@ -254,8 +263,6 @@ struct dm_gpio_ops {
int value);
int (*get_value)(struct udevice *dev, unsigned offset);
int (*set_value)(struct udevice *dev, unsigned offset, int value);
- int (*get_open_drain)(struct udevice *dev, unsigned offset);
- int (*set_open_drain)(struct udevice *dev, unsigned offset, int value);
/**
* get_function() Get the GPIO function
*
@@ -290,6 +297,37 @@ struct dm_gpio_ops {
*/
int (*xlate)(struct udevice *dev, struct gpio_desc *desc,
struct ofnode_phandle_args *args);
+
+ /**
+ * set_dir_flags() - Set GPIO dir flags
+ *
+ * This function should set up the GPIO configuration according to the
+ * information provide by the direction flags bitfield.
+ *
+ * This method is optional.
+ *
+ * @dev: GPIO device
+ * @offset: GPIO offset within that device
+ * @flags: GPIO configuration to use
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_dir_flags)(struct udevice *dev, unsigned int offset,
+ ulong flags);
+
+ /**
+ * get_dir_flags() - Get GPIO dir flags
+ *
+ * This function return the GPIO direction flags used.
+ *
+ * This method is optional.
+ *
+ * @dev: GPIO device
+ * @offset: GPIO offset within that device
+ * @flags: place to put the used direction flags by GPIO
+ * @return 0 if OK, -ve on error
+ */
+ int (*get_dir_flags)(struct udevice *dev, unsigned int offset,
+ ulong *flags);
};
/**
@@ -587,63 +625,41 @@ int dm_gpio_get_value(const struct gpio_desc *desc);
int dm_gpio_set_value(const struct gpio_desc *desc, int value);
/**
- * dm_gpio_get_open_drain() - Check if open-drain-mode of a GPIO is active
- *
- * This checks if open-drain-mode for a GPIO is enabled or not. This method is
- * optional.
- *
- * @desc: GPIO description containing device, offset and flags,
- * previously returned by gpio_request_by_name()
- * @return Value of open drain mode for GPIO (0 for inactive, 1 for active) or
- * -ve on error
- */
-int dm_gpio_get_open_drain(struct gpio_desc *desc);
-
-/**
- * dm_gpio_set_open_drain() - Switch open-drain-mode of a GPIO on or off
- *
- * This enables or disables open-drain mode for a GPIO. This method is
- * optional; if the driver does not support it, nothing happens when the method
- * is called.
+ * dm_gpio_set_dir() - Set the direction for a GPIO
*
- * In open-drain mode, instead of actively driving the output (Push-pull
- * output), the GPIO's pin is connected to the collector (for a NPN transistor)
- * or the drain (for a MOSFET) of a transistor, respectively. The pin then
- * either forms an open circuit or a connection to ground, depending on the
- * state of the transistor.
+ * This sets up the direction according to the GPIO flags: desc->flags.
*
* @desc: GPIO description containing device, offset and flags,
* previously returned by gpio_request_by_name()
* @return 0 if OK, -ve on error
*/
-int dm_gpio_set_open_drain(struct gpio_desc *desc, int value);
+int dm_gpio_set_dir(struct gpio_desc *desc);
/**
- * dm_gpio_set_dir() - Set the direction for a GPIO
+ * dm_gpio_set_dir_flags() - Set direction using description and added flags
*
- * This sets up the direction according tot the provided flags. It will do
- * nothing unless the direction is actually specified.
+ * This sets up the direction according to the provided flags and the GPIO
+ * description (desc->flags) which include direction information.
+ * Note that desc->flags is updated by this function.
*
* @desc: GPIO description containing device, offset and flags,
* previously returned by gpio_request_by_name()
- * @return 0 if OK, -ve on error
+ * @flags: New flags to use
+ * @return 0 if OK, -ve on error, in which case desc->flags is not updated
*/
-int dm_gpio_set_dir(struct gpio_desc *desc);
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
/**
- * dm_gpio_set_dir_flags() - Set direction using specific flags
+ * dm_gpio_get_dir_flags() - Get direction flags
*
- * This is like dm_gpio_set_dir() except that the flags value is provided
- * instead of being used from desc->flags. This is needed because in many
- * cases the GPIO description does not include direction information.
- * Note that desc->flags is updated by this function.
+ * read the current direction flags
*
* @desc: GPIO description containing device, offset and flags,
* previously returned by gpio_request_by_name()
- * @flags: New flags to use
+ * @flags: place to put the used flags
* @return 0 if OK, -ve on error, in which case desc->flags is not updated
*/
-int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
+int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags);
/**
* gpio_get_number() - Get the global GPIO number of a GPIO
diff --git a/include/clk.h b/include/clk.h
index a5ee53d..950b5da 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -9,6 +9,7 @@
#define _CLK_H_
#include <dm/ofnode.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -221,6 +222,8 @@ static inline int clk_get_by_index(struct udevice *dev, int index,
static inline int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
{
+ if (bulk)
+ bulk->count = 0;
return -ENOSYS;
}
@@ -272,6 +275,7 @@ static inline int clk_release_bulk(struct clk_bulk *bulk)
return clk_release_all(bulk->clks, bulk->count);
}
+#if CONFIG_IS_ENABLED(CLK)
/**
* clk_request - Request a clock by provider-specific ID.
*
@@ -393,19 +397,6 @@ int clk_disable_bulk(struct clk_bulk *bulk);
*/
bool clk_is_match(const struct clk *p, const struct clk *q);
-int soc_clk_dump(void);
-
-/**
- * clk_valid() - check if clk is valid
- *
- * @clk: the clock to check
- * @return true if valid, or false
- */
-static inline bool clk_valid(struct clk *clk)
-{
- return clk && !!clk->dev;
-}
-
/**
* clk_get_by_id() - Get the clock by its ID
*
@@ -425,6 +416,93 @@ int clk_get_by_id(ulong id, struct clk **clkp);
* @return true on binded, or false on no
*/
bool clk_dev_binded(struct clk *clk);
+
+#else /* CONFIG_IS_ENABLED(CLK) */
+
+static inline int clk_request(struct udevice *dev, struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline int clk_free(struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline ulong clk_get_rate(struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline struct clk *clk_get_parent(struct clk *clk)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline long long clk_get_parent_rate(struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline ulong clk_set_rate(struct clk *clk, ulong rate)
+{
+ return -ENOSYS;
+}
+
+static inline int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ return -ENOSYS;
+}
+
+static inline int clk_enable(struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline int clk_enable_bulk(struct clk_bulk *bulk)
+{
+ return bulk && bulk->count == 0 ? 0 : -ENOSYS;
+}
+
+static inline int clk_disable(struct clk *clk)
+{
+ return -ENOSYS;
+}
+
+static inline int clk_disable_bulk(struct clk_bulk *bulk)
+{
+ return bulk && bulk->count == 0 ? 0 : -ENOSYS;
+}
+
+static inline bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+ return false;
+}
+
+static inline int clk_get_by_id(ulong id, struct clk **clkp)
+{
+ return -ENOSYS;
+}
+
+static inline bool clk_dev_binded(struct clk *clk)
+{
+ return false;
+}
+#endif /* CONFIG_IS_ENABLED(CLK) */
+
+/**
+ * clk_valid() - check if clk is valid
+ *
+ * @clk: the clock to check
+ * @return true if valid, or false
+ */
+static inline bool clk_valid(struct clk *clk)
+{
+ return clk && !!clk->dev;
+}
+
+int soc_clk_dump(void);
+
#endif
#define clk_prepare_enable(clk) clk_enable(clk)
diff --git a/include/configs/odroid.h b/include/configs/odroid.h
index 77fca32..5d78825 100644
--- a/include/configs/odroid.h
+++ b/include/configs/odroid.h
@@ -64,7 +64,6 @@
""PARTS_BOOT" part 0 1;" \
""PARTS_ROOT" part 0 2\0" \
-#define CONFIG_SET_DFU_ALT_INFO
#define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
#define CONFIG_DFU_ALT_BOOT_EMMC \
diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h
index 47c3054..564319c 100644
--- a/include/configs/odroid_xu3.h
+++ b/include/configs/odroid_xu3.h
@@ -76,7 +76,6 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */
#define CONFIG_MISC_COMMON
-#define CONFIG_SET_DFU_ALT_INFO
#define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
/* Set soc_rev, soc_id, board_rev, board_name, fdtfile */
diff --git a/include/configs/omap3_igep00x0.h b/include/configs/omap3_igep00x0.h
index 4ad7dc1..8dc30be 100644
--- a/include/configs/omap3_igep00x0.h
+++ b/include/configs/omap3_igep00x0.h
@@ -71,8 +71,6 @@
#endif
-#define CONFIG_SYS_MTDPARTS_RUNTIME
-
/* OneNAND config */
#define CONFIG_USE_ONENAND_BOARD_INIT
#define CONFIG_SYS_ONENAND_BASE ONENAND_MAP
diff --git a/include/configs/stm32f429-evaluation.h b/include/configs/stm32f429-evaluation.h
index 7a17222..a715031 100644
--- a/include/configs/stm32f429-evaluation.h
+++ b/include/configs/stm32f429-evaluation.h
@@ -7,6 +7,11 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#include <linux/sizes.h>
+
+/* For booting Linux, use the first 16MB of memory */
+#define CONFIG_SYS_BOOTMAPSZ SZ_16M
+
#define CONFIG_SYS_FLASH_BASE 0x08000000
#define CONFIG_SYS_INIT_SP_ADDR 0x10010000
@@ -40,12 +45,10 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr_r=0x00008000\0" \
"fdtfile=stm32429i-eval.dtb\0" \
- "fdt_addr_r=0x00700000\0" \
- "scriptaddr=0x00800000\0" \
- "pxefile_addr_r=0x00800000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "ramdisk_addr_r=0x00900000\0" \
+ "fdt_addr_r=0x00408000\0" \
+ "scriptaddr=0x00418000\0" \
+ "pxefile_addr_r=0x00428000\0" \
+ "ramdisk_addr_r=0x00438000\0" \
BOOTENV
/*
diff --git a/include/configs/stm32f469-discovery.h b/include/configs/stm32f469-discovery.h
index 463f1c4..8212fb6 100644
--- a/include/configs/stm32f469-discovery.h
+++ b/include/configs/stm32f469-discovery.h
@@ -7,6 +7,11 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#include <linux/sizes.h>
+
+/* For booting Linux, use the first 12MB of memory */
+#define CONFIG_SYS_BOOTMAPSZ SZ_8M + SZ_4M
+
#define CONFIG_SYS_FLASH_BASE 0x08000000
#define CONFIG_SYS_INIT_SP_ADDR 0x10010000
@@ -40,12 +45,10 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr_r=0x00008000\0" \
"fdtfile=stm32f469-disco.dtb\0" \
- "fdt_addr_r=0x00700000\0" \
- "scriptaddr=0x00800000\0" \
- "pxefile_addr_r=0x00800000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "ramdisk_addr_r=0x00900000\0" \
+ "fdt_addr_r=0x00408000\0" \
+ "scriptaddr=0x00418000\0" \
+ "pxefile_addr_r=0x00428000\0" \
+ "ramdisk_addr_r=0x00438000\0" \
BOOTENV
/*
diff --git a/include/configs/stm32f746-disco.h b/include/configs/stm32f746-disco.h
index 337b999..45343d2 100644
--- a/include/configs/stm32f746-disco.h
+++ b/include/configs/stm32f746-disco.h
@@ -7,6 +7,11 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#include <linux/sizes.h>
+
+/* For booting Linux, use the first 6MB of memory */
+#define CONFIG_SYS_BOOTMAPSZ SZ_4M + SZ_2M
+
#define CONFIG_SYS_FLASH_BASE 0x08000000
#define CONFIG_SYS_INIT_SP_ADDR 0x20050000
@@ -48,12 +53,10 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr_r=0xC0008000\0" \
"fdtfile=stm32f746-disco.dtb\0" \
- "fdt_addr_r=0xC0500000\0" \
- "scriptaddr=0xC0008000\0" \
- "pxefile_addr_r=0xC0008000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "ramdisk_addr_r=0xC0600000\0" \
+ "fdt_addr_r=0xC0408000\0" \
+ "scriptaddr=0xC0418000\0" \
+ "pxefile_addr_r=0xC0428000\0" \
+ "ramdisk_addr_r=0xC0438000\0" \
BOOTENV
/*
diff --git a/include/configs/stm32h743-disco.h b/include/configs/stm32h743-disco.h
index 74c69eb..39c93ee 100644
--- a/include/configs/stm32h743-disco.h
+++ b/include/configs/stm32h743-disco.h
@@ -8,6 +8,10 @@
#define __CONFIG_H
#include <config.h>
+#include <linux/sizes.h>
+
+/* For booting Linux, use the first 16MB of memory */
+#define CONFIG_SYS_BOOTMAPSZ SZ_16M
#define CONFIG_SYS_FLASH_BASE 0x08000000
#define CONFIG_SYS_INIT_SP_ADDR 0x24040000
@@ -35,12 +39,10 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr_r=0xD0008000\0" \
"fdtfile=stm32h743i-disco.dtb\0" \
- "fdt_addr_r=0xD0700000\0" \
- "scriptaddr=0xD0800000\0" \
- "pxefile_addr_r=0xD0800000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "ramdisk_addr_r=0xD0900000\0" \
+ "fdt_addr_r=0xD0408000\0" \
+ "scriptaddr=0xD0418000\0" \
+ "pxefile_addr_r=0xD0428000\0" \
+ "ramdisk_addr_r=0xD0438000\0" \
BOOTENV
/*
diff --git a/include/configs/stm32h743-eval.h b/include/configs/stm32h743-eval.h
index b7c8492..8eb94c1 100644
--- a/include/configs/stm32h743-eval.h
+++ b/include/configs/stm32h743-eval.h
@@ -8,6 +8,10 @@
#define __CONFIG_H
#include <config.h>
+#include <linux/sizes.h>
+
+/* For booting Linux, use the first 16MB of memory */
+#define CONFIG_SYS_BOOTMAPSZ SZ_16M
#define CONFIG_SYS_FLASH_BASE 0x08000000
#define CONFIG_SYS_INIT_SP_ADDR 0x24040000
@@ -35,12 +39,10 @@
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr_r=0xD0008000\0" \
"fdtfile=stm32h743i-eval.dtb\0" \
- "fdt_addr_r=0xD0700000\0" \
- "scriptaddr=0xD0800000\0" \
- "pxefile_addr_r=0xD0800000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "ramdisk_addr_r=0xD0900000\0" \
+ "fdt_addr_r=0xD0408000\0" \
+ "scriptaddr=0xD0418000\0" \
+ "pxefile_addr_r=0xD0428000\0" \
+ "ramdisk_addr_r=0xD0438000\0" \
BOOTENV
/*
diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h
index d42a786..7b4fe48 100644
--- a/include/configs/stm32mp1.h
+++ b/include/configs/stm32mp1.h
@@ -23,27 +23,30 @@
#define CONFIG_SYS_SDRAM_BASE STM32_DDR_BASE
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE
-#ifdef CONFIG_STM32MP1_OPTEE
-#define CONFIG_SYS_MEM_TOP_HIDE SZ_32M
-#endif /* CONFIG_STM32MP1_OPTEE */
-
/*
* Console I/O buffer size
*/
#define CONFIG_SYS_CBSIZE SZ_1K
/*
- * Needed by "loadb"
+ * default load address used for command tftp, bootm , loadb, ...
*/
-#define CONFIG_SYS_LOAD_ADDR STM32_DDR_BASE
+#define CONFIG_LOADADDR 0xc2000000
+#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
/* ATAGs */
#define CONFIG_CMDLINE_TAG
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_INITRD_TAG
+/*
+ * For booting Linux, use the first 256 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+#define CONFIG_SYS_BOOTMAPSZ SZ_256M
+
/* Extend size of kernel image for uncompression */
-#define CONFIG_SYS_BOOTM_LEN SZ_32M
+#define CONFIG_SYS_BOOTM_LEN SZ_32M
/* SPL support */
#ifdef CONFIG_SPL
@@ -70,6 +73,11 @@
#define CONFIG_SYS_NAND_ONFI_DETECTION
#define CONFIG_SYS_MAX_NAND_DEVICE 1
+/* SPI FLASH support */
+#if defined(CONFIG_SPL_BUILD)
+#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x80000
+#endif
+
/* Ethernet need */
#ifdef CONFIG_DWC_ETH_QOS
#define CONFIG_SYS_NONCACHED_MEMORY (1 * SZ_1M) /* 1M */
@@ -78,13 +86,6 @@
#define CONFIG_SYS_AUTOLOAD "no"
#endif
-/* Dynamic MTD partition support */
-#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC2)
-#define CONFIG_SYS_MTDPARTS_RUNTIME
-#endif
-
-#define CONFIG_SET_DFU_ALT_INFO
-
#ifdef CONFIG_DM_VIDEO
#define CONFIG_VIDEO_BMP_RLE8
#define CONFIG_BMP_16BPP
@@ -98,20 +99,44 @@
#if !defined(CONFIG_SPL_BUILD)
-#define BOOT_TARGET_DEVICES(func) \
- func(MMC, mmc, 1) \
- func(UBIFS, ubifs, 0) \
- func(MMC, mmc, 0) \
- func(MMC, mmc, 2) \
- func(PXE, pxe, na)
+#ifdef CONFIG_CMD_MMC
+#define BOOT_TARGET_MMC0(func) func(MMC, mmc, 0)
+#define BOOT_TARGET_MMC1(func) func(MMC, mmc, 1)
+#define BOOT_TARGET_MMC2(func) func(MMC, mmc, 2)
+#else
+#define BOOT_TARGET_MMC0(func)
+#define BOOT_TARGET_MMC1(func)
+#define BOOT_TARGET_MMC2(func)
+#endif
+
+#ifdef CONFIG_NET
+#define BOOT_TARGET_PXE(func) func(PXE, pxe, na)
+#else
+#define BOOT_TARGET_PXE(func)
+#endif
+
+#ifdef CONFIG_CMD_UBIFS
+#define BOOT_TARGET_UBIFS(func) func(UBIFS, ubifs, 0)
+#else
+#define BOOT_TARGET_UBIFS(func)
+#endif
+
+#define BOOT_TARGET_DEVICES(func) \
+ BOOT_TARGET_MMC1(func) \
+ BOOT_TARGET_UBIFS(func) \
+ BOOT_TARGET_MMC0(func) \
+ BOOT_TARGET_MMC2(func) \
+ BOOT_TARGET_PXE(func)
/*
* 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
+ * for nand or spi-nand boot, boot with on ubifs partition on UBI partition
+ * for nor boot, use SD card = mmc0
*/
+
#define STM32MP_BOOTCMD "bootcmd_stm32mp=" \
"echo \"Boot over ${boot_device}${boot_instance}!\";" \
"if test ${boot_device} = serial || test ${boot_device} = usb;" \
@@ -120,65 +145,86 @@
"run env_check;" \
"if test ${boot_device} = mmc;" \
"then env set boot_targets \"mmc${boot_instance}\"; fi;" \
- "if test ${boot_device} = nand;" \
+ "if test ${boot_device} = nand ||" \
+ " test ${boot_device} = spi-nand ;" \
"then env set boot_targets ubifs0; fi;" \
+ "if test ${boot_device} = nor;" \
+ "then env set boot_targets mmc0; fi;" \
"run distro_bootcmd;" \
"fi;\0"
-#include <config_distro_bootcmd.h>
+/* 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
+ */
-#ifdef CONFIG_STM32MP1_OPTEE
-/* with OPTEE: define specific MTD partitions = teeh, teed, teex */
-#define STM32MP_MTDPARTS \
- "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(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 */
-
-#ifndef CONFIG_SYS_MTDPARTS_RUNTIME
-#undef STM32MP_MTDPARTS
-#define STM32MP_MTDPARTS
-#endif
+#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 */
-#define STM32MP_DFU_ALT_RAM \
- "dfu_alt_info_ram=ram 0=" \
- "uImage ram ${kernel_addr_r} 0x2000000;" \
- "devicetree.dtb ram ${fdt_addr_r} 0x100000;" \
- "uramdisk.image.gz ram ${ramdisk_addr_r} 0x10000000\0"
-
-#ifdef CONFIG_SET_DFU_ALT_INFO
-#define STM32MP_DFU_ALT_INFO \
- "dfu_alt_info_nor0=mtd nor0=" \
- "nor_fsbl1 part 1;nor_fsbl2 part 2;" \
- "nor_ssbl part 3;nor_env part 4\0" \
- "dfu_alt_info_nand0=mtd nand0="\
- "nand_fsbl part 1;nand_ssbl1 part 2;" \
- "nand_ssbl2 part 3;nand_UBI partubi 4\0" \
- "dfu_alt_info_spi-nand0=mtd spi-nand0="\
- "spi-nand_fsbl part 1;spi-nand_ssbl1 part 2;" \
- "spi-nand_ssbl2 part 3;spi-nand_UBI partubi 4\0" \
- "dfu_alt_info_mmc0=mmc 0=" \
- "sdcard_fsbl1 part 0 1;sdcard_fsbl2 part 0 2;" \
- "sdcard_ssbl part 0 3;sdcard_bootfs part 0 4;" \
- "sdcard_vendorfs part 0 5;sdcard_rootfs part 0 6;" \
- "sdcard_userfs part 0 7\0" \
- "dfu_alt_info_mmc1=mmc 1=" \
- "emmc_fsbl1 raw 0x0 0x200 mmcpart 1;" \
- "emmc_fsbl2 raw 0x0 0x200 mmcpart 2;emmc_ssbl part 1 1;" \
- "emmc_bootfs part 1 2;emmc_vendorfs part 1 3;" \
- "emmc_rootfs part 1 4;emmc_userfs part 1 5\0"
+#ifdef CONFIG_FASTBOOT_CMD_OEM_FORMAT
+/* eMMC default partitions for fastboot command: oem format */
+#define PARTS_DEFAULT \
+ "partitions=" \
+ "name=ssbl,size=2M;" \
+ "name=bootfs,size=64MB,bootable;" \
+ "name=vendorfs,size=16M;" \
+ "name=rootfs,size=746M;" \
+ "name=userfs,size=-\0"
#else
-#define STM32MP_DFU_ALT_INFO
+#define PARTS_DEFAULT
#endif
+#include <config_distro_bootcmd.h>
+
/*
* memory layout for 32M uncompressed/compressed kernel,
* 1M fdt, 1M script, 1M pxe and 1M for splashimage
@@ -192,16 +238,18 @@
"pxefile_addr_r=0xc4200000\0" \
"splashimage=0xc4300000\0" \
"ramdisk_addr_r=0xc4400000\0" \
- "fdt_high=0xffffffff\0" \
- "initrd_high=0xffffffff\0" \
"altbootcmd=run bootcmd\0" \
- "env_default=1\0" \
- "env_check=if test $env_default -eq 1;"\
- " then env set env_default 0;env save;fi\0" \
+ "env_check=" \
+ "env exists env_ver || env set env_ver ${ver};" \
+ "if env info -p -d -q; then env save; fi;" \
+ "if test \"$env_ver\" != \"$ver\"; then" \
+ " echo \"*** Warning: old environment ${env_ver}\";" \
+ " echo '* set default: env default -a; env save; reset';" \
+ " echo '* update current: env set env_ver ${ver}; env save';" \
+ "fi;\0" \
STM32MP_BOOTCMD \
- STM32MP_MTDPARTS \
- STM32MP_DFU_ALT_RAM \
- STM32MP_DFU_ALT_INFO \
+ STM32MP_ANDROID \
+ PARTS_DEFAULT \
BOOTENV \
"boot_net_usb_start=true\0"
diff --git a/include/dfu.h b/include/dfu.h
index 5649663..bb512a8 100644
--- a/include/dfu.h
+++ b/include/dfu.h
@@ -205,6 +205,9 @@ void dfu_initiated_callback(struct dfu_entity *dfu);
*/
void dfu_flush_callback(struct dfu_entity *dfu);
+int dfu_transaction_initiate(struct dfu_entity *dfu, bool read);
+void dfu_transaction_cleanup(struct dfu_entity *dfu);
+
/*
* dfu_defer_flush - pointer to store dfu_entity for deferred flashing.
* It should be NULL when not used.
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index 13fedb7..1eb1ce1 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -104,6 +104,46 @@ const void *of_get_property(const struct device_node *np, const char *name,
int *lenp);
/**
+ * of_get_first_property()- get to the pointer of the first property
+ *
+ * Get pointer to the first property of the node, it is used to iterate
+ * and read all the property with of_get_next_property_by_prop().
+ *
+ * @np: Pointer to device node
+ * @return pointer to property or NULL if not found
+ */
+const struct property *of_get_first_property(const struct device_node *np);
+
+/**
+ * of_get_next_property() - get to the pointer of the next property
+ *
+ * Get pointer to the next property of the node, it is used to iterate
+ * and read all the property with of_get_property_by_prop().
+ *
+ * @np: Pointer to device node
+ * @property: pointer of the current property
+ * @return pointer to next property or NULL if not found
+ */
+const struct property *of_get_next_property(const struct device_node *np,
+ const struct property *property);
+
+/**
+ * of_get_property_by_prop() - get a property value of a node property
+ *
+ * Get value for the property identified by node and property pointer.
+ *
+ * @node: node to read
+ * @property: pointer of the property to read
+ * @propname: place to property name on success
+ * @lenp: place to put length on success
+ * @return pointer to property value or NULL if error
+ */
+const void *of_get_property_by_prop(const struct device_node *np,
+ const struct property *property,
+ const char **name,
+ int *lenp);
+
+/**
* of_device_is_compatible() - Check if the node matches given constraints
* @device: pointer to node
* @compat: required compatible string, NULL or "" for any match
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 5c4cbf0..9ee5556 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -59,6 +59,31 @@ struct ofnode_phandle_args {
};
/**
+ * ofprop - reference to a property of a device tree node
+ *
+ * This struct hold the reference on one property of one node,
+ * using struct ofnode and an offset within the flat device tree or either
+ * a pointer to a struct property in the live device tree.
+ *
+ * Thus we can reference arguments in both the live tree and the flat tree.
+ *
+ * The property reference can also hold a null reference. This corresponds to
+ * a struct property NULL pointer or an offset of -1.
+ *
+ * @node: Pointer to device node
+ * @offset: Pointer into flat device tree, used for flat tree.
+ * @prop: Pointer to property, used for live treee.
+ */
+
+struct ofprop {
+ ofnode node;
+ union {
+ int offset;
+ const struct property *prop;
+ };
+};
+
+/**
* _ofnode_to_np() - convert an ofnode to a live DT node pointer
*
* This cannot be called if the reference contains an offset.
@@ -543,7 +568,7 @@ int ofnode_decode_display_timing(ofnode node, int index,
struct display_timing *config);
/**
- * ofnode_get_property()- - get a pointer to the value of a node property
+ * ofnode_get_property() - get a pointer to the value of a node property
*
* @node: node to read
* @propname: property to read
@@ -553,6 +578,42 @@ int ofnode_decode_display_timing(ofnode node, int index,
const void *ofnode_get_property(ofnode node, const char *propname, int *lenp);
/**
+ * ofnode_get_first_property()- get the reference of the first property
+ *
+ * Get reference to the first property of the node, it is used to iterate
+ * and read all the property with ofnode_get_property_by_prop().
+ *
+ * @node: node to read
+ * @prop: place to put argument reference
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+int ofnode_get_first_property(ofnode node, struct ofprop *prop);
+
+/**
+ * ofnode_get_next_property() - get the reference of the next property
+ *
+ * Get reference to the next property of the node, it is used to iterate
+ * and read all the property with ofnode_get_property_by_prop().
+ *
+ * @prop: reference of current argument and place to put reference of next one
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+int ofnode_get_next_property(struct ofprop *prop);
+
+/**
+ * ofnode_get_property_by_prop() - get a pointer to the value of a property
+ *
+ * Get value for the property identified by the provided reference.
+ *
+ * @prop: reference on property
+ * @propname: If non-NULL, place to property name on success,
+ * @lenp: If non-NULL, place to put length on success
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+const void *ofnode_get_property_by_prop(const struct ofprop *prop,
+ const char **propname, int *lenp);
+
+/**
* ofnode_is_available() - check if a node is marked available
*
* @node: node to check
diff --git a/include/dm/read.h b/include/dm/read.h
index d37fcb5..3c6bed7 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -466,6 +466,42 @@ int dev_read_phandle(struct udevice *dev);
const void *dev_read_prop(struct udevice *dev, const char *propname, int *lenp);
/**
+ * dev_read_first_prop()- get the reference of the first property
+ *
+ * Get reference to the first property of the node, it is used to iterate
+ * and read all the property with dev_read_prop_by_prop().
+ *
+ * @dev: device to check
+ * @prop: place to put argument reference
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+int dev_read_first_prop(struct udevice *dev, struct ofprop *prop);
+
+/**
+ * ofnode_get_next_property() - get the reference of the next property
+ *
+ * Get reference to the next property of the node, it is used to iterate
+ * and read all the property with dev_read_prop_by_prop().
+ *
+ * @prop: reference of current argument and place to put reference of next one
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+int dev_read_next_prop(struct ofprop *prop);
+
+/**
+ * dev_read_prop_by_prop() - get a pointer to the value of a property
+ *
+ * Get value for the property identified by the provided reference.
+ *
+ * @prop: reference on property
+ * @propname: If non-NULL, place to property name on success,
+ * @lenp: If non-NULL, place to put length on success
+ * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ */
+const void *dev_read_prop_by_prop(struct ofprop *prop,
+ const char **propname, int *lenp);
+
+/**
* dev_read_alias_seq() - Get the alias sequence number of a node
*
* This works out whether a node is pointed to by an alias, and if so, the
@@ -812,6 +848,23 @@ static inline const void *dev_read_prop(struct udevice *dev,
return ofnode_get_property(dev_ofnode(dev), propname, lenp);
}
+static inline int dev_read_first_prop(struct udevice *dev, struct ofprop *prop)
+{
+ return ofnode_get_first_property(dev_ofnode(dev), prop);
+}
+
+static inline int dev_read_next_prop(struct ofprop *prop)
+{
+ return ofnode_get_next_property(prop);
+}
+
+static inline const void *dev_read_prop_by_prop(struct ofprop *prop,
+ const char **propname,
+ int *lenp)
+{
+ return ofnode_get_property_by_prop(prop, propname, lenp);
+}
+
static inline int dev_read_alias_seq(struct udevice *dev, int *devnump)
{
return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name,
@@ -889,4 +942,18 @@ static inline int dev_read_alias_highest_id(const char *stem)
ofnode_valid(subnode); \
subnode = ofnode_next_subnode(subnode))
+/**
+ * dev_for_each_property() - Helper function to iterate through property
+ *
+ * This creates a for() loop which works through the property in a device's
+ * device-tree node.
+ *
+ * @prop: struct ofprop holding the current property
+ * @dev: device to use for interation (struct udevice *)
+ */
+#define dev_for_each_property(prop, dev) \
+ for (int ret_prop = dev_read_first_prop(dev, &prop); \
+ !ret_prop; \
+ ret_prop = dev_read_next_prop(&prop))
+
#endif
diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
index 4cdaf13..ec7b1a9 100644
--- a/include/dt-bindings/clock/stm32mp1-clks.h
+++ b/include/dt-bindings/clock/stm32mp1-clks.h
@@ -179,6 +179,12 @@
#define DAC12_K 168
#define ETHPTP_K 169
+#define PCLK1 170
+#define PCLK2 171
+#define PCLK3 172
+#define PCLK4 173
+#define PCLK5 174
+
/* PLL */
#define PLL1 176
#define PLL2 177
@@ -248,4 +254,31 @@
#define STM32MP1_LAST_CLK 232
+/* SCMI clock identifiers */
+#define CK_SCMI0_HSE 0
+#define CK_SCMI0_HSI 1
+#define CK_SCMI0_CSI 2
+#define CK_SCMI0_LSE 3
+#define CK_SCMI0_LSI 4
+#define CK_SCMI0_PLL2_Q 5
+#define CK_SCMI0_PLL2_R 6
+#define CK_SCMI0_MPU 7
+#define CK_SCMI0_AXI 8
+#define CK_SCMI0_BSEC 9
+#define CK_SCMI0_CRYP1 10
+#define CK_SCMI0_GPIOZ 11
+#define CK_SCMI0_HASH1 12
+#define CK_SCMI0_I2C4 13
+#define CK_SCMI0_I2C6 14
+#define CK_SCMI0_IWDG1 15
+#define CK_SCMI0_RNG1 16
+#define CK_SCMI0_RTC 17
+#define CK_SCMI0_RTCAPB 18
+#define CK_SCMI0_SPI6 19
+#define CK_SCMI0_USART1 20
+
+#define CK_SCMI1_PLL3_Q 0
+#define CK_SCMI1_PLL3_R 1
+#define CK_SCMI1_MCU 2
+
#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h
index 2cc10ae..c029467 100644
--- a/include/dt-bindings/gpio/gpio.h
+++ b/include/dt-bindings/gpio/gpio.h
@@ -33,4 +33,10 @@
#define GPIO_PERSISTENT 0
#define GPIO_TRANSITORY 8
+/* Bit 4 express pull up */
+#define GPIO_PULL_UP 16
+
+/* Bit 5 express pull down */
+#define GPIO_PULL_DOWN 32
+
#endif
diff --git a/include/dt-bindings/gpio/sandbox-gpio.h b/include/dt-bindings/gpio/sandbox-gpio.h
new file mode 100644
index 0000000..e4bfdb3
--- /dev/null
+++ b/include/dt-bindings/gpio/sandbox-gpio.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for binding sandbox,gpio
+ *
+ */
+#ifndef _DT_BINDINGS_GPIO_SANDBOX_GPIO_H
+#define _DT_BINDINGS_GPIO_SANDBOX_GPIO_H
+
+/*
+ * Add a specific binding for sandbox gpio.
+ * The value need to be after the generic defines of
+ * dt-bindings/gpio/gpio.h
+ */
+
+/* Bit 16 express GPIO input mode */
+#define GPIO_IN 0x10000
+
+/* Bit 17 express GPIO output mode */
+#define GPIO_OUT 0x20000
+
+/* Bit 18 express GPIO output is active */
+#define GPIO_OUT_ACTIVE 0x40000
+
+#endif
diff --git a/include/dt-bindings/mfd/stm32h7-rcc.h b/include/dt-bindings/mfd/stm32h7-rcc.h
index 06e8476..a1efc30 100644
--- a/include/dt-bindings/mfd/stm32h7-rcc.h
+++ b/include/dt-bindings/mfd/stm32h7-rcc.h
@@ -13,7 +13,6 @@
#define STM32H7_RCC_AHB3_QUADSPI 14
#define STM32H7_RCC_AHB3_SDMMC1 16
#define STM32H7_RCC_AHB3_CPU 31
-#define STM32H7_RCC_AHB3_CPU1 31
#define STM32H7_AHB3_RESET(bit) (STM32H7_RCC_AHB3_##bit + (0x7C * 8))
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
index e6fb8ad..370a25a 100644
--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
@@ -26,6 +26,7 @@
#define AF14 0xf
#define AF15 0x10
#define ANALOG 0x11
+#define RSVD 0x12
/* define Pins number*/
#define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line))
diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h
index f0c3aae..bc71924 100644
--- a/include/dt-bindings/reset/stm32mp1-resets.h
+++ b/include/dt-bindings/reset/stm32mp1-resets.h
@@ -105,4 +105,17 @@
#define GPIOJ_R 19785
#define GPIOK_R 19786
+/* SCMI reset domain identifiers */
+#define RST_SCMI0_SPI6 0
+#define RST_SCMI0_I2C4 1
+#define RST_SCMI0_I2C6 2
+#define RST_SCMI0_USART1 3
+#define RST_SCMI0_STGEN 4
+#define RST_SCMI0_GPIOZ 5
+#define RST_SCMI0_CRYP1 6
+#define RST_SCMI0_HASH1 7
+#define RST_SCMI0_RNG1 8
+#define RST_SCMI0_MDMA 9
+#define RST_SCMI0_MCU 10
+
#endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */
diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h
new file mode 100644
index 0000000..4373c4d
--- /dev/null
+++ b/include/dt-bindings/rtc/rtc-stm32.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for STM32_RTC bindings.
+ */
+
+#ifndef _DT_BINDINGS_RTC_RTC_STM32_H
+#define _DT_BINDINGS_RTC_RTC_STM32_H
+
+#define RTC_OUT1 0
+#define RTC_OUT2 1
+#define RTC_OUT2_RMP 2
+
+#endif
diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h
new file mode 100644
index 0000000..d986653
--- /dev/null
+++ b/include/dt-bindings/soc/stm32-hdp.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Roullier Christophe <christophe.roullier@st.com>
+ * for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32_HDP_H
+#define _DT_BINDINGS_STM32_HDP_H
+
+#define STM32_HDP(port, value) ((value) << ((port) * 4))
+
+/* define HDP Pins number*/
+#define HDP0_PWR_PWRWAKE_SYS 0
+#define HDP0_CM4_SLEEPDEEP 1
+#define HDP0_PWR_STDBY_WKUP 2
+#define HDP0_PWR_ENCOMP_VDDCORE 3
+#define HDP0_BSEC_OUT_SEC_NIDEN 4
+#define HDP0_RCC_CM4_SLEEPDEEP 6
+#define HDP0_GPU_DBG7 7
+#define HDP0_DDRCTRL_LP_REQ 8
+#define HDP0_PWR_DDR_RET_ENABLE_N 9
+#define HDP0_GPOVAL_0 15
+
+#define HDP1_PWR_PWRWAKE_MCU 0
+#define HDP1_CM4_HALTED 1
+#define HDP1_CA7_NAXIERRIRQ 2
+#define HDP1_PWR_OKIN_MR 3
+#define HDP1_BSEC_OUT_SEC_DBGEN 4
+#define HDP1_EXTI_SYS_WAKEUP 5
+#define HDP1_RCC_PWRDS_MPU 6
+#define HDP1_GPU_DBG6 7
+#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8
+#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9
+#define HDP1_GPOVAL_1 15
+
+#define HDP2_PWR_PWRWAKE_MPU 0
+#define HDP2_CM4_RXEV 1
+#define HDP2_CA7_NPMUIRQ1 2
+#define HDP2_CA7_NFIQOUT1 3
+#define HDP2_BSEC_IN_RSTCORE_N 4
+#define HDP2_EXTI_C2_WAKEUP 5
+#define HDP2_RCC_PWRDS_MCU 6
+#define HDP2_GPU_DBG5 7
+#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8
+#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9
+#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10
+#define HDP2_GPOVAL_2 15
+
+#define HDP3_PWR_SEL_VTH_VDD_CORE 0
+#define HDP3_CM4_TXEV 1
+#define HDP3_CA7_NPMUIRQ0 2
+#define HDP3_CA7_NFIQOUT0 3
+#define HDP3_BSEC_OUT_SEC_DFTLOCK 4
+#define HDP3_EXTI_C1_WAKEUP 5
+#define HDP3_RCC_PWRDS_SYS 6
+#define HDP3_GPU_DBG4 7
+#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8
+#define HDP3_DDRCTRL_CACTIVE_1 9
+#define HDP3_GPOVAL_3 15
+
+#define HDP4_PWR_PDDS 0
+#define HDP4_CM4_SLEEPING 1
+#define HDP4_CA7_NRESET1 2
+#define HDP4_CA7_NIRQOUT1 3
+#define HDP4_BSEC_OUT_SEC_DFTEN 4
+#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5
+#define HDP4_ETH_OUT_PMT_INTR_O 6
+#define HDP4_GPU_DBG3 7
+#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8
+#define HDP4_DDRCTRL_CACTIVE_0 9
+#define HDP4_GPOVAL_4 15
+
+#define HDP5_CA7_STANDBYWFIL2 0
+#define HDP5_PWR_VTH_VDDCORE_ACK 1
+#define HDP5_CA7_NRESET0 2
+#define HDP5_CA7_NIRQOUT0 3
+#define HDP5_BSEC_IN_PWROK 4
+#define HDP5_BSEC_OUT_SEC_DEVICEEN 5
+#define HDP5_ETH_OUT_LPI_INTR_O 6
+#define HDP5_GPU_DBG2 7
+#define HDP5_DDRCTRL_CACTIVE_DDRC 8
+#define HDP5_DDRCTRL_WR_CREDIT_CNT 9
+#define HDP5_GPOVAL_5 15
+
+#define HDP6_CA7_STANDBYWFI1 0
+#define HDP6_CA7_STANDBYWFE1 1
+#define HDP6_CA7_EVENT0 2
+#define HDP6_CA7_DBGACK1 3
+#define HDP6_BSEC_OUT_SEC_SPNIDEN 5
+#define HDP6_ETH_OUT_MAC_SPEED_O1 6
+#define HDP6_GPU_DBG1 7
+#define HDP6_DDRCTRL_CSYSACK_DDRC 8
+#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9
+#define HDP6_GPOVAL_6 15
+
+#define HDP7_CA7_STANDBYWFI0 0
+#define HDP7_CA7_STANDBYWFE0 1
+#define HDP7_CA7_DBGACK0 3
+#define HDP7_BSEC_OUT_FUSE_OK 4
+#define HDP7_BSEC_OUT_SEC_SPIDEN 5
+#define HDP7_ETH_OUT_MAC_SPEED_O0 6
+#define HDP7_GPU_DBG0 7
+#define HDP7_DDRCTRL_CSYSREQ_DDRC 8
+#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9
+#define HDP7_GPOVAL_7 15
+
+#endif /* _DT_BINDINGS_STM32_HDP_H */
diff --git a/include/env_internal.h b/include/env_internal.h
index 90a4df8..3f13a90 100644
--- a/include/env_internal.h
+++ b/include/env_internal.h
@@ -209,6 +209,37 @@ struct env_driver {
extern struct hsearch_data env_htab;
+/**
+ * env_ext4_get_intf() - Provide the interface for env in EXT4
+ *
+ * It is a weak function allowing board to overidde the default interface for
+ * U-Boot env in EXT4: CONFIG_ENV_EXT4_INTERFACE
+ *
+ * @return string of interface, empty if not supported
+ */
+const char *env_ext4_get_intf(void);
+
+/**
+ * env_ext4_get_dev_part() - Provide the device and partition for env in EXT4
+ *
+ * It is a weak function allowing board to overidde the default device and
+ * partition used for U-Boot env in EXT4: CONFIG_ENV_EXT4_DEVICE_AND_PART
+ *
+ * @return string of device and partition
+ */
+const char *env_ext4_get_dev_part(void);
+
+/**
+ * env_get_location()- Provide the best location for the U-Boot environment
+ *
+ * It is a weak function allowing board to overidde the environment location
+ *
+ * @op: operations performed on the environment
+ * @prio: priority between the multiple environments, 0 being the
+ * highest priority
+ * @return an enum env_location value on success, or -ve error code.
+ */
+enum env_location env_get_location(enum env_operation op, int prio);
#endif /* DO_DEPS_ONLY */
#endif /* _ENV_INTERNAL_H_ */
diff --git a/include/fastboot.h b/include/fastboot.h
index 1933b1d..966ffc6 100644
--- a/include/fastboot.h
+++ b/include/fastboot.h
@@ -36,6 +36,12 @@ enum {
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
FASTBOOT_COMMAND_OEM_FORMAT,
#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
+ FASTBOOT_COMMAND_OEM_PARTCONF,
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
+ FASTBOOT_COMMAND_OEM_BOOTBUS,
+#endif
FASTBOOT_COMMAND_COUNT
};
diff --git a/include/g_dnl.h b/include/g_dnl.h
index 6d461c7..836ee60 100644
--- a/include/g_dnl.h
+++ b/include/g_dnl.h
@@ -38,6 +38,7 @@ int g_dnl_board_usb_cable_connected(void);
int g_dnl_register(const char *s);
void g_dnl_unregister(void);
void g_dnl_set_serialnumber(char *);
+void g_dnl_set_product(const char *s);
bool g_dnl_detach(void);
void g_dnl_trigger_detach(void);
diff --git a/include/i2c.h b/include/i2c.h
index 33570f5..6642480 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -30,6 +30,32 @@ enum dm_i2c_chip_flags {
DM_I2C_CHIP_WR_ADDRESS = 1 << 2, /* Send address for each write byte */
};
+/** enum i2c_speed_mode - standard I2C speed modes */
+enum i2c_speed_mode {
+ IC_SPEED_MODE_STANDARD,
+ IC_SPEED_MODE_FAST,
+ IC_SPEED_MODE_FAST_PLUS,
+ IC_SPEED_MODE_HIGH,
+ IC_SPEED_MODE_FAST_ULTRA,
+
+ IC_SPEED_MODE_COUNT,
+};
+
+/** enum i2c_speed_rate - standard I2C speeds in Hz */
+enum i2c_speed_rate {
+ I2C_SPEED_STANDARD_RATE = 100000,
+ I2C_SPEED_FAST_RATE = 400000,
+ I2C_SPEED_FAST_PLUS_RATE = 1000000,
+ I2C_SPEED_HIGH_RATE = 3400000,
+ I2C_SPEED_FAST_ULTRA_RATE = 5000000,
+};
+
+/** enum i2c_address_mode - available address modes */
+enum i2c_address_mode {
+ I2C_MODE_7_BIT,
+ I2C_MODE_10_BIT
+};
+
struct udevice;
/**
* struct dm_i2c_chip - information about an i2c chip
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/mipi_dsi.h b/include/mipi_dsi.h
index f4a63b4..52a7a87 100644
--- a/include/mipi_dsi.h
+++ b/include/mipi_dsi.h
@@ -220,9 +220,15 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
/**
* struct mipi_dsi_panel_plat - DSI panel platform data
* @device: DSI peripheral device
+ * @lanes: number of active data lanes
+ * @format: pixel format for video mode
+ * @mode_flags: DSI operation mode related flags
*/
struct mipi_dsi_panel_plat {
struct mipi_dsi_device *device;
+ unsigned int lanes;
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
};
/**
diff --git a/include/mtd.h b/include/mtd.h
index 65fcd3c..b0f8693 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -11,4 +11,6 @@
int mtd_probe(struct udevice *dev);
int mtd_probe_devices(void);
+void board_mtdparts_default(const char **mtdids, const char **mtdparts);
+
#endif /* _MTD_H_ */
diff --git a/include/power/stpmic1.h b/include/power/stpmic1.h
index dc8b5a7..1493a67 100644
--- a/include/power/stpmic1.h
+++ b/include/power/stpmic1.h
@@ -37,6 +37,7 @@
#define STPMIC1_BUCK_VOUT(sel) (sel << STPMIC1_BUCK_VOUT_SHIFT)
#define STPMIC1_BUCK2_1200000V STPMIC1_BUCK_VOUT(24)
+#define STPMIC1_BUCK2_1250000V STPMIC1_BUCK_VOUT(26)
#define STPMIC1_BUCK2_1350000V STPMIC1_BUCK_VOUT(30)
#define STPMIC1_BUCK3_1800000V STPMIC1_BUCK_VOUT(39)
diff --git a/include/remoteproc.h b/include/remoteproc.h
index 046cd9e..a903acb 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -277,6 +277,64 @@ int rproc_elf_load_image(struct udevice *dev, unsigned long addr, ulong size);
* image.
*/
ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr);
+
+/**
+ * rproc_elf32_load_rsc_table() - load the resource table from an ELF32 image
+ *
+ * Search for the resource table in an ELF32 image, and if found, copy it to
+ * device memory.
+ *
+ * @dev: device loading the resource table
+ * @fw_addr: ELF image address
+ * @fw_size: size of the ELF image
+ * @rsc_addr: pointer to the found resource table address. Updated on
+ * operation success
+ * @rsc_size: pointer to the found resource table size. Updated on operation
+ * success
+ *
+ * @return 0 if a valid resource table is successfully loaded, -ENODATA if there
+ * is no resource table (which is optional), or another appropriate error value.
+ */
+int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size);
+/**
+ * rproc_elf64_load_rsc_table() - load the resource table from an ELF64 image
+ *
+ * Search for the resource table in an ELF64 image, and if found, copy it to
+ * device memory.
+ *
+ * @dev: device loading the resource table
+ * @fw_addr: ELF image address
+ * @fw_size: size of the ELF image
+ * @rsc_addr: pointer to the found resource table address. Updated on
+ * operation success
+ * @rsc_size: pointer to the found resource table size. Updated on operation
+ * success
+ *
+ * @return 0 if a valid resource table is successfully loaded, -ENODATA if there
+ * is no resource table (which is optional), or another appropriate error value.
+ */
+int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size);
+/**
+ * rproc_elf_load_rsc_table() - load the resource table from an ELF image
+ *
+ * Auto detects if the image is ELF32 or ELF64 image and search accordingly for
+ * the resource table, and if found, copy it to device memory.
+ *
+ * @dev: device loading the resource table
+ * @fw_addr: ELF image address
+ * @fw_size: size of the ELF image
+ * @rsc_addr: pointer to the found resource table address. Updated on
+ * operation success
+ * @rsc_size: pointer to the found resource table size. Updated on operation
+ * success
+ *
+ * @return 0 if a valid resource table is successfully loaded, -ENODATA if there
+ * is no resource table (which is optional), or another appropriate error value.
+ */
+int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr, ulong *rsc_size);
#else
static inline int rproc_init(void) { return -ENOSYS; }
static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -304,6 +362,18 @@ static inline int rproc_elf_load_image(struct udevice *dev, ulong addr,
{ return -ENOSYS; }
static inline ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
{ return 0; }
+static inline int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr,
+ ulong *rsc_size)
+{ return -ENOSYS; }
+static inline int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr,
+ ulong *rsc_size)
+{ return -ENOSYS; }
+static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
+ ulong fw_size, ulong *rsc_addr,
+ ulong *rsc_size)
+{ return -ENOSYS; }
#endif
#endif /* _RPROC_H_ */
diff --git a/include/scmi_agent.h b/include/scmi_agent.h
new file mode 100644
index 0000000..78fcc3b
--- /dev/null
+++ b/include/scmi_agent.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019, Linaro Limited
+ */
+#ifndef SCMI_AGENT_H
+#define SCMI_AGENT_H
+
+#include <asm/types.h>
+
+/**
+ * An SCMI agent represent on communication path from a device driver to
+ * the remote SCMI server which driver sends messages to and receives
+ * response messages from.
+ */
+struct scmi_agent;
+
+enum scmi_std_protocol {
+ SCMI_PROTOCOL_ID_BASE = 0x10,
+ SCMI_PROTOCOL_ID_POWER_DOMAIN = 0x11,
+ SCMI_PROTOCOL_ID_SYSTEM = 0x12,
+ SCMI_PROTOCOL_ID_PERF = 0x13,
+ SCMI_PROTOCOL_ID_CLOCK = 0x14,
+ SCMI_PROTOCOL_ID_SENSOR = 0x15,
+ SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16,
+};
+
+enum scmi_status_code {
+ SCMI_SUCCESS = 0,
+ SCMI_NOT_SUPPORTED = -1,
+ SCMI_INVALID_PARAMETERS = -2,
+ SCMI_DENIED = -3,
+ SCMI_NOT_FOUND = -4,
+ SCMI_OUT_OF_RANGE = -5,
+ SCMI_BUSY = -6,
+ SCMI_COMMS_ERROR = -7,
+ SCMI_GENERIC_ERROR = -8,
+ SCMI_HARDWARE_ERROR = -9,
+ SCMI_PROTOCOL_ERROR = -10,
+};
+
+/*
+ * struct scmi_msg - Context of a SCMI message sent and the response received
+ *
+ * @protocol_id: SCMI protocol ID
+ * @message_id: SCMI message ID for a defined protocol ID
+ * @in_msg: pointer to the message payload sent by the driver
+ * @in_msg_sz: byte size of the message payload sent
+ * @out_msg: pointer to buffer to store response message payload
+ * @out_msg_size: Byte size of the response buffer or payload
+ */
+struct scmi_msg {
+ unsigned int protocol_id;
+ unsigned int message_id;
+ u8 *in_msg;
+ size_t in_msg_sz;
+ u8 *out_msg;
+ size_t out_msg_sz;
+};
+
+/**
+ * scmi_send_and_process_msg() - send and process a SCMI message
+ *
+ * Send a message to a SCMI server through a target SCMI agent device.
+ * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
+ * On return, scmi_msg::out_msg_sz stores the response payload size.
+ *
+ * @dev: SCMI agent device
+ * @msg: Message structure reference
+ * @return 0 on success, a negative errno otherwise
+ */
+int scmi_agent_process_msg(struct udevice *dev, struct scmi_msg *msg);
+
+/**
+ * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
+ *
+ * @scmi_errno: SCMI error code value
+ * @return 0 for successful status and a negative errno otherwise
+ */
+int scmi_to_linux_errno(int32_t scmi_errno);
+
+#endif /* SCMI_AGENT_H */
diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
index 560041b..be03aea 100644
--- a/lib/libfdt/fdt_ro.c
+++ b/lib/libfdt/fdt_ro.c
@@ -183,8 +183,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
if (fdt_chk_extra() && !re)
return -FDT_ERR_BADOFFSET;
- *address = fdt64_ld(&re->address);
- *size = fdt64_ld(&re->size);
+ *address = fdt64_to_cpu(re->address);
+ *size = fdt64_to_cpu(re->size);
return 0;
}
@@ -194,7 +194,7 @@ int fdt_num_mem_rsv(const void *fdt)
const struct fdt_reserve_entry *re;
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
- if (fdt64_ld(&re->size) == 0)
+ if (fdt64_to_cpu(re->size) == 0)
return i;
}
return -FDT_ERR_TRUNCATED;
@@ -372,7 +372,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_ld(&prop->len);
+ *lenp = fdt32_to_cpu(prop->len);
return prop;
}
@@ -410,7 +410,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
offset = -FDT_ERR_INTERNAL;
break;
}
- if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+ if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@@ -463,7 +463,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
/* Handle realignment */
if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -481,7 +481,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
int namelen;
if (fdt_chk_extra()) {
- name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+ name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff),
&namelen);
if (!name) {
if (lenp)
@@ -490,13 +490,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
}
*namep = name;
} else {
- *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
+ *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
}
}
/* Handle realignment */
if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -521,7 +521,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_ld(php);
+ return fdt32_to_cpu(*php);
}
const char *fdt_get_alias_namelen(const void *fdt,
diff --git a/lib/optee/optee.c b/lib/optee/optee.c
index c883c49..79b058a 100644
--- a/lib/optee/optee.c
+++ b/lib/optee/optee.c
@@ -91,7 +91,7 @@ static int optee_copy_firmware_node(const void *old_blob, void *fdt_blob)
offs = fdt_add_subnode(fdt_blob, offs, "optee");
if (offs < 0)
- return ret;
+ return offs;
/* copy the compatible property */
prop = fdt_getprop(old_blob, old_offs, "compatible", &len);
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index cf1808e..db089be 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1547,7 +1547,6 @@ CONFIG_SETUP_MEMORY_TAGS
CONFIG_SET_BIST
CONFIG_SET_BOOTARGS
CONFIG_SET_DFU_ALT_BUF_LEN
-CONFIG_SET_DFU_ALT_INFO
CONFIG_SFIO
CONFIG_SF_DATAFLASH
CONFIG_SGI_IP28
@@ -3228,7 +3227,6 @@ CONFIG_SYS_MRAM_SIZE
CONFIG_SYS_MSC0_VAL
CONFIG_SYS_MSC1_VAL
CONFIG_SYS_MSC2_VAL
-CONFIG_SYS_MTDPARTS_RUNTIME
CONFIG_SYS_MX5_CLK32
CONFIG_SYS_MX5_HCLK
CONFIG_SYS_MX6_CLK32
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index e398815..d9d52e0 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -179,8 +179,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
if (fdt_chk_extra() && !re)
return -FDT_ERR_BADOFFSET;
- *address = fdt64_ld(&re->address);
- *size = fdt64_ld(&re->size);
+ *address = fdt64_to_cpu(re->address);
+ *size = fdt64_to_cpu(re->size);
return 0;
}
@@ -190,7 +190,7 @@ int fdt_num_mem_rsv(const void *fdt)
const struct fdt_reserve_entry *re;
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
- if (fdt64_ld(&re->size) == 0)
+ if (fdt64_to_cpu(re->size) == 0)
return i;
}
return -FDT_ERR_TRUNCATED;
@@ -368,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_ld(&prop->len);
+ *lenp = fdt32_to_cpu(prop->len);
return prop;
}
@@ -406,7 +406,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
offset = -FDT_ERR_INTERNAL;
break;
}
- if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+ if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@@ -459,7 +459,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
/* Handle realignment */
if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -477,7 +477,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
int namelen;
if (fdt_chk_extra()) {
- name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+ name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff),
&namelen);
if (!name) {
if (lenp)
@@ -486,13 +486,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
}
*namep = name;
} else {
- *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
+ *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
}
}
/* Handle realignment */
if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
- (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
+ (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -517,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_ld(php);
+ return fdt32_to_cpu(*php);
}
const char *fdt_get_alias_namelen(const void *fdt,
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 36fadcd..fa63fff 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -117,23 +117,6 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
-/*
- * Alignment helpers:
- * These helpers access words from a device tree blob. They're
- * built to work even with unaligned pointers on platforms (ike
- * ARM) that don't like unaligned loads and stores
- */
-
-static inline uint32_t fdt32_ld(const fdt32_t *p)
-{
- const uint8_t *bp = (const uint8_t *)p;
-
- return ((uint32_t)bp[0] << 24)
- | ((uint32_t)bp[1] << 16)
- | ((uint32_t)bp[2] << 8)
- | bp[3];
-}
-
static inline void fdt32_st(void *property, uint32_t value)
{
uint8_t *bp = (uint8_t *)property;
@@ -144,20 +127,6 @@ static inline void fdt32_st(void *property, uint32_t value)
bp[3] = value & 0xff;
}
-static inline uint64_t fdt64_ld(const fdt64_t *p)
-{
- const uint8_t *bp = (const uint8_t *)p;
-
- return ((uint64_t)bp[0] << 56)
- | ((uint64_t)bp[1] << 48)
- | ((uint64_t)bp[2] << 40)
- | ((uint64_t)bp[3] << 32)
- | ((uint64_t)bp[4] << 24)
- | ((uint64_t)bp[5] << 16)
- | ((uint64_t)bp[6] << 8)
- | bp[7];
-}
-
static inline void fdt64_st(void *property, uint64_t value)
{
uint8_t *bp = (uint8_t *)property;
@@ -232,7 +201,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
- (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 0c2fd5c..6a1af15 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LED) += led.o
obj-$(CONFIG_DM_MAILBOX) += mailbox.o
obj-$(CONFIG_DM_MMC) += mmc.o
obj-y += ofnode.o
+obj-y += ofread.o
obj-$(CONFIG_OSD) += osd.o
obj-$(CONFIG_DM_VIDEO) += panel.o
obj-$(CONFIG_DM_PCI) += pci.o
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index bb4b20c..5992d93 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -23,9 +23,9 @@ static int dm_test_gpio(struct unit_test_state *uts)
char buf[80];
/*
- * We expect to get 3 banks. One is anonymous (just numbered) and
- * comes from platdata. The other two are named a (20 gpios)
- * and b (10 gpios) and come from the device tree. See
+ * We expect to get 4 banks. One is anonymous (just numbered) and
+ * comes from platdata. The other are named a (20 gpios),
+ * b (10 gpios) and c (10 gpios) and come from the device tree. See
* test/dm/test.dts.
*/
ut_assertok(gpio_lookup_name("b4", &dev, &offset, &gpio));
@@ -73,11 +73,16 @@ static int dm_test_gpio(struct unit_test_state *uts)
ut_asserteq(1, ops->get_value(dev, offset));
/* Make it an open drain output, and reset it */
- ut_asserteq(0, sandbox_gpio_get_open_drain(dev, offset));
- ut_assertok(ops->set_open_drain(dev, offset, 1));
- ut_asserteq(1, sandbox_gpio_get_open_drain(dev, offset));
- ut_assertok(ops->set_open_drain(dev, offset, 0));
- ut_asserteq(0, sandbox_gpio_get_open_drain(dev, offset));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
+ sandbox_gpio_get_dir_flags(dev, offset));
+ ut_assertok(ops->set_dir_flags(dev, offset,
+ GPIOD_IS_OUT | GPIOD_OPEN_DRAIN));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
+ sandbox_gpio_get_dir_flags(dev, offset));
+ ut_assertok(ops->set_dir_flags(dev, offset,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
+ sandbox_gpio_get_dir_flags(dev, offset));
/* Make it an input */
ut_assertok(ops->direction_input(dev, offset));
@@ -214,11 +219,14 @@ static int dm_test_gpio_phandles(struct unit_test_state *uts)
desc_list2,
ARRAY_SIZE(desc_list2),
0));
+ ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 4, NULL));
ut_assertok(gpio_free_list(dev, desc_list, 3));
+ ut_asserteq(GPIOF_UNUSED, gpio_get_function(gpio_a, 4, NULL));
ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc_list,
ARRAY_SIZE(desc_list),
GPIOD_IS_OUT |
GPIOD_IS_OUT_ACTIVE));
+ ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_a, 4, NULL));
ut_asserteq_ptr(gpio_a, desc_list[0].dev);
ut_asserteq(1, desc_list[0].offset);
ut_asserteq_ptr(gpio_a, desc_list[1].dev);
@@ -228,10 +236,14 @@ static int dm_test_gpio_phandles(struct unit_test_state *uts)
ut_asserteq(1, dm_gpio_get_value(desc_list));
ut_assertok(gpio_free_list(dev, desc_list, 3));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
+ sandbox_gpio_get_dir_flags(gpio_a, 1));
ut_asserteq(6, gpio_request_list_by_name(dev, "test2-gpios", desc_list,
ARRAY_SIZE(desc_list), 0));
- /* This was set to output previously, so still will be */
- ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_a, 1, NULL));
+
+ /* This was set to output previously but flags resetted to 0 = INPUT */
+ ut_asserteq(0, sandbox_gpio_get_dir_flags(gpio_a, 1));
+ ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 1, NULL));
/* Active low should invert the input value */
ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_b, 6, NULL));
@@ -243,7 +255,42 @@ static int dm_test_gpio_phandles(struct unit_test_state *uts)
ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_b, 9, NULL));
ut_asserteq(1, dm_gpio_get_value(&desc_list[5]));
-
return 0;
}
DM_TEST(dm_test_gpio_phandles, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Check the gpio pin configuration get from device tree information */
+static int dm_test_gpio_get_dir_flags(struct unit_test_state *uts)
+{
+ struct gpio_desc desc_list[6];
+ struct udevice *dev;
+ ulong flags;
+
+ ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+
+ ut_asserteq(6, gpio_request_list_by_name(dev, "test3-gpios", desc_list,
+ ARRAY_SIZE(desc_list), 0));
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[0], &flags));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, flags);
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[1], &flags));
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, flags);
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[2], &flags));
+ ut_asserteq(GPIOD_IS_OUT, flags);
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[3], &flags));
+ ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags);
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[4], &flags));
+ ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_DOWN, flags);
+
+ ut_assertok(dm_gpio_get_dir_flags(&desc_list[5], &flags));
+ ut_asserteq(GPIOD_IS_IN, flags);
+
+ ut_assertok(gpio_free_list(dev, desc_list, 6));
+
+ return 0;
+}
+DM_TEST(dm_test_gpio_get_dir_flags, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/ofread.c b/test/dm/ofread.c
new file mode 100644
index 0000000..f2a1382
--- /dev/null
+++ b/test/dm/ofread.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <dm.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts)
+{
+ ofnode node;
+ struct ofprop prop;
+ const void *value;
+ const char *propname;
+ int res, len, count = 0;
+
+ node = ofnode_path("/cros-ec/flash");
+ for (res = ofnode_get_first_property(node, &prop);
+ !res;
+ res = ofnode_get_next_property(&prop)) {
+ value = ofnode_get_property_by_prop(&prop, &propname, &len);
+ ut_assertnonnull(value);
+ switch (count) {
+ case 0:
+ ut_asserteq_str("image-pos", propname);
+ ut_asserteq(4, len);
+ break;
+ case 1:
+ ut_asserteq_str("size", propname);
+ ut_asserteq(4, len);
+ break;
+ case 2:
+ ut_asserteq_str("erase-value", propname);
+ ut_asserteq(4, len);
+ break;
+ case 3:
+ /* only for platdata */
+ ut_asserteq_str("name", propname);
+ ut_asserteq(6, len);
+ ut_asserteq_str("flash", value);
+ break;
+ default:
+ break;
+ }
+ count++;
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_ofnode_get_property_by_prop,
+ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c
index 1d9a9b3..4067596 100644
--- a/test/dm/remoteproc.c
+++ b/test/dm/remoteproc.c
@@ -103,8 +103,8 @@ static int dm_test_remoteproc_elf(struct unit_test_state *uts)
0x00, 0x00, 0x00, 0x08,
/* phoff (program header offset @ 0x40)*/
0x40, 0x00, 0x00, 0x00,
- /* shoff (section header offset : none) */
- 0x00, 0x00, 0x00, 0x00,
+ /* shoff (section header offset @ 0x90) */
+ 0x90, 0x00, 0x00, 0x00,
/* flags */
0x00, 0x00, 0x00, 0x00,
/* ehsize (elf header size = 0x34) */
@@ -113,16 +113,17 @@ static int dm_test_remoteproc_elf(struct unit_test_state *uts)
0x20, 0x00,
/* phnum (program header number : 1) */
0x01, 0x00,
- /* shentsize (section heade size : none) */
- 0x00, 0x00,
- /* shnum (section header number: none) */
- 0x00, 0x00,
- /* shstrndx (section header name section index: none) */
- 0x00, 0x00,
+ /* shentsize (section header size : 40 bytes) */
+ 0x28, 0x00,
+ /* shnum (section header number: 3) */
+ 0x02, 0x00,
+ /* shstrndx (section header name section index: 1) */
+ 0x01, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
+
/* @0x40 - PROGRAM HEADER TABLE - */
/* type : PT_LOAD */
0x01, 0x00, 0x00, 0x00,
@@ -140,14 +141,63 @@ static int dm_test_remoteproc_elf(struct unit_test_state *uts)
0x05, 0x00, 0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
+
+ /* @0x60 - RESOURCE TABLE SECTION - */
+ /* version */
+ 0x01, 0x00, 0x00, 0x00,
+ /* num (0, no entries) */
+ 0x00, 0x00, 0x00, 0x00,
+ /* Reserved */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* @0x70 - SECTION'S NAMES SECTION - */
+ /* section 0 name (".shrtrtab") */
+ 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00,
+ /* section 1 name (".resource_table") */
+ 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x00,
+ /* padding */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* @0x90 - SECTION HEADER TABLE - */
+ /* Section 0 : resource table header */
+ /* sh_name - index into section header string table section */
+ 0x0a, 0x00, 0x00, 0x00,
+ /* sh_type and sh_flags */
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ /* sh_addr = where the resource table has to be copied to */
+ 0x00, 0x00, 0x00, 0x00,
+ /* sh_offset = 0x60 */
+ 0x60, 0x00, 0x00, 0x00,
+ /* sh_size = 16 bytes */
+ 0x10, 0x00, 0x00, 0x00,
+ /* sh_link, sh_info, sh_addralign, sh_entsize */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Section 1 : section's names section header */
+ /* sh_name - index into section header string table section */
+ 0x00, 0x00, 0x00, 0x00,
+ /* sh_type and sh_flags */
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* sh_addr */
+ 0x00, 0x00, 0x00, 0x00,
+ /* sh_offset = 0x70 */
+ 0x70, 0x00, 0x00, 0x00,
+ /* sh_size = 27 bytes */
+ 0x1b, 0x00, 0x00, 0x00,
+ /* sh_link, sh_info, sh_addralign, sh_entsize */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
unsigned int size = ARRAY_SIZE(valid_elf32);
struct udevice *dev;
- phys_addr_t loaded_firmware_paddr;
- void *loaded_firmware;
- u32 loaded_firmware_size;
+ phys_addr_t loaded_firmware_paddr, loaded_rsc_table_paddr;
+ void *loaded_firmware, *loaded_rsc_table;
+ u32 loaded_firmware_size, rsc_table_size;
+ ulong rsc_addr, rsc_size;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
+ Elf32_Shdr *shdr = (Elf32_Shdr *)(valid_elf32 + ehdr->e_shoff);
ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
@@ -178,6 +228,25 @@ static int dm_test_remoteproc_elf(struct unit_test_state *uts)
0x08000000);
unmap_physmem(loaded_firmware, MAP_NOCACHE);
+ /* Resource table */
+ shdr->sh_addr = CONFIG_SYS_SDRAM_BASE;
+ rsc_table_size = shdr->sh_size;
+
+ loaded_rsc_table_paddr = shdr->sh_addr + DEVICE_TO_PHYSICAL_OFFSET;
+ loaded_rsc_table = map_physmem(loaded_rsc_table_paddr,
+ rsc_table_size, MAP_NOCACHE);
+ ut_assertnonnull(loaded_rsc_table);
+ memset(loaded_rsc_table, 0, rsc_table_size);
+
+ /* Load and verify */
+ ut_assertok(rproc_elf32_load_rsc_table(dev, (ulong)valid_elf32, size,
+ &rsc_addr, &rsc_size));
+ ut_asserteq(rsc_addr, CONFIG_SYS_SDRAM_BASE);
+ ut_asserteq(rsc_size, rsc_table_size);
+ ut_assertok(memcmp(loaded_firmware, valid_elf32 + shdr->sh_offset,
+ shdr->sh_size));
+ unmap_physmem(loaded_firmware, MAP_NOCACHE);
+
/* Invalid ELF Magic */
valid_elf32[0] = 0;
ut_asserteq(-EPROTONOSUPPORT,
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 1fb8b5c..0997d2b 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -196,7 +196,7 @@ static int dm_test_fdt(struct unit_test_state *uts)
int ret;
int i;
- ret = dm_scan_fdt(gd->fdt_blob, false);
+ ret = dm_extended_scan_fdt(gd->fdt_blob, false);
ut_assert(!ret);
ret = uclass_get(UCLASS_TEST_FDT, &uc);
@@ -227,7 +227,7 @@ static int dm_test_alias_highest_id(struct unit_test_state *uts)
ut_asserteq(5, ret);
ret = dev_read_alias_highest_id("gpio");
- ut_asserteq(2, ret);
+ ut_asserteq(3, ret);
ret = dev_read_alias_highest_id("pci");
ut_asserteq(2, ret);
diff --git a/test/py/tests/test_env.py b/test/py/tests/test_env.py
index 6ff38f1..cbdb410 100644
--- a/test/py/tests/test_env.py
+++ b/test/py/tests/test_env.py
@@ -336,3 +336,47 @@ def test_env_import_whitelist_delete(state_test_env):
unset_var(state_test_env, 'foo2')
unset_var(state_test_env, 'foo3')
unset_var(state_test_env, 'foo4')
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_nvedit_info')
+def test_env_info(state_test_env):
+
+ """Test 'env info' command with several options.
+ """
+ c = state_test_env.u_boot_console
+
+ response = c.run_command('env info')
+ assert 'env_valid = invalid' in response
+ assert 'env_ready = true' in response
+ assert 'env_use_default = true' in response
+
+ response = c.run_command('env info -p -d')
+ assert 'Default environment is used' in response
+ assert 'Environment cannot be persisted' in response
+
+ response = c.run_command('env info -p -d -q')
+ assert response == ""
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_nvedit_info')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_env_info_quiet(state_test_env):
+
+ """Test 'env info' quiet command result with several options for test.
+ """
+ c = state_test_env.u_boot_console
+
+ response = c.run_command('env info -d -q')
+ assert response == ""
+ response = c.run_command('echo $?')
+ assert response == "0"
+
+ response = c.run_command('env info -p -q')
+ assert response == ""
+ response = c.run_command('echo $?')
+ assert response == "1"
+
+ response = c.run_command('env info -d -p -q')
+ assert response == ""
+ response = c.run_command('echo $?')
+ assert response == "1"
diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py
index 25394f1..4e6df99 100644
--- a/test/py/tests/test_pinmux.py
+++ b/test/py/tests/test_pinmux.py
@@ -22,11 +22,21 @@ def test_pinmux_usage_2(u_boot_console):
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')
- assert ('SCL : I2C SCL' in output)
- assert ('SDA : I2C SDA' in output)
- assert ('TX : Uart TX' in output)
- assert ('RX : Uart RX' in output)
- assert ('W1 : 1-wire gpio' in output)
+
+ assert ('pinctrl-gpio:' in output)
+ assert ('a5 : gpio output .' in output)
+ assert ('a6 : gpio output .' in output)
+
+ assert ('pinctrl:' in output)
+ assert ('SCL : I2C SCL.' in output)
+ assert ('SDA : I2C SDA.' in output)
+ assert ('TX : Uart TX.' in output)
+ assert ('RX : Uart RX.' in output)
+ assert ('W1 : 1-wire gpio.' in output)
+ assert ('GPIO0 : gpio bias-pull-up input-disable.' in output)
+ assert ('GPIO1 : gpio drive-open-drain.' in output)
+ assert ('GPIO2 : gpio bias-pull-down input-enable.' in output)
+ assert ('GPIO3 : gpio bias-disable.' in output)
@pytest.mark.buildconfigspec('cmd_pinmux')
@pytest.mark.boardspec('sandbox')
@@ -59,8 +69,16 @@ def test_pinmux_status(u_boot_console):
"""Test that 'pinmux status' displays selected pincontroller's pin
muxing descriptions."""
output = u_boot_console.run_command('pinmux status')
- assert ('SCL : I2C SCL' in output)
- assert ('SDA : I2C SDA' in output)
- assert ('TX : Uart TX' in output)
- assert ('RX : Uart RX' in output)
- assert ('W1 : 1-wire gpio' in output)
+
+ assert (not 'pinctrl-gpio:' in output)
+ assert (not 'pinctrl:' in output)
+
+ assert ('SCL : I2C SCL.' in output)
+ assert ('SDA : I2C SDA.' in output)
+ assert ('TX : Uart TX.' in output)
+ assert ('RX : Uart RX.' in output)
+ assert ('W1 : 1-wire gpio.' in output)
+ assert ('GPIO0 : gpio bias-pull-up input-disable.' in output)
+ assert ('GPIO1 : gpio drive-open-drain.' in output)
+ assert ('GPIO2 : gpio bias-pull-down input-enable.' in output)
+ assert ('GPIO3 : gpio bias-disable.' in output)
diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c
index 8f44f59..2a8058f 100644
--- a/tools/fdtgrep.c
+++ b/tools/fdtgrep.c
@@ -805,7 +805,7 @@ static int do_fdtgrep(struct display_info *disp, const char *filename)
* we do another pass to actually record them.
*/
for (i = 0; i < 2; i++) {
- region = malloc(count * sizeof(struct fdt_region));
+ region = realloc(region, count * sizeof(struct fdt_region));
if (!region) {
fprintf(stderr, "Out of memory for %d regions\n",
count);
@@ -823,8 +823,10 @@ static int do_fdtgrep(struct display_info *disp, const char *filename)
}
if (count <= max_regions)
break;
+ }
+ if (count > max_regions) {
free(region);
- fprintf(stderr, "Internal error with fdtgrep_find_region)(\n");
+ fprintf(stderr, "Internal error with fdtgrep_find_region()\n");
return -1;
}
diff --git a/tools/stm32image.c b/tools/stm32image.c
index ff3ec5f..18357c0 100644
--- a/tools/stm32image.c
+++ b/tools/stm32image.c
@@ -45,7 +45,7 @@ static void stm32image_default_header(struct stm32_header *ptr)
ptr->magic_number = HEADER_MAGIC;
ptr->header_version[VER_MAJOR_IDX] = HEADER_VERSION_V1;
ptr->option_flags = HEADER_DEFAULT_OPTION;
- ptr->ecdsa_algorithm = 1;
+ ptr->ecdsa_algorithm = cpu_to_le32(1);
ptr->binary_type = HEADER_TYPE_UBOOT;
}
@@ -131,7 +131,8 @@ static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
stm32hdr->image_entry_point = cpu_to_le32(params->ep);
stm32hdr->image_length = cpu_to_le32((uint32_t)sbuf->st_size -
sizeof(struct stm32_header));
- stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size);
+ stm32hdr->image_checksum =
+ cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size));
}
/*
--
2.7.4