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