Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | // SPDX-License-Identifier: GPL-2.0+ /* * Cortex-R Memory Protection Unit specific code * * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ * Lokesh Vutla <lokeshvutla@ti.com> */ #include <command.h> #include <cpu_func.h> #include <asm/armv7.h> #include <asm/system.h> #include <asm/barriers.h> #include <linux/bitops.h> #include <linux/compiler.h> #include <asm/armv7_mpu.h> /* MPU Type register definitions */ #define MPUIR_S_SHIFT 0 #define MPUIR_S_MASK BIT(MPUIR_S_SHIFT) #define MPUIR_DREGION_SHIFT 8 #define MPUIR_DREGION_MASK (0xff << 8) /** * Note: * The Memory Protection Unit(MPU) allows to partition memory into regions * and set individual protection attributes for each region. In absence * of MPU a default map[1] will take effect. make sure to run this code * from a region which has execution permissions by default. * [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0460d/I1002400.html */ void disable_mpu(void) { u32 reg; reg = get_cr(); reg &= ~CR_M; dsb(); set_cr(reg); isb(); } void enable_mpu(void) { u32 reg; reg = get_cr(); reg |= CR_M; dsb(); set_cr(reg); isb(); } int mpu_enabled(void) { return get_cr() & CR_M; } void mpu_config(struct mpu_region_config *rgn) { u32 attr, val; attr = get_attr_encoding(rgn->mr_attr); /* MPU Region Number Register */ asm volatile ("mcr p15, 0, %0, c6, c2, 0" : : "r" (rgn->region_no)); /* MPU Region Base Address Register */ asm volatile ("mcr p15, 0, %0, c6, c1, 0" : : "r" (rgn->start_addr)); /* MPU Region Size and Enable Register */ if (rgn->reg_size) val = (rgn->reg_size << REGION_SIZE_SHIFT) | ENABLE_REGION; else val = DISABLE_REGION; asm volatile ("mcr p15, 0, %0, c6, c1, 2" : : "r" (val)); /* MPU Region Access Control Register */ val = rgn->xn << XN_SHIFT | rgn->ap << AP_SHIFT | attr; asm volatile ("mcr p15, 0, %0, c6, c1, 4" : : "r" (val)); } void setup_mpu_regions(struct mpu_region_config *rgns, u32 num_rgns) { u32 num, i; asm volatile ("mrc p15, 0, %0, c0, c0, 4" : "=r" (num)); num = (num & MPUIR_DREGION_MASK) >> MPUIR_DREGION_SHIFT; /* Regions to be configured cannot be greater than available regions */ if (num < num_rgns) num_rgns = num; /** * Assuming dcache might not be enabled at this point, disabling * and invalidating only icache. */ icache_disable(); invalidate_icache_all(); disable_mpu(); for (i = 0; i < num_rgns; i++) mpu_config(&rgns[i]); enable_mpu(); icache_enable(); } void enable_caches(void) { /* * setup_mpu_regions() might have enabled Icache. So add a check * before enabling Icache */ if (!icache_status()) icache_enable(); dcache_enable(); } |