* [PATCH 00/13] Add i.MX9 DDR support
@ 2023-11-10 13:00 Sascha Hauer
2023-11-10 13:00 ` [PATCH 01/13] ddr: imx8m: rename driver to imx Sascha Hauer
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-11-10 13:00 UTC (permalink / raw)
To: Barebox List
The i.MX9 DDR controller is very similar to the one found on i.MX8M.
Most patches in this series are for preparing the i.MX8M DDR driver
for integrating i.MX9 support. i.MX9 support is added in the last patch.
Sascha
Sascha Hauer (13):
ddr: imx8m: rename driver to imx
ddr: imx8m: introduce dram_controller struct
ddr: imx8m: move get_trained_CDD() to SoC code
ddr: imx8m: move PLL init to SoC specific code
ddr: imx8m: clean up defines
ddr: imx8m: move phy_base to controller struct
ddr: imx8m: remove empty function
ddr: imx8m: get rid of hardcoded phy address
ddr: imx8m: split header file
ddr: imx8m: return cfg from dram_config_save()
ddr: imx8m: Drop '8m' suffix from pr_fmt
ddr: move imx8m_ddr_old_spreadsheet to controller
ddr: Initial i.MX9 support
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/Kconfig | 2 +-
drivers/ddr/Makefile | 2 +-
drivers/ddr/{imx8m => imx}/Kconfig | 12 +-
drivers/ddr/imx/Makefile | 8 +
drivers/ddr/{imx8m => imx}/ddrphy_csr.c | 2 +-
drivers/ddr/{imx8m => imx}/ddrphy_train.c | 50 +-
drivers/ddr/imx/ddrphy_utils.c | 97 +++
drivers/ddr/{imx8m => imx}/helper.c | 28 +-
.../ddrphy_utils.c => imx/imx8m_ddr_init.c} | 595 +++++++++------
drivers/ddr/imx/imx9_ddr_init.c | 698 ++++++++++++++++++
drivers/ddr/imx8m/Makefile | 7 -
drivers/ddr/imx8m/ddr_init.c | 217 ------
include/soc/imx/ddr.h | 167 +++++
include/soc/imx8m/ddr.h | 162 +---
include/soc/imx9/ddr.h | 18 +
18 files changed, 1431 insertions(+), 666 deletions(-)
rename drivers/ddr/{imx8m => imx}/Kconfig (51%)
create mode 100644 drivers/ddr/imx/Makefile
rename drivers/ddr/{imx8m => imx}/ddrphy_csr.c (99%)
rename drivers/ddr/{imx8m => imx}/ddrphy_train.c (75%)
create mode 100644 drivers/ddr/imx/ddrphy_utils.c
rename drivers/ddr/{imx8m => imx}/helper.c (74%)
rename drivers/ddr/{imx8m/ddrphy_utils.c => imx/imx8m_ddr_init.c} (66%)
create mode 100644 drivers/ddr/imx/imx9_ddr_init.c
delete mode 100644 drivers/ddr/imx8m/Makefile
delete mode 100644 drivers/ddr/imx8m/ddr_init.c
create mode 100644 include/soc/imx/ddr.h
create mode 100644 include/soc/imx9/ddr.h
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [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
end of thread, other threads:[~2023-11-10 13:02 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 03/13] ddr: imx8m: move get_trained_CDD() to SoC code Sascha Hauer
2023-11-10 13:00 ` [PATCH 04/13] ddr: imx8m: move PLL init to SoC specific code Sascha Hauer
2023-11-10 13:00 ` [PATCH 05/13] ddr: imx8m: clean up defines Sascha Hauer
2023-11-10 13:00 ` [PATCH 06/13] ddr: imx8m: move phy_base to controller struct Sascha Hauer
2023-11-10 13:00 ` [PATCH 07/13] ddr: imx8m: remove empty function Sascha Hauer
2023-11-10 13:00 ` [PATCH 08/13] ddr: imx8m: get rid of hardcoded phy address Sascha Hauer
2023-11-10 13:00 ` [PATCH 09/13] ddr: imx8m: split header file Sascha Hauer
2023-11-10 13:00 ` [PATCH 10/13] ddr: imx8m: return cfg from dram_config_save() Sascha Hauer
2023-11-10 13:00 ` [PATCH 11/13] ddr: imx8m: Drop '8m' suffix from pr_fmt 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox