summaryrefslogtreecommitdiff
path: root/arch/arm/mach-rockchip
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-rockchip')
-rw-r--r--arch/arm/mach-rockchip/Kconfig6
-rw-r--r--arch/arm/mach-rockchip/Makefile3
-rw-r--r--arch/arm/mach-rockchip/atf.c34
-rw-r--r--arch/arm/mach-rockchip/bootrom.c51
-rw-r--r--arch/arm/mach-rockchip/dmc.c219
-rw-r--r--arch/arm/mach-rockchip/rk3568.c29
6 files changed, 314 insertions, 28 deletions
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 9b4913d5da..0bce83ecee 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -91,6 +91,12 @@ config MACH_RADXA_ROCK3
help
Say Y here if you are using a Radxa ROCK3
+config MACH_RADXA_CM3
+ select ARCH_RK3568
+ bool "Radxa CM3"
+ help
+ Say Y here if you are using a Radxa CM3
+
endif
comment "select board features:"
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 2529af7c7e..04d75ce287 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += rockchip.o
+obj-y += rockchip.o bootrom.o
pbl-$(CONFIG_ARCH_ROCKCHIP_ATF) += atf.o
obj-$(CONFIG_ARCH_RK3188) += rk3188.o
obj-$(CONFIG_ARCH_RK3288) += rk3288.o
obj-pbl-$(CONFIG_ARCH_RK3568) += rk3568.o
obj-$(CONFIG_ARCH_ROCKCHIP_V8) += bootm.o
+obj-pbl-$(CONFIG_ARCH_ROCKCHIP_V8) += dmc.o
obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o
diff --git a/arch/arm/mach-rockchip/atf.c b/arch/arm/mach-rockchip/atf.c
index 93025faf68..d1431cc526 100644
--- a/arch/arm/mach-rockchip/atf.c
+++ b/arch/arm/mach-rockchip/atf.c
@@ -5,6 +5,11 @@
#include <mach/rockchip/atf.h>
#include <elf.h>
#include <asm/atf_common.h>
+#include <asm/barebox-arm.h>
+#include <mach/rockchip/dmc.h>
+#include <mach/rockchip/rockchip.h>
+#include <mach/rockchip/bootrom.h>
+#include <mach/rockchip/rk3568-regs.h>
static unsigned long load_elf64_image_phdr(const void *elf)
{
@@ -69,3 +74,32 @@ void rk3568_atf_load_bl31(void *fdt)
{
rockchip_atf_load_bl31(RK3568, rk3568_bl31_bin, rk3568_op_tee_bin, fdt);
}
+
+void __noreturn rk3568_barebox_entry(void *fdt)
+{
+ unsigned long membase, memsize;
+
+ membase = RK3568_DRAM_BOTTOM;
+ memsize = rk3568_ram0_size() - RK3568_DRAM_BOTTOM;
+
+ if (current_el() == 3) {
+ rk3568_lowlevel_init();
+ rockchip_store_bootrom_iram(membase, memsize, IOMEM(RK3568_IRAM_BASE));
+
+ /*
+ * The downstream TF-A doesn't cope with our device tree when
+ * CONFIG_OF_OVERLAY_LIVE is enabled, supposedly because it is
+ * too big for some reason. Otherwise it doesn't have any visible
+ * effect if we pass a device tree or not, except that the TF-A
+ * fills in the ethernet MAC address into the device tree.
+ * The upstream TF-A doesn't use the device tree at all.
+ *
+ * Pass NULL for now until we have a good reason to pass a real
+ * device tree.
+ */
+ rk3568_atf_load_bl31(NULL);
+ /* not reached when CONFIG_ARCH_ROCKCHIP_ATF */
+ }
+
+ barebox_arm_entry(membase, memsize, fdt);
+}
diff --git a/arch/arm/mach-rockchip/bootrom.c b/arch/arm/mach-rockchip/bootrom.c
new file mode 100644
index 0000000000..cdd0536cda
--- /dev/null
+++ b/arch/arm/mach-rockchip/bootrom.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <mach/rockchip/bootrom.h>
+#include <io.h>
+#include <bootsource.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <errno.h>
+
+#define BROM_BOOTSOURCE_ID 0x10
+#define BROM_BOOTSOURCE_SLOT 0x14
+#define BROM_BOOTSOURCE_SLOT_ACTIVE GENMASK(12, 10)
+
+static const void __iomem *rk_iram;
+
+int rockchip_bootsource_get_active_slot(void)
+{
+ if (!rk_iram)
+ return -EINVAL;
+
+ return FIELD_GET(BROM_BOOTSOURCE_SLOT_ACTIVE,
+ readl(IOMEM(rk_iram) + BROM_BOOTSOURCE_SLOT));
+}
+
+struct rk_bootsource {
+ enum bootsource src;
+ int instance;
+};
+
+static struct rk_bootsource bootdev_map[] = {
+ [0x1] = { .src = BOOTSOURCE_NAND, .instance = 0 },
+ [0x2] = { .src = BOOTSOURCE_MMC, .instance = 0 },
+ [0x3] = { .src = BOOTSOURCE_SPI_NOR, .instance = 0 },
+ [0x4] = { .src = BOOTSOURCE_SPI_NAND, .instance = 0 },
+ [0x5] = { .src = BOOTSOURCE_MMC, .instance = 1 },
+ [0xa] = { .src = BOOTSOURCE_USB, .instance = 0 },
+};
+
+void rockchip_parse_bootrom_iram(const void *iram)
+{
+ u32 v;
+
+ rk_iram = iram;
+
+ v = readl(iram + BROM_BOOTSOURCE_ID);
+
+ if (v >= ARRAY_SIZE(bootdev_map))
+ return;
+
+ bootsource_set(bootdev_map[v].src, bootdev_map[v].instance);
+}
diff --git a/arch/arm/mach-rockchip/dmc.c b/arch/arm/mach-rockchip/dmc.c
new file mode 100644
index 0000000000..dd60db5830
--- /dev/null
+++ b/arch/arm/mach-rockchip/dmc.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#define pr_fmt(fmt) "rockchip-dmc: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <asm/barebox-arm.h>
+#include <asm/memory.h>
+#include <pbl.h>
+#include <io.h>
+#include <regmap.h>
+#include <mfd/syscon.h>
+#include <mach/rockchip/dmc.h>
+#include <mach/rockchip/rk3399-regs.h>
+#include <mach/rockchip/rk3568-regs.h>
+
+#define RK3399_PMUGRF_OS_REG2 0x308
+#define RK3399_PMUGRF_OS_REG3 0x30C
+
+#define RK3568_PMUGRF_OS_REG2 0x208
+#define RK3568_PMUGRF_OS_REG3 0x20c
+
+#define RK3399_INT_REG_START 0xf0000000
+#define RK3568_INT_REG_START RK3399_INT_REG_START
+
+struct rockchip_dmc_drvdata {
+ unsigned int os_reg2;
+ unsigned int os_reg3;
+ resource_size_t internal_registers_start;
+};
+
+static resource_size_t rockchip_sdram_size(u32 sys_reg2, u32 sys_reg3)
+{
+ u32 rank, cs0_col, bk, cs0_row, cs1_row, bw, row_3_4;
+ resource_size_t chipsize_mb, size_mb = 0;
+ u32 ch;
+ u32 cs1_col;
+ u32 bg = 0;
+ u32 dbw, dram_type;
+ u32 ch_num = 1 + FIELD_GET(SYS_REG_NUM_CH, sys_reg2);
+ u32 version = FIELD_GET(SYS_REG_VERSION, sys_reg3);
+
+ pr_debug("%s(reg2=%x, reg3=%x)\n", __func__, sys_reg2, sys_reg3);
+
+ dram_type = FIELD_GET(SYS_REG_DDRTYPE, sys_reg2);
+
+ if (version >= 3)
+ dram_type |= FIELD_GET(SYS_REG_EXTEND_DDRTYPE, sys_reg3) << 3;
+
+ for (ch = 0; ch < ch_num; ch++) {
+ rank = 1 + (sys_reg2 >> SYS_REG_RANK_SHIFT(ch) & SYS_REG_RANK_MASK);
+ cs0_col = 9 + (sys_reg2 >> SYS_REG_COL_SHIFT(ch) & SYS_REG_COL_MASK);
+ cs1_col = cs0_col;
+
+ bk = 3 - ((sys_reg2 >> SYS_REG_BK_SHIFT(ch)) & SYS_REG_BK_MASK);
+
+ cs0_row = sys_reg2 >> SYS_REG_CS0_ROW_SHIFT(ch) & SYS_REG_CS0_ROW_MASK;
+ cs1_row = sys_reg2 >> SYS_REG_CS1_ROW_SHIFT(ch) & SYS_REG_CS1_ROW_MASK;
+
+ if (version >= 2) {
+ cs1_col = 9 + (sys_reg3 >> SYS_REG_CS1_COL_SHIFT(ch) &
+ SYS_REG_CS1_COL_MASK);
+
+ cs0_row |= (sys_reg3 >> SYS_REG_EXTEND_CS0_ROW_SHIFT(ch) &
+ SYS_REG_EXTEND_CS0_ROW_MASK) << 2;
+
+ if (cs0_row == 7)
+ cs0_row = 12;
+ else
+ cs0_row += 13;
+
+ cs1_row |= (sys_reg3 >> SYS_REG_EXTEND_CS1_ROW_SHIFT(ch) &
+ SYS_REG_EXTEND_CS1_ROW_MASK) << 2;
+
+ if (cs1_row == 7)
+ cs1_row = 12;
+ else
+ cs1_row += 13;
+ } else {
+ cs0_row += 13;
+ cs1_row += 13;
+ }
+
+ bw = (2 >> ((sys_reg2 >> SYS_REG_BW_SHIFT(ch)) & SYS_REG_BW_MASK));
+ row_3_4 = sys_reg2 >> SYS_REG_ROW_3_4_SHIFT(ch) & SYS_REG_ROW_3_4_MASK;
+
+ if (dram_type == DDR4) {
+ dbw = (sys_reg2 >> SYS_REG_DBW_SHIFT(ch)) & SYS_REG_DBW_MASK;
+ bg = (dbw == 2) ? 2 : 1;
+ }
+
+ chipsize_mb = (1 << (cs0_row + cs0_col + bk + bg + bw - 20));
+
+ if (rank > 1)
+ chipsize_mb += chipsize_mb >> ((cs0_row - cs1_row) +
+ (cs0_col - cs1_col));
+ if (row_3_4)
+ chipsize_mb = chipsize_mb * 3 / 4;
+
+ size_mb += chipsize_mb;
+
+ if (rank > 1)
+ pr_debug("rank %d cs0_col %d cs1_col %d bk %d cs0_row %d "
+ "cs1_row %d bw %d row_3_4 %d\n",
+ rank, cs0_col, cs1_col, bk, cs0_row,
+ cs1_row, bw, row_3_4);
+ else
+ pr_debug("rank %d cs0_col %d bk %d cs0_row %d "
+ "bw %d row_3_4 %d\n",
+ rank, cs0_col, bk, cs0_row,
+ bw, row_3_4);
+ }
+
+ return (resource_size_t)size_mb << 20;
+}
+
+resource_size_t rk3399_ram0_size(void)
+{
+ void __iomem *pmugrf = IOMEM(RK3399_PMUGRF_BASE);
+ u32 sys_reg2, sys_reg3;
+ resource_size_t size;
+
+ sys_reg2 = readl(pmugrf + RK3399_PMUGRF_OS_REG2);
+ sys_reg3 = readl(pmugrf + RK3399_PMUGRF_OS_REG3);
+
+ size = rockchip_sdram_size(sys_reg2, sys_reg3);
+ size = min_t(resource_size_t, RK3399_INT_REG_START, size);
+
+ pr_debug("%s() = %llu\n", __func__, (u64)size);
+
+ return size;
+}
+
+resource_size_t rk3568_ram0_size(void)
+{
+ void __iomem *pmugrf = IOMEM(RK3568_PMUGRF_BASE);
+ u32 sys_reg2, sys_reg3;
+ resource_size_t size;
+
+ sys_reg2 = readl(pmugrf + RK3568_PMUGRF_OS_REG2);
+ sys_reg3 = readl(pmugrf + RK3568_PMUGRF_OS_REG3);
+
+ size = rockchip_sdram_size(sys_reg2, sys_reg3);
+ size = min_t(resource_size_t, RK3568_INT_REG_START, size);
+
+ pr_debug("%s() = %llu\n", __func__, (u64)size);
+
+ return size;
+}
+
+static int rockchip_dmc_probe(struct device *dev)
+{
+ const struct rockchip_dmc_drvdata *drvdata;
+ resource_size_t membase, memsize;
+ struct regmap *regmap;
+ u32 sys_reg2, sys_reg3;
+
+ regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ drvdata = device_get_match_data(dev);
+ if (!drvdata)
+ return -ENOENT;
+
+ regmap_read(regmap, drvdata->os_reg2, &sys_reg2);
+ regmap_read(regmap, drvdata->os_reg3, &sys_reg3);
+
+ memsize = rockchip_sdram_size(sys_reg2, sys_reg3);
+
+ dev_info(dev, "Detected memory size: %pa\n", &memsize);
+
+ /* lowest 10M are shaved off for secure world firmware */
+ membase = 0xa00000;
+
+ /* ram0, from 0xa00000 up to SoC internal register space start */
+ arm_add_mem_device("ram0", membase,
+ min_t(resource_size_t, drvdata->internal_registers_start, memsize) - membase);
+
+ /* ram1, remaining RAM beyond 32bit space */
+ if (memsize > SZ_4G)
+ arm_add_mem_device("ram1", SZ_4G, memsize - SZ_4G);
+
+ return 0;
+}
+
+static const struct rockchip_dmc_drvdata rk3399_drvdata = {
+ .os_reg2 = RK3399_PMUGRF_OS_REG2,
+ .os_reg3 = RK3399_PMUGRF_OS_REG3,
+ .internal_registers_start = RK3399_INT_REG_START,
+};
+
+static const struct rockchip_dmc_drvdata rk3568_drvdata = {
+ .os_reg2 = RK3568_PMUGRF_OS_REG2,
+ .os_reg3 = RK3568_PMUGRF_OS_REG3,
+ .internal_registers_start = RK3568_INT_REG_START,
+};
+
+static struct of_device_id rockchip_dmc_dt_ids[] = {
+ {
+ .compatible = "rockchip,rk3399-dmc",
+ .data = &rk3399_drvdata,
+ },
+ {
+ .compatible = "rockchip,rk3568-dmc",
+ .data = &rk3568_drvdata,
+ },
+ { /* sentinel */ }
+};
+
+static struct driver rockchip_dmc_driver = {
+ .name = "rockchip-dmc",
+ .probe = rockchip_dmc_probe,
+ .of_compatible = rockchip_dmc_dt_ids,
+};
+mem_platform_driver(rockchip_dmc_driver);
diff --git a/arch/arm/mach-rockchip/rk3568.c b/arch/arm/mach-rockchip/rk3568.c
index 39bd4772a6..c0453ea0c4 100644
--- a/arch/arm/mach-rockchip/rk3568.c
+++ b/arch/arm/mach-rockchip/rk3568.c
@@ -2,6 +2,7 @@
#include <common.h>
#include <io.h>
#include <bootsource.h>
+#include <mach/rockchip/bootrom.h>
#include <mach/rockchip/rk3568-regs.h>
#include <mach/rockchip/rockchip.h>
@@ -137,35 +138,9 @@ void rk3568_lowlevel_init(void)
qos_priority_init();
}
-struct rk_bootsource {
- enum bootsource src;
- int instance;
-};
-
-static struct rk_bootsource bootdev_map[] = {
- [0x1] = { .src = BOOTSOURCE_NAND, .instance = 0 },
- [0x2] = { .src = BOOTSOURCE_MMC, .instance = 0 },
- [0x3] = { .src = BOOTSOURCE_SPI_NOR, .instance = 0 },
- [0x4] = { .src = BOOTSOURCE_SPI_NAND, .instance = 0 },
- [0x5] = { .src = BOOTSOURCE_MMC, .instance = 1 },
- [0xa] = { .src = BOOTSOURCE_USB, .instance = 0 },
-};
-
-static void rk3568_bootsource(void)
-{
- u32 v;
-
- v = readl(RK3568_IRAM_BASE + 0x10);
-
- if (v >= ARRAY_SIZE(bootdev_map))
- return;
-
- bootsource_set(bootdev_map[v].src, bootdev_map[v].instance);
-}
-
int rk3568_init(void)
{
- rk3568_bootsource();
+ rockchip_parse_bootrom_iram(rockchip_scratch_space());
return 0;
}