[PATCH 7/9] ddr: imx8m: ddrphy_train: add DDR4 support
Ahmad Fatoum
a.fatoum at pengutronix.de
Sun Sep 5 06:51:20 PDT 2021
There are DDR3L, DDR4 and LPDDR4 variants of the i.MX8M* SoMs used with
the NXP EVKs. So far, we only supported LPDDR4. For DDR4, we just need
different PHY training code. Encode the DRAM variant information
into a new dram_timing_info::dram_type and adjust the driver to make use
of it. The new CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN Kconfig symbol can
co-exist with CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN, allowing the same
barebox binary to target different memory types, provided board code
can determine what kind of DRAM is fitted.
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
arch/arm/boards/mnt-reform/lpddr4-timing.c | 1 +
.../arm/boards/nxp-imx8mm-evk/lpddr4-timing.c | 1 +
.../arm/boards/nxp-imx8mp-evk/lpddr4-timing.c | 1 +
arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 6 ++---
.../boards/phytec-som-imx8mq/ddrphy_train.c | 6 ++---
.../protonic-imx8m/lpddr4-timing-prt8mm.c | 1 +
arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c | 6 ++---
drivers/ddr/imx8m/ddrphy_train.c | 26 ++++++++++++++-----
firmware/Kconfig | 3 +++
firmware/Makefile | 6 +++++
include/soc/imx8m/ddr.h | 20 +++++++++++++-
11 files changed, 60 insertions(+), 17 deletions(-)
diff --git a/arch/arm/boards/mnt-reform/lpddr4-timing.c b/arch/arm/boards/mnt-reform/lpddr4-timing.c
index 0b5853000d03..0e962890fde2 100644
--- a/arch/arm/boards/mnt-reform/lpddr4-timing.c
+++ b/arch/arm/boards/mnt-reform/lpddr4-timing.c
@@ -1000,6 +1000,7 @@ static struct dram_fsp_msg mnt_reform_lpddr4_dram_fsp_msg[] = {
/* ddr timing config params */
struct dram_timing_info mnt_reform_dram_timing = {
+ .dram_type = DRAM_TYPE_LPDDR4,
.ddrc_cfg = mnt_reform_lpddr4_ddrc_cfg,
.ddrc_cfg_num = ARRAY_SIZE(mnt_reform_lpddr4_ddrc_cfg),
.ddrphy_cfg = mnt_reform_lpddr4_ddrphy_cfg,
diff --git a/arch/arm/boards/nxp-imx8mm-evk/lpddr4-timing.c b/arch/arm/boards/nxp-imx8mm-evk/lpddr4-timing.c
index e7c01f9cc9a0..68efbbdf917b 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/lpddr4-timing.c
+++ b/arch/arm/boards/nxp-imx8mm-evk/lpddr4-timing.c
@@ -1965,6 +1965,7 @@ static struct dram_fsp_msg lpddr4_dram_fsp_msg[] = {
/* lpddr4 timing config params on EVK board */
struct dram_timing_info imx8mm_evk_dram_timing = {
+ .dram_type = DRAM_TYPE_LPDDR4,
.ddrc_cfg = lpddr4_ddrc_cfg,
.ddrc_cfg_num = ARRAY_SIZE(lpddr4_ddrc_cfg),
.ddrphy_cfg = lpddr4_ddrphy_cfg,
diff --git a/arch/arm/boards/nxp-imx8mp-evk/lpddr4-timing.c b/arch/arm/boards/nxp-imx8mp-evk/lpddr4-timing.c
index 3028bc084c73..681e70d06022 100644
--- a/arch/arm/boards/nxp-imx8mp-evk/lpddr4-timing.c
+++ b/arch/arm/boards/nxp-imx8mp-evk/lpddr4-timing.c
@@ -1834,6 +1834,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg[] = {
/* ddr timing config params */
struct dram_timing_info imx8mp_evk_dram_timing = {
+ .dram_type = DRAM_TYPE_LPDDR4,
.ddrc_cfg = ddr_ddrc_cfg,
.ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg),
.ddrphy_cfg = ddr_ddrphy_cfg,
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
index 1b30ff725797..d2c73fc7ce22 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
@@ -142,7 +142,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 1D training image
- ddr_load_train_code(FW_1D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
//configure DDRPHY-FW DMEM structure @clock0...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
@@ -289,7 +289,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 2D training image
- ddr_load_train_code(FW_2D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
@@ -932,4 +932,4 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x2006e, 0x0);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
-}
\ No newline at end of file
+}
diff --git a/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c b/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
index cc0052764971..2c84a0f5fd5a 100644
--- a/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
+++ b/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
@@ -146,7 +146,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 1D training image
- ddr_load_train_code(FW_1D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54004,0x2);
@@ -222,7 +222,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 1D training image
- ddr_load_train_code(FW_1D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54002,0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0x29c);
@@ -298,7 +298,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 2D training image
- ddr_load_train_code(FW_2D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54004,0x2);
diff --git a/arch/arm/boards/protonic-imx8m/lpddr4-timing-prt8mm.c b/arch/arm/boards/protonic-imx8m/lpddr4-timing-prt8mm.c
index 2c55e7d45144..ea5c0b915437 100644
--- a/arch/arm/boards/protonic-imx8m/lpddr4-timing-prt8mm.c
+++ b/arch/arm/boards/protonic-imx8m/lpddr4-timing-prt8mm.c
@@ -1981,6 +1981,7 @@ static struct dram_fsp_msg lpddr4_dram_fsp_msg[] = {
/* lpddr4 timing config params on EVK board */
struct dram_timing_info prt8mm_dram_timing = {
+ .dram_type = DRAM_TYPE_LPDDR4,
.ddrc_cfg = lpddr4_ddrc_cfg,
.ddrc_cfg_num = ARRAY_SIZE(lpddr4_ddrc_cfg),
.ddrphy_cfg = lpddr4_ddrphy_cfg,
diff --git a/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
index 1b30ff725797..d2c73fc7ce22 100644
--- a/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
+++ b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
@@ -142,7 +142,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 1D training image
- ddr_load_train_code(FW_1D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
//configure DDRPHY-FW DMEM structure @clock0...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
@@ -289,7 +289,7 @@ void ddr_cfg_phy(void) {
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 2D training image
- ddr_load_train_code(FW_2D_IMAGE);
+ ddr_load_train_code(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
@@ -932,4 +932,4 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x2006e, 0x0);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
-}
\ No newline at end of file
+}
diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c
index a4677f903c6b..d930a2fffe44 100644
--- a/drivers/ddr/imx8m/ddrphy_train.c
+++ b/drivers/ddr/imx8m/ddrphy_train.c
@@ -11,17 +11,29 @@
#include <firmware.h>
#include <mach/imx8m-regs.h>
-void ddr_load_train_code(enum fw_type type)
+void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type)
{
const u16 *imem, *dmem;
size_t isize, dsize;
- if (type == FW_1D_IMAGE) {
- get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &imem, &isize);
- get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &dmem, &dsize);
+ if (dram_is_lpddr4(dram_type)) {
+ if (fw_type == FW_1D_IMAGE) {
+ get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &imem, &isize);
+ get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &dmem, &dsize);
+ } else {
+ get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize);
+ get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize);
+ }
+ } else if (dram_is_ddr4(dram_type)) {
+ if (fw_type == FW_1D_IMAGE) {
+ get_builtin_firmware(ddr4_imem_1d_bin, &imem, &isize);
+ get_builtin_firmware(ddr4_dmem_1d_bin, &dmem, &dsize);
+ } else {
+ get_builtin_firmware(ddr4_imem_2d_bin, &imem, &isize);
+ get_builtin_firmware(ddr4_dmem_2d_bin, &dmem, &dsize);
+ }
} else {
- get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize);
- get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize);
+ panic("No matching DDR PHY firmware found");
}
ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
@@ -58,7 +70,7 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type)
/* load the dram training firmware image */
dwc_ddrphy_apb_wr(0xd0000, 0x0);
- ddr_load_train_code(fsp_msg->fw_type);
+ ddr_load_train_code(dram_timing->dram_type, fsp_msg->fw_type);
/* load the frequency set point message block parameter */
dram_cfg = fsp_msg->fsp_cfg;
diff --git a/firmware/Kconfig b/firmware/Kconfig
index 16acab7c5f08..b44753892776 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -7,6 +7,9 @@ config EXTRA_FIRMWARE_DIR
config FIRMWARE_IMX_LPDDR4_PMU_TRAIN
bool
+config FIRMWARE_IMX_DDR4_PMU_TRAIN
+ bool
+
config FIRMWARE_IMX8MM_ATF
bool
diff --git a/firmware/Makefile b/firmware/Makefile
index e3fe8d604f13..8873f5178d33 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -6,6 +6,12 @@ firmware-$(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) += \
lpddr4_pmu_train_2d_dmem.bin \
lpddr4_pmu_train_2d_imem.bin
+firmware-$(CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN) += \
+ ddr4_dmem_1d.bin \
+ ddr4_dmem_2d.bin \
+ ddr4_imem_1d.bin \
+ ddr4_imem_2d.bin
+
firmware-$(CONFIG_FIRMWARE_IMX8MM_ATF) += imx8mm-bl31.bin
firmware-$(CONFIG_FIRMWARE_IMX8MN_ATF) += imx8mn-bl31.bin
firmware-$(CONFIG_FIRMWARE_IMX8MP_ATF) += imx8mp-bl31.bin
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index a25274c57671..9ae7cb877686 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -329,6 +329,11 @@ enum fw_type {
FW_2D_IMAGE,
};
+enum dram_type {
+ DRAM_TYPE_LPDDR4,
+ DRAM_TYPE_DDR4,
+};
+
struct dram_cfg_param {
unsigned int reg;
unsigned int val;
@@ -342,6 +347,7 @@ struct dram_fsp_msg {
};
struct dram_timing_info {
+ enum dram_type dram_type;
/* umctl2 config */
struct dram_cfg_param *ddrc_cfg;
unsigned int ddrc_cfg_num;
@@ -409,12 +415,24 @@ enum ddrc_phy_firmware_offset {
DDRC_PHY_DMEM = 0x00054000U,
};
-void ddr_load_train_code(enum fw_type type);
+void ddr_load_train_code(enum dram_type dram_type, enum fw_type type);
void ddrc_phy_load_firmware(void __iomem *,
enum ddrc_phy_firmware_offset,
const u16 *, size_t);
+static inline bool dram_is_lpddr4(enum dram_type type)
+{
+ return IS_ENABLED(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) &&
+ type == DRAM_TYPE_LPDDR4;
+}
+
+static inline bool dram_is_ddr4(enum dram_type type)
+{
+ return IS_ENABLED(CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN) &&
+ type == DRAM_TYPE_DDR4;
+}
+
#define DDRC_PHY_REG(x) ((x) * 4)
#endif
--
2.30.2
More information about the barebox
mailing list