mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/25] Add i.MX93 support
@ 2023-11-10 12:57 Sascha Hauer
  2023-11-10 12:57 ` [PATCH 01/25] ARM: initial i.MX9 support Sascha Hauer
                   ` (24 more replies)
  0 siblings, 25 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

This series adds support for the NXP i.MX93 SoC along with board
support for the TQ TQMa93xxCA board.

Currently supported are:
- Pinctrl
- GPIO
- clock
- watchdog
- UART
- I2C
- SPI
- FEC ethernet

DDR support is not part of this series, I'll send it shortly in a
separate series.

Sascha

Sascha Hauer (25):
  ARM: initial i.MX9 support
  ARM: i.MX: Add i.MX93 s4mu support
  ARM: i.MX: Add i.MX93 trdc support
  scripts: Add imx9image tool
  scripts: imx9image: Add PBL size option
  clk: Add i.MX93 clock support
  clk: imx: clk-fracn-gppll: make usable from PBL
  gpio-vf610: Add i.MX93 support
  iomux: Add i.MX93 support
  watchdog: Add ULP wdog support
  I2c: Add i2c_8bit_addr_from_msg()
  i2c: Add lpi2c support
  ARM: Add imx93.dtsi for USB
  serial: Add lpuart32 driver
  ARM: i.MX: add i.MX9 debug_ll support
  ARM: Add TQ MBA9XXXCA board support
  ARM: i.MX93: Add DDR size read support
  ARM: i.MX: romapi: rename functions to *romapi*
  ARM: i.MX: romapi: Implement i.MX93 support
  ARM: i.MX: atf: add imx93_load_and_start_image_via_tfa()
  imx-usb-loader: Add i.MX9 support
  spi: spi-nxp-fspi: Enable for i.MX9
  usb: i.MX chipidea: Enable usbmisc driver for i.MX9
  ARM: Update imx_v8_defconfig
  ARM: multi_v8_defconfig: enable i.MX9 boards

 arch/arm/boards/Makefile                      |    1 +
 arch/arm/boards/tqmba9xxxca/Makefile          |    2 +
 arch/arm/boards/tqmba9xxxca/board.c           |   58 +
 arch/arm/boards/tqmba9xxxca/lowlevel.c        |   43 +
 .../tqmba9xxxca/lpddr4x_tqma93xxca_timing.c   | 1480 +++++++++++
 arch/arm/configs/imx_v8_defconfig             |    9 +-
 arch/arm/configs/multi_v8_defconfig           |    7 +
 arch/arm/dts/Makefile                         |    1 +
 arch/arm/dts/imx93-tqma9352-mba93xxca.dts     |  826 +++++++
 arch/arm/dts/imx93.dtsi                       |   62 +
 arch/arm/mach-imx/Kconfig                     |   26 +
 arch/arm/mach-imx/Makefile                    |    6 +-
 arch/arm/mach-imx/atf.c                       |   38 +-
 arch/arm/mach-imx/cpu_init.c                  |   42 +
 arch/arm/mach-imx/esdctl.c                    |   42 +
 arch/arm/mach-imx/imx-bbu-internal.c          |    5 +
 arch/arm/mach-imx/imx93-s4mu.c                |   97 +
 arch/arm/mach-imx/imx93-trdc.c                |  364 +++
 arch/arm/mach-imx/romapi.c                    |  166 +-
 common/Kconfig                                |    5 +
 drivers/clk/imx/Makefile                      |    1 +
 drivers/clk/imx/clk-composite-93.c            |  216 ++
 drivers/clk/imx/clk-fracn-gppll.c             |  297 +++
 drivers/clk/imx/clk-gate-93.c                 |  186 ++
 drivers/clk/imx/clk-imx93.c                   |  331 +++
 drivers/clk/imx/clk.h                         |   16 +
 drivers/gpio/Kconfig                          |    3 +-
 drivers/gpio/gpio-vf610.c                     |   78 +-
 drivers/i2c/busses/Kconfig                    |    7 +
 drivers/i2c/busses/Makefile                   |    1 +
 drivers/i2c/busses/i2c-imx-lpi2c.c            |  518 ++++
 drivers/pinctrl/imx-iomux-v3.c                |    2 +
 drivers/serial/Kconfig                        |    4 +
 drivers/serial/Makefile                       |    1 +
 drivers/serial/serial_lpuart32.c              |  185 ++
 drivers/spi/Kconfig                           |    2 +-
 drivers/usb/imx/imx-usb-misc.c                |    2 +-
 drivers/watchdog/Kconfig                      |    6 +
 drivers/watchdog/Makefile                     |    1 +
 drivers/watchdog/imxulp-wdt.c                 |  161 ++
 firmware/Kconfig                              |    3 +
 firmware/Makefile                             |    1 +
 images/Makefile.imx                           |   11 +
 include/i2c/i2c.h                             |    4 +
 include/mach/imx/atf.h                        |    2 +
 include/mach/imx/bbu.h                        |    9 +
 include/mach/imx/debug_ll.h                   |   13 +
 include/mach/imx/generic.h                    |    1 +
 include/mach/imx/imx9-regs.h                  |   24 +
 include/mach/imx/romapi.h                     |    5 +-
 include/mach/imx/xload.h                      |    1 +
 include/serial/lpuart32.h                     |  168 ++
 include/soc/imx/clk-fracn-gppll.h             |  144 ++
 include/soc/imx9/flash_header.h               |   88 +
 include/soc/imx9/mu_hal.h                     |   12 +
 include/soc/imx9/s400_api.h                   |  124 +
 include/soc/imx9/trdc.h                       |   11 +
 scripts/Kconfig                               |    7 +
 scripts/Makefile                              |    1 +
 scripts/imx/imx-usb-loader.c                  |   29 +
 scripts/imx9image.c                           | 2179 +++++++++++++++++
 61 files changed, 8110 insertions(+), 25 deletions(-)
 create mode 100644 arch/arm/boards/tqmba9xxxca/Makefile
 create mode 100644 arch/arm/boards/tqmba9xxxca/board.c
 create mode 100644 arch/arm/boards/tqmba9xxxca/lowlevel.c
 create mode 100644 arch/arm/boards/tqmba9xxxca/lpddr4x_tqma93xxca_timing.c
 create mode 100644 arch/arm/dts/imx93-tqma9352-mba93xxca.dts
 create mode 100644 arch/arm/dts/imx93.dtsi
 create mode 100644 arch/arm/mach-imx/imx93-s4mu.c
 create mode 100644 arch/arm/mach-imx/imx93-trdc.c
 create mode 100644 drivers/clk/imx/clk-composite-93.c
 create mode 100644 drivers/clk/imx/clk-fracn-gppll.c
 create mode 100644 drivers/clk/imx/clk-gate-93.c
 create mode 100644 drivers/clk/imx/clk-imx93.c
 create mode 100644 drivers/i2c/busses/i2c-imx-lpi2c.c
 create mode 100644 drivers/serial/serial_lpuart32.c
 create mode 100644 drivers/watchdog/imxulp-wdt.c
 create mode 100644 include/mach/imx/imx9-regs.h
 create mode 100644 include/serial/lpuart32.h
 create mode 100644 include/soc/imx/clk-fracn-gppll.h
 create mode 100644 include/soc/imx9/flash_header.h
 create mode 100644 include/soc/imx9/mu_hal.h
 create mode 100644 include/soc/imx9/s400_api.h
 create mode 100644 include/soc/imx9/trdc.h
 create mode 100644 scripts/imx9image.c

-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 01/25] ARM: initial i.MX9 support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support Sascha Hauer
                   ` (23 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Kconfig            | 17 +++++++++++
 arch/arm/mach-imx/Makefile           |  5 ++--
 arch/arm/mach-imx/cpu_init.c         | 42 ++++++++++++++++++++++++++++
 arch/arm/mach-imx/imx-bbu-internal.c |  5 ++++
 firmware/Kconfig                     |  3 ++
 firmware/Makefile                    |  1 +
 include/mach/imx/bbu.h               |  9 ++++++
 include/mach/imx/generic.h           |  1 +
 include/mach/imx/imx9-regs.h         | 24 ++++++++++++++++
 9 files changed, 105 insertions(+), 2 deletions(-)
 create mode 100644 include/mach/imx/imx9-regs.h

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 6a7d90e2c8..358d1ef362 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -31,6 +31,14 @@ config RESET_IMX_SRC
 	def_bool y
 	depends on ARCH_IMX6 || ARCH_IMX50 || ARCH_IMX51 || ARCH_IMX53
 
+config ARCH_IMX_ATF
+	def_bool y
+	depends on ARCH_IMX8M || ARCH_IMX93
+
+config ARCH_IMX_ROMAPI
+	def_bool y
+	depends on ARCH_IMX8M || ARCH_IMX93
+
 #
 # PMIC configuration found on i.MX51 Babbadge board
 #
@@ -164,6 +172,15 @@ config ARCH_IMX8MQ
 	select ARCH_IMX8M
 	bool
 
+config ARCH_IMX93
+	bool
+	select CPU_V8
+	select PINCTRL_IMX_IOMUX_V3
+	select OFTREE
+	select COMMON_CLK_OF_PROVIDER
+	select ARM_USE_COMPRESSED_DTB
+	select ARCH_HAS_FEC_IMX
+
 config ARCH_VF610
 	bool
 	select ARCH_HAS_L2X0
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index f49bbea2b4..7b093ba7fd 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -18,8 +18,9 @@ lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o
 obj-$(CONFIG_ARCH_IMX7) += imx7.o
 obj-$(CONFIG_ARCH_VF610) += vf610.o
 obj-pbl-$(CONFIG_ARCH_IMX8M) += imx8m.o
-lwl-$(CONFIG_ARCH_IMX8M) += atf.o
-obj-pbl-$(CONFIG_ARCH_IMX8M) += romapi.o tzasc.o
+lwl-$(CONFIG_ARCH_IMX_ATF) += atf.o
+obj-pbl-$(CONFIG_ARCH_IMX8M) += tzasc.o
+obj-pbl-$(CONFIG_ARCH_IMX_ROMAPI) += romapi.o
 obj-$(CONFIG_IMX_IIM)	+= iim.o
 obj-$(CONFIG_NAND_IMX) += nand.o
 lwl-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o
diff --git a/arch/arm/mach-imx/cpu_init.c b/arch/arm/mach-imx/cpu_init.c
index 4e55d72857..b20172076e 100644
--- a/arch/arm/mach-imx/cpu_init.c
+++ b/arch/arm/mach-imx/cpu_init.c
@@ -10,6 +10,8 @@
 #include <mach/imx/imx7-regs.h>
 #include <mach/imx/imx8mq-regs.h>
 #include <mach/imx/imx8m-ccm-regs.h>
+#include <mach/imx/imx9-regs.h>
+#include <soc/imx9/trdc.h>
 #include <io.h>
 #include <asm/syscounter.h>
 #include <asm/system.h>
@@ -85,4 +87,44 @@ void imx8mq_cpu_lowlevel_init(void)
 {
 	imx8m_cpu_lowlevel_init();
 }
+
+#define CCM_AUTHEN_TZ_NS	BIT(9)
+
+#define OSCPLLa_AUTHEN(n)		(0x5030  + (n) * 0x40) /* 0..18 */
+#define CLOCK_ROOT_AUTHEN(n)		(0x30  + (n) * 0x80) /* 0..94 */
+#define LPCGa_AUTHEN(n)			(0x8030 + (n) * 0x40) /* 0..126 */
+#define GPR_SHARED0_AUTHEN(n)		(0x4810 + (n) * 0x10) /* 0..3 */
+#define SET 4
+
+#define SRC_SP_ISO_CTRL			0x10c
+
+void imx93_cpu_lowlevel_init(void)
+{
+	void __iomem *ccm = IOMEM(MX9_CCM_BASE_ADDR);
+	void __iomem *src = IOMEM(MX9_SRC_BASE_ADDR);
+	int i;
+
+	arm_cpu_lowlevel_init();
+
+	if (current_el() != 3)
+		return;
+
+	imx9_trdc_init();
+
+	imx_cpu_timer_init(IOMEM(MX9_SYSCNT_CTRL_BASE_ADDR));
+
+	for (i = 0; i <= 18; i++)
+		writel(CCM_AUTHEN_TZ_NS, ccm + OSCPLLa_AUTHEN(i) + SET);
+	for (i = 0; i <= 94; i++)
+		writel(CCM_AUTHEN_TZ_NS, ccm + CLOCK_ROOT_AUTHEN(i) + SET);
+	for (i = 0; i <= 126 ; i++)
+		writel(CCM_AUTHEN_TZ_NS, ccm + LPCGa_AUTHEN(i) + SET);
+	for (i = 0; i <= 3 ; i++)
+		writel(CCM_AUTHEN_TZ_NS, ccm + GPR_SHARED0_AUTHEN(i) + SET);
+
+	/* clear isolation for usbphy, dsi, csi*/
+	writel(0x0, src + SRC_SP_ISO_CTRL);
+
+}
+
 #endif
diff --git a/arch/arm/mach-imx/imx-bbu-internal.c b/arch/arm/mach-imx/imx-bbu-internal.c
index 8cdaab5c16..e26317e8bf 100644
--- a/arch/arm/mach-imx/imx-bbu-internal.c
+++ b/arch/arm/mach-imx/imx-bbu-internal.c
@@ -617,6 +617,11 @@ int imx8m_bbu_internal_mmcboot_register_handler(const char *name,
 						 unsigned long flags)
 	__alias(imx_bbu_internal_mmcboot_register_handler);
 
+int imx9_bbu_internal_mmcboot_register_handler(const char *name,
+						 const char *devicefile,
+						 unsigned long flags)
+	__alias(imx_bbu_internal_mmcboot_register_handler);
+
 /*
  * Register an i.MX53 internal boot update handler for i2c/spi
  * EEPROMs / flashes. Nearly the same as MMC/SD, but we do not need to
diff --git a/firmware/Kconfig b/firmware/Kconfig
index 3328dbc0b1..38fbf85555 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -38,6 +38,9 @@ config FIRMWARE_IMX8MP_ATF
 config FIRMWARE_IMX8MQ_ATF
 	bool
 
+config FIRMWARE_IMX93_ATF
+	bool
+
 config FIRMWARE_IMX8MM_OPTEE
 	bool "install OP-TEE on i.MX8MM boards"
 	depends on FIRMWARE_IMX8MM_ATF && PBL_OPTEE
diff --git a/firmware/Makefile b/firmware/Makefile
index 4fca83f808..51d98d54bf 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -16,6 +16,7 @@ pbl-firmware-$(CONFIG_FIRMWARE_IMX8MM_ATF) += imx8mm-bl31.bin$(if $(CONFIG_FIRMW
 pbl-firmware-$(CONFIG_FIRMWARE_IMX8MN_ATF) += imx8mn-bl31.bin$(if $(CONFIG_FIRMWARE_IMX8MN_OPTEE),-optee,)
 pbl-firmware-$(CONFIG_FIRMWARE_IMX8MP_ATF) += imx8mp-bl31.bin$(if $(CONFIG_FIRMWARE_IMX8MP_OPTEE),-optee,)
 pbl-firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx8mq-bl31.bin
+pbl-firmware-$(CONFIG_FIRMWARE_IMX93_ATF) += imx93-bl31.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MM_OPTEE) += imx8mm-bl32.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MN_OPTEE) += imx8mn-bl32.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MP_OPTEE) += imx8mp-bl32.bin
diff --git a/include/mach/imx/bbu.h b/include/mach/imx/bbu.h
index 50657d9895..f6397a9dd7 100644
--- a/include/mach/imx/bbu.h
+++ b/include/mach/imx/bbu.h
@@ -82,6 +82,8 @@ int imx8m_bbu_internal_mmc_register_handler(const char *name, const char *device
 					    unsigned long flags);
 int imx8m_bbu_internal_mmcboot_register_handler(const char *name, const char *devicefile,
 						unsigned long flags);
+int imx9_bbu_internal_mmcboot_register_handler(const char *name, const char *devicefile,
+					       unsigned long flags);
 
 int imx_bbu_external_nor_register_handler(const char *name, const char *devicefile,
 		unsigned long flags);
@@ -182,6 +184,13 @@ static inline int imx8m_bbu_internal_mmcboot_register_handler(const char *name,
 	return -ENOSYS;
 }
 
+static inline int imx9_bbu_internal_mmcboot_register_handler(const char *name,
+							      const char *devicefile,
+							      unsigned long flags)
+{
+	return -ENOSYS;
+}
+
 static inline int imx_bbu_external_nor_register_handler(const char *name, const char *devicefile,
 		unsigned long flags)
 {
diff --git a/include/mach/imx/generic.h b/include/mach/imx/generic.h
index f674e28697..ce65e4d8ec 100644
--- a/include/mach/imx/generic.h
+++ b/include/mach/imx/generic.h
@@ -73,6 +73,7 @@ void imx8mq_cpu_lowlevel_init(void);
 void imx8mm_cpu_lowlevel_init(void);
 void imx8mn_cpu_lowlevel_init(void);
 void imx8mp_cpu_lowlevel_init(void);
+void imx93_cpu_lowlevel_init(void);
 
 /* There's a off-by-one betweem the gpio bank number and the gpiochip */
 /* range e.g. GPIO_1_5 is gpio 5 under linux */
diff --git a/include/mach/imx/imx9-regs.h b/include/mach/imx/imx9-regs.h
new file mode 100644
index 0000000000..dd02abf52a
--- /dev/null
+++ b/include/mach/imx/imx9-regs.h
@@ -0,0 +1,24 @@
+#ifndef __MACH_IMX9_REGS_H
+#define __MACH_IMX9_REGS_H
+
+#define MX9_UART3_BASE_ADDR		0x42570000UL
+#define MX9_UART4_BASE_ADDR		0x42580000UL
+#define MX9_UART5_BASE_ADDR		0x42590000UL
+#define MX9_UART6_BASE_ADDR		0x425a0000UL
+#define MX9_UART7_BASE_ADDR		0x42690000UL
+#define MX9_UART8_BASE_ADDR		0x426a0000UL
+#define MX9_SYSCNT_CTRL_BASE_ADDR	0x44290000UL
+#define MX9_UART1_BASE_ADDR		0x44380000UL
+#define MX9_UART2_BASE_ADDR		0x44390000UL
+#define MX9_IOMUXC_BASE_ADDR		0x443c0000UL
+#define MX9_CCM_BASE_ADDR		0x44450000UL
+#define MX9_SRC_BASE_ADDR		0x44460000UL
+#define MX9_ANATOP_BASE_ADDR		0x44480000UL
+#define MX9_ANATOP_DRAM_PLL_BASE_ADDR	0x44481300UL
+#define MX9_TRDC_NICMIX_BASE_ADDR	0x49010000UL
+#define MX9_DDRMIX_BLK_CTRL_BASE	0x4E010000UL
+#define MX9_DDR_PHY_BASE		0x4E100000UL
+#define MX9_DDR_CTL_BASE		0x4E300000UL
+#define MX9_DDR_CSD1_BASE_ADDR		0x80000000UL
+
+#endif /* __MACH_IMX9_REGS_H */
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
  2023-11-10 12:57 ` [PATCH 01/25] ARM: initial i.MX9 support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-13  7:25   ` Ahmad Fatoum
  2023-11-10 12:57 ` [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support Sascha Hauer
                   ` (22 subsequent siblings)
  24 siblings, 1 reply; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Makefile     |   1 +
 arch/arm/mach-imx/imx93-s4mu.c |  97 ++++++++++++++++++++++++++
 include/soc/imx9/mu_hal.h      |  12 ++++
 include/soc/imx9/s400_api.h    | 124 +++++++++++++++++++++++++++++++++
 4 files changed, 234 insertions(+)
 create mode 100644 arch/arm/mach-imx/imx93-s4mu.c
 create mode 100644 include/soc/imx9/mu_hal.h
 create mode 100644 include/soc/imx9/s400_api.h

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 7b093ba7fd..4efac08ee8 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -33,3 +33,4 @@ obj-$(CONFIG_RESET_IMX_SRC) += src.o
 lwl-y += cpu_init.o
 pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
 pbl-y += xload-qspi.o
+pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o
diff --git a/arch/arm/mach-imx/imx93-s4mu.c b/arch/arm/mach-imx/imx93-s4mu.c
new file mode 100644
index 0000000000..11a787d44d
--- /dev/null
+++ b/arch/arm/mach-imx/imx93-s4mu.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020-2022 NXP
+ */
+#define pr_fmt(fmt) "s4mu: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <soc/imx9/s400_api.h>
+#include <soc/imx9/mu_hal.h>
+#include <linux/iopoll.h>
+
+#define MU_SR_TE0_MASK		BIT(0)
+#define MU_SR_RF0_MASK		BIT(0)
+#define MU_TR_COUNT		8
+#define MU_RR_COUNT		4
+
+struct mu_type {
+	u32 ver;
+	u32 par;
+	u32 cr;
+	u32 sr;
+	u32 reserved0[60];
+	u32 fcr;
+	u32 fsr;
+	u32 reserved1[2];
+	u32 gier;
+	u32 gcr;
+	u32 gsr;
+	u32 reserved2;
+	u32 tcr;
+	u32 tsr;
+	u32 rcr;
+	u32 rsr;
+	u32 reserved3[52];
+	u32 tr[16];
+	u32 reserved4[16];
+	u32 rr[16];
+	u32 reserved5[14];
+	u32 mu_attr;
+};
+
+void mu_hal_init(ulong base)
+{
+	struct mu_type *mu_base = (struct mu_type *)base;
+
+	writel(0, &mu_base->tcr);
+	writel(0, &mu_base->rcr);
+}
+
+int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg)
+{
+	struct mu_type *mu_base = (struct mu_type *)base;
+	u32 mask = MU_SR_TE0_MASK << reg_index;
+	u32 val;
+	int ret;
+
+	BUG_ON(reg_index >= MU_TR_COUNT);
+
+	pr_vdebug("sendmsg tsr 0x%x\n", readl(&mu_base->tsr));
+
+	/* Wait TX register to be empty. */
+	ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
+	if (ret < 0) {
+		pr_debug("%s timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	pr_vdebug("tr[%d] 0x%x\n", reg_index, msg);
+
+	writel(msg, &mu_base->tr[reg_index]);
+
+	return 0;
+}
+
+int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg)
+{
+	struct mu_type *mu_base = (struct mu_type *)base;
+	u32 mask = MU_SR_RF0_MASK << reg_index;
+	u32 val;
+	int ret;
+
+	BUG_ON(reg_index >= MU_RR_COUNT);
+
+	pr_vdebug("receivemsg rsr 0x%x\n", readl(&mu_base->rsr));
+
+	/* Wait RX register to be full. */
+	ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 10000000);
+	if (ret < 0)
+		return -ETIMEDOUT;
+
+	*msg = readl(&mu_base->rr[reg_index]);
+
+	pr_vdebug("rr[%d] 0x%x\n", reg_index, *msg);
+
+	return 0;
+}
diff --git a/include/soc/imx9/mu_hal.h b/include/soc/imx9/mu_hal.h
new file mode 100644
index 0000000000..5db559c1ac
--- /dev/null
+++ b/include/soc/imx9/mu_hal.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef __SNT_MU_HAL_H__
+#define __SNT_MU_HAL_H__
+
+void mu_hal_init(ulong base);
+int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg);
+int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg);
+#endif
diff --git a/include/soc/imx9/s400_api.h b/include/soc/imx9/s400_api.h
new file mode 100644
index 0000000000..6d2dd71d67
--- /dev/null
+++ b/include/soc/imx9/s400_api.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef __S400_API_H__
+#define __S400_API_H__
+
+#define AHAB_VERSION    0x6
+#define AHAB_CMD_TAG    0x17
+#define AHAB_RESP_TAG   0xe1
+
+/* ELE commands */
+#define ELE_PING_REQ (0x01)
+#define ELE_FW_AUTH_REQ (0x02)
+#define ELE_RESTART_RST_TIMER_REQ (0x04)
+#define ELE_DUMP_DEBUG_BUFFER_REQ (0x21)
+#define ELE_OEM_CNTN_AUTH_REQ (0x87)
+#define ELE_VERIFY_IMAGE_REQ (0x88)
+#define ELE_RELEASE_CONTAINER_REQ (0x89)
+#define ELE_WRITE_SECURE_FUSE_REQ (0x91)
+#define ELE_FWD_LIFECYCLE_UP_REQ (0x95)
+#define ELE_READ_FUSE_REQ (0x97)
+#define ELE_GET_FW_VERSION_REQ (0x9D)
+#define ELE_RET_LIFECYCLE_UP_REQ (0xA0)
+#define ELE_GET_EVENTS_REQ (0xA2)
+#define ELE_START_RNG (0xA3)
+#define ELE_GENERATE_DEK_BLOB (0xAF)
+#define ELE_ENABLE_PATCH_REQ (0xC3)
+#define ELE_RELEASE_RDC_REQ (0xC4)
+#define ELE_GET_FW_STATUS_REQ (0xC5)
+#define ELE_ENABLE_OTFAD_REQ (0xC6)
+#define ELE_RESET_REQ (0xC7)
+#define ELE_UPDATE_OTP_CLKDIV_REQ (0xD0)
+#define ELE_POWER_DOWN_REQ (0xD1)
+#define ELE_ENABLE_APC_REQ (0xD2)
+#define ELE_ENABLE_RTC_REQ (0xD3)
+#define ELE_DEEP_POWER_DOWN_REQ (0xD4)
+#define ELE_STOP_RST_TIMER_REQ (0xD5)
+#define ELE_WRITE_FUSE_REQ (0xD6)
+#define ELE_RELEASE_CAAM_REQ (0xD7)
+#define ELE_RESET_A35_CTX_REQ (0xD8)
+#define ELE_MOVE_TO_UNSECURED_REQ (0xD9)
+#define ELE_GET_INFO_REQ (0xDA)
+#define ELE_ATTEST_REQ (0xDB)
+#define ELE_RELEASE_PATCH_REQ (0xDC)
+#define ELE_OTP_SEQ_SWITH_REQ (0xDD)
+
+/* ELE failure indications */
+#define ELE_ROM_PING_FAILURE_IND (0x0A)
+#define ELE_FW_PING_FAILURE_IND (0x1A)
+#define ELE_BAD_SIGNATURE_FAILURE_IND (0xF0)
+#define ELE_BAD_HASH_FAILURE_IND (0xF1)
+#define ELE_INVALID_LIFECYCLE_IND (0xF2)
+#define ELE_PERMISSION_DENIED_FAILURE_IND (0xF3)
+#define ELE_INVALID_MESSAGE_FAILURE_IND (0xF4)
+#define ELE_BAD_VALUE_FAILURE_IND (0xF5)
+#define ELE_BAD_FUSE_ID_FAILURE_IND (0xF6)
+#define ELE_BAD_CONTAINER_FAILURE_IND (0xF7)
+#define ELE_BAD_VERSION_FAILURE_IND (0xF8)
+#define ELE_INVALID_KEY_FAILURE_IND (0xF9)
+#define ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
+#define ELE_NO_VALID_CONTAINER_FAILURE_IND (0xFB)
+#define ELE_BAD_CERTIFICATE_FAILURE_IND (0xFC)
+#define ELE_BAD_UID_FAILURE_IND (0xFD)
+#define ELE_BAD_MONOTONIC_COUNTER_FAILURE_IND (0xFE)
+#define ELE_MUST_SIGNED_FAILURE_IND (0xE0)
+#define ELE_NO_AUTHENTICATION_FAILURE_IND (0xEE)
+#define ELE_BAD_SRK_SET_FAILURE_IND (0xEF)
+#define ELE_UNALIGNED_PAYLOAD_FAILURE_IND (0xA6)
+#define ELE_WRONG_SIZE_FAILURE_IND (0xA7)
+#define ELE_ENCRYPTION_FAILURE_IND (0xA8)
+#define ELE_DECRYPTION_FAILURE_IND (0xA9)
+#define ELE_OTP_PROGFAIL_FAILURE_IND (0xAA)
+#define ELE_OTP_LOCKED_FAILURE_IND (0xAB)
+#define ELE_OTP_INVALID_IDX_FAILURE_IND (0xAD)
+#define ELE_TIME_OUT_FAILURE_IND (0xB0)
+#define ELE_BAD_PAYLOAD_FAILURE_IND (0xB1)
+#define ELE_WRONG_ADDRESS_FAILURE_IND (0xB4)
+#define ELE_DMA_FAILURE_IND (0xB5)
+#define ELE_DISABLED_FEATURE_FAILURE_IND (0xB6)
+#define ELE_MUST_ATTEST_FAILURE_IND (0xB7)
+#define ELE_RNG_NOT_STARTED_FAILURE_IND (0xB8)
+#define ELE_CRC_ERROR_IND (0xB9)
+#define ELE_AUTH_SKIPPED_OR_FAILED_FAILURE_IND (0xBB)
+#define ELE_INCONSISTENT_PAR_FAILURE_IND (0xBC)
+#define ELE_RNG_INST_FAILURE_FAILURE_IND (0xBD)
+#define ELE_LOCKED_REG_FAILURE_IND (0xBE)
+#define ELE_BAD_ID_FAILURE_IND (0xBF)
+#define ELE_INVALID_OPERATION_FAILURE_IND (0xC0)
+#define ELE_NON_SECURE_STATE_FAILURE_IND (0xC1)
+#define ELE_MSG_TRUNCATED_IND (0xC2)
+#define ELE_BAD_IMAGE_NUM_FAILURE_IND (0xC3)
+#define ELE_BAD_IMAGE_ADDR_FAILURE_IND (0xC4)
+#define ELE_BAD_IMAGE_PARAM_FAILURE_IND (0xC5)
+#define ELE_BAD_IMAGE_TYPE_FAILURE_IND (0xC6)
+#define ELE_CORRUPTED_SRK_FAILURE_IND (0xD0)
+#define ELE_OUT_OF_MEMORY_IND (0xD1)
+#define ELE_CSTM_FAILURE_IND (0xCF)
+#define ELE_OLD_VERSION_FAILURE_IND (0xCE)
+#define ELE_WRONG_BOOT_MODE_FAILURE_IND (0xCD)
+#define ELE_APC_ALREADY_ENABLED_FAILURE_IND (0xCB)
+#define ELE_RTC_ALREADY_ENABLED_FAILURE_IND (0xCC)
+#define ELE_ABORT_IND (0xFF)
+
+/* ELE IPC identifier */
+#define ELE_IPC_MU_RTD (0x1)
+#define ELE_IPC_MU_APD (0x2)
+
+/* ELE Status*/
+#define ELE_SUCCESS_IND (0xD6)
+#define ELE_FAILURE_IND (0x29)
+
+#define S400_MAX_MSG          255U
+
+struct sentinel_msg {
+	u8 version;
+	u8 size;
+	u8 command;
+	u8 tag;
+	u32 data[(S400_MAX_MSG - 1U)];
+};
+
+#endif
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
  2023-11-10 12:57 ` [PATCH 01/25] ARM: initial i.MX9 support Sascha Hauer
  2023-11-10 12:57 ` [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-13  7:24   ` Ahmad Fatoum
  2023-11-10 12:57 ` [PATCH 04/25] scripts: Add imx9image tool Sascha Hauer
                   ` (21 subsequent siblings)
  24 siblings, 1 reply; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Makefile     |   2 +-
 arch/arm/mach-imx/imx93-trdc.c | 364 +++++++++++++++++++++++++++++++++
 include/soc/imx9/trdc.h        |  11 +
 3 files changed, 376 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/imx93-trdc.c
 create mode 100644 include/soc/imx9/trdc.h

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 4efac08ee8..8a1ccabe15 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -33,4 +33,4 @@ obj-$(CONFIG_RESET_IMX_SRC) += src.o
 lwl-y += cpu_init.o
 pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
 pbl-y += xload-qspi.o
-pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o
+pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o imx93-trdc.o
diff --git a/arch/arm/mach-imx/imx93-trdc.c b/arch/arm/mach-imx/imx93-trdc.c
new file mode 100644
index 0000000000..a1c7d49515
--- /dev/null
+++ b/arch/arm/mach-imx/imx93-trdc.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ */
+#define pr_fmt(fmt) "trdc: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <soc/imx9/mu_hal.h>
+#include <soc/imx9/s400_api.h>
+#include <soc/imx9/trdc.h>
+#include <mach/imx/imx9-regs.h>
+
+#define DID_NUM 16
+#define MBC_MAX_NUM 4
+#define MRC_MAX_NUM 2
+#define MBC_NUM(HWCFG) ((HWCFG >> 16) & 0xF)
+#define MRC_NUM(HWCFG) ((HWCFG >> 24) & 0x1F)
+
+struct mbc_mem_dom {
+	u32 mem_glbcfg[4];
+	u32 nse_blk_index;
+	u32 nse_blk_set;
+	u32 nse_blk_clr;
+	u32 nsr_blk_clr_all;
+	u32 memn_glbac[8];
+	/* The upper only existed in the beginning of each MBC */
+	u32 mem0_blk_cfg_w[64];
+	u32 mem0_blk_nse_w[16];
+	u32 mem1_blk_cfg_w[8];
+	u32 mem1_blk_nse_w[2];
+	u32 mem2_blk_cfg_w[8];
+	u32 mem2_blk_nse_w[2];
+	u32 mem3_blk_cfg_w[8];
+	u32 mem3_blk_nse_w[2];/*0x1F0, 0x1F4 */
+	u32 reserved[2];
+};
+
+struct mrc_rgn_dom {
+	u32 mrc_glbcfg[4];
+	u32 nse_rgn_indirect;
+	u32 nse_rgn_set;
+	u32 nse_rgn_clr;
+	u32 nse_rgn_clr_all;
+	u32 memn_glbac[8];
+	/* The upper only existed in the beginning of each MRC */
+	u32 rgn_desc_words[16][2]; /* 16  regions at max, 2 words per region */
+	u32 rgn_nse;
+	u32 reserved2[15];
+};
+
+struct mda_inst {
+	u32 mda_w[8];
+};
+
+struct trdc_mgr {
+	u32 trdc_cr;
+	u32 res0[59];
+	u32 trdc_hwcfg0;
+	u32 trdc_hwcfg1;
+	u32 res1[450];
+	struct mda_inst mda[8];
+	u32 res2[15808];
+};
+
+struct trdc_mbc {
+	struct mbc_mem_dom mem_dom[DID_NUM];
+};
+
+struct trdc_mrc {
+	struct mrc_rgn_dom mrc_dom[DID_NUM];
+};
+
+static void *trdc_get_mbc_base(ulong trdc_reg, u32 mbc_x)
+{
+	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
+	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
+
+	if (mbc_x >= mbc_num)
+		return 0;
+
+	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_x;
+}
+
+static void *trdc_get_mrc_base(ulong trdc_reg, u32 mrc_x)
+{
+	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
+	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
+	u32 mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
+
+	if (mrc_x >= mrc_num)
+		return 0;
+
+	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
+}
+
+static int trdc_mbc_set_control(ulong trdc_reg, u32 mbc_x, u32 glbac_id,
+			 u32 glbac_val)
+{
+	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
+	struct mbc_mem_dom *mbc_dom;
+
+	if (mbc_base == 0 || glbac_id >= 8)
+		return -EINVAL;
+
+	/* only first dom has the glbac */
+	mbc_dom = &mbc_base->mem_dom[0];
+
+	writel(glbac_val, &mbc_dom->memn_glbac[glbac_id]);
+
+	return 0;
+}
+
+static int trdc_mbc_blk_config(ulong trdc_reg, u32 mbc_x, u32 dom_x, u32 mem_x,
+			u32 blk_x, bool sec_access, u32 glbac_id)
+{
+	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
+	struct mbc_mem_dom *mbc_dom;
+	u32 *cfg_w, *nse_w;
+	u32 index, offset, val;
+
+	if (mbc_base == 0 || glbac_id >= 8)
+		return -EINVAL;
+
+	mbc_dom = &mbc_base->mem_dom[dom_x];
+
+	switch (mem_x) {
+	case 0:
+		cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
+		nse_w = &mbc_dom->mem0_blk_nse_w[blk_x / 32];
+		break;
+	case 1:
+		cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
+		nse_w = &mbc_dom->mem1_blk_nse_w[blk_x / 32];
+		break;
+	case 2:
+		cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
+		nse_w = &mbc_dom->mem2_blk_nse_w[blk_x / 32];
+		break;
+	case 3:
+		cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
+		nse_w = &mbc_dom->mem3_blk_nse_w[blk_x / 32];
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	index = blk_x % 8;
+	offset = index * 4;
+
+	val = readl((void __iomem *)cfg_w);
+
+	val &= ~(0xFU << offset);
+
+	/* MBC0-3
+	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+	 *  So select MBC0_MEMN_GLBAC0
+	 */
+	if (sec_access) {
+		val |= ((0x0 | (glbac_id & 0x7)) << offset);
+		writel(val, (void __iomem *)cfg_w);
+	} else {
+		val |= ((0x8 | (glbac_id & 0x7)) << offset); /* nse bit set */
+		writel(val, (void __iomem *)cfg_w);
+	}
+
+	return 0;
+}
+
+static int trdc_mrc_set_control(ulong trdc_reg, u32 mrc_x, u32 glbac_id, u32 glbac_val)
+{
+	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
+	struct mrc_rgn_dom *mrc_dom;
+
+	if (mrc_base == 0 || glbac_id >= 8)
+		return -EINVAL;
+
+	/* only first dom has the glbac */
+	mrc_dom = &mrc_base->mrc_dom[0];
+
+	pr_vdebug("mrc_dom 0x%lx\n", (ulong)mrc_dom);
+
+	writel(glbac_val, &mrc_dom->memn_glbac[glbac_id]);
+
+	return 0;
+}
+
+static int trdc_mrc_region_config(ulong trdc_reg, u32 mrc_x, u32 dom_x, u32 addr_start,
+			   u32 addr_end, bool sec_access, u32 glbac_id)
+{
+	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
+	struct mrc_rgn_dom *mrc_dom;
+	u32 *desc_w;
+	u32 start, end;
+	u32 i, free = 8;
+	bool vld, hit = false;
+
+	if (mrc_base == 0 || glbac_id >= 8)
+		return -EINVAL;
+
+	mrc_dom = &mrc_base->mrc_dom[dom_x];
+
+	addr_start &= ~0x3fff;
+	addr_end &= ~0x3fff;
+
+	for (i = 0; i < 8; i++) {
+		desc_w = &mrc_dom->rgn_desc_words[i][0];
+
+		start = readl((void __iomem *)desc_w) & (~0x3fff);
+		end = readl((void __iomem *)(desc_w + 1));
+		vld = end & 0x1;
+		end = end & (~0x3fff);
+
+		if (start == 0 && end == 0 && !vld && free >= 8)
+			free = i;
+
+		/* Check all the region descriptors, even overlap */
+		if (addr_start >= end || addr_end <= start || !vld)
+			continue;
+
+		/* MRC0,1
+		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+		 *  So select MRCx_MEMN_GLBAC0
+		 */
+		if (sec_access) {
+			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
+			writel(end | 0x1, (void __iomem *)(desc_w + 1));
+		} else {
+			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
+			writel(end | 0x1 | 0x10, (void __iomem *)(desc_w + 1));
+		}
+
+		if (addr_start >= start && addr_end <= end)
+			hit = true;
+	}
+
+	if (!hit) {
+		if (free >= 8)
+			return -EFAULT;
+
+		desc_w = &mrc_dom->rgn_desc_words[free][0];
+
+		if (sec_access) {
+			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
+			writel(addr_end | 0x1, (void __iomem *)(desc_w + 1));
+		} else {
+			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
+			writel((addr_end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
+		}
+	}
+
+	return 0;
+}
+
+static bool trdc_mrc_enabled(ulong trdc_base)
+{
+	return (!!(readl((void __iomem *)trdc_base) & 0x8000));
+}
+
+static int release_rdc(u8 xrdc)
+{
+	ulong s_mu_base = 0x47520000UL;
+	struct sentinel_msg msg;
+	int ret;
+	u32 rdc_id;
+
+	switch (xrdc) {
+	case 0:
+		rdc_id = 0x74;
+		break;
+	case 1:
+		rdc_id = 0x78;
+		break;
+	case 2:
+		rdc_id = 0x82;
+		break;
+	case 3:
+		rdc_id = 0x86;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	msg.version = AHAB_VERSION;
+	msg.tag = AHAB_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_RELEASE_RDC_REQ;
+	msg.data[0] = (rdc_id << 8) | 0x2; /* A55 */
+
+	mu_hal_init(s_mu_base);
+	mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
+	mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
+
+	ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
+	if (ret)
+		return ret;
+
+	ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
+	if (ret)
+		return -EIO;
+
+	if ((msg.data[0] & 0xff) == 0xd6)
+		return 0;
+
+	return -EIO;
+}
+
+void imx9_trdc_init(void)
+{
+	unsigned long base = MX9_TRDC_NICMIX_BASE_ADDR;
+	int ret = 0, i;
+
+	ret |= release_rdc(0);
+	ret |= release_rdc(2);
+	ret |= release_rdc(1);
+	ret |= release_rdc(3);
+
+	if (ret)
+		return;
+
+	/* Set OCRAM to RWX for secure, when OEM_CLOSE, the image is RX only */
+	trdc_mbc_set_control(base, 3, 0, 0x7700);
+
+	for (i = 0; i < 40; i++)
+		trdc_mbc_blk_config(base, 3, 3, 0, i, true, 0);
+
+	for (i = 0; i < 40; i++)
+		trdc_mbc_blk_config(base, 3, 3, 1, i, true, 0);
+
+	for (i = 0; i < 40; i++)
+		trdc_mbc_blk_config(base, 3, 0, 0, i, true, 0);
+
+	for (i = 0; i < 40; i++)
+		trdc_mbc_blk_config(base, 3, 0, 1, i, true, 0);
+
+	/* TRDC mega */
+	if (!trdc_mrc_enabled(base))
+		return;
+
+	/* DDR */
+	trdc_mrc_set_control(base, 0, 0, 0x7777);
+	/* S400*/
+	trdc_mrc_region_config(base, 0, 0, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* MTR */
+	trdc_mrc_region_config(base, 0, 1, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* M33 */
+	trdc_mrc_region_config(base, 0, 2, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* A55*/
+	trdc_mrc_region_config(base, 0, 3, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* For USDHC1 to DDR, USDHC1 is default force to non-secure */
+	trdc_mrc_region_config(base, 0, 5, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* For USDHC2 to DDR, USDHC2 is default force to non-secure */
+	trdc_mrc_region_config(base, 0, 6, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* eDMA */
+	trdc_mrc_region_config(base, 0, 7, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* CoreSight, TestPort */
+	trdc_mrc_region_config(base, 0, 8, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* DAP */
+	trdc_mrc_region_config(base, 0, 9, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* SoC masters */
+	trdc_mrc_region_config(base, 0, 10, 0x80000000, 0xFFFFFFFF, false, 0);
+	/* USB */
+	trdc_mrc_region_config(base, 0, 11, 0x80000000, 0xFFFFFFFF, false, 0);
+}
diff --git a/include/soc/imx9/trdc.h b/include/soc/imx9/trdc.h
new file mode 100644
index 0000000000..624e267ab6
--- /dev/null
+++ b/include/soc/imx9/trdc.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022 NXP
+ */
+
+#ifndef __ASM_ARCH_IMX9_TRDC_H
+#define __ASM_ARCH_IMX9_TRDC_H
+
+void imx9_trdc_init(void);
+
+#endif
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 04/25] scripts: Add imx9image tool
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (2 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 05/25] scripts: imx9image: Add PBL size option Sascha Hauer
                   ` (20 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

This adds a tool for building images for the NXP i.MX9 SoC. The code
is based on:
https://github.com/nxp-imx/imx-mkimage/tree/5a0faefc223e51e088433663b6e7d6fbce89bf59

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/soc/imx9/flash_header.h |   88 ++
 scripts/Kconfig                 |    7 +
 scripts/Makefile                |    1 +
 scripts/imx9image.c             | 2171 +++++++++++++++++++++++++++++++
 4 files changed, 2267 insertions(+)
 create mode 100644 include/soc/imx9/flash_header.h
 create mode 100644 scripts/imx9image.c

diff --git a/include/soc/imx9/flash_header.h b/include/soc/imx9/flash_header.h
new file mode 100644
index 0000000000..51819929dd
--- /dev/null
+++ b/include/soc/imx9/flash_header.h
@@ -0,0 +1,88 @@
+#ifndef SOC_IMX_FLASH_HEADER_H
+#define SOC_IMX_FLASH_HEADER_H
+
+#define HASH_MAX_LEN			64
+#define IV_MAX_LEN			32
+#define MAX_NUM_IMGS			8
+#define MAX_NUM_OF_CONTAINER		3
+#define MAX_HW_CFG_SIZE_V2		359
+
+struct img_flags {
+	char type;
+	char core_id;
+	char hash_type;
+	bool encrypted;
+	uint16_t boot_flags;
+};
+
+struct sig_blk_hdr {
+	uint8_t version;
+	uint16_t length;
+	uint8_t tag;
+	uint16_t srk_table_offset;
+	uint16_t cert_offset;
+	uint16_t blob_offset;
+	uint16_t signature_offset;
+	uint32_t reserved;
+} __attribute__((packed));
+
+struct boot_img {
+	uint32_t offset;
+	uint32_t size;
+	uint64_t dst;
+	uint64_t entry;
+	uint32_t hab_flags;
+	uint32_t meta;
+	uint8_t hash[HASH_MAX_LEN];
+	uint8_t iv[IV_MAX_LEN];
+} __attribute__((packed));
+
+struct flash_header_v3 {
+	uint8_t version;
+	uint16_t length;
+	uint8_t tag;
+	uint32_t flags;
+	uint16_t sw_version;
+	uint8_t fuse_version;
+	uint8_t num_images;
+	uint16_t sig_blk_offset;
+	uint16_t reserved;
+	struct boot_img img[MAX_NUM_IMGS];
+	struct sig_blk_hdr sig_blk_hdr;
+	uint32_t sigblk_size;
+	uint32_t padding;
+} __attribute__((packed));
+
+struct ivt_header {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t version;
+} __attribute__((packed));
+
+struct write_dcd_command {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t param;
+} __attribute__((packed));
+
+struct dcd_addr_data {
+	uint32_t addr;
+	uint32_t value;
+};
+
+struct dcd_v2_cmd {
+	struct write_dcd_command write_dcd_command; /*4*/
+	struct dcd_addr_data addr_data[MAX_HW_CFG_SIZE_V2]; /*2872*/
+} __attribute__((packed));
+
+struct dcd_v2 {
+	struct ivt_header header;   /*4*/
+	struct dcd_v2_cmd dcd_cmd; /*2876*/
+} __attribute__((packed)) ;                     /*2880*/
+
+struct imx_header_v3 {
+	struct flash_header_v3 fhdr[MAX_NUM_OF_CONTAINER];
+	struct dcd_v2 dcd_table;
+}  __attribute__((packed));
+
+#endif /* SOC_IMX_FLASH_HEADER_H */
diff --git a/scripts/Kconfig b/scripts/Kconfig
index 9be04fa7c8..4b675671ee 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -28,6 +28,13 @@ config ZYNQ_MKIMAGE
 	help
 	  This enables building the image creation tool for Zynq
 
+config IMX9_IMAGE
+	bool "imx9image"
+	depends on ARCH_IMX93 || COMPILE_HOST_TOOLS
+	default y if ARCH_IMX93
+	help
+	  This enables building the image tool for NXP i.MX9 SoCs
+
 config MXS_HOSTTOOLS
 	bool "MXS host tools" if COMPILE_HOST_TOOLS
 	depends on ARCH_MXS || COMPILE_HOST_TOOLS
diff --git a/scripts/Makefile b/scripts/Makefile
index 42ac4e548b..cb1d916439 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -25,6 +25,7 @@ hostprogs-always-$(CONFIG_SOCFPGA_MKIMAGE)		+= socfpga_mkimage
 hostprogs-always-$(CONFIG_MXS_HOSTTOOLS)		+= mxsimage mxsboot
 hostprogs-always-$(CONFIG_LAYERSCAPE_PBLIMAGE)		+= pblimage
 hostprogs-always-$(CONFIG_STM32_IMAGE)			+= stm32image
+hostprogs-always-$(CONFIG_IMX9_IMAGE)			+= imx9image
 hostprogs-always-$(CONFIG_RISCV)			+= prelink-riscv
 hostprogs-always-$(CONFIG_RK_IMAGE)			+= rkimage
 HOSTCFLAGS_rkimage.o = `$(PKG_CONFIG) --cflags openssl`
diff --git a/scripts/imx9image.c b/scripts/imx9image.c
new file mode 100644
index 0000000000..a991ba5f35
--- /dev/null
+++ b/scripts/imx9image.c
@@ -0,0 +1,2171 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ * derived from u-boot's mkimage utility
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <linux/kernel.h>
+
+#include "../include/soc/imx9/flash_header.h"
+#include "compiler.h"
+
+typedef enum option_type {
+	NO_IMG = 0,
+	DCD,
+	SCFW,
+	SECO,
+	M4,
+	AP,
+	OUTPUT,
+	SCD,
+	CSF,
+	FLAG,
+	DEVICE,
+	NEW_CONTAINER,
+	APPEND,
+	DATA,
+	PARTITION,
+	FILEOFF,
+	MSG_BLOCK,
+	DUMMY_V2X,
+	SENTINEL,
+	UPOWER,
+	FCB
+} option_type_t;
+
+typedef struct {
+	option_type_t option;
+	char* filename;
+	uint64_t src;
+	uint64_t dst;
+	uint64_t entry;/* image entry address or general purpose num */
+	uint64_t ext;
+	uint64_t mu;
+	uint64_t part;
+} image_t;
+
+typedef enum REVISION_TYPE {
+	NO_REV = 0,
+	A0,
+	B0
+} rev_type_t;
+
+typedef enum SOC_TYPE {
+	NONE = 0,
+	QX,
+	QM,
+	DXL,
+	ULP,
+	IMX9,
+} soc_type_t;
+
+#define CORE_SC         0x1
+#define CORE_CM4_0      0x2
+#define CORE_CM4_1      0x3
+#define CORE_CA53       0x4
+#define CORE_CA35       0x4
+#define CORE_CA72       0x5
+#define CORE_SECO       0x6
+#define CORE_V2X_P      0x9
+#define CORE_V2X_S      0xA
+
+#define CORE_ULP_CM33		0x1
+#define CORE_ULP_CA35		0x2
+#define CORE_ULP_UPOWER 	0x4
+#define CORE_ULP_SENTINEL 	0x6
+
+#define SC_R_OTP		357U
+#define SC_R_DEBUG		354U
+#define SC_R_ROM_0		236U
+#define SC_R_PWM_0		191U
+#define SC_R_SNVS		356U
+#define SC_R_DC_0		32U
+
+#define IMG_TYPE_CSF		0x01   /* CSF image type */
+#define IMG_TYPE_SCD		0x02   /* SCD image type */
+#define IMG_TYPE_EXEC		0x03   /* Executable image type */
+#define IMG_TYPE_DATA		0x04   /* Data image type */
+#define IMG_TYPE_DCD_DDR	0x05   /* DCD/DDR image type */
+#define IMG_TYPE_SECO		0x06   /* SECO image type */
+#define IMG_TYPE_SENTINEL	0x06   /* SENTINEL image type */
+#define IMG_TYPE_PROV		0x07   /* Provisioning image type */
+#define IMG_TYPE_DEK		0x08   /* DEK validation type */
+#define IMG_TYPE_FCB_CHK	0x08   /* The FCB copy image */
+#define IMG_TYPE_PRIM_V2X	0x0B   /* Primary V2X FW image */
+#define IMG_TYPE_SEC_V2X	0x0C   /* Secondary V2X FW image*/
+#define IMG_TYPE_V2X_ROM	0x0D   /* V2X ROM Patch image */
+#define IMG_TYPE_V2X_DUMMY	0x0E   /* V2X Dummy image */
+
+#define IMG_TYPE_SHIFT   0
+#define IMG_TYPE_MASK    0x1f
+#define IMG_TYPE(x)      (((x) & IMG_TYPE_MASK) >> IMG_TYPE_SHIFT)
+
+#define BOOT_IMG_FLAGS_CORE_MASK		0xF
+#define BOOT_IMG_FLAGS_CORE_SHIFT		0x04
+#define BOOT_IMG_FLAGS_CPU_RID_MASK		0x3FF0
+#define BOOT_IMG_FLAGS_CPU_RID_SHIFT		4
+#define BOOT_IMG_FLAGS_MU_RID_MASK		0xFFC000
+#define BOOT_IMG_FLAGS_MU_RID_SHIFT		14
+#define BOOT_IMG_FLAGS_PARTITION_ID_MASK	0x1F000000
+#define BOOT_IMG_FLAGS_PARTITION_ID_SHIFT	24
+
+#define SC_R_A35_0      508
+#define SC_R_A53_0      1
+#define SC_R_A72_0      6
+#define SC_R_MU_0A      213
+#define SC_R_MU_3A      216
+#define SC_R_M4_0_PID0  278
+#define SC_R_M4_0_MU_1A 297
+#define SC_R_M4_1_PID0  298
+#define SC_R_M4_1_MU_1A 317
+#define PARTITION_ID_M4 0
+#define PARTITION_ID_AP 1
+#define PARTITION_ID_AP2 3
+
+/* Command tags and parameters */
+#define HAB_DATA_WIDTH_BYTE 1 /* 8-bit value */
+#define HAB_DATA_WIDTH_HALF 2 /* 16-bit value */
+#define HAB_DATA_WIDTH_WORD 4 /* 32-bit value */
+#define HAB_CMD_WRT_DAT_MSK 1 /* mask/value flag */
+#define HAB_CMD_WRT_DAT_SET 2 /* set/clear flag */
+#define HAB_CMD_CHK_DAT_SET 2 /* set/clear flag */
+#define HAB_CMD_CHK_DAT_ANY 4 /* any/all flag */
+#define HAB_CMD_WRT_DAT_FLAGS_WIDTH   5 /* flags field width */
+#define HAB_CMD_WRT_DAT_FLAGS_SHIFT   3 /* flags field offset */
+#define HAB_CMD_WRT_DAT_BYTES_WIDTH   3 /* bytes field width */
+#define HAB_CMD_WRT_DAT_BYTES_SHIFT   0 /* bytes field offset */
+
+#define IVT_VER                         0x01
+#define IVT_VERSION                     0x43
+#define DCD_HEADER_TAG                  0xD2
+#define DCD_VERSION                     0x43
+#define DCD_WRITE_DATA_COMMAND_TAG      0xCC
+#define DCD_WRITE_DATA_PARAM            (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x4 */
+#define DCD_WRITE_CLR_BIT_PARAM         ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0xC */
+#define DCD_WRITE_SET_BIT_PARAM         ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_WRT_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x1C */
+#define DCD_CHECK_DATA_COMMAND_TAG      0xCF
+#define DCD_CHECK_BITS_CLR_PARAM        (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x04 */
+#define DCD_CHECK_BITS_SET_PARAM        ((HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x14 */
+#define DCD_CHECK_ANY_BIT_CLR_PARAM     ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x24 */
+#define DCD_CHECK_ANY_BIT_SET_PARAM     ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x34 */
+
+#define IVT_OFFSET_NAND         (0x400)
+#define IVT_OFFSET_I2C          (0x400)
+#define IVT_OFFSET_FLEXSPI      (0x1000)
+#define IVT_OFFSET_SD           (0x400)
+#define IVT_OFFSET_SATA         (0x400)
+#define IVT_OFFSET_EMMC         (0x400)
+
+#define CSF_DATA_SIZE       (0x4000)
+#define INITIAL_LOAD_ADDR_SCU_ROM 0x2000e000
+#define INITIAL_LOAD_ADDR_AP_ROM 0x00110000
+#define INITIAL_LOAD_ADDR_FLEXSPI 0x08000000
+#define IMG_AUTO_ALIGN 0x10
+
+#define UNDEFINED 0xFFFFFFFF
+
+#define OCRAM_START						0x00100000
+#define OCRAM_END						0x00400000
+
+#define MAX_NUM_SRK_RECORDS		4
+
+#define IVT_HEADER_TAG_B0		0x87
+#define IVT_VERSION_B0			0x00
+
+#define IMG_FLAG_HASH_SHA256		0x000
+#define IMG_FLAG_HASH_SHA384		0x100
+#define IMG_FLAG_HASH_SHA512		0x200
+#define IMG_FLAG_HASH_SM3		0x300
+
+#define IMG_FLAG_ENCRYPTED_MASK		0x400
+#define IMG_FLAG_ENCRYPTED_SHIFT	0x0A
+
+#define IMG_FLAG_BOOTFLAGS_MASK		0xFFFF0000
+#define IMG_FLAG_BOOTFLAGS_SHIFT	0x10
+
+#define IMG_ARRAY_ENTRY_SIZE		128
+#define HEADER_IMG_ARRAY_OFFSET		0x10
+
+#define HASH_STR_SHA_256		"sha256"
+#define HASH_STR_SHA_384		"sha384"
+#define HASH_STR_SHA_512		"sha512"
+#define HASH_STR_SM3			"sm3"
+
+#define HASH_TYPE_SHA_256		256
+#define HASH_TYPE_SHA_384		384
+#define HASH_TYPE_SHA_512		512
+#define HASH_TYPE_SM3			003
+
+#define IMAGE_HASH_ALGO_DEFAULT		HASH_TYPE_SHA_384
+#define IMAGE_HASH_ALGO_DEFAULT_NAME	HASH_STR_SHA_384
+#define IMAGE_PADDING_DEFAULT		0x1000
+
+#define DCD_ENTRY_ADDR_IN_SCFW		0x240
+
+#define CONTAINER_ALIGNMENT		0x400
+#define CONTAINER_FLAGS_DEFAULT		0x10
+#define CONTAINER_FUSE_DEFAULT		0x0
+
+#define SIGNATURE_BLOCK_HEADER_LENGTH	0x10
+
+#define BOOT_IMG_META_MU_RID_SHIFT	10
+#define BOOT_IMG_META_PART_ID_SHIFT	20
+
+#define IMAGE_TYPE_MASK	0xF
+
+#define CORE_ID_SHIFT	0x4
+#define CORE_ID_MASK	0xF
+
+#define HASH_TYPE_SHIFT	0x8
+#define HASH_TYPE_MASK	0x7
+
+#define IMAGE_ENCRYPTED_SHIFT	0x11
+#define IMAGE_ENCRYPTED_MASK	0x1
+
+#define IMAGE_A35_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A35_0)
+
+#define IMAGE_A53_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	 SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT |					\
+	 SC_R_A53_0)
+
+#define IMAGE_A72_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP2 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	 SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A72_0)
+
+#define IMAGE_M4_0_DEFAULT_META(PART)							\
+	(((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_M4_0_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_0_PID0)
+
+#define IMAGE_M4_1_DEFAULT_META(PART)							\
+	(((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_M4_1_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_1_PID0)
+
+#define CONTAINER_IMAGE_ARRAY_START_OFFSET	0x2000
+
+uint32_t scfw_flags = 0;
+
+static uint32_t custom_partition = 0;
+
+static void copy_file_aligned(int ifd, const char *datafile, int offset, int align)
+{
+	int dfd;
+	struct stat sbuf;
+	unsigned char *ptr;
+	uint8_t zeros[0x4000];
+	int size;
+	int ret;
+
+	if (align > 0x4000) {
+		fprintf (stderr, "Wrong alignment requested %d\n",
+			align);
+		exit (EXIT_FAILURE);
+	}
+
+	memset(zeros, 0, sizeof(zeros));
+
+	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
+		fprintf (stderr, "Can't open %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf (stderr, "Can't stat %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (sbuf.st_size == 0)
+		goto close;
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf (stderr, "Can't read %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	size = sbuf.st_size;
+	ret = lseek(ifd, offset, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n",
+			__func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (write(ifd, ptr, size) != size) {
+		fprintf (stderr, "Write error %s\n",
+			strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	align = ALIGN(size, align) - size;
+
+	if (write(ifd, (char *)&zeros, align) != align) {
+		fprintf(stderr, "Write error: %s\n",
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+close:
+	(void) close (dfd);
+
+}
+
+static void set_imx_hdr_v3(struct imx_header_v3 *imxhdr, uint32_t dcd_len,
+		uint32_t flash_offset, uint32_t hdr_base, uint32_t cont_id)
+{
+	struct flash_header_v3 *fhdr_v3 = &imxhdr->fhdr[cont_id];
+
+	/* Set magic number */
+	fhdr_v3->tag = IVT_HEADER_TAG_B0;
+	fhdr_v3->version = IVT_VERSION_B0;
+}
+
+static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_type)
+{
+	FILE *fp = NULL;
+	char sha_command[512];
+	char digest_type[10];
+	char hash[2 * HASH_MAX_LEN + 1];
+	int digest_length = 0;
+	int i;
+
+	switch (hash_type) {
+	case HASH_TYPE_SHA_256:
+		img->hab_flags |= IMG_FLAG_HASH_SHA256;
+		strcpy(digest_type, "sha256sum" );
+		digest_length = 64;
+		break;
+	case HASH_TYPE_SHA_384:
+		img->hab_flags |= IMG_FLAG_HASH_SHA384;
+		strcpy(digest_type, "sha384sum" );
+		digest_length = 96;
+		break;
+	case HASH_TYPE_SHA_512:
+		img->hab_flags |= IMG_FLAG_HASH_SHA512;
+		strcpy(digest_type, "sha512sum" );
+		digest_length = 128;
+		break;
+	case HASH_TYPE_SM3:
+		img->hab_flags |= IMG_FLAG_HASH_SM3;
+		strcpy(digest_type, "sm3sum" );
+		digest_length = 64;
+		break;
+	default:
+		fprintf(stderr, "Wrong hash type selected (%d) !!!\n\n",
+				hash_type);
+		exit(EXIT_FAILURE);
+		break;
+	}
+
+	if (img->size == 0 || !filename)
+		sprintf(sha_command, "%s /dev/null", digest_type);
+	else
+		sprintf(sha_command, "dd status=none if=/dev/zero of=tmp_pad bs=%d count=1;\
+				dd status=none if=\'%s\' of=tmp_pad conv=notrunc;\
+				%s tmp_pad; rm -f tmp_pad",
+			img->size, filename, digest_type);
+
+	memset(img->hash, 0, HASH_MAX_LEN);
+
+	fp = popen(sha_command, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "Failed to run command hash\n" );
+		exit(EXIT_FAILURE);
+	}
+
+	if (fgets(hash, digest_length + 1, fp) == NULL) {
+		fprintf(stderr, "Failed to hash file: %s\n", filename ? filename : "<none>");
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 0; i < strlen(hash)/2; i++)
+		sscanf(hash + 2*i, "%02hhx", &img->hash[i]);
+
+	pclose(fp);
+}
+
+#define append(p, s, l) do {memcpy(p, (uint8_t *)s, l); p += l; } while (0)
+
+static uint8_t *flatten_container_header(struct imx_header_v3 *imx_header,
+					uint8_t containers_count,
+					uint32_t *size_out, uint32_t file_offset)
+{
+	uint8_t *flat = NULL;
+	uint8_t *ptr = NULL;
+	uint16_t size = 0;
+	int i;
+
+	/* Compute size of all container headers */
+	for (i = 0; i < containers_count; i++) {
+
+		struct flash_header_v3 *container = &imx_header->fhdr[i];
+
+		container->sig_blk_offset = HEADER_IMG_ARRAY_OFFSET +
+			container->num_images * IMG_ARRAY_ENTRY_SIZE;
+
+		container->length = HEADER_IMG_ARRAY_OFFSET +
+			(IMG_ARRAY_ENTRY_SIZE * container->num_images) + sizeof(struct sig_blk_hdr);
+
+		/* Print info needed by CST to sign the container header */
+		printf("CST: CONTAINER %d offset: 0x%x\n", i, file_offset + size);
+		printf("CST: CONTAINER %d: Signature Block: offset is at 0x%x\n", i,
+						file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH);
+
+		printf("\tOffsets = \t0x%x \t0x%x\n", file_offset + size,
+						file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH);
+
+		size += ALIGN(container->length, container->padding);
+	}
+
+	flat = calloc(size, sizeof(uint8_t));
+	if (!flat) {
+		fprintf(stderr, "Failed to allocate memory (%d)\n", size);
+		exit(EXIT_FAILURE);
+	}
+
+	ptr = flat;
+	*size_out = size;
+
+	for (i = 0; i < containers_count; i++) {
+		struct flash_header_v3 *container = &imx_header->fhdr[i];
+		uint32_t container_start_offset = ptr - flat;
+		int j;
+
+		/* Append container header */
+		append(ptr, container, HEADER_IMG_ARRAY_OFFSET);
+
+		/* Adjust images offset to start from container headers start */
+		for (j = 0; j < container->num_images; j++)
+			container->img[j].offset -= container_start_offset + file_offset;
+
+		/* Append each image array entry */
+		for (j = 0; j < container->num_images; j++)
+			append(ptr, &container->img[j], sizeof(struct boot_img));
+
+		append(ptr, &container->sig_blk_hdr, sizeof(struct sig_blk_hdr));
+
+		/* Padding for container (if necessary) */
+		ptr += ALIGN(container->length, container->padding) - container->length;
+	}
+
+	return flat;
+}
+
+static uint64_t read_dcd_offset(char *filename)
+{
+	int dfd;
+	struct stat sbuf;
+	uint8_t *ptr;
+	uint64_t offset = 0;
+
+	dfd = open(filename, O_RDONLY|O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	offset = *(uint32_t *)(ptr + DCD_ENTRY_ADDR_IN_SCFW);
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+	(void) close(dfd);
+
+	return offset;
+}
+
+static uint32_t get_hash_algo(char *images_hash)
+{
+	uint32_t hash_algo;
+	const char *hash_name;
+
+	if (!images_hash) {
+		hash_algo = IMAGE_HASH_ALGO_DEFAULT;
+		hash_name = IMAGE_HASH_ALGO_DEFAULT_NAME;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_256)) {
+		hash_algo = HASH_TYPE_SHA_256;
+		hash_name = HASH_STR_SHA_256;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_384)) {
+		hash_algo = HASH_TYPE_SHA_384;
+		hash_name = HASH_STR_SHA_384;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_512)) {
+		hash_algo = HASH_TYPE_SHA_512;
+		hash_name = HASH_STR_SHA_512;
+	} else if (!strcmp(images_hash, HASH_STR_SM3)) {
+		hash_algo = HASH_TYPE_SM3;
+		hash_name = HASH_STR_SM3;
+	} else {
+		fprintf(stderr,
+			"\nERROR: %s is an invalid hash argument\n"
+			"    Expected values: %s, %s, %s, %s\n\n",
+			images_hash, HASH_STR_SHA_256, HASH_STR_SHA_384,
+			HASH_STR_SHA_512, HASH_STR_SM3);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("image hash type:\t%s\n", hash_name);
+	return hash_algo;
+}
+
+static void set_image_array_entry(struct flash_header_v3 *container, soc_type_t soc,
+		const image_t *image_stack, uint32_t offset,
+		uint32_t size, char *tmp_filename, bool dcd_skip, char *images_hash)
+{
+	uint64_t entry = image_stack->entry;
+	uint64_t dst = image_stack->dst;
+	uint64_t core = image_stack->ext;
+	uint32_t meta;
+	char *tmp_name = "";
+	option_type_t type = image_stack->option;
+	struct boot_img *img = &container->img[container->num_images];
+
+	if (container->num_images >= MAX_NUM_IMGS) {
+		fprintf(stderr, "Error: Container allows 8 images at most\n");
+		exit(EXIT_FAILURE);
+	}
+
+	img->offset = offset;  /* Is re-adjusted later */
+	img->size = size;
+
+	set_image_hash(img, tmp_filename, get_hash_algo(images_hash));
+
+	switch (type) {
+	case SECO:
+		if (container->num_images > 0) {
+			fprintf(stderr, "Error: SECO container only allows 1 image\n");
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_SECO;
+		img->hab_flags |= CORE_SECO << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SECO";
+		img->dst = 0x20C00000;
+		img->entry = 0x20000000;
+
+		break;
+	case SENTINEL:
+		if (container->num_images > 0) {
+			fprintf(stderr, "Error: SENTINEL container only allows 1 image\n");
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_SENTINEL;
+		img->hab_flags |= CORE_ULP_SENTINEL << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SENTINEL";
+		img->dst = 0XE7FE8000; /* S400 IRAM base */
+		img->entry = 0XE7FE8000;
+
+		break;
+	case AP:
+		if ((soc == QX || soc == DXL) && core == CORE_CA35)
+			meta = IMAGE_A35_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (soc == QM && core == CORE_CA53)
+			meta = IMAGE_A53_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (soc == QM && core == CORE_CA72)
+			meta = IMAGE_A72_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (((soc == ULP) || (soc == IMX9)) && core == CORE_CA35)
+			meta = 0;
+		else {
+			fprintf(stderr, "Error: invalid AP core id: %" PRIi64 "\n", core);
+			exit(EXIT_FAILURE);
+		}
+		img->hab_flags |= IMG_TYPE_EXEC;
+		if ((soc == ULP) || (soc == IMX9))
+			img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		else
+			img->hab_flags |= CORE_CA53 << BOOT_IMG_FLAGS_CORE_SHIFT; /* On B0, only core id = 4 is valid */
+		tmp_name = "AP";
+		img->dst = entry;
+		img->entry = entry;
+		img->meta = meta;
+		custom_partition = 0;
+		break;
+	case M4:
+		if ((soc == ULP) || (soc == IMX9)) {
+			core = CORE_ULP_CM33;
+			meta = 0;
+		} else if (core == 0) {
+			core = CORE_CM4_0;
+			meta = IMAGE_M4_0_DEFAULT_META(custom_partition);
+		} else if (core == 1) {
+			core = CORE_CM4_1;
+			meta = IMAGE_M4_1_DEFAULT_META(custom_partition);
+		} else {
+			fprintf(stderr, "Error: invalid m4 core id: %" PRIi64 "\n", core);
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_EXEC;
+		img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "M4";
+		if ((entry & 0x7) != 0)
+			fprintf(stderr, "\n\nWarning: M4 Destination address is not 8 byte aligned\n\n");
+
+		if (dst)
+			img->dst = dst;
+		else
+			img->dst = entry;
+
+		img->entry = entry;
+		img->meta = meta;
+		custom_partition = 0;
+		break;
+	case DATA:
+		img->hab_flags |= IMG_TYPE_DATA;
+		if ((soc == ULP) || (soc == IMX9))
+			if (core == CORE_CM4_0)
+				img->hab_flags |= CORE_ULP_CM33 << BOOT_IMG_FLAGS_CORE_SHIFT;
+			else
+				img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		else
+			img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "DATA";
+		img->dst = entry;
+		break;
+	case MSG_BLOCK:
+		img->hab_flags |= IMG_TYPE_DATA;
+		img->hab_flags |= CORE_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		img->meta = core << BOOT_IMG_META_MU_RID_SHIFT;
+		tmp_name = "MSG_BLOCK";
+		img->dst = entry;
+		break;
+	case SCFW:
+		img->hab_flags |= scfw_flags & 0xFFFF0000;
+		img->hab_flags |= IMG_TYPE_EXEC;
+		img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SCFW";
+		img->dst = 0x1FFE0000;
+		img->entry = 0x1FFE0000;
+
+		/* Lets add the DCD now */
+		if (!dcd_skip) {
+			container->num_images++;
+			img = &container->img[container->num_images];
+			img->hab_flags |= IMG_TYPE_DCD_DDR;
+			img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+			set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT);
+			img->offset = offset + img->size;
+			img->entry = read_dcd_offset(tmp_filename);
+			img->dst = img->entry - 1;
+		}
+		break;
+	case UPOWER:
+		if (soc == ULP) {
+			img->hab_flags |= IMG_TYPE_EXEC;
+			img->hab_flags |= CORE_ULP_UPOWER << BOOT_IMG_FLAGS_CORE_SHIFT;
+			tmp_name = "UPOWER";
+			img->dst = 0x28300200; /* UPOWER code RAM */
+			img->entry = 0x28300200;
+		}
+		break;
+	case DUMMY_V2X:
+		img->hab_flags |= IMG_TYPE_V2X_DUMMY;
+		img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "V2X Dummy";
+		img->dst = entry;
+		img->entry = entry;
+		img->size = 0; /* dummy image has no size */
+		break;
+	case FCB:
+		img->hab_flags |= IMG_TYPE_FCB_CHK;
+		img->dst = entry;
+		tmp_name = "FCB";
+		break;
+	default:
+		fprintf(stderr, "unrecognized image type (%d)\n", type);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s file_offset = 0x%x size = 0x%x\n", tmp_name, offset, size);
+
+	container->num_images++;
+}
+
+static void set_container(struct flash_header_v3 *container,  uint16_t sw_version,
+			uint32_t alignment, uint32_t flags, uint16_t fuse_version)
+{
+	container->sig_blk_hdr.tag = 0x90;
+	container->sig_blk_hdr.length = sizeof(struct sig_blk_hdr);
+	container->sw_version = sw_version;
+	container->padding = alignment;
+	container->fuse_version = fuse_version;
+	container->flags = flags;
+	printf("flags:\t\t\t0x%x\n", container->flags);
+}
+
+static int get_container_image_start_pos(image_t *image_stack, uint32_t align, soc_type_t soc,
+					 uint32_t *scu_cont_hdr_off)
+{
+	image_t *img_sp = image_stack;
+	/* 8K total container header */
+	int file_off = CONTAINER_IMAGE_ARRAY_START_OFFSET,  ofd = -1;
+	struct flash_header_v3 header;
+
+	while (img_sp->option != NO_IMG) {
+		if (img_sp->option != APPEND) {
+			img_sp++;
+			continue;
+		}
+
+		ofd = open(img_sp->filename, O_RDONLY);
+		if (ofd < 0) {
+			printf("Failure open first container file %s\n", img_sp->filename);
+			break;
+		}
+
+		if (soc == DXL) {
+			/* Skip SECO container, jump to V2X container */
+			if (lseek(ofd, CONTAINER_ALIGNMENT, SEEK_SET) < 0) {
+				printf("Failure Skip SECO header \n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		if (read(ofd, &header, sizeof(header)) != sizeof(header)) {
+			printf("Failure Read header \n");
+			exit(EXIT_FAILURE);
+		}
+
+		close(ofd);
+
+		if (header.tag != IVT_HEADER_TAG_B0) {
+			printf("header tag mismatch %x\n", header.tag);
+		} else if (header.num_images == 0) {
+			printf("image num is 0 \n");
+		} else {
+			file_off = header.img[header.num_images - 1].offset + header.img[header.num_images - 1].size;
+			if (soc == DXL) {
+				file_off += CONTAINER_ALIGNMENT;
+				*scu_cont_hdr_off = CONTAINER_ALIGNMENT + ALIGN(header.length, CONTAINER_ALIGNMENT);
+			} else {
+				*scu_cont_hdr_off = ALIGN(header.length, CONTAINER_ALIGNMENT);
+			}
+			file_off = ALIGN(file_off, align);
+		}
+
+		img_sp++;
+	}
+
+	return file_off;
+}
+
+static void check_file(struct stat *sbuf, char *filename)
+{
+	int tmp_fd  = open(filename, O_RDONLY | O_BINARY);
+
+	if (tmp_fd < 0) {
+		fprintf(stderr, "%s: Can't open: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(tmp_fd, sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	close(tmp_fd);
+}
+
+static void copy_file(int ifd, const char *datafile, int pad, int offset)
+{
+	int dfd;
+	struct stat sbuf;
+	unsigned char *ptr;
+	int tail;
+	uint8_t zeros[4096];
+	int size, ret;
+
+	memset(zeros, 0, sizeof(zeros));
+
+	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "Can't stat %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (sbuf.st_size == 0)
+		goto close;
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	size = sbuf.st_size;
+	ret = lseek(ifd, offset, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (write(ifd, ptr, size) != size) {
+		fprintf(stderr, "Write error %s\n", strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	tail = size % 4;
+	pad = pad - size;
+	if ((pad == 1) && (tail != 0)) {
+
+		if (write(ifd, zeros, 4 - tail) != 4 - tail) {
+			fprintf(stderr, "Write error on %s\n", strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+	} else if (pad > 1) {
+		while (pad > 0) {
+			int todo = sizeof(zeros);
+
+			if (todo > pad)
+				todo = pad;
+			if (write(ifd, (char *)&zeros, todo) != todo) {
+				fprintf(stderr, "Write error: %s\n",
+					strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			pad -= todo;
+		}
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+close:
+	(void) close (dfd);
+}
+
+static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32_t ivt_offset,
+				    char *out_file, bool emmc_fastboot, image_t *image_stack,
+				    bool dcd_skip, uint8_t fuse_version, uint16_t sw_version,
+				    char *images_hash)
+{
+	int file_off, ofd = -1;
+	unsigned int dcd_len = 0;
+	struct imx_header_v3 imx_header = {};
+	image_t *img_sp = image_stack;
+	struct stat sbuf;
+	uint32_t size = 0;
+	uint32_t file_padding = 0;
+	int ret;
+	const char *platform;
+
+	int container = -1;
+	int cont_img_count = 0; /* indexes to arrange the container */
+
+	if (image_stack == NULL) {
+		fprintf(stderr, "Empty image stack ");
+		exit(EXIT_FAILURE);
+	}
+
+	switch (soc) {
+	case QX: platform = "i.MX8QXP B0"; break;
+	case QM: platform = "i.MX8QM B0"; break;
+	case DXL: platform = "i.MX8DXL A0"; break;
+	case ULP: platform = "i.MX8ULP A0"; break;
+	case IMX9: platform = "i.MX9"; break;
+	default:
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Platform:\t\t%s\n", platform);
+
+	set_imx_hdr_v3(&imx_header, dcd_len, ivt_offset, INITIAL_LOAD_ADDR_SCU_ROM, 0);
+	set_imx_hdr_v3(&imx_header, 0, ivt_offset, INITIAL_LOAD_ADDR_AP_ROM, 1);
+
+	printf("ivt_offset:\t\t0x%x\n", ivt_offset);
+
+	file_off = get_container_image_start_pos(image_stack, sector_size, soc, &file_padding);
+	printf("container image offset (aligned): 0x%x\n", file_off);
+
+	printf("csf_off:\t\t0x%x\n", ivt_offset + file_off);
+
+	/* step through image stack and generate the header */
+	img_sp = image_stack;
+
+	while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */
+		switch (img_sp->option) {
+		case FCB:
+		case AP:
+		case M4:
+		case SCFW:
+		case DATA:
+		case UPOWER:
+		case MSG_BLOCK:
+		case SENTINEL:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			check_file(&sbuf, img_sp->filename);
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						ALIGN(sbuf.st_size, sector_size),
+						img_sp->filename,
+						dcd_skip,
+						images_hash);
+			img_sp->src = file_off;
+
+			file_off += ALIGN(sbuf.st_size, sector_size);
+			cont_img_count++;
+			break;
+
+		case DUMMY_V2X:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						0,
+						NULL,
+						dcd_skip,
+						images_hash);
+			img_sp->src = file_off;
+
+			cont_img_count++;
+			break;
+
+		case SECO:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			check_file(&sbuf, img_sp->filename);
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						sbuf.st_size,
+						img_sp->filename,
+						dcd_skip,
+						"sha384");
+			img_sp->src = file_off;
+
+			file_off += sbuf.st_size;
+			cont_img_count++;
+			break;
+
+		case NEW_CONTAINER:
+			container++;
+			set_container(&imx_header.fhdr[container], sw_version,
+					CONTAINER_ALIGNMENT,
+					CONTAINER_FLAGS_DEFAULT,
+					fuse_version);
+			cont_img_count = 0; /* reset img count when moving to new container */
+			scfw_flags = 0;
+			break;
+
+		case APPEND:
+			/* nothing to do here, the container is appended in the output */
+			break;
+		case FLAG:
+			/* override the flags for scfw in current container */
+			scfw_flags = img_sp->entry & 0xFFFF0000;/* mask off bottom 16 bits */
+			break;
+		case FILEOFF:
+			if (file_off > img_sp->dst) {
+				fprintf(stderr, "FILEOFF address less than current file offset!!!\n");
+				exit(EXIT_FAILURE);
+			}
+			if (img_sp->dst != ALIGN(img_sp->dst, sector_size)) {
+				fprintf(stderr, "FILEOFF address is not aligned to sector size!!!\n");
+				exit(EXIT_FAILURE);
+			}
+			file_off = img_sp->dst;
+			break;
+		case PARTITION: /* keep custom partition until next executable image */
+			custom_partition = img_sp->entry; /* use a global var for default behaviour */
+			break;
+		default:
+			fprintf(stderr, "unrecognized option in input stack (%d)\n", img_sp->option);
+			exit(EXIT_FAILURE);
+		}
+		img_sp++;/* advance index */
+	}
+
+	/* Open output file */
+	ofd = open(out_file, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
+	if (ofd < 0) {
+		fprintf(stderr, "%s: Can't open: %s\n",
+				out_file, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Append container (if specified) */
+	img_sp = image_stack;
+	while (img_sp->option != NO_IMG) {
+		if (img_sp->option == APPEND)
+			copy_file(ofd, img_sp->filename, 0, 0);
+
+		img_sp++;
+	}
+
+	/* Add padding or skip appended container */
+	ret = lseek(ofd, file_padding, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Note: Image offset are not contained in the image */
+	uint8_t *tmp = flatten_container_header(&imx_header, container + 1, &size, file_padding);
+	/* Write image header */
+	if (write(ofd, tmp, size) != size) {
+		fprintf(stderr, "error writing image hdr\n");
+		exit(1);
+	}
+
+	/* Clean-up memory used by the headers */
+	free(tmp);
+
+	if (emmc_fastboot)
+		ivt_offset = 0; /*set ivt offset to 0 if emmc */
+
+	/* step through the image stack again this time copying images to final bin */
+	img_sp = image_stack;
+	while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */
+		if (img_sp->option == M4 ||
+		    img_sp->option == AP ||
+		    img_sp->option == DATA ||
+		    img_sp->option == SCD ||
+		    img_sp->option == SCFW ||
+		    img_sp->option == SECO ||
+		    img_sp->option == MSG_BLOCK ||
+		    img_sp->option == UPOWER ||
+		    img_sp->option == SENTINEL ||
+		    img_sp->option == FCB) {
+			copy_file_aligned(ofd, img_sp->filename, img_sp->src, sector_size);
+		}
+		img_sp++;
+	}
+
+	/* Close output file */
+	close(ofd);
+	return 0;
+}
+
+static struct img_flags parse_image_flags(uint32_t flags, char *flag_list, soc_type_t soc)
+{
+	struct img_flags img_flags;
+
+	strcpy(flag_list, "(");
+
+	/* first extract the image type */
+	strcat(flag_list, "IMG TYPE: ");
+	img_flags.type = flags & IMAGE_TYPE_MASK;
+
+	switch (img_flags.type) {
+
+	case 0x3:
+		strcat(flag_list, "Executable");
+		break;
+	case 0x4:
+		strcat(flag_list, "Data");
+		break;
+	case 0x5:
+		strcat(flag_list, "DDR Init");
+		break;
+	case 0x6:
+		if ((soc == ULP) || (soc == IMX9))
+			strcat(flag_list, "SENTINEL");
+		else
+			strcat(flag_list, "SECO");
+		break;
+	case 0x7:
+		strcat(flag_list, "Provisioning");
+		break;
+	case 0x8:
+		if (soc == IMX9)
+		    strcat(flag_list, "FCB Check");
+		else
+		    strcat(flag_list, "DEK validation");
+		break;
+	case 0xB:
+		strcat(flag_list, "Primary V2X FW image");
+		break;
+	case 0xC:
+		strcat(flag_list, "Secondary V2X FW image");
+		break;
+	case 0xD:
+		strcat(flag_list, "V2X ROM Patch image");
+		break;
+	case 0xE:
+		strcat(flag_list, "V2X Dummy image");
+		break;
+	default:
+		strcat(flag_list, "Invalid img type");
+		break;
+	}
+	strcat(flag_list, " | ");
+
+	/* next get the core id */
+	strcat(flag_list, "CORE ID: ");
+	img_flags.core_id = (flags >> CORE_ID_SHIFT) & CORE_ID_MASK;
+
+	if ((soc == ULP) || (soc == IMX9)) {
+		switch (img_flags.core_id) {
+		case CORE_ULP_CM33:
+			strcat(flag_list, "CORE_CM33");
+			break;
+		case CORE_ULP_SENTINEL:
+			strcat(flag_list, "CORE_SENTINEL");
+			break;
+		case CORE_ULP_UPOWER:
+			strcat(flag_list, "CORE_UPOWER");
+			break;
+		case CORE_ULP_CA35:
+			if (soc == IMX9)
+				strcat(flag_list, "CORE_CA55");
+			else
+				strcat(flag_list, "CORE_CA35");
+			break;
+		default:
+			strcat(flag_list, "Invalid core id");
+			break;
+		}
+	} else {
+		switch (img_flags.core_id) {
+		case CORE_SC:
+			strcat(flag_list, "CORE_SC");
+			break;
+		case CORE_CM4_0:
+			strcat(flag_list, "CORE_CM4_0");
+			break;
+		case CORE_CM4_1:
+			strcat(flag_list, "CORE_CM4_1");
+			break;
+		case CORE_CA53:
+			strcat(flag_list, "CORE_CA53");
+			break;
+		case CORE_CA72:
+			strcat(flag_list, "CORE_CA72");
+			break;
+		case CORE_SECO:
+			strcat(flag_list, "CORE_SECO");
+			break;
+		case CORE_V2X_P:
+			strcat(flag_list, "CORE_V2X_P");
+			break;
+		case CORE_V2X_S:
+			strcat(flag_list, "CORE_V2X_S");
+			break;
+		default:
+			strcat(flag_list, "Invalid core id");
+			break;
+		}
+	}
+	strcat(flag_list, " | ");
+
+	/* next get the hash type */
+	strcat(flag_list, "HASH TYPE: ");
+	img_flags.hash_type = (flags >> HASH_TYPE_SHIFT) & HASH_TYPE_MASK;
+
+	switch (img_flags.hash_type) {
+	case 0x0:
+		strcat(flag_list, "SHA256");
+		break;
+	case 0x1:
+		strcat(flag_list, "SHA384");
+		break;
+	case 0x2:
+		strcat(flag_list, "SHA512");
+		break;
+	case 0x3:
+		strcat(flag_list, "SM3");
+		break;
+	default:
+		break;
+	}
+	strcat(flag_list, " | ");
+
+	/* lastly, read the encrypted bit */
+	strcat(flag_list, "ENCRYPTED: ");
+	img_flags.encrypted = (flags >> IMAGE_ENCRYPTED_SHIFT) & IMAGE_ENCRYPTED_MASK;
+
+	if (img_flags.encrypted)
+		strcat(flag_list, "YES");
+	else
+		strcat(flag_list, "NO");
+
+	/* terminate flag string */
+	strcat(flag_list, ")");
+
+	return img_flags;
+}
+
+static void print_image_array_fields(struct flash_header_v3 *container_hdrs, soc_type_t soc, bool app_cntr)
+{
+	struct boot_img img; /* image array entry */
+	struct img_flags img_flags; /* image hab flags */
+	int hash_length = 0;
+	char img_name[32]; /* scfw, bootloader, etc. */
+	char hash_name[8]; /* sha256, sha384, or sha512 */
+	char flag_string[128]; /* text representation of image hab flags */
+	int i;
+
+	for (i = 0; i < container_hdrs->num_images; i++) {
+		/* get the next image array entry */
+		img = container_hdrs->img[i];
+
+		/* get the image flags */
+		img_flags = parse_image_flags(img.hab_flags, flag_string, soc);
+
+		/* determine the type of image */
+		switch (img_flags.type) {
+		case 0x3:
+			if ((soc == ULP) || (soc == IMX9)) {
+				if (img_flags.core_id == CORE_ULP_UPOWER)
+					strcpy(img_name, "uPower FW");
+				else if ((img_flags.core_id == CORE_ULP_CA35))
+					if (app_cntr)
+						strcpy(img_name, "A core Image");
+					else
+						strcpy(img_name, "Bootloader");
+				else if ((img_flags.core_id == CORE_ULP_CM33))
+					strcpy(img_name, "M33");
+
+			} else {
+				if (img_flags.core_id == CORE_SC)
+					strcpy(img_name, "SCFW");
+				else if ((img_flags.core_id == CORE_CA53) || (img_flags.core_id == CORE_CA72))
+					if (app_cntr)
+						strcpy(img_name, "A core Image");
+					else
+						strcpy(img_name, "Bootloader");
+				else if (img_flags.core_id == CORE_CM4_0)
+					strcpy(img_name, "M4_0");
+				else if (img_flags.core_id == CORE_CM4_1)
+					strcpy(img_name, "M4_1");
+			}
+			break;
+		case 0x4:
+			strcpy(img_name, "Data");
+			break;
+		case 0x5:
+			strcpy(img_name, "DDR Init");
+			break;
+		case 0x6:
+			if ((soc == ULP) || (soc == IMX9))
+				strcpy(img_name, "SENTINEL FW");
+			else
+				strcpy(img_name, "SECO FW");
+			break;
+		case 0x7:
+			strcpy(img_name, "Provisioning");
+			break;
+		case 0x8:
+			if (soc == IMX9)
+				strcpy(img_name, "FCB Check");
+			else
+				strcpy(img_name, "DEK Validation");
+			break;
+		case 0xB:
+			strcpy(img_name, "Primary V2X FW image");
+			break;
+		case 0xC:
+			strcpy(img_name, "Secondary V2X FW image");
+			break;
+		case 0xD:
+			strcpy(img_name, "V2X ROM Patch image");
+			break;
+		case 0xE:
+			strcpy(img_name, "V2X Dummy image");
+			break;
+		default:
+			strcpy(img_name, "Unknown image");
+			break;
+		}
+
+		/* get the image hash type */
+		switch (img_flags.hash_type) {
+		case 0x0:
+			hash_length = 256 / 8;
+			strcpy(hash_name, "SHA256");
+			break;
+		case 0x1:
+			hash_length = 384 / 8;
+			strcpy(hash_name, "SHA384");
+			break;
+		case 0x2:
+			hash_length = 512 / 8;
+			strcpy(hash_name, "SHA512");
+			break;
+		case 0x3:
+			hash_length = 256 / 8;
+			strcpy(hash_name, "SM3");
+			break;
+		default:
+			strcpy(hash_name, "Unknown");
+			break;
+		}
+
+		/* print the image array fields */
+		printf("%sIMAGE %d (%s)%s\n", "\x1B[33m", i+1, img_name, "\x1B[37m");
+		printf("Offset: %#X\n", img.offset);
+		printf("Size: %#X (%d)\n", img.size, img.size);
+		printf("Load Addr: %#lX\n", img.dst);
+		printf("Entry Addr: %#lX\n", img.entry);
+		printf("Flags: %#X %s\n", img.hab_flags, flag_string);
+
+		/* only print metadata and hash if the image isn't DDR init */
+		if (img_flags.type != 0x5) {
+			int j;
+
+			printf("Metadata: %#X\n", img.meta);
+
+			/* print the image hash */
+			printf("Hash: ");
+			for (j = 0; j < hash_length; j++)
+				printf("%02x", img.hash[j]);
+
+			printf(" (%s)\n", hash_name);
+
+		}
+		printf("\n");
+	}
+}
+
+static void print_container_hdr_fields(struct flash_header_v3 *container_hdrs, int num_cntrs,
+				       soc_type_t soc, bool app_cntr)
+{
+	int i;
+
+	for (i = 0; i < num_cntrs; i++) {
+		printf("\n");
+		printf("*********************************\n");
+		printf("*				*\n");
+		if (app_cntr)
+			printf("*          APP CONTAINER %-2d     *\n", i + 1);
+		else
+			printf("*          ROM CONTAINER %-2d     *\n", i + 1);
+		printf("*				*\n");
+		printf("*********************************\n\n");
+		printf("%16s", "Length: ");
+		printf("%#X (%d)\n", container_hdrs->length, container_hdrs->length);
+		printf("%16s", "Tag: ");
+		printf("%#X\n", container_hdrs->tag);
+		printf("%16s", "Version: ");
+		printf("%#X\n", container_hdrs->version);
+		printf("%16s", "Flags: ");
+		printf("%#X\n", container_hdrs->flags);
+		printf("%16s", "Num images: ");
+		printf("%d\n", container_hdrs->num_images);
+		printf("%16s", "Fuse version: ");
+		printf("%#X\n", container_hdrs->fuse_version);
+		printf("%16s", "SW version: ");
+		printf("%#X\n", container_hdrs->sw_version);
+		printf("%16s", "Sig blk offset: ");
+		printf("%#X\n\n", container_hdrs->sig_blk_offset);
+
+		print_image_array_fields(container_hdrs, soc, app_cntr);
+
+		container_hdrs++;
+	}
+}
+
+static int get_container_size(struct flash_header_v3 *phdr)
+{
+	uint8_t i = 0;
+	uint32_t max_offset = 0, img_end;
+
+	max_offset = phdr->length;
+
+	for (i = 0; i < phdr->num_images; i++) {
+		img_end = phdr->img[i].offset + phdr->img[i].size;
+		if (img_end > max_offset)
+			max_offset = img_end;
+	}
+
+	if (phdr->sig_blk_offset != 0) {
+		uint16_t len = phdr->sig_blk_hdr.length;
+
+		if (phdr->sig_blk_offset + len > max_offset)
+			max_offset = phdr->sig_blk_offset + len;
+	}
+
+	return max_offset;
+}
+
+static int search_app_container(struct flash_header_v3 *container_hdrs, int num_cntrs, int ifd,
+				struct flash_header_v3 *app_container_hdr)
+{
+	int off[MAX_NUM_OF_CONTAINER];
+	int end = 0, last = 0;
+	int img_array_entries = 0;
+	ssize_t rd_err;
+	off_t err;
+	int i;
+
+	off[0] = 0;
+
+	for (i = 0; i < num_cntrs; i++) {
+		end = get_container_size(&container_hdrs[i]);
+		if (end + off[i] > last)
+			last = end + off[i];
+
+		if ((i + 1) < num_cntrs)
+			off[i + 1] = off[i] + ALIGN(container_hdrs[i].length, CONTAINER_ALIGNMENT);
+	}
+
+	/* Check app container tag at each 1KB beginning until 16KB */
+	last = ALIGN(last, 0x400);
+	for (i = 0; i < 16; i++) {
+		last = last + (i * 0x400);
+		err = lseek(ifd, last, SEEK_SET);
+		if (err < 0)
+			break;
+
+		rd_err = read(ifd, (void *)app_container_hdr, 16);
+		if (rd_err < 0) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* check that the current container has a valid tag */
+		if (app_container_hdr->tag != IVT_HEADER_TAG_B0)
+			continue;
+
+		if (app_container_hdr->num_images > MAX_NUM_IMGS) {
+			fprintf(stderr, "This container includes %d images, beyond max 8 images\n",
+				app_container_hdr->num_images);
+			exit(EXIT_FAILURE);
+		}
+
+		/* compute the size of the image array */
+		img_array_entries = app_container_hdr->num_images * sizeof(struct boot_img);
+
+		/* read in the full image array */
+		rd_err = read(ifd, (void *)&app_container_hdr->img, img_array_entries);
+		if (rd_err < 0) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* read in signature block header */
+		if (app_container_hdr->sig_blk_offset != 0) {
+			lseek(ifd, last + app_container_hdr->sig_blk_offset, SEEK_SET);
+			rd_err = read(ifd, (void *)&app_container_hdr->sig_blk_hdr, sizeof(struct sig_blk_hdr));
+			if (rd_err == -1) {
+				fprintf(stderr, "Error reading from input binary\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		return last;
+	}
+
+	return 0;
+}
+
+static int extract_container_images(struct flash_header_v3 *container_hdr, char *ifname, int num_cntrs,
+				    int ifd, soc_type_t soc, int app_cntr_off)
+{
+	uint32_t img_offset = 0; /* image offset from container header */
+	uint32_t img_size = 0; /* image size */
+	uint32_t file_off = 0; /* current offset within container binary */
+	const uint32_t pad = 0;
+	int ofd = 0;
+	int ret = 0;
+	uint32_t seco_off = 0;
+	char dd_cmd[512]; /* dd cmd to extract each image from container binary */
+	struct stat buf;
+	FILE *f_ptr = NULL; /* file pointer to the dd process */
+	char *mem_ptr; /* pointer to input container in memory */
+	int i, j;
+
+	printf("Extracting container images...\n");
+
+	/* create output directory if it does not exist */
+	if (stat("extracted_imgs", &buf) == -1)
+		mkdir("extracted_imgs", S_IRWXU|S_IRWXG|S_IRWXO);
+
+	/* open container binary and map to memory */
+	fstat(ifd, &buf);
+	mem_ptr = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+
+	for (i = 0; i < num_cntrs; i++) {
+		for (j = 0; j < container_hdr->num_images; j++) {
+
+			/* first get the image offset and size from the container header */
+			img_offset = container_hdr->img[j].offset;
+			img_size = container_hdr->img[j].size;
+
+			if (!img_size) {
+				/* check for images with zero size (DDR Init) */
+				continue;
+			} else if (app_cntr_off > 0) {
+				sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/app_container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc",
+						ifname, i+1, j+1, app_cntr_off+img_offset, img_size);
+				printf("APP Container %d Image %d -> extracted_imgs/app_container%d_img%d.bin\n", i+1, j+1, i+1, j+1);
+
+			} else if ((i == 0) && (soc != DXL)) { /* first container is always SECO FW */
+				int k;
+
+				/* open output file */
+				ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
+
+				/* first copy container header to output image */
+				ret = write(ofd, (void *)mem_ptr, 1024);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file\n");
+
+
+				/* next, pad the output with zeros until the start of the image */
+				for (k = 0; k < (img_offset-CONTAINER_ALIGNMENT)/4; k++)
+					ret = write(ofd, (void *)&pad, 4);
+
+				/* now write the fw image to the output file */
+				ret = write(ofd, (void *)(mem_ptr+img_offset), img_size);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file\n");
+
+				/* close output file and unmap input file */
+				close(ofd);
+
+				printf("Container %d Image %d -> extracted_imgs/ahab-container.img\n", i+1, j+1);
+
+			} else if ((i < 2 ) && (soc == DXL)) { /* Second Container is Always V2X for DXL */
+				if (i == 0) {
+					/* open output file */
+					ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
+
+					/* first copy container header to output image */
+					ret = write(ofd, (void *)mem_ptr, 0x400);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file1\n");
+
+					/* For DXL go to next container to copy header */
+					seco_off = img_offset;
+					continue;
+				} else if (i == 1 && j == 0) {
+					int k;
+
+					/* copy v2x container header and seco fw */
+					ret = write(ofd,(void *) mem_ptr + file_off, container_hdr->length);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file2\n");
+
+
+					/* next, pad the output with zeros until the start of SECO image */
+					for (k = 0; k < (seco_off - (file_off + container_hdr->length)) / 4; k++)
+						ret = write(ofd, (void *)&pad, 4);
+
+					/* now write the SECO fw image to the output file */
+					ret = write(ofd, (void *)(mem_ptr+seco_off), file_off + img_offset - seco_off);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file3: %x\n",ret);
+				}
+
+				/* now write the next image to the output file */
+				ret = write(ofd, (void *)(mem_ptr + file_off + img_offset), img_size);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file4: %x\n",ret);
+
+				/* Iterate through V2X container for other images */
+				if (j < (container_hdr->num_images - 1))
+					continue;
+
+				/* close output file and unmap input file */
+				close(ofd);
+
+
+				printf("Container %d Image %d -> extracted_imgs/v2x-container.img\n", i+1, j+1);
+
+			} else {
+				sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc",
+						ifname, i+1, j+1, file_off+img_offset, img_size);
+				printf("Container %d Image %d -> extracted_imgs/container%d_img%d.bin\n", i+1, j+1, i+1, j+1);
+			}
+
+			/* run dd command to extract current image from container */
+			fprintf(stderr, "FOOO: %s\n", dd_cmd);
+			f_ptr = popen(dd_cmd, "r");
+			if (f_ptr == NULL) {
+				fprintf(stderr, "Failed to extract image\n");
+				exit(EXIT_FAILURE);
+			}
+
+			/* close the pipe */
+			pclose(f_ptr);
+		}
+
+		file_off += ALIGN(container_hdr->length, CONTAINER_ALIGNMENT);
+		container_hdr++;
+	}
+
+	munmap((void *)mem_ptr, buf.st_size);
+	printf("Done\n\n");
+	return 0;
+}
+
+static int parse_container_hdrs_qx_qm_b0(char *ifname, bool extract, soc_type_t soc, off_t file_off)
+{
+	int ifd; /* container file descriptor */
+	int max_containers = (soc == DXL) ? 3 : 2;
+	int cntr_num = 0; /* number of containers in binary */
+	int img_array_entries = 0; /* number of images in container */
+	ssize_t rd_err;
+	struct flash_header_v3 container_headers[MAX_NUM_OF_CONTAINER];
+	struct flash_header_v3 app_container_header;
+	int app_cntr_off;
+
+	/* initialize region of memory where flash header will be stored */
+	memset((void *)container_headers, 0, sizeof(container_headers));
+
+	/* open container binary */
+	ifd = open(ifname, O_RDONLY|O_BINARY);
+
+	if (file_off) /* inital offset within container binary */
+		lseek(ifd, file_off, SEEK_SET);
+
+	while (cntr_num < max_containers) {
+
+		/* read in next container header up to the image array */
+		rd_err = read(ifd, (void *)&container_headers[cntr_num], 16);
+		if (rd_err == -1) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* check that the current container has a valid tag */
+		if (container_headers[cntr_num].tag != IVT_HEADER_TAG_B0)
+			break;
+
+		if (container_headers[cntr_num].num_images > MAX_NUM_IMGS) {
+			fprintf(stderr, "This container includes %d images, beyond max 8 images\n",
+				container_headers[cntr_num].num_images);
+			exit(EXIT_FAILURE);
+		}
+
+		/* compute the size of the image array */
+		img_array_entries = container_headers[cntr_num].num_images * sizeof(struct boot_img);
+
+		/* read in the full image array */
+		rd_err = read(ifd, (void *)&container_headers[cntr_num].img, img_array_entries);
+		if (rd_err == -1) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (container_headers[cntr_num].sig_blk_offset != 0) {
+			/* read in signature block header */
+			lseek(ifd, file_off + container_headers[cntr_num].sig_blk_offset, SEEK_SET);
+			rd_err = read(ifd, (void *)&container_headers[cntr_num].sig_blk_hdr, sizeof(struct sig_blk_hdr));
+			if (rd_err == -1) {
+				fprintf(stderr, "Error reading from input binary\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		/* seek to next container in binary */
+		file_off += ALIGN(container_headers[cntr_num].length, CONTAINER_ALIGNMENT);
+		lseek(ifd, file_off, SEEK_SET);
+
+		/* increment current container count */
+		cntr_num++;
+	}
+
+
+	print_container_hdr_fields(container_headers, cntr_num, soc, false);
+
+	if (extract)
+		extract_container_images(container_headers, ifname, cntr_num, ifd, soc, 0);
+
+	app_cntr_off = search_app_container(container_headers, cntr_num, ifd, &app_container_header);
+
+	if (app_cntr_off > 0) {
+		print_container_hdr_fields(&app_container_header, 1, soc, true);
+		if (extract)
+			extract_container_images(&app_container_header, ifname, 1, ifd, soc, app_cntr_off);
+	}
+
+	close(ifd);
+
+	return 0;
+
+}
+
+#define IMG_STACK_SIZE			32 /* max of 32 images for commandline images */
+
+/*
+ * Read commandline parameters and construct the header in order
+ *
+ * This will then construct the image according to the header and
+ *
+ * parameters passed in
+ *
+ */
+int main(int argc, char **argv)
+{
+	int c;
+	char *ofname = NULL;
+	char *ifname = NULL;
+	bool output = false;
+	bool dcd_skip = false;
+	bool emmc_fastboot = false;
+	bool extract = false;
+	bool parse = false;
+
+	int container = -1;
+	image_t param_stack[IMG_STACK_SIZE];/* stack of input images */
+	int p_idx = 0;/* param index counter */
+	off_t file_off = 0;
+
+	uint32_t ivt_offset = IVT_OFFSET_SD;
+	uint32_t sector_size = 0x400; /* default sector size */
+	soc_type_t soc = NONE; /* Initially No SOC defined */
+
+	uint8_t  fuse_version = 0;
+	uint16_t sw_version   = 0;
+	char     *images_hash = NULL;
+
+	static struct option long_options[] = {
+		{"scfw", required_argument, NULL, 'f'},
+		{"seco", required_argument, NULL, 'O'},
+		{"m4", required_argument, NULL, 'm'},
+		{"ap", required_argument, NULL, 'a'},
+		{"dcd", required_argument, NULL, 'd'},
+		{"out", required_argument, NULL, 'o'},
+		{"flags", required_argument, NULL, 'l'},
+		{"scd", required_argument, NULL, 'x'},
+		{"csf", required_argument, NULL, 'z'},
+		{"dev", required_argument, NULL, 'e'},
+		{"soc", required_argument, NULL, 's'},
+		{"dummy",required_argument, NULL, 'y'},
+		{"container", no_argument, NULL, 'c'},
+		{"partition", required_argument, NULL, 'p'},
+		{"append", no_argument, NULL, 'A'},
+		{"data", required_argument, NULL, 'D'},
+		{"fileoff", required_argument, NULL, 'P'},
+		{"msg_blk", required_argument, NULL, 'M'},
+		{"fuse_version", required_argument, NULL, 'u'},
+		{"sw_version", required_argument, NULL, 'v'},
+		{"images_hash", required_argument, NULL, 'h'},
+		{"extract", required_argument, NULL, 'X'},
+		{"parse", required_argument, NULL, 'R'},
+		{"sentinel", required_argument, NULL, 'i'},
+		{"upower", required_argument, NULL, 'w'},
+		{"fcb", required_argument, NULL, 'b'},
+		{"padding", required_argument, NULL, 'G'},
+		{NULL, 0, NULL, 0}
+	};
+
+	/* scan in parameters in order */
+	while (1) {
+		/* getopt_long stores the option index here. */
+		int option_index = 0;
+
+		c = getopt_long_only (argc, argv, ":f:m:a:d:o:l:x:z:e:p:cu:v:h:i:w:",
+			long_options, &option_index);
+
+		/* Detect the end of the options. */
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 0:
+			fprintf(stderr, "option %s", long_options[option_index].name);
+			if (optarg)
+				fprintf(stderr, " with arg %s", optarg);
+			fprintf(stderr, "\n");
+			break;
+		case 'A':
+			param_stack[p_idx].option = APPEND;
+			param_stack[p_idx++].filename = argv[optind++];
+			break;
+		case 'p':
+			printf("PARTITION:\t%s\n", optarg);
+			param_stack[p_idx].option = PARTITION;
+			param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0);
+			break;
+		case 's':
+			if (!strncmp(optarg, "QX", 2)) {
+				soc = QX;
+			} else if (!strncmp(optarg, "QM", 2)) {
+				soc = QM;
+			} else if (!strncmp(optarg, "DXL", 3)) {
+				soc = DXL;
+			} else if (!strncmp(optarg, "ULP", 3)) {
+				soc = ULP;
+			} else if (!strncmp(optarg, "IMX9", 4)) {
+				soc = IMX9;
+			} else {
+				printf("unrecognized SOC: %s \n",optarg);
+				exit(EXIT_FAILURE);
+			}
+			printf("SOC: %s \n",optarg);
+			break;
+		case 'b':
+			printf("FCB:\t%s\n", optarg);
+			param_stack[p_idx].option = FCB;
+			param_stack[p_idx].filename = optarg;
+			if (optind < argc && *argv[optind] != '-') {
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-fcb option require Two arguments: filename, load address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'i':
+			printf("SENTINEL:\t%s\n", optarg);
+			param_stack[p_idx].option = SENTINEL;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'w':
+			printf("UPOWER:\t%s\n", optarg);
+			param_stack[p_idx].option = UPOWER;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'f':
+			printf("SCFW:\t%s\n", optarg);
+			param_stack[p_idx].option = SCFW;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'O':
+			printf("SECO:\t%s\n", optarg);
+			param_stack[p_idx].option = SECO;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'd':
+			printf("DCD:\t%s\n", optarg);
+			if (soc == DXL) {
+				if (!strncmp(optarg, "skip", 4)) {
+					dcd_skip = true;
+				} else {
+					fprintf(stderr, "\n-dcd option requires argument skip\n\n");
+					exit(EXIT_FAILURE);
+				}
+			} else if ((soc == ULP) || (soc == IMX9)) {
+				fprintf(stderr, "\n-dcd option is not used on ULP and IMX9\n\n");
+				exit(EXIT_FAILURE);
+			} else {
+				param_stack[p_idx].option = DCD;
+				param_stack[p_idx].filename = optarg;
+				p_idx++;
+			}
+			break;
+		case 'D':
+			if ((soc == DXL) || (soc == ULP) || (soc == IMX9)) {
+				printf("Data:\t%s", optarg);
+				param_stack[p_idx].option = DATA;
+				param_stack[p_idx].filename = optarg;
+				if ((optind < argc && *argv[optind] != '-') &&
+				    (optind+1 < argc && *argv[optind+1] != '-' )) {
+					if (!strncmp(argv[optind], "a53", 3))
+						param_stack[p_idx].ext = CORE_CA53;
+					else if (!strncmp(argv[optind], "a55", 3))
+						param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */
+					else if (!strncmp(argv[optind], "a35", 3))
+						param_stack[p_idx].ext = CORE_CA35;
+					else if (!strncmp(argv[optind], "a72", 3))
+						param_stack[p_idx].ext = CORE_CA72;
+					else if (!strncmp(argv[optind], "m4_1", 4))
+						param_stack[p_idx].ext = CORE_CM4_1;
+					else if (!strncmp(argv[optind], "m4", 2))
+						param_stack[p_idx].ext = CORE_CM4_0;
+					else {
+						fprintf(stderr, "ERROR: incorrect core ID for --data option: %s\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tcore: %s\n", argv[optind++]);
+					param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				} else {
+					fprintf(stderr, "\n-data option require THREE arguments: filename, core: a55/a35/a53/a72/m4_0/m4_1, load address in hex\n\n");
+					exit(EXIT_FAILURE);
+				}
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-data option is only used with -rev B0, or DXL or ULP or IMX9 soc.\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'm':
+			printf("CM4:\t%s", optarg);
+			param_stack[p_idx].option = M4;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind + 1 < argc &&*argv[optind+1] != '-' )) {
+				param_stack[p_idx].ext = strtol(argv[optind++], NULL, 0);
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				param_stack[p_idx].dst = 0;
+				printf("\tcore: %" PRIi64, param_stack[p_idx].ext);
+				printf(" entry addr: 0x%08" PRIx64 , param_stack[p_idx].entry);
+				if (optind < argc && *argv[optind] != '-') {
+					param_stack[p_idx].dst = (uint32_t) strtoll(argv[optind++], NULL, 0);
+					printf(" load addr: 0x%08" PRIx64 , param_stack[p_idx].dst);
+				}
+				printf("\n");
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-m4 option require FOUR arguments: filename, core: 0/1, entry address in hex, load address in hex(optional)\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'a':
+			printf("AP:\t%s", optarg);
+			param_stack[p_idx].option = AP;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind + 1 < argc &&*argv[optind+1] != '-' )) {
+				if (!strncmp(argv[optind], "a53", 3))
+					param_stack[p_idx].ext = CORE_CA53;
+				else if (!strncmp(argv[optind], "a55", 3))
+					param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */
+				else if (!strncmp(argv[optind], "a35", 3))
+					param_stack[p_idx].ext = CORE_CA35;
+				else if (!strncmp(argv[optind], "a72", 3))
+					param_stack[p_idx].ext = CORE_CA72;
+				else {
+					fprintf(stderr, "ERROR: AP Core not found %s\n", argv[optind+2]);
+					exit(EXIT_FAILURE);
+				}
+				printf("\tcore: %s", argv[optind++]);
+
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				param_stack[p_idx].mu = SC_R_MU_0A;
+				param_stack[p_idx].part = 1;
+
+				if (optind < argc && *argv[optind] != '-') {
+					if (!strncmp(argv[optind], "mu0", 3))
+						param_stack[p_idx].mu = SC_R_MU_0A;
+					else if (!strncmp(argv[optind], "mu3", 3))
+						param_stack[p_idx].mu = SC_R_MU_3A;
+					else {
+						fprintf(stderr, "ERROR: MU number %s not found\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tMU: %s ", argv[optind++]);
+				}
+				if (optind < argc && *argv[optind] != '-') {
+					if (!strncmp(argv[optind], "pt", 2) &&
+					    (argv[optind][2] > '0') &&
+					    (argv[optind][2] != '2') &&
+					    (argv[optind][2] <= '9')) {
+						char str[2];
+						str[0] = argv[optind][2];
+						str[1] = '\0';
+						param_stack[p_idx].part = strtoll(str, NULL, 0);
+					} else {
+						fprintf(stderr, "ERROR: partition number %s not found\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tPartition: %s ", argv[optind++]);
+				}
+				printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry);
+			} else {
+				fprintf(stderr, "\n-ap option require THREE arguments: filename, a35/a53/a72, start address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'l':
+			printf("FLAG:\t%s\n", optarg);
+			param_stack[p_idx].option = FLAG;
+			param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'o':
+			printf("Output:\t%s\n", optarg);
+			ofname = optarg;
+			output = true;
+			break;
+		case 'x':
+			printf("SCD:\t%s\n", optarg);
+			param_stack[p_idx].option = SCD;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'z':
+			printf("CSF:\t%s\n", optarg);
+			param_stack[p_idx].option = CSF;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'e':
+			printf("BOOT DEVICE:\t%s\n", optarg);
+			if (!strcmp(optarg, "flexspi")) {
+				ivt_offset = IVT_OFFSET_FLEXSPI;
+			} else if (!strcmp(optarg, "sd")) {
+				ivt_offset = IVT_OFFSET_SD;
+			} else if (!strcmp(optarg, "nand")) {
+				sector_size = 0x8000;/* sector size for NAND */
+				if ((soc == DXL) || (soc == IMX9)) {
+					if (optind < argc && *argv[optind] != '-') {
+						if (!strcmp(argv[optind], "4K")) {
+							sector_size = 0x1000;
+						} else if (!strcmp(argv[optind], "8K")) {
+							sector_size = 0x2000;
+						} else if (!strcmp(argv[optind], "16K")) {
+							sector_size = 0x4000;
+						} else
+							printf("\nwrong nand page size:\r\n 4K\r\n8K\r\n16K\n\n");
+					} else {
+						printf("\n-dev nand requires the page size:\r\n 4K\r\n8K\r\n16K\n\n");
+					}
+				}
+			} else if (!strcmp(optarg, "emmc_fast")) {
+					ivt_offset = IVT_OFFSET_EMMC;
+					emmc_fastboot = true;/* emmc boot */
+			} else {
+				printf("\n-dev option, Valid boot devices are:\r\n sd\r\nflexspi\r\nnand\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'c':
+			printf("New Container: \t%d\n",++container);
+			param_stack[p_idx++].option = NEW_CONTAINER;
+			break;
+		case ':':
+			fprintf(stderr, "option %c missing arguments\n", optopt);
+			exit(EXIT_FAILURE);
+			break;
+		case 'P':
+			printf("FILEOFF:\t%s\n", optarg);
+			param_stack[p_idx].option = FILEOFF;
+			param_stack[p_idx++].dst = (uint64_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'M':
+			printf("MSG BLOCK:\t%s", optarg);
+			param_stack[p_idx].option = MSG_BLOCK;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind+1 < argc &&*argv[optind + 1] != '-' )) {
+				if (!strncmp(argv[optind], "fuse", 4))
+					param_stack[p_idx].ext = SC_R_OTP;
+				else if (!strncmp(argv[optind], "debug", 5))
+					param_stack[p_idx].ext = SC_R_DEBUG;
+				else if (!strncmp(argv[optind], "field", 5))
+					param_stack[p_idx].ext = SC_R_ROM_0;
+				else if (!strncmp(argv[optind], "zero", 4))
+					param_stack[p_idx].ext = SC_R_PWM_0;
+				else if (!strncmp(argv[optind], "patch", 5))
+					param_stack[p_idx].ext = SC_R_SNVS;
+				else if (!strncmp(argv[optind], "degrade", 7))
+					param_stack[p_idx].ext = SC_R_DC_0;
+				else {
+					fprintf(stderr, "ERROR: MSG type not found %s\n", argv[optind+2]);
+					exit(EXIT_FAILURE);
+				}
+				printf("\ttype: %s", argv[optind++]);
+
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+
+				printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry);
+			} else {
+				fprintf(stderr, "\nmsg block option require THREE arguments: filename, debug/fuse/field/patch, start address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'u':
+			fuse_version = (uint8_t) (strtoll(optarg, NULL, 0) & 0xFF);
+			break;
+		case 'v':
+			sw_version = (uint16_t) (strtoll(optarg, NULL, 0) & 0xFFFF);
+			break;
+		case 'h':
+			images_hash = optarg;
+			break;
+		case 'X':
+			printf("Input container binary to be deconstructed: %s\n", optarg);
+			ifname = optarg;
+			extract = true;
+			break;
+		case 'R':
+			printf("Input container binary to be parsed: %s\n", optarg);
+			ifname = optarg;
+			parse = true;
+			break;
+		case 'y':
+			printf("Dummy V2X image at:\t%s\n", optarg);
+			param_stack[p_idx].option = DUMMY_V2X;
+			param_stack[p_idx++].entry = (uint64_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'G':
+			printf("Padding length:\t%s bytes\n", optarg);
+			file_off = atoi(optarg);
+			break;
+		case '?':
+		default:
+			/* invalid option */
+			fprintf(stderr, "option '%c' is invalid: ignored\n",
+				optopt);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!parse) {
+		printf("CONTAINER FUSE VERSION:\t0x%02x\n", fuse_version);
+		printf("CONTAINER SW VERSION:\t0x%04x\n", sw_version);
+	}
+
+	param_stack[p_idx].option = NO_IMG; /* null terminate the img stack */
+
+	if (soc == NONE) {
+		fprintf(stderr, " No SOC defined");
+		exit(EXIT_FAILURE);
+	}
+
+	if (parse || extract) {
+		parse_container_hdrs_qx_qm_b0(ifname, extract, soc, file_off);
+		return 0;
+	}
+
+	if (container < 0) {
+		/* check to make sure there is at least 1 container defined */
+		fprintf(stderr, " No Container defined");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!output) {
+		fprintf(stderr, "mandatory args scfw and output file name missing! abort\n");
+		exit(EXIT_FAILURE);
+	}
+
+	build_container_qx_qm_b0(soc, sector_size, ivt_offset, ofname, emmc_fastboot,
+				 (image_t *) param_stack, dcd_skip, fuse_version,
+				 sw_version, images_hash);
+
+	printf("DONE.\n");
+	printf("Note: Please copy image to offset: IVT_OFFSET + IMAGE_OFFSET\n");
+
+	return 0;
+}
+
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 05/25] scripts: imx9image: Add PBL size option
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (3 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 04/25] scripts: Add imx9image tool Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 06/25] clk: Add i.MX93 clock support Sascha Hauer
                   ` (19 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The i.MX9 ROM can only load images that fit into OCRAM. The barebox
image is usually bigger. This adds a -pblsize option that has the
effect that it sets the image size in the header to the provided pbl
size, so that the ROM only partially loads the image. barebox will
then use the ROMAPI to load the rest of the image.

We also add an additional alignment of 1KiB to the pblsize. This
helps us with USB booting, as the USB protocol uploads in chunks of
1KiB.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 scripts/imx9image.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/scripts/imx9image.c b/scripts/imx9image.c
index a991ba5f35..53fb879882 100644
--- a/scripts/imx9image.c
+++ b/scripts/imx9image.c
@@ -346,7 +346,7 @@ static void set_imx_hdr_v3(struct imx_header_v3 *imxhdr, uint32_t dcd_len,
 	fhdr_v3->version = IVT_VERSION_B0;
 }
 
-static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_type)
+static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_type, int size)
 {
 	FILE *fp = NULL;
 	char sha_command[512];
@@ -383,13 +383,11 @@ static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_t
 		break;
 	}
 
-	if (img->size == 0 || !filename)
+	if (!size || !filename)
 		sprintf(sha_command, "%s /dev/null", digest_type);
 	else
-		sprintf(sha_command, "dd status=none if=/dev/zero of=tmp_pad bs=%d count=1;\
-				dd status=none if=\'%s\' of=tmp_pad conv=notrunc;\
-				%s tmp_pad; rm -f tmp_pad",
-			img->size, filename, digest_type);
+		sprintf(sha_command, "cat \'%s\' /dev/zero | dd status=none bs=1 count=%d | %s",
+			filename, size, digest_type);
 
 	memset(img->hash, 0, HASH_MAX_LEN);
 
@@ -562,7 +560,7 @@ static void set_image_array_entry(struct flash_header_v3 *container, soc_type_t
 	img->offset = offset;  /* Is re-adjusted later */
 	img->size = size;
 
-	set_image_hash(img, tmp_filename, get_hash_algo(images_hash));
+	set_image_hash(img, tmp_filename, get_hash_algo(images_hash), size);
 
 	switch (type) {
 	case SECO:
@@ -678,7 +676,7 @@ static void set_image_array_entry(struct flash_header_v3 *container, soc_type_t
 			img = &container->img[container->num_images];
 			img->hab_flags |= IMG_TYPE_DCD_DDR;
 			img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
-			set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT);
+			set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT, 0);
 			img->offset = offset + img->size;
 			img->entry = read_dcd_offset(tmp_filename);
 			img->dst = img->entry - 1;
@@ -871,6 +869,8 @@ static void copy_file(int ifd, const char *datafile, int pad, int offset)
 	(void) close (dfd);
 }
 
+static int pblsize;
+
 static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32_t ivt_offset,
 				    char *out_file, bool emmc_fastboot, image_t *image_stack,
 				    bool dcd_skip, uint8_t fuse_version, uint16_t sw_version,
@@ -920,6 +920,7 @@ static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32
 	img_sp = image_stack;
 
 	while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */
+		int isize;
 		switch (img_sp->option) {
 		case FCB:
 		case AP:
@@ -934,11 +935,14 @@ static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32
 				exit(EXIT_FAILURE);
 			}
 			check_file(&sbuf, img_sp->filename);
+			isize = ALIGN(sbuf.st_size, sector_size);
+			if (pblsize && isize > ALIGN(pblsize, 1024))
+				isize = ALIGN(pblsize, 1024);
 			set_image_array_entry(&imx_header.fhdr[container],
 						soc,
 						img_sp,
 						file_off,
-						ALIGN(sbuf.st_size, sector_size),
+						isize,
 						img_sp->filename,
 						dcd_skip,
 						images_hash);
@@ -1788,6 +1792,7 @@ int main(int argc, char **argv)
 		{"upower", required_argument, NULL, 'w'},
 		{"fcb", required_argument, NULL, 'b'},
 		{"padding", required_argument, NULL, 'G'},
+		{"pblsize", required_argument, NULL, 0x1000},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -2122,6 +2127,9 @@ int main(int argc, char **argv)
 			printf("Padding length:\t%s bytes\n", optarg);
 			file_off = atoi(optarg);
 			break;
+		case 0x1000:
+			pblsize = atoi(optarg);
+			break;
 		case '?':
 		default:
 			/* invalid option */
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 06/25] clk: Add i.MX93 clock support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (4 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 05/25] scripts: imx9image: Add PBL size option Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 07/25] clk: imx: clk-fracn-gppll: make usable from PBL Sascha Hauer
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Based on Linux i.MX93 clock support as of Linux-6.6

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/imx/Makefile           |   1 +
 drivers/clk/imx/clk-composite-93.c | 216 ++++++++++++++++
 drivers/clk/imx/clk-fracn-gppll.c  | 392 +++++++++++++++++++++++++++++
 drivers/clk/imx/clk-gate-93.c      | 186 ++++++++++++++
 drivers/clk/imx/clk-imx93.c        | 331 ++++++++++++++++++++++++
 drivers/clk/imx/clk.h              |  42 ++++
 6 files changed, 1168 insertions(+)
 create mode 100644 drivers/clk/imx/clk-composite-93.c
 create mode 100644 drivers/clk/imx/clk-fracn-gppll.c
 create mode 100644 drivers/clk/imx/clk-gate-93.c
 create mode 100644 drivers/clk/imx/clk-imx93.c

diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 4a792422d5..eb9f8334c3 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -34,4 +34,5 @@ obj-$(CONFIG_ARCH_IMX8MM) += clk-imx8mm.o
 obj-$(CONFIG_ARCH_IMX8MN) += clk-imx8mn.o
 obj-$(CONFIG_ARCH_IMX8MP) += clk-imx8mp.o
 obj-$(CONFIG_ARCH_IMX8MQ) += clk-imx8mq.o
+obj-$(CONFIG_ARCH_IMX93) += clk-imx93.o clk-composite-93.o clk-gate-93.o clk-fracn-gppll.o
 obj-$(CONFIG_ARCH_VF610)  += clk-vf610.o
diff --git a/drivers/clk/imx/clk-composite-93.c b/drivers/clk/imx/clk-composite-93.c
new file mode 100644
index 0000000000..2b3753d569
--- /dev/null
+++ b/drivers/clk/imx/clk-composite-93.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <of_address.h>
+#include <linux/iopoll.h>
+
+#include "clk.h"
+
+#define TIMEOUT_US	500U
+
+#define CCM_DIV_SHIFT	0
+#define CCM_DIV_WIDTH	8
+#define CCM_MUX_SHIFT	8
+#define CCM_MUX_MASK	3
+#define CCM_OFF_SHIFT	24
+#define CCM_BUSY_SHIFT	28
+
+#define STAT_OFFSET	0x4
+#define AUTHEN_OFFSET	0x30
+#define TZ_NS_SHIFT	9
+#define TZ_NS_MASK	BIT(9)
+
+#define WHITE_LIST_SHIFT	16
+
+static int imx93_clk_composite_wait_ready(struct clk_hw *hw, void __iomem *reg)
+{
+	int ret;
+	u32 val;
+
+	ret = readl_poll_timeout(reg + STAT_OFFSET, val, !(val & BIT(CCM_BUSY_SHIFT)),
+				 TIMEOUT_US);
+	if (ret)
+		pr_err("Slice[%s] busy timeout\n", clk_hw_get_name(hw));
+
+	return ret;
+}
+
+static void imx93_clk_composite_gate_endisable(struct clk_hw *hw, int enable)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	u32 reg;
+
+	reg = readl(gate->reg);
+
+	if (enable)
+		reg &= ~BIT(gate->shift);
+	else
+		reg |= BIT(gate->shift);
+
+	writel(reg, gate->reg);
+
+	imx93_clk_composite_wait_ready(hw, gate->reg);
+}
+
+static int imx93_clk_composite_gate_enable(struct clk_hw *hw)
+{
+	imx93_clk_composite_gate_endisable(hw, 1);
+
+	return 0;
+}
+
+static void imx93_clk_composite_gate_disable(struct clk_hw *hw)
+{
+	imx93_clk_composite_gate_endisable(hw, 0);
+}
+
+static const struct clk_ops imx93_clk_composite_gate_ops = {
+	.enable = imx93_clk_composite_gate_enable,
+	.disable = imx93_clk_composite_gate_disable,
+	.is_enabled = clk_gate_is_enabled,
+};
+
+static unsigned long
+imx93_clk_composite_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long
+imx93_clk_composite_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
+{
+	return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int imx93_clk_composite_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+						unsigned long parent_rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	int value;
+	u32 val;
+	int ret;
+
+	value = divider_get_val(rate, parent_rate, divider->table, divider->width, divider->flags);
+	if (value < 0)
+		return value;
+
+	val = readl(divider->reg);
+	val &= ~(clk_div_mask(divider->width) << divider->shift);
+	val |= (u32)value << divider->shift;
+	writel(val, divider->reg);
+
+	ret = imx93_clk_composite_wait_ready(hw, divider->reg);
+
+	return ret;
+}
+
+static const struct clk_ops imx93_clk_composite_divider_ops = {
+	.recalc_rate = imx93_clk_composite_divider_recalc_rate,
+	.round_rate = imx93_clk_composite_divider_round_rate,
+	.set_rate = imx93_clk_composite_divider_set_rate,
+};
+
+static int imx93_clk_composite_mux_get_parent(struct clk_hw *hw)
+{
+	return clk_mux_ops.get_parent(hw);
+}
+
+static int imx93_clk_composite_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
+	u32 reg;
+	int ret;
+
+	reg = readl(mux->reg);
+	reg &= ~(((1 << mux->width) - 1) << mux->shift);
+	val = val << mux->shift;
+	reg |= val;
+	writel(reg, mux->reg);
+
+	ret = imx93_clk_composite_wait_ready(hw, mux->reg);
+
+	return ret;
+}
+
+static const struct clk_ops imx93_clk_composite_mux_ops = {
+	.get_parent = imx93_clk_composite_mux_get_parent,
+	.set_parent = imx93_clk_composite_mux_set_parent,
+};
+
+struct clk *imx93_clk_composite_flags(const char *name, const char * const *parent_names,
+				      int num_parents, void __iomem *reg, u32 domain_id,
+				      unsigned long flags)
+{
+	struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
+	struct clk_hw *div_hw, *gate_hw;
+	struct clk_divider *div = NULL;
+	struct clk_gate *gate = NULL;
+	struct clk_mux *mux = NULL;
+	bool clk_ro = false;
+	u32 authen;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		goto fail;
+
+	mux_hw = &mux->hw;
+	mux->reg = reg;
+	mux->shift = CCM_MUX_SHIFT;
+	mux->width = 2;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		goto fail;
+
+	div_hw = &div->hw;
+	div->reg = reg;
+	div->shift = CCM_DIV_SHIFT;
+	div->width = CCM_DIV_WIDTH;
+//	div->flags = CLK_DIVIDER_ROUND_CLOSEST;
+
+	authen = readl(reg + AUTHEN_OFFSET);
+	if (!(authen & TZ_NS_MASK) || !(authen & BIT(WHITE_LIST_SHIFT + domain_id)))
+		clk_ro = true;
+
+	if (clk_ro) {
+		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+					       mux_hw, &clk_mux_ro_ops, div_hw,
+					       &clk_divider_ro_ops, NULL, NULL, flags);
+	} else {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate)
+			goto fail;
+
+		gate_hw = &gate->hw;
+		gate->reg = reg;
+		gate->shift = CCM_OFF_SHIFT;
+		gate->flags = CLK_GATE_SET_TO_DISABLE;
+
+		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+					       mux_hw, &imx93_clk_composite_mux_ops, div_hw,
+					       &imx93_clk_composite_divider_ops, gate_hw,
+					       &imx93_clk_composite_gate_ops,
+					       flags | CLK_SET_RATE_NO_REPARENT);
+	}
+
+	if (IS_ERR(hw))
+		goto fail;
+
+	return &hw->clk;
+
+fail:
+	kfree(gate);
+	kfree(div);
+	kfree(mux);
+	return ERR_CAST(hw);
+}
+EXPORT_SYMBOL_GPL(imx93_clk_composite_flags);
diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
new file mode 100644
index 0000000000..5fbc79f948
--- /dev/null
+++ b/drivers/clk/imx/clk-fracn-gppll.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <of_address.h>
+#include <linux/iopoll.h>
+#include <linux/bitfield.h>
+
+#include "clk.h"
+
+#define PLL_CTRL		0x0
+#define HW_CTRL_SEL		BIT(16)
+#define CLKMUX_BYPASS		BIT(2)
+#define CLKMUX_EN		BIT(1)
+#define POWERUP_MASK		BIT(0)
+
+#define PLL_ANA_PRG		0x10
+#define PLL_SPREAD_SPECTRUM	0x30
+
+#define PLL_NUMERATOR		0x40
+#define PLL_MFN_MASK		GENMASK(31, 2)
+
+#define PLL_DENOMINATOR		0x50
+#define PLL_MFD_MASK		GENMASK(29, 0)
+
+#define PLL_DIV			0x60
+#define PLL_MFI_MASK		GENMASK(24, 16)
+#define PLL_RDIV_MASK		GENMASK(15, 13)
+#define PLL_ODIV_MASK		GENMASK(7, 0)
+
+#define PLL_DFS_CTRL(x)		(0x70 + (x) * 0x10)
+
+#define PLL_STATUS		0xF0
+#define LOCK_STATUS		BIT(0)
+
+#define DFS_STATUS		0xF4
+
+#define LOCK_TIMEOUT_US		200
+
+#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv)	\
+	{							\
+		.rate	=	(_rate),			\
+		.mfi	=	(_mfi),				\
+		.mfn	=	(_mfn),				\
+		.mfd	=	(_mfd),				\
+		.rdiv	=	(_rdiv),			\
+		.odiv	=	(_odiv),			\
+	}
+
+#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv)		\
+	{							\
+		.rate	=	(_rate),			\
+		.mfi	=	(_mfi),				\
+		.mfn	=	0,				\
+		.mfd	=	0,				\
+		.rdiv	=	(_rdiv),			\
+		.odiv	=	(_odiv),			\
+	}
+
+struct clk_fracn_gppll {
+	struct clk_hw			hw;
+	void __iomem			*base;
+	const struct imx_fracn_gppll_rate_table *rate_table;
+	int rate_count;
+	u32 flags;
+};
+
+/*
+ * Fvco = (Fref / rdiv) * (MFI + MFN / MFD)
+ * Fout = Fvco / odiv
+ * The (Fref / rdiv) should be in range 20MHz to 40MHz
+ * The Fvco should be in range 2.5Ghz to 5Ghz
+ */
+static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
+	PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
+	PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
+	PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
+	PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8),
+	PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
+	PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
+	PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
+	PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
+	PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
+	PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
+};
+
+struct imx_fracn_gppll_clk imx_fracn_gppll = {
+	.rate_table = fracn_tbl,
+	.rate_count = ARRAY_SIZE(fracn_tbl),
+};
+EXPORT_SYMBOL_GPL(imx_fracn_gppll);
+
+/*
+ * Fvco = (Fref / rdiv) * MFI
+ * Fout = Fvco / odiv
+ * The (Fref / rdiv) should be in range 20MHz to 40MHz
+ * The Fvco should be in range 2.5Ghz to 5Ghz
+ */
+static const struct imx_fracn_gppll_rate_table int_tbl[] = {
+	PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
+	PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
+	PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
+};
+
+struct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
+	.rate_table = int_tbl,
+	.rate_count = ARRAY_SIZE(int_tbl),
+};
+EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer);
+
+static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw)
+{
+	return container_of(hw, struct clk_fracn_gppll, hw);
+}
+
+static const struct imx_fracn_gppll_rate_table *
+imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
+{
+	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+	int i;
+
+	for (i = 0; i < pll->rate_count; i++)
+		if (rate == rate_table[i].rate)
+			return &rate_table[i];
+
+	return NULL;
+}
+
+static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long *prate)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+	int i;
+
+	/* Assuming rate_table is in descending order */
+	for (i = 0; i < pll->rate_count; i++)
+		if (rate >= rate_table[i].rate)
+			return rate_table[i].rate;
+
+	/* return minimum supported value */
+	return rate_table[pll->rate_count - 1].rate;
+}
+
+static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+	u32 pll_numerator, pll_denominator, pll_div;
+	u32 mfi, mfn, mfd, rdiv, odiv;
+	u64 fvco = parent_rate;
+	long rate = 0;
+	int i;
+
+	pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
+	mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
+
+	pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
+	mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
+
+	pll_div = readl_relaxed(pll->base + PLL_DIV);
+	mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
+
+	rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
+	odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
+
+	/*
+	 * Sometimes, the recalculated rate has deviation due to
+	 * the frac part. So find the accurate pll rate from the table
+	 * first, if no match rate in the table, use the rate calculated
+	 * from the equation below.
+	 */
+	for (i = 0; i < pll->rate_count; i++) {
+		if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
+		    rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
+		    rate_table[i].odiv == odiv)
+			rate = rate_table[i].rate;
+	}
+
+	if (rate)
+		return (unsigned long)rate;
+
+	if (!rdiv)
+		rdiv = rdiv + 1;
+
+	switch (odiv) {
+	case 0:
+		odiv = 2;
+		break;
+	case 1:
+		odiv = 3;
+		break;
+	default:
+		break;
+	}
+
+	if (pll->flags & CLK_FRACN_GPPLL_INTEGER) {
+		/* Fvco = (Fref / rdiv) * MFI */
+		fvco = fvco * mfi;
+		do_div(fvco, rdiv * odiv);
+	} else {
+		/* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
+		fvco = fvco * mfi * mfd + fvco * mfn;
+		do_div(fvco, mfd * rdiv * odiv);
+	}
+
+	return (unsigned long)fvco;
+}
+
+static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
+{
+	u32 val;
+
+	return readl_poll_timeout(pll->base + PLL_STATUS, val,
+				  val & LOCK_STATUS, LOCK_TIMEOUT_US);
+}
+
+static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
+				    unsigned long prate)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	const struct imx_fracn_gppll_rate_table *rate;
+	u32 tmp, pll_div, ana_mfn;
+	int ret;
+
+	rate = imx_get_pll_settings(pll, drate);
+
+	/* Hardware control select disable. PLL is control by register */
+	tmp = readl_relaxed(pll->base + PLL_CTRL);
+	tmp &= ~HW_CTRL_SEL;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	/* Disable output */
+	tmp = readl_relaxed(pll->base + PLL_CTRL);
+	tmp &= ~CLKMUX_EN;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	/* Power Down */
+	tmp &= ~POWERUP_MASK;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	/* Disable BYPASS */
+	tmp &= ~CLKMUX_BYPASS;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
+		FIELD_PREP(PLL_MFI_MASK, rate->mfi);
+	writel_relaxed(pll_div, pll->base + PLL_DIV);
+	if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
+		writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
+		writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
+	}
+
+	/* Wait for 5us according to fracn mode pll doc */
+	udelay(5);
+
+	/* Enable Powerup */
+	tmp |= POWERUP_MASK;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	/* Wait Lock */
+	ret = clk_fracn_gppll_wait_lock(pll);
+	if (ret)
+		return ret;
+
+	/* Enable output */
+	tmp |= CLKMUX_EN;
+	writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+	ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
+	ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
+
+	WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
+
+	return 0;
+}
+
+static int clk_fracn_gppll_prepare(struct clk_hw *hw)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	u32 val;
+	int ret;
+
+	val = readl_relaxed(pll->base + PLL_CTRL);
+	if (val & POWERUP_MASK)
+		return 0;
+
+	val |= CLKMUX_BYPASS;
+	writel_relaxed(val, pll->base + PLL_CTRL);
+
+	val |= POWERUP_MASK;
+	writel_relaxed(val, pll->base + PLL_CTRL);
+
+	val |= CLKMUX_EN;
+	writel_relaxed(val, pll->base + PLL_CTRL);
+
+	ret = clk_fracn_gppll_wait_lock(pll);
+	if (ret)
+		return ret;
+
+	val &= ~CLKMUX_BYPASS;
+	writel_relaxed(val, pll->base + PLL_CTRL);
+
+	return 0;
+}
+
+static int clk_fracn_gppll_is_prepared(struct clk_hw *hw)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->base + PLL_CTRL);
+
+	return (val & POWERUP_MASK) ? 1 : 0;
+}
+
+static void clk_fracn_gppll_unprepare(struct clk_hw *hw)
+{
+	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->base + PLL_CTRL);
+	val &= ~POWERUP_MASK;
+	writel_relaxed(val, pll->base + PLL_CTRL);
+}
+
+static const struct clk_ops clk_fracn_gppll_ops = {
+	.enable		= clk_fracn_gppll_prepare,
+	.disable	= clk_fracn_gppll_unprepare,
+	.is_enabled	= clk_fracn_gppll_is_prepared,
+	.recalc_rate	= clk_fracn_gppll_recalc_rate,
+	.round_rate	= clk_fracn_gppll_round_rate,
+	.set_rate	= clk_fracn_gppll_set_rate,
+};
+
+static struct clk *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
+					void __iomem *base,
+					const struct imx_fracn_gppll_clk *pll_clk,
+					u32 pll_flags)
+{
+	struct clk_fracn_gppll *pll;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = pll_clk->flags;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.ops = &clk_fracn_gppll_ops;
+
+	pll->base = base;
+	pll->hw.init = &init;
+	pll->rate_table = pll_clk->rate_table;
+	pll->rate_count = pll_clk->rate_count;
+	pll->flags = pll_flags;
+
+	hw = &pll->hw;
+
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		pr_err("%s: failed to register pll %s %d\n", __func__, name, ret);
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	return &hw->clk;
+}
+
+struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
+				const struct imx_fracn_gppll_clk *pll_clk)
+{
+	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN);
+}
+EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll);
+
+struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
+					void __iomem *base,
+					const struct imx_fracn_gppll_clk *pll_clk)
+{
+	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER);
+}
+EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer);
diff --git a/drivers/clk/imx/clk-gate-93.c b/drivers/clk/imx/clk-gate-93.c
new file mode 100644
index 0000000000..ed2714a03c
--- /dev/null
+++ b/drivers/clk/imx/clk-gate-93.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <of_address.h>
+#include <linux/iopoll.h>
+
+#include "clk.h"
+
+#define DIRECT_OFFSET		0x0
+
+/*
+ * 0b000 - LPCG will be OFF in any CPU mode.
+ * 0b100 - LPCG will be ON in any CPU mode.
+ */
+#define LPM_SETTING_OFF		0x0
+#define LPM_SETTING_ON		0x4
+
+#define LPM_CUR_OFFSET		0x1c
+
+#define AUTHEN_OFFSET		0x30
+#define CPULPM_EN		BIT(2)
+#define TZ_NS_SHIFT		9
+#define TZ_NS_MASK		BIT(9)
+
+#define WHITE_LIST_SHIFT	16
+
+struct imx93_clk_gate {
+	struct clk_hw hw;
+	void __iomem	*reg;
+	u32		bit_idx;
+	u32		val;
+	u32		mask;
+	spinlock_t	*lock;
+	unsigned int	*share_count;
+};
+
+#define to_imx93_clk_gate(_hw) container_of(_hw, struct imx93_clk_gate, hw)
+
+static void imx93_clk_gate_do_hardware(struct clk_hw *hw, bool enable)
+{
+	struct imx93_clk_gate *gate = to_imx93_clk_gate(hw);
+	u32 val;
+
+	val = readl(gate->reg + AUTHEN_OFFSET);
+	if (val & CPULPM_EN) {
+		val = enable ? LPM_SETTING_ON : LPM_SETTING_OFF;
+		writel(val, gate->reg + LPM_CUR_OFFSET);
+	} else {
+		val = readl(gate->reg + DIRECT_OFFSET);
+		val &= ~(gate->mask << gate->bit_idx);
+		if (enable)
+			val |= (gate->val & gate->mask) << gate->bit_idx;
+		writel(val, gate->reg + DIRECT_OFFSET);
+	}
+}
+
+static int imx93_clk_gate_enable(struct clk_hw *hw)
+{
+	struct imx93_clk_gate *gate = to_imx93_clk_gate(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(gate->lock, flags);
+
+	if (gate->share_count && (*gate->share_count)++ > 0)
+		goto out;
+
+	imx93_clk_gate_do_hardware(hw, true);
+out:
+	spin_unlock_irqrestore(gate->lock, flags);
+
+	return 0;
+}
+
+static void imx93_clk_gate_disable(struct clk_hw *hw)
+{
+	struct imx93_clk_gate *gate = to_imx93_clk_gate(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(gate->lock, flags);
+
+	if (gate->share_count) {
+		if (WARN_ON(*gate->share_count == 0))
+			goto out;
+		else if (--(*gate->share_count) > 0)
+			goto out;
+	}
+
+	imx93_clk_gate_do_hardware(hw, false);
+out:
+	spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int imx93_clk_gate_reg_is_enabled(struct imx93_clk_gate *gate)
+{
+	u32 val = readl(gate->reg + AUTHEN_OFFSET);
+
+	if (val & CPULPM_EN) {
+		val = readl(gate->reg + LPM_CUR_OFFSET);
+		if (val == LPM_SETTING_ON)
+			return 1;
+	} else {
+		val = readl(gate->reg);
+		if (((val >> gate->bit_idx) & gate->mask) == gate->val)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int imx93_clk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct imx93_clk_gate *gate = to_imx93_clk_gate(hw);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(gate->lock, flags);
+
+	ret = imx93_clk_gate_reg_is_enabled(gate);
+
+	spin_unlock_irqrestore(gate->lock, flags);
+
+	return ret;
+}
+
+static const struct clk_ops imx93_clk_gate_ops = {
+	.set_rate = clk_parent_set_rate,
+	.round_rate = clk_parent_round_rate,
+	.enable = imx93_clk_gate_enable,
+	.disable = imx93_clk_gate_disable,
+	.is_enabled = imx93_clk_gate_is_enabled,
+};
+
+static const struct clk_ops imx93_clk_gate_ro_ops = {
+	.is_enabled = imx93_clk_gate_is_enabled,
+};
+
+struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name,
+			   unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val,
+			   u32 mask, u32 domain_id, unsigned int *share_count)
+{
+	struct imx93_clk_gate *gate;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+	u32 authen;
+
+	gate = kzalloc(sizeof(struct imx93_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->val = val;
+	gate->mask = mask;
+	gate->share_count = share_count;
+
+	init.name = name;
+	init.ops = &imx93_clk_gate_ops;
+	init.flags = flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	gate->hw.init = &init;
+	hw = &gate->hw;
+
+	authen = readl(reg + AUTHEN_OFFSET);
+	if (!(authen & TZ_NS_MASK) || !(authen & BIT(WHITE_LIST_SHIFT + domain_id)))
+		init.ops = &imx93_clk_gate_ro_ops;
+
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(gate);
+		return ERR_PTR(ret);
+	}
+
+	return &hw->clk;
+}
+EXPORT_SYMBOL_GPL(imx93_clk_gate);
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
new file mode 100644
index 0000000000..e460091ba6
--- /dev/null
+++ b/drivers/clk/imx/clk-imx93.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 NXP.
+ */
+
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <of_address.h>
+#include <dt-bindings/clock/imx93-clock.h>
+
+#include "clk.h"
+
+enum clk_sel {
+	LOW_SPEED_IO_SEL,
+	NON_IO_SEL,
+	FAST_SEL,
+	AUDIO_SEL,
+	VIDEO_SEL,
+	TPM_SEL,
+	CKO1_SEL,
+	CKO2_SEL,
+	MISC_SEL,
+	MAX_SEL
+};
+
+static u32 share_count_sai1;
+static u32 share_count_sai2;
+static u32 share_count_sai3;
+static u32 share_count_mub;
+static u32 share_count_pdm;
+
+static const char * const a55_core_sels[] = {"a55_alt", "arm_pll"};
+static const char *parent_names[MAX_SEL][4] = {
+	{"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "video_pll"},
+	{"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "sys_pll_pfd2_div2"},
+	{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "sys_pll_pfd2"},
+	{"osc_24m", "audio_pll", "video_pll", "clk_ext1"},
+	{"osc_24m", "audio_pll", "video_pll", "sys_pll_pfd0"},
+	{"osc_24m", "sys_pll_pfd0", "audio_pll", "clk_ext1"},
+	{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "audio_pll"},
+	{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "video_pll"},
+	{"osc_24m", "audio_pll", "video_pll", "sys_pll_pfd2"},
+};
+
+static const struct imx93_clk_root {
+	u32 clk;
+	char *name;
+	u32 off;
+	enum clk_sel sel;
+	unsigned long flags;
+} root_array[] = {
+	/* a55/m33/bus critical clk for system run */
+	{ IMX93_CLK_A55_PERIPH,		"a55_periph_root",	0x0000,	FAST_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_A55_MTR_BUS,	"a55_mtr_bus_root",	0x0080,	LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_A55,		"a55_alt_root",		0x0100,	FAST_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_M33,		"m33_root",		0x0180,	LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_BUS_WAKEUP,		"bus_wakeup_root",	0x0280,	LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_BUS_AON,		"bus_aon_root",		0x0300,	LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_WAKEUP_AXI,		"wakeup_axi_root",	0x0380,	FAST_SEL, CLK_IS_CRITICAL },
+	{ IMX93_CLK_SWO_TRACE,		"swo_trace_root",	0x0400,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_M33_SYSTICK,	"m33_systick_root",	0x0480,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_FLEXIO1,		"flexio1_root",		0x0500,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_FLEXIO2,		"flexio2_root",		0x0580,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPTMR1,		"lptmr1_root",		0x0700,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPTMR2,		"lptmr2_root",		0x0780,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_TPM2,		"tpm2_root",		0x0880,	TPM_SEL, },
+	{ IMX93_CLK_TPM4,		"tpm4_root",		0x0980,	TPM_SEL, },
+	{ IMX93_CLK_TPM5,		"tpm5_root",		0x0a00,	TPM_SEL, },
+	{ IMX93_CLK_TPM6,		"tpm6_root",		0x0a80,	TPM_SEL, },
+	{ IMX93_CLK_FLEXSPI1,		"flexspi1_root",	0x0b00,	FAST_SEL, },
+	{ IMX93_CLK_CAN1,		"can1_root",		0x0b80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_CAN2,		"can2_root",		0x0c00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART1,		"lpuart1_root",		0x0c80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART2,		"lpuart2_root",		0x0d00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART3,		"lpuart3_root",		0x0d80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART4,		"lpuart4_root",		0x0e00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART5,		"lpuart5_root",		0x0e80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART6,		"lpuart6_root",		0x0f00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART7,		"lpuart7_root",		0x0f80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPUART8,		"lpuart8_root",		0x1000,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C1,		"lpi2c1_root",		0x1080,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C2,		"lpi2c2_root",		0x1100,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C3,		"lpi2c3_root",		0x1180,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C4,		"lpi2c4_root",		0x1200,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C5,		"lpi2c5_root",		0x1280,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C6,		"lpi2c6_root",		0x1300,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C7,		"lpi2c7_root",		0x1380,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPI2C8,		"lpi2c8_root",		0x1400,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI1,		"lpspi1_root",		0x1480,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI2,		"lpspi2_root",		0x1500,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI3,		"lpspi3_root",		0x1580,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI4,		"lpspi4_root",		0x1600,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI5,		"lpspi5_root",		0x1680,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI6,		"lpspi6_root",		0x1700,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI7,		"lpspi7_root",		0x1780,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_LPSPI8,		"lpspi8_root",		0x1800,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_I3C1,		"i3c1_root",		0x1880,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_I3C2,		"i3c2_root",		0x1900,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_USDHC1,		"usdhc1_root",		0x1980,	FAST_SEL, },
+	{ IMX93_CLK_USDHC2,		"usdhc2_root",		0x1a00,	FAST_SEL, },
+	{ IMX93_CLK_USDHC3,		"usdhc3_root",		0x1a80,	FAST_SEL, },
+	{ IMX93_CLK_SAI1,		"sai1_root",		0x1b00,	AUDIO_SEL, },
+	{ IMX93_CLK_SAI2,		"sai2_root",		0x1b80,	AUDIO_SEL, },
+	{ IMX93_CLK_SAI3,		"sai3_root",		0x1c00,	AUDIO_SEL, },
+	{ IMX93_CLK_CCM_CKO1,		"ccm_cko1_root",	0x1c80,	CKO1_SEL, },
+	{ IMX93_CLK_CCM_CKO2,		"ccm_cko2_root",	0x1d00,	CKO2_SEL, },
+	{ IMX93_CLK_CCM_CKO3,		"ccm_cko3_root",	0x1d80,	CKO1_SEL, },
+	{ IMX93_CLK_CCM_CKO4,		"ccm_cko4_root",	0x1e00,	CKO2_SEL, },
+	/*
+	 * Critical because clk is used for handshake between HSIOMIX and NICMIX when
+	 * NICMIX power down/on during system suspend/resume
+	 */
+	{ IMX93_CLK_HSIO,		"hsio_root",		0x1e80,	LOW_SPEED_IO_SEL, CLK_IS_CRITICAL},
+	{ IMX93_CLK_HSIO_USB_TEST_60M,	"hsio_usb_test_60m_root", 0x1f00, LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_HSIO_ACSCAN_80M,	"hsio_acscan_80m_root",	0x1f80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_HSIO_ACSCAN_480M,	"hsio_acscan_480m_root", 0x2000, MISC_SEL, },
+	{ IMX93_CLK_NIC_AXI,		"nic_axi_root",		0x2080, FAST_SEL, CLK_IS_CRITICAL, },
+	{ IMX93_CLK_ML_APB,		"ml_apb_root",		0x2180,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_ML,			"ml_root",		0x2200,	FAST_SEL, },
+	{ IMX93_CLK_MEDIA_AXI,		"media_axi_root",	0x2280,	FAST_SEL, },
+	{ IMX93_CLK_MEDIA_APB,		"media_apb_root",	0x2300,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_MEDIA_LDB,		"media_ldb_root",	0x2380,	VIDEO_SEL, },
+	{ IMX93_CLK_MEDIA_DISP_PIX,	"media_disp_pix_root",	0x2400,	VIDEO_SEL, },
+	{ IMX93_CLK_CAM_PIX,		"cam_pix_root",		0x2480,	VIDEO_SEL, },
+	{ IMX93_CLK_MIPI_TEST_BYTE,	"mipi_test_byte_root",	0x2500,	VIDEO_SEL, },
+	{ IMX93_CLK_MIPI_PHY_CFG,	"mipi_phy_cfg_root",	0x2580,	VIDEO_SEL, },
+	{ IMX93_CLK_ADC,		"adc_root",		0x2700,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_PDM,		"pdm_root",		0x2780,	AUDIO_SEL, },
+	{ IMX93_CLK_TSTMR1,		"tstmr1_root",		0x2800,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_TSTMR2,		"tstmr2_root",		0x2880,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_MQS1,		"mqs1_root",		0x2900,	AUDIO_SEL, },
+	{ IMX93_CLK_MQS2,		"mqs2_root",		0x2980,	AUDIO_SEL, },
+	{ IMX93_CLK_AUDIO_XCVR,		"audio_xcvr_root",	0x2a00,	NON_IO_SEL, },
+	{ IMX93_CLK_SPDIF,		"spdif_root",		0x2a80,	AUDIO_SEL, },
+	{ IMX93_CLK_ENET,		"enet_root",		0x2b00,	NON_IO_SEL, },
+	{ IMX93_CLK_ENET_TIMER1,	"enet_timer1_root",	0x2b80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_ENET_TIMER2,	"enet_timer2_root",	0x2c00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_ENET_REF,		"enet_ref_root",	0x2c80,	NON_IO_SEL, },
+	{ IMX93_CLK_ENET_REF_PHY,	"enet_ref_phy_root",	0x2d00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_I3C1_SLOW,		"i3c1_slow_root",	0x2d80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_I3C2_SLOW,		"i3c2_slow_root",	0x2e00,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_USB_PHY_BURUNIN,	"usb_phy_root",		0x2e80,	LOW_SPEED_IO_SEL, },
+	{ IMX93_CLK_PAL_CAME_SCAN,	"pal_came_scan_root",	0x2f00,	MISC_SEL, }
+};
+
+static const struct imx93_clk_ccgr {
+	u32 clk;
+	char *name;
+	char *parent_name;
+	u32 off;
+	unsigned long flags;
+	u32 *shared_count;
+} ccgr_array[] = {
+	{ IMX93_CLK_A55_GATE,		"a55_alt",	"a55_alt_root",		0x8000, },
+	/* M33 critical clk for system run */
+	{ IMX93_CLK_CM33_GATE,		"cm33",		"m33_root",		0x8040, CLK_IS_CRITICAL },
+	{ IMX93_CLK_ADC1_GATE,		"adc1",		"adc_root",		0x82c0, },
+	{ IMX93_CLK_WDOG1_GATE,		"wdog1",	"osc_24m",		0x8300, },
+	{ IMX93_CLK_WDOG2_GATE,		"wdog2",	"osc_24m",		0x8340, },
+	{ IMX93_CLK_WDOG3_GATE,		"wdog3",	"osc_24m",		0x8380, },
+	{ IMX93_CLK_WDOG4_GATE,		"wdog4",	"osc_24m",		0x83c0, },
+	{ IMX93_CLK_WDOG5_GATE,		"wdog5",	"osc_24m",		0x8400, },
+	{ IMX93_CLK_SEMA1_GATE,		"sema1",	"bus_aon_root",		0x8440, },
+	{ IMX93_CLK_SEMA2_GATE,		"sema2",	"bus_wakeup_root",	0x8480, },
+	{ IMX93_CLK_MU1_A_GATE,		"mu1_a",	"bus_aon_root",		0x84c0, CLK_IGNORE_UNUSED },
+	{ IMX93_CLK_MU2_A_GATE,		"mu2_a",	"bus_wakeup_root",	0x84c0, CLK_IGNORE_UNUSED },
+	{ IMX93_CLK_MU1_B_GATE,		"mu1_b",	"bus_aon_root",		0x8500, 0, &share_count_mub },
+	{ IMX93_CLK_MU2_B_GATE,		"mu2_b",	"bus_wakeup_root",	0x8500, 0, &share_count_mub },
+	{ IMX93_CLK_EDMA1_GATE,		"edma1",	"m33_root",		0x8540, },
+	{ IMX93_CLK_EDMA2_GATE,		"edma2",	"wakeup_axi_root",	0x8580, },
+	{ IMX93_CLK_FLEXSPI1_GATE,	"flexspi1",	"flexspi1_root",	0x8640, },
+	{ IMX93_CLK_GPIO1_GATE,		"gpio1",	"m33_root",		0x8880, },
+	{ IMX93_CLK_GPIO2_GATE,		"gpio2",	"bus_wakeup_root",	0x88c0, },
+	{ IMX93_CLK_GPIO3_GATE,		"gpio3",	"bus_wakeup_root",	0x8900, },
+	{ IMX93_CLK_GPIO4_GATE,		"gpio4",	"bus_wakeup_root",	0x8940, },
+	{ IMX93_CLK_FLEXIO1_GATE,	"flexio1",	"flexio1_root",		0x8980, },
+	{ IMX93_CLK_FLEXIO2_GATE,	"flexio2",	"flexio2_root",		0x89c0, },
+	{ IMX93_CLK_LPIT1_GATE,		"lpit1",	"bus_aon_root",		0x8a00, },
+	{ IMX93_CLK_LPIT2_GATE,		"lpit2",	"bus_wakeup_root",	0x8a40, },
+	{ IMX93_CLK_LPTMR1_GATE,	"lptmr1",	"lptmr1_root",		0x8a80, },
+	{ IMX93_CLK_LPTMR2_GATE,	"lptmr2",	"lptmr2_root",		0x8ac0, },
+	{ IMX93_CLK_TPM1_GATE,		"tpm1",		"bus_aon_root",		0x8b00, },
+	{ IMX93_CLK_TPM2_GATE,		"tpm2",		"tpm2_root",		0x8b40, },
+	{ IMX93_CLK_TPM3_GATE,		"tpm3",		"bus_wakeup_root",	0x8b80, },
+	{ IMX93_CLK_TPM4_GATE,		"tpm4",		"tpm4_root",		0x8bc0, },
+	{ IMX93_CLK_TPM5_GATE,		"tpm5",		"tpm5_root",		0x8c00, },
+	{ IMX93_CLK_TPM6_GATE,		"tpm6",		"tpm6_root",		0x8c40, },
+	{ IMX93_CLK_CAN1_GATE,		"can1",		"can1_root",		0x8c80, },
+	{ IMX93_CLK_CAN2_GATE,		"can2",		"can2_root",		0x8cc0, },
+	{ IMX93_CLK_LPUART1_GATE,	"lpuart1",	"lpuart1_root",		0x8d00, },
+	{ IMX93_CLK_LPUART2_GATE,	"lpuart2",	"lpuart2_root",		0x8d40, },
+	{ IMX93_CLK_LPUART3_GATE,	"lpuart3",	"lpuart3_root",		0x8d80, },
+	{ IMX93_CLK_LPUART4_GATE,	"lpuart4",	"lpuart4_root",		0x8dc0, },
+	{ IMX93_CLK_LPUART5_GATE,	"lpuart5",	"lpuart5_root",		0x8e00, },
+	{ IMX93_CLK_LPUART6_GATE,	"lpuart6",	"lpuart6_root",		0x8e40, },
+	{ IMX93_CLK_LPUART7_GATE,	"lpuart7",	"lpuart7_root",		0x8e80, },
+	{ IMX93_CLK_LPUART8_GATE,	"lpuart8",	"lpuart8_root",		0x8ec0, },
+	{ IMX93_CLK_LPI2C1_GATE,	"lpi2c1",	"lpi2c1_root",		0x8f00, },
+	{ IMX93_CLK_LPI2C2_GATE,	"lpi2c2",	"lpi2c2_root",		0x8f40, },
+	{ IMX93_CLK_LPI2C3_GATE,	"lpi2c3",	"lpi2c3_root",		0x8f80, },
+	{ IMX93_CLK_LPI2C4_GATE,	"lpi2c4",	"lpi2c4_root",		0x8fc0, },
+	{ IMX93_CLK_LPI2C5_GATE,	"lpi2c5",	"lpi2c5_root",		0x9000, },
+	{ IMX93_CLK_LPI2C6_GATE,	"lpi2c6",	"lpi2c6_root",		0x9040, },
+	{ IMX93_CLK_LPI2C7_GATE,	"lpi2c7",	"lpi2c7_root",		0x9080, },
+	{ IMX93_CLK_LPI2C8_GATE,	"lpi2c8",	"lpi2c8_root",		0x90c0, },
+	{ IMX93_CLK_LPSPI1_GATE,	"lpspi1",	"lpspi1_root",		0x9100, },
+	{ IMX93_CLK_LPSPI2_GATE,	"lpspi2",	"lpspi2_root",		0x9140, },
+	{ IMX93_CLK_LPSPI3_GATE,	"lpspi3",	"lpspi3_root",		0x9180, },
+	{ IMX93_CLK_LPSPI4_GATE,	"lpspi4",	"lpspi4_root",		0x91c0, },
+	{ IMX93_CLK_LPSPI5_GATE,	"lpspi5",	"lpspi5_root",		0x9200, },
+	{ IMX93_CLK_LPSPI6_GATE,	"lpspi6",	"lpspi6_root",		0x9240, },
+	{ IMX93_CLK_LPSPI7_GATE,	"lpspi7",	"lpspi7_root",		0x9280, },
+	{ IMX93_CLK_LPSPI8_GATE,	"lpspi8",	"lpspi8_root",		0x92c0, },
+	{ IMX93_CLK_I3C1_GATE,		"i3c1",		"i3c1_root",		0x9300, },
+	{ IMX93_CLK_I3C2_GATE,		"i3c2",		"i3c2_root",		0x9340, },
+	{ IMX93_CLK_USDHC1_GATE,	"usdhc1",	"usdhc1_root",		0x9380, },
+	{ IMX93_CLK_USDHC2_GATE,	"usdhc2",	"usdhc2_root",		0x93c0, },
+	{ IMX93_CLK_USDHC3_GATE,	"usdhc3",	"usdhc3_root",		0x9400, },
+	{ IMX93_CLK_SAI1_GATE,          "sai1",         "sai1_root",            0x9440, 0, &share_count_sai1},
+	{ IMX93_CLK_SAI1_IPG,		"sai1_ipg_clk", "bus_aon_root",		0x9440, 0, &share_count_sai1},
+	{ IMX93_CLK_SAI2_GATE,          "sai2",         "sai2_root",            0x9480, 0, &share_count_sai2},
+	{ IMX93_CLK_SAI2_IPG,		"sai2_ipg_clk", "bus_wakeup_root",	0x9480, 0, &share_count_sai2},
+	{ IMX93_CLK_SAI3_GATE,          "sai3",         "sai3_root",            0x94c0, 0, &share_count_sai3},
+	{ IMX93_CLK_SAI3_IPG,		"sai3_ipg_clk", "bus_wakeup_root",	0x94c0, 0, &share_count_sai3},
+	{ IMX93_CLK_MIPI_CSI_GATE,	"mipi_csi",	"media_apb_root",	0x9580, },
+	{ IMX93_CLK_MIPI_DSI_GATE,	"mipi_dsi",	"media_apb_root",	0x95c0, },
+	{ IMX93_CLK_LVDS_GATE,		"lvds",		"media_ldb_root",	0x9600, },
+	{ IMX93_CLK_LCDIF_GATE,		"lcdif",	"media_apb_root",	0x9640, },
+	{ IMX93_CLK_PXP_GATE,		"pxp",		"media_apb_root",	0x9680, },
+	{ IMX93_CLK_ISI_GATE,		"isi",		"media_apb_root",	0x96c0, },
+	{ IMX93_CLK_NIC_MEDIA_GATE,	"nic_media",	"media_axi_root",	0x9700, },
+	{ IMX93_CLK_USB_CONTROLLER_GATE, "usb_controller", "hsio_root",		0x9a00, },
+	{ IMX93_CLK_USB_TEST_60M_GATE,	"usb_test_60m",	"hsio_usb_test_60m_root", 0x9a40, },
+	{ IMX93_CLK_HSIO_TROUT_24M_GATE, "hsio_trout_24m", "osc_24m",		0x9a80, },
+	{ IMX93_CLK_PDM_GATE,		"pdm",		"pdm_root",		0x9ac0, 0, &share_count_pdm},
+	{ IMX93_CLK_PDM_IPG,		"pdm_ipg_clk",	"bus_aon_root",		0x9ac0, 0, &share_count_pdm},
+	{ IMX93_CLK_MQS1_GATE,		"mqs1",		"sai1_root",		0x9b00, },
+	{ IMX93_CLK_MQS2_GATE,		"mqs2",		"sai3_root",		0x9b40, },
+	{ IMX93_CLK_AUD_XCVR_GATE,	"aud_xcvr",	"audio_xcvr_root",	0x9b80, },
+	{ IMX93_CLK_SPDIF_GATE,		"spdif",	"spdif_root",		0x9c00, },
+	{ IMX93_CLK_HSIO_32K_GATE,	"hsio_32k",	"osc_32k",		0x9dc0, },
+	{ IMX93_CLK_ENET1_GATE,		"enet1",	"wakeup_axi_root",	0x9e00, },
+	{ IMX93_CLK_ENET_QOS_GATE,	"enet_qos",	"wakeup_axi_root",	0x9e40, },
+	/* Critical because clk accessed during CPU idle */
+	{ IMX93_CLK_SYS_CNT_GATE,	"sys_cnt",	"osc_24m",		0x9e80, CLK_IS_CRITICAL},
+	{ IMX93_CLK_TSTMR1_GATE,	"tstmr1",	"bus_aon_root",		0x9ec0, },
+	{ IMX93_CLK_TSTMR2_GATE,	"tstmr2",	"bus_wakeup_root",	0x9f00, },
+	{ IMX93_CLK_TMC_GATE,		"tmc",		"osc_24m",		0x9f40, },
+	{ IMX93_CLK_PMRO_GATE,		"pmro",		"osc_24m",		0x9f80, }
+};
+
+static struct clk_onecell_data clk_data;
+static struct clk *clks[IMX93_CLK_END];
+
+static int imx93_clocks_probe(struct device_node *np)
+{
+	struct device_node *anatop_np;
+	const struct imx93_clk_root *root;
+	const struct imx93_clk_ccgr *ccgr;
+	void __iomem *base, *anatop_base;
+	int i, ret;
+
+	clk_data.clk_num = IMX93_CLK_END;
+	clk_data.clks = clks;
+
+	clks[IMX93_CLK_DUMMY] = clk_fixed("dummy", 0);
+	clks[IMX93_CLK_24M] = of_clk_get_by_name(np, "osc_24m");
+	clks[IMX93_CLK_32K] = of_clk_get_by_name(np, "osc_32k");
+	clks[IMX93_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1");
+
+	clks[IMX93_CLK_SYS_PLL_PFD0] = clk_fixed("sys_pll_pfd0", 1000000000);
+	clks[IMX93_CLK_SYS_PLL_PFD0_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd0_div2",
+								    "sys_pll_pfd0", 1, 2);
+	clks[IMX93_CLK_SYS_PLL_PFD1] = clk_fixed("sys_pll_pfd1", 800000000);
+	clks[IMX93_CLK_SYS_PLL_PFD1_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd1_div2",
+								    "sys_pll_pfd1", 1, 2);
+	clks[IMX93_CLK_SYS_PLL_PFD2] = clk_fixed("sys_pll_pfd2", 625000000);
+	clks[IMX93_CLK_SYS_PLL_PFD2_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd2_div2",
+								    "sys_pll_pfd2", 1, 2);
+
+	anatop_np = of_find_compatible_node(NULL, NULL, "fsl,imx93-anatop");
+	anatop_base = of_iomap(anatop_np, 0);
+	if (WARN_ON(IS_ERR(anatop_base)))
+		return PTR_ERR(anatop_base);
+
+	clks[IMX93_CLK_ARM_PLL] = imx_clk_fracn_gppll_integer("arm_pll", "osc_24m",
+							      anatop_base + 0x1000,
+							      &imx_fracn_gppll_integer);
+	clks[IMX93_CLK_AUDIO_PLL] = imx_clk_fracn_gppll("audio_pll", "osc_24m", anatop_base + 0x1200,
+							&imx_fracn_gppll);
+	clks[IMX93_CLK_VIDEO_PLL] = imx_clk_fracn_gppll("video_pll", "osc_24m", anatop_base + 0x1400,
+							&imx_fracn_gppll);
+
+	base = of_iomap(np, 0);
+	if (WARN_ON(IS_ERR(base)))
+		return PTR_ERR(base);
+
+	for (i = 0; i < ARRAY_SIZE(root_array); i++) {
+		root = &root_array[i];
+		clks[root->clk] = imx93_clk_composite_flags(root->name,
+							    parent_names[root->sel],
+							    4, base + root->off, 3,
+							    root->flags);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) {
+		ccgr = &ccgr_array[i];
+		clks[ccgr->clk] = imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name,
+						 ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
+						 ccgr->shared_count);
+	}
+
+	clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels,
+						  ARRAY_SIZE(a55_core_sels));
+	clks[IMX93_CLK_A55_CORE] = imx_clk_hw_cpu("a55_core", "a55_sel",
+						  clks[IMX93_CLK_A55_SEL],
+						  clks[IMX93_CLK_A55_SEL],
+						  clks[IMX93_CLK_ARM_PLL],
+						  clks[IMX93_CLK_A55_GATE]);
+
+	imx_check_clocks(clks, IMX93_CLK_END);
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+CLK_OF_DECLARE(imx93, "fsl,imx93-ccm", imx93_clocks_probe);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 041592a064..1d3316619f 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -304,6 +304,48 @@ struct clk *imx8m_clk_composite_flags(const char *name,
 #define imx8m_clk_composite_critical(name, parent_names, reg) \
 	__imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
 
+#define CLK_FRACN_GPPLL_INTEGER BIT(0)
+#define CLK_FRACN_GPPLL_FRACN   BIT(1)
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_fracn_gppll_rate_table {
+	unsigned int rate;
+	unsigned int mfi;
+	unsigned int mfn;
+	unsigned int mfd;
+	unsigned int rdiv;
+	unsigned int odiv;
+};
+
+struct imx_fracn_gppll_clk {
+	const struct imx_fracn_gppll_rate_table *rate_table;
+	int rate_count;
+	int flags;
+};
+
+struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
+				const struct imx_fracn_gppll_clk *pll_clk);
+struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
+					void __iomem *base,
+					const struct imx_fracn_gppll_clk *pll_clk);
+
+extern struct imx_fracn_gppll_clk imx_fracn_gppll;
+extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer;
+
+struct clk *imx93_clk_composite_flags(const char *name,
+				      const char * const *parent_names,
+				      int num_parents,
+				      void __iomem *reg,
+				      u32 domain_id,
+				      unsigned long flags);
+#define imx93_clk_composite(name, parent_names, num_parents, reg, domain_id) \
+        imx93_clk_composite_flags(name, parent_names, num_parents, reg, domain_id \
+                                  CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
+
+struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name,
+			   unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val,
+			   u32 mask, u32 domain_id, unsigned int *share_count);
+
 /*
  * Names of the above functions used in the Linux Kernel. Added here
  * to be able to use the same names in barebox to reduce the diffs
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 07/25] clk: imx: clk-fracn-gppll: make usable from PBL
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (5 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 06/25] clk: Add i.MX93 clock support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 08/25] gpio-vf610: Add i.MX93 support Sascha Hauer
                   ` (17 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The PBL code needs to adjust the DDR PLL before setting up DDR.
Factor out the PLL setup code as a static inline function for
PBL usage.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/imx/clk-fracn-gppll.c | 135 +++++-----------------------
 drivers/clk/imx/clk.h             |  28 +-----
 include/soc/imx/clk-fracn-gppll.h | 144 ++++++++++++++++++++++++++++++
 3 files changed, 165 insertions(+), 142 deletions(-)
 create mode 100644 include/soc/imx/clk-fracn-gppll.h

diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
index 5fbc79f948..24e66fd65f 100644
--- a/drivers/clk/imx/clk-fracn-gppll.c
+++ b/drivers/clk/imx/clk-fracn-gppll.c
@@ -10,38 +10,10 @@
 #include <of_address.h>
 #include <linux/iopoll.h>
 #include <linux/bitfield.h>
+#include <soc/imx/clk-fracn-gppll.h>
 
 #include "clk.h"
 
-#define PLL_CTRL		0x0
-#define HW_CTRL_SEL		BIT(16)
-#define CLKMUX_BYPASS		BIT(2)
-#define CLKMUX_EN		BIT(1)
-#define POWERUP_MASK		BIT(0)
-
-#define PLL_ANA_PRG		0x10
-#define PLL_SPREAD_SPECTRUM	0x30
-
-#define PLL_NUMERATOR		0x40
-#define PLL_MFN_MASK		GENMASK(31, 2)
-
-#define PLL_DENOMINATOR		0x50
-#define PLL_MFD_MASK		GENMASK(29, 0)
-
-#define PLL_DIV			0x60
-#define PLL_MFI_MASK		GENMASK(24, 16)
-#define PLL_RDIV_MASK		GENMASK(15, 13)
-#define PLL_ODIV_MASK		GENMASK(7, 0)
-
-#define PLL_DFS_CTRL(x)		(0x70 + (x) * 0x10)
-
-#define PLL_STATUS		0xF0
-#define LOCK_STATUS		BIT(0)
-
-#define DFS_STATUS		0xF4
-
-#define LOCK_TIMEOUT_US		200
-
 #define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv)	\
 	{							\
 		.rate	=	(_rate),			\
@@ -118,19 +90,6 @@ static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw)
 	return container_of(hw, struct clk_fracn_gppll, hw);
 }
 
-static const struct imx_fracn_gppll_rate_table *
-imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
-{
-	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
-	int i;
-
-	for (i = 0; i < pll->rate_count; i++)
-		if (rate == rate_table[i].rate)
-			return &rate_table[i];
-
-	return NULL;
-}
-
 static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate,
 				       unsigned long *prate)
 {
@@ -157,17 +116,17 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon
 	long rate = 0;
 	int i;
 
-	pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
-	mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
+	pll_numerator = readl_relaxed(pll->base + GPPLL_NUMERATOR);
+	mfn = FIELD_GET(GPPLL_MFN_MASK, pll_numerator);
 
-	pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
-	mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
+	pll_denominator = readl_relaxed(pll->base + GPPLL_DENOMINATOR);
+	mfd = FIELD_GET(GPPLL_MFD_MASK, pll_denominator);
 
-	pll_div = readl_relaxed(pll->base + PLL_DIV);
-	mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
+	pll_div = readl_relaxed(pll->base + GPPLL_DIV);
+	mfi = FIELD_GET(GPPLL_MFI_MASK, pll_div);
 
-	rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
-	odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
+	rdiv = FIELD_GET(GPPLL_RDIV_MASK, pll_div);
+	odiv = FIELD_GET(GPPLL_ODIV_MASK, pll_div);
 
 	/*
 	 * Sometimes, the recalculated rate has deviation due to
@@ -214,70 +173,16 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon
 
 static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
 {
-	u32 val;
-
-	return readl_poll_timeout(pll->base + PLL_STATUS, val,
-				  val & LOCK_STATUS, LOCK_TIMEOUT_US);
+	return fracn_gppll_wait_lock(pll->base);
 }
 
 static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
 				    unsigned long prate)
 {
 	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
-	const struct imx_fracn_gppll_rate_table *rate;
-	u32 tmp, pll_div, ana_mfn;
-	int ret;
-
-	rate = imx_get_pll_settings(pll, drate);
-
-	/* Hardware control select disable. PLL is control by register */
-	tmp = readl_relaxed(pll->base + PLL_CTRL);
-	tmp &= ~HW_CTRL_SEL;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	/* Disable output */
-	tmp = readl_relaxed(pll->base + PLL_CTRL);
-	tmp &= ~CLKMUX_EN;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	/* Power Down */
-	tmp &= ~POWERUP_MASK;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	/* Disable BYPASS */
-	tmp &= ~CLKMUX_BYPASS;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
-		FIELD_PREP(PLL_MFI_MASK, rate->mfi);
-	writel_relaxed(pll_div, pll->base + PLL_DIV);
-	if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
-		writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
-		writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
-	}
-
-	/* Wait for 5us according to fracn mode pll doc */
-	udelay(5);
 
-	/* Enable Powerup */
-	tmp |= POWERUP_MASK;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	/* Wait Lock */
-	ret = clk_fracn_gppll_wait_lock(pll);
-	if (ret)
-		return ret;
-
-	/* Enable output */
-	tmp |= CLKMUX_EN;
-	writel_relaxed(tmp, pll->base + PLL_CTRL);
-
-	ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
-	ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
-
-	WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
-
-	return 0;
+	return fracn_gppll_set_rate(pll->base, pll->flags, pll->rate_table,
+				    pll->rate_count, drate);
 }
 
 static int clk_fracn_gppll_prepare(struct clk_hw *hw)
@@ -286,25 +191,25 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw)
 	u32 val;
 	int ret;
 
-	val = readl_relaxed(pll->base + PLL_CTRL);
+	val = readl_relaxed(pll->base + GPPLL_CTRL);
 	if (val & POWERUP_MASK)
 		return 0;
 
 	val |= CLKMUX_BYPASS;
-	writel_relaxed(val, pll->base + PLL_CTRL);
+	writel_relaxed(val, pll->base + GPPLL_CTRL);
 
 	val |= POWERUP_MASK;
-	writel_relaxed(val, pll->base + PLL_CTRL);
+	writel_relaxed(val, pll->base + GPPLL_CTRL);
 
 	val |= CLKMUX_EN;
-	writel_relaxed(val, pll->base + PLL_CTRL);
+	writel_relaxed(val, pll->base + GPPLL_CTRL);
 
 	ret = clk_fracn_gppll_wait_lock(pll);
 	if (ret)
 		return ret;
 
 	val &= ~CLKMUX_BYPASS;
-	writel_relaxed(val, pll->base + PLL_CTRL);
+	writel_relaxed(val, pll->base + GPPLL_CTRL);
 
 	return 0;
 }
@@ -314,7 +219,7 @@ static int clk_fracn_gppll_is_prepared(struct clk_hw *hw)
 	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
 	u32 val;
 
-	val = readl_relaxed(pll->base + PLL_CTRL);
+	val = readl_relaxed(pll->base + GPPLL_CTRL);
 
 	return (val & POWERUP_MASK) ? 1 : 0;
 }
@@ -324,9 +229,9 @@ static void clk_fracn_gppll_unprepare(struct clk_hw *hw)
 	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
 	u32 val;
 
-	val = readl_relaxed(pll->base + PLL_CTRL);
+	val = readl_relaxed(pll->base + GPPLL_CTRL);
 	val &= ~POWERUP_MASK;
-	writel_relaxed(val, pll->base + PLL_CTRL);
+	writel_relaxed(val, pll->base + GPPLL_CTRL);
 }
 
 static const struct clk_ops clk_fracn_gppll_ops = {
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 1d3316619f..9058f913d3 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -304,33 +304,7 @@ struct clk *imx8m_clk_composite_flags(const char *name,
 #define imx8m_clk_composite_critical(name, parent_names, reg) \
 	__imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
 
-#define CLK_FRACN_GPPLL_INTEGER BIT(0)
-#define CLK_FRACN_GPPLL_FRACN   BIT(1)
-
-/* NOTE: Rate table should be kept sorted in descending order. */
-struct imx_fracn_gppll_rate_table {
-	unsigned int rate;
-	unsigned int mfi;
-	unsigned int mfn;
-	unsigned int mfd;
-	unsigned int rdiv;
-	unsigned int odiv;
-};
-
-struct imx_fracn_gppll_clk {
-	const struct imx_fracn_gppll_rate_table *rate_table;
-	int rate_count;
-	int flags;
-};
-
-struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
-				const struct imx_fracn_gppll_clk *pll_clk);
-struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
-					void __iomem *base,
-					const struct imx_fracn_gppll_clk *pll_clk);
-
-extern struct imx_fracn_gppll_clk imx_fracn_gppll;
-extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer;
+#include <soc/imx/clk-fracn-gppll.h>
 
 struct clk *imx93_clk_composite_flags(const char *name,
 				      const char * const *parent_names,
diff --git a/include/soc/imx/clk-fracn-gppll.h b/include/soc/imx/clk-fracn-gppll.h
new file mode 100644
index 0000000000..15ab9e67ec
--- /dev/null
+++ b/include/soc/imx/clk-fracn-gppll.h
@@ -0,0 +1,144 @@
+#ifndef __SOC_IMX_CLK_FRACN_GPGPPLL_H
+#define __SOC_IMX_CLK_FRACN_GPGPPLL_H
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+
+#define GPPLL_CTRL		0x0
+#define HW_CTRL_SEL		BIT(16)
+#define CLKMUX_BYPASS		BIT(2)
+#define CLKMUX_EN		BIT(1)
+#define POWERUP_MASK		BIT(0)
+
+#define GPPLL_ANA_PRG		0x10
+#define GPPLL_SPREAD_SPECTRUM	0x30
+
+#define GPPLL_NUMERATOR		0x40
+#define GPPLL_MFN_MASK		GENMASK(31, 2)
+
+#define GPPLL_DENOMINATOR	0x50
+#define GPPLL_MFD_MASK		GENMASK(29, 0)
+
+#define GPPLL_DIV		0x60
+#define GPPLL_MFI_MASK		GENMASK(24, 16)
+#define GPPLL_RDIV_MASK		GENMASK(15, 13)
+#define GPPLL_ODIV_MASK		GENMASK(7, 0)
+
+#define GPPLL_DFS_CTRL(x)	(0x70 + (x) * 0x10)
+
+#define GPPLL_STATUS		0xF0
+#define GPPLL_LOCK_STATUS	BIT(0)
+
+#define GPPLL_DFS_STATUS	0xF4
+
+#define GPPLL_LOCK_TIMEOUT_US	200
+
+#define CLK_FRACN_GPPLL_INTEGER BIT(0)
+#define CLK_FRACN_GPPLL_FRACN   BIT(1)
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_fracn_gppll_rate_table {
+	unsigned int rate;
+	unsigned int mfi;
+	unsigned int mfn;
+	unsigned int mfd;
+	unsigned int rdiv;
+	unsigned int odiv;
+};
+
+struct imx_fracn_gppll_clk {
+	const struct imx_fracn_gppll_rate_table *rate_table;
+	int rate_count;
+	int flags;
+};
+
+struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
+				const struct imx_fracn_gppll_clk *pll_clk);
+struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
+					void __iomem *base,
+					const struct imx_fracn_gppll_clk *pll_clk);
+
+extern struct imx_fracn_gppll_clk imx_fracn_gppll;
+extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer;
+
+static inline int fracn_gppll_wait_lock(void __iomem *base)
+{
+	u32 val;
+
+	return readl_poll_timeout(base + GPPLL_STATUS, val,
+				  val & GPPLL_LOCK_STATUS, GPPLL_LOCK_TIMEOUT_US);
+}
+
+static inline const struct imx_fracn_gppll_rate_table *imx_get_gppll_settings(
+	const struct imx_fracn_gppll_rate_table *rate_table, int n_table, unsigned long rate)
+{
+	int i;
+
+	for (i = 0; i < n_table; i++)
+		if (rate == rate_table[i].rate)
+			return &rate_table[i];
+
+	return NULL;
+}
+
+static inline int fracn_gppll_set_rate(void __iomem *base, unsigned int flags,
+				       const struct imx_fracn_gppll_rate_table *table, int n_table,
+				       unsigned long drate)
+{
+	const struct imx_fracn_gppll_rate_table *rate;
+	u32 tmp, pll_div, ana_mfn;
+	int ret;
+
+	rate = imx_get_gppll_settings(table, n_table, drate);
+
+	/* Hardware control select disable. PLL is control by register */
+	tmp = readl_relaxed(base + GPPLL_CTRL);
+	tmp &= ~HW_CTRL_SEL;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	/* Disable output */
+	tmp = readl_relaxed(base + GPPLL_CTRL);
+	tmp &= ~CLKMUX_EN;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	/* Power Down */
+	tmp &= ~POWERUP_MASK;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	/* Disable BYPASS */
+	tmp &= ~CLKMUX_BYPASS;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	pll_div = FIELD_PREP(GPPLL_RDIV_MASK, rate->rdiv) | rate->odiv |
+		FIELD_PREP(GPPLL_MFI_MASK, rate->mfi);
+	writel_relaxed(pll_div, base + GPPLL_DIV);
+	if (flags & CLK_FRACN_GPPLL_FRACN) {
+		writel_relaxed(rate->mfd, base + GPPLL_DENOMINATOR);
+		writel_relaxed(FIELD_PREP(GPPLL_MFN_MASK, rate->mfn), base + GPPLL_NUMERATOR);
+	}
+
+	/* Wait for 5us according to fracn mode pll doc */
+	udelay(5);
+
+	/* Enable Powerup */
+	tmp |= POWERUP_MASK;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	/* Wait Lock */
+	ret = fracn_gppll_wait_lock(base);
+	if (ret)
+		return ret;
+
+	/* Enable output */
+	tmp |= CLKMUX_EN;
+	writel_relaxed(tmp, base + GPPLL_CTRL);
+
+	ana_mfn = readl_relaxed(base + GPPLL_STATUS);
+	ana_mfn = FIELD_GET(GPPLL_MFN_MASK, ana_mfn);
+
+	WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
+
+	return 0;
+}
+
+#endif /* __SOC_IMX_CLK_FRACN_GPGPPLL_H */
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 08/25] gpio-vf610: Add i.MX93 support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (6 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 07/25] clk: imx: clk-fracn-gppll: make usable from PBL Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 09/25] iomux: " Sascha Hauer
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpio/Kconfig      |  3 +-
 drivers/gpio/gpio-vf610.c | 78 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e19f5a5aba..6f9ba2aad2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -63,7 +63,8 @@ config GPIO_IMX
 
 config GPIO_VF610
 	bool "VF610 GPIO controller" if COMPILE_TEST
-	default y if ARCH_VF610
+	depends on ARCH_IMX || ARCH_VF610 || COMPILE_TEST
+	default y if ARCH_VF610 || ARCH_IMX93
 
 config GPIO_MXS
 	bool "MXS GPIO controller" if COMPILE_TEST
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 43b2a18496..486463a2d2 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -21,6 +21,8 @@ struct vf610_gpio_port {
 	struct gpio_chip chip;
 	void __iomem *gpio_base;
 	unsigned int pinctrl_base;
+	bool have_paddr;
+	bool need_pinctrl;
 };
 
 #define GPIO_PDOR		0x00
@@ -28,9 +30,25 @@ struct vf610_gpio_port {
 #define GPIO_PCOR		0x08
 #define GPIO_PTOR		0x0c
 #define GPIO_PDIR		0x10
+#define GPIO_PDDR		0x14
+
+struct fsl_gpio_soc_data {
+	/* SoCs has a Port Data Direction Register (PDDR) */
+	bool have_paddr;
+	bool need_pinctrl;
+};
+
+static const struct fsl_gpio_soc_data vf610_data = {
+	.need_pinctrl = true,
+};
+
+static const struct fsl_gpio_soc_data imx_data = {
+	.have_paddr = true,
+};
 
 static const struct of_device_id vf610_gpio_dt_ids[] = {
-	{ .compatible = "fsl,vf610-gpio" },
+	{ .compatible = "fsl,vf610-gpio", .data = &vf610_data, },
+	{ .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, vf610_gpio_dt_ids);
@@ -40,8 +58,16 @@ static int vf610_gpio_get_value(struct gpio_chip *chip, unsigned int gpio)
 {
 	struct vf610_gpio_port *port =
 		container_of(chip, struct vf610_gpio_port, chip);
+	unsigned long mask = BIT(gpio);
+	unsigned long offset = GPIO_PDIR;
+
+	if (port->have_paddr) {
+		mask &= readl(port->gpio_base + GPIO_PDDR);
+		if (mask)
+			offset = GPIO_PDOR;
+	}
 
-	return !!(readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
+	return !!(readl(port->gpio_base + offset) & BIT(gpio));
 }
 
 static void vf610_gpio_set_value(struct gpio_chip *chip,
@@ -58,8 +84,19 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
 	struct vf610_gpio_port *port =
 		container_of(chip, struct vf610_gpio_port, chip);
+	unsigned long mask = BIT(gpio);
+	u32 val;
 
-	return pinctrl_gpio_direction_input(port->pinctrl_base + gpio);
+	if (port->have_paddr) {
+		val = readl(port->gpio_base + GPIO_PDDR);
+		val &= ~mask;
+		writel(val, port->gpio_base + GPIO_PDDR);
+	}
+
+	if (port->need_pinctrl)
+		return pinctrl_gpio_direction_input(port->pinctrl_base + gpio);
+
+	return 0;
 }
 
 static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
@@ -67,18 +104,41 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 {
 	struct vf610_gpio_port *port =
 		container_of(chip, struct vf610_gpio_port, chip);
+	unsigned long mask = BIT(gpio);
+	u32 val;
 
 	vf610_gpio_set_value(chip, gpio, value);
 
-	return pinctrl_gpio_direction_output(port->pinctrl_base + gpio);
+	if (port->have_paddr) {
+		val = readl(port->gpio_base + GPIO_PDDR);
+		val |= mask;
+		writel(val, port->gpio_base + GPIO_PDDR);
+	}
+
+	if (port->need_pinctrl)
+		return pinctrl_gpio_direction_output(port->pinctrl_base + gpio);
+
+	return 0;
 }
 
 static int vf610_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
 {
 	struct vf610_gpio_port *port =
 		container_of(chip, struct vf610_gpio_port, chip);
+	u32 val;
+
+	if (port->have_paddr) {
+		val = readl(port->gpio_base + GPIO_PDDR);
+		if (val & BIT(gpio))
+			return GPIOF_DIR_OUT;
+		else
+			return GPIOF_DIR_IN;
+	}
+
+	if (port->need_pinctrl)
+		return pinctrl_gpio_get_direction(port->pinctrl_base + gpio);
 
-	return pinctrl_gpio_get_direction(port->pinctrl_base + gpio);
+	return 0;
 }
 
 static struct gpio_ops vf610_gpio_ops = {
@@ -95,6 +155,11 @@ static int vf610_gpio_probe(struct device *dev)
 	struct resource *iores;
 	struct vf610_gpio_port *port;
 	const __be32 *gpio_ranges;
+	struct fsl_gpio_soc_data *devtype;
+
+	ret = dev_get_drvdata(dev, (const void **)&devtype);
+	if (ret)
+		return ret;
 
 	port = xzalloc(sizeof(*port));
 
@@ -106,6 +171,9 @@ static int vf610_gpio_probe(struct device *dev)
 		goto free_port;
 	}
 
+	port->have_paddr = devtype->have_paddr;
+	port->need_pinctrl = devtype->need_pinctrl;
+
 	port->pinctrl_base = be32_to_cpu(gpio_ranges[PINCTRL_BASE]);
 	port->chip.ngpio   = be32_to_cpu(gpio_ranges[COUNT]);
 
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 09/25] iomux: Add i.MX93 support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (7 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 08/25] gpio-vf610: Add i.MX93 support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 10/25] watchdog: Add ULP wdog support Sascha Hauer
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pinctrl/imx-iomux-v3.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c
index 5dbb745b13..673674c1dc 100644
--- a/drivers/pinctrl/imx-iomux-v3.c
+++ b/drivers/pinctrl/imx-iomux-v3.c
@@ -246,6 +246,8 @@ static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = {
 		.compatible = "fsl,imx8mp-iomuxc",
 	}, {
 		.compatible = "fsl,imx8mq-iomuxc",
+	}, {
+		.compatible = "fsl,imx93-iomuxc",
 	}, {
 		/* sentinel */
 	}
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 10/25] watchdog: Add ULP wdog support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (8 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 09/25] iomux: " Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 11/25] I2c: Add i2c_8bit_addr_from_msg() Sascha Hauer
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/watchdog/Kconfig      |   6 ++
 drivers/watchdog/Makefile     |   1 +
 drivers/watchdog/imxulp-wdt.c | 161 ++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 drivers/watchdog/imxulp-wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index e5c2036e6d..159b495acb 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -59,6 +59,12 @@ config WATCHDOG_IMX
 	help
 	  Add support for watchdog found on Freescale i.MX SoCs.
 
+config WATCHDOG_IMXULP
+	bool "i.MX ULP watchdog"
+	depends on ARCH_IMX || COMPILE_TEST
+	help
+	  Add support for watchdog found on Freescale i.MX SoCs.
+
 config WATCHDOG_JZ4740
 	bool "Ingenic jz4740 SoC hardware watchdog"
 	depends on MACH_MIPS_XBURST || COMPILE_TEST
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index cdd9460e34..2b0da7cea9 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_WATCHDOG_DW) += dw_wdt.o
 obj-$(CONFIG_WATCHDOG_JZ4740) += jz4740.o
 obj-$(CONFIG_WATCHDOG_IMX_RESET_SOURCE) += imxwd.o
 obj-$(CONFIG_WATCHDOG_IMX) += imxwd.o
+obj-$(CONFIG_WATCHDOG_IMXULP) += imxulp-wdt.o
 obj-$(CONFIG_WATCHDOG_KVX) += kvx_wdt.o
 obj-$(CONFIG_WATCHDOG_ORION) += orion_wdt.o
 obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
diff --git a/drivers/watchdog/imxulp-wdt.c b/drivers/watchdog/imxulp-wdt.c
new file mode 100644
index 0000000000..78d1527782
--- /dev/null
+++ b/drivers/watchdog/imxulp-wdt.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <errno.h>
+#include <malloc.h>
+#include <restart.h>
+#include <watchdog.h>
+#include <reset_source.h>
+#include <linux/clk.h>
+#include <asm/system.h>
+
+struct imxulp_socdata {
+	unsigned int rate;
+};
+
+struct imxulp_wd {
+	struct watchdog wd;
+	void __iomem *base;
+	unsigned int rate;
+	struct device *dev;
+};
+
+#define REFRESH_WORD0 0xA602 /* 1st refresh word */
+#define REFRESH_WORD1 0xB480 /* 2nd refresh word */
+
+#define UNLOCK_WORD0 0xC520 /* 1st unlock word */
+#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
+
+#define UNLOCK_WORD 0xD928C520 /* unlock word */
+#define REFRESH_WORD 0xB480A602 /* refresh word */
+
+#define WDOG_CS                 0x0
+#define WDOG_CS_UPDATE		BIT(5)
+#define WDOG_CS_EN		BIT(7)
+#define WDOG_CS_RCS		BIT(10)
+#define WDOG_CS_ULK		BIT(11)
+#define WDOG_CS_PRES		BIT(12)
+#define WDOG_CS_CMD32EN		BIT(13)
+#define WDOG_CS_FLG		BIT(14)
+#define WDOG_CS_INT		BIT(6)
+#define WDOG_CS_LPO_CLK		(0x1 << 8)
+
+#define WDOG_CNT		0x4
+#define WDOG_TOVAL		0x8
+
+#define CLK_RATE_1KHZ		1000
+#define CLK_RATE_32KHZ		125
+
+static int imxulp_watchdog_set_timeout(struct watchdog *wd, unsigned int timeout)
+{
+	struct imxulp_wd *imxwd = container_of(wd, struct imxulp_wd, wd);
+	u32 cmd32 = 0;
+
+	if (timeout == 0)
+		return -ENOSYS;
+
+	if (readl(imxwd->base + WDOG_CS) & WDOG_CS_CMD32EN) {
+		writel(UNLOCK_WORD, imxwd->base + WDOG_CNT);
+		cmd32 = WDOG_CS_CMD32EN;
+	} else {
+		writel(UNLOCK_WORD0, imxwd->base + WDOG_CNT);
+		writel(UNLOCK_WORD1, imxwd->base + WDOG_CNT);
+	}
+
+	/* Wait WDOG Unlock */
+	while (!(readl(imxwd->base + WDOG_CS) & WDOG_CS_ULK))
+		;
+
+	writel(timeout * imxwd->rate, imxwd->base + WDOG_TOVAL);
+
+	writel(cmd32 | WDOG_CS_EN | WDOG_CS_UPDATE | WDOG_CS_LPO_CLK |
+	       WDOG_CS_FLG | WDOG_CS_PRES | WDOG_CS_INT, imxwd->base + WDOG_CS);
+
+	/* Wait WDOG reconfiguration */
+	while (!(readl(imxwd->base + WDOG_CS) & WDOG_CS_RCS))
+		;
+
+	if (readl(imxwd->base + WDOG_CS) & WDOG_CS_CMD32EN) {
+		writel(REFRESH_WORD, imxwd->base + WDOG_CNT);
+	} else {
+		writel(REFRESH_WORD0, imxwd->base + WDOG_CNT);
+		writel(REFRESH_WORD1, imxwd->base + WDOG_CNT);
+	}
+
+	return 0;
+}
+
+static enum wdog_hw_runnning imxulp_wd_running(struct imxulp_wd *imxwd)
+{
+	if (readl(imxwd->base + WDOG_CS) & WDOG_CS_EN)
+		return WDOG_HW_RUNNING;
+	else
+		return WDOG_HW_NOT_RUNNING;
+}
+
+static int imxulp_wd_probe(struct device *dev)
+{
+	struct imxulp_wd *imxwd;
+	struct resource *iores;
+	struct imxulp_socdata *socdata;
+	int ret;
+
+	ret = dev_get_drvdata(dev, (const void **)&socdata);
+	if (ret)
+		return ret;
+
+	imxwd = xzalloc(sizeof(*imxwd));
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return dev_err_probe(dev, PTR_ERR(iores), "could not get memory region\n");
+
+	imxwd->rate = socdata->rate;
+	imxwd->base = IOMEM(iores->start);
+	imxwd->wd.set_timeout = imxulp_watchdog_set_timeout;
+	imxwd->wd.timeout_max = 0xffff / imxwd->rate;
+	imxwd->wd.hwdev = dev;
+	imxwd->wd.running = imxulp_wd_running(imxwd);
+
+	ret = watchdog_register(&imxwd->wd);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register watchdog device\n");
+
+	return 0;
+}
+
+static struct imxulp_socdata imx7ulp_wd_socdata = {
+	.rate = CLK_RATE_1KHZ,
+};
+
+static struct imxulp_socdata imx93_wd_socdata = {
+	.rate = CLK_RATE_32KHZ,
+};
+
+static __maybe_unused struct of_device_id imxulp_wdt_dt_ids[] = {
+	{
+		.compatible = "fsl,imx7ulp-wdt",
+		.data = &imx7ulp_wd_socdata,
+	}, {
+		.compatible = "fsl,imx8ulp-wdt",
+		.data = &imx7ulp_wd_socdata,
+	}, {
+		.compatible = "fsl,imx93-wdt",
+		.data = &imx93_wd_socdata,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, imx_wdt_dt_ids);
+
+static struct driver imxulp_wd_driver = {
+	.name = "imxulp-watchdog",
+	.probe = imxulp_wd_probe,
+	.of_compatible = DRV_OF_COMPAT(imxulp_wdt_dt_ids),
+};
+device_platform_driver(imxulp_wd_driver);
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 11/25] I2c: Add i2c_8bit_addr_from_msg()
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (9 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 10/25] watchdog: Add ULP wdog support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 12/25] i2c: Add lpi2c support Sascha Hauer
                   ` (13 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/i2c/i2c.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index 4fc278f800..9094003b68 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -329,6 +329,10 @@ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 extern int i2c_master_send(struct i2c_client *client, const char *buf, int count);
 extern int i2c_master_recv(struct i2c_client *client, char *buf, int count);
 
+static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
+{
+	return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
+}
 
 #define I2C_ADDR_16_BIT	(1 << 31)
 
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 12/25] i2c: Add lpi2c support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (10 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 11/25] I2c: Add i2c_8bit_addr_from_msg() Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 13/25] ARM: Add imx93.dtsi for USB Sascha Hauer
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/i2c/busses/Kconfig         |   7 +
 drivers/i2c/busses/Makefile        |   1 +
 drivers/i2c/busses/i2c-imx-lpi2c.c | 518 +++++++++++++++++++++++++++++
 3 files changed, 526 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-imx-lpi2c.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 766aa5edfa..a274baf4b6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -30,6 +30,13 @@ config I2C_IMX
 	  for many i.MX ARM based SoCs, for MPC85xx and MPC5200 PowerPC based
 	  SoCs.
 
+config I2C_IMX_LPI2C
+	tristate "IMX Low Power I2C interface"
+	depends on ARCH_IMX || COMPILE_TEST
+	help
+	  Say Y here if you want to use the Low Power IIC bus controller
+	  on the Freescale i.MX processors.
+
 config I2C_DESIGNWARE
 	bool "Synopsys DesignWare I2C Master driver"
 	help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a1ab46fb28..48f9b5be04 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_BCM283X)	+= i2c-bcm283x.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 lwl-$(CONFIG_I2C_IMX_EARLY)	+= i2c-imx-early.o
+obj-$(CONFIG_I2C_IMX_LPI2C)	+= i2c-imx-lpi2c.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
 obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
new file mode 100644
index 0000000000..f28a445601
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This is i.MX low power i2c controller driver.
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <of.h>
+#include <gpio.h>
+#include <malloc.h>
+#include <types.h>
+#include <xfuncs.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <pinctrl.h>
+#include <of_gpio.h>
+#include <of_device.h>
+
+#include <io.h>
+#include <i2c/i2c.h>
+
+#define DRIVER_NAME "imx-lpi2c"
+
+#define LPI2C_PARAM	0x04	/* i2c RX/TX FIFO size */
+#define LPI2C_MCR	0x10	/* i2c contrl register */
+#define LPI2C_MSR	0x14	/* i2c status register */
+#define LPI2C_MIER	0x18	/* i2c interrupt enable */
+#define LPI2C_MCFGR0	0x20	/* i2c master configuration */
+#define LPI2C_MCFGR1	0x24	/* i2c master configuration */
+#define LPI2C_MCFGR2	0x28	/* i2c master configuration */
+#define LPI2C_MCFGR3	0x2C	/* i2c master configuration */
+#define LPI2C_MCCR0	0x48	/* i2c master clk configuration */
+#define LPI2C_MCCR1	0x50	/* i2c master clk configuration */
+#define LPI2C_MFCR	0x58	/* i2c master FIFO control */
+#define LPI2C_MFSR	0x5C	/* i2c master FIFO status */
+#define LPI2C_MTDR	0x60	/* i2c master TX data register */
+#define LPI2C_MRDR	0x70	/* i2c master RX data register */
+
+/* i2c command */
+#define TRAN_DATA	0X00
+#define RECV_DATA	0X01
+#define GEN_STOP	0X02
+#define RECV_DISCARD	0X03
+#define GEN_START	0X04
+#define START_NACK	0X05
+#define START_HIGH	0X06
+#define START_HIGH_NACK	0X07
+
+#define MCR_MEN		BIT(0)
+#define MCR_RST		BIT(1)
+#define MCR_DOZEN	BIT(2)
+#define MCR_DBGEN	BIT(3)
+#define MCR_RTF		BIT(8)
+#define MCR_RRF		BIT(9)
+#define MSR_TDF		BIT(0)
+#define MSR_RDF		BIT(1)
+#define MSR_SDF		BIT(9)
+#define MSR_NDF		BIT(10)
+#define MSR_ALF		BIT(11)
+#define MSR_MBF		BIT(24)
+#define MSR_BBF		BIT(25)
+#define MIER_TDIE	BIT(0)
+#define MIER_RDIE	BIT(1)
+#define MIER_SDIE	BIT(9)
+#define MIER_NDIE	BIT(10)
+#define MCFGR1_AUTOSTOP	BIT(8)
+#define MCFGR1_IGNACK	BIT(9)
+#define MRDR_RXEMPTY	BIT(14)
+
+#define I2C_CLK_RATIO	2
+#define CHUNK_DATA	256
+
+#define I2C_PM_TIMEOUT		10 /* ms */
+
+enum lpi2c_imx_mode {
+	STANDARD,	/* 100+Kbps */
+	FAST,		/* 400+Kbps */
+	FAST_PLUS,	/* 1.0+Mbps */
+	HS,		/* 3.4+Mbps */
+	ULTRA_FAST,	/* 5.0+Mbps */
+};
+
+enum lpi2c_imx_pincfg {
+	TWO_PIN_OD,
+	TWO_PIN_OO,
+	TWO_PIN_PP,
+	FOUR_PIN_PP,
+};
+
+struct lpi2c_imx_struct {
+	struct i2c_adapter	adapter;
+	int			num_clks;
+	struct clk_bulk_data	*clks;
+	void __iomem		*base;
+	__u8			*rx_buf;
+	__u8			*tx_buf;
+	unsigned int		msglen;
+	unsigned int		delivered;
+	unsigned int		bitrate;
+	unsigned int		txfifosize;
+	unsigned int		rxfifosize;
+	enum lpi2c_imx_mode	mode;
+};
+
+static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
+			      unsigned int enable)
+{
+	writel(enable, lpi2c_imx->base + LPI2C_MIER);
+}
+
+static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int temp;
+	u64 start = get_time_ns();
+
+	while (1) {
+		temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+		/* check for arbitration lost, clear if set */
+		if (temp & (MSR_ALF | MSR_NDF)) {
+			writel(temp, lpi2c_imx->base + LPI2C_MSR);
+			return -EAGAIN;
+		}
+
+		if (temp & (MSR_BBF | MSR_MBF))
+			break;
+
+		if (is_timeout(start, 500 * MSECOND)) {
+			dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int bitrate = lpi2c_imx->bitrate;
+	enum lpi2c_imx_mode mode;
+
+	if (bitrate < I2C_MAX_FAST_MODE_FREQ)
+		mode = STANDARD;
+	else if (bitrate < I2C_MAX_FAST_MODE_PLUS_FREQ)
+		mode = FAST;
+	else if (bitrate < I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		mode = FAST_PLUS;
+	else if (bitrate < I2C_MAX_ULTRA_FAST_MODE_FREQ)
+		mode = HS;
+	else
+		mode = ULTRA_FAST;
+
+	lpi2c_imx->mode = mode;
+}
+
+static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
+			   struct i2c_msg *msgs)
+{
+	unsigned int temp;
+
+	temp = readl(lpi2c_imx->base + LPI2C_MCR);
+	temp |= MCR_RRF | MCR_RTF;
+	writel(temp, lpi2c_imx->base + LPI2C_MCR);
+	writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
+
+	temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
+	writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+	return lpi2c_imx_bus_busy(lpi2c_imx);
+}
+
+static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int temp;
+	u64 start = get_time_ns();
+
+	writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
+
+	do {
+		temp = readl(lpi2c_imx->base + LPI2C_MSR);
+		if (temp & MSR_SDF)
+			break;
+
+		if (is_timeout(start, 500 * MSECOND)) {
+			dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
+			break;
+		}
+
+	} while (1);
+}
+
+/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
+static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	u8 prescale, filt, sethold, datavd;
+	unsigned int clk_rate, clk_cycle, clkhi, clklo;
+	enum lpi2c_imx_pincfg pincfg;
+	unsigned int temp;
+
+	lpi2c_imx_set_mode(lpi2c_imx);
+
+	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
+	if (!clk_rate)
+		return -EINVAL;
+
+	if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
+		filt = 0;
+	else
+		filt = 2;
+
+	for (prescale = 0; prescale <= 7; prescale++) {
+		clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate)
+			    - 3 - (filt >> 1);
+		clkhi = DIV_ROUND_UP(clk_cycle, I2C_CLK_RATIO + 1);
+		clklo = clk_cycle - clkhi;
+		if (clklo < 64)
+			break;
+	}
+
+	if (prescale > 7)
+		return -EINVAL;
+
+	/* set MCFGR1: PINCFG, PRESCALE, IGNACK */
+	if (lpi2c_imx->mode == ULTRA_FAST)
+		pincfg = TWO_PIN_OO;
+	else
+		pincfg = TWO_PIN_OD;
+	temp = prescale | pincfg << 24;
+
+	if (lpi2c_imx->mode == ULTRA_FAST)
+		temp |= MCFGR1_IGNACK;
+
+	writel(temp, lpi2c_imx->base + LPI2C_MCFGR1);
+
+	/* set MCFGR2: FILTSDA, FILTSCL */
+	temp = (filt << 16) | (filt << 24);
+	writel(temp, lpi2c_imx->base + LPI2C_MCFGR2);
+
+	/* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */
+	sethold = clkhi;
+	datavd = clkhi >> 1;
+	temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo;
+
+	if (lpi2c_imx->mode == HS)
+		writel(temp, lpi2c_imx->base + LPI2C_MCCR1);
+	else
+		writel(temp, lpi2c_imx->base + LPI2C_MCCR0);
+
+	return 0;
+}
+
+static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int temp;
+	int ret;
+
+	temp = MCR_RST;
+	writel(temp, lpi2c_imx->base + LPI2C_MCR);
+	writel(0, lpi2c_imx->base + LPI2C_MCR);
+
+	ret = lpi2c_imx_config(lpi2c_imx);
+	if (ret)
+		return ret;
+
+	temp = readl(lpi2c_imx->base + LPI2C_MCR);
+	temp |= MCR_MEN;
+	writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+	return 0;
+}
+
+static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	u32 temp;
+
+	temp = readl(lpi2c_imx->base + LPI2C_MCR);
+	temp &= ~MCR_MEN;
+	writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+	return 0;
+}
+
+static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	u32 txcnt;
+	u64 start = get_time_ns();
+
+	do {
+		txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+		if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
+			dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
+			return -EIO;
+		}
+
+		if (is_timeout(start, 500 * MSECOND)) {
+			dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
+			return -ETIMEDOUT;
+		}
+
+	} while (txcnt);
+
+	return 0;
+}
+
+static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	writel(lpi2c_imx->txfifosize >> 1, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int temp, remaining;
+
+	remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+	if (remaining > (lpi2c_imx->rxfifosize >> 1))
+		temp = lpi2c_imx->rxfifosize >> 1;
+	else
+		temp = 0;
+
+	writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static int lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int data, remaining;
+	uint64_t start = get_time_ns();
+
+	do {
+		u32 cnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+		if (cnt == lpi2c_imx->txfifosize) {
+			if (is_timeout(start, 100 * MSECOND))
+				return -EIO;
+			continue;
+		}
+
+		data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++];
+
+		writel(data, lpi2c_imx->base + LPI2C_MTDR);
+		remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+	} while (remaining);
+
+	return 0;
+}
+
+static int lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+	unsigned int remaining;
+	unsigned int data;
+	uint64_t start = get_time_ns();
+
+	do {
+		data = readl(lpi2c_imx->base + LPI2C_MRDR);
+		if (data & MRDR_RXEMPTY) {
+			if (is_timeout(start, 100 * MSECOND))
+				return -EIO;
+			continue;
+		}
+
+		lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
+
+		remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+	} while (remaining);
+
+	return 0;
+}
+
+static int lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
+			    struct i2c_msg *msgs)
+{
+	lpi2c_imx->tx_buf = msgs->buf;
+	lpi2c_imx_set_tx_watermark(lpi2c_imx);
+
+	return lpi2c_imx_write_txfifo(lpi2c_imx);
+}
+
+static int lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
+			   struct i2c_msg *msgs)
+{
+	unsigned int temp;
+
+	lpi2c_imx->rx_buf = msgs->buf;
+
+	lpi2c_imx_set_rx_watermark(lpi2c_imx);
+	temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
+	temp |= (RECV_DATA << 8);
+	writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+	lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
+
+	return lpi2c_imx_read_rxfifo(lpi2c_imx);
+}
+
+static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
+			  struct i2c_msg *msgs, int num)
+{
+	struct lpi2c_imx_struct *lpi2c_imx = container_of(adapter, struct lpi2c_imx_struct, adapter);
+	unsigned int temp;
+	int i, result;
+
+	result = lpi2c_imx_master_enable(lpi2c_imx);
+	if (result)
+		return result;
+
+	for (i = 0; i < num; i++) {
+		result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
+		if (result)
+			goto disable;
+
+		/* quick smbus */
+		if (num == 1 && msgs[0].len == 0)
+			goto stop;
+
+		lpi2c_imx->rx_buf = NULL;
+		lpi2c_imx->tx_buf = NULL;
+		lpi2c_imx->delivered = 0;
+		lpi2c_imx->msglen = msgs[i].len;
+
+		if (msgs[i].flags & I2C_M_RD)
+			result = lpi2c_imx_read(lpi2c_imx, &msgs[i]);
+		else
+			result = lpi2c_imx_write(lpi2c_imx, &msgs[i]);
+
+		if (result)
+			goto stop;
+
+		if (!(msgs[i].flags & I2C_M_RD)) {
+			result = lpi2c_imx_txfifo_empty(lpi2c_imx);
+			if (result)
+				goto stop;
+		}
+	}
+
+stop:
+	lpi2c_imx_stop(lpi2c_imx);
+
+	temp = readl(lpi2c_imx->base + LPI2C_MSR);
+	if ((temp & MSR_NDF) && !result)
+		result = -EIO;
+
+disable:
+	lpi2c_imx_master_disable(lpi2c_imx);
+
+	dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+		(result < 0) ? "error" : "success msg",
+		(result < 0) ? result : num);
+
+	return (result < 0) ? result : num;
+}
+
+static const struct of_device_id lpi2c_imx_of_match[] = {
+	{ .compatible = "fsl,imx7ulp-lpi2c" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
+
+static int lpi2c_imx_probe(struct device *dev)
+{
+	struct lpi2c_imx_struct *lpi2c_imx;
+	struct resource *iores;
+	unsigned int temp;
+	int ret;
+
+	lpi2c_imx = xzalloc(sizeof(*lpi2c_imx));
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	lpi2c_imx->base = IOMEM(iores->start);
+
+	lpi2c_imx->adapter.nr = -1;
+	lpi2c_imx->adapter.master_xfer	= lpi2c_imx_xfer;
+	lpi2c_imx->adapter.dev.parent	= dev;
+	lpi2c_imx->adapter.dev.of_node	= dev->of_node;
+
+	ret = clk_bulk_get_all(dev, &lpi2c_imx->clks);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "can't get I2C peripheral clock\n");
+	lpi2c_imx->num_clks = ret;
+
+	ret = of_property_read_u32(dev->of_node,
+				   "clock-frequency", &lpi2c_imx->bitrate);
+	if (ret)
+		lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
+
+	ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+	if (ret)
+		return ret;
+
+	temp = readl(lpi2c_imx->base + LPI2C_PARAM);
+	lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
+	lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+
+	ret = i2c_add_numbered_adapter(&lpi2c_imx->adapter);
+	if (ret)
+		return ret;
+
+	dev_dbg(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
+
+	return 0;
+}
+
+static struct driver lpi2c_imx_driver = {
+        .probe  = lpi2c_imx_probe,
+        .name   = "i2c-fsl",
+        .of_compatible = DRV_OF_COMPAT(lpi2c_imx_of_match),
+};
+coredevice_platform_driver(lpi2c_imx_driver);
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");
+MODULE_LICENSE("GPL");
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 13/25] ARM: Add imx93.dtsi for USB
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (11 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 12/25] i2c: Add lpi2c support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 14/25] serial: Add lpuart32 driver Sascha Hauer
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Current upstream i.MX93 dtsi file doesn't have USB support. Add a
local dtsi file for that.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/dts/imx93.dtsi | 62 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 arch/arm/dts/imx93.dtsi

diff --git a/arch/arm/dts/imx93.dtsi b/arch/arm/dts/imx93.dtsi
new file mode 100644
index 0000000000..2d8d4b2b58
--- /dev/null
+++ b/arch/arm/dts/imx93.dtsi
@@ -0,0 +1,62 @@
+/{
+	soc@0 {
+		usbphynop1: usbphynop1 {
+			compatible = "usb-nop-xceiv";
+			clocks = <&clk IMX93_CLK_USB_PHY_BURUNIN>;
+			clock-names = "main_clk";
+		};
+
+		usbotg1: usb@4c100000 {
+			compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+			reg = <0x4c100000 0x200>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX93_CLK_USB_CONTROLLER_GATE>,
+				 <&clk IMX93_CLK_HSIO_32K_GATE>;
+			clock-names = "usb_ctrl_root_clk", "usb_wakeup_clk";
+			assigned-clocks = <&clk IMX93_CLK_HSIO>;
+			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
+			assigned-clock-rates = <133000000>;
+			fsl,usbphy = <&usbphynop1>;
+			fsl,usbmisc = <&usbmisc1 0>;
+			status = "disabled";
+		};
+
+		usbmisc1: usbmisc@4c100200 {
+			compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+			#index-cells = <1>;
+			reg = <0x4c100200 0x200>;
+		};
+
+		usbphynop2: usbphynop2 {
+			compatible = "usb-nop-xceiv";
+			clocks = <&clk IMX93_CLK_USB_PHY_BURUNIN>;
+			clock-names = "main_clk";
+		};
+
+		usbotg2: usb@4c200000 {
+			compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+			reg = <0x4c200000 0x200>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX93_CLK_USB_CONTROLLER_GATE>,
+				 <&clk IMX93_CLK_HSIO_32K_GATE>;
+			clock-names = "usb_ctrl_root_clk", "usb_wakeup_clk";
+			assigned-clocks = <&clk IMX93_CLK_HSIO>;
+			assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
+			assigned-clock-rates = <133000000>;
+			fsl,usbphy = <&usbphynop2>;
+			fsl,usbmisc = <&usbmisc2 0>;
+			status = "disabled";
+		};
+
+		usbmisc2: usbmisc@4c200200 {
+			compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+			#index-cells = <1>;
+			reg = <0x4c200200 0x200>;
+		};
+
+		ddrc: memory-controller@4e300000 {
+			compatible = "fsl,imx93-ddrc";
+			reg = <0x4e300000 0x400000>;
+		};
+	};
+};
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 14/25] serial: Add lpuart32 driver
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (12 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 13/25] ARM: Add imx93.dtsi for USB Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 15/25] ARM: i.MX: add i.MX9 debug_ll support Sascha Hauer
                   ` (10 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

This adds a lpuart32 driver. This is a variant of the lpuart driver
that is found on i.MX9 and other SoCs.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/serial/Kconfig           |   4 +
 drivers/serial/Makefile          |   1 +
 drivers/serial/serial_lpuart32.c | 185 +++++++++++++++++++++++++++++++
 include/serial/lpuart32.h        | 158 ++++++++++++++++++++++++++
 4 files changed, 348 insertions(+)
 create mode 100644 drivers/serial/serial_lpuart32.c
 create mode 100644 include/serial/lpuart32.h

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 77c827e436..803f6b6aee 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -122,6 +122,10 @@ config DRIVER_SERIAL_LPUART
 	default y
 	bool "LPUART serial driver"
 
+config DRIVER_SERIAL_LPUART32
+	depends on ARCH_IMX
+	bool "LPUART32 serial driver"
+
 config VIRTIO_CONSOLE
 	tristate "Virtio console"
 	depends on VIRTIO
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index bbc517f521..4887e24ee1 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_SERIAL_CADENCE)		+= serial_cadence.o
 obj-$(CONFIG_DRIVER_SERIAL_EFI_STDIO)		+= efi-stdio.o
 obj-$(CONFIG_DRIVER_SERIAL_DIGIC)		+= serial_digic.o
 obj-$(CONFIG_DRIVER_SERIAL_LPUART)		+= serial_lpuart.o
+obj-$(CONFIG_DRIVER_SERIAL_LPUART32)		+= serial_lpuart32.o
 obj-$(CONFIG_VIRTIO_CONSOLE)			+= virtio_console.o
 obj-$(CONFIG_SERIAL_SIFIVE)			+= serial_sifive.o
 obj-$(CONFIG_SERIAL_SBI)			+= serial_sbi.o
diff --git a/drivers/serial/serial_lpuart32.c b/drivers/serial/serial_lpuart32.c
new file mode 100644
index 0000000000..0f3e7c7a04
--- /dev/null
+++ b/drivers/serial/serial_lpuart32.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Pengutronix
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <notifier.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <serial/lpuart32.h>
+
+struct lpuart32_devtype_data {
+	unsigned int reg_offs;
+};
+
+struct lpuart32 {
+	struct console_device cdev;
+	int baudrate;
+	int dte_mode;
+	struct notifier_block notify;
+	struct resource *io;
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static struct lpuart32 *cdev_to_lpuart32(struct console_device *cdev)
+{
+	return container_of(cdev, struct lpuart32, cdev);
+}
+
+static void lpuart32_enable(struct lpuart32 *lpuart32)
+{
+	writel(LPUART32_UARTCTRL_TE | LPUART32_UARTCTRL_RE,
+	       lpuart32->base + LPUART32_UARTCTRL);
+}
+
+static void lpuart32_disable(struct lpuart32 *lpuart32)
+{
+	writel(0, lpuart32->base + LPUART32_UARTCTRL);
+}
+
+static int lpuart32_serial_setbaudrate(struct console_device *cdev,
+				     int baudrate)
+{
+	struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+	lpuart32_disable(lpuart32);
+
+	/*
+	 * We treat baudrate of 0 as a request to disable UART
+	 */
+	if (baudrate) {
+		lpuart32_setbrg(lpuart32->base, clk_get_rate(lpuart32->clk),
+			      baudrate);
+		lpuart32_enable(lpuart32);
+	}
+
+	lpuart32->baudrate = baudrate;
+
+	return 0;
+}
+
+static int lpuart32_serial_getc(struct console_device *cdev)
+{
+	struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+	while (!(readl(lpuart32->base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_RDRF));
+
+	return readl(lpuart32->base + LPUART32_UARTDATA) & 0xff;
+}
+
+static void lpuart32_serial_putc(struct console_device *cdev, char c)
+{
+	struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+	lpuart32_putc(lpuart32->base, c);
+}
+
+/* Test whether a character is in the RX buffer */
+static int lpuart32_serial_tstc(struct console_device *cdev)
+{
+	struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+	return readl(lpuart32->base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_RDRF;
+}
+
+static void lpuart32_serial_flush(struct console_device *cdev)
+{
+}
+
+static int lpuart32_serial_probe(struct device *dev)
+{
+	int ret;
+	struct console_device *cdev;
+	struct lpuart32 *lpuart32;
+	const char *devname;
+	struct lpuart32_devtype_data *devtype;
+
+	ret = dev_get_drvdata(dev, (const void **)&devtype);
+	if (ret)
+		return ret;
+
+	lpuart32 = xzalloc(sizeof(*lpuart32));
+	cdev = &lpuart32->cdev;
+	dev->priv = lpuart32;
+
+	lpuart32->io = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(lpuart32->io)) {
+		ret = PTR_ERR(lpuart32->io);
+		goto err_free;
+	}
+	lpuart32->base = IOMEM(lpuart32->io->start) + devtype->reg_offs;
+
+	lpuart32->clk = clk_get(dev, NULL);
+	if (IS_ERR(lpuart32->clk)) {
+		ret = PTR_ERR(lpuart32->clk);
+		dev_err(dev, "Failed to get UART clock %d\n", ret);
+		goto io_release;
+	}
+
+	ret = clk_enable(lpuart32->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable UART clock %d\n", ret);
+		goto io_release;
+	}
+
+	cdev->dev    = dev;
+	cdev->tstc   = lpuart32_serial_tstc;
+	cdev->putc   = lpuart32_serial_putc;
+	cdev->getc   = lpuart32_serial_getc;
+	cdev->flush  = lpuart32_serial_flush;
+	cdev->setbrg = lpuart32_serial_setbaudrate;
+
+	if (dev->of_node) {
+		devname = of_alias_get(dev->of_node);
+		if (devname) {
+			cdev->devname = xstrdup(devname);
+			cdev->devid   = DEVICE_ID_SINGLE;
+		}
+	}
+
+	cdev->linux_console_name = "ttyLP";
+	cdev->linux_earlycon_name = "lpuart";
+	cdev->phys_base = lpuart32->base;
+
+	lpuart32_setup(lpuart32->base, clk_get_rate(lpuart32->clk));
+
+	ret = console_register(cdev);
+	if (!ret)
+		return 0;
+
+	clk_put(lpuart32->clk);
+io_release:
+	release_region(lpuart32->io);
+err_free:
+	free(lpuart32);
+
+	return ret;
+}
+
+static struct lpuart32_devtype_data imx7ulp_data = {
+	.reg_offs = 0x10,
+};
+
+static struct of_device_id lpuart32_serial_dt_ids[] = {
+	{
+		.compatible = "fsl,imx7ulp-lpuart",
+		.data = &imx7ulp_data,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, lpuart32_serial_dt_ids);
+
+static struct driver lpuart32_serial_driver = {
+	.name   = "lpuart32-serial",
+	.probe  = lpuart32_serial_probe,
+	.of_compatible = DRV_OF_COMPAT(lpuart32_serial_dt_ids),
+};
+console_platform_driver(lpuart32_serial_driver);
diff --git a/include/serial/lpuart32.h b/include/serial/lpuart32.h
new file mode 100644
index 0000000000..bcfd067113
--- /dev/null
+++ b/include/serial/lpuart32.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016 Zodiac Inflight Innovation
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * Based on code found in Linux kernel and U-Boot.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __lpuart32_H__
+#define __lpuart32_H__
+
+
+/* 32-bit register definition */
+#define LPUART32_UARTBAUD		0x00
+#define LPUART32_UARTSTAT		0x04
+#define LPUART32_UARTCTRL		0x08
+#define LPUART32_UARTDATA		0x0C
+#define LPUART32_UARTMATCH		0x10
+#define LPUART32_UARTMODIR		0x14
+#define LPUART32_UARTFIFO		0x18
+#define LPUART32_UARTWATER		0x1c
+
+#define LPUART32_UARTBAUD_MAEN1		0x80000000
+#define LPUART32_UARTBAUD_MAEN2		0x40000000
+#define LPUART32_UARTBAUD_M10		0x20000000
+#define LPUART32_UARTBAUD_TDMAE		0x00800000
+#define LPUART32_UARTBAUD_RDMAE		0x00200000
+#define LPUART32_UARTBAUD_MATCFG	0x00400000
+#define LPUART32_UARTBAUD_BOTHEDGE	0x00020000
+#define LPUART32_UARTBAUD_RESYNCDIS	0x00010000
+#define LPUART32_UARTBAUD_LBKDIE	0x00008000
+#define LPUART32_UARTBAUD_RXEDGIE	0x00004000
+#define LPUART32_UARTBAUD_SBNS		0x00002000
+#define LPUART32_UARTBAUD_SBR		0x00000000
+#define LPUART32_UARTBAUD_SBR_MASK	0x1fff
+#define LPUART32_UARTBAUD_OSR_MASK	0x1f
+#define LPUART32_UARTBAUD_OSR_SHIFT	24
+
+#define LPUART32_UARTSTAT_LBKDIF	0x80000000
+#define LPUART32_UARTSTAT_RXEDGIF	0x40000000
+#define LPUART32_UARTSTAT_MSBF		0x20000000
+#define LPUART32_UARTSTAT_RXINV		0x10000000
+#define LPUART32_UARTSTAT_RWUID		0x08000000
+#define LPUART32_UARTSTAT_BRK13		0x04000000
+#define LPUART32_UARTSTAT_LBKDE		0x02000000
+#define LPUART32_UARTSTAT_RAF		0x01000000
+#define LPUART32_UARTSTAT_TDRE		0x00800000
+#define LPUART32_UARTSTAT_TC		0x00400000
+#define LPUART32_UARTSTAT_RDRF		0x00200000
+#define LPUART32_UARTSTAT_IDLE		0x00100000
+#define LPUART32_UARTSTAT_OR		0x00080000
+#define LPUART32_UARTSTAT_NF		0x00040000
+#define LPUART32_UARTSTAT_FE		0x00020000
+#define LPUART32_UARTSTAT_PE		0x00010000
+#define LPUART32_UARTSTAT_MA1F		0x00008000
+#define LPUART32_UARTSTAT_M21F		0x00004000
+
+#define LPUART32_UARTCTRL_R8T9		0x80000000
+#define LPUART32_UARTCTRL_R9T8		0x40000000
+#define LPUART32_UARTCTRL_TXDIR		0x20000000
+#define LPUART32_UARTCTRL_TXINV		0x10000000
+#define LPUART32_UARTCTRL_ORIE		0x08000000
+#define LPUART32_UARTCTRL_NEIE		0x04000000
+#define LPUART32_UARTCTRL_FEIE		0x02000000
+#define LPUART32_UARTCTRL_PEIE		0x01000000
+#define LPUART32_UARTCTRL_TIE		0x00800000
+#define LPUART32_UARTCTRL_TCIE		0x00400000
+#define LPUART32_UARTCTRL_RIE		0x00200000
+#define LPUART32_UARTCTRL_ILIE		0x00100000
+#define LPUART32_UARTCTRL_TE		0x00080000
+#define LPUART32_UARTCTRL_RE		0x00040000
+#define LPUART32_UARTCTRL_RWU		0x00020000
+#define LPUART32_UARTCTRL_SBK		0x00010000
+#define LPUART32_UARTCTRL_MA1IE		0x00008000
+#define LPUART32_UARTCTRL_MA2IE		0x00004000
+#define LPUART32_UARTCTRL_IDLECFG	GENMASK(10, 8)
+#define LPUART32_UARTCTRL_LOOPS		0x00000080
+#define LPUART32_UARTCTRL_DOZEEN	0x00000040
+#define LPUART32_UARTCTRL_RSRC		0x00000020
+#define LPUART32_UARTCTRL_M		0x00000010
+#define LPUART32_UARTCTRL_WAKE		0x00000008
+#define LPUART32_UARTCTRL_ILT		0x00000004
+#define LPUART32_UARTCTRL_PE		0x00000002
+#define LPUART32_UARTCTRL_PT		0x00000001
+
+#define LPUART32_UARTDATA_NOISY		0x00008000
+#define LPUART32_UARTDATA_PARITYE	0x00004000
+#define LPUART32_UARTDATA_FRETSC	0x00002000
+#define LPUART32_UARTDATA_RXEMPT	0x00001000
+#define LPUART32_UARTDATA_IDLINE	0x00000800
+#define LPUART32_UARTDATA_MASK		0x3ff
+
+#define LPUART32_UARTMODIR_IREN		0x00020000
+#define LPUART32_UARTMODIR_RTSWATER	GENMASK(10, 8)
+#define LPUART32_UARTMODIR_TXCTSSRC	0x00000020
+#define LPUART32_UARTMODIR_TXCTSC	0x00000010
+#define LPUART32_UARTMODIR_RXRTSE	0x00000008
+#define LPUART32_UARTMODIR_TXRTSPOL	0x00000004
+#define LPUART32_UARTMODIR_TXRTSE	0x00000002
+#define LPUART32_UARTMODIR_TXCTSE	0x00000001
+
+#define LPUART32_UARTFIFO_TXEMPT	0x00800000
+#define LPUART32_UARTFIFO_RXEMPT	0x00400000
+#define LPUART32_UARTFIFO_TXOF		0x00020000
+#define LPUART32_UARTFIFO_RXUF		0x00010000
+#define LPUART32_UARTFIFO_TXFLUSH	0x00008000
+#define LPUART32_UARTFIFO_RXFLUSH	0x00004000
+#define LPUART32_UARTFIFO_RXIDEN	GENMASK(12, 10)
+#define LPUART32_UARTFIFO_TXOFE		0x00000200
+#define LPUART32_UARTFIFO_RXUFE		0x00000100
+#define LPUART32_UARTFIFO_TXFE		0x00000080
+#define LPUART32_UARTFIFO_FIFOSIZE_MASK	0x7
+#define LPUART32_UARTFIFO_TXSIZE_OFF	4
+#define LPUART32_UARTFIFO_RXFE		0x00000008
+#define LPUART32_UARTFIFO_RXSIZE_OFF	0
+#define LPUART32_UARTFIFO_DEPTH(x)	(0x1 << ((x) ? ((x) + 1) : 0))
+
+#define LPUART32_UARTWATER_COUNT_MASK	0xff
+#define LPUART32_UARTWATER_TXCNT_OFF	8
+#define LPUART32_UARTWATER_RXCNT_OFF	24
+#define LPUART32_UARTWATER_WATER_MASK	0xff
+#define LPUART32_UARTWATER_TXWATER_OFF	0
+#define LPUART32_UARTWATER_RXWATER_OFF	16
+
+static inline void lpuart32_setbrg(void __iomem *base,
+				 unsigned int refclock,
+				 unsigned int baudrate)
+{
+	u32 sbr;
+
+	sbr = (refclock / (16 * baudrate));
+	writel(sbr, base + LPUART32_UARTBAUD);
+}
+
+static inline void lpuart32_setup(void __iomem *base,
+				unsigned int refclock)
+{
+	lpuart32_setbrg(base, refclock, CONFIG_BAUDRATE);
+	writel(LPUART32_UARTCTRL_TE | LPUART32_UARTCTRL_RE, base + LPUART32_UARTCTRL);
+}
+
+static inline void lpuart32_putc(void __iomem *base, int c)
+{
+	while (!(readl(base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_TDRE));
+
+	writel(c, base + LPUART32_UARTDATA);
+}
+
+#endif
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 15/25] ARM: i.MX: add i.MX9 debug_ll support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (13 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 14/25] serial: Add lpuart32 driver Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 16/25] ARM: Add TQ MBA9XXXCA board support Sascha Hauer
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

This adds support for debug_ll output on i.MX9 SoCs.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/Kconfig              |  5 +++++
 include/mach/imx/debug_ll.h | 13 +++++++++++++
 include/serial/lpuart32.h   | 10 ++++++++++
 3 files changed, 28 insertions(+)

diff --git a/common/Kconfig b/common/Kconfig
index 15c648de5d..792f93d381 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1365,6 +1365,10 @@ config DEBUG_IMX8M_UART
 	  Say Y here if you want barebox low-level debugging support
 	  on i.MX8M*.
 
+config DEBUG_IMX9_UART
+	bool "i.MX9 Debug UART"
+	select DEBUG_IMX_UART
+
 config DEBUG_VEXPRESS_UART
 	bool "Vexpress Debug UART"
 	depends on ARCH_VEXPRESS
@@ -1571,6 +1575,7 @@ config DEBUG_IMX_UART_PORT
 						DEBUG_IMX6Q_UART || \
 						DEBUG_IMX7D_UART || \
 						DEBUG_IMX8M_UART || \
+						DEBUG_IMX9_UART || \
 						DEBUG_VF610_UART
 	default 1
 	depends on ARCH_IMX
diff --git a/include/mach/imx/debug_ll.h b/include/mach/imx/debug_ll.h
index d25631d116..618cbc784e 100644
--- a/include/mach/imx/debug_ll.h
+++ b/include/mach/imx/debug_ll.h
@@ -18,10 +18,12 @@
 #include <mach/imx/imx6-regs.h>
 #include <mach/imx/imx7-regs.h>
 #include <mach/imx/imx8m-regs.h>
+#include <mach/imx/imx9-regs.h>
 #include <mach/imx/vf610-regs.h>
 
 #include <serial/imx-uart.h>
 #include <serial/lpuart.h>
+#include <serial/lpuart32.h>
 
 #ifdef CONFIG_DEBUG_IMX_UART
 
@@ -54,6 +56,8 @@
 #define IMX_DEBUG_SOC MX8M
 #elif defined CONFIG_DEBUG_VF610_UART
 #define IMX_DEBUG_SOC VF610
+#elif defined CONFIG_DEBUG_IMX9_UART
+#define IMX_DEBUG_SOC MX9
 #else
 #error "unknown i.MX debug uart soc type"
 #endif
@@ -107,6 +111,13 @@ static inline void imx8m_uart_setup_ll(void)
 	imx8m_uart_setup(base);
 }
 
+static inline void imx9_uart_setup_ll(void)
+{
+	void *base = IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC,
+					 CONFIG_DEBUG_IMX_UART_PORT));
+	lpuart32_setup(base + 0x10, 24000000);
+}
+
 static inline void PUTC_LL(int c)
 {
 	void __iomem *base = IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC,
@@ -117,6 +128,8 @@ static inline void PUTC_LL(int c)
 
 	if (IS_ENABLED(CONFIG_DEBUG_VF610_UART))
 		lpuart_putc(base, c);
+	else if (IS_ENABLED(CONFIG_DEBUG_IMX9_UART))
+		lpuart32_putc(base + 0x10, c);
 	else
 		imx_uart_putc(base, c);
 }
diff --git a/include/serial/lpuart32.h b/include/serial/lpuart32.h
index bcfd067113..12526ee0ae 100644
--- a/include/serial/lpuart32.h
+++ b/include/serial/lpuart32.h
@@ -155,4 +155,14 @@ static inline void lpuart32_putc(void __iomem *base, int c)
 	writel(c, base + LPUART32_UARTDATA);
 }
 
+static inline void imx9_uart_setup(void __iomem *uartbase)
+{
+	/*
+	 * On i.MX9 the registers start at offset 0x10
+	 */
+	BUG_ON((unsigned long)uartbase & 0x10);
+
+	lpuart32_setup(uartbase + 0x10, 24000000);
+}
+
 #endif
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 16/25] ARM: Add TQ MBA9XXXCA board support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (14 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 15/25] ARM: i.MX: add i.MX9 debug_ll support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 17/25] ARM: i.MX93: Add DDR size read support Sascha Hauer
                   ` (8 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The TQ MBA9XXXCA is a i.MX93 based board, see
https://www.tq-group.com/de/produkte/tq-embedded/arm-architektur/stka93xx/

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/boards/Makefile                      |    1 +
 arch/arm/boards/tqmba9xxxca/Makefile          |    2 +
 arch/arm/boards/tqmba9xxxca/board.c           |   58 +
 arch/arm/boards/tqmba9xxxca/lowlevel.c        |   43 +
 .../tqmba9xxxca/lpddr4x_tqma93xxca_timing.c   | 1480 +++++++++++++++++
 arch/arm/dts/Makefile                         |    1 +
 arch/arm/dts/imx93-tqma9352-mba93xxca.dts     |  826 +++++++++
 arch/arm/mach-imx/Kconfig                     |    9 +
 images/Makefile.imx                           |   11 +
 9 files changed, 2431 insertions(+)
 create mode 100644 arch/arm/boards/tqmba9xxxca/Makefile
 create mode 100644 arch/arm/boards/tqmba9xxxca/board.c
 create mode 100644 arch/arm/boards/tqmba9xxxca/lowlevel.c
 create mode 100644 arch/arm/boards/tqmba9xxxca/lpddr4x_tqma93xxca_timing.c
 create mode 100644 arch/arm/dts/imx93-tqma9352-mba93xxca.dts

diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index bdac1e69ee..5b78c760b9 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -197,3 +197,4 @@ obj-$(CONFIG_MACH_RADXA_ROCK3)			+= radxa-rock3/
 obj-$(CONFIG_MACH_RADXA_ROCK5)			+= radxa-rock5/
 obj-$(CONFIG_MACH_VARISCITE_DT8MCUSTOMBOARD_IMX8MP)	+= variscite-dt8mcustomboard-imx8mp/
 obj-$(CONFIG_MACH_RADXA_CM3)			+= radxa-cm3/
+obj-$(CONFIG_MACH_TQ_MBA9XXXCA)			+= tqmba9xxxca/
diff --git a/arch/arm/boards/tqmba9xxxca/Makefile b/arch/arm/boards/tqmba9xxxca/Makefile
new file mode 100644
index 0000000000..2957523cdd
--- /dev/null
+++ b/arch/arm/boards/tqmba9xxxca/Makefile
@@ -0,0 +1,2 @@
+lwl-y += lowlevel.o lpddr4x_tqma93xxca_timing.o
+obj-y += board.o
diff --git a/arch/arm/boards/tqmba9xxxca/board.c b/arch/arm/boards/tqmba9xxxca/board.c
new file mode 100644
index 0000000000..b181784079
--- /dev/null
+++ b/arch/arm/boards/tqmba9xxxca/board.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "TQMa93xx: " fmt
+
+#include <common.h>
+#include <gpio.h>
+#include <init.h>
+#include <i2c/i2c.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <environment.h>
+#include <mfd/pca9450.h>
+#include <deep-probe.h>
+#include <mach/imx/bbu.h>
+
+static void tqma93xx_init_pmic(struct regmap *map)
+{
+	/* BUCKxOUT_DVS0/1 control BUCK123 output */
+	regmap_write(map, PCA9450_BUCK123_DVS, 0x29);
+	/* enable DVS control through PMIC_STBY_REQ */
+	regmap_write(map, PCA9450_BUCK1CTRL, 0x59);
+	/* 0.9 V */
+	regmap_write(map, PCA9450_BUCK1OUT_DVS0, 0x18);
+	regmap_write(map, PCA9450_BUCK3OUT_DVS0, 0x18);
+	/* set standby voltage to 0.65v */
+	regmap_write(map, PCA9450_BUCK1OUT_DVS1, 0x4);
+
+	/* I2C_LT_EN*/
+	regmap_write(map, 0xa, 0x3);
+
+	/* set WDOG_B_CFG to cold reset */
+	regmap_write(map, PCA9450_RESET_CTRL, 0xA1);
+}
+
+static int tqma93xx_probe(struct device *dev)
+{
+	pca9450_register_init_callback(tqma93xx_init_pmic);
+
+	imx9_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc0", 0);
+
+	return 0;
+}
+
+static const struct of_device_id tqma93xx_of_match[] = {
+        {
+                .compatible = "tq,imx93-tqma9352",
+        },
+        { /* sentinel */ },
+};
+
+static struct driver tqma93xx_board_driver = {
+        .name = "board-tqma93xx",
+        .probe = tqma93xx_probe,
+        .of_compatible = tqma93xx_of_match,
+};
+coredevice_platform_driver(tqma93xx_board_driver);
+
+BAREBOX_DEEP_PROBE_ENABLE(tqma93xx_of_match);
diff --git a/arch/arm/boards/tqmba9xxxca/lowlevel.c b/arch/arm/boards/tqmba9xxxca/lowlevel.c
new file mode 100644
index 0000000000..8207cd9515
--- /dev/null
+++ b/arch/arm/boards/tqmba9xxxca/lowlevel.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <debug_ll.h>
+#include <mach/imx/debug_ll.h>
+#include <mach/imx/generic.h>
+#include <asm/barebox-arm.h>
+#include <soc/imx9/ddr.h>
+#include <mach/imx/atf.h>
+#include <mach/imx/romapi.h>
+
+extern char __dtb_z_imx93_tqma9352_mba93xxca_start[];
+extern struct dram_timing_info tqma93xxca_dram_timing;
+
+static noinline void tqma9352_mba93xxca_continue(void)
+{
+	void *base = IOMEM(MX9_UART1_BASE_ADDR);
+	void *muxbase = IOMEM(MX9_IOMUXC_BASE_ADDR);
+
+	writel(0x0, muxbase + 0x184);
+	imx9_uart_setup(IOMEM(base));
+	pbl_set_putc(lpuart32_putc, base + 0x10);
+
+	if (current_el() == 3) {
+		imx93_ddr_init(&tqma93xxca_dram_timing, DRAM_TYPE_LPDDR4);
+
+		imx93_romapi_load_image();
+		imx93_load_and_start_image_via_tfa();
+	}
+
+	barebox_arm_entry(0x80000000, 0x40000000, __dtb_z_imx93_tqma9352_mba93xxca_start);
+}
+
+ENTRY_FUNCTION(start_imx93_tqma9352_mba93xxca, r0, r1, r2)
+{
+	if (current_el() == 3)
+		imx93_cpu_lowlevel_init();
+
+	relocate_to_current_adr();
+	setup_c();
+
+	tqma9352_mba93xxca_continue();
+}
diff --git a/arch/arm/boards/tqmba9xxxca/lpddr4x_tqma93xxca_timing.c b/arch/arm/boards/tqmba9xxxca/lpddr4x_tqma93xxca_timing.c
new file mode 100644
index 0000000000..09e6744ddf
--- /dev/null
+++ b/arch/arm/boards/tqmba9xxxca/lpddr4x_tqma93xxca_timing.c
@@ -0,0 +1,1480 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 NXP
+ */
+
+#include <common.h>
+#include <soc/imx9/ddr.h>
+
+static struct dram_cfg_param ddr_ddrc_cfg[] = {
+	/** Initialize DDRC registers **/
+	{ 0x4e300110, 0x44100001 },
+	{ 0x4e300000, 0x8000bf },
+	{ 0x4e300008, 0x0 },
+	{ 0x4e300080, 0x80000412 },
+	{ 0x4e300084, 0x0 },
+	{ 0x4e300100, 0x24a0321b },
+	{ 0x4e300104, 0xa8ee001b },
+	{ 0x4e300108, 0x2f2e3233 },
+	{ 0x4e30010c, 0x85c18b },
+	{ 0x4e300114, 0x1002 },
+	{ 0x4e300124, 0x1c77071d },
+	{ 0x4e300160, 0x5402 },
+	{ 0x4e30016c, 0x35f00000 },
+	{ 0x4e300170, 0x8b0b0608 },
+	{ 0x4e300250, 0x28 },
+	{ 0x4e300254, 0x0 },
+	{ 0x4e30025c, 0x400 },
+	{ 0x4e300260, 0x0 },
+	{ 0x4e300300, 0x14281114 },
+	{ 0x4e300304, 0x106110a },
+	{ 0x4e300308, 0xa200e3c },
+	{ 0x4e300f04, 0x80 },
+	{ 0x4e300800, 0x39300002 },
+	{ 0x4e300804, 0x1f1f1f1f },
+};
+
+/* PHY Initialize Configuration */
+static struct dram_cfg_param ddr_ddrphy_cfg[] = {
+	{ 0x100a0, 0x4 },
+	{ 0x100a1, 0x5 },
+	{ 0x100a2, 0x6 },
+	{ 0x100a3, 0x7 },
+	{ 0x100a4, 0x0 },
+	{ 0x100a5, 0x1 },
+	{ 0x100a6, 0x2 },
+	{ 0x100a7, 0x3 },
+	{ 0x110a0, 0x3 },
+	{ 0x110a1, 0x2 },
+	{ 0x110a2, 0x0 },
+	{ 0x110a3, 0x1 },
+	{ 0x110a4, 0x7 },
+	{ 0x110a5, 0x6 },
+	{ 0x110a6, 0x4 },
+	{ 0x110a7, 0x5 },
+	{ 0x1005f, 0x5ff },
+	{ 0x1015f, 0x5ff },
+	{ 0x1105f, 0x5ff },
+	{ 0x1115f, 0x5ff },
+	{ 0x55, 0x1ff },
+	{ 0x1055, 0x1ff },
+	{ 0x2055, 0x1ff },
+	{ 0x200c5, 0x19 },
+	{ 0x2002e, 0x2 },
+	{ 0x90204, 0x0 },
+	{ 0x20024, 0x1e3 },
+	{ 0x2003a, 0x2 },
+	{ 0x2007d, 0x212 },
+	{ 0x2007c, 0x61 },
+	{ 0x20056, 0x3 },
+	{ 0x1004d, 0xe00 },
+	{ 0x1014d, 0xe00 },
+	{ 0x1104d, 0xe00 },
+	{ 0x1114d, 0xe00 },
+	{ 0x10049, 0xe00 },
+	{ 0x10149, 0xe00 },
+	{ 0x11049, 0xe00 },
+	{ 0x11149, 0xe00 },
+	{ 0x43, 0x60 },
+	{ 0x1043, 0x60 },
+	{ 0x2043, 0x60 },
+	{ 0x20018, 0x1 },
+	{ 0x20075, 0x4 },
+	{ 0x20050, 0x0 },
+	{ 0x2009b, 0x2 },
+	{ 0x20008, 0x3a5 },
+	{ 0x20088, 0x9 },
+	{ 0x200b2, 0x10c },
+	{ 0x10043, 0x5a1 },
+	{ 0x10143, 0x5a1 },
+	{ 0x11043, 0x5a1 },
+	{ 0x11143, 0x5a1 },
+	{ 0x200fa, 0x2 },
+	{ 0x20019, 0x1 },
+	{ 0x200f0, 0x0 },
+	{ 0x200f1, 0x0 },
+	{ 0x200f2, 0x4444 },
+	{ 0x200f3, 0x8888 },
+	{ 0x200f4, 0x5555 },
+	{ 0x200f5, 0x0 },
+	{ 0x200f6, 0x0 },
+	{ 0x200f7, 0xf000 },
+	{ 0x1004a, 0x500 },
+	{ 0x1104a, 0x500 },
+	{ 0x20025, 0x0 },
+	{ 0x2002d, 0x0 },
+	{ 0x2002c, 0x0 },
+};
+
+/* ddr phy trained csr */
+static struct dram_cfg_param ddr_ddrphy_trained_csr[] = {
+	{ 0x200b2, 0x0 },
+	{ 0x1200b2, 0x0 },
+	{ 0x2200b2, 0x0 },
+	{ 0x200cb, 0x0 },
+	{ 0x10043, 0x0 },
+	{ 0x110043, 0x0 },
+	{ 0x210043, 0x0 },
+	{ 0x10143, 0x0 },
+	{ 0x110143, 0x0 },
+	{ 0x210143, 0x0 },
+	{ 0x11043, 0x0 },
+	{ 0x111043, 0x0 },
+	{ 0x211043, 0x0 },
+	{ 0x11143, 0x0 },
+	{ 0x111143, 0x0 },
+	{ 0x211143, 0x0 },
+	{ 0x12043, 0x0 },
+	{ 0x112043, 0x0 },
+	{ 0x212043, 0x0 },
+	{ 0x12143, 0x0 },
+	{ 0x112143, 0x0 },
+	{ 0x212143, 0x0 },
+	{ 0x13043, 0x0 },
+	{ 0x113043, 0x0 },
+	{ 0x213043, 0x0 },
+	{ 0x13143, 0x0 },
+	{ 0x113143, 0x0 },
+	{ 0x213143, 0x0 },
+	{ 0x80, 0x0 },
+	{ 0x100080, 0x0 },
+	{ 0x200080, 0x0 },
+	{ 0x1080, 0x0 },
+	{ 0x101080, 0x0 },
+	{ 0x201080, 0x0 },
+	{ 0x2080, 0x0 },
+	{ 0x102080, 0x0 },
+	{ 0x202080, 0x0 },
+	{ 0x3080, 0x0 },
+	{ 0x103080, 0x0 },
+	{ 0x203080, 0x0 },
+	{ 0x4080, 0x0 },
+	{ 0x104080, 0x0 },
+	{ 0x204080, 0x0 },
+	{ 0x5080, 0x0 },
+	{ 0x105080, 0x0 },
+	{ 0x205080, 0x0 },
+	{ 0x6080, 0x0 },
+	{ 0x106080, 0x0 },
+	{ 0x206080, 0x0 },
+	{ 0x7080, 0x0 },
+	{ 0x107080, 0x0 },
+	{ 0x207080, 0x0 },
+	{ 0x8080, 0x0 },
+	{ 0x108080, 0x0 },
+	{ 0x208080, 0x0 },
+	{ 0x9080, 0x0 },
+	{ 0x109080, 0x0 },
+	{ 0x209080, 0x0 },
+	{ 0x10080, 0x0 },
+	{ 0x110080, 0x0 },
+	{ 0x210080, 0x0 },
+	{ 0x10180, 0x0 },
+	{ 0x110180, 0x0 },
+	{ 0x210180, 0x0 },
+	{ 0x11080, 0x0 },
+	{ 0x111080, 0x0 },
+	{ 0x211080, 0x0 },
+	{ 0x11180, 0x0 },
+	{ 0x111180, 0x0 },
+	{ 0x211180, 0x0 },
+	{ 0x12080, 0x0 },
+	{ 0x112080, 0x0 },
+	{ 0x212080, 0x0 },
+	{ 0x12180, 0x0 },
+	{ 0x112180, 0x0 },
+	{ 0x212180, 0x0 },
+	{ 0x13080, 0x0 },
+	{ 0x113080, 0x0 },
+	{ 0x213080, 0x0 },
+	{ 0x13180, 0x0 },
+	{ 0x113180, 0x0 },
+	{ 0x213180, 0x0 },
+	{ 0x10081, 0x0 },
+	{ 0x110081, 0x0 },
+	{ 0x210081, 0x0 },
+	{ 0x10181, 0x0 },
+	{ 0x110181, 0x0 },
+	{ 0x210181, 0x0 },
+	{ 0x11081, 0x0 },
+	{ 0x111081, 0x0 },
+	{ 0x211081, 0x0 },
+	{ 0x11181, 0x0 },
+	{ 0x111181, 0x0 },
+	{ 0x211181, 0x0 },
+	{ 0x12081, 0x0 },
+	{ 0x112081, 0x0 },
+	{ 0x212081, 0x0 },
+	{ 0x12181, 0x0 },
+	{ 0x112181, 0x0 },
+	{ 0x212181, 0x0 },
+	{ 0x13081, 0x0 },
+	{ 0x113081, 0x0 },
+	{ 0x213081, 0x0 },
+	{ 0x13181, 0x0 },
+	{ 0x113181, 0x0 },
+	{ 0x213181, 0x0 },
+	{ 0x100d0, 0x0 },
+	{ 0x1100d0, 0x0 },
+	{ 0x2100d0, 0x0 },
+	{ 0x101d0, 0x0 },
+	{ 0x1101d0, 0x0 },
+	{ 0x2101d0, 0x0 },
+	{ 0x110d0, 0x0 },
+	{ 0x1110d0, 0x0 },
+	{ 0x2110d0, 0x0 },
+	{ 0x111d0, 0x0 },
+	{ 0x1111d0, 0x0 },
+	{ 0x2111d0, 0x0 },
+	{ 0x120d0, 0x0 },
+	{ 0x1120d0, 0x0 },
+	{ 0x2120d0, 0x0 },
+	{ 0x121d0, 0x0 },
+	{ 0x1121d0, 0x0 },
+	{ 0x2121d0, 0x0 },
+	{ 0x130d0, 0x0 },
+	{ 0x1130d0, 0x0 },
+	{ 0x2130d0, 0x0 },
+	{ 0x131d0, 0x0 },
+	{ 0x1131d0, 0x0 },
+	{ 0x2131d0, 0x0 },
+	{ 0x100d1, 0x0 },
+	{ 0x1100d1, 0x0 },
+	{ 0x2100d1, 0x0 },
+	{ 0x101d1, 0x0 },
+	{ 0x1101d1, 0x0 },
+	{ 0x2101d1, 0x0 },
+	{ 0x110d1, 0x0 },
+	{ 0x1110d1, 0x0 },
+	{ 0x2110d1, 0x0 },
+	{ 0x111d1, 0x0 },
+	{ 0x1111d1, 0x0 },
+	{ 0x2111d1, 0x0 },
+	{ 0x120d1, 0x0 },
+	{ 0x1120d1, 0x0 },
+	{ 0x2120d1, 0x0 },
+	{ 0x121d1, 0x0 },
+	{ 0x1121d1, 0x0 },
+	{ 0x2121d1, 0x0 },
+	{ 0x130d1, 0x0 },
+	{ 0x1130d1, 0x0 },
+	{ 0x2130d1, 0x0 },
+	{ 0x131d1, 0x0 },
+	{ 0x1131d1, 0x0 },
+	{ 0x2131d1, 0x0 },
+	{ 0x10068, 0x0 },
+	{ 0x10168, 0x0 },
+	{ 0x10268, 0x0 },
+	{ 0x10368, 0x0 },
+	{ 0x10468, 0x0 },
+	{ 0x10568, 0x0 },
+	{ 0x10668, 0x0 },
+	{ 0x10768, 0x0 },
+	{ 0x10868, 0x0 },
+	{ 0x11068, 0x0 },
+	{ 0x11168, 0x0 },
+	{ 0x11268, 0x0 },
+	{ 0x11368, 0x0 },
+	{ 0x11468, 0x0 },
+	{ 0x11568, 0x0 },
+	{ 0x11668, 0x0 },
+	{ 0x11768, 0x0 },
+	{ 0x11868, 0x0 },
+	{ 0x12068, 0x0 },
+	{ 0x12168, 0x0 },
+	{ 0x12268, 0x0 },
+	{ 0x12368, 0x0 },
+	{ 0x12468, 0x0 },
+	{ 0x12568, 0x0 },
+	{ 0x12668, 0x0 },
+	{ 0x12768, 0x0 },
+	{ 0x12868, 0x0 },
+	{ 0x13068, 0x0 },
+	{ 0x13168, 0x0 },
+	{ 0x13268, 0x0 },
+	{ 0x13368, 0x0 },
+	{ 0x13468, 0x0 },
+	{ 0x13568, 0x0 },
+	{ 0x13668, 0x0 },
+	{ 0x13768, 0x0 },
+	{ 0x13868, 0x0 },
+	{ 0x10069, 0x0 },
+	{ 0x10169, 0x0 },
+	{ 0x10269, 0x0 },
+	{ 0x10369, 0x0 },
+	{ 0x10469, 0x0 },
+	{ 0x10569, 0x0 },
+	{ 0x10669, 0x0 },
+	{ 0x10769, 0x0 },
+	{ 0x10869, 0x0 },
+	{ 0x11069, 0x0 },
+	{ 0x11169, 0x0 },
+	{ 0x11269, 0x0 },
+	{ 0x11369, 0x0 },
+	{ 0x11469, 0x0 },
+	{ 0x11569, 0x0 },
+	{ 0x11669, 0x0 },
+	{ 0x11769, 0x0 },
+	{ 0x11869, 0x0 },
+	{ 0x12069, 0x0 },
+	{ 0x12169, 0x0 },
+	{ 0x12269, 0x0 },
+	{ 0x12369, 0x0 },
+	{ 0x12469, 0x0 },
+	{ 0x12569, 0x0 },
+	{ 0x12669, 0x0 },
+	{ 0x12769, 0x0 },
+	{ 0x12869, 0x0 },
+	{ 0x13069, 0x0 },
+	{ 0x13169, 0x0 },
+	{ 0x13269, 0x0 },
+	{ 0x13369, 0x0 },
+	{ 0x13469, 0x0 },
+	{ 0x13569, 0x0 },
+	{ 0x13669, 0x0 },
+	{ 0x13769, 0x0 },
+	{ 0x13869, 0x0 },
+	{ 0x1008c, 0x0 },
+	{ 0x11008c, 0x0 },
+	{ 0x21008c, 0x0 },
+	{ 0x1018c, 0x0 },
+	{ 0x11018c, 0x0 },
+	{ 0x21018c, 0x0 },
+	{ 0x1108c, 0x0 },
+	{ 0x11108c, 0x0 },
+	{ 0x21108c, 0x0 },
+	{ 0x1118c, 0x0 },
+	{ 0x11118c, 0x0 },
+	{ 0x21118c, 0x0 },
+	{ 0x1208c, 0x0 },
+	{ 0x11208c, 0x0 },
+	{ 0x21208c, 0x0 },
+	{ 0x1218c, 0x0 },
+	{ 0x11218c, 0x0 },
+	{ 0x21218c, 0x0 },
+	{ 0x1308c, 0x0 },
+	{ 0x11308c, 0x0 },
+	{ 0x21308c, 0x0 },
+	{ 0x1318c, 0x0 },
+	{ 0x11318c, 0x0 },
+	{ 0x21318c, 0x0 },
+	{ 0x1008d, 0x0 },
+	{ 0x11008d, 0x0 },
+	{ 0x21008d, 0x0 },
+	{ 0x1018d, 0x0 },
+	{ 0x11018d, 0x0 },
+	{ 0x21018d, 0x0 },
+	{ 0x1108d, 0x0 },
+	{ 0x11108d, 0x0 },
+	{ 0x21108d, 0x0 },
+	{ 0x1118d, 0x0 },
+	{ 0x11118d, 0x0 },
+	{ 0x21118d, 0x0 },
+	{ 0x1208d, 0x0 },
+	{ 0x11208d, 0x0 },
+	{ 0x21208d, 0x0 },
+	{ 0x1218d, 0x0 },
+	{ 0x11218d, 0x0 },
+	{ 0x21218d, 0x0 },
+	{ 0x1308d, 0x0 },
+	{ 0x11308d, 0x0 },
+	{ 0x21308d, 0x0 },
+	{ 0x1318d, 0x0 },
+	{ 0x11318d, 0x0 },
+	{ 0x21318d, 0x0 },
+	{ 0x100c0, 0x0 },
+	{ 0x1100c0, 0x0 },
+	{ 0x2100c0, 0x0 },
+	{ 0x101c0, 0x0 },
+	{ 0x1101c0, 0x0 },
+	{ 0x2101c0, 0x0 },
+	{ 0x102c0, 0x0 },
+	{ 0x1102c0, 0x0 },
+	{ 0x2102c0, 0x0 },
+	{ 0x103c0, 0x0 },
+	{ 0x1103c0, 0x0 },
+	{ 0x2103c0, 0x0 },
+	{ 0x104c0, 0x0 },
+	{ 0x1104c0, 0x0 },
+	{ 0x2104c0, 0x0 },
+	{ 0x105c0, 0x0 },
+	{ 0x1105c0, 0x0 },
+	{ 0x2105c0, 0x0 },
+	{ 0x106c0, 0x0 },
+	{ 0x1106c0, 0x0 },
+	{ 0x2106c0, 0x0 },
+	{ 0x107c0, 0x0 },
+	{ 0x1107c0, 0x0 },
+	{ 0x2107c0, 0x0 },
+	{ 0x108c0, 0x0 },
+	{ 0x1108c0, 0x0 },
+	{ 0x2108c0, 0x0 },
+	{ 0x110c0, 0x0 },
+	{ 0x1110c0, 0x0 },
+	{ 0x2110c0, 0x0 },
+	{ 0x111c0, 0x0 },
+	{ 0x1111c0, 0x0 },
+	{ 0x2111c0, 0x0 },
+	{ 0x112c0, 0x0 },
+	{ 0x1112c0, 0x0 },
+	{ 0x2112c0, 0x0 },
+	{ 0x113c0, 0x0 },
+	{ 0x1113c0, 0x0 },
+	{ 0x2113c0, 0x0 },
+	{ 0x114c0, 0x0 },
+	{ 0x1114c0, 0x0 },
+	{ 0x2114c0, 0x0 },
+	{ 0x115c0, 0x0 },
+	{ 0x1115c0, 0x0 },
+	{ 0x2115c0, 0x0 },
+	{ 0x116c0, 0x0 },
+	{ 0x1116c0, 0x0 },
+	{ 0x2116c0, 0x0 },
+	{ 0x117c0, 0x0 },
+	{ 0x1117c0, 0x0 },
+	{ 0x2117c0, 0x0 },
+	{ 0x118c0, 0x0 },
+	{ 0x1118c0, 0x0 },
+	{ 0x2118c0, 0x0 },
+	{ 0x120c0, 0x0 },
+	{ 0x1120c0, 0x0 },
+	{ 0x2120c0, 0x0 },
+	{ 0x121c0, 0x0 },
+	{ 0x1121c0, 0x0 },
+	{ 0x2121c0, 0x0 },
+	{ 0x122c0, 0x0 },
+	{ 0x1122c0, 0x0 },
+	{ 0x2122c0, 0x0 },
+	{ 0x123c0, 0x0 },
+	{ 0x1123c0, 0x0 },
+	{ 0x2123c0, 0x0 },
+	{ 0x124c0, 0x0 },
+	{ 0x1124c0, 0x0 },
+	{ 0x2124c0, 0x0 },
+	{ 0x125c0, 0x0 },
+	{ 0x1125c0, 0x0 },
+	{ 0x2125c0, 0x0 },
+	{ 0x126c0, 0x0 },
+	{ 0x1126c0, 0x0 },
+	{ 0x2126c0, 0x0 },
+	{ 0x127c0, 0x0 },
+	{ 0x1127c0, 0x0 },
+	{ 0x2127c0, 0x0 },
+	{ 0x128c0, 0x0 },
+	{ 0x1128c0, 0x0 },
+	{ 0x2128c0, 0x0 },
+	{ 0x130c0, 0x0 },
+	{ 0x1130c0, 0x0 },
+	{ 0x2130c0, 0x0 },
+	{ 0x131c0, 0x0 },
+	{ 0x1131c0, 0x0 },
+	{ 0x2131c0, 0x0 },
+	{ 0x132c0, 0x0 },
+	{ 0x1132c0, 0x0 },
+	{ 0x2132c0, 0x0 },
+	{ 0x133c0, 0x0 },
+	{ 0x1133c0, 0x0 },
+	{ 0x2133c0, 0x0 },
+	{ 0x134c0, 0x0 },
+	{ 0x1134c0, 0x0 },
+	{ 0x2134c0, 0x0 },
+	{ 0x135c0, 0x0 },
+	{ 0x1135c0, 0x0 },
+	{ 0x2135c0, 0x0 },
+	{ 0x136c0, 0x0 },
+	{ 0x1136c0, 0x0 },
+	{ 0x2136c0, 0x0 },
+	{ 0x137c0, 0x0 },
+	{ 0x1137c0, 0x0 },
+	{ 0x2137c0, 0x0 },
+	{ 0x138c0, 0x0 },
+	{ 0x1138c0, 0x0 },
+	{ 0x2138c0, 0x0 },
+	{ 0x100c1, 0x0 },
+	{ 0x1100c1, 0x0 },
+	{ 0x2100c1, 0x0 },
+	{ 0x101c1, 0x0 },
+	{ 0x1101c1, 0x0 },
+	{ 0x2101c1, 0x0 },
+	{ 0x102c1, 0x0 },
+	{ 0x1102c1, 0x0 },
+	{ 0x2102c1, 0x0 },
+	{ 0x103c1, 0x0 },
+	{ 0x1103c1, 0x0 },
+	{ 0x2103c1, 0x0 },
+	{ 0x104c1, 0x0 },
+	{ 0x1104c1, 0x0 },
+	{ 0x2104c1, 0x0 },
+	{ 0x105c1, 0x0 },
+	{ 0x1105c1, 0x0 },
+	{ 0x2105c1, 0x0 },
+	{ 0x106c1, 0x0 },
+	{ 0x1106c1, 0x0 },
+	{ 0x2106c1, 0x0 },
+	{ 0x107c1, 0x0 },
+	{ 0x1107c1, 0x0 },
+	{ 0x2107c1, 0x0 },
+	{ 0x108c1, 0x0 },
+	{ 0x1108c1, 0x0 },
+	{ 0x2108c1, 0x0 },
+	{ 0x110c1, 0x0 },
+	{ 0x1110c1, 0x0 },
+	{ 0x2110c1, 0x0 },
+	{ 0x111c1, 0x0 },
+	{ 0x1111c1, 0x0 },
+	{ 0x2111c1, 0x0 },
+	{ 0x112c1, 0x0 },
+	{ 0x1112c1, 0x0 },
+	{ 0x2112c1, 0x0 },
+	{ 0x113c1, 0x0 },
+	{ 0x1113c1, 0x0 },
+	{ 0x2113c1, 0x0 },
+	{ 0x114c1, 0x0 },
+	{ 0x1114c1, 0x0 },
+	{ 0x2114c1, 0x0 },
+	{ 0x115c1, 0x0 },
+	{ 0x1115c1, 0x0 },
+	{ 0x2115c1, 0x0 },
+	{ 0x116c1, 0x0 },
+	{ 0x1116c1, 0x0 },
+	{ 0x2116c1, 0x0 },
+	{ 0x117c1, 0x0 },
+	{ 0x1117c1, 0x0 },
+	{ 0x2117c1, 0x0 },
+	{ 0x118c1, 0x0 },
+	{ 0x1118c1, 0x0 },
+	{ 0x2118c1, 0x0 },
+	{ 0x120c1, 0x0 },
+	{ 0x1120c1, 0x0 },
+	{ 0x2120c1, 0x0 },
+	{ 0x121c1, 0x0 },
+	{ 0x1121c1, 0x0 },
+	{ 0x2121c1, 0x0 },
+	{ 0x122c1, 0x0 },
+	{ 0x1122c1, 0x0 },
+	{ 0x2122c1, 0x0 },
+	{ 0x123c1, 0x0 },
+	{ 0x1123c1, 0x0 },
+	{ 0x2123c1, 0x0 },
+	{ 0x124c1, 0x0 },
+	{ 0x1124c1, 0x0 },
+	{ 0x2124c1, 0x0 },
+	{ 0x125c1, 0x0 },
+	{ 0x1125c1, 0x0 },
+	{ 0x2125c1, 0x0 },
+	{ 0x126c1, 0x0 },
+	{ 0x1126c1, 0x0 },
+	{ 0x2126c1, 0x0 },
+	{ 0x127c1, 0x0 },
+	{ 0x1127c1, 0x0 },
+	{ 0x2127c1, 0x0 },
+	{ 0x128c1, 0x0 },
+	{ 0x1128c1, 0x0 },
+	{ 0x2128c1, 0x0 },
+	{ 0x130c1, 0x0 },
+	{ 0x1130c1, 0x0 },
+	{ 0x2130c1, 0x0 },
+	{ 0x131c1, 0x0 },
+	{ 0x1131c1, 0x0 },
+	{ 0x2131c1, 0x0 },
+	{ 0x132c1, 0x0 },
+	{ 0x1132c1, 0x0 },
+	{ 0x2132c1, 0x0 },
+	{ 0x133c1, 0x0 },
+	{ 0x1133c1, 0x0 },
+	{ 0x2133c1, 0x0 },
+	{ 0x134c1, 0x0 },
+	{ 0x1134c1, 0x0 },
+	{ 0x2134c1, 0x0 },
+	{ 0x135c1, 0x0 },
+	{ 0x1135c1, 0x0 },
+	{ 0x2135c1, 0x0 },
+	{ 0x136c1, 0x0 },
+	{ 0x1136c1, 0x0 },
+	{ 0x2136c1, 0x0 },
+	{ 0x137c1, 0x0 },
+	{ 0x1137c1, 0x0 },
+	{ 0x2137c1, 0x0 },
+	{ 0x138c1, 0x0 },
+	{ 0x1138c1, 0x0 },
+	{ 0x2138c1, 0x0 },
+	{ 0x10020, 0x0 },
+	{ 0x110020, 0x0 },
+	{ 0x210020, 0x0 },
+	{ 0x11020, 0x0 },
+	{ 0x111020, 0x0 },
+	{ 0x211020, 0x0 },
+	{ 0x12020, 0x0 },
+	{ 0x112020, 0x0 },
+	{ 0x212020, 0x0 },
+	{ 0x13020, 0x0 },
+	{ 0x113020, 0x0 },
+	{ 0x213020, 0x0 },
+	{ 0x20072, 0x0 },
+	{ 0x20073, 0x0 },
+	{ 0x20074, 0x0 },
+	{ 0x100aa, 0x0 },
+	{ 0x110aa, 0x0 },
+	{ 0x120aa, 0x0 },
+	{ 0x130aa, 0x0 },
+	{ 0x20010, 0x0 },
+	{ 0x120010, 0x0 },
+	{ 0x220010, 0x0 },
+	{ 0x20011, 0x0 },
+	{ 0x120011, 0x0 },
+	{ 0x220011, 0x0 },
+	{ 0x100ae, 0x0 },
+	{ 0x1100ae, 0x0 },
+	{ 0x2100ae, 0x0 },
+	{ 0x100af, 0x0 },
+	{ 0x1100af, 0x0 },
+	{ 0x2100af, 0x0 },
+	{ 0x110ae, 0x0 },
+	{ 0x1110ae, 0x0 },
+	{ 0x2110ae, 0x0 },
+	{ 0x110af, 0x0 },
+	{ 0x1110af, 0x0 },
+	{ 0x2110af, 0x0 },
+	{ 0x120ae, 0x0 },
+	{ 0x1120ae, 0x0 },
+	{ 0x2120ae, 0x0 },
+	{ 0x120af, 0x0 },
+	{ 0x1120af, 0x0 },
+	{ 0x2120af, 0x0 },
+	{ 0x130ae, 0x0 },
+	{ 0x1130ae, 0x0 },
+	{ 0x2130ae, 0x0 },
+	{ 0x130af, 0x0 },
+	{ 0x1130af, 0x0 },
+	{ 0x2130af, 0x0 },
+	{ 0x20020, 0x0 },
+	{ 0x120020, 0x0 },
+	{ 0x220020, 0x0 },
+	{ 0x100a0, 0x0 },
+	{ 0x100a1, 0x0 },
+	{ 0x100a2, 0x0 },
+	{ 0x100a3, 0x0 },
+	{ 0x100a4, 0x0 },
+	{ 0x100a5, 0x0 },
+	{ 0x100a6, 0x0 },
+	{ 0x100a7, 0x0 },
+	{ 0x110a0, 0x0 },
+	{ 0x110a1, 0x0 },
+	{ 0x110a2, 0x0 },
+	{ 0x110a3, 0x0 },
+	{ 0x110a4, 0x0 },
+	{ 0x110a5, 0x0 },
+	{ 0x110a6, 0x0 },
+	{ 0x110a7, 0x0 },
+	{ 0x120a0, 0x0 },
+	{ 0x120a1, 0x0 },
+	{ 0x120a2, 0x0 },
+	{ 0x120a3, 0x0 },
+	{ 0x120a4, 0x0 },
+	{ 0x120a5, 0x0 },
+	{ 0x120a6, 0x0 },
+	{ 0x120a7, 0x0 },
+	{ 0x130a0, 0x0 },
+	{ 0x130a1, 0x0 },
+	{ 0x130a2, 0x0 },
+	{ 0x130a3, 0x0 },
+	{ 0x130a4, 0x0 },
+	{ 0x130a5, 0x0 },
+	{ 0x130a6, 0x0 },
+	{ 0x130a7, 0x0 },
+	{ 0x2007c, 0x0 },
+	{ 0x12007c, 0x0 },
+	{ 0x22007c, 0x0 },
+	{ 0x2007d, 0x0 },
+	{ 0x12007d, 0x0 },
+	{ 0x22007d, 0x0 },
+	{ 0x400fd, 0x0 },
+	{ 0x400c0, 0x0 },
+	{ 0x90201, 0x0 },
+	{ 0x190201, 0x0 },
+	{ 0x290201, 0x0 },
+	{ 0x90202, 0x0 },
+	{ 0x190202, 0x0 },
+	{ 0x290202, 0x0 },
+	{ 0x90203, 0x0 },
+	{ 0x190203, 0x0 },
+	{ 0x290203, 0x0 },
+	{ 0x90204, 0x0 },
+	{ 0x190204, 0x0 },
+	{ 0x290204, 0x0 },
+	{ 0x90205, 0x0 },
+	{ 0x190205, 0x0 },
+	{ 0x290205, 0x0 },
+	{ 0x90206, 0x0 },
+	{ 0x190206, 0x0 },
+	{ 0x290206, 0x0 },
+	{ 0x90207, 0x0 },
+	{ 0x190207, 0x0 },
+	{ 0x290207, 0x0 },
+	{ 0x90208, 0x0 },
+	{ 0x190208, 0x0 },
+	{ 0x290208, 0x0 },
+	{ 0x10062, 0x0 },
+	{ 0x10162, 0x0 },
+	{ 0x10262, 0x0 },
+	{ 0x10362, 0x0 },
+	{ 0x10462, 0x0 },
+	{ 0x10562, 0x0 },
+	{ 0x10662, 0x0 },
+	{ 0x10762, 0x0 },
+	{ 0x10862, 0x0 },
+	{ 0x11062, 0x0 },
+	{ 0x11162, 0x0 },
+	{ 0x11262, 0x0 },
+	{ 0x11362, 0x0 },
+	{ 0x11462, 0x0 },
+	{ 0x11562, 0x0 },
+	{ 0x11662, 0x0 },
+	{ 0x11762, 0x0 },
+	{ 0x11862, 0x0 },
+	{ 0x12062, 0x0 },
+	{ 0x12162, 0x0 },
+	{ 0x12262, 0x0 },
+	{ 0x12362, 0x0 },
+	{ 0x12462, 0x0 },
+	{ 0x12562, 0x0 },
+	{ 0x12662, 0x0 },
+	{ 0x12762, 0x0 },
+	{ 0x12862, 0x0 },
+	{ 0x13062, 0x0 },
+	{ 0x13162, 0x0 },
+	{ 0x13262, 0x0 },
+	{ 0x13362, 0x0 },
+	{ 0x13462, 0x0 },
+	{ 0x13562, 0x0 },
+	{ 0x13662, 0x0 },
+	{ 0x13762, 0x0 },
+	{ 0x13862, 0x0 },
+	{ 0x20077, 0x0 },
+	{ 0x10001, 0x0 },
+	{ 0x11001, 0x0 },
+	{ 0x12001, 0x0 },
+	{ 0x13001, 0x0 },
+	{ 0x10040, 0x0 },
+	{ 0x10140, 0x0 },
+	{ 0x10240, 0x0 },
+	{ 0x10340, 0x0 },
+	{ 0x10440, 0x0 },
+	{ 0x10540, 0x0 },
+	{ 0x10640, 0x0 },
+	{ 0x10740, 0x0 },
+	{ 0x10840, 0x0 },
+	{ 0x10030, 0x0 },
+	{ 0x10130, 0x0 },
+	{ 0x10230, 0x0 },
+	{ 0x10330, 0x0 },
+	{ 0x10430, 0x0 },
+	{ 0x10530, 0x0 },
+	{ 0x10630, 0x0 },
+	{ 0x10730, 0x0 },
+	{ 0x10830, 0x0 },
+	{ 0x11040, 0x0 },
+	{ 0x11140, 0x0 },
+	{ 0x11240, 0x0 },
+	{ 0x11340, 0x0 },
+	{ 0x11440, 0x0 },
+	{ 0x11540, 0x0 },
+	{ 0x11640, 0x0 },
+	{ 0x11740, 0x0 },
+	{ 0x11840, 0x0 },
+	{ 0x11030, 0x0 },
+	{ 0x11130, 0x0 },
+	{ 0x11230, 0x0 },
+	{ 0x11330, 0x0 },
+	{ 0x11430, 0x0 },
+	{ 0x11530, 0x0 },
+	{ 0x11630, 0x0 },
+	{ 0x11730, 0x0 },
+	{ 0x11830, 0x0 },
+	{ 0x12040, 0x0 },
+	{ 0x12140, 0x0 },
+	{ 0x12240, 0x0 },
+	{ 0x12340, 0x0 },
+	{ 0x12440, 0x0 },
+	{ 0x12540, 0x0 },
+	{ 0x12640, 0x0 },
+	{ 0x12740, 0x0 },
+	{ 0x12840, 0x0 },
+	{ 0x12030, 0x0 },
+	{ 0x12130, 0x0 },
+	{ 0x12230, 0x0 },
+	{ 0x12330, 0x0 },
+	{ 0x12430, 0x0 },
+	{ 0x12530, 0x0 },
+	{ 0x12630, 0x0 },
+	{ 0x12730, 0x0 },
+	{ 0x12830, 0x0 },
+	{ 0x13040, 0x0 },
+	{ 0x13140, 0x0 },
+	{ 0x13240, 0x0 },
+	{ 0x13340, 0x0 },
+	{ 0x13440, 0x0 },
+	{ 0x13540, 0x0 },
+	{ 0x13640, 0x0 },
+	{ 0x13740, 0x0 },
+	{ 0x13840, 0x0 },
+	{ 0x13030, 0x0 },
+	{ 0x13130, 0x0 },
+	{ 0x13230, 0x0 },
+	{ 0x13330, 0x0 },
+	{ 0x13430, 0x0 },
+	{ 0x13530, 0x0 },
+	{ 0x13630, 0x0 },
+	{ 0x13730, 0x0 },
+	{ 0x13830, 0x0 },
+};
+
+/* P0 message block parameter for training firmware */
+static struct dram_cfg_param ddr_fsp0_cfg[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54003, 0xe94 },
+	{ 0x54004, 0x4 },
+	{ 0x54006, 0x15 },
+	{ 0x54008, 0x131f },
+	{ 0x54009, 0xff },
+	{ 0x5400b, 0x4 },
+	{ 0x5400c, 0x1 },
+	{ 0x5400d, 0x100 },
+	{ 0x5400f, 0x100 },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x36e4 },
+	{ 0x5401a, 0x32 },
+	{ 0x5401b, 0x1146 },
+	{ 0x5401c, 0x1108 },
+	{ 0x5401e, 0x6 },
+	{ 0x5401f, 0x36e4 },
+	{ 0x54020, 0x32 },
+	{ 0x54021, 0x1146 },
+	{ 0x54022, 0x1108 },
+	{ 0x54024, 0x6 },
+	{ 0x54032, 0xe400 },
+	{ 0x54033, 0x3236 },
+	{ 0x54034, 0x4600 },
+	{ 0x54035, 0x811 },
+	{ 0x54036, 0x11 },
+	{ 0x54037, 0x600 },
+	{ 0x54038, 0xe400 },
+	{ 0x54039, 0x3236 },
+	{ 0x5403a, 0x4600 },
+	{ 0x5403b, 0x811 },
+	{ 0x5403c, 0x11 },
+	{ 0x5403d, 0x600 },
+	{ 0xd0000, 0x1 }
+};
+
+/* P0 2D message block paremeter for training firmware */
+static struct dram_cfg_param ddr_fsp0_2d_cfg[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54003, 0xe94 },
+	{ 0x54004, 0x4 },
+	{ 0x54006, 0x15 },
+	{ 0x54008, 0x61 },
+	{ 0x54009, 0xff },
+	{ 0x5400b, 0x4 },
+	{ 0x5400c, 0x1 },
+	{ 0x5400d, 0x100 },
+	{ 0x5400f, 0x100 },
+	{ 0x54010, 0x2080 },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x36e4 },
+	{ 0x5401a, 0x32 },
+	{ 0x5401b, 0x1146 },
+	{ 0x5401c, 0x1108 },
+	{ 0x5401e, 0x6 },
+	{ 0x5401f, 0x36e4 },
+	{ 0x54020, 0x32 },
+	{ 0x54021, 0x1146 },
+	{ 0x54022, 0x1108 },
+	{ 0x54024, 0x6 },
+	{ 0x54032, 0xe400 },
+	{ 0x54033, 0x3236 },
+	{ 0x54034, 0x4600 },
+	{ 0x54035, 0x811 },
+	{ 0x54036, 0x11 },
+	{ 0x54037, 0x600 },
+	{ 0x54038, 0xe400 },
+	{ 0x54039, 0x3236 },
+	{ 0x5403a, 0x4600 },
+	{ 0x5403b, 0x811 },
+	{ 0x5403c, 0x11 },
+	{ 0x5403d, 0x600 },
+	{ 0xd0000, 0x1 }
+};
+
+/* DRAM PHY init engine image */
+static struct dram_cfg_param ddr_phy_pie[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x90000, 0x10 },
+	{ 0x90001, 0x400 },
+	{ 0x90002, 0x10e },
+	{ 0x90003, 0x0 },
+	{ 0x90004, 0x0 },
+	{ 0x90005, 0x8 },
+	{ 0x90029, 0xb },
+	{ 0x9002a, 0x480 },
+	{ 0x9002b, 0x109 },
+	{ 0x9002c, 0x8 },
+	{ 0x9002d, 0x448 },
+	{ 0x9002e, 0x139 },
+	{ 0x9002f, 0x8 },
+	{ 0x90030, 0x478 },
+	{ 0x90031, 0x109 },
+	{ 0x90032, 0x0 },
+	{ 0x90033, 0xe8 },
+	{ 0x90034, 0x109 },
+	{ 0x90035, 0x2 },
+	{ 0x90036, 0x10 },
+	{ 0x90037, 0x139 },
+	{ 0x90038, 0xb },
+	{ 0x90039, 0x7c0 },
+	{ 0x9003a, 0x139 },
+	{ 0x9003b, 0x44 },
+	{ 0x9003c, 0x633 },
+	{ 0x9003d, 0x159 },
+	{ 0x9003e, 0x14f },
+	{ 0x9003f, 0x630 },
+	{ 0x90040, 0x159 },
+	{ 0x90041, 0x47 },
+	{ 0x90042, 0x633 },
+	{ 0x90043, 0x149 },
+	{ 0x90044, 0x4f },
+	{ 0x90045, 0x633 },
+	{ 0x90046, 0x179 },
+	{ 0x90047, 0x8 },
+	{ 0x90048, 0xe0 },
+	{ 0x90049, 0x109 },
+	{ 0x9004a, 0x0 },
+	{ 0x9004b, 0x7c8 },
+	{ 0x9004c, 0x109 },
+	{ 0x9004d, 0x0 },
+	{ 0x9004e, 0x1 },
+	{ 0x9004f, 0x8 },
+	{ 0x90050, 0x30 },
+	{ 0x90051, 0x65a },
+	{ 0x90052, 0x9 },
+	{ 0x90053, 0x0 },
+	{ 0x90054, 0x45a },
+	{ 0x90055, 0x9 },
+	{ 0x90056, 0x0 },
+	{ 0x90057, 0x448 },
+	{ 0x90058, 0x109 },
+	{ 0x90059, 0x40 },
+	{ 0x9005a, 0x633 },
+	{ 0x9005b, 0x179 },
+	{ 0x9005c, 0x1 },
+	{ 0x9005d, 0x618 },
+	{ 0x9005e, 0x109 },
+	{ 0x9005f, 0x40c0 },
+	{ 0x90060, 0x633 },
+	{ 0x90061, 0x149 },
+	{ 0x90062, 0x8 },
+	{ 0x90063, 0x4 },
+	{ 0x90064, 0x48 },
+	{ 0x90065, 0x4040 },
+	{ 0x90066, 0x633 },
+	{ 0x90067, 0x149 },
+	{ 0x90068, 0x0 },
+	{ 0x90069, 0x4 },
+	{ 0x9006a, 0x48 },
+	{ 0x9006b, 0x40 },
+	{ 0x9006c, 0x633 },
+	{ 0x9006d, 0x149 },
+	{ 0x9006e, 0x0 },
+	{ 0x9006f, 0x658 },
+	{ 0x90070, 0x109 },
+	{ 0x90071, 0x10 },
+	{ 0x90072, 0x4 },
+	{ 0x90073, 0x18 },
+	{ 0x90074, 0x0 },
+	{ 0x90075, 0x4 },
+	{ 0x90076, 0x78 },
+	{ 0x90077, 0x549 },
+	{ 0x90078, 0x633 },
+	{ 0x90079, 0x159 },
+	{ 0x9007a, 0xd49 },
+	{ 0x9007b, 0x633 },
+	{ 0x9007c, 0x159 },
+	{ 0x9007d, 0x94a },
+	{ 0x9007e, 0x633 },
+	{ 0x9007f, 0x159 },
+	{ 0x90080, 0x441 },
+	{ 0x90081, 0x633 },
+	{ 0x90082, 0x149 },
+	{ 0x90083, 0x42 },
+	{ 0x90084, 0x633 },
+	{ 0x90085, 0x149 },
+	{ 0x90086, 0x1 },
+	{ 0x90087, 0x633 },
+	{ 0x90088, 0x149 },
+	{ 0x90089, 0x0 },
+	{ 0x9008a, 0xe0 },
+	{ 0x9008b, 0x109 },
+	{ 0x9008c, 0xa },
+	{ 0x9008d, 0x10 },
+	{ 0x9008e, 0x109 },
+	{ 0x9008f, 0x9 },
+	{ 0x90090, 0x3c0 },
+	{ 0x90091, 0x149 },
+	{ 0x90092, 0x9 },
+	{ 0x90093, 0x3c0 },
+	{ 0x90094, 0x159 },
+	{ 0x90095, 0x18 },
+	{ 0x90096, 0x10 },
+	{ 0x90097, 0x109 },
+	{ 0x90098, 0x0 },
+	{ 0x90099, 0x3c0 },
+	{ 0x9009a, 0x109 },
+	{ 0x9009b, 0x18 },
+	{ 0x9009c, 0x4 },
+	{ 0x9009d, 0x48 },
+	{ 0x9009e, 0x18 },
+	{ 0x9009f, 0x4 },
+	{ 0x900a0, 0x58 },
+	{ 0x900a1, 0xb },
+	{ 0x900a2, 0x10 },
+	{ 0x900a3, 0x109 },
+	{ 0x900a4, 0x1 },
+	{ 0x900a5, 0x10 },
+	{ 0x900a6, 0x109 },
+	{ 0x900a7, 0x5 },
+	{ 0x900a8, 0x7c0 },
+	{ 0x900a9, 0x109 },
+	{ 0x40000, 0x811 },
+	{ 0x40020, 0x880 },
+	{ 0x40040, 0x0 },
+	{ 0x40060, 0x0 },
+	{ 0x40001, 0x4008 },
+	{ 0x40021, 0x83 },
+	{ 0x40041, 0x4f },
+	{ 0x40061, 0x0 },
+	{ 0x40002, 0x4040 },
+	{ 0x40022, 0x83 },
+	{ 0x40042, 0x51 },
+	{ 0x40062, 0x0 },
+	{ 0x40003, 0x811 },
+	{ 0x40023, 0x880 },
+	{ 0x40043, 0x0 },
+	{ 0x40063, 0x0 },
+	{ 0x40004, 0x720 },
+	{ 0x40024, 0xf },
+	{ 0x40044, 0x1740 },
+	{ 0x40064, 0x0 },
+	{ 0x40005, 0x16 },
+	{ 0x40025, 0x83 },
+	{ 0x40045, 0x4b },
+	{ 0x40065, 0x0 },
+	{ 0x40006, 0x716 },
+	{ 0x40026, 0xf },
+	{ 0x40046, 0x2001 },
+	{ 0x40066, 0x0 },
+	{ 0x40007, 0x716 },
+	{ 0x40027, 0xf },
+	{ 0x40047, 0x2800 },
+	{ 0x40067, 0x0 },
+	{ 0x40008, 0x716 },
+	{ 0x40028, 0xf },
+	{ 0x40048, 0xf00 },
+	{ 0x40068, 0x0 },
+	{ 0x40009, 0x720 },
+	{ 0x40029, 0xf },
+	{ 0x40049, 0x1400 },
+	{ 0x40069, 0x0 },
+	{ 0x4000a, 0xe08 },
+	{ 0x4002a, 0xc15 },
+	{ 0x4004a, 0x0 },
+	{ 0x4006a, 0x0 },
+	{ 0x4000b, 0x625 },
+	{ 0x4002b, 0x15 },
+	{ 0x4004b, 0x0 },
+	{ 0x4006b, 0x0 },
+	{ 0x4000c, 0x4028 },
+	{ 0x4002c, 0x80 },
+	{ 0x4004c, 0x0 },
+	{ 0x4006c, 0x0 },
+	{ 0x4000d, 0xe08 },
+	{ 0x4002d, 0xc1a },
+	{ 0x4004d, 0x0 },
+	{ 0x4006d, 0x0 },
+	{ 0x4000e, 0x625 },
+	{ 0x4002e, 0x1a },
+	{ 0x4004e, 0x0 },
+	{ 0x4006e, 0x0 },
+	{ 0x4000f, 0x4040 },
+	{ 0x4002f, 0x80 },
+	{ 0x4004f, 0x0 },
+	{ 0x4006f, 0x0 },
+	{ 0x40010, 0x2604 },
+	{ 0x40030, 0x15 },
+	{ 0x40050, 0x0 },
+	{ 0x40070, 0x0 },
+	{ 0x40011, 0x708 },
+	{ 0x40031, 0x5 },
+	{ 0x40051, 0x0 },
+	{ 0x40071, 0x2002 },
+	{ 0x40012, 0x8 },
+	{ 0x40032, 0x80 },
+	{ 0x40052, 0x0 },
+	{ 0x40072, 0x0 },
+	{ 0x40013, 0x2604 },
+	{ 0x40033, 0x1a },
+	{ 0x40053, 0x0 },
+	{ 0x40073, 0x0 },
+	{ 0x40014, 0x708 },
+	{ 0x40034, 0xa },
+	{ 0x40054, 0x0 },
+	{ 0x40074, 0x2002 },
+	{ 0x40015, 0x4040 },
+	{ 0x40035, 0x80 },
+	{ 0x40055, 0x0 },
+	{ 0x40075, 0x0 },
+	{ 0x40016, 0x60a },
+	{ 0x40036, 0x15 },
+	{ 0x40056, 0x1200 },
+	{ 0x40076, 0x0 },
+	{ 0x40017, 0x61a },
+	{ 0x40037, 0x15 },
+	{ 0x40057, 0x1300 },
+	{ 0x40077, 0x0 },
+	{ 0x40018, 0x60a },
+	{ 0x40038, 0x1a },
+	{ 0x40058, 0x1200 },
+	{ 0x40078, 0x0 },
+	{ 0x40019, 0x642 },
+	{ 0x40039, 0x1a },
+	{ 0x40059, 0x1300 },
+	{ 0x40079, 0x0 },
+	{ 0x4001a, 0x4808 },
+	{ 0x4003a, 0x880 },
+	{ 0x4005a, 0x0 },
+	{ 0x4007a, 0x0 },
+	{ 0x900aa, 0x0 },
+	{ 0x900ab, 0x790 },
+	{ 0x900ac, 0x11a },
+	{ 0x900ad, 0x8 },
+	{ 0x900ae, 0x7aa },
+	{ 0x900af, 0x2a },
+	{ 0x900b0, 0x10 },
+	{ 0x900b1, 0x7b2 },
+	{ 0x900b2, 0x2a },
+	{ 0x900b3, 0x0 },
+	{ 0x900b4, 0x7c8 },
+	{ 0x900b5, 0x109 },
+	{ 0x900b6, 0x10 },
+	{ 0x900b7, 0x10 },
+	{ 0x900b8, 0x109 },
+	{ 0x900b9, 0x10 },
+	{ 0x900ba, 0x2a8 },
+	{ 0x900bb, 0x129 },
+	{ 0x900bc, 0x8 },
+	{ 0x900bd, 0x370 },
+	{ 0x900be, 0x129 },
+	{ 0x900bf, 0xa },
+	{ 0x900c0, 0x3c8 },
+	{ 0x900c1, 0x1a9 },
+	{ 0x900c2, 0xc },
+	{ 0x900c3, 0x408 },
+	{ 0x900c4, 0x199 },
+	{ 0x900c5, 0x14 },
+	{ 0x900c6, 0x790 },
+	{ 0x900c7, 0x11a },
+	{ 0x900c8, 0x8 },
+	{ 0x900c9, 0x4 },
+	{ 0x900ca, 0x18 },
+	{ 0x900cb, 0xe },
+	{ 0x900cc, 0x408 },
+	{ 0x900cd, 0x199 },
+	{ 0x900ce, 0x8 },
+	{ 0x900cf, 0x8568 },
+	{ 0x900d0, 0x108 },
+	{ 0x900d1, 0x18 },
+	{ 0x900d2, 0x790 },
+	{ 0x900d3, 0x16a },
+	{ 0x900d4, 0x8 },
+	{ 0x900d5, 0x1d8 },
+	{ 0x900d6, 0x169 },
+	{ 0x900d7, 0x10 },
+	{ 0x900d8, 0x8558 },
+	{ 0x900d9, 0x168 },
+	{ 0x900da, 0x1ff8 },
+	{ 0x900db, 0x85a8 },
+	{ 0x900dc, 0x1e8 },
+	{ 0x900dd, 0x50 },
+	{ 0x900de, 0x798 },
+	{ 0x900df, 0x16a },
+	{ 0x900e0, 0x60 },
+	{ 0x900e1, 0x7a0 },
+	{ 0x900e2, 0x16a },
+	{ 0x900e3, 0x8 },
+	{ 0x900e4, 0x8310 },
+	{ 0x900e5, 0x168 },
+	{ 0x900e6, 0x8 },
+	{ 0x900e7, 0xa310 },
+	{ 0x900e8, 0x168 },
+	{ 0x900e9, 0xa },
+	{ 0x900ea, 0x408 },
+	{ 0x900eb, 0x169 },
+	{ 0x900ec, 0x6e },
+	{ 0x900ed, 0x0 },
+	{ 0x900ee, 0x68 },
+	{ 0x900ef, 0x0 },
+	{ 0x900f0, 0x408 },
+	{ 0x900f1, 0x169 },
+	{ 0x900f2, 0x0 },
+	{ 0x900f3, 0x8310 },
+	{ 0x900f4, 0x168 },
+	{ 0x900f5, 0x0 },
+	{ 0x900f6, 0xa310 },
+	{ 0x900f7, 0x168 },
+	{ 0x900f8, 0x1ff8 },
+	{ 0x900f9, 0x85a8 },
+	{ 0x900fa, 0x1e8 },
+	{ 0x900fb, 0x68 },
+	{ 0x900fc, 0x798 },
+	{ 0x900fd, 0x16a },
+	{ 0x900fe, 0x78 },
+	{ 0x900ff, 0x7a0 },
+	{ 0x90100, 0x16a },
+	{ 0x90101, 0x68 },
+	{ 0x90102, 0x790 },
+	{ 0x90103, 0x16a },
+	{ 0x90104, 0x8 },
+	{ 0x90105, 0x8b10 },
+	{ 0x90106, 0x168 },
+	{ 0x90107, 0x8 },
+	{ 0x90108, 0xab10 },
+	{ 0x90109, 0x168 },
+	{ 0x9010a, 0xa },
+	{ 0x9010b, 0x408 },
+	{ 0x9010c, 0x169 },
+	{ 0x9010d, 0x58 },
+	{ 0x9010e, 0x0 },
+	{ 0x9010f, 0x68 },
+	{ 0x90110, 0x0 },
+	{ 0x90111, 0x408 },
+	{ 0x90112, 0x169 },
+	{ 0x90113, 0x0 },
+	{ 0x90114, 0x8b10 },
+	{ 0x90115, 0x168 },
+	{ 0x90116, 0x1 },
+	{ 0x90117, 0xab10 },
+	{ 0x90118, 0x168 },
+	{ 0x90119, 0x0 },
+	{ 0x9011a, 0x1d8 },
+	{ 0x9011b, 0x169 },
+	{ 0x9011c, 0x80 },
+	{ 0x9011d, 0x790 },
+	{ 0x9011e, 0x16a },
+	{ 0x9011f, 0x18 },
+	{ 0x90120, 0x7aa },
+	{ 0x90121, 0x6a },
+	{ 0x90122, 0xa },
+	{ 0x90123, 0x0 },
+	{ 0x90124, 0x1e9 },
+	{ 0x90125, 0x8 },
+	{ 0x90126, 0x8080 },
+	{ 0x90127, 0x108 },
+	{ 0x90128, 0xf },
+	{ 0x90129, 0x408 },
+	{ 0x9012a, 0x169 },
+	{ 0x9012b, 0xc },
+	{ 0x9012c, 0x0 },
+	{ 0x9012d, 0x68 },
+	{ 0x9012e, 0x9 },
+	{ 0x9012f, 0x0 },
+	{ 0x90130, 0x1a9 },
+	{ 0x90131, 0x0 },
+	{ 0x90132, 0x408 },
+	{ 0x90133, 0x169 },
+	{ 0x90134, 0x0 },
+	{ 0x90135, 0x8080 },
+	{ 0x90136, 0x108 },
+	{ 0x90137, 0x8 },
+	{ 0x90138, 0x7aa },
+	{ 0x90139, 0x6a },
+	{ 0x9013a, 0x0 },
+	{ 0x9013b, 0x8568 },
+	{ 0x9013c, 0x108 },
+	{ 0x9013d, 0xb7 },
+	{ 0x9013e, 0x790 },
+	{ 0x9013f, 0x16a },
+	{ 0x90140, 0x1f },
+	{ 0x90141, 0x0 },
+	{ 0x90142, 0x68 },
+	{ 0x90143, 0x8 },
+	{ 0x90144, 0x8558 },
+	{ 0x90145, 0x168 },
+	{ 0x90146, 0xf },
+	{ 0x90147, 0x408 },
+	{ 0x90148, 0x169 },
+	{ 0x90149, 0xd },
+	{ 0x9014a, 0x0 },
+	{ 0x9014b, 0x68 },
+	{ 0x9014c, 0x0 },
+	{ 0x9014d, 0x408 },
+	{ 0x9014e, 0x169 },
+	{ 0x9014f, 0x0 },
+	{ 0x90150, 0x8558 },
+	{ 0x90151, 0x168 },
+	{ 0x90152, 0x8 },
+	{ 0x90153, 0x3c8 },
+	{ 0x90154, 0x1a9 },
+	{ 0x90155, 0x3 },
+	{ 0x90156, 0x370 },
+	{ 0x90157, 0x129 },
+	{ 0x90158, 0x20 },
+	{ 0x90159, 0x2aa },
+	{ 0x9015a, 0x9 },
+	{ 0x9015b, 0x8 },
+	{ 0x9015c, 0xe8 },
+	{ 0x9015d, 0x109 },
+	{ 0x9015e, 0x0 },
+	{ 0x9015f, 0x8140 },
+	{ 0x90160, 0x10c },
+	{ 0x90161, 0x10 },
+	{ 0x90162, 0x8138 },
+	{ 0x90163, 0x104 },
+	{ 0x90164, 0x8 },
+	{ 0x90165, 0x448 },
+	{ 0x90166, 0x109 },
+	{ 0x90167, 0xf },
+	{ 0x90168, 0x7c0 },
+	{ 0x90169, 0x109 },
+	{ 0x9016a, 0x0 },
+	{ 0x9016b, 0xe8 },
+	{ 0x9016c, 0x109 },
+	{ 0x9016d, 0x47 },
+	{ 0x9016e, 0x630 },
+	{ 0x9016f, 0x109 },
+	{ 0x90170, 0x8 },
+	{ 0x90171, 0x618 },
+	{ 0x90172, 0x109 },
+	{ 0x90173, 0x8 },
+	{ 0x90174, 0xe0 },
+	{ 0x90175, 0x109 },
+	{ 0x90176, 0x0 },
+	{ 0x90177, 0x7c8 },
+	{ 0x90178, 0x109 },
+	{ 0x90179, 0x8 },
+	{ 0x9017a, 0x8140 },
+	{ 0x9017b, 0x10c },
+	{ 0x9017c, 0x0 },
+	{ 0x9017d, 0x478 },
+	{ 0x9017e, 0x109 },
+	{ 0x9017f, 0x0 },
+	{ 0x90180, 0x1 },
+	{ 0x90181, 0x8 },
+	{ 0x90182, 0x8 },
+	{ 0x90183, 0x4 },
+	{ 0x90184, 0x0 },
+	{ 0x90006, 0x8 },
+	{ 0x90007, 0x7c8 },
+	{ 0x90008, 0x109 },
+	{ 0x90009, 0x0 },
+	{ 0x9000a, 0x400 },
+	{ 0x9000b, 0x106 },
+	{ 0xd00e7, 0x400 },
+	{ 0x90017, 0x0 },
+	{ 0x9001f, 0x2b },
+	{ 0x90026, 0x69 },
+	{ 0x400d0, 0x0 },
+	{ 0x400d1, 0x101 },
+	{ 0x400d2, 0x105 },
+	{ 0x400d3, 0x107 },
+	{ 0x400d4, 0x10f },
+	{ 0x400d5, 0x202 },
+	{ 0x400d6, 0x20a },
+	{ 0x400d7, 0x20b },
+	{ 0x2003a, 0x2 },
+	{ 0x200be, 0x3 },
+	{ 0x2000b, 0x75 },
+	{ 0x2000c, 0xe9 },
+	{ 0x2000d, 0x91c },
+	{ 0x2000e, 0x2c },
+	{ 0x9000c, 0x0 },
+	{ 0x9000d, 0x173 },
+	{ 0x9000e, 0x60 },
+	{ 0x9000f, 0x6110 },
+	{ 0x90010, 0x2152 },
+	{ 0x90011, 0xdfbd },
+	{ 0x90012, 0x2060 },
+	{ 0x90013, 0x6152 },
+	{ 0x20010, 0x5a },
+	{ 0x20011, 0x3 },
+	{ 0x40080, 0xe0 },
+	{ 0x40081, 0x12 },
+	{ 0x40082, 0xe0 },
+	{ 0x40083, 0x12 },
+	{ 0x40084, 0xe0 },
+	{ 0x40085, 0x12 },
+	{ 0x400fd, 0xf },
+	{ 0x400f1, 0xe },
+	{ 0x10011, 0x1 },
+	{ 0x10012, 0x1 },
+	{ 0x10013, 0x180 },
+	{ 0x10018, 0x1 },
+	{ 0x10002, 0x6209 },
+	{ 0x100b2, 0x1 },
+	{ 0x101b4, 0x1 },
+	{ 0x102b4, 0x1 },
+	{ 0x103b4, 0x1 },
+	{ 0x104b4, 0x1 },
+	{ 0x105b4, 0x1 },
+	{ 0x106b4, 0x1 },
+	{ 0x107b4, 0x1 },
+	{ 0x108b4, 0x1 },
+	{ 0x11011, 0x1 },
+	{ 0x11012, 0x1 },
+	{ 0x11013, 0x180 },
+	{ 0x11018, 0x1 },
+	{ 0x11002, 0x6209 },
+	{ 0x110b2, 0x1 },
+	{ 0x111b4, 0x1 },
+	{ 0x112b4, 0x1 },
+	{ 0x113b4, 0x1 },
+	{ 0x114b4, 0x1 },
+	{ 0x115b4, 0x1 },
+	{ 0x116b4, 0x1 },
+	{ 0x117b4, 0x1 },
+	{ 0x118b4, 0x1 },
+	{ 0x20089, 0x1 },
+	{ 0x20088, 0x19 },
+	{ 0xc0080, 0x0 },
+	{ 0xd0000, 0x1 },
+};
+
+static struct dram_fsp_msg ddr_dram_fsp_msg[] = {
+	{
+		/* P0 3733mts 1D */
+		.drate = 3733,
+		.fw_type = FW_1D_IMAGE,
+		.fsp_cfg = ddr_fsp0_cfg,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_cfg),
+	},
+	{
+		/* P0 3733mts 2D */
+		.drate = 3733,
+		.fw_type = FW_2D_IMAGE,
+		.fsp_cfg = ddr_fsp0_2d_cfg,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_2d_cfg),
+	},
+};
+
+/* ddr timing config params */
+struct dram_timing_info tqma93xxca_dram_timing = {
+	.ddrc_cfg = ddr_ddrc_cfg,
+	.ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg),
+	.ddrphy_cfg = ddr_ddrphy_cfg,
+	.ddrphy_cfg_num = ARRAY_SIZE(ddr_ddrphy_cfg),
+	.fsp_msg = ddr_dram_fsp_msg,
+	.fsp_msg_num = ARRAY_SIZE(ddr_dram_fsp_msg),
+	.ddrphy_trained_csr = ddr_ddrphy_trained_csr,
+	.ddrphy_trained_csr_num = ARRAY_SIZE(ddr_ddrphy_trained_csr),
+	.ddrphy_pie = ddr_phy_pie,
+	.ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie),
+	.fsp_table = { 3733, },
+};
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index e9512a30c8..2e02baf8dc 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -217,5 +217,6 @@ lwl-$(CONFIG_MACH_LS1021AIOT) += fsl-ls1021a-iot.dtb.o
 lwl-$(CONFIG_MACH_ZEDBOARD) += zynq-zed.dtb.o
 lwl-$(CONFIG_MACH_MNT_REFORM) += imx8mq-mnt-reform2.dtb.o
 lwl-$(CONFIG_MACH_VARISCITE_DT8MCUSTOMBOARD_IMX8MP) += imx8mp-var-dart-dt8mcustomboard.dtb.o
+lwl-$(CONFIG_MACH_TQ_MBA9XXXCA) += imx93-tqma9352-mba93xxca.dtb.o
 
 clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtb.z
diff --git a/arch/arm/dts/imx93-tqma9352-mba93xxca.dts b/arch/arm/dts/imx93-tqma9352-mba93xxca.dts
new file mode 100644
index 0000000000..1de05d0573
--- /dev/null
+++ b/arch/arm/dts/imx93-tqma9352-mba93xxca.dts
@@ -0,0 +1,826 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2022-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Markus Niebel
+ * Author: Alexander Stein
+ */
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/pwm/pwm.h>
+
+#include <arm64/freescale/imx93-tqma9352.dtsi>
+#include "imx93.dtsi"
+
+/{
+	model = "TQ-Systems i.MX93 TQMa93xxLA/TQMa93xxCA on MBa93xxCA starter kit";
+	compatible = "tq,imx93-tqma9352-mba93xxca",
+		     "tq,imx93-tqma9352", "fsl,imx93";
+	chassis-type = "embedded";
+
+	chosen {
+		stdout-path = &lpuart1;
+		environment-spi-nor {
+			compatible = "barebox,environment";
+			device-path = &environment_spi_nor;
+		};
+	};
+
+	aliases {
+		eeprom0 = &eeprom0;
+		rtc0 = &pcf85063;
+		rtc1 = &bbnsm_rtc;
+	};
+
+	backlight_lvds: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&tpm5 0 5000000 0>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <7>;
+		power-supply = <&reg_12v0>;
+		enable-gpios = <&expander2 2 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+
+	fan0: pwm-fan {
+		compatible = "pwm-fan";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pwmfan>;
+		fan-supply = <&reg_pwm_fan>;
+		#cooling-cells = <2>;
+		/* typical 25 kHz -> 40.000 nsec */
+		pwms = <&tpm6 0 40000 PWM_POLARITY_INVERTED>;
+		cooling-levels = <0 32 64 128 196 240>;
+		pulses-per-revolution = <2>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+		status = "disabled";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		autorepeat;
+
+		switch-a {
+			label = "switcha";
+			linux,code = <BTN_0>;
+			gpios = <&expander0 6 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+
+		switch-b {
+			label = "switchb";
+			linux,code = <BTN_1>;
+			gpios = <&expander0 7 GPIO_ACTIVE_LOW>;
+			wakeup-source;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led-1 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&expander2 6 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		led-2 {
+			color = <LED_COLOR_ID_AMBER>;
+			gpios = <&expander2 7 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>;
+	};
+
+	reg_3v3: regulator-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_3V3_MB";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_5v0: regulator-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_5V0_MB";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_12v0: regulator-12v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_12V";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		gpio = <&expander1 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_mpcie_1v5: regulator-mpcie-1v5 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_1V5_MPCIE";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		gpio = <&expander0 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_mpcie_3v3: regulator-mpcie-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "V_3V3_MPCIE";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&expander0 3 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_pwm_fan: regulator-pwm-fan {
+		compatible = "regulator-fixed";
+		regulator-name = "FAN_PWR";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		gpio = <&expander0 0 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		vin-supply = <&reg_12v0>;
+	};
+
+	thermal-zones {
+		cpu-thermal {
+			trips {
+				cpu_active0: trip-active0 {
+					temperature = <40000>;
+					hysteresis = <5000>;
+					type = "active";
+				};
+
+				cpu_active1: trip-active1 {
+					temperature = <48000>;
+					hysteresis = <3000>;
+					type = "active";
+				};
+
+				cpu_active2: trip-active2 {
+					temperature = <60000>;
+					hysteresis = <10000>;
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map1 {
+					trip = <&cpu_active0>;
+					cooling-device = <&fan0 1 1>;
+				};
+
+				map2 {
+					trip = <&cpu_active1>;
+					cooling-device = <&fan0 2 2>;
+				};
+
+				map3 {
+					trip = <&cpu_active2>;
+					cooling-device = <&fan0 3 3>;
+				};
+			};
+		};
+	};
+};
+
+&adc1 {
+	status = "okay";
+};
+
+&eqos {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_eqos>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy_eqos>;
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy_eqos: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_eqos_phy>;
+			reset-gpios = <&expander1 0 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <500000>;
+			reset-deassert-us = <50000>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+			enet-phy-lane-no-swap;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,dp83867-rxctrl-strap-quirk;
+			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy_fec>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <5000000>;
+
+		ethphy_fec: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_fec_phy>;
+			reset-gpios = <&expander1 1 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <500000>;
+			reset-deassert-us = <50000>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
+			enet-phy-lane-no-swap;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,dp83867-rxctrl-strap-quirk;
+			ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+		};
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	xceiver-supply = <&reg_3v3>;
+	status = "okay";
+};
+
+&flexcan2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	xceiver-supply = <&reg_3v3>;
+	status = "okay";
+};
+
+&gpio1 {
+	expander-irq-hog {
+		gpio-hog;
+		gpios = <12 GPIO_ACTIVE_LOW>;
+		input;
+		line-name = "PEX_INT#";
+	};
+
+	tcpc-irq-hog {
+		gpio-hog;
+		gpios = <2 GPIO_ACTIVE_LOW>;
+		input;
+		line-name = "USB_C_ALERT#";
+	};
+};
+
+&lpi2c1 {
+	pca9451a: pmic@25 {
+		compatible = "nxp,pca9451a";
+		reg = <0x25>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pca9451>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+		pca9451a_regulators: regulators {
+			/* V_0V8_SOC - hw developer guide: 0.75 .. 0.9 */
+			buck1: BUCK1 {
+				regulator-name = "BUCK1";
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			/* V_DDRQ - 1.1 LPDDR4 or 0.6 LPDDR4X */
+			buck2: BUCK2 {
+				regulator-name = "BUCK2";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <600000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			/* V_3V3 - EEPROM, RTC, ... */
+			buck4: BUCK4{
+				regulator-name = "BUCK4";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* V_1V8 - SPI NOR, eMMC, RAM VDD1... */
+			buck5: BUCK5{
+				regulator-name = "BUCK5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* V_1V1 - RAM VDD2*/
+			buck6: BUCK6 {
+				regulator-name = "BUCK6";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* V_1V8_BBSM, fix 1.8 */
+			ldo1: LDO1 {
+				regulator-name = "LDO1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* V_0V8_ANA */
+			ldo4: LDO4 {
+				regulator-name = "LDO4";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* V_SD2 - 3.3/1.8V USDHC2 io Voltage */
+			ldo5: LDO5 {
+				regulator-name = "LDO5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&lpi2c3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c3>;
+	pinctrl-1 = <&pinctrl_lpi2c3>;
+	status = "okay";
+
+	temperature-sensor@1c {
+		compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+		reg = <0x1c>;
+	};
+
+	eeprom2: eeprom@54 {
+		compatible = "nxp,se97b", "atmel,24c02";
+		reg = <0x54>;
+		pagesize = <16>;
+		vcc-supply = <&reg_3v3>;
+	};
+
+	expander0: gpio@70 {
+		compatible = "nxp,pca9538";
+		reg = <0x70>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pexp_irq>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+		vcc-supply = <&reg_3v3>;
+		gpio-line-names = "FAN_PWR_EN", "MPCIE_WAKE#",
+				  "MPCIE_1V5_EN", "MPCIE_3V3_EN",
+				  "MPCIE_PERST#", "MPCIE_WDISABLE#",
+				  "BUTTON_A#", "BUTTON_B#";
+
+		mpcie-wake-hog {
+			gpio-hog;
+			gpios = <1 GPIO_ACTIVE_LOW>;
+			input;
+			line-name = "MPCIE_WAKE#";
+		};
+
+		/*
+		 * Controls the mPCIE slot reset which is low active as
+		 * reset signal. The output-low states, the signal is
+		 * inactive, e.g. not in reset
+		 */
+		mpcie_rst_hog: mpcie-rst-hog {
+			gpio-hog;
+			gpios = <4 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "MPCIE_PERST#";
+		};
+
+		/*
+		 * Controls the mPCIE slot WDISABLE pin which is low active
+		 * as disable signal. The output-low states, the signal is
+		 * inactive, e.g. not disabled
+		 */
+		mpcie_wdisable_hog: mpcie-wdisable-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "MPCIE_WDISABLE#";
+		};
+	};
+
+	expander1: gpio@71 {
+		compatible = "nxp,pca9538";
+		reg = <0x71>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		vcc-supply = <&reg_3v3>;
+		gpio-line-names = "ENET1_RESET#", "ENET2_RESET#",
+				  "USB_RESET#", "",
+				  "WLAN_PD#", "WLAN_W_DISABLE#",
+				  "WLAN_PERST#", "12V_EN";
+
+		/*
+		 * Controls the on board USB Hub reset which is low
+		 * active as reset signal. The output-low states, the
+		 * signal is inactive, e.g. no reset
+		 */
+		usb-reset-hog {
+			gpio-hog;
+			gpios = <2 GPIO_ACTIVE_LOW>;
+			output-low;
+			line-name = "USB_RESET#";
+		};
+
+		/*
+		 * Controls the WiFi card PD pin which is low active
+		 * as power down signal. The output-high states, the signal
+		 * is active, e.g. card is powered down
+		 */
+		wlan-pd-hog {
+			gpio-hog;
+			gpios = <4 GPIO_ACTIVE_LOW>;
+			output-high;
+			line-name = "WLAN_PD#";
+		};
+
+		/*
+		 * Controls the WiFi card disable pin which is low active
+		 * as disable signal. The output-high states, the signal
+		 * is active, e.g. card is disabled
+		 */
+		wlan-wdisable-hog {
+			gpio-hog;
+			gpios = <5 GPIO_ACTIVE_LOW>;
+			output-high;
+			line-name = "WLAN_W_DISABLE#";
+		};
+
+		/*
+		 * Controls the WiFi card reset pin which is low active
+		 * as reset signal. The output-high states, the signal
+		 * is active, e.g. card in reset
+		 */
+		wlan-perst-hog {
+			gpio-hog;
+			gpios = <6 GPIO_ACTIVE_LOW>;
+			output-high;
+			line-name = "WLAN_PERST#";
+		};
+	};
+
+	expander2: gpio@72 {
+		compatible = "nxp,pca9538";
+		reg = <0x72>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		vcc-supply = <&reg_3v3>;
+		gpio-line-names = "LCD_RESET#", "LCD_PWR_EN",
+				  "LCD_BLT_EN", "DP_EN",
+				  "MIPI_CSI_EN", "MIPI_CSI_RST#",
+				  "USER_LED1", "USER_LED2";
+	};
+};
+
+&lpi2c5 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_lpi2c5>;
+	pinctrl-1 = <&pinctrl_lpi2c5>;
+	status = "okay";
+};
+
+&lpspi6 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_lpspi6>;
+	pinctrl-1 = <&pinctrl_lpspi6>;
+	status = "okay";
+};
+
+&lpuart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&lpuart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	linux,rs485-enabled-at-boot-time;
+	status = "okay";
+};
+
+/* disabled per default, console for M33 */
+&lpuart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "disabled";
+};
+
+&lpuart6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart6>;
+	status = "okay";
+};
+
+&lpuart8 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart8>;
+	status = "okay";
+};
+
+&tpm5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_tpm5>;
+};
+
+&tpm6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_tpm6>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2_hs>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	no-sdio;
+	no-mmc;
+	disable-wp;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			/* PD | FSEL_2 | DSE X4 */
+			MX93_PAD_ENET1_MDC__ENET_QOS_MDC		0x51e
+			MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO		0x4000051e
+			/* PD | FSEL_2 | DSE X6 */
+			MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0		0x57e
+			MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1		0x57e
+			MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2		0x57e
+			MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3		0x57e
+			/* PD | FSEL_3 | DSE X6 */
+			MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x5fe
+			MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL	0x57e
+			/* PD | FSEL_2 | DSE X4 */
+			MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0		0x51e
+			MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1		0x51e
+			MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2		0x51e
+			MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3		0x51e
+			MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL	0x51e
+			/* PD | FSEL_3 | DSE X3 */
+			MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x58e
+		>;
+	};
+
+	pinctrl_eqos_phy: eqosphygrp {
+		fsl,pins = <
+			MX93_PAD_CCM_CLKO1__GPIO3_IO26		0x1306
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			/* PD | FSEL_2 | DSE X4 */
+			MX93_PAD_ENET2_MDC__ENET1_MDC			0x51e
+			MX93_PAD_ENET2_MDIO__ENET1_MDIO			0x4000051e
+			/* PD | FSEL_2 | DSE X6 */
+			MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0		0x57e
+			MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1		0x57e
+			MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2		0x57e
+			MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3		0x57e
+			/* PD | FSEL_3 | DSE X6 */
+			MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC		0x5fe
+			MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL	0x57e
+			/* PD | FSEL_2 | DSE X4 */
+			MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0		0x51e
+			MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1		0x51e
+			MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2		0x51e
+			MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3		0x51e
+			MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL	0x51e
+			/* PD | FSEL_3 | DSE X3 */
+			MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC		0x58e
+		>;
+	};
+
+	pinctrl_fec_phy: fecphygrp {
+		fsl,pins = <
+			MX93_PAD_CCM_CLKO2__GPIO3_IO27		0x1306
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX93_PAD_PDM_BIT_STREAM0__CAN1_RX	0x139e
+			MX93_PAD_PDM_CLK__CAN1_TX		0x139e
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO25__CAN2_TX		0x139e
+			MX93_PAD_GPIO_IO27__CAN2_RX		0x139e
+		>;
+	};
+
+	pinctrl_lpi2c3: lpi2c3grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO28__LPI2C3_SDA		0x40000b9e
+			MX93_PAD_GPIO_IO29__LPI2C3_SCL		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpi2c5: lpi2c5grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO22__LPI2C5_SDA		0x40000b9e
+			MX93_PAD_GPIO_IO23__LPI2C5_SCL		0x40000b9e
+		>;
+	};
+
+	pinctrl_lpspi6: lpspi6grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO00__LPSPI6_PCS0		0x3fe
+			MX93_PAD_GPIO_IO01__LPSPI6_SIN		0x3fe
+			MX93_PAD_GPIO_IO02__LPSPI6_SOUT		0x3fe
+			MX93_PAD_GPIO_IO03__LPSPI6_SCK		0x3fe
+		>;
+	};
+
+	pinctrl_pexp_irq: pexpirqgrp {
+		fsl,pins = <
+			MX93_PAD_SAI1_TXC__GPIO1_IO12		0x1306
+		>;
+	};
+
+	pinctrl_pwmfan: pwmfangrp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO09__GPIO2_IO09		0x1306
+		>;
+	};
+
+	pinctrl_tpm5: tpm5grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO06__TPM5_CH0		0x57e
+		>;
+	};
+
+	pinctrl_tpm6: tpm6grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO08__TPM6_CH0		0x57e
+		>;
+	};
+
+	pinctrl_typec: typecgrp {
+		fsl,pins = <
+			MX93_PAD_I2C2_SCL__GPIO1_IO02		0x1306
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX93_PAD_UART1_RXD__LPUART1_RX		0x31e
+			MX93_PAD_UART1_TXD__LPUART1_TX		0x31e
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX93_PAD_UART2_TXD__LPUART2_TX		0x31e
+			MX93_PAD_UART2_RXD__LPUART2_RX		0x31e
+			MX93_PAD_SAI1_TXD0__LPUART2_RTS_B   0x51e
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO14__LPUART3_TX		0x31e
+			MX93_PAD_GPIO_IO15__LPUART3_RX		0x31e
+		>;
+	};
+
+	pinctrl_uart6: uart6grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO04__LPUART6_TX		0x31e
+			MX93_PAD_GPIO_IO05__LPUART6_RX		0x31e
+		>;
+	};
+
+	pinctrl_uart8: uart8grp {
+		fsl,pins = <
+			MX93_PAD_GPIO_IO12__LPUART8_TX		0x31e
+			MX93_PAD_GPIO_IO13__LPUART8_RX		0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX93_PAD_SD2_CD_B__GPIO3_IO00		0x31e
+		>;
+	};
+
+	pinctrl_usdhc2_hs: usdhc2hsgrp {
+		fsl,pins = <
+			/* HYS | PD | PU | FSEL_3 | DSE X5 */
+			MX93_PAD_SD2_CLK__USDHC2_CLK		0x17be
+			/* HYS | PD | PU | FSEL_3 | DSE X4 */
+			MX93_PAD_SD2_CMD__USDHC2_CMD		0x139e
+			/* HYS | PD | PU | FSEL_3 | DSE X3 */
+			MX93_PAD_SD2_DATA0__USDHC2_DATA0	0x138e
+			MX93_PAD_SD2_DATA1__USDHC2_DATA1	0x138e
+			MX93_PAD_SD2_DATA2__USDHC2_DATA2	0x138e
+			MX93_PAD_SD2_DATA3__USDHC2_DATA3	0x138e
+			/* PD | PU | FSEL_2 | DSE X3 */
+			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT	0x50e
+		>;
+	};
+
+	pinctrl_usdhc2_uhs: usdhc2uhsgrp {
+		fsl,pins = <
+			/* HYS | PD | PU | FSEL_3 | DSE X6 */
+			MX93_PAD_SD2_CLK__USDHC2_CLK		0x17fe
+			/* HYS | PD | PU | FSEL_3 | DSE X4 */
+			MX93_PAD_SD2_CMD__USDHC2_CMD		0x139e
+			MX93_PAD_SD2_DATA0__USDHC2_DATA0	0x139e
+			MX93_PAD_SD2_DATA1__USDHC2_DATA1	0x139e
+			MX93_PAD_SD2_DATA2__USDHC2_DATA2	0x139e
+			MX93_PAD_SD2_DATA3__USDHC2_DATA3	0x139e
+			/* PD | PU | FSEL_2 | DSE X3 */
+			MX93_PAD_SD2_VSELECT__USDHC2_VSELECT	0x50e
+		>;
+	};
+};
+
+&usbotg1 {
+	status = "okay";
+};
+
+&usbotg2 {
+	status = "okay";
+	dr_mode = "host";
+};
+
+&{flexspi1/flash@0} {
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "barebox";
+			reg = <0x0 0x400000>;
+		};
+
+		environment_spi_nor: partition@400000 {
+			label = "barebox-environment";
+			reg = <0x400000 0x100000>;
+		};
+	};
+};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 358d1ef362..fc1021c0ec 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -715,6 +715,15 @@ config MACH_ZII_IMX8MQ_DEV
 	select MCI_IMX_ESDHC_PBL
 	select MACH_ZII_COMMON
 
+comment "i.MX93 boards"
+
+config MACH_TQ_MBA9XXXCA
+	bool "TQ i.MX93 on MBa9xxxCA Board"
+	select ARCH_IMX93
+	select IMX9_DRAM
+	select FIRMWARE_IMX93_ATF
+	select FIRMWARE_IMX_LPDDR4_PMU_TRAIN
+
 endif
 
 endmenu
diff --git a/images/Makefile.imx b/images/Makefile.imx
index 8b6958872a..693f7ca12a 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -495,3 +495,14 @@ CFG_start_mnt_reform.pblb.imximg = $(board)/mnt-reform/flash-header-mnt-reform.i
 MAX_PBL_MEMORY_SIZE_start_mnt_reform = 0x3f000
 FILE_barebox-mnt-reform.img = start_mnt_reform.pblb.imximg
 image-$(CONFIG_MACH_MNT_REFORM) += barebox-mnt-reform.img
+
+quiet_cmd_imx9img = IMX9IMG  $@
+cmd_imx9img = $(objtree)/scripts/imx9image -soc IMX9 -c -ap $< a55 0x2049A000 -out $@ \
+		-pblsize $($(patsubst $(obj)/%.pblb,PBL_MEMORY_SIZE_%,$<)) > /dev/null
+
+$(obj)/%.imx9img: $(obj)/% FORCE
+	$(call if_changed,imx9img)
+
+pblb-$(CONFIG_MACH_TQ_MBA9XXXCA) += start_imx93_tqma9352_mba93xxca
+FILE_barebox-tqmba9xxxca.img = start_imx93_tqma9352_mba93xxca.pblb.imx9img
+image-$(CONFIG_MACH_TQ_MBA9XXXCA) += barebox-tqmba9xxxca.img
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 17/25] ARM: i.MX93: Add DDR size read support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (15 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 16/25] ARM: Add TQ MBA9XXXCA board support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 18/25] ARM: i.MX: romapi: rename functions to *romapi* Sascha Hauer
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/esdctl.c | 42 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-imx/esdctl.c
index 2fca0a44a1..ac35a2de66 100644
--- a/arch/arm/mach-imx/esdctl.c
+++ b/arch/arm/mach-imx/esdctl.c
@@ -28,6 +28,7 @@
 #include <mach/imx/vf610-ddrmc.h>
 #include <mach/imx/imx8m-regs.h>
 #include <mach/imx/imx7-regs.h>
+#include <mach/imx/imx9-regs.h>
 
 struct imx_esdctl_data {
 	unsigned long base0;
@@ -555,6 +556,39 @@ static int imx8mn_ddrc_add_mem(void *mmdcbase, struct imx_esdctl_data *data)
 	return _imx8m_ddrc_add_mem(mmdcbase, data, 16);
 }
 
+#define IMX9_DDRC_CS_CONFIG(n)	(0x80 + (n) * 4)
+#define IMX9_DDRC_CS_ROW_BITS	GENMASK(10, 8)
+#define IMX9_DDRC_CS_COL_BITS	GENMASK(2, 0)
+#define IMX9_DDRC_CS_EN		BIT(31)
+
+static int imx9_ddrc_add_mem(void *mmdcbase, struct imx_esdctl_data *data)
+{
+	int width = 2;
+	int banks = 8;
+	unsigned long mem = 0;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		int rows, cols;
+		u32 cs, col_bits;
+
+		cs = readl(mmdcbase + IMX9_DDRC_CS_CONFIG(i));
+		if (!(cs & IMX9_DDRC_CS_EN))
+			continue;
+
+		rows = FIELD_GET(IMX9_DDRC_CS_ROW_BITS, cs) + 12;
+		col_bits = FIELD_GET(IMX9_DDRC_CS_COL_BITS, cs);
+		if (col_bits == 7)
+			cols = 7;
+		else
+			cols = col_bits + 8;
+
+		mem += memory_sdram_size(cols, rows, banks, width);
+	}
+
+	return arm_add_mem_device("ram0", data->base0, mem);
+}
+
 static resource_size_t imx7d_ddrc_sdram_size(void __iomem *ddrc)
 {
 	const u32 addrmap[DDRC_ADDRMAP_LENGTH] = {
@@ -695,6 +729,11 @@ static __maybe_unused struct imx_esdctl_data imx8mn_data = {
 	.add_mem = imx8mn_ddrc_add_mem,
 };
 
+static __maybe_unused struct imx_esdctl_data imx9_data = {
+	.base0 = MX9_DDR_CSD1_BASE_ADDR,
+	.add_mem = imx9_ddrc_add_mem,
+};
+
 static __maybe_unused struct imx_esdctl_data imx7d_data = {
 	.base0 = MX7_DDR_BASE_ADDR,
 	.add_mem = imx7d_ddrc_add_mem,
@@ -770,6 +809,9 @@ static __maybe_unused struct of_device_id imx_esdctl_dt_ids[] = {
 	}, {
 		.compatible = "fsl,imx8mn-ddrc",
 		.data = &imx8mn_data
+	}, {
+		.compatible = "fsl,imx93-ddrc",
+		.data = &imx9_data
 	}, {
 		.compatible = "fsl,imx7d-ddrc",
 		.data = &imx7d_data
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 18/25] ARM: i.MX: romapi: rename functions to *romapi*
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (16 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 17/25] ARM: i.MX93: Add DDR size read support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 19/25] ARM: i.MX: romapi: Implement i.MX93 support Sascha Hauer
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The file the romapi is implemented in is named romapi and that's also
the name the i.MX ROM API is normally referred to, so rename the
functions accordingly.
While at it, rename some internal functions from imx8m_* to imx_* as
they can and will also be used by upcoming i.MX9 support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/atf.c    |  4 ++--
 arch/arm/mach-imx/romapi.c | 14 +++++++-------
 include/mach/imx/romapi.h  |  4 ++--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c
index d6d1aa3d68..1a0ac72fff 100644
--- a/arch/arm/mach-imx/atf.c
+++ b/arch/arm/mach-imx/atf.c
@@ -157,7 +157,7 @@ void imx8mp_load_bl33(void *bl33)
 		imx8mp_esdhc_load_image(instance, false);
 		break;
 	case BOOTSOURCE_SERIAL:
-		imx8mp_bootrom_load_image();
+		imx8mp_romapi_load_image();
 		break;
 	case BOOTSOURCE_SPI:
 		imx8mp_qspi_load_image(instance, false);
@@ -221,7 +221,7 @@ void imx8mn_load_bl33(void *bl33)
 		imx8mn_esdhc_load_image(instance, false);
 		break;
 	case BOOTSOURCE_SERIAL:
-		imx8mn_bootrom_load_image();
+		imx8mn_romapi_load_image();
 		break;
 	case BOOTSOURCE_SPI:
 		imx8mn_qspi_load_image(instance, false);
diff --git a/arch/arm/mach-imx/romapi.c b/arch/arm/mach-imx/romapi.c
index aef0ff0534..29c2d4005c 100644
--- a/arch/arm/mach-imx/romapi.c
+++ b/arch/arm/mach-imx/romapi.c
@@ -14,7 +14,7 @@
 #include <init.h>
 #include <pbl.h>
 
-static int imx8m_bootrom_load(struct rom_api *rom_api, void *adr, size_t size)
+static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size)
 {
 	while (size) {
 		size_t chunksize = min(size, (size_t)1024);
@@ -35,25 +35,25 @@ static int imx8m_bootrom_load(struct rom_api *rom_api, void *adr, size_t size)
 }
 
 /* read piggydata via a bootrom callback and place it behind our copy in SDRAM */
-static int imx8m_bootrom_load_image(struct rom_api *rom_api)
+static int imx_romapi_load_image(struct rom_api *rom_api)
 {
-	return imx8m_bootrom_load(rom_api,
+	return imx_romapi_load(rom_api,
 				  (void *)MX8M_ATF_BL33_BASE_ADDR + barebox_pbl_size,
 				  __image_end - __piggydata_start);
 }
 
-int imx8mp_bootrom_load_image(void)
+int imx8mp_romapi_load_image(void)
 {
 	struct rom_api *rom_api = (void *)0x980;
 
 	OPTIMIZER_HIDE_VAR(rom_api);
 
-	return imx8m_bootrom_load_image(rom_api);
+	return imx_romapi_load_image(rom_api);
 }
 
-int imx8mn_bootrom_load_image(void)
+int imx8mn_romapi_load_image(void)
 {
-	return imx8mp_bootrom_load_image();
+	return imx8mp_romapi_load_image();
 }
 
 const u32 *imx8m_get_bootrom_log(void)
diff --git a/include/mach/imx/romapi.h b/include/mach/imx/romapi.h
index 2243fdcf6d..8ea7fbfb04 100644
--- a/include/mach/imx/romapi.h
+++ b/include/mach/imx/romapi.h
@@ -35,8 +35,8 @@ enum boot_dev_type_e {
 
 #define ROM_API_OKAY		0xF0
 
-int imx8mp_bootrom_load_image(void);
-int imx8mn_bootrom_load_image(void);
+int imx8mp_romapi_load_image(void);
+int imx8mn_romapi_load_image(void);
 
 /* only call after DRAM has been configured */
 void imx8m_save_bootrom_log(void *dst);
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 19/25] ARM: i.MX: romapi: Implement i.MX93 support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (17 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 18/25] ARM: i.MX: romapi: rename functions to *romapi* Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 20/25] ARM: i.MX: atf: add imx93_load_and_start_image_via_tfa() Sascha Hauer
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

We used to use the ROM API for USB loading only, now with i.MX93 we
fully rely on the ROM API also with SD/eMMC and other boot sources.

The ROM provides us information about the boot source. There are
generally two types of boot sources: seekable for storage devices
like SD/eMMC and streamable for USB. the load_image call must be
handled slightly different for both types of boot sources, so
we fist detect which type we have and call the right load_image
function accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/romapi.c | 156 ++++++++++++++++++++++++++++++++++++-
 include/mach/imx/romapi.h  |   1 +
 2 files changed, 153 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-imx/romapi.c b/arch/arm/mach-imx/romapi.c
index 29c2d4005c..1b1800f1e0 100644
--- a/arch/arm/mach-imx/romapi.c
+++ b/arch/arm/mach-imx/romapi.c
@@ -3,6 +3,8 @@
 #define pr_fmt(fmt) "romapi: " fmt
 
 #include <common.h>
+#include <linux/bitfield.h>
+#include <soc/imx9/flash_header.h>
 #include <asm/sections.h>
 #include <mach/imx/romapi.h>
 #include <mach/imx/atf.h>
@@ -14,7 +16,39 @@
 #include <init.h>
 #include <pbl.h>
 
-static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size)
+#define BOOTROM_INFO_VERSION		0x1
+#define BOOTROM_INFO_BOOT_DEVICE	0x2
+#define BOOTROM_INFO_DEVICE_PAGE_SIZE	0x3
+#define BOOTROM_INFO_OFFSET_IVT		0x4
+#define BOOTROM_INFO_BOOT_STAGE		0x5
+#define BOOTROM_INFO_OFFSET_IMAGE	0x6
+
+#define BOOTROM_BOOT_DEVICE_INTERFACE	GENMASK(23, 16)
+#define BOOTROM_BOOT_DEVICE_SD			0x1
+#define BOOTROM_BOOT_DEVICE_EMMC		0x2
+#define BOOTROM_BOOT_DEVICE_FLEXSPI_NOR		0x4
+#define BOOTROM_BOOT_DEVICE_LPSPI		0x6
+#define BOOTROM_BOOT_DEVICE_FLEXSPI_NAND	0x8
+#define BOOTROM_BOOT_DEVICE_USB			0xe
+#define BOOTROM_BOOT_DEVICE_INSTANCE	GENMASK(15, 8)
+#define BOOTROM_BOOT_DEVICE_STATE	GENMASK(7, 0)
+
+static int imx_bootrom_query(struct rom_api *rom_api, uint32_t type, uint32_t *__info)
+{
+	static uint32_t info;
+	uint32_t xor = type ^ (uintptr_t)&info;
+	int ret;
+
+	ret = rom_api->query_boot_infor(type, &info, xor);
+	if (ret != ROM_API_OKAY)
+		return -EIO;
+
+	*__info = info;
+
+	return 0;
+}
+
+static int imx_romapi_load_stream(struct rom_api *rom_api, void *adr, size_t size)
 {
 	while (size) {
 		size_t chunksize = min(size, (size_t)1024);
@@ -30,6 +64,22 @@ static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size)
 		adr += chunksize;
 		size -= chunksize;
 	}
+	return 0;
+}
+
+static int imx_romapi_load_seekable(struct rom_api *rom_api, void *adr, uint32_t offset,
+				       size_t size)
+{
+	int ret;
+
+	size = PAGE_ALIGN(size);
+
+	ret = rom_api->download_image(adr, offset, size,
+				      (uintptr_t)adr ^ offset ^ size);
+	if (ret != ROM_API_OKAY) {
+		pr_err("Failed to load piggy data (ret = %x)\n", ret);
+		return -EIO;
+	}
 
 	return 0;
 }
@@ -37,9 +87,9 @@ static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size)
 /* read piggydata via a bootrom callback and place it behind our copy in SDRAM */
 static int imx_romapi_load_image(struct rom_api *rom_api)
 {
-	return imx_romapi_load(rom_api,
-				  (void *)MX8M_ATF_BL33_BASE_ADDR + barebox_pbl_size,
-				  __image_end - __piggydata_start);
+	return imx_romapi_load_stream(rom_api,
+			(void *)MX8M_ATF_BL33_BASE_ADDR,
+			__image_end - __piggydata_start);
 }
 
 int imx8mp_romapi_load_image(void)
@@ -56,6 +106,104 @@ int imx8mn_romapi_load_image(void)
 	return imx8mp_romapi_load_image();
 }
 
+static int imx_romapi_boot_device_seekable(struct rom_api *rom_api)
+{
+	uint32_t boot_device, boot_device_type, boot_device_state;
+	int ret;
+	bool seekable;
+
+	ret = imx_bootrom_query(rom_api, BOOTROM_INFO_BOOT_DEVICE, &boot_device);
+	if (ret)
+		return ret;
+
+	boot_device_type = FIELD_GET(BOOTROM_BOOT_DEVICE_INTERFACE, boot_device);
+
+	switch (boot_device_type) {
+	case BOOTROM_BOOT_DEVICE_SD:
+	case BOOTROM_BOOT_DEVICE_FLEXSPI_NOR:
+	case BOOTROM_BOOT_DEVICE_LPSPI:
+	case BOOTROM_BOOT_DEVICE_FLEXSPI_NAND:
+		seekable = true;
+		break;
+	case BOOTROM_BOOT_DEVICE_USB:
+		seekable = false;
+		break;
+	case BOOTROM_BOOT_DEVICE_EMMC:
+		boot_device_state = FIELD_GET(BOOTROM_BOOT_DEVICE_STATE, boot_device);
+		if (boot_device_state & BIT(0))
+			seekable = false;
+		else
+			seekable = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return seekable;
+}
+
+int imx93_romapi_load_image(void)
+{
+	struct rom_api *rom_api = (void *)0x1980;
+	int ret;
+	int seekable;
+	uint32_t offset, image_offset;
+	void *bl33 = (void *)MX93_ATF_BL33_BASE_ADDR;
+	struct flash_header_v3 *fh;
+
+	OPTIMIZER_HIDE_VAR(rom_api);
+
+	seekable = imx_romapi_boot_device_seekable(rom_api);
+	if (seekable < 0)
+		return seekable;
+
+	if (!seekable) {
+		int align_size = ALIGN(barebox_pbl_size, 1024) - barebox_pbl_size;
+		void *pbl_size_aligned = bl33 + ALIGN(barebox_pbl_size, 1024);
+
+		/*
+		 * The USB protocol uploads in chunks of 1024 bytes. This means
+		 * the initial piggy data up to the next 1KiB boundary is already
+		 * transferred. Align up the start address to this boundary.
+		 */
+
+		return imx_romapi_load_stream(rom_api,
+				pbl_size_aligned,
+				__image_end - __piggydata_start - align_size);
+	}
+
+	ret = imx_bootrom_query(rom_api, BOOTROM_INFO_OFFSET_IMAGE, &offset);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: IVT offset on boot device: 0x%08x\n", __func__, offset);
+
+	ret = imx_romapi_load_seekable(rom_api, bl33, offset, 4096);
+	if (ret)
+		return ret;
+
+	fh = bl33;
+
+	if (fh->tag != 0x87) {
+		pr_err("Invalid IVT header: 0x%02x, expected 0x87\n", fh->tag);
+		return -EINVAL;
+	}
+
+	image_offset = fh->img[0].offset;
+
+	pr_debug("%s: offset in image: 0x%08x\n", __func__, image_offset);
+
+	/*
+	 * We assume the first image in the first container is the barebox image,
+	 * which is what the imx9image call in images/Makefile.imx generates.
+	 */
+	ret = imx_romapi_load_seekable(rom_api, bl33, offset + image_offset, barebox_image_size);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
 const u32 *imx8m_get_bootrom_log(void)
 {
 	if (current_el() == 3) {
diff --git a/include/mach/imx/romapi.h b/include/mach/imx/romapi.h
index 8ea7fbfb04..959d165a33 100644
--- a/include/mach/imx/romapi.h
+++ b/include/mach/imx/romapi.h
@@ -37,6 +37,7 @@ enum boot_dev_type_e {
 
 int imx8mp_romapi_load_image(void);
 int imx8mn_romapi_load_image(void);
+int imx93_romapi_load_image(void);
 
 /* only call after DRAM has been configured */
 void imx8m_save_bootrom_log(void *dst);
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 20/25] ARM: i.MX: atf: add imx93_load_and_start_image_via_tfa()
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (18 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 19/25] ARM: i.MX: romapi: Implement i.MX93 support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 21/25] imx-usb-loader: Add i.MX9 support Sascha Hauer
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/atf.c  | 34 ++++++++++++++++++++++++++++++++++
 include/mach/imx/atf.h   |  2 ++
 include/mach/imx/xload.h |  1 +
 3 files changed, 37 insertions(+)

diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c
index 1a0ac72fff..e1a89ef543 100644
--- a/arch/arm/mach-imx/atf.c
+++ b/arch/arm/mach-imx/atf.c
@@ -329,3 +329,37 @@ __noreturn void imx8mq_load_and_start_image_via_tfa(void)
 
 	imx8m_atf_start_bl31(bl31, bl31_size, (void *)MX8MQ_ATF_BL31_BASE_ADDR);
 }
+
+void __noreturn imx93_load_and_start_image_via_tfa(void)
+{
+	unsigned long atf_dest = MX93_ATF_BL31_BASE_ADDR;
+	void __noreturn (*bl31)(void) = (void *)atf_dest;
+	const void *tfa;
+	size_t tfa_size;
+
+	/*
+	 * On completion the TF-A will jump to MX93_ATF_BL33_BASE_ADDR
+	 * in EL2. Copy the image there, but replace the PBL part of
+	 * that image with ourselves. On a high assurance boot only the
+	 * currently running code is validated and contains the checksum
+	 * for the piggy data, so we need to ensure that we are running
+	 * the same code in DRAM.
+	 *
+	 * The second purpose of this memcpy is for USB booting. When booting
+	 * from USB the image comes in as a stream, so the PBL is transferred
+	 * only once. As we jump into the PBL again in SDRAM we need to copy
+	 * it there. The USB protocol transfers data in chunks of 1024 bytes,
+	 * so align the copy size up to the next 1KiB boundary.
+	 */
+	memcpy((void *)MX93_ATF_BL33_BASE_ADDR, __image_start, ALIGN(barebox_pbl_size, 1024));
+
+	get_builtin_firmware(imx93_bl31_bin, &tfa, &tfa_size);
+
+	memcpy(bl31, tfa, tfa_size);
+
+	asm volatile("msr sp_el2, %0" : :
+		     "r" (MX93_ATF_BL33_BASE_ADDR - 16) :
+		     "cc");
+	bl31();
+	__builtin_unreachable();
+}
diff --git a/include/mach/imx/atf.h b/include/mach/imx/atf.h
index 587e778635..fb367d6a70 100644
--- a/include/mach/imx/atf.h
+++ b/include/mach/imx/atf.h
@@ -17,5 +17,7 @@
 #define MX8M_ATF_BL33_BASE_ADDR		0x40200000
 #define MX8MM_ATF_BL33_BASE_ADDR	MX8M_ATF_BL33_BASE_ADDR
 #define MX8MQ_ATF_BL33_BASE_ADDR	MX8M_ATF_BL33_BASE_ADDR
+#define MX93_ATF_BL31_BASE_ADDR		0x204e0000
+#define MX93_ATF_BL33_BASE_ADDR		0x80200000
 
 #endif
diff --git a/include/mach/imx/xload.h b/include/mach/imx/xload.h
index 11c2738c2d..2c2d2fa3c5 100644
--- a/include/mach/imx/xload.h
+++ b/include/mach/imx/xload.h
@@ -30,6 +30,7 @@ void __noreturn imx8mm_load_and_start_image_via_tfa(void);
 void __noreturn imx8mn_load_and_start_image_via_tfa(void);
 void __noreturn imx8mp_load_and_start_image_via_tfa(void);
 void __noreturn imx8mq_load_and_start_image_via_tfa(void);
+void __noreturn imx93_load_and_start_image_via_tfa(void);
 
 int imx_load_image(ptrdiff_t address, ptrdiff_t entry, u32 offset,
 		   u32 ivt_offset, bool start, unsigned int alignment,
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 21/25] imx-usb-loader: Add i.MX9 support
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (19 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 20/25] ARM: i.MX: atf: add imx93_load_and_start_image_via_tfa() Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 22/25] spi: spi-nxp-fspi: Enable for i.MX9 Sascha Hauer
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

i.MX9 support is straight forward: Just upload the whole image
in one go.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 scripts/imx/imx-usb-loader.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c
index ece4603b2b..91a15345a2 100644
--- a/scripts/imx/imx-usb-loader.c
+++ b/scripts/imx/imx-usb-loader.c
@@ -76,6 +76,7 @@ struct mach_id {
 	unsigned short max_transfer;
 #define DEV_IMX		0
 #define DEV_MXS		1
+#define DEV_IMX9	2
 	unsigned char dev_type;
 	unsigned char hid_endpoint;
 };
@@ -214,6 +215,14 @@ static const struct mach_id imx_ids[] = {
 		.header_type = HDR_MX53,
 		.mode = MODE_HID,
 		.max_transfer = 1024,
+	}, {
+		.vid = 0x1fc9,
+		.pid = 0x014e,
+		.name = "i.MX9",
+		.mode = MODE_HID,
+		.max_transfer = 1020,
+		.hid_endpoint = 1,
+		.dev_type = DEV_IMX9,
 	},
 };
 
@@ -1350,6 +1359,23 @@ static int process_header(struct usb_work *curr, unsigned char *buf, int cnt,
 	return -ENODEV;
 }
 
+static int imx9_load_file(struct usb_work *curr)
+{
+	void *buf;
+	size_t fsize = 0;
+	int ret;
+
+	buf = read_file(curr->filename, &fsize);
+	if (!buf)
+		return -errno;
+
+	ret = send_buf(buf, fsize);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
 static int do_irom_download(struct usb_work *curr, int verify)
 {
 	int ret;
@@ -1649,6 +1675,9 @@ int main(int argc, char *argv[])
 	if (mach_id->dev_type == DEV_MXS) {
 		ret = mxs_load_file(&w);
 		goto out;
+	} else if (mach_id->dev_type == DEV_IMX9) {
+		ret = imx9_load_file(&w);
+		goto out;
 	}
 
 	if (!mach_id->hid_endpoint) {
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 22/25] spi: spi-nxp-fspi: Enable for i.MX9
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (20 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 21/25] imx-usb-loader: Add i.MX9 support Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 23/25] usb: i.MX chipidea: Enable usbmisc driver " Sascha Hauer
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The i.MX9 flexspi is compatible to the one on i.MX8mm, just add the
necessary Kconfig dependency.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/spi/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e37c7821fb..445c756a38 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -112,7 +112,7 @@ config DRIVER_SPI_STM32
 
 config SPI_NXP_FLEXSPI
 	tristate "NXP Flex SPI controller"
-	depends on ARCH_IMX8M || COMPILE_TEST
+	depends on ARCH_IMX8M || ARCH_IMX93 || COMPILE_TEST
 	help
 	  This enables support for the Flex SPI controller in master mode.
 	  Up to four slave devices can be connected on two buses with two
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 23/25] usb: i.MX chipidea: Enable usbmisc driver for i.MX9
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (21 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 22/25] spi: spi-nxp-fspi: Enable for i.MX9 Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:57 ` [PATCH 24/25] ARM: Update imx_v8_defconfig Sascha Hauer
  2023-11-10 12:58 ` [PATCH 25/25] ARM: multi_v8_defconfig: enable i.MX9 boards Sascha Hauer
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

The usbmisc unit on the i.MX9 is compatible to the one on i.MX8MM.
Extend the #ifdef accordingly.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/imx/imx-usb-misc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/imx/imx-usb-misc.c b/drivers/usb/imx/imx-usb-misc.c
index 61d01688a1..bf9583e626 100644
--- a/drivers/usb/imx/imx-usb-misc.c
+++ b/drivers/usb/imx/imx-usb-misc.c
@@ -602,7 +602,7 @@ static __maybe_unused struct of_device_id imx_usbmisc_dt_ids[] = {
 		.data = &mx7_data,
 	},
 #endif
-#ifdef CONFIG_ARCH_IMX8M
+#if defined CONFIG_ARCH_IMX8M || defined CONFIG_ARCH_IMX93
 	{
 		.compatible = "fsl,imx8mm-usbmisc",
 		.data = &mx7_data,
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 24/25] ARM: Update imx_v8_defconfig
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (22 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 23/25] usb: i.MX chipidea: Enable usbmisc driver " Sascha Hauer
@ 2023-11-10 12:57 ` Sascha Hauer
  2023-11-10 12:58 ` [PATCH 25/25] ARM: multi_v8_defconfig: enable i.MX9 boards Sascha Hauer
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:57 UTC (permalink / raw)
  To: Barebox List

Enable i.MX9 support and drivers useful on that SoC.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/configs/imx_v8_defconfig | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm/configs/imx_v8_defconfig b/arch/arm/configs/imx_v8_defconfig
index 8084e72ea0..731156e4fe 100644
--- a/arch/arm/configs/imx_v8_defconfig
+++ b/arch/arm/configs/imx_v8_defconfig
@@ -1,5 +1,6 @@
 CONFIG_ARCH_IMX=y
 CONFIG_MACH_INNOCOMM_WB15=y
+CONFIG_MACH_MNT_REFORM=y
 CONFIG_MACH_NXP_IMX8MM_EVK=y
 CONFIG_MACH_NXP_IMX8MN_EVK=y
 CONFIG_MACH_NXP_IMX8MP_EVK=y
@@ -12,6 +13,7 @@ CONFIG_MACH_TQ_MBA8MPXL=y
 CONFIG_MACH_VARISCITE_DT8MCUSTOMBOARD_IMX8MP=y
 CONFIG_MACH_ZII_IMX8MQ_DEV=y
 CONFIG_64BIT=y
+CONFIG_MACH_TQ_MBA9XXXCA=y
 CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_MMU=y
 CONFIG_MALLOC_SIZE=0x0
@@ -93,6 +95,7 @@ CONFIG_OFDEVICE=y
 CONFIG_OF_BAREBOX_DRIVERS=y
 CONFIG_SERIAL_DEV_BUS=y
 CONFIG_DRIVER_NET_DESIGNWARE_IMX8=y
+CONFIG_DRIVER_SERIAL_LPUART32=y
 CONFIG_DRIVER_NET_FEC_IMX=y
 CONFIG_DP83867_PHY=y
 CONFIG_MICREL_PHY=y
@@ -108,6 +111,7 @@ CONFIG_DRIVER_SPI_IMX=y
 CONFIG_SPI_NXP_FLEXSPI=y
 CONFIG_I2C=y
 CONFIG_I2C_IMX=y
+CONFIG_I2C_IMX_LPI2C=y
 CONFIG_MTD=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_M25P80=y
@@ -122,6 +126,7 @@ CONFIG_MCI=y
 CONFIG_MCI_MMC_BOOT_PARTITIONS=y
 CONFIG_MCI_IMX_ESDHC=y
 CONFIG_RAVE_SP_CORE=y
+CONFIG_MFD_PCA9450=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
 CONFIG_LED_GPIO_OF=y
@@ -129,10 +134,11 @@ CONFIG_LED_TRIGGERS=y
 CONFIG_EEPROM_AT25=y
 CONFIG_EEPROM_AT24=y
 CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_POLLER=y
 CONFIG_WATCHDOG_IMX=y
+CONFIG_WATCHDOG_IMXULP=y
 CONFIG_RAVE_SP_WATCHDOG=y
 CONFIG_GPIO_PCA953X=y
-CONFIG_IMX_OCOTP=y
 CONFIG_RAVE_SP_EEPROM=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED=y
@@ -145,7 +151,6 @@ CONFIG_FS_TFTP=y
 CONFIG_FS_NFS=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
-CONFIG_FS_FAT_LFN=y
 CONFIG_FS_RATP=y
 CONFIG_ZLIB=y
 # CONFIG_MISSING_FIRMWARE_ERROR is not set
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 25/25] ARM: multi_v8_defconfig: enable i.MX9 boards
  2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
                   ` (23 preceding siblings ...)
  2023-11-10 12:57 ` [PATCH 24/25] ARM: Update imx_v8_defconfig Sascha Hauer
@ 2023-11-10 12:58 ` Sascha Hauer
  24 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-10 12:58 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/configs/multi_v8_defconfig | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/configs/multi_v8_defconfig b/arch/arm/configs/multi_v8_defconfig
index 9c538e698d..aea63b32d4 100644
--- a/arch/arm/configs/multi_v8_defconfig
+++ b/arch/arm/configs/multi_v8_defconfig
@@ -8,6 +8,7 @@ CONFIG_MACH_NXP_IMX8MM_EVK=y
 CONFIG_MACH_NXP_IMX8MN_EVK=y
 CONFIG_MACH_NXP_IMX8MP_EVK=y
 CONFIG_MACH_NXP_IMX8MQ_EVK=y
+CONFIG_MACH_PHYTEC_SOM_IMX8MM=y
 CONFIG_MACH_PHYTEC_SOM_IMX8MQ=y
 CONFIG_MACH_POLYHEX_DEBIX=y
 CONFIG_MACH_PROTONIC_IMX8M=y
@@ -15,6 +16,7 @@ CONFIG_MACH_SKOV_IMX8MP=y
 CONFIG_MACH_TQ_MBA8MPXL=y
 CONFIG_MACH_VARISCITE_DT8MCUSTOMBOARD_IMX8MP=y
 CONFIG_MACH_ZII_IMX8MQ_DEV=y
+CONFIG_MACH_TQ_MBA9XXXCA=y
 CONFIG_IMX_IIM=y
 CONFIG_MACH_RK3568_EVB=y
 CONFIG_MACH_RK3568_BPI_R2PRO=y
@@ -140,6 +142,7 @@ CONFIG_SERIAL_DEV_BUS=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_DRIVER_SERIAL_NS16550=y
 CONFIG_DRIVER_SERIAL_CADENCE=y
+CONFIG_DRIVER_SERIAL_LPUART32=y
 CONFIG_VIRTIO_CONSOLE=y
 CONFIG_DRIVER_NET_DESIGNWARE_IMX8=y
 CONFIG_DRIVER_NET_DESIGNWARE_ROCKCHIP=y
@@ -164,9 +167,11 @@ CONFIG_SPI_NXP_FLEXSPI=y
 CONFIG_I2C=y
 CONFIG_I2C_GPIO=y
 CONFIG_I2C_IMX=y
+CONFIG_I2C_IMX_LPI2C=y
 CONFIG_I2C_RK3X=y
 CONFIG_MTD=y
 CONFIG_MTD_CONCAT=y
+CONFIG_MTD_M25P80=y
 CONFIG_DRIVER_CFI=y
 CONFIG_CFI_BUFFER_WRITE=y
 CONFIG_VIRTIO_BLK=y
@@ -195,6 +200,7 @@ CONFIG_MCI_ARASAN=y
 CONFIG_COMMON_CLK_SCMI=y
 CONFIG_MFD_ACT8846=y
 CONFIG_RAVE_SP_CORE=y
+CONFIG_MFD_PCA9450=y
 CONFIG_MFD_RK808=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
@@ -206,6 +212,7 @@ CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_POLLER=y
 CONFIG_WATCHDOG_DW=y
 CONFIG_WATCHDOG_IMX=y
+CONFIG_WATCHDOG_IMXULP=y
 CONFIG_RAVE_SP_WATCHDOG=y
 CONFIG_HWRNG=y
 CONFIG_HW_RANDOM_VIRTIO=y
-- 
2.39.2




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support
  2023-11-10 12:57 ` [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support Sascha Hauer
@ 2023-11-13  7:24   ` Ahmad Fatoum
  2023-11-13  8:11     ` Sascha Hauer
  0 siblings, 1 reply; 29+ messages in thread
From: Ahmad Fatoum @ 2023-11-13  7:24 UTC (permalink / raw)
  To: Sascha Hauer, Barebox List

On 10.11.23 13:57, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

TRDC is presumably Tsomething Resource Domain Controller?
Would be nice to have a commit message spelling it out and describing
why this needs to be done in PBL for future reference.

Thanks,
Ahmad

> ---
>  arch/arm/mach-imx/Makefile     |   2 +-
>  arch/arm/mach-imx/imx93-trdc.c | 364 +++++++++++++++++++++++++++++++++
>  include/soc/imx9/trdc.h        |  11 +
>  3 files changed, 376 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/mach-imx/imx93-trdc.c
>  create mode 100644 include/soc/imx9/trdc.h
> 
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index 4efac08ee8..8a1ccabe15 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -33,4 +33,4 @@ obj-$(CONFIG_RESET_IMX_SRC) += src.o
>  lwl-y += cpu_init.o
>  pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
>  pbl-y += xload-qspi.o
> -pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o
> +pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o imx93-trdc.o
> diff --git a/arch/arm/mach-imx/imx93-trdc.c b/arch/arm/mach-imx/imx93-trdc.c
> new file mode 100644
> index 0000000000..a1c7d49515
> --- /dev/null
> +++ b/arch/arm/mach-imx/imx93-trdc.c
> @@ -0,0 +1,364 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2022 NXP
> + */
> +#define pr_fmt(fmt) "trdc: " fmt
> +
> +#include <common.h>
> +#include <io.h>
> +#include <soc/imx9/mu_hal.h>
> +#include <soc/imx9/s400_api.h>
> +#include <soc/imx9/trdc.h>
> +#include <mach/imx/imx9-regs.h>
> +
> +#define DID_NUM 16
> +#define MBC_MAX_NUM 4
> +#define MRC_MAX_NUM 2
> +#define MBC_NUM(HWCFG) ((HWCFG >> 16) & 0xF)
> +#define MRC_NUM(HWCFG) ((HWCFG >> 24) & 0x1F)
> +
> +struct mbc_mem_dom {
> +	u32 mem_glbcfg[4];
> +	u32 nse_blk_index;
> +	u32 nse_blk_set;
> +	u32 nse_blk_clr;
> +	u32 nsr_blk_clr_all;
> +	u32 memn_glbac[8];
> +	/* The upper only existed in the beginning of each MBC */
> +	u32 mem0_blk_cfg_w[64];
> +	u32 mem0_blk_nse_w[16];
> +	u32 mem1_blk_cfg_w[8];
> +	u32 mem1_blk_nse_w[2];
> +	u32 mem2_blk_cfg_w[8];
> +	u32 mem2_blk_nse_w[2];
> +	u32 mem3_blk_cfg_w[8];
> +	u32 mem3_blk_nse_w[2];/*0x1F0, 0x1F4 */
> +	u32 reserved[2];
> +};
> +
> +struct mrc_rgn_dom {
> +	u32 mrc_glbcfg[4];
> +	u32 nse_rgn_indirect;
> +	u32 nse_rgn_set;
> +	u32 nse_rgn_clr;
> +	u32 nse_rgn_clr_all;
> +	u32 memn_glbac[8];
> +	/* The upper only existed in the beginning of each MRC */
> +	u32 rgn_desc_words[16][2]; /* 16  regions at max, 2 words per region */
> +	u32 rgn_nse;
> +	u32 reserved2[15];
> +};
> +
> +struct mda_inst {
> +	u32 mda_w[8];
> +};
> +
> +struct trdc_mgr {
> +	u32 trdc_cr;
> +	u32 res0[59];
> +	u32 trdc_hwcfg0;
> +	u32 trdc_hwcfg1;
> +	u32 res1[450];
> +	struct mda_inst mda[8];
> +	u32 res2[15808];
> +};
> +
> +struct trdc_mbc {
> +	struct mbc_mem_dom mem_dom[DID_NUM];
> +};
> +
> +struct trdc_mrc {
> +	struct mrc_rgn_dom mrc_dom[DID_NUM];
> +};
> +
> +static void *trdc_get_mbc_base(ulong trdc_reg, u32 mbc_x)
> +{
> +	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
> +	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
> +
> +	if (mbc_x >= mbc_num)
> +		return 0;
> +
> +	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_x;
> +}
> +
> +static void *trdc_get_mrc_base(ulong trdc_reg, u32 mrc_x)
> +{
> +	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
> +	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
> +	u32 mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
> +
> +	if (mrc_x >= mrc_num)
> +		return 0;
> +
> +	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
> +}
> +
> +static int trdc_mbc_set_control(ulong trdc_reg, u32 mbc_x, u32 glbac_id,
> +			 u32 glbac_val)
> +{
> +	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
> +	struct mbc_mem_dom *mbc_dom;
> +
> +	if (mbc_base == 0 || glbac_id >= 8)
> +		return -EINVAL;
> +
> +	/* only first dom has the glbac */
> +	mbc_dom = &mbc_base->mem_dom[0];
> +
> +	writel(glbac_val, &mbc_dom->memn_glbac[glbac_id]);
> +
> +	return 0;
> +}
> +
> +static int trdc_mbc_blk_config(ulong trdc_reg, u32 mbc_x, u32 dom_x, u32 mem_x,
> +			u32 blk_x, bool sec_access, u32 glbac_id)
> +{
> +	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
> +	struct mbc_mem_dom *mbc_dom;
> +	u32 *cfg_w, *nse_w;
> +	u32 index, offset, val;
> +
> +	if (mbc_base == 0 || glbac_id >= 8)
> +		return -EINVAL;
> +
> +	mbc_dom = &mbc_base->mem_dom[dom_x];
> +
> +	switch (mem_x) {
> +	case 0:
> +		cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
> +		nse_w = &mbc_dom->mem0_blk_nse_w[blk_x / 32];
> +		break;
> +	case 1:
> +		cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
> +		nse_w = &mbc_dom->mem1_blk_nse_w[blk_x / 32];
> +		break;
> +	case 2:
> +		cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
> +		nse_w = &mbc_dom->mem2_blk_nse_w[blk_x / 32];
> +		break;
> +	case 3:
> +		cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
> +		nse_w = &mbc_dom->mem3_blk_nse_w[blk_x / 32];
> +		break;
> +	default:
> +		return -EINVAL;
> +	};
> +
> +	index = blk_x % 8;
> +	offset = index * 4;
> +
> +	val = readl((void __iomem *)cfg_w);
> +
> +	val &= ~(0xFU << offset);
> +
> +	/* MBC0-3
> +	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
> +	 *  So select MBC0_MEMN_GLBAC0
> +	 */
> +	if (sec_access) {
> +		val |= ((0x0 | (glbac_id & 0x7)) << offset);
> +		writel(val, (void __iomem *)cfg_w);
> +	} else {
> +		val |= ((0x8 | (glbac_id & 0x7)) << offset); /* nse bit set */
> +		writel(val, (void __iomem *)cfg_w);
> +	}
> +
> +	return 0;
> +}
> +
> +static int trdc_mrc_set_control(ulong trdc_reg, u32 mrc_x, u32 glbac_id, u32 glbac_val)
> +{
> +	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
> +	struct mrc_rgn_dom *mrc_dom;
> +
> +	if (mrc_base == 0 || glbac_id >= 8)
> +		return -EINVAL;
> +
> +	/* only first dom has the glbac */
> +	mrc_dom = &mrc_base->mrc_dom[0];
> +
> +	pr_vdebug("mrc_dom 0x%lx\n", (ulong)mrc_dom);
> +
> +	writel(glbac_val, &mrc_dom->memn_glbac[glbac_id]);
> +
> +	return 0;
> +}
> +
> +static int trdc_mrc_region_config(ulong trdc_reg, u32 mrc_x, u32 dom_x, u32 addr_start,
> +			   u32 addr_end, bool sec_access, u32 glbac_id)
> +{
> +	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
> +	struct mrc_rgn_dom *mrc_dom;
> +	u32 *desc_w;
> +	u32 start, end;
> +	u32 i, free = 8;
> +	bool vld, hit = false;
> +
> +	if (mrc_base == 0 || glbac_id >= 8)
> +		return -EINVAL;
> +
> +	mrc_dom = &mrc_base->mrc_dom[dom_x];
> +
> +	addr_start &= ~0x3fff;
> +	addr_end &= ~0x3fff;
> +
> +	for (i = 0; i < 8; i++) {
> +		desc_w = &mrc_dom->rgn_desc_words[i][0];
> +
> +		start = readl((void __iomem *)desc_w) & (~0x3fff);
> +		end = readl((void __iomem *)(desc_w + 1));
> +		vld = end & 0x1;
> +		end = end & (~0x3fff);
> +
> +		if (start == 0 && end == 0 && !vld && free >= 8)
> +			free = i;
> +
> +		/* Check all the region descriptors, even overlap */
> +		if (addr_start >= end || addr_end <= start || !vld)
> +			continue;
> +
> +		/* MRC0,1
> +		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
> +		 *  So select MRCx_MEMN_GLBAC0
> +		 */
> +		if (sec_access) {
> +			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
> +			writel(end | 0x1, (void __iomem *)(desc_w + 1));
> +		} else {
> +			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
> +			writel(end | 0x1 | 0x10, (void __iomem *)(desc_w + 1));
> +		}
> +
> +		if (addr_start >= start && addr_end <= end)
> +			hit = true;
> +	}
> +
> +	if (!hit) {
> +		if (free >= 8)
> +			return -EFAULT;
> +
> +		desc_w = &mrc_dom->rgn_desc_words[free][0];
> +
> +		if (sec_access) {
> +			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
> +			writel(addr_end | 0x1, (void __iomem *)(desc_w + 1));
> +		} else {
> +			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
> +			writel((addr_end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static bool trdc_mrc_enabled(ulong trdc_base)
> +{
> +	return (!!(readl((void __iomem *)trdc_base) & 0x8000));
> +}
> +
> +static int release_rdc(u8 xrdc)
> +{
> +	ulong s_mu_base = 0x47520000UL;
> +	struct sentinel_msg msg;
> +	int ret;
> +	u32 rdc_id;
> +
> +	switch (xrdc) {
> +	case 0:
> +		rdc_id = 0x74;
> +		break;
> +	case 1:
> +		rdc_id = 0x78;
> +		break;
> +	case 2:
> +		rdc_id = 0x82;
> +		break;
> +	case 3:
> +		rdc_id = 0x86;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	msg.version = AHAB_VERSION;
> +	msg.tag = AHAB_CMD_TAG;
> +	msg.size = 2;
> +	msg.command = ELE_RELEASE_RDC_REQ;
> +	msg.data[0] = (rdc_id << 8) | 0x2; /* A55 */
> +
> +	mu_hal_init(s_mu_base);
> +	mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
> +	mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
> +
> +	ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
> +	if (ret)
> +		return ret;
> +
> +	ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
> +	if (ret)
> +		return -EIO;
> +
> +	if ((msg.data[0] & 0xff) == 0xd6)
> +		return 0;
> +
> +	return -EIO;
> +}
> +
> +void imx9_trdc_init(void)
> +{
> +	unsigned long base = MX9_TRDC_NICMIX_BASE_ADDR;
> +	int ret = 0, i;
> +
> +	ret |= release_rdc(0);
> +	ret |= release_rdc(2);
> +	ret |= release_rdc(1);
> +	ret |= release_rdc(3);
> +
> +	if (ret)
> +		return;
> +
> +	/* Set OCRAM to RWX for secure, when OEM_CLOSE, the image is RX only */
> +	trdc_mbc_set_control(base, 3, 0, 0x7700);
> +
> +	for (i = 0; i < 40; i++)
> +		trdc_mbc_blk_config(base, 3, 3, 0, i, true, 0);
> +
> +	for (i = 0; i < 40; i++)
> +		trdc_mbc_blk_config(base, 3, 3, 1, i, true, 0);
> +
> +	for (i = 0; i < 40; i++)
> +		trdc_mbc_blk_config(base, 3, 0, 0, i, true, 0);
> +
> +	for (i = 0; i < 40; i++)
> +		trdc_mbc_blk_config(base, 3, 0, 1, i, true, 0);
> +
> +	/* TRDC mega */
> +	if (!trdc_mrc_enabled(base))
> +		return;
> +
> +	/* DDR */
> +	trdc_mrc_set_control(base, 0, 0, 0x7777);
> +	/* S400*/
> +	trdc_mrc_region_config(base, 0, 0, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* MTR */
> +	trdc_mrc_region_config(base, 0, 1, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* M33 */
> +	trdc_mrc_region_config(base, 0, 2, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* A55*/
> +	trdc_mrc_region_config(base, 0, 3, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* For USDHC1 to DDR, USDHC1 is default force to non-secure */
> +	trdc_mrc_region_config(base, 0, 5, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* For USDHC2 to DDR, USDHC2 is default force to non-secure */
> +	trdc_mrc_region_config(base, 0, 6, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* eDMA */
> +	trdc_mrc_region_config(base, 0, 7, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* CoreSight, TestPort */
> +	trdc_mrc_region_config(base, 0, 8, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* DAP */
> +	trdc_mrc_region_config(base, 0, 9, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* SoC masters */
> +	trdc_mrc_region_config(base, 0, 10, 0x80000000, 0xFFFFFFFF, false, 0);
> +	/* USB */
> +	trdc_mrc_region_config(base, 0, 11, 0x80000000, 0xFFFFFFFF, false, 0);
> +}
> diff --git a/include/soc/imx9/trdc.h b/include/soc/imx9/trdc.h
> new file mode 100644
> index 0000000000..624e267ab6
> --- /dev/null
> +++ b/include/soc/imx9/trdc.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2022 NXP
> + */
> +
> +#ifndef __ASM_ARCH_IMX9_TRDC_H
> +#define __ASM_ARCH_IMX9_TRDC_H
> +
> +void imx9_trdc_init(void);
> +
> +#endif

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support
  2023-11-10 12:57 ` [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support Sascha Hauer
@ 2023-11-13  7:25   ` Ahmad Fatoum
  0 siblings, 0 replies; 29+ messages in thread
From: Ahmad Fatoum @ 2023-11-13  7:25 UTC (permalink / raw)
  To: Sascha Hauer, Barebox List

On 10.11.23 13:57, Sascha Hauer wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

A short message along the lines of: We will require to communicate with
the ELE firmware/coprocessor/? for X, so add support here would be good
to have.

Thanks,
Ahmad

> ---
>  arch/arm/mach-imx/Makefile     |   1 +
>  arch/arm/mach-imx/imx93-s4mu.c |  97 ++++++++++++++++++++++++++
>  include/soc/imx9/mu_hal.h      |  12 ++++
>  include/soc/imx9/s400_api.h    | 124 +++++++++++++++++++++++++++++++++
>  4 files changed, 234 insertions(+)
>  create mode 100644 arch/arm/mach-imx/imx93-s4mu.c
>  create mode 100644 include/soc/imx9/mu_hal.h
>  create mode 100644 include/soc/imx9/s400_api.h
> 
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index 7b093ba7fd..4efac08ee8 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -33,3 +33,4 @@ obj-$(CONFIG_RESET_IMX_SRC) += src.o
>  lwl-y += cpu_init.o
>  pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
>  pbl-y += xload-qspi.o
> +pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o
> diff --git a/arch/arm/mach-imx/imx93-s4mu.c b/arch/arm/mach-imx/imx93-s4mu.c
> new file mode 100644
> index 0000000000..11a787d44d
> --- /dev/null
> +++ b/arch/arm/mach-imx/imx93-s4mu.c
> @@ -0,0 +1,97 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2020-2022 NXP
> + */
> +#define pr_fmt(fmt) "s4mu: " fmt
> +
> +#include <common.h>
> +#include <io.h>
> +#include <soc/imx9/s400_api.h>
> +#include <soc/imx9/mu_hal.h>
> +#include <linux/iopoll.h>
> +
> +#define MU_SR_TE0_MASK		BIT(0)
> +#define MU_SR_RF0_MASK		BIT(0)
> +#define MU_TR_COUNT		8
> +#define MU_RR_COUNT		4
> +
> +struct mu_type {
> +	u32 ver;
> +	u32 par;
> +	u32 cr;
> +	u32 sr;
> +	u32 reserved0[60];
> +	u32 fcr;
> +	u32 fsr;
> +	u32 reserved1[2];
> +	u32 gier;
> +	u32 gcr;
> +	u32 gsr;
> +	u32 reserved2;
> +	u32 tcr;
> +	u32 tsr;
> +	u32 rcr;
> +	u32 rsr;
> +	u32 reserved3[52];
> +	u32 tr[16];
> +	u32 reserved4[16];
> +	u32 rr[16];
> +	u32 reserved5[14];
> +	u32 mu_attr;
> +};
> +
> +void mu_hal_init(ulong base)
> +{
> +	struct mu_type *mu_base = (struct mu_type *)base;
> +
> +	writel(0, &mu_base->tcr);
> +	writel(0, &mu_base->rcr);
> +}
> +
> +int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg)
> +{
> +	struct mu_type *mu_base = (struct mu_type *)base;
> +	u32 mask = MU_SR_TE0_MASK << reg_index;
> +	u32 val;
> +	int ret;
> +
> +	BUG_ON(reg_index >= MU_TR_COUNT);
> +
> +	pr_vdebug("sendmsg tsr 0x%x\n", readl(&mu_base->tsr));
> +
> +	/* Wait TX register to be empty. */
> +	ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
> +	if (ret < 0) {
> +		pr_debug("%s timeout\n", __func__);
> +		return -ETIMEDOUT;
> +	}
> +
> +	pr_vdebug("tr[%d] 0x%x\n", reg_index, msg);
> +
> +	writel(msg, &mu_base->tr[reg_index]);
> +
> +	return 0;
> +}
> +
> +int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg)
> +{
> +	struct mu_type *mu_base = (struct mu_type *)base;
> +	u32 mask = MU_SR_RF0_MASK << reg_index;
> +	u32 val;
> +	int ret;
> +
> +	BUG_ON(reg_index >= MU_RR_COUNT);
> +
> +	pr_vdebug("receivemsg rsr 0x%x\n", readl(&mu_base->rsr));
> +
> +	/* Wait RX register to be full. */
> +	ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 10000000);
> +	if (ret < 0)
> +		return -ETIMEDOUT;
> +
> +	*msg = readl(&mu_base->rr[reg_index]);
> +
> +	pr_vdebug("rr[%d] 0x%x\n", reg_index, *msg);
> +
> +	return 0;
> +}
> diff --git a/include/soc/imx9/mu_hal.h b/include/soc/imx9/mu_hal.h
> new file mode 100644
> index 0000000000..5db559c1ac
> --- /dev/null
> +++ b/include/soc/imx9/mu_hal.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2021 NXP
> + */
> +
> +#ifndef __SNT_MU_HAL_H__
> +#define __SNT_MU_HAL_H__
> +
> +void mu_hal_init(ulong base);
> +int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg);
> +int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg);
> +#endif
> diff --git a/include/soc/imx9/s400_api.h b/include/soc/imx9/s400_api.h
> new file mode 100644
> index 0000000000..6d2dd71d67
> --- /dev/null
> +++ b/include/soc/imx9/s400_api.h
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2021 NXP
> + */
> +
> +#ifndef __S400_API_H__
> +#define __S400_API_H__
> +
> +#define AHAB_VERSION    0x6
> +#define AHAB_CMD_TAG    0x17
> +#define AHAB_RESP_TAG   0xe1
> +
> +/* ELE commands */
> +#define ELE_PING_REQ (0x01)
> +#define ELE_FW_AUTH_REQ (0x02)
> +#define ELE_RESTART_RST_TIMER_REQ (0x04)
> +#define ELE_DUMP_DEBUG_BUFFER_REQ (0x21)
> +#define ELE_OEM_CNTN_AUTH_REQ (0x87)
> +#define ELE_VERIFY_IMAGE_REQ (0x88)
> +#define ELE_RELEASE_CONTAINER_REQ (0x89)
> +#define ELE_WRITE_SECURE_FUSE_REQ (0x91)
> +#define ELE_FWD_LIFECYCLE_UP_REQ (0x95)
> +#define ELE_READ_FUSE_REQ (0x97)
> +#define ELE_GET_FW_VERSION_REQ (0x9D)
> +#define ELE_RET_LIFECYCLE_UP_REQ (0xA0)
> +#define ELE_GET_EVENTS_REQ (0xA2)
> +#define ELE_START_RNG (0xA3)
> +#define ELE_GENERATE_DEK_BLOB (0xAF)
> +#define ELE_ENABLE_PATCH_REQ (0xC3)
> +#define ELE_RELEASE_RDC_REQ (0xC4)
> +#define ELE_GET_FW_STATUS_REQ (0xC5)
> +#define ELE_ENABLE_OTFAD_REQ (0xC6)
> +#define ELE_RESET_REQ (0xC7)
> +#define ELE_UPDATE_OTP_CLKDIV_REQ (0xD0)
> +#define ELE_POWER_DOWN_REQ (0xD1)
> +#define ELE_ENABLE_APC_REQ (0xD2)
> +#define ELE_ENABLE_RTC_REQ (0xD3)
> +#define ELE_DEEP_POWER_DOWN_REQ (0xD4)
> +#define ELE_STOP_RST_TIMER_REQ (0xD5)
> +#define ELE_WRITE_FUSE_REQ (0xD6)
> +#define ELE_RELEASE_CAAM_REQ (0xD7)
> +#define ELE_RESET_A35_CTX_REQ (0xD8)
> +#define ELE_MOVE_TO_UNSECURED_REQ (0xD9)
> +#define ELE_GET_INFO_REQ (0xDA)
> +#define ELE_ATTEST_REQ (0xDB)
> +#define ELE_RELEASE_PATCH_REQ (0xDC)
> +#define ELE_OTP_SEQ_SWITH_REQ (0xDD)
> +
> +/* ELE failure indications */
> +#define ELE_ROM_PING_FAILURE_IND (0x0A)
> +#define ELE_FW_PING_FAILURE_IND (0x1A)
> +#define ELE_BAD_SIGNATURE_FAILURE_IND (0xF0)
> +#define ELE_BAD_HASH_FAILURE_IND (0xF1)
> +#define ELE_INVALID_LIFECYCLE_IND (0xF2)
> +#define ELE_PERMISSION_DENIED_FAILURE_IND (0xF3)
> +#define ELE_INVALID_MESSAGE_FAILURE_IND (0xF4)
> +#define ELE_BAD_VALUE_FAILURE_IND (0xF5)
> +#define ELE_BAD_FUSE_ID_FAILURE_IND (0xF6)
> +#define ELE_BAD_CONTAINER_FAILURE_IND (0xF7)
> +#define ELE_BAD_VERSION_FAILURE_IND (0xF8)
> +#define ELE_INVALID_KEY_FAILURE_IND (0xF9)
> +#define ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
> +#define ELE_NO_VALID_CONTAINER_FAILURE_IND (0xFB)
> +#define ELE_BAD_CERTIFICATE_FAILURE_IND (0xFC)
> +#define ELE_BAD_UID_FAILURE_IND (0xFD)
> +#define ELE_BAD_MONOTONIC_COUNTER_FAILURE_IND (0xFE)
> +#define ELE_MUST_SIGNED_FAILURE_IND (0xE0)
> +#define ELE_NO_AUTHENTICATION_FAILURE_IND (0xEE)
> +#define ELE_BAD_SRK_SET_FAILURE_IND (0xEF)
> +#define ELE_UNALIGNED_PAYLOAD_FAILURE_IND (0xA6)
> +#define ELE_WRONG_SIZE_FAILURE_IND (0xA7)
> +#define ELE_ENCRYPTION_FAILURE_IND (0xA8)
> +#define ELE_DECRYPTION_FAILURE_IND (0xA9)
> +#define ELE_OTP_PROGFAIL_FAILURE_IND (0xAA)
> +#define ELE_OTP_LOCKED_FAILURE_IND (0xAB)
> +#define ELE_OTP_INVALID_IDX_FAILURE_IND (0xAD)
> +#define ELE_TIME_OUT_FAILURE_IND (0xB0)
> +#define ELE_BAD_PAYLOAD_FAILURE_IND (0xB1)
> +#define ELE_WRONG_ADDRESS_FAILURE_IND (0xB4)
> +#define ELE_DMA_FAILURE_IND (0xB5)
> +#define ELE_DISABLED_FEATURE_FAILURE_IND (0xB6)
> +#define ELE_MUST_ATTEST_FAILURE_IND (0xB7)
> +#define ELE_RNG_NOT_STARTED_FAILURE_IND (0xB8)
> +#define ELE_CRC_ERROR_IND (0xB9)
> +#define ELE_AUTH_SKIPPED_OR_FAILED_FAILURE_IND (0xBB)
> +#define ELE_INCONSISTENT_PAR_FAILURE_IND (0xBC)
> +#define ELE_RNG_INST_FAILURE_FAILURE_IND (0xBD)
> +#define ELE_LOCKED_REG_FAILURE_IND (0xBE)
> +#define ELE_BAD_ID_FAILURE_IND (0xBF)
> +#define ELE_INVALID_OPERATION_FAILURE_IND (0xC0)
> +#define ELE_NON_SECURE_STATE_FAILURE_IND (0xC1)
> +#define ELE_MSG_TRUNCATED_IND (0xC2)
> +#define ELE_BAD_IMAGE_NUM_FAILURE_IND (0xC3)
> +#define ELE_BAD_IMAGE_ADDR_FAILURE_IND (0xC4)
> +#define ELE_BAD_IMAGE_PARAM_FAILURE_IND (0xC5)
> +#define ELE_BAD_IMAGE_TYPE_FAILURE_IND (0xC6)
> +#define ELE_CORRUPTED_SRK_FAILURE_IND (0xD0)
> +#define ELE_OUT_OF_MEMORY_IND (0xD1)
> +#define ELE_CSTM_FAILURE_IND (0xCF)
> +#define ELE_OLD_VERSION_FAILURE_IND (0xCE)
> +#define ELE_WRONG_BOOT_MODE_FAILURE_IND (0xCD)
> +#define ELE_APC_ALREADY_ENABLED_FAILURE_IND (0xCB)
> +#define ELE_RTC_ALREADY_ENABLED_FAILURE_IND (0xCC)
> +#define ELE_ABORT_IND (0xFF)
> +
> +/* ELE IPC identifier */
> +#define ELE_IPC_MU_RTD (0x1)
> +#define ELE_IPC_MU_APD (0x2)
> +
> +/* ELE Status*/
> +#define ELE_SUCCESS_IND (0xD6)
> +#define ELE_FAILURE_IND (0x29)
> +
> +#define S400_MAX_MSG          255U
> +
> +struct sentinel_msg {
> +	u8 version;
> +	u8 size;
> +	u8 command;
> +	u8 tag;
> +	u32 data[(S400_MAX_MSG - 1U)];
> +};
> +
> +#endif

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support
  2023-11-13  7:24   ` Ahmad Fatoum
@ 2023-11-13  8:11     ` Sascha Hauer
  0 siblings, 0 replies; 29+ messages in thread
From: Sascha Hauer @ 2023-11-13  8:11 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: Barebox List

On Mon, Nov 13, 2023 at 08:24:21AM +0100, Ahmad Fatoum wrote:
> On 10.11.23 13:57, Sascha Hauer wrote:
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> 
> TRDC is presumably Tsomething Resource Domain Controller?
> Would be nice to have a commit message spelling it out and describing
> why this needs to be done in PBL for future reference.

TRDC is for "Trusted Reource Domain Controller". Honestly I don't really
know what the code does, but there's a reason this is done in PBL and
indeed it should be mentioned in the commit message: Without running
this code the OCRAM is readonly and relocate_to_current_adr() won't
work.

Sascha

> 
> Thanks,
> Ahmad
> 
> > ---
> >  arch/arm/mach-imx/Makefile     |   2 +-
> >  arch/arm/mach-imx/imx93-trdc.c | 364 +++++++++++++++++++++++++++++++++
> >  include/soc/imx9/trdc.h        |  11 +
> >  3 files changed, 376 insertions(+), 1 deletion(-)
> >  create mode 100644 arch/arm/mach-imx/imx93-trdc.c
> >  create mode 100644 include/soc/imx9/trdc.h
> > 
> > diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> > index 4efac08ee8..8a1ccabe15 100644
> > --- a/arch/arm/mach-imx/Makefile
> > +++ b/arch/arm/mach-imx/Makefile
> > @@ -33,4 +33,4 @@ obj-$(CONFIG_RESET_IMX_SRC) += src.o
> >  lwl-y += cpu_init.o
> >  pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
> >  pbl-y += xload-qspi.o
> > -pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o
> > +pbl-$(CONFIG_ARCH_IMX93) += imx93-s4mu.o imx93-trdc.o
> > diff --git a/arch/arm/mach-imx/imx93-trdc.c b/arch/arm/mach-imx/imx93-trdc.c
> > new file mode 100644
> > index 0000000000..a1c7d49515
> > --- /dev/null
> > +++ b/arch/arm/mach-imx/imx93-trdc.c
> > @@ -0,0 +1,364 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2022 NXP
> > + */
> > +#define pr_fmt(fmt) "trdc: " fmt
> > +
> > +#include <common.h>
> > +#include <io.h>
> > +#include <soc/imx9/mu_hal.h>
> > +#include <soc/imx9/s400_api.h>
> > +#include <soc/imx9/trdc.h>
> > +#include <mach/imx/imx9-regs.h>
> > +
> > +#define DID_NUM 16
> > +#define MBC_MAX_NUM 4
> > +#define MRC_MAX_NUM 2
> > +#define MBC_NUM(HWCFG) ((HWCFG >> 16) & 0xF)
> > +#define MRC_NUM(HWCFG) ((HWCFG >> 24) & 0x1F)
> > +
> > +struct mbc_mem_dom {
> > +	u32 mem_glbcfg[4];
> > +	u32 nse_blk_index;
> > +	u32 nse_blk_set;
> > +	u32 nse_blk_clr;
> > +	u32 nsr_blk_clr_all;
> > +	u32 memn_glbac[8];
> > +	/* The upper only existed in the beginning of each MBC */
> > +	u32 mem0_blk_cfg_w[64];
> > +	u32 mem0_blk_nse_w[16];
> > +	u32 mem1_blk_cfg_w[8];
> > +	u32 mem1_blk_nse_w[2];
> > +	u32 mem2_blk_cfg_w[8];
> > +	u32 mem2_blk_nse_w[2];
> > +	u32 mem3_blk_cfg_w[8];
> > +	u32 mem3_blk_nse_w[2];/*0x1F0, 0x1F4 */
> > +	u32 reserved[2];
> > +};
> > +
> > +struct mrc_rgn_dom {
> > +	u32 mrc_glbcfg[4];
> > +	u32 nse_rgn_indirect;
> > +	u32 nse_rgn_set;
> > +	u32 nse_rgn_clr;
> > +	u32 nse_rgn_clr_all;
> > +	u32 memn_glbac[8];
> > +	/* The upper only existed in the beginning of each MRC */
> > +	u32 rgn_desc_words[16][2]; /* 16  regions at max, 2 words per region */
> > +	u32 rgn_nse;
> > +	u32 reserved2[15];
> > +};
> > +
> > +struct mda_inst {
> > +	u32 mda_w[8];
> > +};
> > +
> > +struct trdc_mgr {
> > +	u32 trdc_cr;
> > +	u32 res0[59];
> > +	u32 trdc_hwcfg0;
> > +	u32 trdc_hwcfg1;
> > +	u32 res1[450];
> > +	struct mda_inst mda[8];
> > +	u32 res2[15808];
> > +};
> > +
> > +struct trdc_mbc {
> > +	struct mbc_mem_dom mem_dom[DID_NUM];
> > +};
> > +
> > +struct trdc_mrc {
> > +	struct mrc_rgn_dom mrc_dom[DID_NUM];
> > +};
> > +
> > +static void *trdc_get_mbc_base(ulong trdc_reg, u32 mbc_x)
> > +{
> > +	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
> > +	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
> > +
> > +	if (mbc_x >= mbc_num)
> > +		return 0;
> > +
> > +	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_x;
> > +}
> > +
> > +static void *trdc_get_mrc_base(ulong trdc_reg, u32 mrc_x)
> > +{
> > +	struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
> > +	u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
> > +	u32 mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
> > +
> > +	if (mrc_x >= mrc_num)
> > +		return 0;
> > +
> > +	return (void *)trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
> > +}
> > +
> > +static int trdc_mbc_set_control(ulong trdc_reg, u32 mbc_x, u32 glbac_id,
> > +			 u32 glbac_val)
> > +{
> > +	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
> > +	struct mbc_mem_dom *mbc_dom;
> > +
> > +	if (mbc_base == 0 || glbac_id >= 8)
> > +		return -EINVAL;
> > +
> > +	/* only first dom has the glbac */
> > +	mbc_dom = &mbc_base->mem_dom[0];
> > +
> > +	writel(glbac_val, &mbc_dom->memn_glbac[glbac_id]);
> > +
> > +	return 0;
> > +}
> > +
> > +static int trdc_mbc_blk_config(ulong trdc_reg, u32 mbc_x, u32 dom_x, u32 mem_x,
> > +			u32 blk_x, bool sec_access, u32 glbac_id)
> > +{
> > +	struct trdc_mbc *mbc_base = trdc_get_mbc_base(trdc_reg, mbc_x);
> > +	struct mbc_mem_dom *mbc_dom;
> > +	u32 *cfg_w, *nse_w;
> > +	u32 index, offset, val;
> > +
> > +	if (mbc_base == 0 || glbac_id >= 8)
> > +		return -EINVAL;
> > +
> > +	mbc_dom = &mbc_base->mem_dom[dom_x];
> > +
> > +	switch (mem_x) {
> > +	case 0:
> > +		cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
> > +		nse_w = &mbc_dom->mem0_blk_nse_w[blk_x / 32];
> > +		break;
> > +	case 1:
> > +		cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
> > +		nse_w = &mbc_dom->mem1_blk_nse_w[blk_x / 32];
> > +		break;
> > +	case 2:
> > +		cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
> > +		nse_w = &mbc_dom->mem2_blk_nse_w[blk_x / 32];
> > +		break;
> > +	case 3:
> > +		cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
> > +		nse_w = &mbc_dom->mem3_blk_nse_w[blk_x / 32];
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	};
> > +
> > +	index = blk_x % 8;
> > +	offset = index * 4;
> > +
> > +	val = readl((void __iomem *)cfg_w);
> > +
> > +	val &= ~(0xFU << offset);
> > +
> > +	/* MBC0-3
> > +	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
> > +	 *  So select MBC0_MEMN_GLBAC0
> > +	 */
> > +	if (sec_access) {
> > +		val |= ((0x0 | (glbac_id & 0x7)) << offset);
> > +		writel(val, (void __iomem *)cfg_w);
> > +	} else {
> > +		val |= ((0x8 | (glbac_id & 0x7)) << offset); /* nse bit set */
> > +		writel(val, (void __iomem *)cfg_w);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int trdc_mrc_set_control(ulong trdc_reg, u32 mrc_x, u32 glbac_id, u32 glbac_val)
> > +{
> > +	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
> > +	struct mrc_rgn_dom *mrc_dom;
> > +
> > +	if (mrc_base == 0 || glbac_id >= 8)
> > +		return -EINVAL;
> > +
> > +	/* only first dom has the glbac */
> > +	mrc_dom = &mrc_base->mrc_dom[0];
> > +
> > +	pr_vdebug("mrc_dom 0x%lx\n", (ulong)mrc_dom);
> > +
> > +	writel(glbac_val, &mrc_dom->memn_glbac[glbac_id]);
> > +
> > +	return 0;
> > +}
> > +
> > +static int trdc_mrc_region_config(ulong trdc_reg, u32 mrc_x, u32 dom_x, u32 addr_start,
> > +			   u32 addr_end, bool sec_access, u32 glbac_id)
> > +{
> > +	struct trdc_mrc *mrc_base = trdc_get_mrc_base(trdc_reg, mrc_x);
> > +	struct mrc_rgn_dom *mrc_dom;
> > +	u32 *desc_w;
> > +	u32 start, end;
> > +	u32 i, free = 8;
> > +	bool vld, hit = false;
> > +
> > +	if (mrc_base == 0 || glbac_id >= 8)
> > +		return -EINVAL;
> > +
> > +	mrc_dom = &mrc_base->mrc_dom[dom_x];
> > +
> > +	addr_start &= ~0x3fff;
> > +	addr_end &= ~0x3fff;
> > +
> > +	for (i = 0; i < 8; i++) {
> > +		desc_w = &mrc_dom->rgn_desc_words[i][0];
> > +
> > +		start = readl((void __iomem *)desc_w) & (~0x3fff);
> > +		end = readl((void __iomem *)(desc_w + 1));
> > +		vld = end & 0x1;
> > +		end = end & (~0x3fff);
> > +
> > +		if (start == 0 && end == 0 && !vld && free >= 8)
> > +			free = i;
> > +
> > +		/* Check all the region descriptors, even overlap */
> > +		if (addr_start >= end || addr_end <= start || !vld)
> > +			continue;
> > +
> > +		/* MRC0,1
> > +		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
> > +		 *  So select MRCx_MEMN_GLBAC0
> > +		 */
> > +		if (sec_access) {
> > +			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
> > +			writel(end | 0x1, (void __iomem *)(desc_w + 1));
> > +		} else {
> > +			writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
> > +			writel(end | 0x1 | 0x10, (void __iomem *)(desc_w + 1));
> > +		}
> > +
> > +		if (addr_start >= start && addr_end <= end)
> > +			hit = true;
> > +	}
> > +
> > +	if (!hit) {
> > +		if (free >= 8)
> > +			return -EFAULT;
> > +
> > +		desc_w = &mrc_dom->rgn_desc_words[free][0];
> > +
> > +		if (sec_access) {
> > +			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
> > +			writel(addr_end | 0x1, (void __iomem *)(desc_w + 1));
> > +		} else {
> > +			writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
> > +			writel((addr_end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static bool trdc_mrc_enabled(ulong trdc_base)
> > +{
> > +	return (!!(readl((void __iomem *)trdc_base) & 0x8000));
> > +}
> > +
> > +static int release_rdc(u8 xrdc)
> > +{
> > +	ulong s_mu_base = 0x47520000UL;
> > +	struct sentinel_msg msg;
> > +	int ret;
> > +	u32 rdc_id;
> > +
> > +	switch (xrdc) {
> > +	case 0:
> > +		rdc_id = 0x74;
> > +		break;
> > +	case 1:
> > +		rdc_id = 0x78;
> > +		break;
> > +	case 2:
> > +		rdc_id = 0x82;
> > +		break;
> > +	case 3:
> > +		rdc_id = 0x86;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	msg.version = AHAB_VERSION;
> > +	msg.tag = AHAB_CMD_TAG;
> > +	msg.size = 2;
> > +	msg.command = ELE_RELEASE_RDC_REQ;
> > +	msg.data[0] = (rdc_id << 8) | 0x2; /* A55 */
> > +
> > +	mu_hal_init(s_mu_base);
> > +	mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
> > +	mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
> > +
> > +	ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
> > +	if (ret)
> > +		return -EIO;
> > +
> > +	if ((msg.data[0] & 0xff) == 0xd6)
> > +		return 0;
> > +
> > +	return -EIO;
> > +}
> > +
> > +void imx9_trdc_init(void)
> > +{
> > +	unsigned long base = MX9_TRDC_NICMIX_BASE_ADDR;
> > +	int ret = 0, i;
> > +
> > +	ret |= release_rdc(0);
> > +	ret |= release_rdc(2);
> > +	ret |= release_rdc(1);
> > +	ret |= release_rdc(3);
> > +
> > +	if (ret)
> > +		return;
> > +
> > +	/* Set OCRAM to RWX for secure, when OEM_CLOSE, the image is RX only */
> > +	trdc_mbc_set_control(base, 3, 0, 0x7700);
> > +
> > +	for (i = 0; i < 40; i++)
> > +		trdc_mbc_blk_config(base, 3, 3, 0, i, true, 0);
> > +
> > +	for (i = 0; i < 40; i++)
> > +		trdc_mbc_blk_config(base, 3, 3, 1, i, true, 0);
> > +
> > +	for (i = 0; i < 40; i++)
> > +		trdc_mbc_blk_config(base, 3, 0, 0, i, true, 0);
> > +
> > +	for (i = 0; i < 40; i++)
> > +		trdc_mbc_blk_config(base, 3, 0, 1, i, true, 0);
> > +
> > +	/* TRDC mega */
> > +	if (!trdc_mrc_enabled(base))
> > +		return;
> > +
> > +	/* DDR */
> > +	trdc_mrc_set_control(base, 0, 0, 0x7777);
> > +	/* S400*/
> > +	trdc_mrc_region_config(base, 0, 0, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* MTR */
> > +	trdc_mrc_region_config(base, 0, 1, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* M33 */
> > +	trdc_mrc_region_config(base, 0, 2, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* A55*/
> > +	trdc_mrc_region_config(base, 0, 3, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* For USDHC1 to DDR, USDHC1 is default force to non-secure */
> > +	trdc_mrc_region_config(base, 0, 5, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* For USDHC2 to DDR, USDHC2 is default force to non-secure */
> > +	trdc_mrc_region_config(base, 0, 6, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* eDMA */
> > +	trdc_mrc_region_config(base, 0, 7, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* CoreSight, TestPort */
> > +	trdc_mrc_region_config(base, 0, 8, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* DAP */
> > +	trdc_mrc_region_config(base, 0, 9, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* SoC masters */
> > +	trdc_mrc_region_config(base, 0, 10, 0x80000000, 0xFFFFFFFF, false, 0);
> > +	/* USB */
> > +	trdc_mrc_region_config(base, 0, 11, 0x80000000, 0xFFFFFFFF, false, 0);
> > +}
> > diff --git a/include/soc/imx9/trdc.h b/include/soc/imx9/trdc.h
> > new file mode 100644
> > index 0000000000..624e267ab6
> > --- /dev/null
> > +++ b/include/soc/imx9/trdc.h
> > @@ -0,0 +1,11 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright 2022 NXP
> > + */
> > +
> > +#ifndef __ASM_ARCH_IMX9_TRDC_H
> > +#define __ASM_ARCH_IMX9_TRDC_H
> > +
> > +void imx9_trdc_init(void);
> > +
> > +#endif
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2023-11-13  8:13 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-10 12:57 [PATCH 00/25] Add i.MX93 support Sascha Hauer
2023-11-10 12:57 ` [PATCH 01/25] ARM: initial i.MX9 support Sascha Hauer
2023-11-10 12:57 ` [PATCH 02/25] ARM: i.MX: Add i.MX93 s4mu support Sascha Hauer
2023-11-13  7:25   ` Ahmad Fatoum
2023-11-10 12:57 ` [PATCH 03/25] ARM: i.MX: Add i.MX93 trdc support Sascha Hauer
2023-11-13  7:24   ` Ahmad Fatoum
2023-11-13  8:11     ` Sascha Hauer
2023-11-10 12:57 ` [PATCH 04/25] scripts: Add imx9image tool Sascha Hauer
2023-11-10 12:57 ` [PATCH 05/25] scripts: imx9image: Add PBL size option Sascha Hauer
2023-11-10 12:57 ` [PATCH 06/25] clk: Add i.MX93 clock support Sascha Hauer
2023-11-10 12:57 ` [PATCH 07/25] clk: imx: clk-fracn-gppll: make usable from PBL Sascha Hauer
2023-11-10 12:57 ` [PATCH 08/25] gpio-vf610: Add i.MX93 support Sascha Hauer
2023-11-10 12:57 ` [PATCH 09/25] iomux: " Sascha Hauer
2023-11-10 12:57 ` [PATCH 10/25] watchdog: Add ULP wdog support Sascha Hauer
2023-11-10 12:57 ` [PATCH 11/25] I2c: Add i2c_8bit_addr_from_msg() Sascha Hauer
2023-11-10 12:57 ` [PATCH 12/25] i2c: Add lpi2c support Sascha Hauer
2023-11-10 12:57 ` [PATCH 13/25] ARM: Add imx93.dtsi for USB Sascha Hauer
2023-11-10 12:57 ` [PATCH 14/25] serial: Add lpuart32 driver Sascha Hauer
2023-11-10 12:57 ` [PATCH 15/25] ARM: i.MX: add i.MX9 debug_ll support Sascha Hauer
2023-11-10 12:57 ` [PATCH 16/25] ARM: Add TQ MBA9XXXCA board support Sascha Hauer
2023-11-10 12:57 ` [PATCH 17/25] ARM: i.MX93: Add DDR size read support Sascha Hauer
2023-11-10 12:57 ` [PATCH 18/25] ARM: i.MX: romapi: rename functions to *romapi* Sascha Hauer
2023-11-10 12:57 ` [PATCH 19/25] ARM: i.MX: romapi: Implement i.MX93 support Sascha Hauer
2023-11-10 12:57 ` [PATCH 20/25] ARM: i.MX: atf: add imx93_load_and_start_image_via_tfa() Sascha Hauer
2023-11-10 12:57 ` [PATCH 21/25] imx-usb-loader: Add i.MX9 support Sascha Hauer
2023-11-10 12:57 ` [PATCH 22/25] spi: spi-nxp-fspi: Enable for i.MX9 Sascha Hauer
2023-11-10 12:57 ` [PATCH 23/25] usb: i.MX chipidea: Enable usbmisc driver " Sascha Hauer
2023-11-10 12:57 ` [PATCH 24/25] ARM: Update imx_v8_defconfig Sascha Hauer
2023-11-10 12:58 ` [PATCH 25/25] ARM: multi_v8_defconfig: enable i.MX9 boards Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox