summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-stm32mp/ddrctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-stm32mp/ddrctrl.c')
-rw-r--r--arch/arm/mach-stm32mp/ddrctrl.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/arch/arm/mach-stm32mp/ddrctrl.c b/arch/arm/mach-stm32mp/ddrctrl.c
new file mode 100644
index 0000000000..962d4c0d52
--- /dev/null
+++ b/arch/arm/mach-stm32mp/ddrctrl.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum <a.fatoum@pengutronix.de>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <mach/stm32.h>
+#include <mach/ddr_regs.h>
+#include <mach/entry.h>
+#include <mach/stm32.h>
+#include <asm/barebox-arm.h>
+#include <asm/memory.h>
+#include <pbl.h>
+#include <io.h>
+
+#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(12, 8)
+#define ADDRMAP3_COL_B8 GENMASK(20, 16)
+#define ADDRMAP3_COL_B9 GENMASK(28, 24)
+
+#define ADDRMAP4_COL_B10 GENMASK( 4, 0)
+#define ADDRMAP4_COL_B11 GENMASK(12, 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 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), 4 / BIT(buswidth));
+}
+
+static inline unsigned ddrctrl_ramsize(void __iomem *base)
+{
+ 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);
+}
+
+static inline unsigned stm32mp1_ddrctrl_ramsize(void)
+{
+ return ddrctrl_ramsize(IOMEM(STM32_DDRCTL_BASE));
+}
+
+void __noreturn stm32mp1_barebox_entry(void *boarddata)
+{
+ barebox_arm_entry(STM32_DDR_BASE, stm32mp1_ddrctrl_ramsize(), boarddata);
+}
+
+
+static int stm32mp1_ddr_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ arm_add_mem_device("ram0", STM32_DDR_BASE, ddrctrl_ramsize(base));
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id stm32mp1_ddr_dt_ids[] = {
+ { .compatible = "st,stm32mp1-ddr" },
+ { /* sentinel */ }
+};
+
+static struct driver_d stm32mp1_ddr_driver = {
+ .name = "stm32mp1-ddr",
+ .probe = stm32mp1_ddr_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32mp1_ddr_dt_ids),
+};
+
+static int stm32mp1_ddr_init(void)
+{
+ return platform_driver_register(&stm32mp1_ddr_driver);
+}
+mem_initcall(stm32mp1_ddr_init);