* [PATCH 01/13] ddr: imx8m: rename driver to imx
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 02/13] ddr: imx8m: introduce dram_controller struct Sascha Hauer
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
The i.MX8M ddr driver can be re-used for i.MX93, so drop the '8m' suffix
from the driver directories and Kconfig options.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/Kconfig | 2 +-
drivers/ddr/Makefile | 2 +-
drivers/ddr/{imx8m => imx}/Kconfig | 6 +++++-
drivers/ddr/imx/Makefile | 7 +++++++
drivers/ddr/{imx8m => imx}/ddrphy_csr.c | 0
drivers/ddr/{imx8m => imx}/ddrphy_train.c | 0
drivers/ddr/{imx8m => imx}/ddrphy_utils.c | 0
drivers/ddr/{imx8m => imx}/helper.c | 0
drivers/ddr/{imx8m/ddr_init.c => imx/imx8m_ddr_init.c} | 0
drivers/ddr/imx8m/Makefile | 7 -------
10 files changed, 14 insertions(+), 10 deletions(-)
rename drivers/ddr/{imx8m => imx}/Kconfig (72%)
create mode 100644 drivers/ddr/imx/Makefile
rename drivers/ddr/{imx8m => imx}/ddrphy_csr.c (100%)
rename drivers/ddr/{imx8m => imx}/ddrphy_train.c (100%)
rename drivers/ddr/{imx8m => imx}/ddrphy_utils.c (100%)
rename drivers/ddr/{imx8m => imx}/helper.c (100%)
rename drivers/ddr/{imx8m/ddr_init.c => imx/imx8m_ddr_init.c} (100%)
delete mode 100644 drivers/ddr/imx8m/Makefile
diff --git a/drivers/ddr/Kconfig b/drivers/ddr/Kconfig
index 17d01ab658..0b0d7a8893 100644
--- a/drivers/ddr/Kconfig
+++ b/drivers/ddr/Kconfig
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
source "drivers/ddr/fsl/Kconfig"
-source "drivers/ddr/imx8m/Kconfig"
+source "drivers/ddr/imx/Kconfig"
diff --git a/drivers/ddr/Makefile b/drivers/ddr/Makefile
index 0b5ac949a4..e5d7bd14db 100644
--- a/drivers/ddr/Makefile
+++ b/drivers/ddr/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DDR_FSL) += fsl/
-obj-$(CONFIG_IMX8M_DRAM) += imx8m/
+obj-$(CONFIG_IMX_DRAM) += imx/
diff --git a/drivers/ddr/imx8m/Kconfig b/drivers/ddr/imx/Kconfig
similarity index 72%
rename from drivers/ddr/imx8m/Kconfig
rename to drivers/ddr/imx/Kconfig
index 720448f551..43e9181582 100644
--- a/drivers/ddr/imx8m/Kconfig
+++ b/drivers/ddr/imx/Kconfig
@@ -1,8 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
-menu "i.MX8M DDR controllers"
+menu "i.MX DDR controllers"
depends on ARCH_IMX8MQ || ARCH_IMX8MM || ARCH_IMX8MN || ARCH_IMX8MP
+config IMX_DRAM
+ bool
+
config IMX8M_DRAM
+ select IMX_DRAM
bool "imx8m dram controller support"
endmenu
diff --git a/drivers/ddr/imx/Makefile b/drivers/ddr/imx/Makefile
new file mode 100644
index 0000000000..62d09e731a
--- /dev/null
+++ b/drivers/ddr/imx/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2018 NXP
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+pbl-$(CONFIG_IMX_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o
+pbl-$(CONFIG_IMX8M_DRAM) += imx8m_ddr_init.o
diff --git a/drivers/ddr/imx8m/ddrphy_csr.c b/drivers/ddr/imx/ddrphy_csr.c
similarity index 100%
rename from drivers/ddr/imx8m/ddrphy_csr.c
rename to drivers/ddr/imx/ddrphy_csr.c
diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
similarity index 100%
rename from drivers/ddr/imx8m/ddrphy_train.c
rename to drivers/ddr/imx/ddrphy_train.c
diff --git a/drivers/ddr/imx8m/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
similarity index 100%
rename from drivers/ddr/imx8m/ddrphy_utils.c
rename to drivers/ddr/imx/ddrphy_utils.c
diff --git a/drivers/ddr/imx8m/helper.c b/drivers/ddr/imx/helper.c
similarity index 100%
rename from drivers/ddr/imx8m/helper.c
rename to drivers/ddr/imx/helper.c
diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
similarity index 100%
rename from drivers/ddr/imx8m/ddr_init.c
rename to drivers/ddr/imx/imx8m_ddr_init.c
diff --git a/drivers/ddr/imx8m/Makefile b/drivers/ddr/imx8m/Makefile
deleted file mode 100644
index 2be313900f..0000000000
--- a/drivers/ddr/imx8m/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Copyright 2018 NXP
-#
-# SPDX-License-Identifier: GPL-2.0+
-#
-
-pbl-$(CONFIG_IMX8M_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o ddr_init.o
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 02/13] ddr: imx8m: introduce dram_controller struct
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
2023-11-10 13:00 ` [PATCH 01/13] ddr: imx8m: rename driver to imx Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 03/13] ddr: imx8m: move get_trained_CDD() to SoC code Sascha Hauer
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Upcoming i.MX9 support will need to implement some functions
differently. Introduce a struct dram_controller to be able
to abstract these differences later. For now only add a few
members, more will come in later patches.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_train.c | 8 +++-----
drivers/ddr/imx/imx8m_ddr_init.c | 16 ++++++++--------
include/soc/imx8m/ddr.h | 32 +++++++++++++++++++++++++-------
3 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index 6a98fa0545..1683ffd9a8 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -93,10 +93,8 @@ void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type)
DDRC_PHY_DMEM, dmem, dsize);
}
-int ddr_cfg_phy(struct dram_timing_info *dram_timing, unsigned type)
+int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timing)
{
- enum ddrc_type ddrc_type = get_ddrc_type(type);
- enum dram_type dram_type = get_dram_type(type);
struct dram_cfg_param *dram_cfg;
struct dram_fsp_msg *fsp_msg;
unsigned int num;
@@ -118,11 +116,11 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing, unsigned type)
for (i = 0; i < dram_timing->fsp_msg_num; i++) {
pr_debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
/* set dram PHY input clocks to desired frequency */
- ddrphy_init_set_dfi_clk(fsp_msg->drate, ddrc_type);
+ ddrphy_init_set_dfi_clk(fsp_msg->drate, dram->ddrc_type);
/* load the dram training firmware image */
dwc_ddrphy_apb_wr(0xd0000, 0x0);
- ddr_load_train_code(dram_type, fsp_msg->fw_type);
+ ddr_load_train_code(dram->dram_type, fsp_msg->fw_type);
/* load the frequency set point message block parameter */
dram_cfg = fsp_msg->fsp_cfg;
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index 9a86280d9c..8acacfac35 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -15,6 +15,8 @@
bool imx8m_ddr_old_spreadsheet = true;
+struct dram_controller imx8m_dram_controller;
+
static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
{
int i = 0;
@@ -49,18 +51,16 @@ static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
*/
#define IMX8M_SAVED_DRAM_TIMING_BASE 0x180000
-int imx8m_ddr_init(struct dram_timing_info *dram_timing,
- unsigned type)
+int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_timing)
{
unsigned long src_ddrc_rcr = MX8M_SRC_DDRC_RCR_ADDR;
unsigned int tmp, initial_drate, target_freq;
- enum ddrc_type ddrc_type = get_ddrc_type(type);
int ret;
pr_debug("start DRAM init\n");
/* Step1: Follow the power up procedure */
- switch (ddrc_type) {
+ switch (dram->ddrc_type) {
case DDRC_TYPE_MQ:
reg32_write(src_ddrc_rcr + 0x04, 0x8f00000f);
reg32_write(src_ddrc_rcr, 0x8f00000f);
@@ -82,7 +82,7 @@ int imx8m_ddr_init(struct dram_timing_info *dram_timing,
initial_drate = dram_timing->fsp_msg[0].drate;
/* default to the frequency point 0 clock */
- ddrphy_init_set_dfi_clk(initial_drate, ddrc_type);
+ ddrphy_init_set_dfi_clk(initial_drate, dram->ddrc_type);
/* D-aasert the presetn */
reg32_write(src_ddrc_rcr, 0x8F000006);
@@ -112,7 +112,7 @@ int imx8m_ddr_init(struct dram_timing_info *dram_timing,
* might not have been called
*/
tmp = reg32_read(DDRC_MSTR(0));
- if (tmp & (0x1 << 5) && ddrc_type != DDRC_TYPE_MN)
+ if (tmp & (0x1 << 5) && dram->ddrc_type != DDRC_TYPE_MN)
reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
/* determine the initial boot frequency */
@@ -139,7 +139,7 @@ int imx8m_ddr_init(struct dram_timing_info *dram_timing,
*/
pr_debug("ddrphy config start\n");
- ret = ddr_cfg_phy(dram_timing, type);
+ ret = ddr_cfg_phy(dram, dram_timing);
if (ret)
return ret;
@@ -159,7 +159,7 @@ int imx8m_ddr_init(struct dram_timing_info *dram_timing,
reg32_write(DDRC_SWCTL(0), 0x00000000);
/* Apply rank-to-rank workaround */
- update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1, ddrc_type);
+ update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1, dram->ddrc_type);
/* Step16: Set DFIMISC.dfi_init_start to 1 */
setbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index e268892957..18d7c96193 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -384,6 +384,11 @@ struct dram_timing_info {
unsigned int fsp_table[4];
};
+struct dram_controller {
+ enum ddrc_type ddrc_type;
+ enum dram_type dram_type;
+};
+
extern struct dram_timing_info dram_timing;
void ddr_get_firmware_lpddr4(void);
@@ -397,42 +402,55 @@ static inline void ddr_get_firmware(enum dram_type dram_type)
ddr_get_firmware_ddr();
}
-int imx8m_ddr_init(struct dram_timing_info *dram_timing,
- unsigned type);
+int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_timing);
+
+extern struct dram_controller imx8m_dram_controller;
static inline int imx8mm_ddr_init(struct dram_timing_info *dram_timing,
enum dram_type dram_type)
{
+ imx8m_dram_controller.ddrc_type = DDRC_TYPE_MM;
+ imx8m_dram_controller.dram_type = dram_type;
+
ddr_get_firmware(dram_type);
- return imx8m_ddr_init(dram_timing, DDRC_TYPE_MM | dram_type);
+ return imx8m_ddr_init(&imx8m_dram_controller, dram_timing);
}
static inline int imx8mn_ddr_init(struct dram_timing_info *dram_timing,
enum dram_type dram_type)
{
+ imx8m_dram_controller.ddrc_type = DDRC_TYPE_MN;
+ imx8m_dram_controller.dram_type = dram_type;
+
ddr_get_firmware(dram_type);
- return imx8m_ddr_init(dram_timing, DDRC_TYPE_MN | dram_type);
+ return imx8m_ddr_init(&imx8m_dram_controller, dram_timing);
}
static inline int imx8mq_ddr_init(struct dram_timing_info *dram_timing,
enum dram_type dram_type)
{
+ imx8m_dram_controller.ddrc_type = DDRC_TYPE_MQ;
+ imx8m_dram_controller.dram_type = dram_type;
+
ddr_get_firmware(dram_type);
- return imx8m_ddr_init(dram_timing, DDRC_TYPE_MQ | dram_type);
+ return imx8m_ddr_init(&imx8m_dram_controller, dram_timing);
}
static inline int imx8mp_ddr_init(struct dram_timing_info *dram_timing,
enum dram_type dram_type)
{
+ imx8m_dram_controller.ddrc_type = DDRC_TYPE_MP;
+ imx8m_dram_controller.dram_type = dram_type;
+
ddr_get_firmware(dram_type);
- return imx8m_ddr_init(dram_timing, DDRC_TYPE_MP | dram_type);
+ return imx8m_ddr_init(&imx8m_dram_controller, dram_timing);
}
-int ddr_cfg_phy(struct dram_timing_info *timing_info, unsigned type);
+int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
void load_lpddr4_phy_pie(void);
void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num);
void dram_config_save(struct dram_timing_info *info, unsigned long base);
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 03/13] ddr: imx8m: move get_trained_CDD() to SoC code
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
2023-11-10 13:00 ` [PATCH 01/13] ddr: imx8m: rename driver to imx Sascha Hauer
2023-11-10 13:00 ` [PATCH 02/13] ddr: imx8m: introduce dram_controller struct Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 04/13] ddr: imx8m: move PLL init to SoC specific code Sascha Hauer
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
get_trained_CDD() will be implemented differently on i.MX9, so move
the function to the i.MX8M specific file and add a hook to struct
dram_controller.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_train.c | 2 +-
drivers/ddr/imx/ddrphy_utils.c | 169 ------------------------------
drivers/ddr/imx/imx8m_ddr_init.c | 171 +++++++++++++++++++++++++++++++
include/soc/imx8m/ddr.h | 5 +-
4 files changed, 173 insertions(+), 174 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index 1683ffd9a8..36fb6d3c11 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -159,7 +159,7 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
ddrphy_init_read_msg_block(fsp_msg->fw_type);
if (fsp_msg->fw_type != FW_2D_IMAGE)
- get_trained_CDD(i);
+ dram->get_trained_CDD(dram, i);
dwc_ddrphy_apb_wr(0xd0000, 0x1);
diff --git a/drivers/ddr/imx/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
index 353a265136..db94b85b74 100644
--- a/drivers/ddr/imx/ddrphy_utils.c
+++ b/drivers/ddr/imx/ddrphy_utils.c
@@ -362,172 +362,3 @@ void ddrphy_init_set_dfi_clk(unsigned int drate_mhz, enum ddrc_type type)
void ddrphy_init_read_msg_block(enum fw_type type)
{
}
-
-static unsigned int g_cdd_rr_max[4];
-static unsigned int g_cdd_rw_max[4];
-static unsigned int g_cdd_wr_max[4];
-static unsigned int g_cdd_ww_max[4];
-
-static unsigned int look_for_max(unsigned int data[], unsigned int addr_start,
- unsigned int addr_end)
-{
- unsigned int i, imax = 0;
-
- for (i = addr_start; i <= addr_end; i++) {
- if (((data[i] >> 7) == 0) && (data[i] > imax))
- imax = data[i];
- }
-
- return imax;
-}
-
-void get_trained_CDD(u32 fsp)
-{
- unsigned int i, ddr_type, tmp;
- unsigned int cdd_cha[12], cdd_chb[12];
- unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
- unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
-
- ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
- if (ddr_type == 0x20) {
- for (i = 0; i < 6; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x54013UL + i) * 4);
- cdd_cha[i * 2] = tmp & 0xff;
- cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
- }
-
- for (i = 0; i < 7; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x5402cUL + i) * 4);
- if (i == 0) {
- cdd_cha[0] = (tmp >> 8) & 0xff;
- } else if (i == 6) {
- cdd_cha[11] = tmp & 0xff;
- } else {
- cdd_chb[ i * 2 - 1] = tmp & 0xff;
- cdd_chb[i * 2] = (tmp >> 8) & 0xff;
- }
- }
-
- cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
- cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
- cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
- cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
- cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
- cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
- cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
- cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
- g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
- g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
- g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
- g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
- } else {
- unsigned int ddr4_cdd[64];
-
- for( i = 0; i < 29; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x54012UL + i) * 4);
- ddr4_cdd[i * 2] = tmp & 0xff;
- ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
- }
-
- g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12);
- g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24);
- g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40);
- g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56);
- }
-}
-
-void update_umctl2_rank_space_setting(unsigned int pstat_num,
- enum ddrc_type type)
-{
- unsigned int i,ddr_type;
- unsigned int rdata, tmp, tmp_t;
- unsigned int ddrc_w2r,ddrc_r2w,ddrc_wr_gap,ddrc_rd_gap;
- unsigned long addr_slot;
-
- ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
- for (i = 0; i < pstat_num; i++) {
- addr_slot = i ? (i + 1) * 0x1000 : 0;
- if (ddr_type == 0x20) {
- /* update r2w:[13:8], w2r:[5:0] */
- rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
- ddrc_w2r = rdata & 0x3f;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
- else
- tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
- ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
-
- ddrc_r2w = (rdata >> 8) & 0x3f;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
- else
- tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
- ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
-
- tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r;
- reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
- } else {
- /* update w2r:[5:0] */
- rdata = reg32_read(DDRC_DRAMTMG9(0) + addr_slot);
- ddrc_w2r = rdata & 0x3f;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
- else
- tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
- ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
- tmp_t = (rdata & 0xffffffc0) | ddrc_w2r;
- reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t);
-
- /* update r2w:[13:8] */
- rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
- ddrc_r2w = (rdata >> 8) & 0x3f;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
- else
- tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
- ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
-
- tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8);
- reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
- }
-
- if (type != DDRC_TYPE_MQ) {
- /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
- rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot);
- ddrc_wr_gap = (rdata >> 8) & 0xf;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1);
- else
- tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1;
- ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
-
- ddrc_rd_gap = (rdata >> 4) & 0xf;
- if (type == DDRC_TYPE_MP)
- tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1);
- else
- tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1;
- ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
-
- tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
- reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t);
- }
- }
-
- if (type == DDRC_TYPE_MQ) {
- /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
- rdata = reg32_read(DDRC_RANKCTL(0));
- ddrc_wr_gap = (rdata >> 8) & 0xf;
- tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1;
- ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
-
- ddrc_rd_gap = (rdata >> 4) & 0xf;
- tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1;
- ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
-
- tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
- reg32_write(DDRC_RANKCTL(0), tmp_t);
- }
-}
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index 8acacfac35..1e704ef8fc 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -43,6 +43,175 @@ static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
}
}
+static unsigned int g_cdd_rr_max[4];
+static unsigned int g_cdd_rw_max[4];
+static unsigned int g_cdd_wr_max[4];
+static unsigned int g_cdd_ww_max[4];
+
+static unsigned int look_for_max(unsigned int data[], unsigned int addr_start,
+ unsigned int addr_end)
+{
+ unsigned int i, imax = 0;
+
+ for (i = addr_start; i <= addr_end; i++) {
+ if (((data[i] >> 7) == 0) && (data[i] > imax))
+ imax = data[i];
+ }
+
+ return imax;
+}
+
+static void get_trained_CDD(struct dram_controller *dram, u32 fsp)
+{
+ unsigned int i, ddr_type, tmp;
+ unsigned int cdd_cha[12], cdd_chb[12];
+ unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
+ unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
+
+ ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+ if (ddr_type == 0x20) {
+ for (i = 0; i < 6; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
+ (0x54013UL + i) * 4);
+ cdd_cha[i * 2] = tmp & 0xff;
+ cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
+ }
+
+ for (i = 0; i < 7; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
+ (0x5402cUL + i) * 4);
+ if (i == 0) {
+ cdd_cha[0] = (tmp >> 8) & 0xff;
+ } else if (i == 6) {
+ cdd_cha[11] = tmp & 0xff;
+ } else {
+ cdd_chb[ i * 2 - 1] = tmp & 0xff;
+ cdd_chb[i * 2] = (tmp >> 8) & 0xff;
+ }
+ }
+
+ cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
+ cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
+ cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
+ cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
+ cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
+ cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
+ cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
+ cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
+ g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
+ g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
+ g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
+ g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
+ } else {
+ unsigned int ddr4_cdd[64];
+
+ for( i = 0; i < 29; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
+ (0x54012UL + i) * 4);
+ ddr4_cdd[i * 2] = tmp & 0xff;
+ ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
+ }
+
+ g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12);
+ g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24);
+ g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40);
+ g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56);
+ }
+}
+
+static void update_umctl2_rank_space_setting(unsigned int pstat_num,
+ enum ddrc_type type)
+{
+ unsigned int i,ddr_type;
+ unsigned int rdata, tmp, tmp_t;
+ unsigned int ddrc_w2r,ddrc_r2w,ddrc_wr_gap,ddrc_rd_gap;
+ unsigned long addr_slot;
+
+ ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+ for (i = 0; i < pstat_num; i++) {
+ addr_slot = i ? (i + 1) * 0x1000 : 0;
+ if (ddr_type == 0x20) {
+ /* update r2w:[13:8], w2r:[5:0] */
+ rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+ ddrc_w2r = rdata & 0x3f;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+ else
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+ ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+
+ ddrc_r2w = (rdata >> 8) & 0x3f;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+ else
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+ ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+ tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r;
+ reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+ } else {
+ /* update w2r:[5:0] */
+ rdata = reg32_read(DDRC_DRAMTMG9(0) + addr_slot);
+ ddrc_w2r = rdata & 0x3f;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+ else
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+ ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+ tmp_t = (rdata & 0xffffffc0) | ddrc_w2r;
+ reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t);
+
+ /* update r2w:[13:8] */
+ rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+ ddrc_r2w = (rdata >> 8) & 0x3f;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+ else
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+ ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+ tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8);
+ reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+ }
+
+ if (type != DDRC_TYPE_MQ) {
+ /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
+ rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot);
+ ddrc_wr_gap = (rdata >> 8) & 0xf;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1);
+ else
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1;
+ ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ ddrc_rd_gap = (rdata >> 4) & 0xf;
+ if (type == DDRC_TYPE_MP)
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1);
+ else
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1;
+ ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+ reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t);
+ }
+ }
+
+ if (type == DDRC_TYPE_MQ) {
+ /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
+ rdata = reg32_read(DDRC_RANKCTL(0));
+ ddrc_wr_gap = (rdata >> 8) & 0xf;
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1;
+ ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ ddrc_rd_gap = (rdata >> 4) & 0xf;
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1;
+ ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+ reg32_write(DDRC_RANKCTL(0), tmp_t);
+ }
+}
+
/*
* We store the timing parameters here. the TF-A will pick these up.
* Note that the timing used we leave the driver with is a PLL bypass 25MHz
@@ -59,6 +228,8 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
pr_debug("start DRAM init\n");
+ dram->get_trained_CDD = get_trained_CDD;
+
/* Step1: Follow the power up procedure */
switch (dram->ddrc_type) {
case DDRC_TYPE_MQ:
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index 18d7c96193..c89dfe78cf 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -387,6 +387,7 @@ struct dram_timing_info {
struct dram_controller {
enum ddrc_type ddrc_type;
enum dram_type dram_type;
+ void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
};
extern struct dram_timing_info dram_timing;
@@ -460,10 +461,6 @@ int wait_ddrphy_training_complete(void);
void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type ddrc_type);
void ddrphy_init_read_msg_block(enum fw_type fw_type);
-void update_umctl2_rank_space_setting(unsigned int pstat_num,
- enum ddrc_type ddrc_type);
-void get_trained_CDD(unsigned int fsp);
-
#define reg32_write(a, v) writel(v, a)
#define reg32_read(a) readl(a)
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 04/13] ddr: imx8m: move PLL init to SoC specific code
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (2 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 03/13] ddr: imx8m: move get_trained_CDD() to SoC code Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 05/13] ddr: imx8m: clean up defines Sascha Hauer
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
The PLL initialization will be different on i.MX9, so move the
code to the i.MX8M specific file and a add a function hook to
struct dram_controller.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_train.c | 2 +-
drivers/ddr/imx/ddrphy_utils.c | 257 ------------------------------
drivers/ddr/imx/imx8m_ddr_init.c | 261 ++++++++++++++++++++++++++++++-
include/soc/imx8m/ddr.h | 2 +-
4 files changed, 262 insertions(+), 260 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index 36fb6d3c11..b44f5ef9b4 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -116,7 +116,7 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
for (i = 0; i < dram_timing->fsp_msg_num; i++) {
pr_debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
/* set dram PHY input clocks to desired frequency */
- ddrphy_init_set_dfi_clk(fsp_msg->drate, dram->ddrc_type);
+ dram->set_dfi_clk(dram, fsp_msg->drate);
/* load the dram training firmware image */
dwc_ddrphy_apb_wr(0xd0000, 0x0);
diff --git a/drivers/ddr/imx/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
index db94b85b74..4577547113 100644
--- a/drivers/ddr/imx/ddrphy_utils.c
+++ b/drivers/ddr/imx/ddrphy_utils.c
@@ -13,111 +13,6 @@
#include <mach/imx/imx8m-regs.h>
#include <mach/imx/imx8m-ccm-regs.h>
-/* DDR Transfer rate, bus clock is transfer rate / 2, and the DDRC runs at bus
- * clock / 2, which is therefor transfer rate / 4. */
-enum ddr_rate {
- DDR_4000,
- DDR_3720,
- DDR_3200,
- DDR_3000,
- DDR_2600, /* Unused */
- DDR_2400,
- DDR_2376, /* Unused */
- DDR_1600,
- DDR_1000, /* Unused */
- DDR_1066,
- DDR_667,
- DDR_400,
- DDR_250, /* Unused */
- DDR_100,
- DDR_NUM_RATES
-};
-
-/* PLL config for IMX8MM type DRAM PLL. This PLL type isn't documented, but
- * it looks like it is a basically a fractional PLL:
- * Frequency = Ref (24 MHz) / P * M / 2^S
- * Note: Divider is equal to register value
- */
-#define MDIV(x) ((x) << 12)
-#define PDIV(x) ((x) << 4)
-#define SDIV(x) ((x) << 0)
-
-#define LOCK_STATUS BIT(31)
-#define LOCK_SEL_MASK BIT(29)
-#define CLKE_MASK BIT(11)
-#define RST_MASK BIT(9)
-#define BYPASS_MASK BIT(4)
-
-static const struct imx8mm_fracpll_config {
- uint32_t r1, r2;
- bool valid;
-} imx8mm_fracpll_table[DDR_NUM_RATES] = {
- [DDR_4000] = { .valid = true, .r1 = MDIV(250) | PDIV(3) | SDIV(1), .r2 = 0 },
- [DDR_3720] = { .valid = true, .r1 = MDIV(310) | PDIV(2) | SDIV(2), .r2 = 0 },
- [DDR_3200] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(0), .r2 = 0 },
- [DDR_3000] = { .valid = true, .r1 = MDIV(250) | PDIV(8) | SDIV(0), .r2 = 0 },
- [DDR_2600] = { .valid = true, .r1 = MDIV(325) | PDIV(3) | SDIV(2), .r2 = 0 },
- [DDR_2400] = { .valid = true, .r1 = MDIV(300) | PDIV(3) | SDIV(2), .r2 = 0 },
- [DDR_2376] = { .valid = true, .r1 = MDIV( 99) | PDIV(1) | SDIV(2), .r2 = 0 },
- [DDR_1600] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(1), .r2 = 0 },
- [DDR_1066] = { .valid = true, .r1 = MDIV(400) | PDIV(9) | SDIV(2), .r2 = 0 },
- [DDR_667] = { .valid = true, .r1 = MDIV(334) | PDIV(3) | SDIV(4), .r2 = 0 },
- [DDR_400] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(3), .r2 = 0 },
-};
-
-/* PLL config for IMX8MQ type DRAM PLL. This is SSCG_PLL:
- * Frequency = Ref (25 MHz) / divr1 * (2*divf1) / divr2 * divf2 / divq
- * Note: IMX8MQ RM, §5.1.5.4.4 Fig. 5-8 shows ÷2 on divf2, but this is not true.
- * Note: divider is register value + 1
- */
-#define SSCG_PLL_LOCK BIT(31)
-#define SSCG_PLL_DRAM_PLL_CLKE BIT(9)
-#define SSCG_PLL_PD BIT(7)
-#define SSCG_PLL_BYPASS1 BIT(5)
-#define SSCG_PLL_BYPASS2 BIT(4)
-
-#define SSCG_PLL_REF_DIVR2_MASK (0x3f << 19)
-#define SSCG_PLL_REF_DIVR2_VAL(n) (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK)
-#define SSCG_PLL_FEEDBACK_DIV_F1_MASK (0x3f << 13)
-#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n) (((n) << 13) & SSCG_PLL_FEEDBACK_DIV_F1_MASK)
-#define SSCG_PLL_FEEDBACK_DIV_F2_MASK (0x3f << 7)
-#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n) (((n) << 7) & SSCG_PLL_FEEDBACK_DIV_F2_MASK)
-#define SSCG_PLL_OUTPUT_DIV_VAL_MASK (0x3f << 1)
-#define SSCG_PLL_OUTPUT_DIV_VAL(n) (((n) << 1) & SSCG_PLL_OUTPUT_DIV_VAL_MASK)
-
-#define SSCG_PLL_CFG2(divf1, divr2, divf2, divq) \
- (SSCG_PLL_FEEDBACK_DIV_F1_VAL(divf1) | SSCG_PLL_FEEDBACK_DIV_F2_VAL(divf2) | \
- SSCG_PLL_REF_DIVR2_VAL(divr2) | SSCG_PLL_OUTPUT_DIV_VAL(divq))
-
-static const struct imx8mq_ssgcpll_config {
- uint32_t val;
- bool valid;
-} imx8mq_ssgcpll_table[DDR_NUM_RATES] = {
- [DDR_3200] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 0) },
- [DDR_2400] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 17, 1) },
- [DDR_1600] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 1) },
- [DDR_667] = { .valid = true, .val = SSCG_PLL_CFG2(45, 30, 8, 3) }, /* ~166.935 MHz = 667.74 */
-};
-
-/* IMX8M Bypass clock config. These configure dram_alt1_clk and the dram apb
- * clock. For the bypass config, clock rate = DRAM tranfer rate, rather than
- * clock = dram / 4
- */
-
-/* prediv is actual divider, register will be set to divider - 1 */
-#define CCM_ROOT_CFG(mux, prediv) (IMX8M_CCM_TARGET_ROOTn_ENABLE | \
- IMX8M_CCM_TARGET_ROOTn_MUX(mux) | IMX8M_CCM_TARGET_ROOTn_PRE_DIV(prediv-1))
-
-static const struct imx8m_bypass_config {
- uint32_t alt_clk;
- uint32_t apb_clk;
- bool valid;
-} imx8m_bypass_table[DDR_NUM_RATES] = {
- [DDR_400] = { .valid = true, .alt_clk = CCM_ROOT_CFG(1, 2), .apb_clk = CCM_ROOT_CFG(3, 2) },
- [DDR_250] = { .valid = true, .alt_clk = CCM_ROOT_CFG(3, 2), .apb_clk = CCM_ROOT_CFG(2, 2) },
- [DDR_100] = { .valid = true, .alt_clk = CCM_ROOT_CFG(2, 1), .apb_clk = CCM_ROOT_CFG(2, 2) },
-};
-
void ddrc_phy_load_firmware(void __iomem *phy,
enum ddrc_phy_firmware_offset offset,
const u16 *blob, size_t size)
@@ -207,158 +102,6 @@ int wait_ddrphy_training_complete(void)
}
}
-static void dram_enable_bypass(enum ddr_rate drate)
-{
- const struct imx8m_bypass_config *config = &imx8m_bypass_table[drate];
-
- if (!config->valid) {
- pr_warn("No matched freq table entry %u\n", drate);
- return;
- }
-
- imx8m_clock_set_target_val(IMX8M_DRAM_ALT_CLK_ROOT, config->alt_clk);
- imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT, config->apb_clk);
- imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG, IMX8M_CCM_TARGET_ROOTn_ENABLE |
- IMX8M_CCM_TARGET_ROOTn_MUX(1));
-}
-
-static void dram_disable_bypass(void)
-{
- imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG,
- IMX8M_CCM_TARGET_ROOTn_ENABLE |
- IMX8M_CCM_TARGET_ROOTn_MUX(0));
- imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT,
- IMX8M_CCM_TARGET_ROOTn_ENABLE |
- IMX8M_CCM_TARGET_ROOTn_MUX(4) |
- IMX8M_CCM_TARGET_ROOTn_PRE_DIV(5 - 1));
-}
-
-static int dram_frac_pll_init(enum ddr_rate drate)
-{
- volatile int i;
- u32 tmp;
- void *pll_base;
- const struct imx8mm_fracpll_config *config = &imx8mm_fracpll_table[drate];
-
- if (!config->valid) {
- pr_warn("No matched freq table entry %u\n", drate);
- return -EINVAL;
- }
-
- setbits_le32(MX8M_GPC_BASE_ADDR + 0xec, 1 << 7);
- setbits_le32(MX8M_GPC_BASE_ADDR + 0xf8, 1 << 5);
- writel(0x8F000000UL, MX8M_SRC_BASE_ADDR + 0x1004);
-
- pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x50;
-
- /* Bypass clock and set lock to pll output lock */
- tmp = readl(pll_base);
- tmp |= BYPASS_MASK;
- writel(tmp, pll_base);
-
- /* Enable RST */
- tmp &= ~RST_MASK;
- writel(tmp, pll_base);
-
- writel(config->r1, pll_base + 4);
- writel(config->r2, pll_base + 8);
-
- for (i = 0; i < 1000; i++);
-
- /* Disable RST */
- tmp |= RST_MASK;
- writel(tmp, pll_base);
-
- /* Wait Lock*/
- while (!(readl(pll_base) & LOCK_STATUS));
-
- /* Bypass */
- tmp &= ~BYPASS_MASK;
- writel(tmp, pll_base);
-
- return 0;
-}
-
-static int dram_sscg_pll_init(enum ddr_rate drate)
-{
- u32 val;
- void __iomem *pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x60;
- const struct imx8mq_ssgcpll_config *config = &imx8mq_ssgcpll_table[drate];
-
- if (!config->valid) {
- pr_warn("No matched freq table entry %u\n", drate);
- return -EINVAL;
- }
-
- /* Bypass */
- setbits_le32(pll_base, SSCG_PLL_BYPASS1 | SSCG_PLL_BYPASS2);
-
- val = readl(pll_base + 0x8);
- val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
- SSCG_PLL_FEEDBACK_DIV_F2_MASK |
- SSCG_PLL_FEEDBACK_DIV_F1_MASK |
- SSCG_PLL_REF_DIVR2_MASK);
- val |= config->val;
- writel(val, pll_base + 0x8);
-
- /* Clear power down bit */
- clrbits_le32(pll_base, SSCG_PLL_PD);
- /* Enable PLL */
- setbits_le32(pll_base, SSCG_PLL_DRAM_PLL_CLKE);
-
- /* Clear bypass */
- clrbits_le32(pll_base, SSCG_PLL_BYPASS1);
- udelay(100);
- clrbits_le32(pll_base, SSCG_PLL_BYPASS2);
- /* Wait lock */
- while (!(readl(pll_base) & SSCG_PLL_LOCK))
- ;
-
- return 0;
-}
-
-static int dram_pll_init(enum ddr_rate drate, enum ddrc_type type)
-{
- switch (type) {
- case DDRC_TYPE_MQ:
- return dram_sscg_pll_init(drate);
- case DDRC_TYPE_MM:
- case DDRC_TYPE_MN:
- case DDRC_TYPE_MP:
- return dram_frac_pll_init(drate);
- default:
- return -ENODEV;
- }
-}
-
-void ddrphy_init_set_dfi_clk(unsigned int drate_mhz, enum ddrc_type type)
-{
- enum ddr_rate drate;
-
- switch (drate_mhz) {
- case 4000: drate = DDR_4000; break;
- case 3720: drate = DDR_3720; break;
- case 3200: drate = DDR_3200; break;
- case 3000: drate = DDR_3000; break;
- case 2400: drate = DDR_2400; break;
- case 1600: drate = DDR_1600; break;
- case 1066: drate = DDR_1066; break;
- case 667: drate = DDR_667; break;
- case 400: drate = DDR_400; break;
- case 100: drate = DDR_100; break;
- default:
- pr_warn("Unsupported frequency %u\n", drate_mhz);
- return;
- }
-
- if (drate_mhz > 400) {
- dram_pll_init(drate, type);
- dram_disable_bypass();
- } else {
- dram_enable_bypass(drate);
- }
-}
-
void ddrphy_init_read_msg_block(enum fw_type type)
{
}
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index 1e704ef8fc..856e7ee4fe 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -212,6 +212,264 @@ static void update_umctl2_rank_space_setting(unsigned int pstat_num,
}
}
+
+/* DDR Transfer rate, bus clock is transfer rate / 2, and the DDRC runs at bus
+ * clock / 2, which is therefor transfer rate / 4. */
+enum ddr_rate {
+ DDR_4000,
+ DDR_3720,
+ DDR_3200,
+ DDR_3000,
+ DDR_2600, /* Unused */
+ DDR_2400,
+ DDR_2376, /* Unused */
+ DDR_1600,
+ DDR_1000, /* Unused */
+ DDR_1066,
+ DDR_667,
+ DDR_400,
+ DDR_250, /* Unused */
+ DDR_100,
+ DDR_NUM_RATES
+};
+
+/* PLL config for IMX8MM type DRAM PLL. This PLL type isn't documented, but
+ * it looks like it is a basically a fractional PLL:
+ * Frequency = Ref (24 MHz) / P * M / 2^S
+ * Note: Divider is equal to register value
+ */
+#define MDIV(x) ((x) << 12)
+#define PDIV(x) ((x) << 4)
+#define SDIV(x) ((x) << 0)
+
+#define LOCK_STATUS BIT(31)
+#define LOCK_SEL_MASK BIT(29)
+#define CLKE_MASK BIT(11)
+#define RST_MASK BIT(9)
+#define BYPASS_MASK BIT(4)
+
+static const struct imx8mm_fracpll_config {
+ uint32_t r1, r2;
+ bool valid;
+} imx8mm_fracpll_table[DDR_NUM_RATES] = {
+ [DDR_4000] = { .valid = true, .r1 = MDIV(250) | PDIV(3) | SDIV(1), .r2 = 0 },
+ [DDR_3720] = { .valid = true, .r1 = MDIV(310) | PDIV(2) | SDIV(2), .r2 = 0 },
+ [DDR_3200] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(0), .r2 = 0 },
+ [DDR_3000] = { .valid = true, .r1 = MDIV(250) | PDIV(8) | SDIV(0), .r2 = 0 },
+ [DDR_2600] = { .valid = true, .r1 = MDIV(325) | PDIV(3) | SDIV(2), .r2 = 0 },
+ [DDR_2400] = { .valid = true, .r1 = MDIV(300) | PDIV(3) | SDIV(2), .r2 = 0 },
+ [DDR_2376] = { .valid = true, .r1 = MDIV( 99) | PDIV(1) | SDIV(2), .r2 = 0 },
+ [DDR_1600] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(1), .r2 = 0 },
+ [DDR_1066] = { .valid = true, .r1 = MDIV(400) | PDIV(9) | SDIV(2), .r2 = 0 },
+ [DDR_667] = { .valid = true, .r1 = MDIV(334) | PDIV(3) | SDIV(4), .r2 = 0 },
+ [DDR_400] = { .valid = true, .r1 = MDIV(300) | PDIV(9) | SDIV(3), .r2 = 0 },
+};
+
+/* PLL config for IMX8MQ type DRAM PLL. This is SSCG_PLL:
+ * Frequency = Ref (25 MHz) / divr1 * (2*divf1) / divr2 * divf2 / divq
+ * Note: IMX8MQ RM, §5.1.5.4.4 Fig. 5-8 shows ÷2 on divf2, but this is not true.
+ * Note: divider is register value + 1
+ */
+#define SSCG_PLL_LOCK BIT(31)
+#define SSCG_PLL_DRAM_PLL_CLKE BIT(9)
+#define SSCG_PLL_PD BIT(7)
+#define SSCG_PLL_BYPASS1 BIT(5)
+#define SSCG_PLL_BYPASS2 BIT(4)
+
+#define SSCG_PLL_REF_DIVR2_MASK (0x3f << 19)
+#define SSCG_PLL_REF_DIVR2_VAL(n) (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F1_MASK (0x3f << 13)
+#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n) (((n) << 13) & SSCG_PLL_FEEDBACK_DIV_F1_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F2_MASK (0x3f << 7)
+#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n) (((n) << 7) & SSCG_PLL_FEEDBACK_DIV_F2_MASK)
+#define SSCG_PLL_OUTPUT_DIV_VAL_MASK (0x3f << 1)
+#define SSCG_PLL_OUTPUT_DIV_VAL(n) (((n) << 1) & SSCG_PLL_OUTPUT_DIV_VAL_MASK)
+
+#define SSCG_PLL_CFG2(divf1, divr2, divf2, divq) \
+ (SSCG_PLL_FEEDBACK_DIV_F1_VAL(divf1) | SSCG_PLL_FEEDBACK_DIV_F2_VAL(divf2) | \
+ SSCG_PLL_REF_DIVR2_VAL(divr2) | SSCG_PLL_OUTPUT_DIV_VAL(divq))
+
+static const struct imx8mq_ssgcpll_config {
+ uint32_t val;
+ bool valid;
+} imx8mq_ssgcpll_table[DDR_NUM_RATES] = {
+ [DDR_3200] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 0) },
+ [DDR_2400] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 17, 1) },
+ [DDR_1600] = { .valid = true, .val = SSCG_PLL_CFG2(39, 29, 11, 1) },
+ [DDR_667] = { .valid = true, .val = SSCG_PLL_CFG2(45, 30, 8, 3) }, /* ~166.935 MHz = 667.74 */
+};
+
+/* IMX8M Bypass clock config. These configure dram_alt1_clk and the dram apb
+ * clock. For the bypass config, clock rate = DRAM tranfer rate, rather than
+ * clock = dram / 4
+ */
+
+/* prediv is actual divider, register will be set to divider - 1 */
+#define CCM_ROOT_CFG(mux, prediv) (IMX8M_CCM_TARGET_ROOTn_ENABLE | \
+ IMX8M_CCM_TARGET_ROOTn_MUX(mux) | IMX8M_CCM_TARGET_ROOTn_PRE_DIV(prediv-1))
+
+static const struct imx8m_bypass_config {
+ uint32_t alt_clk;
+ uint32_t apb_clk;
+ bool valid;
+} imx8m_bypass_table[DDR_NUM_RATES] = {
+ [DDR_400] = { .valid = true, .alt_clk = CCM_ROOT_CFG(1, 2), .apb_clk = CCM_ROOT_CFG(3, 2) },
+ [DDR_250] = { .valid = true, .alt_clk = CCM_ROOT_CFG(3, 2), .apb_clk = CCM_ROOT_CFG(2, 2) },
+ [DDR_100] = { .valid = true, .alt_clk = CCM_ROOT_CFG(2, 1), .apb_clk = CCM_ROOT_CFG(2, 2) },
+};
+
+static void dram_enable_bypass(enum ddr_rate drate)
+{
+ const struct imx8m_bypass_config *config = &imx8m_bypass_table[drate];
+
+ if (!config->valid) {
+ pr_warn("No matched freq table entry %u\n", drate);
+ return;
+ }
+
+ imx8m_clock_set_target_val(IMX8M_DRAM_ALT_CLK_ROOT, config->alt_clk);
+ imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT, config->apb_clk);
+ imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG, IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(1));
+}
+
+static void dram_disable_bypass(void)
+{
+ imx8m_clock_set_target_val(IMX8M_DRAM_SEL_CFG,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(0));
+ imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(4) |
+ IMX8M_CCM_TARGET_ROOTn_PRE_DIV(5 - 1));
+}
+
+static int dram_frac_pll_init(enum ddr_rate drate)
+{
+ volatile int i;
+ u32 tmp;
+ void *pll_base;
+ const struct imx8mm_fracpll_config *config = &imx8mm_fracpll_table[drate];
+
+ if (!config->valid) {
+ pr_warn("No matched freq table entry %u\n", drate);
+ return -EINVAL;
+ }
+
+ setbits_le32(MX8M_GPC_BASE_ADDR + 0xec, 1 << 7);
+ setbits_le32(MX8M_GPC_BASE_ADDR + 0xf8, 1 << 5);
+ writel(0x8F000000UL, MX8M_SRC_BASE_ADDR + 0x1004);
+
+ pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x50;
+
+ /* Bypass clock and set lock to pll output lock */
+ tmp = readl(pll_base);
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ /* Enable RST */
+ tmp &= ~RST_MASK;
+ writel(tmp, pll_base);
+
+ writel(config->r1, pll_base + 4);
+ writel(config->r2, pll_base + 8);
+
+ for (i = 0; i < 1000; i++);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel(tmp, pll_base);
+
+ /* Wait Lock*/
+ while (!(readl(pll_base) & LOCK_STATUS));
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ return 0;
+}
+
+static int dram_sscg_pll_init(enum ddr_rate drate)
+{
+ u32 val;
+ void __iomem *pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x60;
+ const struct imx8mq_ssgcpll_config *config = &imx8mq_ssgcpll_table[drate];
+
+ if (!config->valid) {
+ pr_warn("No matched freq table entry %u\n", drate);
+ return -EINVAL;
+ }
+
+ /* Bypass */
+ setbits_le32(pll_base, SSCG_PLL_BYPASS1 | SSCG_PLL_BYPASS2);
+
+ val = readl(pll_base + 0x8);
+ val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+ SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+ SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+ SSCG_PLL_REF_DIVR2_MASK);
+ val |= config->val;
+ writel(val, pll_base + 0x8);
+
+ /* Clear power down bit */
+ clrbits_le32(pll_base, SSCG_PLL_PD);
+ /* Enable PLL */
+ setbits_le32(pll_base, SSCG_PLL_DRAM_PLL_CLKE);
+
+ /* Clear bypass */
+ clrbits_le32(pll_base, SSCG_PLL_BYPASS1);
+ udelay(100);
+ clrbits_le32(pll_base, SSCG_PLL_BYPASS2);
+ /* Wait lock */
+ while (!(readl(pll_base) & SSCG_PLL_LOCK))
+ ;
+
+ return 0;
+}
+
+static int dram_pll_init(enum ddr_rate drate, enum ddrc_type type)
+{
+ switch (type) {
+ case DDRC_TYPE_MQ:
+ return dram_sscg_pll_init(drate);
+ case DDRC_TYPE_MM:
+ case DDRC_TYPE_MN:
+ case DDRC_TYPE_MP:
+ return dram_frac_pll_init(drate);
+ default:
+ return -ENODEV;
+ }
+}
+
+static void ddrphy_init_set_dfi_clk(struct dram_controller *dram, unsigned int drate_mhz)
+{
+ enum ddr_rate drate;
+
+ switch (drate_mhz) {
+ case 4000: drate = DDR_4000; break;
+ case 3720: drate = DDR_3720; break;
+ case 3200: drate = DDR_3200; break;
+ case 3000: drate = DDR_3000; break;
+ case 2400: drate = DDR_2400; break;
+ case 1600: drate = DDR_1600; break;
+ case 1066: drate = DDR_1066; break;
+ case 667: drate = DDR_667; break;
+ case 400: drate = DDR_400; break;
+ case 100: drate = DDR_100; break;
+ default:
+ pr_warn("Unsupported frequency %u\n", drate_mhz);
+ return;
+ }
+
+ if (drate_mhz > 400) {
+ dram_pll_init(drate, dram->ddrc_type);
+ dram_disable_bypass();
+ } else {
+ dram_enable_bypass(drate);
+ }
+}
+
/*
* We store the timing parameters here. the TF-A will pick these up.
* Note that the timing used we leave the driver with is a PLL bypass 25MHz
@@ -229,6 +487,7 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
pr_debug("start DRAM init\n");
dram->get_trained_CDD = get_trained_CDD;
+ dram->set_dfi_clk = ddrphy_init_set_dfi_clk;
/* Step1: Follow the power up procedure */
switch (dram->ddrc_type) {
@@ -253,7 +512,7 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
initial_drate = dram_timing->fsp_msg[0].drate;
/* default to the frequency point 0 clock */
- ddrphy_init_set_dfi_clk(initial_drate, dram->ddrc_type);
+ dram->set_dfi_clk(dram, initial_drate);
/* D-aasert the presetn */
reg32_write(src_ddrc_rcr, 0x8F000006);
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index c89dfe78cf..ec82f3233a 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -388,6 +388,7 @@ struct dram_controller {
enum ddrc_type ddrc_type;
enum dram_type dram_type;
void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
+ void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
};
extern struct dram_timing_info dram_timing;
@@ -458,7 +459,6 @@ void dram_config_save(struct dram_timing_info *info, unsigned long base);
/* utils function for ddr phy training */
int wait_ddrphy_training_complete(void);
-void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type ddrc_type);
void ddrphy_init_read_msg_block(enum fw_type fw_type);
#define reg32_write(a, v) writel(v, a)
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 05/13] ddr: imx8m: clean up defines
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (3 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 04/13] ddr: imx8m: move PLL init to SoC specific code Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 06/13] ddr: imx8m: move phy_base to controller struct Sascha Hauer
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Use register defines we already have in mach/imx/imx8m-regs.h rather
than duplicating them in the ddr code. Also remove some unused defines.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/helper.c | 8 --------
drivers/ddr/imx/imx8m_ddr_init.c | 2 +-
include/soc/imx8m/ddr.h | 11 +++--------
3 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/drivers/ddr/imx/helper.c b/drivers/ddr/imx/helper.c
index 98e4084958..81c3ed7f30 100644
--- a/drivers/ddr/imx/helper.c
+++ b/drivers/ddr/imx/helper.c
@@ -10,14 +10,6 @@
#include <errno.h>
#include <soc/imx8m/ddr.h>
-#define IMEM_LEN 32768 /* byte */
-#define DMEM_LEN 16384 /* byte */
-#define IMEM_2D_OFFSET 49152
-
-#define IMEM_OFFSET_ADDR 0x00050000
-#define DMEM_OFFSET_ADDR 0x00054000
-#define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0)
-
void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr,
unsigned int num)
{
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index 856e7ee4fe..f76aafe769 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -543,7 +543,7 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
*/
tmp = reg32_read(DDRC_MSTR(0));
if (tmp & (0x1 << 5) && dram->ddrc_type != DDRC_TYPE_MN)
- reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
+ reg32_write(MX8M_DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
/* determine the initial boot frequency */
target_freq = reg32_read(DDRC_MSTR2(0)) & 0x3;
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index ec82f3233a..9ff9c0a2da 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -8,11 +8,9 @@
#include <io.h>
#include <asm/types.h>
+#include <mach/imx/imx8m-regs.h>
-#define DDRC_DDR_SS_GPR0 0x3d000000
-#define DDRC_IPS_BASE_ADDR_0 0x3f400000
-#define IP2APB_DDRPHY_IPS_BASE_ADDR(X) (0x3c000000 + (X * 0x2000000))
-#define DDRPHY_MEM(X) (0x3c000000 + (X * 0x2000000) + 0x50000)
+#define IP2APB_DDRPHY_IPS_BASE_ADDR(X) MX8M_DDRC_PHY_BASE_ADDR
#define DDRC_MSTR(X) (DDRC_IPS_BASE_ADDR(X) + 0x00)
#define DDRC_STAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x04)
@@ -320,7 +318,7 @@
#define DRC_PERF_MON_MRR14_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x78)
#define DRC_PERF_MON_MRR15_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x7C)
-#define DDRC_IPS_BASE_ADDR(X) (0x3d400000 + (X * 0x2000000))
+#define DDRC_IPS_BASE_ADDR(X) MX8M_DDRC_IPS_BASE_ADDR(X)
/* user data type */
enum fw_type {
@@ -391,8 +389,6 @@ struct dram_controller {
void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
};
-extern struct dram_timing_info dram_timing;
-
void ddr_get_firmware_lpddr4(void);
void ddr_get_firmware_ddr(void);
@@ -453,7 +449,6 @@ static inline int imx8mp_ddr_init(struct dram_timing_info *dram_timing,
}
int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
-void load_lpddr4_phy_pie(void);
void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num);
void dram_config_save(struct dram_timing_info *info, unsigned long base);
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 06/13] ddr: imx8m: move phy_base to controller struct
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (4 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 05/13] ddr: imx8m: clean up defines Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 07/13] ddr: imx8m: remove empty function Sascha Hauer
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
The phy_base will be different on i.MX9, so move the base address to
struct dram_controller.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_train.c | 24 ++++++++++++------------
drivers/ddr/imx/helper.c | 12 ++++++------
drivers/ddr/imx/imx8m_ddr_init.c | 13 ++++++-------
include/soc/imx8m/ddr.h | 22 +++++++++++++++++-----
4 files changed, 41 insertions(+), 30 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index b44f5ef9b4..af4d710dc0 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -107,7 +107,7 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
num = dram_timing->ddrphy_cfg_num;
for (i = 0; i < num; i++) {
/* config phy reg */
- dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dwc_ddrphy_apb_wr(dram, dram_cfg->reg, dram_cfg->val);
dram_cfg++;
}
@@ -119,14 +119,14 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
dram->set_dfi_clk(dram, fsp_msg->drate);
/* load the dram training firmware image */
- dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x0);
ddr_load_train_code(dram->dram_type, fsp_msg->fw_type);
/* load the frequency set point message block parameter */
dram_cfg = fsp_msg->fsp_cfg;
num = fsp_msg->fsp_cfg_num;
for (j = 0; j < num; j++) {
- dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dwc_ddrphy_apb_wr(dram, dram_cfg->reg, dram_cfg->val);
dram_cfg++;
}
@@ -140,10 +140,10 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
* 4. read the message block result.
* -------------------------------------------------------------
*/
- dwc_ddrphy_apb_wr(0xd0000, 0x1);
- dwc_ddrphy_apb_wr(0xd0099, 0x9);
- dwc_ddrphy_apb_wr(0xd0099, 0x1);
- dwc_ddrphy_apb_wr(0xd0099, 0x0);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x1);
+ dwc_ddrphy_apb_wr(dram, 0xd0099, 0x9);
+ dwc_ddrphy_apb_wr(dram, 0xd0099, 0x1);
+ dwc_ddrphy_apb_wr(dram, 0xd0099, 0x0);
/* Wait for the training firmware to complete */
ret = wait_ddrphy_training_complete();
@@ -151,17 +151,17 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
return ret;
/* Halt the microcontroller. */
- dwc_ddrphy_apb_wr(0xd0099, 0x1);
+ dwc_ddrphy_apb_wr(dram, 0xd0099, 0x1);
/* Read the Message Block results */
- dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x0);
ddrphy_init_read_msg_block(fsp_msg->fw_type);
if (fsp_msg->fw_type != FW_2D_IMAGE)
dram->get_trained_CDD(dram, i);
- dwc_ddrphy_apb_wr(0xd0000, 0x1);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x1);
fsp_msg++;
}
@@ -170,12 +170,12 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
dram_cfg = dram_timing->ddrphy_pie;
num = dram_timing->ddrphy_pie_num;
for (i = 0; i < num; i++) {
- dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
+ dwc_ddrphy_apb_wr(dram, dram_cfg->reg, dram_cfg->val);
dram_cfg++;
}
/* save the ddr PHY trained CSR in memory for low power use */
- ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
+ ddrphy_trained_csr_save(dram, ddrphy_trained_csr, ddrphy_trained_csr_num);
return 0;
}
diff --git a/drivers/ddr/imx/helper.c b/drivers/ddr/imx/helper.c
index 81c3ed7f30..0bd8d2688a 100644
--- a/drivers/ddr/imx/helper.c
+++ b/drivers/ddr/imx/helper.c
@@ -10,21 +10,21 @@
#include <errno.h>
#include <soc/imx8m/ddr.h>
-void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr,
+void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *ddrphy_csr,
unsigned int num)
{
int i = 0;
/* enable the ddrphy apb */
- dwc_ddrphy_apb_wr(0xd0000, 0x0);
- dwc_ddrphy_apb_wr(0xc0080, 0x3);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x0);
+ dwc_ddrphy_apb_wr(dram, 0xc0080, 0x3);
for (i = 0; i < num; i++) {
- ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg);
+ ddrphy_csr->val = dwc_ddrphy_apb_rd(dram, ddrphy_csr->reg);
ddrphy_csr++;
}
/* disable the ddrphy apb */
- dwc_ddrphy_apb_wr(0xc0080, 0x2);
- dwc_ddrphy_apb_wr(0xd0000, 0x1);
+ dwc_ddrphy_apb_wr(dram, 0xc0080, 0x2);
+ dwc_ddrphy_apb_wr(dram, 0xd0000, 0x1);
}
void dram_config_save(struct dram_timing_info *timing_info,
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index f76aafe769..8d473a3e63 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -15,7 +15,9 @@
bool imx8m_ddr_old_spreadsheet = true;
-struct dram_controller imx8m_dram_controller;
+struct dram_controller imx8m_dram_controller = {
+ .phy_base = IOMEM(IP2APB_DDRPHY_IPS_BASE_ADDR(0)),
+};
static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
{
@@ -71,15 +73,13 @@ static void get_trained_CDD(struct dram_controller *dram, u32 fsp)
ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
if (ddr_type == 0x20) {
for (i = 0; i < 6; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x54013UL + i) * 4);
+ tmp = dwc_ddrphy_apb_rd(dram, 0x54013UL + i);
cdd_cha[i * 2] = tmp & 0xff;
cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
}
for (i = 0; i < 7; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x5402cUL + i) * 4);
+ tmp = dwc_ddrphy_apb_rd(dram, 0x5402cUL + i);
if (i == 0) {
cdd_cha[0] = (tmp >> 8) & 0xff;
} else if (i == 6) {
@@ -106,8 +106,7 @@ static void get_trained_CDD(struct dram_controller *dram, u32 fsp)
unsigned int ddr4_cdd[64];
for( i = 0; i < 29; i++) {
- tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) +
- (0x54012UL + i) * 4);
+ tmp = dwc_ddrphy_apb_rd(dram, 0x54012UL + i);
ddr4_cdd[i * 2] = tmp & 0xff;
ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
}
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index 9ff9c0a2da..bdf0f25727 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -385,6 +385,7 @@ struct dram_timing_info {
struct dram_controller {
enum ddrc_type ddrc_type;
enum dram_type dram_type;
+ void __iomem *phy_base;
void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
};
@@ -449,7 +450,8 @@ static inline int imx8mp_ddr_init(struct dram_timing_info *dram_timing,
}
int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
-void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num);
+void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param,
+ unsigned int num);
void dram_config_save(struct dram_timing_info *info, unsigned long base);
/* utils function for ddr phy training */
@@ -464,10 +466,20 @@ static inline void reg32setbit(unsigned long addr, u32 bit)
setbits_le32(addr, (1 << bit));
}
-#define dwc_ddrphy_apb_wr(addr, data) \
- reg32_write(IOMEM(IP2APB_DDRPHY_IPS_BASE_ADDR(0)) + 4 * (addr), data)
-#define dwc_ddrphy_apb_rd(addr) \
- reg32_read(IOMEM(IP2APB_DDRPHY_IPS_BASE_ADDR(0)) + 4 * (addr))
+static inline void *dwc_ddrphy_apb_addr(struct dram_controller *dram, unsigned int addr)
+{
+ return dram->phy_base + addr * 4;
+}
+
+static inline void dwc_ddrphy_apb_wr(struct dram_controller *dram, unsigned int addr, u32 data)
+{
+ reg32_write(dwc_ddrphy_apb_addr(dram, addr), data);
+}
+
+static inline u32 dwc_ddrphy_apb_rd(struct dram_controller *dram, unsigned int addr)
+{
+ return reg32_read(dwc_ddrphy_apb_addr(dram, addr));
+}
extern bool imx8m_ddr_old_spreadsheet;
extern struct dram_cfg_param ddrphy_trained_csr[];
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 07/13] ddr: imx8m: remove empty function
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (5 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 06/13] ddr: imx8m: move phy_base to controller struct Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 08/13] ddr: imx8m: get rid of hardcoded phy address Sascha Hauer
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
ddrphy_init_read_msg_block() is empty. Remove it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_train.c | 2 --
drivers/ddr/imx/ddrphy_utils.c | 4 ----
include/soc/imx8m/ddr.h | 1 -
3 files changed, 7 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index af4d710dc0..302acdfe62 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -156,8 +156,6 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
/* Read the Message Block results */
dwc_ddrphy_apb_wr(dram, 0xd0000, 0x0);
- ddrphy_init_read_msg_block(fsp_msg->fw_type);
-
if (fsp_msg->fw_type != FW_2D_IMAGE)
dram->get_trained_CDD(dram, i);
diff --git a/drivers/ddr/imx/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
index 4577547113..5f80b8fdc1 100644
--- a/drivers/ddr/imx/ddrphy_utils.c
+++ b/drivers/ddr/imx/ddrphy_utils.c
@@ -101,7 +101,3 @@ int wait_ddrphy_training_complete(void)
}
}
}
-
-void ddrphy_init_read_msg_block(enum fw_type type)
-{
-}
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index bdf0f25727..0a2a7b0e2f 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -456,7 +456,6 @@ void dram_config_save(struct dram_timing_info *info, unsigned long base);
/* utils function for ddr phy training */
int wait_ddrphy_training_complete(void);
-void ddrphy_init_read_msg_block(enum fw_type fw_type);
#define reg32_write(a, v) writel(v, a)
#define reg32_read(a) readl(a)
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 08/13] ddr: imx8m: get rid of hardcoded phy address
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (6 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 07/13] ddr: imx8m: remove empty function Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 09/13] ddr: imx8m: split header file Sascha Hauer
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
The phy address is hardcoded in several functions. Use the address
provided in struct dram_controller instead. Some functions are used
from legacy DDR setup in board code which only uses parts of the
DDR initialization code. The board code doesn't have any struct
dram_controller *, so provide some static inline wrappers for these
functions.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 10 ++---
.../boards/phytec-som-imx8mq/ddrphy_train.c | 12 +++---
arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c | 10 ++---
drivers/ddr/imx/ddrphy_train.c | 14 +++----
drivers/ddr/imx/ddrphy_utils.c | 40 ++++++++-----------
include/soc/imx8m/ddr.h | 17 ++++++--
6 files changed, 53 insertions(+), 50 deletions(-)
diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
index e8577369dc..bac7d0a517 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
+++ b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c
@@ -144,7 +144,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(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
+ imx8m_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);
@@ -189,7 +189,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//configure DDRPHY-FW DMEM structure @clock1...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
@@ -258,7 +258,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//set the PHY input clock to the desired frequency for pstate 0
reg32_write(0x3038a088,0x7070000);
@@ -291,7 +291,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(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
+ imx8m_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);
@@ -332,7 +332,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//Halt MPU
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
diff --git a/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c b/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
index 2ed6578093..fac9e184ae 100644
--- a/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
+++ b/arch/arm/boards/phytec-som-imx8mq/ddrphy_train.c
@@ -148,7 +148,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(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
+ imx8m_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);
@@ -190,7 +190,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//configure DDRPHY-FW DMEM structure @clock1...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
@@ -224,7 +224,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(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
+ imx8m_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);
@@ -267,7 +267,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//set the PHY input clock to the desired frequency for pstate 0
reg32_write(0x3038a088,0x7070000);
@@ -300,7 +300,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(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
+ imx8m_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);
@@ -343,7 +343,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//Halt MPU
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
diff --git a/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
index e8577369dc..bac7d0a517 100644
--- a/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
+++ b/arch/arm/boards/zii-imx8mq-dev/ddrphy_train.c
@@ -144,7 +144,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(DRAM_TYPE_LPDDR4, FW_1D_IMAGE);
+ imx8m_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);
@@ -189,7 +189,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//configure DDRPHY-FW DMEM structure @clock1...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
@@ -258,7 +258,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//set the PHY input clock to the desired frequency for pstate 0
reg32_write(0x3038a088,0x7070000);
@@ -291,7 +291,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(DRAM_TYPE_LPDDR4, FW_2D_IMAGE);
+ imx8m_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);
@@ -332,7 +332,7 @@ void ddr_cfg_phy(void) {
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
- wait_ddrphy_training_complete();
+ imx8m_wait_ddrphy_training_complete();
//Halt MPU
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index 302acdfe62..c0555ffe01 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <soc/imx8m/ddr.h>
#include <firmware.h>
-#include <mach/imx/imx8m-regs.h>
static const u16 *lpddr4_imem_1d;
static size_t lpddr4_imem_1d_size;
@@ -53,7 +52,8 @@ void ddr_get_firmware_ddr(void)
&ddr4_dmem_2d_size);
}
-void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type)
+void ddr_load_train_code(struct dram_controller *dram, enum dram_type dram_type,
+ enum fw_type fw_type)
{
const u16 *imem, *dmem;
size_t isize, dsize;
@@ -86,11 +86,9 @@ void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type)
panic("No matching DDR PHY firmware found");
}
- ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
- DDRC_PHY_IMEM, imem, isize);
+ ddrc_phy_load_firmware(dram, DDRC_PHY_IMEM, imem, isize);
- ddrc_phy_load_firmware(IOMEM(MX8M_DDRC_PHY_BASE_ADDR),
- DDRC_PHY_DMEM, dmem, dsize);
+ ddrc_phy_load_firmware(dram, DDRC_PHY_DMEM, dmem, dsize);
}
int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timing)
@@ -120,7 +118,7 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
/* load the dram training firmware image */
dwc_ddrphy_apb_wr(dram, 0xd0000, 0x0);
- ddr_load_train_code(dram->dram_type, fsp_msg->fw_type);
+ ddr_load_train_code(dram, dram->dram_type, fsp_msg->fw_type);
/* load the frequency set point message block parameter */
dram_cfg = fsp_msg->fsp_cfg;
@@ -146,7 +144,7 @@ int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *dram_timi
dwc_ddrphy_apb_wr(dram, 0xd0099, 0x0);
/* Wait for the training firmware to complete */
- ret = wait_ddrphy_training_complete();
+ ret = wait_ddrphy_training_complete(dram);
if (ret)
return ret;
diff --git a/drivers/ddr/imx/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
index 5f80b8fdc1..37274b0b5a 100644
--- a/drivers/ddr/imx/ddrphy_utils.c
+++ b/drivers/ddr/imx/ddrphy_utils.c
@@ -10,15 +10,13 @@
#include <io.h>
#include <linux/iopoll.h>
#include <soc/imx8m/ddr.h>
-#include <mach/imx/imx8m-regs.h>
-#include <mach/imx/imx8m-ccm-regs.h>
-void ddrc_phy_load_firmware(void __iomem *phy,
+void ddrc_phy_load_firmware(struct dram_controller *dram,
enum ddrc_phy_firmware_offset offset,
const u16 *blob, size_t size)
{
while (size) {
- writew(*blob++, phy + DDRC_PHY_REG(offset));
+ writew(*blob++, dwc_ddrphy_apb_addr(dram, offset));
offset++;
size -= sizeof(*blob);
}
@@ -33,28 +31,27 @@ enum pmc_constants {
PMC_TRAIN_FAIL = 0xff,
};
-static u32 ddrc_phy_get_message(void __iomem *phy, int type)
+static u32 ddrc_phy_get_message(struct dram_controller *dram, int type)
{
- u32 r, message;
+ u32 message;
/*
* When BIT0 set to 0, the PMU has a message for the user
* Wait for it indefinitely.
*/
- readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
- r, !(r & BIT(0)), 0);
+ while (dwc_ddrphy_apb_rd(dram, 0xd0004) & BIT(0));
switch (type) {
case PMC_MESSAGE_ID:
/*
* Get the major message ID
*/
- message = readl(phy + DDRC_PHY_REG(0xd0032));
+ message = dwc_ddrphy_apb_rd(dram, 0xd0032);
break;
case PMC_MESSAGE_STREAM:
- message = readl(phy + DDRC_PHY_REG(0xd0034));
+ message = dwc_ddrphy_apb_rd(dram, 0xd0034);
message <<= 16;
- message |= readl(phy + DDRC_PHY_REG(0xd0032));
+ message |= dwc_ddrphy_apb_rd(dram, 0xd0032);
break;
}
@@ -62,37 +59,34 @@ static u32 ddrc_phy_get_message(void __iomem *phy, int type)
* By setting this register to 0, the user acknowledges the
* receipt of the message.
*/
- writel(0x00000000, phy + DDRC_PHY_REG(0xd0031));
+ dwc_ddrphy_apb_wr(dram, 0xd0031, 0x00000000);
/*
* When BIT0 set to 0, the PMU has a message for the user
*/
- readl_poll_timeout(phy + DDRC_PHY_REG(0xd0004),
- r, r & BIT(0), 0);
+ while (!(dwc_ddrphy_apb_rd(dram, 0xd0004) & BIT(0)));
- writel(0x00000001, phy + DDRC_PHY_REG(0xd0031));
+ dwc_ddrphy_apb_wr(dram, 0xd0031, 0x00000001);
return message;
}
-static void ddrc_phy_fetch_streaming_message(void __iomem *phy)
+static void ddrc_phy_fetch_streaming_message(struct dram_controller *dram)
{
- const u16 index = ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+ const u16 index = ddrc_phy_get_message(dram, PMC_MESSAGE_STREAM);
u16 i;
for (i = 0; i < index; i++)
- ddrc_phy_get_message(phy, PMC_MESSAGE_STREAM);
+ ddrc_phy_get_message(dram, PMC_MESSAGE_STREAM);
}
-int wait_ddrphy_training_complete(void)
+int wait_ddrphy_training_complete(struct dram_controller *dram)
{
- void __iomem *phy = IOMEM(MX8M_DDRC_PHY_BASE_ADDR);
-
for (;;) {
- const u32 m = ddrc_phy_get_message(phy, PMC_MESSAGE_ID);
+ const u32 m = ddrc_phy_get_message(dram, PMC_MESSAGE_ID);
switch (m) {
case PMC_TRAIN_STREAM_START:
- ddrc_phy_fetch_streaming_message(phy);
+ ddrc_phy_fetch_streaming_message(dram);
break;
case PMC_TRAIN_SUCCESS:
return 0;
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index 0a2a7b0e2f..04addc1448 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -455,7 +455,12 @@ void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param
void dram_config_save(struct dram_timing_info *info, unsigned long base);
/* utils function for ddr phy training */
-int wait_ddrphy_training_complete(void);
+int wait_ddrphy_training_complete(struct dram_controller *dram);
+
+static inline int imx8m_wait_ddrphy_training_complete(void)
+{
+ return wait_ddrphy_training_complete(&imx8m_dram_controller);
+}
#define reg32_write(a, v) writel(v, a)
#define reg32_read(a) readl(a)
@@ -489,9 +494,15 @@ enum ddrc_phy_firmware_offset {
DDRC_PHY_DMEM = 0x00054000U,
};
-void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type);
+void ddr_load_train_code(struct dram_controller *dram, enum dram_type dram_type,
+ enum fw_type fw_type);
+static inline void imx8m_ddr_load_train_code(enum dram_type dram_type,
+ enum fw_type fw_type)
+{
+ ddr_load_train_code(&imx8m_dram_controller, dram_type, fw_type);
+}
-void ddrc_phy_load_firmware(void __iomem *,
+void ddrc_phy_load_firmware(struct dram_controller *dram,
enum ddrc_phy_firmware_offset,
const u16 *, size_t);
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 09/13] ddr: imx8m: split header file
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (7 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 08/13] ddr: imx8m: get rid of hardcoded phy address Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 10/13] ddr: imx8m: return cfg from dram_config_save() Sascha Hauer
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Split the header file to a common part and a SoC specific part so that
upcoming i.MX9 support can re-use the common part.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
include/soc/imx/ddr.h | 150 ++++++++++++++++++++++++++++++++++++++++
include/soc/imx8m/ddr.h | 140 +------------------------------------
2 files changed, 151 insertions(+), 139 deletions(-)
create mode 100644 include/soc/imx/ddr.h
diff --git a/include/soc/imx/ddr.h b/include/soc/imx/ddr.h
new file mode 100644
index 0000000000..711abc07ba
--- /dev/null
+++ b/include/soc/imx/ddr.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2017 NXP
+ */
+
+#ifndef __SOC_IMX_DDR_H
+#define __SOC_IMX_DDR_H
+
+/* user data type */
+enum fw_type {
+ FW_1D_IMAGE,
+ FW_2D_IMAGE,
+};
+
+enum dram_type {
+#define DRAM_TYPE_MASK 0x00ff
+ DRAM_TYPE_LPDDR4 = 0 << 0,
+ DRAM_TYPE_DDR4 = 1 << 0,
+};
+
+static inline enum dram_type get_dram_type(unsigned type)
+{
+ return type & DRAM_TYPE_MASK;
+}
+
+enum ddrc_type {
+#define DDRC_TYPE_MASK 0xff00
+ DDRC_TYPE_MM = 0 << 8,
+ DDRC_TYPE_MN = 1 << 8,
+ DDRC_TYPE_MQ = 2 << 8,
+ DDRC_TYPE_MP = 3 << 8,
+};
+
+static inline enum ddrc_type get_ddrc_type(unsigned type)
+{
+ return type & DDRC_TYPE_MASK;
+}
+
+struct dram_cfg_param {
+ unsigned int reg;
+ unsigned int val;
+};
+
+struct dram_fsp_msg {
+ unsigned int drate;
+ enum fw_type fw_type;
+ struct dram_cfg_param *fsp_cfg;
+ unsigned int fsp_cfg_num;
+};
+
+struct dram_timing_info {
+ /* umctl2 config */
+ struct dram_cfg_param *ddrc_cfg;
+ unsigned int ddrc_cfg_num;
+ /* ddrphy config */
+ struct dram_cfg_param *ddrphy_cfg;
+ unsigned int ddrphy_cfg_num;
+ /* ddr fsp train info */
+ struct dram_fsp_msg *fsp_msg;
+ unsigned int fsp_msg_num;
+ /* ddr phy trained CSR */
+ struct dram_cfg_param *ddrphy_trained_csr;
+ unsigned int ddrphy_trained_csr_num;
+ /* ddr phy PIE */
+ struct dram_cfg_param *ddrphy_pie;
+ unsigned int ddrphy_pie_num;
+ /* initialized drate table */
+ unsigned int fsp_table[4];
+};
+
+struct dram_controller {
+ enum ddrc_type ddrc_type;
+ enum dram_type dram_type;
+ void __iomem *phy_base;
+ void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
+ void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
+};
+
+void ddr_get_firmware_lpddr4(void);
+void ddr_get_firmware_ddr(void);
+
+static inline void ddr_get_firmware(enum dram_type dram_type)
+{
+ if (dram_type == DRAM_TYPE_LPDDR4)
+ ddr_get_firmware_lpddr4();
+ else
+ ddr_get_firmware_ddr();
+}
+
+int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
+void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param,
+ unsigned int num);
+void dram_config_save(struct dram_timing_info *info, unsigned long base);
+
+/* utils function for ddr phy training */
+int wait_ddrphy_training_complete(struct dram_controller *dram);
+
+#define reg32_write(a, v) writel(v, a)
+#define reg32_read(a) readl(a)
+
+static inline void reg32setbit(unsigned long addr, u32 bit)
+{
+ setbits_le32(addr, (1 << bit));
+}
+
+static inline void *dwc_ddrphy_apb_addr(struct dram_controller *dram, unsigned int addr)
+{
+ return dram->phy_base + addr * 4;
+}
+
+static inline void dwc_ddrphy_apb_wr(struct dram_controller *dram, unsigned int addr, u32 data)
+{
+ reg32_write(dwc_ddrphy_apb_addr(dram, addr), data);
+}
+
+static inline u32 dwc_ddrphy_apb_rd(struct dram_controller *dram, unsigned int addr)
+{
+ return reg32_read(dwc_ddrphy_apb_addr(dram, addr));
+}
+
+extern struct dram_cfg_param ddrphy_trained_csr[];
+extern uint32_t ddrphy_trained_csr_num;
+
+enum ddrc_phy_firmware_offset {
+ DDRC_PHY_IMEM = 0x00050000U,
+ DDRC_PHY_DMEM = 0x00054000U,
+};
+
+void ddr_load_train_code(struct dram_controller *dram, enum dram_type dram_type,
+ enum fw_type fw_type);
+
+void ddrc_phy_load_firmware(struct dram_controller *dram,
+ enum ddrc_phy_firmware_offset,
+ const u16 *, size_t);
+
+static inline bool dram_is_lpddr4(enum dram_type dram_type)
+{
+ return IS_ENABLED(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) &&
+ dram_type == DRAM_TYPE_LPDDR4;
+}
+
+static inline bool dram_is_ddr4(enum dram_type dram_type)
+{
+ return IS_ENABLED(CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN) &&
+ dram_type == DRAM_TYPE_DDR4;
+}
+
+#define DDRC_PHY_REG(x) ((x) * 4)
+
+#endif /* __SOC_IMX_DDR_H */
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index 04addc1448..abd9961099 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -9,6 +9,7 @@
#include <io.h>
#include <asm/types.h>
#include <mach/imx/imx8m-regs.h>
+#include <soc/imx/ddr.h>
#define IP2APB_DDRPHY_IPS_BASE_ADDR(X) MX8M_DDRC_PHY_BASE_ADDR
@@ -320,87 +321,6 @@
#define DDRC_IPS_BASE_ADDR(X) MX8M_DDRC_IPS_BASE_ADDR(X)
-/* user data type */
-enum fw_type {
- FW_1D_IMAGE,
- FW_2D_IMAGE,
-};
-
-enum dram_type {
-#define DRAM_TYPE_MASK 0x00ff
- DRAM_TYPE_LPDDR4 = 0 << 0,
- DRAM_TYPE_DDR4 = 1 << 0,
-};
-
-static inline enum dram_type get_dram_type(unsigned type)
-{
- return type & DRAM_TYPE_MASK;
-}
-
-enum ddrc_type {
-#define DDRC_TYPE_MASK 0xff00
- DDRC_TYPE_MM = 0 << 8,
- DDRC_TYPE_MN = 1 << 8,
- DDRC_TYPE_MQ = 2 << 8,
- DDRC_TYPE_MP = 3 << 8,
-};
-
-static inline enum ddrc_type get_ddrc_type(unsigned type)
-{
- return type & DDRC_TYPE_MASK;
-}
-
-struct dram_cfg_param {
- unsigned int reg;
- unsigned int val;
-};
-
-struct dram_fsp_msg {
- unsigned int drate;
- enum fw_type fw_type;
- struct dram_cfg_param *fsp_cfg;
- unsigned int fsp_cfg_num;
-};
-
-struct dram_timing_info {
- /* umctl2 config */
- struct dram_cfg_param *ddrc_cfg;
- unsigned int ddrc_cfg_num;
- /* ddrphy config */
- struct dram_cfg_param *ddrphy_cfg;
- unsigned int ddrphy_cfg_num;
- /* ddr fsp train info */
- struct dram_fsp_msg *fsp_msg;
- unsigned int fsp_msg_num;
- /* ddr phy trained CSR */
- struct dram_cfg_param *ddrphy_trained_csr;
- unsigned int ddrphy_trained_csr_num;
- /* ddr phy PIE */
- struct dram_cfg_param *ddrphy_pie;
- unsigned int ddrphy_pie_num;
- /* initialized drate table */
- unsigned int fsp_table[4];
-};
-
-struct dram_controller {
- enum ddrc_type ddrc_type;
- enum dram_type dram_type;
- void __iomem *phy_base;
- void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
- void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
-};
-
-void ddr_get_firmware_lpddr4(void);
-void ddr_get_firmware_ddr(void);
-
-static inline void ddr_get_firmware(enum dram_type dram_type)
-{
- if (dram_type == DRAM_TYPE_LPDDR4)
- ddr_get_firmware_lpddr4();
- else
- ddr_get_firmware_ddr();
-}
-
int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_timing);
extern struct dram_controller imx8m_dram_controller;
@@ -449,75 +369,17 @@ static inline int imx8mp_ddr_init(struct dram_timing_info *dram_timing,
return imx8m_ddr_init(&imx8m_dram_controller, dram_timing);
}
-int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
-void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param,
- unsigned int num);
-void dram_config_save(struct dram_timing_info *info, unsigned long base);
-
-/* utils function for ddr phy training */
-int wait_ddrphy_training_complete(struct dram_controller *dram);
-
static inline int imx8m_wait_ddrphy_training_complete(void)
{
return wait_ddrphy_training_complete(&imx8m_dram_controller);
}
-#define reg32_write(a, v) writel(v, a)
-#define reg32_read(a) readl(a)
-
-static inline void reg32setbit(unsigned long addr, u32 bit)
-{
- setbits_le32(addr, (1 << bit));
-}
-
-static inline void *dwc_ddrphy_apb_addr(struct dram_controller *dram, unsigned int addr)
-{
- return dram->phy_base + addr * 4;
-}
-
-static inline void dwc_ddrphy_apb_wr(struct dram_controller *dram, unsigned int addr, u32 data)
-{
- reg32_write(dwc_ddrphy_apb_addr(dram, addr), data);
-}
-
-static inline u32 dwc_ddrphy_apb_rd(struct dram_controller *dram, unsigned int addr)
-{
- return reg32_read(dwc_ddrphy_apb_addr(dram, addr));
-}
-
extern bool imx8m_ddr_old_spreadsheet;
-extern struct dram_cfg_param ddrphy_trained_csr[];
-extern uint32_t ddrphy_trained_csr_num;
-
-enum ddrc_phy_firmware_offset {
- DDRC_PHY_IMEM = 0x00050000U,
- DDRC_PHY_DMEM = 0x00054000U,
-};
-void ddr_load_train_code(struct dram_controller *dram, enum dram_type dram_type,
- enum fw_type fw_type);
static inline void imx8m_ddr_load_train_code(enum dram_type dram_type,
enum fw_type fw_type)
{
ddr_load_train_code(&imx8m_dram_controller, dram_type, fw_type);
}
-void ddrc_phy_load_firmware(struct dram_controller *dram,
- enum ddrc_phy_firmware_offset,
- const u16 *, size_t);
-
-static inline bool dram_is_lpddr4(enum dram_type dram_type)
-{
- return IS_ENABLED(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) &&
- dram_type == DRAM_TYPE_LPDDR4;
-}
-
-static inline bool dram_is_ddr4(enum dram_type dram_type)
-{
- return IS_ENABLED(CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN) &&
- dram_type == DRAM_TYPE_DDR4;
-}
-
-#define DDRC_PHY_REG(x) ((x) * 4)
-
#endif
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 10/13] ddr: imx8m: return cfg from dram_config_save()
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (8 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 09/13] ddr: imx8m: split header file Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 11/13] ddr: imx8m: Drop '8m' suffix from pr_fmt Sascha Hauer
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Upcoming i.MX9 support needs this.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/helper.c | 4 +++-
include/soc/imx/ddr.h | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/ddr/imx/helper.c b/drivers/ddr/imx/helper.c
index 0bd8d2688a..f21b14447c 100644
--- a/drivers/ddr/imx/helper.c
+++ b/drivers/ddr/imx/helper.c
@@ -27,7 +27,7 @@ void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param
dwc_ddrphy_apb_wr(dram, 0xd0000, 0x1);
}
-void dram_config_save(struct dram_timing_info *timing_info,
+void *dram_config_save(struct dram_timing_info *timing_info,
unsigned long saved_timing_base)
{
int i = 0;
@@ -83,4 +83,6 @@ void dram_config_save(struct dram_timing_info *timing_info,
cfg->val = timing_info->ddrphy_pie[i].val;
cfg++;
}
+
+ return cfg;
}
diff --git a/include/soc/imx/ddr.h b/include/soc/imx/ddr.h
index 711abc07ba..bc793cf3ed 100644
--- a/include/soc/imx/ddr.h
+++ b/include/soc/imx/ddr.h
@@ -90,7 +90,7 @@ static inline void ddr_get_firmware(enum dram_type dram_type)
int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param,
unsigned int num);
-void dram_config_save(struct dram_timing_info *info, unsigned long base);
+void *dram_config_save(struct dram_timing_info *info, unsigned long base);
/* utils function for ddr phy training */
int wait_ddrphy_training_complete(struct dram_controller *dram);
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 11/13] ddr: imx8m: Drop '8m' suffix from pr_fmt
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (9 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 10/13] ddr: imx8m: return cfg from dram_config_save() Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 12/13] ddr: move imx8m_ddr_old_spreadsheet to controller Sascha Hauer
2023-11-10 13:00 ` [PATCH 13/13] ddr: Initial i.MX9 support Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
As the driver will gain i.MX9 support, drop the '8m' suffix from the
messages.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/ddrphy_csr.c | 2 +-
drivers/ddr/imx/ddrphy_train.c | 2 +-
drivers/ddr/imx/ddrphy_utils.c | 2 +-
drivers/ddr/imx/helper.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/ddr/imx/ddrphy_csr.c b/drivers/ddr/imx/ddrphy_csr.c
index d1cbf8f880..744e140879 100644
--- a/drivers/ddr/imx/ddrphy_csr.c
+++ b/drivers/ddr/imx/ddrphy_csr.c
@@ -3,7 +3,7 @@
* Copyright 2018 NXP
*/
-#define pr_fmt(fmt) "imx8m-ddr: " fmt
+#define pr_fmt(fmt) "imx-ddr: " fmt
#include <linux/kernel.h>
#include <soc/imx8m/ddr.h>
diff --git a/drivers/ddr/imx/ddrphy_train.c b/drivers/ddr/imx/ddrphy_train.c
index c0555ffe01..d599445e6f 100644
--- a/drivers/ddr/imx/ddrphy_train.c
+++ b/drivers/ddr/imx/ddrphy_train.c
@@ -3,7 +3,7 @@
* Copyright 2018 NXP
*/
-#define pr_fmt(fmt) "imx8m-ddr: " fmt
+#define pr_fmt(fmt) "imx-ddr: " fmt
#include <common.h>
#include <linux/kernel.h>
diff --git a/drivers/ddr/imx/ddrphy_utils.c b/drivers/ddr/imx/ddrphy_utils.c
index 37274b0b5a..4925fc39d4 100644
--- a/drivers/ddr/imx/ddrphy_utils.c
+++ b/drivers/ddr/imx/ddrphy_utils.c
@@ -3,7 +3,7 @@
* Copyright 2018 NXP
*/
-#define pr_fmt(fmt) "imx8m-ddr: " fmt
+#define pr_fmt(fmt) "imx-ddr: " fmt
#include <common.h>
#include <errno.h>
diff --git a/drivers/ddr/imx/helper.c b/drivers/ddr/imx/helper.c
index f21b14447c..f38b9a0060 100644
--- a/drivers/ddr/imx/helper.c
+++ b/drivers/ddr/imx/helper.c
@@ -3,7 +3,7 @@
* Copyright 2018 NXP
*/
-#define pr_fmt(fmt) "imx8m-ddr: " fmt
+#define pr_fmt(fmt) "imx-ddr: " fmt
#include <common.h>
#include <io.h>
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 12/13] ddr: move imx8m_ddr_old_spreadsheet to controller
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (10 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 11/13] ddr: imx8m: Drop '8m' suffix from pr_fmt Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
2023-11-10 13:00 ` [PATCH 13/13] ddr: Initial i.MX9 support Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/helper.c | 4 ++--
drivers/ddr/imx/imx8m_ddr_init.c | 14 +++++++-------
include/soc/imx/ddr.h | 4 +++-
include/soc/imx8m/ddr.h | 2 --
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/ddr/imx/helper.c b/drivers/ddr/imx/helper.c
index f38b9a0060..674ca7e4ac 100644
--- a/drivers/ddr/imx/helper.c
+++ b/drivers/ddr/imx/helper.c
@@ -27,7 +27,7 @@ void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param
dwc_ddrphy_apb_wr(dram, 0xd0000, 0x1);
}
-void *dram_config_save(struct dram_timing_info *timing_info,
+void *dram_config_save(struct dram_controller *dram, struct dram_timing_info *timing_info,
unsigned long saved_timing_base)
{
int i = 0;
@@ -54,7 +54,7 @@ void *dram_config_save(struct dram_timing_info *timing_info,
cfg++;
}
- if (imx8m_ddr_old_spreadsheet) {
+ if (dram->imx8m_ddr_old_spreadsheet) {
cfg->reg = DDRC_ADDRMAP7(0);
cfg->val = 0xf0f;
cfg++;
diff --git a/drivers/ddr/imx/imx8m_ddr_init.c b/drivers/ddr/imx/imx8m_ddr_init.c
index 8d473a3e63..8b829645c0 100644
--- a/drivers/ddr/imx/imx8m_ddr_init.c
+++ b/drivers/ddr/imx/imx8m_ddr_init.c
@@ -13,19 +13,19 @@
#include <mach/imx/imx8m-regs.h>
#include <mach/imx/imx8m-ccm-regs.h>
-bool imx8m_ddr_old_spreadsheet = true;
-
struct dram_controller imx8m_dram_controller = {
.phy_base = IOMEM(IP2APB_DDRPHY_IPS_BASE_ADDR(0)),
};
-static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
+static void ddr_cfg_umctl2(struct dram_controller *dram, struct dram_cfg_param *ddrc_cfg, int num)
{
int i = 0;
+ dram->imx8m_ddr_old_spreadsheet = true;
+
for (i = 0; i < num; i++) {
if (ddrc_cfg->reg == DDRC_ADDRMAP7(0))
- imx8m_ddr_old_spreadsheet = false;
+ dram->imx8m_ddr_old_spreadsheet = false;
reg32_write((unsigned long)ddrc_cfg->reg, ddrc_cfg->val);
ddrc_cfg++;
}
@@ -35,7 +35,7 @@ static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
* which falsifies the memory size read back from the controller
* in barebox proper.
*/
- if (imx8m_ddr_old_spreadsheet) {
+ if (dram->imx8m_ddr_old_spreadsheet) {
pr_warn("Working around old spreadsheet. Please regenerate\n");
/*
* Alternatively, stick { DDRC_ADDRMAP7(0), 0xf0f } into
@@ -518,7 +518,7 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
/* Step2: Program the dwc_ddr_umctl2 registers */
pr_debug("ddrc config start\n");
- ddr_cfg_umctl2(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
+ ddr_cfg_umctl2(dram, dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
pr_debug("ddrc config done\n");
/* Step3: De-assert reset signal(core_ddrc_rstn & aresetn_n) */
@@ -640,7 +640,7 @@ int imx8m_ddr_init(struct dram_controller *dram, struct dram_timing_info *dram_t
pr_debug("ddrmix config done\n");
/* save the dram timing config into memory */
- dram_config_save(dram_timing, IMX8M_SAVED_DRAM_TIMING_BASE);
+ dram_config_save(dram, dram_timing, IMX8M_SAVED_DRAM_TIMING_BASE);
return 0;
}
diff --git a/include/soc/imx/ddr.h b/include/soc/imx/ddr.h
index bc793cf3ed..581a3b461c 100644
--- a/include/soc/imx/ddr.h
+++ b/include/soc/imx/ddr.h
@@ -74,6 +74,7 @@ struct dram_controller {
void __iomem *phy_base;
void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
+ bool imx8m_ddr_old_spreadsheet;
};
void ddr_get_firmware_lpddr4(void);
@@ -90,7 +91,8 @@ static inline void ddr_get_firmware(enum dram_type dram_type)
int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info);
void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param,
unsigned int num);
-void *dram_config_save(struct dram_timing_info *info, unsigned long base);
+void *dram_config_save(struct dram_controller *dram, struct dram_timing_info *info,
+ unsigned long base);
/* utils function for ddr phy training */
int wait_ddrphy_training_complete(struct dram_controller *dram);
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index abd9961099..5df07772b3 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -374,8 +374,6 @@ static inline int imx8m_wait_ddrphy_training_complete(void)
return wait_ddrphy_training_complete(&imx8m_dram_controller);
}
-extern bool imx8m_ddr_old_spreadsheet;
-
static inline void imx8m_ddr_load_train_code(enum dram_type dram_type,
enum fw_type fw_type)
{
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 13/13] ddr: Initial i.MX9 support
2023-11-10 13:00 [PATCH 00/13] Add i.MX9 DDR support Sascha Hauer
` (11 preceding siblings ...)
2023-11-10 13:00 ` [PATCH 12/13] ddr: move imx8m_ddr_old_spreadsheet to controller Sascha Hauer
@ 2023-11-10 13:00 ` Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/ddr/imx/Kconfig | 6 +-
drivers/ddr/imx/Makefile | 1 +
drivers/ddr/imx/imx9_ddr_init.c | 698 ++++++++++++++++++++++++++++++++
include/soc/imx/ddr.h | 17 +-
include/soc/imx9/ddr.h | 18 +
5 files changed, 738 insertions(+), 2 deletions(-)
create mode 100644 drivers/ddr/imx/imx9_ddr_init.c
create mode 100644 include/soc/imx9/ddr.h
diff --git a/drivers/ddr/imx/Kconfig b/drivers/ddr/imx/Kconfig
index 43e9181582..71d4144e85 100644
--- a/drivers/ddr/imx/Kconfig
+++ b/drivers/ddr/imx/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "i.MX DDR controllers"
- depends on ARCH_IMX8MQ || ARCH_IMX8MM || ARCH_IMX8MN || ARCH_IMX8MP
+ depends on ARCH_IMX8MQ || ARCH_IMX8MM || ARCH_IMX8MN || ARCH_IMX8MP || ARCH_IMX93
config IMX_DRAM
bool
@@ -9,4 +9,8 @@ config IMX8M_DRAM
select IMX_DRAM
bool "imx8m dram controller support"
+config IMX9_DRAM
+ select IMX_DRAM
+ bool "imx9 dram controller support"
+
endmenu
diff --git a/drivers/ddr/imx/Makefile b/drivers/ddr/imx/Makefile
index 62d09e731a..1d24522bbb 100644
--- a/drivers/ddr/imx/Makefile
+++ b/drivers/ddr/imx/Makefile
@@ -5,3 +5,4 @@
#
pbl-$(CONFIG_IMX_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o
pbl-$(CONFIG_IMX8M_DRAM) += imx8m_ddr_init.o
+pbl-$(CONFIG_IMX9_DRAM) += imx9_ddr_init.o
diff --git a/drivers/ddr/imx/imx9_ddr_init.c b/drivers/ddr/imx/imx9_ddr_init.c
new file mode 100644
index 0000000000..cdee18e4ad
--- /dev/null
+++ b/drivers/ddr/imx/imx9_ddr_init.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ */
+
+#define pr_fmt(fmt) "imx9-ddr: " fmt
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <soc/imx9/ddr.h>
+#include <mach/imx/generic.h>
+#include <linux/iopoll.h>
+#include <soc/imx/clk-fracn-gppll.h>
+#include <mach/imx/imx9-regs.h>
+
+#define MX9_SRC_DPHY_BASE_ADDR (MX9_SRC_BASE_ADDR + 0x1400)
+#define REG_DDR_SDRAM_MD_CNTL (MX9_DDR_CTL_BASE + 0x120)
+#define REG_DDR_CS0_BNDS (MX9_DDR_CTL_BASE + 0x0)
+#define REG_DDR_CS1_BNDS (MX9_DDR_CTL_BASE + 0x8)
+#define REG_DDRDSR_2 (MX9_DDR_CTL_BASE + 0xB24)
+#define REG_DDR_TIMING_CFG_0 (MX9_DDR_CTL_BASE + 0x104)
+#define REG_DDR_SDRAM_CFG (MX9_DDR_CTL_BASE + 0x110)
+#define REG_DDR_TIMING_CFG_4 (MX9_DDR_CTL_BASE + 0x160)
+#define REG_DDR_DEBUG_19 (MX9_DDR_CTL_BASE + 0xF48)
+#define REG_DDR_SDRAM_CFG_3 (MX9_DDR_CTL_BASE + 0x260)
+#define REG_DDR_SDRAM_CFG_4 (MX9_DDR_CTL_BASE + 0x264)
+#define REG_DDR_SDRAM_MD_CNTL_2 (MX9_DDR_CTL_BASE + 0x270)
+#define REG_DDR_SDRAM_MPR4 (MX9_DDR_CTL_BASE + 0x28C)
+#define REG_DDR_SDRAM_MPR5 (MX9_DDR_CTL_BASE + 0x290)
+
+#define REG_DDR_ERR_EN (MX9_DDR_CTL_BASE + 0x1000)
+#define REG_SRC_DPHY_SW_CTRL (MX9_SRC_DPHY_BASE_ADDR + 0x20)
+#define REG_SRC_DPHY_SINGLE_RESET_SW_CTRL (MX9_SRC_DPHY_BASE_ADDR + 0x24)
+
+#define IMX9_SAVED_DRAM_TIMING_BASE 0x2051C000
+
+static unsigned int g_cdd_rr_max[4];
+static unsigned int g_cdd_rw_max[4];
+static unsigned int g_cdd_wr_max[4];
+static unsigned int g_cdd_ww_max[4];
+
+static void ddrphy_coldreset(void)
+{
+ /* dramphy_apb_n default 1 , assert -> 0, de_assert -> 1 */
+ /* dramphy_reset_n default 0 , assert -> 0, de_assert -> 1 */
+ /* dramphy_PwrOKIn default 0 , assert -> 1, de_assert -> 0 */
+
+ /* src_gen_dphy_apb_sw_rst_de_assert */
+ clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+ /* src_gen_dphy_sw_rst_de_assert */
+ clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+ /* src_gen_dphy_PwrOKIn_sw_rst_de_assert() */
+ setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0));
+ mdelay(10);
+
+ /* src_gen_dphy_apb_sw_rst_assert */
+ setbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+ /* src_gen_dphy_sw_rst_assert */
+ setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+ mdelay(10);
+ /* src_gen_dphy_PwrOKIn_sw_rst_assert */
+ clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0));
+ mdelay(10);
+
+ /* src_gen_dphy_apb_sw_rst_de_assert */
+ clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0));
+ /* src_gen_dphy_sw_rst_de_assert() */
+ clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2));
+}
+
+static void check_ddrc_idle(void)
+{
+ u32 regval;
+
+ readl_poll_timeout(REG_DDRDSR_2, regval, regval & BIT(31), 0);
+}
+
+static void check_dfi_init_complete(void)
+{
+ u32 regval;
+
+ readl_poll_timeout(REG_DDRDSR_2, regval, regval & BIT(2), 0);
+
+ setbits_le32(REG_DDRDSR_2, BIT(2));
+}
+
+static void ddrc_config(struct dram_timing_info *dram_timing)
+{
+ u32 num = dram_timing->ddrc_cfg_num;
+ struct dram_cfg_param *ddrc_config;
+ int i = 0;
+
+ ddrc_config = dram_timing->ddrc_cfg;
+ for (i = 0; i < num; i++) {
+ writel(ddrc_config->val, (ulong)ddrc_config->reg);
+ ddrc_config++;
+ }
+
+ if (dram_timing->fsp_cfg) {
+ ddrc_config = dram_timing->fsp_cfg[0].ddrc_cfg;
+ while (ddrc_config->reg != 0) {
+ writel(ddrc_config->val, (ulong)ddrc_config->reg);
+ ddrc_config++;
+ }
+ }
+}
+
+static unsigned int look_for_max(unsigned int data[], unsigned int addr_start,
+ unsigned int addr_end)
+{
+ unsigned int i, imax = 0;
+
+ for (i = addr_start; i <= addr_end; i++) {
+ if (((data[i] >> 7) == 0) && data[i] > imax)
+ imax = data[i];
+ }
+
+ return imax;
+}
+
+static void get_trained_CDD(struct dram_controller *dram, u32 fsp)
+{
+ unsigned int i, tmp;
+ unsigned int cdd_cha[12], cdd_chb[12];
+ unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
+ unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
+
+ for (i = 0; i < 6; i++) {
+ tmp = dwc_ddrphy_apb_rd(dram, 0x54013 + i);
+ cdd_cha[i * 2] = tmp & 0xff;
+ cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
+ }
+
+ for (i = 0; i < 7; i++) {
+ tmp = dwc_ddrphy_apb_rd(dram, 0x5402c + i);
+
+ if (i == 0) {
+ cdd_chb[0] = (tmp >> 8) & 0xff;
+ } else if (i == 6) {
+ cdd_chb[11] = tmp & 0xff;
+ } else {
+ cdd_chb[i * 2 - 1] = tmp & 0xff;
+ cdd_chb[i * 2] = (tmp >> 8) & 0xff;
+ }
+ }
+
+ cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
+ cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
+ cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
+ cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
+ cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
+ cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
+ cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
+ cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
+ g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
+ g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
+ g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
+ g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
+}
+
+static u32 ddrc_get_fsp_reg_setting(struct dram_cfg_param *ddrc_cfg, unsigned int cfg_num, u32 reg)
+{
+ unsigned int i;
+
+ for (i = 0; i < cfg_num; i++) {
+ if (reg == ddrc_cfg[i].reg)
+ return ddrc_cfg[i].val;
+ }
+
+ return 0;
+}
+
+static void ddrc_update_fsp_reg_setting(struct dram_cfg_param *ddrc_cfg, int cfg_num,
+ u32 reg, u32 val)
+{
+ unsigned int i;
+
+ for (i = 0; i < cfg_num; i++) {
+ if (reg == ddrc_cfg[i].reg) {
+ ddrc_cfg[i].val = val;
+ return;
+ }
+ }
+}
+
+static void update_umctl2_rank_space_setting(struct dram_timing_info *dram_timing,
+ unsigned int pstat_num)
+{
+ u32 tmp, tmp_t;
+ u32 wwt, rrt, wrt, rwt;
+ u32 ext_wwt, ext_rrt, ext_wrt, ext_rwt;
+ u32 max_wwt, max_rrt, max_wrt, max_rwt;
+ u32 i;
+
+ for (i = 0; i < pstat_num; i++) {
+ /* read wwt, rrt, wrt, rwt fields from timing_cfg_0 */
+ if (!dram_timing->fsp_cfg_num) {
+ tmp = ddrc_get_fsp_reg_setting(dram_timing->ddrc_cfg,
+ dram_timing->ddrc_cfg_num,
+ REG_DDR_TIMING_CFG_0);
+ } else {
+ tmp = ddrc_get_fsp_reg_setting(dram_timing->fsp_cfg[i].ddrc_cfg,
+ ARRAY_SIZE(dram_timing->fsp_cfg[i].ddrc_cfg),
+ REG_DDR_TIMING_CFG_0);
+ }
+ wwt = (tmp >> 24) & 0x3;
+ rrt = (tmp >> 26) & 0x3;
+ wrt = (tmp >> 28) & 0x3;
+ rwt = (tmp >> 30) & 0x3;
+
+ /* read rxt_wwt, ext_rrt, ext_wrt, ext_rwt fields from timing_cfg_4 */
+ if (!dram_timing->fsp_cfg_num) {
+ tmp_t = ddrc_get_fsp_reg_setting(dram_timing->ddrc_cfg,
+ dram_timing->ddrc_cfg_num,
+ REG_DDR_TIMING_CFG_4);
+ } else {
+ tmp_t = ddrc_get_fsp_reg_setting(dram_timing->fsp_cfg[i].ddrc_cfg,
+ ARRAY_SIZE(dram_timing->fsp_cfg[i].ddrc_cfg),
+ REG_DDR_TIMING_CFG_4);
+ }
+ ext_wwt = (tmp_t >> 8) & 0x3;
+ ext_rrt = (tmp_t >> 10) & 0x3;
+ ext_wrt = (tmp_t >> 12) & 0x3;
+ ext_rwt = (tmp_t >> 14) & 0x3;
+
+ wwt = (ext_wwt << 2) | wwt;
+ rrt = (ext_rrt << 2) | rrt;
+ wrt = (ext_wrt << 2) | wrt;
+ rwt = (ext_rwt << 2) | rwt;
+
+ max_wwt = max(g_cdd_ww_max[0], wwt);
+ max_rrt = max(g_cdd_rr_max[0], rrt);
+ max_wrt = max(g_cdd_wr_max[0], wrt);
+ max_rwt = max(g_cdd_rw_max[0], rwt);
+ /* verify values to see if are bigger then 15 (4 bits) */
+ if (max_wwt > 15)
+ max_wwt = 15;
+ if (max_rrt > 15)
+ max_rrt = 15;
+ if (max_wrt > 15)
+ max_wrt = 15;
+ if (max_rwt > 15)
+ max_rwt = 15;
+
+ /* recalculate timings for controller registers */
+ wwt = max_wwt & 0x3;
+ rrt = max_rrt & 0x3;
+ wrt = max_wrt & 0x3;
+ rwt = max_rwt & 0x3;
+
+ ext_wwt = (max_wwt & 0xC) >> 2;
+ ext_rrt = (max_rrt & 0xC) >> 2;
+ ext_wrt = (max_wrt & 0xC) >> 2;
+ ext_rwt = (max_rwt & 0xC) >> 2;
+
+ /* update timing_cfg_0 and timing_cfg_4 */
+ tmp = (tmp & 0x00ffffff) | (rwt << 30) | (wrt << 28) |
+ (rrt << 26) | (wwt << 24);
+ tmp_t = (tmp_t & 0xFFFF00FF) | (ext_rwt << 14) |
+ (ext_wrt << 12) | (ext_rrt << 10) | (ext_wwt << 8);
+
+ if (!dram_timing->fsp_cfg_num) {
+ ddrc_update_fsp_reg_setting(dram_timing->ddrc_cfg,
+ dram_timing->ddrc_cfg_num,
+ REG_DDR_TIMING_CFG_0, tmp);
+ ddrc_update_fsp_reg_setting(dram_timing->ddrc_cfg,
+ dram_timing->ddrc_cfg_num,
+ REG_DDR_TIMING_CFG_4, tmp_t);
+ } else {
+ ddrc_update_fsp_reg_setting(dram_timing->fsp_cfg[i].ddrc_cfg,
+ ARRAY_SIZE(dram_timing->fsp_cfg[i].ddrc_cfg),
+ REG_DDR_TIMING_CFG_0, tmp);
+ ddrc_update_fsp_reg_setting(dram_timing->fsp_cfg[i].ddrc_cfg,
+ ARRAY_SIZE(dram_timing->fsp_cfg[i].ddrc_cfg),
+ REG_DDR_TIMING_CFG_4, tmp_t);
+ }
+ }
+}
+
+static u32 ddrc_mrr(u32 chip_select, u32 mode_reg_num, u32 *mode_reg_val)
+{
+ u32 temp;
+
+ writel(0x80000000, REG_DDR_SDRAM_MD_CNTL_2);
+ temp = 0x80000000 | (chip_select << 28) | (mode_reg_num << 0);
+ writel(temp, REG_DDR_SDRAM_MD_CNTL);
+ while ((readl(REG_DDR_SDRAM_MD_CNTL) & 0x80000000) == 0x80000000)
+ ;
+ while (!(readl(REG_DDR_SDRAM_MPR5)))
+ ;
+ *mode_reg_val = (readl(REG_DDR_SDRAM_MPR4) & 0xFF0000) >> 16;
+ writel(0x0, REG_DDR_SDRAM_MPR5);
+ while ((readl(REG_DDR_SDRAM_MPR5)))
+ ;
+ writel(0x0, REG_DDR_SDRAM_MPR4);
+ writel(0x0, REG_DDR_SDRAM_MD_CNTL_2);
+
+ return 0;
+}
+
+static void ddrc_mrs(u32 cs_sel, u32 opcode, u32 mr)
+{
+ u32 regval;
+
+ regval = (cs_sel << 28) | (opcode << 6) | (mr);
+ writel(regval, REG_DDR_SDRAM_MD_CNTL);
+ setbits_le32(REG_DDR_SDRAM_MD_CNTL, BIT(31));
+ check_ddrc_idle();
+}
+
+static u32 lpddr4_mr_read(u32 mr_rank, u32 mr_addr)
+{
+ u32 chip_select, regval;
+
+ if (mr_rank == 1)
+ chip_select = 0; /* CS0 */
+ else if (mr_rank == 2)
+ chip_select = 1; /* CS1 */
+ else
+ chip_select = 4; /* CS0 & CS1 */
+
+ ddrc_mrr(chip_select, mr_addr, ®val);
+
+ return regval;
+}
+
+static void update_mr_fsp_op0(struct dram_cfg_param *cfg, unsigned int num)
+{
+ int i;
+
+ ddrc_mrs(0x4, 0x88, 13); /* FSP-OP->1, FSP-WR->0, VRCG=1, DMD=0 */
+ for (i = 0; i < num; i++) {
+ if (cfg[i].reg)
+ ddrc_mrs(0x4, cfg[i].val, cfg[i].reg);
+ }
+ ddrc_mrs(0x4, 0xc0, 13); /* FSP-OP->1, FSP-WR->1, VRCG=0, DMD=0 */
+}
+
+static void save_trained_mr12_14(struct dram_cfg_param *cfg, u32 cfg_num, u32 mr12, u32 mr14)
+{
+ int i;
+
+ for (i = 0; i < cfg_num; i++) {
+ if (cfg->reg == 12)
+ cfg->val = mr12;
+ else if (cfg->reg == 14)
+ cfg->val = mr14;
+ cfg++;
+ }
+}
+
+#define MHZ(x) ((x) * 1000000UL)
+
+#define SHARED_GPR_DRAM_CLK 2
+#define SHARED_GPR_DRAM_CLK_SEL_PLL 0
+#define SHARED_GPR_DRAM_CLK_SEL_CCM BIT(0)
+
+static struct imx_fracn_gppll_rate_table imx9_fracpll_tbl[] = {
+ { .rate = 1000000000U, .rdiv = 1, .mfi = 166, .odiv = 4, .mfn = 2, .mfd = 3 }, /* 1000MHz */
+ { .rate = 933000000U, .rdiv = 1, .mfi = 155, .odiv = 4, .mfn = 1, .mfd = 2 }, /* 933MHz */
+ { .rate = 700000000U, .rdiv = 1, .mfi = 145, .odiv = 5, .mfn = 5, .mfd = 6 }, /* 700MHz */
+ { .rate = 484000000U, .rdiv = 1, .mfi = 121, .odiv = 6, .mfn = 0, .mfd = 1 }, /* 480MHz */
+ { .rate = 445333333U, .rdiv = 1, .mfi = 167, .odiv = 9, .mfn = 0, .mfd = 1 },
+ { .rate = 466000000U, .rdiv = 1, .mfi = 155, .odiv = 8, .mfn = 1, .mfd = 3 }, /* 466MHz */
+ { .rate = 400000000U, .rdiv = 1, .mfi = 200, .odiv = 12, .mfn = 0, .mfd = 1 }, /* 400MHz */
+ { .rate = 300000000U, .rdiv = 1, .mfi = 150, .odiv = 12, .mfn = 0, .mfd = 1 },
+};
+
+static int dram_pll_init(u32 freq)
+{
+ return fracn_gppll_set_rate(IOMEM(MX9_ANATOP_DRAM_PLL_BASE_ADDR),
+ CLK_FRACN_GPPLL_FRACN, imx9_fracpll_tbl,
+ ARRAY_SIZE(imx9_fracpll_tbl), freq);
+}
+
+static void ccm_shared_gpr_set(u32 gpr, u32 val)
+{
+ writel(val, IOMEM(MX9_CCM_BASE_ADDR + 0x4800));
+}
+
+#define DRAM_ALT_CLK_ROOT 76
+#define DRAM_APB_CLK_ROOT 77
+
+#define CLK_ROOT_MUX GENMASK(9, 8)
+#define CLK_ROOT_DIV GENMASK(9, 0)
+
+static void ccm_clk_root_cfg(u32 clk_root_id, int mux, u32 div)
+{
+ void __iomem *base = IOMEM(MX9_CCM_BASE_ADDR) + clk_root_id * 0x80;
+
+ writel(FIELD_PREP(CLK_ROOT_MUX, mux) | FIELD_PREP(CLK_ROOT_DIV, div - 1), base);
+};
+
+static void dram_enable_bypass(ulong clk_val)
+{
+ switch (clk_val) {
+ case MHZ(625):
+ ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, 3, 1);
+ break;
+ case MHZ(400):
+ ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, 2, 2);
+ break;
+ case MHZ(333):
+ ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, 1, 3);
+ break;
+ case MHZ(200):
+ ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, 2, 4);
+ break;
+ case MHZ(100):
+ ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, 2, 8);
+ break;
+ default:
+ printf("No matched freq table %lu\n", clk_val);
+ return;
+ }
+
+ /* Set DRAM APB to 133Mhz */
+ ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, 2, 3);
+ /* Switch from DRAM clock root from PLL to CCM */
+ ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_CCM);
+}
+
+static void dram_disable_bypass(void)
+{
+ /* Set DRAM APB to 133Mhz */
+ ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, 2, 3);
+ /* Switch from DRAM clock root from CCM to PLL */
+ ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_PLL);
+}
+
+static void ddrphy_init_set_dfi_clk(struct dram_controller *dram, unsigned int drate_mhz)
+{
+ switch (drate_mhz) {
+ case 4000:
+ dram_pll_init(MHZ(1000));
+ dram_disable_bypass();
+ break;
+ case 3733:
+ case 3732:
+ dram_pll_init(MHZ(933));
+ dram_disable_bypass();
+ break;
+ case 3200:
+ dram_pll_init(MHZ(800));
+ dram_disable_bypass();
+ break;
+ case 3000:
+ dram_pll_init(MHZ(750));
+ dram_disable_bypass();
+ break;
+ case 2800:
+ dram_pll_init(MHZ(700));
+ dram_disable_bypass();
+ break;
+ case 2400:
+ dram_pll_init(MHZ(600));
+ dram_disable_bypass();
+ break;
+ case 1866:
+ dram_pll_init(MHZ(466));
+ dram_disable_bypass();
+ break;
+ case 1600:
+ dram_pll_init(MHZ(400));
+ dram_disable_bypass();
+ break;
+ case 1066:
+ dram_pll_init(MHZ(266));
+ dram_disable_bypass();
+ break;
+ case 667:
+ dram_pll_init(MHZ(167));
+ dram_disable_bypass();
+ break;
+ case 625:
+ dram_enable_bypass(MHZ(625));
+ break;
+ case 400:
+ dram_enable_bypass(MHZ(400));
+ break;
+ case 333:
+ dram_enable_bypass(MHZ(333));
+ break;
+ case 200:
+ dram_enable_bypass(MHZ(200));
+ break;
+ case 100:
+ dram_enable_bypass(MHZ(100));
+ break;
+ default:
+ return;
+ }
+}
+
+static u32 ddrphy_addr_remap(u32 paddr_apb_from_ctlr)
+{
+ u32 paddr_apb_qual;
+ u32 paddr_apb_unqual_dec_22_13;
+ u32 paddr_apb_unqual_dec_19_13;
+ u32 paddr_apb_unqual_dec_12_1;
+ u32 paddr_apb_unqual;
+ u32 paddr_apb_phy;
+
+ paddr_apb_qual = (paddr_apb_from_ctlr << 1);
+ paddr_apb_unqual_dec_22_13 = ((paddr_apb_qual & 0x7fe000) >> 13);
+ paddr_apb_unqual_dec_12_1 = ((paddr_apb_qual & 0x1ffe) >> 1);
+
+ switch (paddr_apb_unqual_dec_22_13) {
+ case 0x000 ... 0x00b:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13;
+ break;
+ case 0x100 ... 0x10b:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x100 + 0xc;
+ break;
+ case 0x200 ... 0x20b:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x200 + 0x18;
+ break;
+ case 0x300 ... 0x30b:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x300 + 0x24;
+ break;
+ case 0x010 ... 0x019:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x10 + 0x30;
+ break;
+ case 0x110 ... 0x119:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x110 + 0x3a;
+ break;
+ case 0x210 ... 0x219:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x210 + 0x44;
+ break;
+ case 0x310 ... 0x319:
+ paddr_apb_unqual_dec_19_13 = paddr_apb_unqual_dec_22_13 - 0x310 + 0x4e;
+ break;
+ case 0x020:
+ paddr_apb_unqual_dec_19_13 = 0x58;
+ break;
+ case 0x120:
+ paddr_apb_unqual_dec_19_13 = 0x59;
+ break;
+ case 0x220:
+ paddr_apb_unqual_dec_19_13 = 0x5a;
+ break;
+ case 0x320:
+ paddr_apb_unqual_dec_19_13 = 0x5b;
+ break;
+ case 0x040:
+ paddr_apb_unqual_dec_19_13 = 0x5c;
+ break;
+ case 0x140:
+ paddr_apb_unqual_dec_19_13 = 0x5d;
+ break;
+ case 0x240:
+ paddr_apb_unqual_dec_19_13 = 0x5e;
+ break;
+ case 0x340:
+ paddr_apb_unqual_dec_19_13 = 0x5f;
+ break;
+ case 0x050:
+ paddr_apb_unqual_dec_19_13 = 0x60;
+ break;
+ case 0x051:
+ paddr_apb_unqual_dec_19_13 = 0x61;
+ break;
+ case 0x052:
+ paddr_apb_unqual_dec_19_13 = 0x62;
+ break;
+ case 0x053:
+ paddr_apb_unqual_dec_19_13 = 0x63;
+ break;
+ case 0x054:
+ paddr_apb_unqual_dec_19_13 = 0x64;
+ break;
+ case 0x055:
+ paddr_apb_unqual_dec_19_13 = 0x65;
+ break;
+ case 0x056:
+ paddr_apb_unqual_dec_19_13 = 0x66;
+ break;
+ case 0x057:
+ paddr_apb_unqual_dec_19_13 = 0x67;
+ break;
+ case 0x070:
+ paddr_apb_unqual_dec_19_13 = 0x68;
+ break;
+ case 0x090:
+ paddr_apb_unqual_dec_19_13 = 0x69;
+ break;
+ case 0x190:
+ paddr_apb_unqual_dec_19_13 = 0x6a;
+ break;
+ case 0x290:
+ paddr_apb_unqual_dec_19_13 = 0x6b;
+ break;
+ case 0x390:
+ paddr_apb_unqual_dec_19_13 = 0x6c;
+ break;
+ case 0x0c0:
+ paddr_apb_unqual_dec_19_13 = 0x6d;
+ break;
+ case 0x0d0:
+ paddr_apb_unqual_dec_19_13 = 0x6e;
+ break;
+ default:
+ paddr_apb_unqual_dec_19_13 = 0x00;
+ break;
+ }
+
+ paddr_apb_unqual = (paddr_apb_unqual_dec_19_13 << 13) | (paddr_apb_unqual_dec_12_1 << 1);
+
+ paddr_apb_phy = paddr_apb_unqual << 1;
+
+ return paddr_apb_phy;
+}
+
+struct dram_controller imx9_dram_controller = {
+ .phy_base = IOMEM(MX9_DDR_PHY_BASE),
+ .phy_remap = ddrphy_addr_remap,
+ .get_trained_CDD = get_trained_CDD,
+ .set_dfi_clk = ddrphy_init_set_dfi_clk,
+};
+
+int imx9_ddr_init(struct dram_timing_info *dram_timing, enum dram_type dram_type)
+{
+ unsigned int initial_drate;
+ struct dram_timing_info *saved_timing;
+ void *fsp;
+ int ret;
+ u32 mr12, mr14;
+ u32 regval;
+ struct dram_controller *dram = &imx9_dram_controller;
+
+ debug("DDRINFO: start DRAM init\n");
+
+ dram->dram_type = dram_type;
+
+ /* reset ddrphy */
+ ddrphy_coldreset();
+
+ debug("DDRINFO: cfg clk\n");
+
+ initial_drate = dram_timing->fsp_msg[0].drate;
+ /* default to the frequency point 0 clock */
+ ddrphy_init_set_dfi_clk(dram, initial_drate);
+
+ /*
+ * Start PHY initialization and training by
+ * accessing relevant PUB registers
+ */
+ debug("DDRINFO:ddrphy config start\n");
+
+ ret = ddr_cfg_phy(dram, dram_timing);
+ if (ret)
+ return ret;
+
+ debug("DDRINFO: ddrphy config done\n");
+
+ update_umctl2_rank_space_setting(dram_timing, dram_timing->fsp_msg_num - 1);
+
+ /* rogram the ddrc registers */
+ debug("DDRINFO: ddrc config start\n");
+ ddrc_config(dram_timing);
+ debug("DDRINFO: ddrc config done\n");
+
+ writel(0x200000, REG_DDR_DEBUG_19);
+
+ check_dfi_init_complete();
+
+ regval = readl(REG_DDR_SDRAM_CFG);
+ writel((regval | 0x80000000), REG_DDR_SDRAM_CFG);
+
+ check_ddrc_idle();
+
+ mr12 = lpddr4_mr_read(1, 12);
+ mr14 = lpddr4_mr_read(1, 14);
+
+ /* save the dram timing config into memory */
+ fsp = dram_config_save(dram, dram_timing, IMX9_SAVED_DRAM_TIMING_BASE);
+
+ saved_timing = (struct dram_timing_info *)IMX9_SAVED_DRAM_TIMING_BASE;
+ saved_timing->fsp_cfg = fsp;
+ saved_timing->fsp_cfg_num = dram_timing->fsp_cfg_num;
+ if (saved_timing->fsp_cfg_num) {
+ memcpy(saved_timing->fsp_cfg, dram_timing->fsp_cfg,
+ dram_timing->fsp_cfg_num * sizeof(struct dram_fsp_cfg));
+
+ save_trained_mr12_14(saved_timing->fsp_cfg[0].mr_cfg,
+ ARRAY_SIZE(saved_timing->fsp_cfg[0].mr_cfg), mr12, mr14);
+ /*
+ * Configure mode registers in fsp1 to mode register 0 because DDRC
+ * doesn't automatically set.
+ */
+ if (saved_timing->fsp_cfg_num > 1)
+ update_mr_fsp_op0(saved_timing->fsp_cfg[1].mr_cfg,
+ ARRAY_SIZE(saved_timing->fsp_cfg[1].mr_cfg));
+ }
+
+ return 0;
+}
diff --git a/include/soc/imx/ddr.h b/include/soc/imx/ddr.h
index 581a3b461c..8553452ad8 100644
--- a/include/soc/imx/ddr.h
+++ b/include/soc/imx/ddr.h
@@ -41,6 +41,12 @@ struct dram_cfg_param {
unsigned int val;
};
+struct dram_fsp_cfg {
+ struct dram_cfg_param ddrc_cfg[20];
+ struct dram_cfg_param mr_cfg[10];
+ unsigned int bypass;
+};
+
struct dram_fsp_msg {
unsigned int drate;
enum fw_type fw_type;
@@ -52,6 +58,9 @@ struct dram_timing_info {
/* umctl2 config */
struct dram_cfg_param *ddrc_cfg;
unsigned int ddrc_cfg_num;
+ /* fsp config */
+ struct dram_fsp_cfg *fsp_cfg;
+ unsigned int fsp_cfg_num;
/* ddrphy config */
struct dram_cfg_param *ddrphy_cfg;
unsigned int ddrphy_cfg_num;
@@ -72,6 +81,7 @@ struct dram_controller {
enum ddrc_type ddrc_type;
enum dram_type dram_type;
void __iomem *phy_base;
+ u32 (*phy_remap)(u32 paddr_apb_from_ctlr);
void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp);
void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz);
bool imx8m_ddr_old_spreadsheet;
@@ -107,7 +117,12 @@ static inline void reg32setbit(unsigned long addr, u32 bit)
static inline void *dwc_ddrphy_apb_addr(struct dram_controller *dram, unsigned int addr)
{
- return dram->phy_base + addr * 4;
+ if (dram->phy_remap)
+ addr = dram->phy_remap(addr);
+ else
+ addr *= 4;
+
+ return dram->phy_base + addr;
}
static inline void dwc_ddrphy_apb_wr(struct dram_controller *dram, unsigned int addr, u32 data)
diff --git a/include/soc/imx9/ddr.h b/include/soc/imx9/ddr.h
new file mode 100644
index 0000000000..6435ce9d6d
--- /dev/null
+++ b/include/soc/imx9/ddr.h
@@ -0,0 +1,18 @@
+#ifndef __SOC_IMX9_DDR_H
+#define __SOC_IMX9_DDR_H
+
+#include <io.h>
+#include <asm/types.h>
+#include <soc/imx/ddr.h>
+
+int imx9_ddr_init(struct dram_timing_info *dram_timing, enum dram_type dram_type);
+
+static inline int imx93_ddr_init(struct dram_timing_info *dram_timing,
+ enum dram_type dram_type)
+{
+ ddr_get_firmware(dram_type);
+
+ return imx9_ddr_init(dram_timing, dram_type);
+}
+
+#endif /* __SOC_IMX9_DDR_H */
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread