mpu_v7r.c 2.6 KB

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