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