diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 10:35:35 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 13:52:14 +0200 |
commit | 99648958668d3a33ee57974479b36201fe303f34 (patch) | |
tree | 6f27ea790e2823c6156e71219a4f54680263fac6 /bsps/powerpc/qoriq | |
parent | bsps: Move start files to bsps (diff) | |
download | rtems-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_specs | 9 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/bspreset.c | 64 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/bsprestart.c | 146 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/bspsmp.c | 252 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/bspstart.c | 197 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/epapr_hcalls.S | 26 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/l1cache.S | 43 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/l2cache.S | 43 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/linkcmds.qoriq_core_0 | 38 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/linkcmds.qoriq_core_1 | 37 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/linkcmds.qoriq_e500 | 38 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_32 | 41 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/linkcmds.qoriq_e6500_64 | 1 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/mmu-config.c | 352 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/mmu-tlb1.S | 107 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/mmu.c | 368 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/portal.c | 43 | ||||
-rw-r--r-- | bsps/powerpc/qoriq/start/restart.S | 80 |
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 |