summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/qoriq
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 10:35:35 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 13:52:14 +0200
commit99648958668d3a33ee57974479b36201fe303f34 (patch)
tree6f27ea790e2823c6156e71219a4f54680263fac6 /bsps/powerpc/qoriq
parentbsps: Move start files to bsps (diff)
downloadrtems-99648958668d3a33ee57974479b36201fe303f34.tar.bz2
bsps: Move startup files to bsps
Adjust build support files to new directory layout. This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/powerpc/qoriq')
-rw-r--r--bsps/powerpc/qoriq/start/bsp_specs9
-rw-r--r--bsps/powerpc/qoriq/start/bspreset.c64
-rw-r--r--bsps/powerpc/qoriq/start/bsprestart.c146
-rw-r--r--bsps/powerpc/qoriq/start/bspsmp.c252
-rw-r--r--bsps/powerpc/qoriq/start/bspstart.c197
-rw-r--r--bsps/powerpc/qoriq/start/epapr_hcalls.S26
-rw-r--r--bsps/powerpc/qoriq/start/l1cache.S43
-rw-r--r--bsps/powerpc/qoriq/start/l2cache.S43
-rw-r--r--bsps/powerpc/qoriq/start/linkcmds.qoriq_core_038
-rw-r--r--bsps/powerpc/qoriq/start/linkcmds.qoriq_core_137
-rw-r--r--bsps/powerpc/qoriq/start/linkcmds.qoriq_e50038
-rw-r--r--bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_3241
-rw-r--r--bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_641
-rw-r--r--bsps/powerpc/qoriq/start/mmu-config.c352
-rw-r--r--bsps/powerpc/qoriq/start/mmu-tlb1.S107
-rw-r--r--bsps/powerpc/qoriq/start/mmu.c368
-rw-r--r--bsps/powerpc/qoriq/start/portal.c43
-rw-r--r--bsps/powerpc/qoriq/start/restart.S80
18 files changed, 1885 insertions, 0 deletions
diff --git a/bsps/powerpc/qoriq/start/bsp_specs b/bsps/powerpc/qoriq/start/bsp_specs
new file mode 100644
index 0000000000..001c45b3c4
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/bsp_specs
@@ -0,0 +1,9 @@
+%rename endfile old_endfile
+%rename startfile old_startfile
+
+*startfile:
+%{!qrtems: %(old_startfile)} \
+%{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s}}
+
+*endfile:
+%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s rtems_crtn.o%s ecrtn.o%s}
diff --git a/bsps/powerpc/qoriq/start/bspreset.c b/bsps/powerpc/qoriq/start/bspreset.c
new file mode 100644
index 0000000000..545aa28ee3
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/bspreset.c
@@ -0,0 +1,64 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQ
+ *
+ * @brief BSP reset.
+ */
+
+/*
+ * Copyright (c) 2010, 2017 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/bootcard.h>
+#include <bsp/fdt.h>
+#include <bsp/qoriq.h>
+
+#include <libfdt.h>
+
+static int find_rstcr_node(const void *fdt, int node)
+{
+ return fdt_node_offset_by_prop_value(fdt, node, "fsl,has-rstcr", NULL, 0);
+}
+
+void bsp_reset(void)
+{
+ rtems_interrupt_level level;
+ const char *fdt;
+
+ rtems_interrupt_local_disable(level);
+ (void) level;
+
+ fdt = bsp_fdt_get();
+
+ /* If we do not find a RSTCR, then loop forever */
+ while (true) {
+ int node;
+
+ node = -1;
+
+ while ((node = find_rstcr_node(fdt, node)) >= 0) {
+ const uint32_t *reg;
+ int len;
+
+ reg = fdt_getprop(fdt, node, "reg", &len);
+ if (reg != NULL && len >= 4) {
+ volatile uint32_t *rstcr;
+
+ rstcr = (volatile uint32_t *)
+ ((uintptr_t) &qoriq + fdt32_to_cpu(reg[0]) + 0xb0);
+ *rstcr = 0x2;
+ }
+ }
+ }
+}
diff --git a/bsps/powerpc/qoriq/start/bsprestart.c b/bsps/powerpc/qoriq/start/bsprestart.c
new file mode 100644
index 0000000000..36e751e50d
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/bsprestart.c
@@ -0,0 +1,146 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQ
+ *
+ * @brief BSP restart.
+ */
+
+/*
+ * Copyright (c) 2016, 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/irq.h>
+#include <bsp/fatal.h>
+#include <bsp/fdt.h>
+#include <bsp/linker-symbols.h>
+#include <bsp/qoriq.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <string.h>
+
+static char fdt_copy[BSP_FDT_BLOB_SIZE_MAX];
+
+static RTEMS_NO_RETURN void do_restart(void *addr)
+{
+ void (*restart)(uintptr_t);
+
+ qoriq_reset_qman_and_bman();
+
+ memcpy(fdt_copy, bsp_fdt_get(), sizeof(fdt_copy));
+ rtems_cache_flush_multiple_data_lines(fdt_copy, sizeof(fdt_copy));
+
+ restart = addr;
+ (*restart)((uintptr_t) fdt_copy);
+ bsp_fatal(QORIQ_FATAL_RESTART_FAILED);
+}
+
+#if defined(RTEMS_SMP) && !defined(QORIQ_IS_HYPERVISOR_GUEST)
+
+#include <rtems/score/smpimpl.h>
+#include <rtems/score/smpbarrier.h>
+
+#define RESTART_IPI_INDEX 1
+
+static SMP_barrier_Control restart_barrier = SMP_BARRIER_CONTROL_INITIALIZER;
+
+static void restart_interrupt(void *arg)
+{
+ uint32_t cpu_self_index;
+ uint32_t thread_index;
+ rtems_interrupt_level level;
+ SMP_barrier_State bs;
+
+ rtems_interrupt_local_disable(level);
+ (void) level;
+
+ _SMP_barrier_State_initialize(&bs);
+ _SMP_barrier_Wait(&restart_barrier, &bs, _SMP_Processor_count);
+
+ cpu_self_index = rtems_get_current_processor();
+ thread_index = cpu_self_index % QORIQ_THREAD_COUNT;
+
+ if (cpu_self_index == 0) {
+ do_restart(arg);
+ } else if (thread_index == 0) {
+ uint32_t real_processor_index;
+ const qoriq_start_spin_table *spin_table;
+
+ real_processor_index = cpu_self_index / QORIQ_THREAD_COUNT;
+ spin_table = qoriq_start_spin_table_addr[real_processor_index];
+
+ qoriq_restart_secondary_processor(spin_table);
+ } else {
+ uint32_t pir_reset_value;
+
+ /* Restore reset PIR value */
+ pir_reset_value = (cpu_self_index & ~0x1U) << 2;
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR, pir_reset_value);
+
+ /* Thread Enable Clear (TENC) */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_TENC, 1U << thread_index);
+
+ RTEMS_UNREACHABLE();
+ }
+}
+
+static void raise_restart_interrupt(void)
+{
+ qoriq.pic.ipidr[RESTART_IPI_INDEX].reg =
+ _Processor_mask_To_uint32_t(_SMP_Get_online_processors(), 0);
+ ppc_synchronize_data();
+ ppc_synchronize_instructions();
+}
+
+void bsp_restart(void *addr)
+{
+ rtems_status_code sc;
+ size_t i;
+
+ for (i = 0; i < RTEMS_ARRAY_SIZE(qoriq_start_spin_table_addr); ++i) {
+ qoriq_start_spin_table *spin_table;
+
+ spin_table = qoriq_start_spin_table_addr[i];
+ memset(spin_table, 0, sizeof(*spin_table));
+ rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
+ }
+
+ sc = rtems_interrupt_handler_install(
+ QORIQ_IRQ_IPI_0 + RESTART_IPI_INDEX,
+ "Restart",
+ RTEMS_INTERRUPT_UNIQUE,
+ restart_interrupt,
+ addr
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ bsp_fatal(QORIQ_FATAL_RESTART_INSTALL_INTERRUPT);
+ }
+
+ raise_restart_interrupt();
+ bsp_fatal(QORIQ_FATAL_RESTART_INTERRUPT_FAILED);
+}
+
+#else /* !RTEMS_SMP || QORIQ_IS_HYPERVISOR_GUEST */
+
+void bsp_restart(void *addr)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_local_disable(level);
+ (void) level;
+ do_restart(addr);
+}
+
+#endif /* RTEMS_SMP && !QORIQ_IS_HYPERVISOR_GUEST */
diff --git a/bsps/powerpc/qoriq/start/bspsmp.c b/bsps/powerpc/qoriq/start/bspsmp.c
new file mode 100644
index 0000000000..a2d9fbede5
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/bspsmp.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2013, 2017 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 <rtems/score/smpimpl.h>
+
+#include <libfdt.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <bsp.h>
+#include <bsp/fdt.h>
+#include <bsp/mmu.h>
+#include <bsp/fatal.h>
+#include <bsp/qoriq.h>
+#include <bsp/vectors.h>
+#include <bsp/bootcard.h>
+#include <bsp/irq-generic.h>
+#include <bsp/linker-symbols.h>
+
+LINKER_SYMBOL(bsp_exc_vector_base);
+
+#if QORIQ_THREAD_COUNT > 1
+void _start_thread(void);
+#endif
+
+void _start_secondary_processor(void);
+
+#define IPI_INDEX 0
+
+#if QORIQ_THREAD_COUNT > 1
+static bool is_started_by_u_boot(uint32_t cpu_index)
+{
+ return cpu_index % QORIQ_THREAD_COUNT == 0;
+}
+
+void qoriq_start_thread(void)
+{
+ const Per_CPU_Control *cpu_self = _Per_CPU_Get();
+
+ ppc_exc_initialize_interrupt_stack(
+ (uintptr_t) cpu_self->interrupt_stack_low,
+ rtems_configuration_get_interrupt_stack_size()
+ );
+
+ bsp_interrupt_facility_initialize();
+
+ _SMP_Start_multitasking_on_secondary_processor();
+}
+#endif
+
+static void start_thread_if_necessary(uint32_t cpu_index_self)
+{
+#if QORIQ_THREAD_COUNT > 1
+ uint32_t i;
+
+ for (i = 1; i < QORIQ_THREAD_COUNT; ++i) {
+ uint32_t cpu_index_next = cpu_index_self + i;
+
+ if (
+ is_started_by_u_boot(cpu_index_self)
+ && cpu_index_next < rtems_configuration_get_maximum_processors()
+ && _SMP_Should_start_processor(cpu_index_next)
+ ) {
+ /* Thread Initial Next Instruction Address (INIA) */
+ PPC_SET_THREAD_MGMT_REGISTER(321, (uintptr_t) _start_thread);
+
+ /* Thread Initial Machine State (IMSR) */
+ PPC_SET_THREAD_MGMT_REGISTER(289, QORIQ_INITIAL_MSR);
+
+ /* Thread Enable Set (TENS) */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_TENS, 1U << i);
+ }
+ }
+#endif
+}
+
+void bsp_start_on_secondary_processor(void)
+{
+ uint32_t cpu_index_self = _SMP_Get_current_processor();
+ const Per_CPU_Control *cpu_self = _Per_CPU_Get_by_index(cpu_index_self);
+
+ qoriq_initialize_exceptions(cpu_self->interrupt_stack_low);
+ bsp_interrupt_facility_initialize();
+
+ start_thread_if_necessary(cpu_index_self);
+
+ _SMP_Start_multitasking_on_secondary_processor();
+}
+
+#ifndef QORIQ_IS_HYPERVISOR_GUEST
+static void bsp_inter_processor_interrupt(void *arg)
+{
+ _SMP_Inter_processor_interrupt_handler();
+}
+#endif
+
+static void setup_boot_page(void)
+{
+#ifdef QORIQ_IS_HYPERVISOR_GUEST
+ qoriq_mmu_context mmu_context;
+
+ qoriq_mmu_context_init(&mmu_context);
+ qoriq_mmu_add(
+ &mmu_context,
+ 0xfffff000,
+ 0xffffffff,
+ 0,
+ 0,
+ FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
+ 0
+ );
+ qoriq_mmu_partition(&mmu_context, 1);
+ qoriq_mmu_write_to_tlb1(&mmu_context, QORIQ_TLB1_ENTRY_COUNT - 1);
+#endif
+}
+
+static uint32_t discover_processors(void)
+{
+ const void *fdt = bsp_fdt_get();
+ int cpus = fdt_path_offset(fdt, "/cpus");
+ int node = fdt_first_subnode(fdt, cpus);
+ uint32_t cpu = 0;
+
+ while (node >= 0 && cpu < RTEMS_ARRAY_SIZE(qoriq_start_spin_table_addr)) {
+ int len;
+ fdt64_t *addr_fdt = (fdt64_t *)
+ fdt_getprop(fdt, node, "cpu-release-addr", &len);
+
+ if (addr_fdt != NULL) {
+ uintptr_t addr = (uintptr_t) fdt64_to_cpu(*addr_fdt);
+
+ qoriq_start_spin_table_addr[cpu] = (qoriq_start_spin_table *) addr;
+ }
+
+ ++cpu;
+ node = fdt_next_subnode(fdt, node);
+ }
+
+ return cpu * QORIQ_THREAD_COUNT;
+}
+
+uint32_t _CPU_SMP_Initialize(void)
+{
+ uint32_t cpu_count = 1;
+
+ if (rtems_configuration_get_maximum_processors() > 0) {
+ setup_boot_page();
+ cpu_count = discover_processors();
+ }
+
+ start_thread_if_necessary(0);
+
+ return cpu_count;
+}
+
+static bool release_processor(
+ qoriq_start_spin_table *spin_table,
+ uint32_t cpu_index
+)
+{
+ bool spin_table_present = (spin_table != NULL);
+
+ if (spin_table_present) {
+ const Per_CPU_Control *cpu = _Per_CPU_Get_by_index(cpu_index);
+
+ spin_table->pir = cpu_index;
+ spin_table->r3 = (uintptr_t) cpu->interrupt_stack_high;
+ rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
+ ppc_synchronize_data();
+ spin_table->addr = (uintptr_t) _start_secondary_processor;
+ rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
+ }
+
+ return spin_table_present;
+}
+
+static qoriq_start_spin_table *get_spin_table(uint32_t cpu_index)
+{
+ qoriq_start_spin_table *spin_table;
+
+ spin_table = qoriq_start_spin_table_addr[cpu_index / QORIQ_THREAD_COUNT];
+
+ return spin_table;
+}
+
+bool _CPU_SMP_Start_processor(uint32_t cpu_index)
+{
+#if QORIQ_THREAD_COUNT > 1
+ if (is_started_by_u_boot(cpu_index)) {
+ qoriq_start_spin_table *spin_table = get_spin_table(cpu_index);
+
+ return release_processor(spin_table, cpu_index);
+ } else {
+ return _SMP_Should_start_processor(cpu_index - 1);
+ }
+#else
+ qoriq_start_spin_table *spin_table = get_spin_table(cpu_index);
+
+ return release_processor(spin_table, cpu_index);
+#endif
+}
+
+void _CPU_SMP_Finalize_initialization(uint32_t cpu_count)
+{
+#ifdef QORIQ_IS_HYPERVISOR_GUEST
+ (void) cpu_count;
+#else
+ if (cpu_count > 1) {
+ rtems_status_code sc;
+
+ sc = rtems_interrupt_handler_install(
+ QORIQ_IRQ_IPI_0 + IPI_INDEX,
+ "IPI",
+ RTEMS_INTERRUPT_UNIQUE,
+ bsp_inter_processor_interrupt,
+ NULL
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ bsp_fatal(QORIQ_FATAL_SMP_IPI_HANDLER_INSTALL);
+ }
+ }
+#endif
+}
+
+void _CPU_SMP_Prepare_start_multitasking(void)
+{
+ /* Do nothing */
+}
+
+void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
+{
+#ifdef QORIQ_IS_HYPERVISOR_GUEST
+ uint32_t msg;
+
+ /* DBELL message type */
+ msg = (0U << (63 - 36)) | target_processor_index;
+ __asm__ volatile ("msgsnd %0" : : "r" (msg));
+#else
+ qoriq.pic.ipidr [IPI_INDEX].reg = 1U << target_processor_index;
+#endif
+}
diff --git a/bsps/powerpc/qoriq/start/bspstart.c b/bsps/powerpc/qoriq/start/bspstart.c
new file mode 100644
index 0000000000..7d9fa0d3c7
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/bspstart.c
@@ -0,0 +1,197 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQ
+ *
+ * @brief BSP startup.
+ */
+
+/*
+ * Copyright (c) 2010, 2017 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 <libfdt.h>
+
+#include <rtems.h>
+#include <rtems/config.h>
+#include <rtems/counter.h>
+#include <rtems/sysinit.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <bsp.h>
+#include <bsp/bootcard.h>
+#include <bsp/console-termios.h>
+#include <bsp/fatal.h>
+#include <bsp/fdt.h>
+#include <bsp/intercom.h>
+#include <bsp/irq-generic.h>
+#include <bsp/linker-symbols.h>
+#include <bsp/mmu.h>
+#include <bsp/qoriq.h>
+#include <bsp/vectors.h>
+
+LINKER_SYMBOL(bsp_exc_vector_base);
+
+qoriq_start_spin_table *
+qoriq_start_spin_table_addr[QORIQ_CPU_COUNT / QORIQ_THREAD_COUNT];
+
+/* Configuration parameters for console driver, ... */
+unsigned int BSP_bus_frequency;
+
+/* Configuration parameter for clock driver, ... */
+uint32_t bsp_time_base_frequency;
+
+uint32_t qoriq_clock_frequency;
+
+static void initialize_frequency_parameters(void)
+{
+ const void *fdt = bsp_fdt_get();
+ int node;
+ int len;
+ fdt32_t *val_fdt;
+
+ node = fdt_node_offset_by_prop_value(fdt, -1, "device_type", "cpu", 4);
+
+ val_fdt = (fdt32_t *) fdt_getprop(fdt, node, "bus-frequency", &len);
+ if (val_fdt == NULL || len != 4) {
+ bsp_fatal(QORIQ_FATAL_FDT_NO_BUS_FREQUENCY);
+ }
+ BSP_bus_frequency = fdt32_to_cpu(*val_fdt) / QORIQ_BUS_CLOCK_DIVIDER;
+
+ val_fdt = (fdt32_t *) fdt_getprop(fdt, node, "timebase-frequency", &len);
+ if (val_fdt == NULL || len != 4) {
+ bsp_fatal(QORIQ_FATAL_FDT_NO_BUS_FREQUENCY);
+ }
+ bsp_time_base_frequency = fdt32_to_cpu(*val_fdt);
+
+ #ifdef __PPC_CPU_E6500__
+ val_fdt = (fdt32_t *) fdt_getprop(fdt, node, "clock-frequency", &len);
+ if (val_fdt == NULL || len != 4) {
+ bsp_fatal(QORIQ_FATAL_FDT_NO_CLOCK_FREQUENCY);
+ }
+ qoriq_clock_frequency = fdt32_to_cpu(*val_fdt);
+ #endif
+ rtems_counter_initialize_converter(fdt32_to_cpu(*val_fdt));
+}
+
+#define MTIVPR(base) \
+ __asm__ volatile ("mtivpr %0" : : "r" (base))
+
+#ifdef __powerpc64__
+#define VECTOR_TABLE_ENTRY_SIZE 32
+#else
+#define VECTOR_TABLE_ENTRY_SIZE 16
+#endif
+
+#define MTIVOR(vec, offset) \
+ do { \
+ __asm__ volatile ("mtspr " RTEMS_XSTRING(vec) ", %0" : : "r" (offset)); \
+ offset += VECTOR_TABLE_ENTRY_SIZE; \
+ } while (0)
+
+void qoriq_initialize_exceptions(void *interrupt_stack_begin)
+{
+ uintptr_t addr;
+
+ ppc_exc_initialize_interrupt_stack(
+ (uintptr_t) interrupt_stack_begin,
+ rtems_configuration_get_interrupt_stack_size()
+ );
+
+ addr = (uintptr_t) bsp_exc_vector_base;
+ MTIVPR(addr);
+ MTIVOR(BOOKE_IVOR0, addr);
+ MTIVOR(BOOKE_IVOR1, addr);
+ MTIVOR(BOOKE_IVOR2, addr);
+ MTIVOR(BOOKE_IVOR3, addr);
+ MTIVOR(BOOKE_IVOR4, addr);
+ MTIVOR(BOOKE_IVOR5, addr);
+ MTIVOR(BOOKE_IVOR6, addr);
+#ifdef __PPC_CPU_E6500__
+ MTIVOR(BOOKE_IVOR7, addr);
+#endif
+ MTIVOR(BOOKE_IVOR8, addr);
+#ifdef __PPC_CPU_E6500__
+ MTIVOR(BOOKE_IVOR9, addr);
+#endif
+ MTIVOR(BOOKE_IVOR10, addr);
+ MTIVOR(BOOKE_IVOR11, addr);
+ MTIVOR(BOOKE_IVOR12, addr);
+ MTIVOR(BOOKE_IVOR13, addr);
+ MTIVOR(BOOKE_IVOR14, addr);
+ MTIVOR(BOOKE_IVOR15, addr);
+ MTIVOR(BOOKE_IVOR32, addr);
+ MTIVOR(BOOKE_IVOR33, addr);
+#ifndef __PPC_CPU_E6500__
+ MTIVOR(BOOKE_IVOR34, addr);
+#endif
+ MTIVOR(BOOKE_IVOR35, addr);
+#ifdef __PPC_CPU_E6500__
+ MTIVOR(BOOKE_IVOR36, addr);
+ MTIVOR(BOOKE_IVOR37, addr);
+#ifndef QORIQ_IS_HYPERVISOR_GUEST
+ MTIVOR(BOOKE_IVOR38, addr);
+ MTIVOR(BOOKE_IVOR39, addr);
+ MTIVOR(BOOKE_IVOR40, addr);
+ MTIVOR(BOOKE_IVOR41, addr);
+ MTIVOR(BOOKE_IVOR42, addr);
+#endif
+#endif
+}
+
+void bsp_start(void)
+{
+ /*
+ * Get CPU identification dynamically. Note that the get_ppc_cpu_type() function
+ * store the result in global variables so that it can be used latter...
+ */
+ get_ppc_cpu_type();
+ get_ppc_cpu_revision();
+
+ initialize_frequency_parameters();
+
+ qoriq_initialize_exceptions(bsp_section_work_begin);
+ bsp_interrupt_initialize();
+
+ rtems_cache_coherent_add_area(
+ bsp_section_nocacheheap_begin,
+ (uintptr_t) bsp_section_nocacheheap_size
+ );
+
+#ifndef QORIQ_IS_HYPERVISOR_GUEST
+ /* Disable boot page translation */
+#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
+ qoriq.lcc.bstar &= ~LCC_BSTAR_EN;
+#else
+ qoriq.lcc.bptr &= ~BPTR_EN;
+#endif
+#endif
+}
+
+uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
+{
+#ifndef QORIQ_IS_HYPERVISOR_GUEST
+ return intr[0] - 16;
+#else
+ return intr[0];
+#endif
+}
+
+#ifdef RTEMS_MULTIPROCESSING
+RTEMS_SYSINIT_ITEM(
+ qoriq_intercom_init,
+ RTEMS_SYSINIT_BSP_PRE_DRIVERS,
+ RTEMS_SYSINIT_ORDER_MIDDLE
+);
+#endif
diff --git a/bsps/powerpc/qoriq/start/epapr_hcalls.S b/bsps/powerpc/qoriq/start/epapr_hcalls.S
new file mode 100644
index 0000000000..b019e5d710
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/epapr_hcalls.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 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 <libcpu/powerpc-utility.h>
+
+ .text
+
+ .global epapr_hypercall_start
+epapr_hypercall_start:
+
+ sc 1
+ nop
+ nop
+ nop
+ blr
diff --git a/bsps/powerpc/qoriq/start/l1cache.S b/bsps/powerpc/qoriq/start/l1cache.S
new file mode 100644
index 0000000000..bee3d28123
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/l1cache.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2016 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 <libcpu/powerpc-utility.h>
+
+ .global qoriq_l1cache_invalidate
+
+ .section ".bsp_start_text", "ax"
+
+qoriq_l1cache_invalidate:
+
+ /* Invalidate L1 data cache */
+ mfspr r3, FSL_EIS_L1CSR0
+ ori r3, r3, FSL_EIS_L1CSR0_CFI
+ mtspr FSL_EIS_L1CSR0, r3
+1:
+ mfspr r3, FSL_EIS_L1CSR0
+ andi. r3, r3, FSL_EIS_L1CSR0_CFI
+ bne 1b
+ isync
+
+ /* Invalidate L1 instruction cache */
+ mfspr r3, FSL_EIS_L1CSR1
+ ori r3, r3, FSL_EIS_L1CSR1_ICFI
+ mtspr FSL_EIS_L1CSR1, r3
+1:
+ mfspr r3, FSL_EIS_L1CSR1
+ andi. r3, r3, FSL_EIS_L1CSR1_ICFI
+ bne 1b
+ isync
+
+ blr
diff --git a/bsps/powerpc/qoriq/start/l2cache.S b/bsps/powerpc/qoriq/start/l2cache.S
new file mode 100644
index 0000000000..1c57659aa1
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/l2cache.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2016 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 <libcpu/powerpc-utility.h>
+
+ .global qoriq_l2cache_flush_invalidate
+
+ .section ".bsp_start_text", "ax"
+
+qoriq_l2cache_flush_invalidate:
+
+ /* Flush L2 cache */
+ lwz r4, 0(r3)
+ oris r4, r4, FSL_EIS_L2CSR0_L2FL >> 16
+ stw r4, 0(r3)
+1:
+ lwz r4, 0(r3)
+ andis. r4, r4, FSL_EIS_L2CSR0_L2FL >> 16
+ bne 1b
+ isync
+
+ /* Invalidate L2 cache */
+ lwz r4, 0(r3)
+ oris r4, r4, FSL_EIS_L2CSR0_L2FI >> 16
+ stw r4, 0(r3)
+1:
+ lwz r4, 0(r3)
+ andis. r4, r4, FSL_EIS_L2CSR0_L2FI >> 16
+ bne 1b
+ isync
+
+ blr
diff --git a/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_0 b/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_0
new file mode 100644
index 0000000000..80ae3937bf
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_0
@@ -0,0 +1,38 @@
+/**
+ * @file
+ *
+ * @brief Memory map for QorIQ Core 0.
+ */
+
+EXTERN (__vectors)
+
+MEMORY {
+ LOW : ORIGIN = 0x4000, LENGTH = 16M - 16k
+ HIGH : ORIGIN = 0x1000000, LENGTH = 32M
+ EMPTY : ORIGIN = 0x0, LENGTH = 0
+}
+
+REGION_ALIAS ("REGION_START", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_TEXT", LOW);
+REGION_ALIAS ("REGION_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_RODATA", HIGH);
+REGION_ALIAS ("REGION_RODATA_LOAD", LOW);
+REGION_ALIAS ("REGION_FAST_DATA", HIGH);
+REGION_ALIAS ("REGION_FAST_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_DATA", HIGH);
+REGION_ALIAS ("REGION_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_BSS", HIGH);
+REGION_ALIAS ("REGION_RWEXTRA", HIGH);
+REGION_ALIAS ("REGION_WORK", HIGH);
+REGION_ALIAS ("REGION_STACK", HIGH);
+REGION_ALIAS ("REGION_NOCACHE", EMPTY);
+REGION_ALIAS ("REGION_NOCACHE_LOAD", EMPTY);
+REGION_ALIAS ("REGION_NVRAM", EMPTY);
+
+bsp_section_robarrier_align = 0x1000000;
+bsp_section_rwbarrier_align = 0x1000000;
+qoriq = 0xffe00000;
+
+INCLUDE linkcmds.base
diff --git a/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_1 b/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_1
new file mode 100644
index 0000000000..ecb601b9ef
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/linkcmds.qoriq_core_1
@@ -0,0 +1,37 @@
+/**
+ * @file
+ *
+ * @brief Memory map for QorIQ Core 1.
+ */
+
+EXTERN (__vectors)
+
+MEMORY {
+ RAM : ORIGIN = 0x4000000, LENGTH = 64M
+ EMPTY : ORIGIN = 0x0, LENGTH = 0
+}
+
+REGION_ALIAS ("REGION_START", RAM);
+REGION_ALIAS ("REGION_TEXT", RAM);
+REGION_ALIAS ("REGION_TEXT_LOAD", RAM);
+REGION_ALIAS ("REGION_RODATA", RAM);
+REGION_ALIAS ("REGION_RODATA_LOAD", RAM);
+REGION_ALIAS ("REGION_DATA", RAM);
+REGION_ALIAS ("REGION_DATA_LOAD", RAM);
+REGION_ALIAS ("REGION_FAST_TEXT", RAM);
+REGION_ALIAS ("REGION_FAST_TEXT_LOAD", RAM);
+REGION_ALIAS ("REGION_FAST_DATA", RAM);
+REGION_ALIAS ("REGION_FAST_DATA_LOAD", RAM);
+REGION_ALIAS ("REGION_BSS", RAM);
+REGION_ALIAS ("REGION_RWEXTRA", RAM);
+REGION_ALIAS ("REGION_WORK", RAM);
+REGION_ALIAS ("REGION_STACK", RAM);
+REGION_ALIAS ("REGION_NOCACHE", EMPTY);
+REGION_ALIAS ("REGION_NOCACHE_LOAD", EMPTY);
+REGION_ALIAS ("REGION_NVRAM", EMPTY);
+
+bsp_section_robarrier_align = 0x1000000;
+bsp_section_rwbarrier_align = 0x1000000;
+qoriq = 0xffe00000;
+
+INCLUDE linkcmds.base
diff --git a/bsps/powerpc/qoriq/start/linkcmds.qoriq_e500 b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e500
new file mode 100644
index 0000000000..b727aefaa8
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e500
@@ -0,0 +1,38 @@
+/**
+ * @file
+ *
+ * Memory map for P1020RDB.
+ */
+
+EXTERN (__vectors)
+
+MEMORY {
+ LOW : ORIGIN = 0x4000, LENGTH = 16M - 16k
+ HIGH : ORIGIN = 0x1000000, LENGTH = 512M - 16M
+ EMPTY : ORIGIN = 0x0, LENGTH = 0
+}
+
+REGION_ALIAS ("REGION_START", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_TEXT", LOW);
+REGION_ALIAS ("REGION_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_RODATA", HIGH);
+REGION_ALIAS ("REGION_RODATA_LOAD", LOW);
+REGION_ALIAS ("REGION_FAST_DATA", HIGH);
+REGION_ALIAS ("REGION_FAST_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_DATA", HIGH);
+REGION_ALIAS ("REGION_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_BSS", HIGH);
+REGION_ALIAS ("REGION_RWEXTRA", HIGH);
+REGION_ALIAS ("REGION_WORK", HIGH);
+REGION_ALIAS ("REGION_STACK", HIGH);
+REGION_ALIAS ("REGION_NOCACHE", EMPTY);
+REGION_ALIAS ("REGION_NOCACHE_LOAD", EMPTY);
+REGION_ALIAS ("REGION_NVRAM", EMPTY);
+
+bsp_section_robarrier_align = 0x1000000;
+bsp_section_rwbarrier_align = 0x1000000;
+qoriq = 0xffe00000;
+
+INCLUDE linkcmds.base
diff --git a/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_32 b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_32
new file mode 100644
index 0000000000..900147c163
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_32
@@ -0,0 +1,41 @@
+/**
+ * @file
+ *
+ * Memory map for e6500 core based QorIQ chips, e.g. T2080, T4240.
+ */
+
+EXTERN (__vectors)
+
+MEMORY {
+ LOW : ORIGIN = 0x00004000, LENGTH = 16M - 16k
+ NOCACHE : ORIGIN = 0x01000000, LENGTH = 48M
+ HIGH : ORIGIN = 0x04000000, LENGTH = 512M - 64M
+ EMPTY : ORIGIN = 0x00000000, LENGTH = 0
+}
+
+REGION_ALIAS ("REGION_START", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT", LOW);
+REGION_ALIAS ("REGION_FAST_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_TEXT", LOW);
+REGION_ALIAS ("REGION_TEXT_LOAD", LOW);
+REGION_ALIAS ("REGION_RODATA", HIGH);
+REGION_ALIAS ("REGION_RODATA_LOAD", LOW);
+REGION_ALIAS ("REGION_FAST_DATA", HIGH);
+REGION_ALIAS ("REGION_FAST_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_DATA", HIGH);
+REGION_ALIAS ("REGION_DATA_LOAD", LOW);
+REGION_ALIAS ("REGION_BSS", HIGH);
+REGION_ALIAS ("REGION_RWEXTRA", HIGH);
+REGION_ALIAS ("REGION_WORK", HIGH);
+REGION_ALIAS ("REGION_STACK", HIGH);
+REGION_ALIAS ("REGION_NOCACHE", NOCACHE);
+REGION_ALIAS ("REGION_NOCACHE_LOAD", LOW);
+REGION_ALIAS ("REGION_NVRAM", EMPTY);
+
+bsp_section_robarrier_align = 0x1000000;
+bsp_section_rwbarrier_align = 0x1000000;
+qoriq = 0xffe000000;
+qoriq_bman_portal = 0xff4000000;
+qoriq_qman_portal = 0xff6000000;
+
+INCLUDE linkcmds.base
diff --git a/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_64 b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_64
new file mode 100644
index 0000000000..a4969756ec
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_64
@@ -0,0 +1 @@
+INCLUDE linkcmds.qoriq_e6500_32
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);
+}
diff --git a/bsps/powerpc/qoriq/start/mmu-tlb1.S b/bsps/powerpc/qoriq/start/mmu-tlb1.S
new file mode 100644
index 0000000000..2dd06e2ed8
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/mmu-tlb1.S
@@ -0,0 +1,107 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQMMU
+ *
+ * @brief qoriq_tlb1_write() and qoriq_tlb1_invalidate() implementation.
+ */
+
+/*
+ * Copyright (c) 2011, 2017 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 <bspopts.h>
+
+#include <libcpu/powerpc-utility.h>
+
+ .global qoriq_tlb1_write
+ .global qoriq_tlb1_invalidate
+ .global qoriq_tlb1_invalidate_all_by_ts
+
+ .section ".bsp_start_text", "ax"
+
+qoriq_tlb1_write:
+ rlwinm r3, r3, 16, 10, 15
+#ifdef __powerpc64__
+ rldicr r8, r8, 0, 51
+#else
+ rlwinm r8, r8, 0, 0, 19
+#endif
+ oris r3, r3, 0x1000
+ mtspr FSL_EIS_MAS0, r3
+ oris r4, r4, 0xc000
+ rlwinm r9, r9, 8, 20, 23
+ or r9, r4, r9
+ mtspr FSL_EIS_MAS1, r9
+ or r5, r8, r5
+ mtspr FSL_EIS_MAS2, r5
+ or r6, r8, r6
+ mtspr FSL_EIS_MAS3, r6
+#ifdef __powerpc64__
+ srdi r8, r8, 32
+ or r7, r7, r8
+ mtspr FSL_EIS_MAS7, r7
+#endif
+ mtspr FSL_EIS_MAS7, r7
+#if defined(QORIQ_HAS_HYPERVISOR_MODE) && !defined(QORIQ_IS_HYPERVISOR_GUEST)
+ li r0, 0
+ mtspr FSL_EIS_MAS8, r0
+#endif
+ isync
+ msync
+ tlbwe
+ isync
+ blr
+
+qoriq_tlb1_invalidate:
+ rlwinm r3, r3, 16, 10, 15
+ oris r3, r3, 0x1000
+ mtspr FSL_EIS_MAS0, r3
+ li r0, 0
+ mtspr FSL_EIS_MAS1, r0
+ mtspr FSL_EIS_MAS2, r0
+ mtspr FSL_EIS_MAS3, r0
+ mtspr FSL_EIS_MAS7, r0
+#if defined(QORIQ_HAS_HYPERVISOR_MODE) && !defined(QORIQ_IS_HYPERVISOR_GUEST)
+ mtspr FSL_EIS_MAS8, r0
+#endif
+ isync
+ msync
+ tlbwe
+ isync
+ blr
+
+/* r3 = 0 for TS0, 1 for TS1 */
+qoriq_tlb1_invalidate_all_by_ts:
+ mflr r12
+ li r11, QORIQ_TLB1_ENTRY_COUNT
+ mtctr r11
+ li r11, 0
+ mr r10, r3
+
+2:
+ rlwinm r0, r11, 16, 10, 15
+ oris r0, r0, (FSL_EIS_MAS0_TLBSEL >> 16)
+ mtspr FSL_EIS_MAS0, r0
+ tlbre
+ mfspr r0, FSL_EIS_MAS1
+ rlwinm r0, r0, 20, 31, 31
+ cmpw r0, r10
+ bne 1f
+ mr r3, r11
+ bl qoriq_tlb1_invalidate
+1:
+ addi r11, r11, 1
+ bdnz 2b
+ mtlr r12
+ blr
diff --git a/bsps/powerpc/qoriq/start/mmu.c b/bsps/powerpc/qoriq/start/mmu.c
new file mode 100644
index 0000000000..2629c9f999
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/mmu.c
@@ -0,0 +1,368 @@
+/**
+ * @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/mmu.h>
+#include <libcpu/powerpc-utility.h>
+
+#define TEXT __attribute__((section(".bsp_start_text")))
+
+static uintptr_t TEXT power_of_two(uintptr_t val)
+{
+ uintptr_t test_power = QORIQ_MMU_MIN_POWER;
+ uintptr_t power = test_power;
+ uintptr_t alignment = 1U << test_power;
+
+ while (test_power <= QORIQ_MMU_MAX_POWER && (val & (alignment - 1)) == 0) {
+ power = test_power;
+ alignment <<= QORIQ_MMU_POWER_STEP;
+ test_power += QORIQ_MMU_POWER_STEP;
+ }
+
+ return power;
+}
+
+static uintptr_t TEXT max_power_of_two(uintptr_t val)
+{
+ uintptr_t test_power = QORIQ_MMU_MIN_POWER;
+ uintptr_t power = test_power;
+ uintptr_t max = 1U << test_power;
+
+ do {
+ power = test_power;
+ max <<= QORIQ_MMU_POWER_STEP;
+ test_power += QORIQ_MMU_POWER_STEP;
+ } while (test_power <= QORIQ_MMU_MAX_POWER && max <= val);
+
+ return power;
+}
+
+void TEXT qoriq_mmu_context_init(qoriq_mmu_context *self)
+{
+ int *cur = (int *) self;
+ const int *end = cur + sizeof(*self) / sizeof(*cur);
+
+ while (cur != end) {
+ *cur = 0;
+ ++cur;
+ }
+}
+
+static void TEXT sort(qoriq_mmu_context *self)
+{
+ qoriq_mmu_entry *entries = self->entries;
+ int n = self->count;
+ int i = 0;
+
+ for (i = 1; i < n; ++i) {
+ qoriq_mmu_entry key = entries [i];
+ int j = 0;
+
+ for (j = i - 1; j >= 0 && entries [j].begin > key.begin; --j) {
+ entries [j + 1] = entries [j];
+ }
+
+ entries [j + 1] = key;
+ }
+}
+
+static bool TEXT mas_compatible(const qoriq_mmu_entry *a, const qoriq_mmu_entry *b)
+{
+ uint32_t m = FSL_EIS_MAS2_M;
+
+ return (a->mas2 & ~m) == (b->mas2 & ~m);
+}
+
+static bool TEXT can_merge(const qoriq_mmu_entry *prev, const qoriq_mmu_entry *cur)
+{
+ return mas_compatible(prev, cur)
+ && (prev->begin == cur->begin || prev->last >= cur->begin - 1);
+}
+
+static void TEXT merge(qoriq_mmu_context *self)
+{
+ qoriq_mmu_entry *entries = self->entries;
+ int n = self->count;
+ int i = 0;
+
+ for (i = 1; i < n; ++i) {
+ qoriq_mmu_entry *prev = &entries [i - 1];
+ qoriq_mmu_entry *cur = &entries [i];
+
+ if (can_merge(prev, cur)) {
+ int j = 0;
+
+ prev->mas1 |= cur->mas1;
+ prev->mas2 |= cur->mas2;
+ prev->mas3 |= cur->mas3;
+
+ if (cur->last > prev->last) {
+ prev->last = cur->last;
+ }
+
+ for (j = i + 1; j < n; ++j) {
+ entries [j - 1] = entries [j];
+ }
+
+ --i;
+ --n;
+ }
+ }
+
+ self->count = n;
+}
+
+static void TEXT compact(qoriq_mmu_context *self)
+{
+ sort(self);
+ merge(self);
+}
+
+static bool TEXT can_expand_down(
+ const qoriq_mmu_context *self,
+ const qoriq_mmu_entry *cur,
+ int i,
+ uintptr_t new_begin
+)
+{
+ int j;
+
+ for (j = 0; j < i; ++j) {
+ const qoriq_mmu_entry *before = &self->entries[j];
+
+ if (
+ before->begin <= new_begin
+ && new_begin <= before->last
+ && !mas_compatible(before, cur)
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TEXT can_expand_up(
+ const qoriq_mmu_context *self,
+ const qoriq_mmu_entry *cur,
+ int i,
+ int n,
+ uintptr_t new_last
+)
+{
+ int j;
+
+ for (j = i + 1; j < n; ++j) {
+ const qoriq_mmu_entry *after = &self->entries[j];
+
+ if (
+ after->begin <= new_last
+ && new_last <= after->last
+ && !mas_compatible(after, cur)
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void TEXT align(qoriq_mmu_context *self, uintptr_t alignment)
+{
+ int n = self->count;
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ qoriq_mmu_entry *cur = &self->entries[i];
+ uintptr_t new_begin = cur->begin & ~(alignment - 1);
+ uintptr_t new_last = alignment + (cur->last & ~(alignment - 1)) - 1;
+
+ if (
+ can_expand_down(self, cur, i, new_begin)
+ && can_expand_up(self, cur, i, n, new_last)
+ ) {
+ cur->begin = new_begin;
+ cur->last = new_last;
+ }
+ }
+}
+
+static bool TEXT is_full(qoriq_mmu_context *self)
+{
+ return self->count >= QORIQ_TLB1_ENTRY_COUNT;
+}
+
+static void TEXT append(qoriq_mmu_context *self, const qoriq_mmu_entry *new_entry)
+{
+ self->entries [self->count] = *new_entry;
+ ++self->count;
+}
+
+bool TEXT qoriq_mmu_add(
+ qoriq_mmu_context *self,
+ uintptr_t begin,
+ uintptr_t last,
+ uint32_t mas1,
+ uint32_t mas2,
+ uint32_t mas3,
+ uint32_t mas7
+)
+{
+ bool ok = true;
+
+ if (is_full(self)) {
+ compact(self);
+ }
+
+ if (!is_full(self)) {
+ if (begin < last) {
+ qoriq_mmu_entry new_entry = {
+ .begin = begin,
+ .last = last,
+ .mas1 = mas1,
+ .mas2 = mas2,
+ .mas3 = mas3,
+ .mas7 = mas7
+ };
+ append(self, &new_entry);
+ } else {
+ ok = false;
+ }
+ } else {
+ ok = false;
+ }
+
+ return ok;
+}
+
+static uintptr_t TEXT min(uintptr_t a, uintptr_t b)
+{
+ return a < b ? a : b;
+}
+
+static bool TEXT split(qoriq_mmu_context *self, qoriq_mmu_entry *cur)
+{
+ bool again = false;
+ uintptr_t begin = cur->begin;
+ uintptr_t end = cur->last + 1;
+ uintptr_t size = end - begin;
+ uintptr_t begin_power = power_of_two(begin);
+ uintptr_t size_power = max_power_of_two(size);
+ uintptr_t power = min(begin_power, size_power);
+ uintptr_t split_size = power < 32 ? (1U << power) : 0;
+ uintptr_t split_pos = begin + split_size;
+
+ if (split_pos != end && !is_full(self)) {
+ qoriq_mmu_entry new_entry = *cur;
+ cur->begin = split_pos;
+ new_entry.last = split_pos - 1;
+ append(self, &new_entry);
+ again = true;
+ }
+
+ return again;
+}
+
+static void TEXT split_all(qoriq_mmu_context *self)
+{
+ qoriq_mmu_entry *entries = self->entries;
+ int n = self->count;
+ int i = 0;
+
+ for (i = 0; i < n; ++i) {
+ qoriq_mmu_entry *cur = &entries [i];
+
+ while (split(self, cur)) {
+ /* Repeat */
+ }
+ }
+}
+
+static TEXT void partition(qoriq_mmu_context *self)
+{
+ compact(self);
+ split_all(self);
+ sort(self);
+}
+
+void TEXT qoriq_mmu_partition(qoriq_mmu_context *self, int max_count)
+{
+ uintptr_t alignment = 4096;
+
+ sort(self);
+
+ do {
+ align(self, alignment);
+ partition(self);
+ alignment *= 4;
+ } while (self->count > max_count);
+}
+
+void TEXT qoriq_mmu_write_to_tlb1(qoriq_mmu_context *self, int first_tlb)
+{
+ qoriq_mmu_entry *entries = self->entries;
+ int n = self->count;
+ int i = 0;
+
+ for (i = 0; i < n; ++i) {
+ qoriq_mmu_entry *cur = &entries [i];
+ uintptr_t ea = cur->begin;
+ uintptr_t size = cur->last - ea + 1;
+ uintptr_t tsize = (power_of_two(size) - 10) / 2;
+ int tlb = first_tlb + i;
+
+ qoriq_tlb1_write(
+ tlb,
+ cur->mas1,
+ cur->mas2,
+ cur->mas3,
+ cur->mas7,
+ ea,
+ (int) tsize
+ );
+ }
+}
+
+void qoriq_mmu_change_perm(uint32_t test, uint32_t set, uint32_t clear)
+{
+ int i = 0;
+
+ for (i = 0; i < 16; ++i) {
+ uint32_t mas0 = FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(i);
+ uint32_t mas1 = 0;
+
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
+ asm volatile ("tlbre");
+
+ mas1 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1);
+ if ((mas1 & FSL_EIS_MAS1_V) != 0) {
+ uint32_t mask = 0x3ff;
+ uint32_t mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
+
+ if ((mas3 & mask) == test) {
+ mas3 &= ~(clear & mask);
+ mas3 |= set & mask;
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
+ asm volatile ("isync; msync; tlbwe; isync" : : : "memory");
+ }
+ }
+ }
+}
diff --git a/bsps/powerpc/qoriq/start/portal.c b/bsps/powerpc/qoriq/start/portal.c
new file mode 100644
index 0000000000..f20eaf4d28
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/portal.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 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/qoriq.h>
+
+#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
+
+#include <libcpu/powerpc-utility.h>
+
+void qoriq_clear_ce_portal(void *base, size_t size)
+{
+ size_t offset;
+
+ for (offset = 0; offset < size; offset += 64) {
+ ppc_data_cache_block_clear_to_zero_2(base, offset);
+ ppc_data_cache_block_flush_2(base, offset);
+ }
+}
+
+void qoriq_clear_ci_portal(void *base, size_t size)
+{
+ uint32_t zero;
+ size_t offset;
+
+ zero = 0;
+
+ for (offset = 0; offset < size; offset += 4) {
+ ppc_write_word(zero, (char *) base + offset);
+ }
+}
+
+#endif
diff --git a/bsps/powerpc/qoriq/start/restart.S b/bsps/powerpc/qoriq/start/restart.S
new file mode 100644
index 0000000000..7dd9eb198d
--- /dev/null
+++ b/bsps/powerpc/qoriq/start/restart.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016 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 <libcpu/powerpc-utility.h>
+
+#define FIRST_TLB 0
+
+#define SCRATCH_TLB QORIQ_TLB1_ENTRY_COUNT - 1
+
+ .global qoriq_restart_secondary_processor
+
+ .section ".bsp_start_text", "ax"
+
+qoriq_restart_secondary_processor:
+
+ mr r14, r3
+
+ /* Invalidate all TS1 MMU entries */
+ li r3, 1
+ bl qoriq_tlb1_invalidate_all_by_ts
+
+ /* Add TS1 entry for the first 4GiB of RAM */
+ li r3, SCRATCH_TLB
+ li r4, FSL_EIS_MAS1_TS
+ li r5, FSL_EIS_MAS2_I
+ li r6, FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW | FSL_EIS_MAS3_SX
+ li r7, 0
+ li r8, 0
+ li r9, 11
+ bl qoriq_tlb1_write
+
+ bl qoriq_l1cache_invalidate
+
+ /* Set MSR and use TS1 for address translation */
+ LWI r0, QORIQ_INITIAL_MSR | MSR_IS | MSR_DS
+ mtmsr r0
+ isync
+
+ /* Invalidate all TS0 MMU entries */
+ li r3, 0
+ bl qoriq_tlb1_invalidate_all_by_ts
+
+ /* Add TS0 entry for the first 4GiB of RAM */
+ li r3, FIRST_TLB
+ li r4, 0
+ li r5, FSL_EIS_MAS2_I
+ li r6, FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW | FSL_EIS_MAS3_SX
+ li r7, 0
+ li r8, 0
+ li r9, 11
+ bl qoriq_tlb1_write
+
+ /* Use TS0 for address translation */
+ LWI r0, QORIQ_INITIAL_MSR
+ mtmsr r0
+ isync
+
+ bl qoriq_l1cache_invalidate
+
+ /* Wait for restart request */
+ li r0, 0
+.Lrestartagain:
+ lwz r4, 4(r14)
+ cmpw r0, r4
+ beq .Lrestartagain
+ isync
+ mtctr r4
+ lwz r3, 12(r14)
+ bctr