aboutsummaryrefslogtreecommitdiff
path: root/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.c
blob: 82318112326ad5a016329edfe721e9c8a80e36ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include "mpu_armv8m_drv.h"
#include "cmsis_cpu.h"
#include "fih.h"

/*
 * FixMe:
 * This is a beta quality driver for MPU in v8M. To be finalized.
 */

fih_int mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
                          uint32_t privdef_en,
                          uint32_t hfnmi_en)
{
    /*No error checking*/

    MPU_Type *mpu = (MPU_Type *)dev->base;

    /*
     * FixMe: Set 3 pre-defined MAIR_ATTR for memory. The attributes come
     * from default memory map, need to check if fine-tune is necessary.
     *
     * MAIR0_0: Peripheral, Device-nGnRE.
     * MAIR0_1: Code, WT RA. Same attr for Outer and Inner.
     * MAIR0_2: SRAM, WBWA RA. Same attr for Outer and Inner.
     */
    mpu->MAIR0 = (MPU_ARMV8M_MAIR_ATTR_DEVICE_VAL << MPU_MAIR0_Attr0_Pos) |
                 (MPU_ARMV8M_MAIR_ATTR_CODE_VAL << MPU_MAIR0_Attr1_Pos) |
                 (MPU_ARMV8M_MAIR_ATTR_DATA_VAL << MPU_MAIR0_Attr2_Pos);

    mpu->CTRL =
            (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
            (hfnmi_en   ? MPU_CTRL_HFNMIENA_Msk   : 0);

    /*Ensure all configuration is written before enable*/

    mpu->CTRL |= MPU_CTRL_ENABLE_Msk;

    /* Enable MPU before next instruction */
    __DSB();
    __ISB();

    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
}

fih_int mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
{
    MPU_Type *mpu = (MPU_Type *)dev->base;

    /* Reset all fields as enable does full setup */
    mpu->CTRL = 0;

    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
}


fih_int mpu_armv8m_region_enable(struct mpu_armv8m_dev_t *dev,
                                 struct mpu_armv8m_region_cfg_t *region_cfg)
{
    MPU_Type *mpu = (MPU_Type *)dev->base;

    uint32_t ctrl_before;
    uint32_t base_cfg;
    uint32_t limit_cfg;

    /*FIXME : Add complete error checking*/
    if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0) {
        FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
    }
    /* region_limit doesn't need to be aligned but the scatter
     * file needs to be setup to ensure that partitions do not overlap.
     */

    ctrl_before = mpu->CTRL;
    mpu->CTRL = 0;

    mpu->RNR  = region_cfg->region_nr & MPU_RNR_REGION_Msk;

    /* This 0s the lower bits of the base address */
    base_cfg = region_cfg->region_base & MPU_RBAR_BASE_Msk;
    base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
    base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
    base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;

    mpu->RBAR = base_cfg;

    /*This 0s the lower bits of base address but they are treated as 1 */
    limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;

    limit_cfg |= (region_cfg->region_attridx << MPU_RLAR_AttrIndx_Pos) &
                 MPU_RLAR_AttrIndx_Msk;

    limit_cfg |= MPU_RLAR_EN_Msk;

    mpu->RLAR = limit_cfg;

    /*Restore main MPU control*/
    mpu->CTRL = ctrl_before;

    /* Enable MPU before the next instruction */
    __DSB();
    __ISB();

    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
}


fih_int mpu_armv8m_region_disable(struct mpu_armv8m_dev_t *dev,
                                  uint32_t region_nr)
{

    MPU_Type *mpu = (MPU_Type *)dev->base;
    uint32_t ctrl_before;

    /*FIXME : Add complete error checking*/

    ctrl_before = mpu->CTRL;
    mpu->CTRL = 0;

    mpu->RNR  = region_nr & MPU_RNR_REGION_Msk;

    mpu->RBAR = 0;
    mpu->RLAR = 0;

    /*Restore main MPU control*/
    mpu->CTRL = ctrl_before;

    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
}

fih_int mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
{
    MPU_Type *mpu = (MPU_Type *)dev->base;
    uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
    fih_int fih_rc = fih_int_encode(MPU_ARMV8M_ERROR);

    while (i > 0) {
        FIH_CALL(mpu_armv8m_region_disable, fih_rc, dev, i - 1);
        i--;
    }

#ifdef TFM_FIH_PROFILE_ON
    if (i > 0) {
        FIH_PANIC;
    }
#endif

    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
}