summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/qoriq/start/mmu-config.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/qoriq/start/mmu-config.c')
-rw-r--r--bsps/powerpc/qoriq/start/mmu-config.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/bsps/powerpc/qoriq/start/mmu-config.c b/bsps/powerpc/qoriq/start/mmu-config.c
new file mode 100644
index 0000000000..b59d9c7114
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/mmu-config.c
@@ -0,0 +1,352 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQMMU
+ *
+ * @brief MMU implementation.
+ */
+
+/*
+ * Copyright (c) 2011, 2018 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/bootcard.h>
+#include <bsp/fdt.h>
+#include <bsp/linker-symbols.h>
+#include <bsp/mmu.h>
+#include <bsp/qoriq.h>
+
+#include <sys/param.h>
+
+#include <libfdt.h>
+
+#include <rtems/config.h>
+
+#define TEXT __attribute__((section(".bsp_start_text")))
+#define DATA __attribute__((section(".bsp_start_data")))
+
+typedef struct {
+ uintptr_t begin;
+ uintptr_t size;
+ uint32_t mas2;
+ uint32_t mas3;
+ uint32_t mas7;
+} entry;
+
+#define ENTRY_X(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = 0, \
+ .mas3 = FSL_EIS_MAS3_SX \
+}
+
+#define ENTRY_R(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = 0, \
+ .mas3 = FSL_EIS_MAS3_SR \
+}
+
+#ifdef RTEMS_SMP
+ #define ENTRY_RW_MAS2 FSL_EIS_MAS2_M
+#else
+ #define ENTRY_RW_MAS2 0
+#endif
+
+#define ENTRY_RW(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = ENTRY_RW_MAS2, \
+ .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW \
+}
+
+#define ENTRY_IO(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = FSL_EIS_MAS2_I | FSL_EIS_MAS2_G, \
+ .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW \
+}
+
+#define ENTRY_DEV(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = FSL_EIS_MAS2_I | FSL_EIS_MAS2_G, \
+ .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, \
+ .mas7 = QORIQ_MMU_DEVICE_MAS7 \
+}
+
+/*
+ * MMU entry for BMan and QMan software portals.
+ *
+ * The M bit must be set if stashing is used, see 3.3.8.6 DQRR Entry Stashing
+ * and 3.3.8 Software Portals in T4240DPAARM.
+ *
+ * The G bit must be set, otherwise ECC errors in the QMan software portals
+ * will occur. No documentation reference for this is available.
+ */
+#define ENTRY_DEV_CACHED(b, s) { \
+ .begin = (uintptr_t) b, \
+ .size = (uintptr_t) s, \
+ .mas2 = FSL_EIS_MAS2_M | FSL_EIS_MAS2_G, \
+ .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, \
+ .mas7 = QORIQ_MMU_DEVICE_MAS7 \
+}
+
+#define WORKSPACE_ENTRY_INDEX 0
+
+static entry DATA config[] = {
+ /* Must be first entry, see WORKSPACE_ENTRY_INDEX */
+ ENTRY_RW(bsp_section_work_begin, bsp_section_work_size),
+
+ #if defined(RTEMS_MULTIPROCESSING) && \
+ defined(QORIQ_INTERCOM_AREA_BEGIN) && \
+ defined(QORIQ_INTERCOM_AREA_SIZE)
+ {
+ .begin = QORIQ_INTERCOM_AREA_BEGIN,
+ .size = QORIQ_INTERCOM_AREA_SIZE,
+ .mas2 = FSL_EIS_MAS2_M,
+ .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW
+ },
+ #endif
+ ENTRY_X(bsp_section_start_begin, bsp_section_start_size),
+ ENTRY_R(bsp_section_fast_text_load_begin, bsp_section_fast_text_size),
+ ENTRY_X(bsp_section_fast_text_begin, bsp_section_fast_text_size),
+ ENTRY_X(bsp_section_text_begin, bsp_section_text_size),
+ ENTRY_R(bsp_section_rodata_load_begin, bsp_section_rodata_size),
+ ENTRY_R(bsp_section_rodata_begin, bsp_section_rodata_size),
+ ENTRY_R(bsp_section_fast_data_load_begin, bsp_section_fast_data_size),
+ ENTRY_RW(bsp_section_fast_data_begin, bsp_section_fast_data_size),
+ ENTRY_R(bsp_section_data_load_begin, bsp_section_data_size),
+ ENTRY_RW(bsp_section_data_begin, bsp_section_data_size),
+ ENTRY_RW(bsp_section_sbss_begin, bsp_section_sbss_size),
+ ENTRY_RW(bsp_section_bss_begin, bsp_section_bss_size),
+ ENTRY_RW(bsp_section_rwextra_begin, bsp_section_rwextra_size),
+ ENTRY_RW(bsp_section_stack_begin, bsp_section_stack_size),
+ ENTRY_IO(bsp_section_nocache_begin, bsp_section_nocache_size),
+ ENTRY_IO(bsp_section_nocachenoload_begin, bsp_section_nocachenoload_size),
+#ifndef QORIQ_IS_HYPERVISOR_GUEST
+#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
+ /* BMan Portals */
+ ENTRY_DEV_CACHED(&qoriq_bman_portal[0][0], sizeof(qoriq_bman_portal[0])),
+ ENTRY_DEV(&qoriq_bman_portal[1][0], sizeof(qoriq_bman_portal[1])),
+ /* QMan Portals */
+ ENTRY_DEV_CACHED(&qoriq_qman_portal[0][0], sizeof(qoriq_qman_portal[0])),
+ ENTRY_DEV(&qoriq_qman_portal[1][0], sizeof(qoriq_qman_portal[1])),
+#endif
+ ENTRY_DEV(&qoriq, sizeof(qoriq))
+#endif
+};
+
+static DATA char memory_path[] = "/memory";
+
+#ifdef QORIQ_IS_HYPERVISOR_GUEST
+static void TEXT add_dpaa_bqman_portals(
+ qoriq_mmu_context *context,
+ const void *fdt,
+ const char *compatible
+)
+{
+ int node;
+
+ node = -1;
+
+ while (true) {
+ const void *val;
+ int len;
+ uintptr_t paddr;
+ uintptr_t size;
+
+ node = fdt_node_offset_by_compatible(fdt, node, compatible);
+ if (node < 0) {
+ break;
+ }
+
+ val = fdt_getprop(fdt, node, "reg", &len);
+ if (len != 32) {
+ continue;
+ }
+
+ paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]);
+ size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]);
+
+ qoriq_mmu_add(
+ context,
+ paddr,
+ paddr + size - 1,
+ 0,
+ FSL_EIS_MAS2_M | FSL_EIS_MAS2_G,
+ FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
+ QORIQ_MMU_DEVICE_MAS7
+ );
+
+ paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]);
+ size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[3]);
+
+ qoriq_mmu_add(
+ context,
+ paddr,
+ paddr + size - 1,
+ 0,
+ FSL_EIS_MAS2_I | FSL_EIS_MAS2_G,
+ FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
+ QORIQ_MMU_DEVICE_MAS7
+ );
+ }
+}
+
+static void TEXT add_dpaa_bpool(qoriq_mmu_context *context, const void *fdt)
+{
+ int node;
+
+ node = -1;
+
+ while (true) {
+ const void *val;
+ int len;
+ uintptr_t config_count;
+ uintptr_t size;
+ uintptr_t paddr;
+
+ node = fdt_node_offset_by_compatible(fdt, node, "fsl,bpool");
+ if (node < 0) {
+ break;
+ }
+
+ val = fdt_getprop(fdt, node, "fsl,bpool-ethernet-cfg", &len);
+ if (len != 24) {
+ continue;
+ }
+
+ config_count = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]);
+ size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]);
+ paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]);
+
+ qoriq_mmu_add(
+ context,
+ paddr,
+ paddr + config_count * size - 1,
+ 0,
+ FSL_EIS_MAS2_M,
+ FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
+ 0
+ );
+ }
+}
+#endif
+
+static void TEXT config_fdt_adjust(const void *fdt)
+{
+ int node;
+
+ node = fdt_path_offset_namelen(
+ fdt,
+ memory_path,
+ (int) sizeof(memory_path) - 1
+ );
+
+ if (node >= 0) {
+ int len;
+ const void *val;
+ uint64_t mem_begin;
+ uint64_t mem_size;
+
+ val = fdt_getprop(fdt, node, "reg", &len);
+ if (len == 8) {
+ mem_begin = fdt32_to_cpu(((fdt32_t *) val)[0]);
+ mem_size = fdt32_to_cpu(((fdt32_t *) val)[1]);
+ } else if (len == 16) {
+ mem_begin = fdt64_to_cpu(((fdt64_t *) val)[0]);
+ mem_size = fdt64_to_cpu(((fdt64_t *) val)[1]);
+ } else {
+ mem_begin = 0;
+ mem_size = 0;
+ }
+
+#ifndef __powerpc64__
+ mem_size = MIN(mem_size, 0x80000000U);
+#endif
+
+ if (
+ mem_begin == 0
+ && mem_size > (uintptr_t) bsp_section_work_end
+ && (uintptr_t) bsp_section_nocache_end
+ < (uintptr_t) bsp_section_work_end
+ ) {
+ /* Assign new value to allow a bsp_restart() */
+ config[WORKSPACE_ENTRY_INDEX].size = (uintptr_t) mem_size
+ - (uintptr_t) bsp_section_work_begin;
+ }
+ }
+}
+
+void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb)
+{
+ qoriq_mmu_context context;
+ const void *fdt;
+ int max_count;
+ int i;
+
+ for (i = 0; i < QORIQ_TLB1_ENTRY_COUNT; ++i) {
+ if (i != scratch_tlb) {
+ qoriq_tlb1_invalidate(i);
+ }
+ }
+
+ fdt = bsp_fdt_get();
+ qoriq_mmu_context_init(&context);
+
+#ifdef QORIQ_IS_HYPERVISOR_GUEST
+ add_dpaa_bqman_portals(&context, fdt, "fsl,bman-portal");
+ add_dpaa_bqman_portals(&context, fdt, "fsl,qman-portal");
+ add_dpaa_bpool(&context, fdt);
+ max_count = QORIQ_TLB1_ENTRY_COUNT - 1;
+#else
+ max_count = (3 * QORIQ_TLB1_ENTRY_COUNT) / 4;
+#endif
+
+ if (boot_processor) {
+ config_fdt_adjust(fdt);
+ }
+
+ for (i = 0; i < (int) (sizeof(config) / sizeof(config [0])); ++i) {
+ const entry *cur = &config [i];
+ if (cur->size > 0) {
+ qoriq_mmu_add(
+ &context,
+ cur->begin,
+ cur->begin + cur->size - 1,
+ 0,
+ cur->mas2,
+ cur->mas3,
+ cur->mas7
+ );
+ }
+ }
+
+ qoriq_mmu_partition(&context, max_count);
+ qoriq_mmu_write_to_tlb1(&context, first_tlb);
+}
+
+void TEXT bsp_work_area_initialize(void)
+{
+ const entry *we = &config[WORKSPACE_ENTRY_INDEX];
+ uintptr_t begin = we->begin;
+ uintptr_t end = begin + we->size;
+
+#ifdef BSP_INTERRUPT_STACK_AT_WORK_AREA_BEGIN
+ begin += rtems_configuration_get_interrupt_stack_size();
+#endif
+
+ bsp_work_area_initialize_default((void *) begin, end - begin);
+}