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