diff options
Diffstat (limited to 'arch/arm/mach-imx/esdctl.c')
-rw-r--r-- | arch/arm/mach-imx/esdctl.c | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-imx/esdctl.c index b070ebc62a..a55ee06b83 100644 --- a/arch/arm/mach-imx/esdctl.c +++ b/arch/arm/mach-imx/esdctl.c @@ -317,6 +317,7 @@ static int vf610_ddrmc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) #define DDRC_ADDRMAP0_CS_BIT0 GENMASK(4, 0) #define DDRC_MSTR 0x0000 +#define DDRC_MSTR_DDR4 BIT(4) #define DDRC_MSTR_LPDDR4 BIT(5) #define DDRC_MSTR_DATA_BUS_WIDTH GENMASK(13, 12) #define DDRC_MSTR_ACTIVE_RANKS GENMASK(27, 24) @@ -370,9 +371,8 @@ static resource_size_t imx_ddrc_sdram_size(void __iomem *ddrc, const u32 addrmap[DDRC_ADDRMAP_LENGTH], u8 col_max, const u8 col_b[], unsigned int col_b_num, u8 row_max, const u8 row_b[], unsigned int row_b_num, - bool reduced_adress_space, bool is_imx8) + bool reduced_adress_space, unsigned int mstr) { - const u32 mstr = readl(ddrc + DDRC_MSTR); unsigned int banks, ranks, columns, rows, active_ranks, width; resource_size_t size; @@ -393,11 +393,13 @@ imx_ddrc_sdram_size(void __iomem *ddrc, const u32 addrmap[DDRC_ADDRMAP_LENGTH], BUG(); } - /* Bus width in bytes, 0 means half byte or 4-bit mode */ - if (is_imx8 && !(mstr & DDRC_MSTR_LPDDR4)) - width = (1 << FIELD_GET(DDRC_MSTR_DEVICE_CONFIG, mstr)) >> 1; - else - width = 4; + /* + * mstr is ignored for some SoCs/RAM types and may yield wrong + * results when used for calculation. Callers of this function + * are expected to fix it up as necessary. + * Bus width in bytes, 0 means half byte or 4-bit mode + */ + width = (1 << FIELD_GET(DDRC_MSTR_DEVICE_CONFIG, mstr)) >> 1; switch (FIELD_GET(DDRC_MSTR_DATA_BUS_WIDTH, mstr)) { case 0b00: /* Full DQ bus */ @@ -423,7 +425,12 @@ imx_ddrc_sdram_size(void __iomem *ddrc, const u32 addrmap[DDRC_ADDRMAP_LENGTH], if (FIELD_GET(DDRC_ADDRMAP1_BANK_B2, addrmap[1]) != 0b11111) banks++; - if (addrmap[8]) { + if (mstr & DDRC_MSTR_DDR4) { + /* FIXME: DDR register spreasheet claims this to be + * 6-bit and 63 meaning bank group address bit 0 is 0, + * but reference manual claims 5-bit without 'neutral' value + * See MX8M_Mini_DDR4_RPA_v17, MX8M_Nano_DDR4_RPA_v8 + */ if (FIELD_GET(DDRC_ADDRMAP8_BG_B0, addrmap[8]) != 0b11111) banks++; if (FIELD_GET(DDRC_ADDRMAP8_BG_B1, addrmap[8]) != 0b111111) @@ -446,7 +453,13 @@ imx_ddrc_sdram_size(void __iomem *ddrc, const u32 addrmap[DDRC_ADDRMAP_LENGTH], return reduced_adress_space ? size * 3 / 4 : size; } -static resource_size_t imx8m_ddrc_sdram_size(void __iomem *ddrc) +static void imx_ddrc_set_mstr_device_config(u32 *mstr, unsigned bits) +{ + *mstr &= ~DDRC_MSTR_DEVICE_CONFIG; + *mstr |= FIELD_PREP(DDRC_MSTR_DEVICE_CONFIG, fls(bits / 8)); +} + +static resource_size_t imx8m_ddrc_sdram_size(void __iomem *ddrc, unsigned buswidth) { const u32 addrmap[DDRC_ADDRMAP_LENGTH] = { readl(ddrc + DDRC_ADDRMAP(0)), @@ -485,17 +498,28 @@ static resource_size_t imx8m_ddrc_sdram_size(void __iomem *ddrc) }; const bool reduced_adress_space = FIELD_GET(DDRC_ADDRMAP6_LPDDR4_6GB_12GB_24GB, addrmap[6]); + u32 mstr = readl(ddrc + DDRC_MSTR); + + /* Device config is ignored and taken as 32-bit for LPDDR4 */ + if (mstr & DDRC_MSTR_LPDDR4) + imx_ddrc_set_mstr_device_config(&mstr, buswidth); return imx_ddrc_sdram_size(ddrc, addrmap, 12, ARRAY_AND_SIZE(col_b), 18, ARRAY_AND_SIZE(row_b), - reduced_adress_space, true); + reduced_adress_space, mstr); } static int imx8m_ddrc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) { return arm_add_mem_device("ram0", data->base0, - imx8m_ddrc_sdram_size(mmdcbase)); + imx8m_ddrc_sdram_size(mmdcbase, 32)); +} + +static int imx8mn_ddrc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) +{ + return arm_add_mem_device("ram0", data->base0, + imx8m_ddrc_sdram_size(mmdcbase, 16)); } static resource_size_t imx7d_ddrc_sdram_size(void __iomem *ddrc) @@ -527,11 +551,15 @@ static resource_size_t imx7d_ddrc_sdram_size(void __iomem *ddrc) }; const bool reduced_adress_space = FIELD_GET(DDRC_ADDRMAP6_LPDDR3_6GB_12GB, addrmap[6]); + u32 mstr = readl(ddrc + DDRC_MSTR); + + /* Device config is unused on i.MX7, so rewrite it as 32-bit wide */ + imx_ddrc_set_mstr_device_config(&mstr, 32); return imx_ddrc_sdram_size(ddrc, addrmap, 11, ARRAY_AND_SIZE(col_b), 15, ARRAY_AND_SIZE(row_b), - reduced_adress_space, false); + reduced_adress_space, mstr); } static int imx7d_ddrc_add_mem(void *mmdcbase, struct imx_esdctl_data *data) @@ -629,6 +657,11 @@ static __maybe_unused struct imx_esdctl_data imx8mq_data = { .add_mem = imx8m_ddrc_add_mem, }; +static __maybe_unused struct imx_esdctl_data imx8mn_data = { + .base0 = MX8M_DDR_CSD1_BASE_ADDR, + .add_mem = imx8mn_ddrc_add_mem, +}; + static __maybe_unused struct imx_esdctl_data imx7d_data = { .base0 = MX7_DDR_BASE_ADDR, .add_mem = imx7d_ddrc_add_mem, @@ -703,7 +736,7 @@ static __maybe_unused struct of_device_id imx_esdctl_dt_ids[] = { .data = &imx8mq_data }, { .compatible = "fsl,imx8mn-ddrc", - .data = &imx8mq_data + .data = &imx8mn_data }, { .compatible = "fsl,imx8mq-ddrc", .data = &imx8mq_data @@ -890,11 +923,11 @@ void __noreturn vf610_barebox_entry(void *boarddata) boarddata); } -static void __noreturn imx8m_barebox_entry(void *boarddata) +static void __noreturn imx8m_barebox_entry(void *boarddata, unsigned buswidth) { resource_size_t size; - size = imx8m_ddrc_sdram_size(IOMEM(MX8M_DDRC_CTL_BASE_ADDR)); + size = imx8m_ddrc_sdram_size(IOMEM(MX8M_DDRC_CTL_BASE_ADDR), buswidth); /* * We artificially limit detected memory size to force malloc * pool placement to be within 4GiB address space, so as to @@ -910,22 +943,22 @@ static void __noreturn imx8m_barebox_entry(void *boarddata) void __noreturn imx8mm_barebox_entry(void *boarddata) { - imx8m_barebox_entry(boarddata); + imx8m_barebox_entry(boarddata, 32); } void __noreturn imx8mn_barebox_entry(void *boarddata) { - imx8m_barebox_entry(boarddata); + imx8m_barebox_entry(boarddata, 16); } void __noreturn imx8mp_barebox_entry(void *boarddata) { - imx8m_barebox_entry(boarddata); + imx8m_barebox_entry(boarddata, 32); } void __noreturn imx8mq_barebox_entry(void *boarddata) { - imx8m_barebox_entry(boarddata); + imx8m_barebox_entry(boarddata, 32); } void __noreturn imx7d_barebox_entry(void *boarddata) |