uboot/arch/arm/cpu/armv7/mpu_v7r.c
<<
>>
Prefs
   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
  33void 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
  44void 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
  55int mpu_enabled(void)
  56{
  57        return get_cr() & CR_M;
  58}
  59
  60void 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
  84void 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
 110void 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