Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsPowerPCQorIQMMU
0007  *
0008  * @brief MMU implementation.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2011, 2018 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 #include <bsp/bootcard.h>
0038 #include <bsp/fdt.h>
0039 #include <bsp/linker-symbols.h>
0040 #include <bsp/mmu.h>
0041 #include <bsp/qoriq.h>
0042 
0043 #include <sys/param.h>
0044 
0045 #include <libfdt.h>
0046 
0047 #include <rtems/config.h>
0048 #include <rtems/sysinit.h>
0049 
0050 #define TEXT __attribute__((section(".bsp_start_text")))
0051 #define DATA __attribute__((section(".bsp_start_data")))
0052 
0053 typedef struct {
0054     uintptr_t begin;
0055     uintptr_t size;
0056     uint32_t mas2;
0057     uint32_t mas3;
0058     uint32_t mas7;
0059 } entry;
0060 
0061 #define ENTRY_X(b, s) { \
0062     .begin = (uintptr_t) b, \
0063     .size = (uintptr_t) s, \
0064     .mas2 = 0, \
0065     .mas3 = FSL_EIS_MAS3_SX \
0066 }
0067 
0068 #define ENTRY_R(b, s) { \
0069     .begin = (uintptr_t) b, \
0070     .size = (uintptr_t) s, \
0071     .mas2 = 0, \
0072     .mas3 = FSL_EIS_MAS3_SR \
0073 }
0074 
0075 #ifdef RTEMS_SMP
0076   #define ENTRY_RW_MAS2 FSL_EIS_MAS2_M
0077 #else
0078   #define ENTRY_RW_MAS2 0
0079 #endif
0080 
0081 #define ENTRY_RW(b, s) { \
0082     .begin = (uintptr_t) b, \
0083     .size = (uintptr_t) s, \
0084     .mas2 = ENTRY_RW_MAS2, \
0085     .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW \
0086 }
0087 
0088 #define ENTRY_IO(b, s) { \
0089     .begin = (uintptr_t) b, \
0090     .size = (uintptr_t) s, \
0091     .mas2 = FSL_EIS_MAS2_I | FSL_EIS_MAS2_G, \
0092     .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW \
0093 }
0094 
0095 #define ENTRY_DEV(b, s) { \
0096     .begin = (uintptr_t) b, \
0097     .size = (uintptr_t) s, \
0098     .mas2 = FSL_EIS_MAS2_I | FSL_EIS_MAS2_G, \
0099     .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, \
0100     .mas7 = QORIQ_MMU_DEVICE_MAS7 \
0101 }
0102 
0103 /*
0104  * MMU entry for BMan and QMan software portals.
0105  *
0106  * The M bit must be set if stashing is used, see 3.3.8.6 DQRR Entry Stashing
0107  * and 3.3.8 Software Portals in T4240DPAARM.
0108  *
0109  * The G bit must be set, otherwise ECC errors in the QMan software portals
0110  * will occur.  No documentation reference for this is available.
0111  */
0112 #define ENTRY_DEV_CACHED(b, s) { \
0113     .begin = (uintptr_t) b, \
0114     .size = (uintptr_t) s, \
0115     .mas2 = FSL_EIS_MAS2_M | FSL_EIS_MAS2_G, \
0116     .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, \
0117     .mas7 = QORIQ_MMU_DEVICE_MAS7 \
0118 }
0119 
0120 #define WORKSPACE_ENTRY_INDEX 0
0121 
0122 static entry DATA config[] = {
0123     /* Must be first entry, see WORKSPACE_ENTRY_INDEX */
0124     ENTRY_RW(bsp_section_work_begin, bsp_section_work_size),
0125 
0126     #if defined(RTEMS_MULTIPROCESSING) && \
0127         defined(QORIQ_INTERCOM_AREA_BEGIN) && \
0128         defined(QORIQ_INTERCOM_AREA_SIZE)
0129         {
0130             .begin = QORIQ_INTERCOM_AREA_BEGIN,
0131             .size = QORIQ_INTERCOM_AREA_SIZE,
0132             .mas2 = FSL_EIS_MAS2_M,
0133             .mas3 = FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW
0134         },
0135     #endif
0136     ENTRY_X(bsp_section_start_begin, bsp_section_start_size),
0137     ENTRY_R(bsp_section_fast_text_load_begin, bsp_section_fast_text_size),
0138     ENTRY_X(bsp_section_fast_text_begin, bsp_section_fast_text_size),
0139     ENTRY_X(bsp_section_text_begin, bsp_section_text_size),
0140     ENTRY_R(bsp_section_rodata_load_begin, bsp_section_rodata_size),
0141     ENTRY_R(bsp_section_rodata_begin, bsp_section_rodata_size),
0142     ENTRY_R(bsp_section_fast_data_load_begin, bsp_section_fast_data_size),
0143     ENTRY_RW(bsp_section_fast_data_begin, bsp_section_fast_data_size),
0144     ENTRY_R(bsp_section_data_load_begin, bsp_section_data_size),
0145     ENTRY_RW(bsp_section_data_begin, bsp_section_data_size),
0146     ENTRY_RW(bsp_section_sbss_begin, bsp_section_sbss_size),
0147     ENTRY_RW(bsp_section_bss_begin, bsp_section_bss_size),
0148     ENTRY_RW(bsp_section_rtemsstack_begin, bsp_section_rtemsstack_size),
0149     ENTRY_RW(bsp_section_noinit_begin, bsp_section_noinit_size),
0150     ENTRY_RW(bsp_section_stack_begin, bsp_section_stack_size),
0151     ENTRY_IO(bsp_section_nocache_begin, bsp_section_nocache_size),
0152     ENTRY_IO(bsp_section_nocachenoload_begin, bsp_section_nocachenoload_size),
0153 #ifndef QORIQ_IS_HYPERVISOR_GUEST
0154 #if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
0155     /* BMan Portals */
0156     ENTRY_DEV_CACHED(&qoriq_bman_portal[0][0], sizeof(qoriq_bman_portal[0])),
0157     ENTRY_DEV(&qoriq_bman_portal[1][0], sizeof(qoriq_bman_portal[1])),
0158     /* QMan Portals */
0159     ENTRY_DEV_CACHED(&qoriq_qman_portal[0][0], sizeof(qoriq_qman_portal[0])),
0160     ENTRY_DEV(&qoriq_qman_portal[1][0], sizeof(qoriq_qman_portal[1])),
0161 #endif
0162     ENTRY_DEV(&qoriq, sizeof(qoriq))
0163 #endif
0164 };
0165 
0166 static DATA char memory_path[] = "/memory";
0167 
0168 #ifdef QORIQ_IS_HYPERVISOR_GUEST
0169 static void TEXT add_dpaa_bqman_portals(
0170     qoriq_mmu_context *context,
0171     const void *fdt,
0172     const char *compatible
0173 )
0174 {
0175     int node;
0176 
0177     node = -1;
0178 
0179     while (true) {
0180         const void *val;
0181         int len;
0182         uintptr_t paddr;
0183         uintptr_t size;
0184 
0185         node = fdt_node_offset_by_compatible(fdt, node, compatible);
0186         if (node < 0) {
0187             break;
0188         }
0189 
0190         val = fdt_getprop(fdt, node, "reg", &len);
0191         if (len != 32) {
0192             continue;
0193         }
0194 
0195         paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]);
0196         size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]);
0197 
0198         qoriq_mmu_add(
0199             context,
0200             paddr,
0201             paddr + size - 1,
0202             0,
0203             FSL_EIS_MAS2_M | FSL_EIS_MAS2_G,
0204             FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
0205             QORIQ_MMU_DEVICE_MAS7
0206         );
0207 
0208         paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]);
0209         size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[3]);
0210 
0211         qoriq_mmu_add(
0212             context,
0213             paddr,
0214             paddr + size - 1,
0215             0,
0216             FSL_EIS_MAS2_I | FSL_EIS_MAS2_G,
0217             FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
0218             QORIQ_MMU_DEVICE_MAS7
0219         );
0220     }
0221 }
0222 
0223 static void TEXT add_dpaa_bpool(qoriq_mmu_context *context, const void *fdt)
0224 {
0225     int node;
0226 
0227     node = -1;
0228 
0229     while (true) {
0230         const void *val;
0231         int len;
0232         uintptr_t config_count;
0233         uintptr_t size;
0234         uintptr_t paddr;
0235 
0236         node = fdt_node_offset_by_compatible(fdt, node, "fsl,bpool");
0237         if (node < 0) {
0238             break;
0239         }
0240 
0241         val = fdt_getprop(fdt, node, "fsl,bpool-ethernet-cfg", &len);
0242         if (len != 24) {
0243             continue;
0244         }
0245 
0246         config_count = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]);
0247         size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]);
0248         paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]);
0249 
0250         qoriq_mmu_add(
0251             context,
0252             paddr,
0253             paddr + config_count * size - 1,
0254             0,
0255             FSL_EIS_MAS2_M,
0256             FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
0257             0
0258         );
0259     }
0260 }
0261 #endif
0262 
0263 static void TEXT config_fdt_adjust(const void *fdt)
0264 {
0265     int node;
0266 
0267     node = fdt_path_offset_namelen(
0268         fdt,
0269         memory_path,
0270         (int) sizeof(memory_path) - 1
0271     );
0272 
0273     if (node >= 0) {
0274         int len;
0275         const void *val;
0276         uint64_t mem_begin;
0277         uint64_t mem_size;
0278 
0279         val = fdt_getprop(fdt, node, "reg", &len);
0280         if (len == 8) {
0281             mem_begin = fdt32_to_cpu(((fdt32_t *) val)[0]);
0282             mem_size = fdt32_to_cpu(((fdt32_t *) val)[1]);
0283         } else if (len == 16) {
0284             mem_begin = fdt64_to_cpu(((fdt64_t *) val)[0]);
0285             mem_size = fdt64_to_cpu(((fdt64_t *) val)[1]);
0286         } else {
0287             mem_begin = 0;
0288             mem_size = 0;
0289         }
0290 
0291 #ifndef __powerpc64__
0292         mem_size = MIN(mem_size, 0x80000000U);
0293 #endif
0294 
0295         if (
0296             mem_begin == 0
0297                 && mem_size > (uintptr_t) bsp_section_work_end
0298                 && (uintptr_t) bsp_section_nocache_end
0299                     < (uintptr_t) bsp_section_work_end
0300         ) {
0301             /* Assign new value to allow a bsp_restart() */
0302             config[WORKSPACE_ENTRY_INDEX].size = (uintptr_t) mem_size
0303                 - (uintptr_t) bsp_section_work_begin;
0304         }
0305     }
0306 }
0307 
0308 /*
0309  * Each PCIe controller has a ranges attribute in the fdt like the following:
0310  *
0311  *   ranges = <0x2000000 0x00 0xc0000000 0x00 0xc0000000 0x00 0x20000000
0312  *             0x1000000 0x00 0x00000000 0x00 0xffc20000 0x00 0x00010000>;
0313  *             |------PCI address------| |-CPU address-| |-----size----|
0314  *
0315  * In theory, some fdt-attributes should be used to find out how long the PCI
0316  * address (#address-cells of the PCIe node), the CPU address (#address-cells of
0317  * the parent node) and the size (#size-cells of the PCIe node) are. In our case
0318  * the structure is fixed because the pcie root controllers are a part of the
0319  * chip. Therefore the sizes will never change and we can assume fixed lengths.
0320  *
0321  * The first cell of the PCI address holds a number of flags. A detailed
0322  * explanation can be found for example here:
0323  *
0324  * https://web.archive.org/web/20240109080338/https://michael2012z.medium.com/understanding-pci-node-in-fdt-769a894a13cc
0325  *
0326  * We are only interested in the entry with the flags 0x02000000 which basically
0327  * means that it is a non-relocatable, non-prefetchable, not-aliased 32 bit
0328  * memory space on the first bus.
0329  *
0330  * The other two cells of the PCI address are a 64 Bit address viewed from PCI
0331  * address space. The two CPU address cells are the same 64 Bit address viewed
0332  * from CPU address space. For our controller these two should always be the
0333  * same (no address translation). The last two cells give a size of the memory
0334  * region (in theory in PCI address space but it has to be the same for CPU and
0335  * PCI).
0336  */
0337 static void TEXT add_pcie_regions(qoriq_mmu_context *context, const void *fdt)
0338 {
0339     int node;
0340 
0341     node = -1;
0342 
0343     while (true) {
0344         static const size_t range_length = 7 * 4;
0345         const void *val;
0346         int len;
0347 
0348         node = fdt_node_offset_by_compatible(
0349             fdt,
0350             node,
0351             "fsl,mpc8548-pcie"
0352         );
0353         if (node < 0) {
0354             break;
0355         }
0356 
0357         val = fdt_getprop(fdt, node, "ranges", &len);
0358         if (len % range_length != 0) {
0359             continue;
0360         }
0361 
0362         while (len >= range_length) {
0363             uint32_t pci_addr_flags;
0364             uintptr_t pci_addr;
0365             uintptr_t cpu_addr;
0366             uintptr_t size;
0367             const uint32_t *cells;
0368 
0369             cells = val;
0370             pci_addr_flags = fdt32_to_cpu(cells[0]);
0371             pci_addr = fdt64_to_cpu(*(fdt64_t *)(&cells[1]));
0372             cpu_addr = fdt64_to_cpu(*(fdt64_t *)(&cells[3]));
0373             size = fdt64_to_cpu(*(fdt64_t *)(&cells[5]));
0374 
0375             if (pci_addr_flags == 0x02000000 &&
0376                 pci_addr == cpu_addr) {
0377                 /* Add as I/O memory */
0378                 qoriq_mmu_add(
0379                     context,
0380                     cpu_addr,
0381                     cpu_addr + size - 1,
0382                     0,
0383                     FSL_EIS_MAS2_I | FSL_EIS_MAS2_G,
0384                     FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
0385                     0
0386                 );
0387             }
0388             len -= range_length;
0389             val += range_length;
0390         }
0391     }
0392 }
0393 
0394 void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb)
0395 {
0396     qoriq_mmu_context context;
0397     const void *fdt;
0398     int max_count;
0399     int i;
0400 
0401     for (i = 0; i < QORIQ_TLB1_ENTRY_COUNT; ++i) {
0402         if (i != scratch_tlb) {
0403             qoriq_tlb1_invalidate(i);
0404         }
0405     }
0406 
0407     fdt = bsp_fdt_get();
0408     qoriq_mmu_context_init(&context);
0409 
0410 #ifdef QORIQ_IS_HYPERVISOR_GUEST
0411     add_dpaa_bqman_portals(&context, fdt, "fsl,bman-portal");
0412     add_dpaa_bqman_portals(&context, fdt, "fsl,qman-portal");
0413     add_dpaa_bpool(&context, fdt);
0414     max_count = QORIQ_TLB1_ENTRY_COUNT - 1;
0415 #else
0416     max_count = (3 * QORIQ_TLB1_ENTRY_COUNT) / 4;
0417 #endif
0418 
0419     if (boot_processor) {
0420         config_fdt_adjust(fdt);
0421     }
0422 
0423     for (i = 0; i < (int) (sizeof(config) / sizeof(config [0])); ++i) {
0424         const entry *cur = &config [i];
0425         if (cur->size > 0) {
0426             qoriq_mmu_add(
0427                 &context,
0428                 cur->begin,
0429                 cur->begin + cur->size - 1,
0430                 0,
0431                 cur->mas2,
0432                 cur->mas3,
0433                 cur->mas7
0434             );
0435         }
0436     }
0437 
0438     add_pcie_regions(&context, fdt);
0439 
0440     qoriq_mmu_partition(&context, max_count);
0441     qoriq_mmu_write_to_tlb1(&context, first_tlb);
0442 }
0443 
0444 static Memory_Area _Memory_Areas[1];
0445 
0446 static const Memory_Information _Memory_Information =
0447     MEMORY_INFORMATION_INITIALIZER(_Memory_Areas);
0448 
0449 static void bsp_memory_initialize(void)
0450 {
0451     const entry *we = &config[WORKSPACE_ENTRY_INDEX];
0452 
0453     _Memory_Initialize_by_size(
0454         &_Memory_Areas[0],
0455         (void *) we->begin,
0456         we->size
0457     );
0458 }
0459 
0460 RTEMS_SYSINIT_ITEM(
0461     bsp_memory_initialize,
0462     RTEMS_SYSINIT_MEMORY,
0463     RTEMS_SYSINIT_ORDER_MIDDLE
0464 );
0465 
0466 const Memory_Information *_Memory_Get(void)
0467 {
0468     return &_Memory_Information;
0469 }