// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 Ahmad Fatoum */ #include #include #include #include #include #include #include #include #include #include #define ADDRMAP1_BANK_B0 GENMASK( 5, 0) #define ADDRMAP1_BANK_B1 GENMASK(13, 8) #define ADDRMAP1_BANK_B2 GENMASK(21, 16) #define ADDRMAP2_COL_B2 GENMASK( 3, 0) #define ADDRMAP2_COL_B3 GENMASK(11, 8) #define ADDRMAP2_COL_B4 GENMASK(19, 16) #define ADDRMAP2_COL_B5 GENMASK(27, 24) #define ADDRMAP3_COL_B6 GENMASK( 3, 0) #define ADDRMAP3_COL_B7 GENMASK(11, 8) #define ADDRMAP3_COL_B8 GENMASK(19, 16) #define ADDRMAP3_COL_B9 GENMASK(27, 24) #define ADDRMAP4_COL_B10 GENMASK( 3, 0) #define ADDRMAP4_COL_B11 GENMASK(11, 8) #define ADDRMAP5_ROW_B0 GENMASK( 3, 0) #define ADDRMAP5_ROW_B1 GENMASK(11, 8) #define ADDRMAP5_ROW_B2_10 GENMASK(19, 16) #define ADDRMAP5_ROW_B11 GENMASK(27, 24) #define ADDRMAP6_ROW_B12 GENMASK( 3, 0) #define ADDRMAP6_ROW_B13 GENMASK(11, 8) #define ADDRMAP6_ROW_B14 GENMASK(19, 16) #define ADDRMAP6_ROW_B15 GENMASK(27, 24) #define ADDRMAP9_ROW_B2 GENMASK( 3, 0) #define ADDRMAP9_ROW_B3 GENMASK(11, 8) #define ADDRMAP9_ROW_B4 GENMASK(19, 16) #define ADDRMAP9_ROW_B5 GENMASK(27, 24) #define ADDRMAP10_ROW_B6 GENMASK( 3, 0) #define ADDRMAP10_ROW_B7 GENMASK(11, 8) #define ADDRMAP10_ROW_B8 GENMASK(19, 16) #define ADDRMAP10_ROW_B9 GENMASK(27, 24) #define ADDRMAP11_ROW_B10 GENMASK( 3, 0) #define LINE_UNUSED(reg, mask) (((reg) & (mask)) == (mask)) enum ddrctrl_buswidth { BUSWIDTH_FULL = 0, BUSWIDTH_HALF = 1, BUSWIDTH_QUARTER = 2 }; static unsigned long ddrctrl_addrmap_ramsize(struct stm32mp1_ddrctl __iomem *d, enum ddrctrl_buswidth buswidth, unsigned nb_bytes) { unsigned banks = 3, cols = 12, rows = 16; u32 reg; cols += buswidth; reg = readl(&d->addrmap1); if (LINE_UNUSED(reg, ADDRMAP1_BANK_B2)) banks--; if (LINE_UNUSED(reg, ADDRMAP1_BANK_B1)) banks--; if (LINE_UNUSED(reg, ADDRMAP1_BANK_B0)) banks--; reg = readl(&d->addrmap2); if (LINE_UNUSED(reg, ADDRMAP2_COL_B5)) cols--; if (LINE_UNUSED(reg, ADDRMAP2_COL_B4)) cols--; if (LINE_UNUSED(reg, ADDRMAP2_COL_B3)) cols--; if (LINE_UNUSED(reg, ADDRMAP2_COL_B2)) cols--; reg = readl(&d->addrmap3); if (LINE_UNUSED(reg, ADDRMAP3_COL_B9)) cols--; if (LINE_UNUSED(reg, ADDRMAP3_COL_B8)) cols--; if (LINE_UNUSED(reg, ADDRMAP3_COL_B7)) cols--; if (LINE_UNUSED(reg, ADDRMAP3_COL_B6)) cols--; reg = readl(&d->addrmap4); if (LINE_UNUSED(reg, ADDRMAP4_COL_B11)) cols--; if (LINE_UNUSED(reg, ADDRMAP4_COL_B10)) cols--; reg = readl(&d->addrmap5); if (LINE_UNUSED(reg, ADDRMAP5_ROW_B11)) rows--; reg = readl(&d->addrmap6); if (LINE_UNUSED(reg, ADDRMAP6_ROW_B15)) rows--; if (LINE_UNUSED(reg, ADDRMAP6_ROW_B14)) rows--; if (LINE_UNUSED(reg, ADDRMAP6_ROW_B13)) rows--; if (LINE_UNUSED(reg, ADDRMAP6_ROW_B12)) rows--; return memory_sdram_size(cols, rows, BIT(banks), DIV_ROUND_UP(nb_bytes, BIT(buswidth))); } static inline unsigned ddrctrl_ramsize(void __iomem *base, unsigned nb_bytes) { struct stm32mp1_ddrctl __iomem *ddrctl = base; unsigned buswidth = readl(&ddrctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK; buswidth >>= DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT; return ddrctrl_addrmap_ramsize(ddrctl, buswidth, nb_bytes); } static inline unsigned stm32mp1_ddrctrl_ramsize(void) { u32 nb_bytes = 4; if (cpu_stm32_is_stm32mp13()) nb_bytes /= 2; return ddrctrl_ramsize(IOMEM(STM32_DDRCTL_BASE), nb_bytes); } void __noreturn __prereloc stm32mp1_barebox_entry(void *boarddata) { barebox_arm_entry(STM32_DDR_BASE, stm32mp1_ddrctrl_ramsize(), boarddata); } static int stm32mp1_ddr_probe(struct device *dev) { struct resource *iores; void __iomem *base; unsigned long nb_bytes; iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); base = IOMEM(iores->start); nb_bytes = (unsigned long)device_get_match_data(dev); return arm_add_mem_device("ram0", STM32_DDR_BASE, ddrctrl_ramsize(base, nb_bytes)); } static __maybe_unused struct of_device_id stm32mp1_ddr_dt_ids[] = { { .compatible = "st,stm32mp1-ddr", .data = (void *)4 }, { .compatible = "st,stm32mp13-ddr", .data = (void *)2 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, stm32mp1_ddr_dt_ids); static struct driver stm32mp1_ddr_driver = { .name = "stm32mp1-ddr", .probe = stm32mp1_ddr_probe, .of_compatible = DRV_OF_COMPAT(stm32mp1_ddr_dt_ids), }; mem_platform_driver(stm32mp1_ddr_driver);