summaryrefslogtreecommitdiffstats
path: root/plat/rockchip/common/drivers/parameter/ddr_parameter.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
commit102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch)
treebcf648efac40ca6139842707f0eba5a4496a6dd2 /plat/rockchip/common/drivers/parameter/ddr_parameter.c
parentInitial commit. (diff)
downloadarm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz
arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/rockchip/common/drivers/parameter/ddr_parameter.c')
-rw-r--r--plat/rockchip/common/drivers/parameter/ddr_parameter.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.c b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
new file mode 100644
index 0000000..e89fe1e
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#include "ddr_parameter.h"
+
+/*
+ * The miniloader delivers the parameters about ddr usage info from address
+ * 0x02000000 and the data format is defined as below figure. It tells ATF the
+ * areas of ddr that are used by platform, we treat them as non-secure regions
+ * by default. Then we should parse the other part regions and configurate them
+ * as secure regions to avoid illegal access.
+ *
+ * [ddr usage info data format]
+ * 0x02000000
+ * -----------------------------------------------------------------------------
+ * | <name> | <size> | <description> |
+ * -----------------------------------------------------------------------------
+ * | count | 4byte | the array numbers of the |
+ * | | | 'addr_array' and 'size_array' |
+ * -----------------------------------------------------------------------------
+ * | reserved | 4byte | just for 'addr_array' 8byte aligned |
+ * -----------------------------------------------------------------------------
+ * | addr_array[count] | per 8byte | memory region base address |
+ * -----------------------------------------------------------------------------
+ * | size_array[count] | per 8byte | memory region size (byte) |
+ * -----------------------------------------------------------------------------
+ */
+
+/*
+ * function: read parameters info(ns-regions) and try to parse s-regions info
+ *
+ * @addr: head address to the ddr usage struct from miniloader
+ * @max_mb: the max ddr capacity(MB) that the platform support
+ */
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb)
+{
+ uint64_t base, top;
+ uint32_t i, addr_offset, size_offset;
+ struct param_ddr_usage p;
+
+ memset(&p, 0, sizeof(p));
+
+ /* read how many blocks of ns-regions, read from offset: 0x0 */
+ p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET);
+ if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) {
+ ERROR("over or zero region, nr=%d, max=%d\n",
+ p.ns_nr, DDR_REGION_NR_MAX);
+ return p;
+ }
+
+ /* whole ddr regions boundary, it will be used when parse s-regions */
+ p.boundary = max_mb;
+
+ /* calculate ns-region base addr and size offset */
+ addr_offset = REGION_ADDR_OFFSET;
+ size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES;
+
+ /* read all ns-regions base and top address */
+ for (i = 0; i < p.ns_nr; i++) {
+ base = mmio_read_64(addr + addr_offset);
+ top = base + mmio_read_64(addr + size_offset);
+ /*
+ * translate byte to MB and store info,
+ * Miniloader will promise every ns-region is MB aligned.
+ */
+ p.ns_base[i] = RG_SIZE_MB(base);
+ p.ns_top[i] = RG_SIZE_MB(top);
+
+ addr_offset += REGION_DATA_PER_BYTES;
+ size_offset += REGION_DATA_PER_BYTES;
+ }
+
+ /*
+ * a s-region's base starts from previous ns-region's top, and a
+ * s-region's top ends with next ns-region's base. maybe like this:
+ *
+ * case1: ns-regison start from 0MB
+ * -----------------------------------------------
+ * | ns0 | S0 | ns1 | S1 | ns2 |
+ * 0----------------------------------------------- max_mb
+ *
+ *
+ * case2: ns-regison not start from 0MB
+ * -----------------------------------------------
+ * | S0 | ns0 | ns1 | ns2 | S1 |
+ * 0----------------------------------------------- max_mb
+ */
+
+ /* like above case2 figure, ns-region is not start from 0MB */
+ if (p.ns_base[0] != 0) {
+ p.s_base[p.s_nr] = 0;
+ p.s_top[p.s_nr] = p.ns_base[0];
+ p.s_nr++;
+ }
+
+ /*
+ * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0
+ */
+ for (i = 0; i < p.ns_nr; i++) {
+ /*
+ * if current ns-regions top covers boundary,
+ * that means s-regions are all parsed yet, so finsh.
+ */
+ if (p.ns_top[i] == p.boundary)
+ goto out;
+
+ /* s-region's base starts from previous ns-region's top */
+ p.s_base[p.s_nr] = p.ns_top[i];
+
+ /* s-region's top ends with next ns-region's base */
+ if (i + 1 < p.ns_nr)
+ p.s_top[p.s_nr] = p.ns_base[i + 1];
+ else
+ p.s_top[p.s_nr] = p.boundary;
+ p.s_nr++;
+ }
+out:
+ return p;
+}