File indexing completed on 2025-05-11 08:22:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <bsp.h>
0038 #include <bsp/ecc_priv.h>
0039 #include <bsp/irq.h>
0040 #include <bsp/utility.h>
0041 #include <libcpu/mmu-vmsav8-64.h>
0042
0043 static uintptr_t ocm_base = 0xFF960000;
0044
0045
0046 #define OCM_ECC_CTRL 0x14
0047
0048 #define OCM_ECC_CTRL_FI_MODE BSP_BIT32(2)
0049
0050 #define OCM_ECC_CTRL_DET_ONLY BSP_BIT32(1)
0051
0052 #define OCM_ECC_CTRL_ECC_ON_OFF BSP_BIT32(0)
0053
0054
0055 #define OCM_IE 0xc
0056 #define OCM_IE_UE_RMW BSP_BIT32(10)
0057 #define OCM_IE_UE BSP_BIT32(7)
0058 #define OCM_IE_CE BSP_BIT32(6)
0059
0060
0061 #define OCM_ERR_CTRL 0x0
0062 #define OCM_ERR_CTRL_UE_RES BSP_BIT32(3)
0063
0064
0065
0066
0067
0068
0069
0070 #define OCM_FI_D0 0x4c
0071 #define OCM_FI_D1 0x50
0072 #define OCM_FI_D2 0x54
0073 #define OCM_FI_D3 0x58
0074
0075
0076 #define OCM_FI_SY 0x5c
0077 #define OCM_FI_SY_DATA(val) BSP_FLD32(val, 0, 15)
0078 #define OCM_FI_SY_DATA_GET(reg) BSP_FLD32GET(reg, 0, 15)
0079 #define OCM_FI_SY_DATA_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
0080
0081
0082 #define OCM_FI_CNTR 0x74
0083 #define OCM_FI_CNTR_COUNT(val) BSP_FLD32(val, 0, 23)
0084 #define OCM_FI_CNTR_COUNT_GET(reg) BSP_FLD32GET(reg, 0, 23)
0085 #define OCM_FI_CNTR_COUNT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 23)
0086
0087
0088 #define OCM_IS 0x4
0089 #define OCM_IS_UE_RMW BSP_BIT32(10)
0090 #define OCM_IS_UE BSP_BIT32(7)
0091 #define OCM_IS_CE BSP_BIT32(6)
0092
0093
0094 #define OCM_IM 0x8
0095 #define OCM_IM_UE_RMW BSP_BIT32(10)
0096 #define OCM_IM_UE BSP_BIT32(7)
0097 #define OCM_IM_CE BSP_BIT32(6)
0098
0099 void zynqmp_ocm_inject_fault( void )
0100 {
0101 volatile uint32_t *fi_d0 = (uint32_t*)(ocm_base + OCM_FI_D0);
0102 volatile uint32_t *fi_cnt = (uint32_t*)(ocm_base + OCM_FI_CNTR);
0103 volatile uint64_t *ocm_top = (uint64_t*)0xFFFFFFF0U;
0104 volatile uint32_t *ecc_ctrl = (uint32_t*)(ocm_base + OCM_ECC_CTRL);
0105 uint64_t ocm_tmp = *ocm_top;
0106
0107
0108 *ecc_ctrl |= OCM_ECC_CTRL_FI_MODE;
0109
0110
0111 *fi_d0 = 1;
0112
0113
0114 *fi_cnt = 0;
0115
0116
0117 _AARCH64_Data_synchronization_barrier();
0118
0119
0120 *ocm_top = 0;
0121
0122
0123 _AARCH64_Data_synchronization_barrier();
0124
0125
0126 *ocm_top;
0127
0128
0129 *ecc_ctrl &= ~(OCM_ECC_CTRL_FI_MODE);
0130
0131
0132 _AARCH64_Data_synchronization_barrier();
0133
0134
0135 *ocm_top = ocm_tmp;
0136 }
0137
0138
0139 #define OCM_CE_FFA 0x1c
0140 #define OCM_CE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
0141 #define OCM_CE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
0142 #define OCM_CE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
0143
0144
0145 #define OCM_CE_FFD0 0x20
0146 #define OCM_CE_FFD1 0x24
0147 #define OCM_CE_FFD2 0x28
0148 #define OCM_CE_FFD3 0x2c
0149
0150
0151 #define OCM_CE_FFE 0x1c
0152 #define OCM_CE_FFE_SYNDROME(val) BSP_FLD32(val, 0, 15)
0153 #define OCM_CE_FFE_SYNDROME_GET(reg) BSP_FLD32GET(reg, 0, 15)
0154 #define OCM_CE_FFE_SYNDROME_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
0155
0156
0157 #define OCM_UE_FFA 0x34
0158 #define OCM_UE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
0159 #define OCM_UE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
0160 #define OCM_UE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
0161
0162
0163 #define OCM_UE_FFD0 0x38
0164 #define OCM_UE_FFD1 0x3c
0165 #define OCM_UE_FFD2 0x40
0166 #define OCM_UE_FFD3 0x44
0167
0168
0169 #define OCM_UE_FFE 0x48
0170 #define OCM_UE_FFE_SYNDROME(val) BSP_FLD32(val, 0, 15)
0171 #define OCM_UE_FFE_SYNDROME_GET(reg) BSP_FLD32GET(reg, 0, 15)
0172 #define OCM_UE_FFE_SYNDROME_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
0173
0174
0175 #define OCM_RMW_UE_FFA 0x70
0176 #define OCM_RMW_UE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
0177 #define OCM_RMW_UE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
0178 #define OCM_RMW_UE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
0179
0180 static void ocm_handle_rmw( void )
0181 {
0182 volatile uint32_t *rmw_ffa = (uint32_t*)(ocm_base + OCM_RMW_UE_FFA);
0183 OCM_Error_Info info;
0184
0185 info.type = OCM_UNCORRECTABLE_RMW;
0186 info.offset = OCM_RMW_UE_FFA_ADDR_GET(*rmw_ffa);
0187 zynqmp_invoke_ecc_handler(OCM_RAM, &info);
0188 }
0189
0190 static void ocm_handle_ce( void )
0191 {
0192 volatile uint32_t *ce_ffa = (uint32_t*)(ocm_base + OCM_CE_FFA);
0193 volatile uint32_t *ce_ffe = (uint32_t*)(ocm_base + OCM_CE_FFA);
0194 volatile uint32_t *ce_ffd0 = (uint32_t*)(ocm_base + OCM_CE_FFD0);
0195 volatile uint32_t *ce_ffd1 = (uint32_t*)(ocm_base + OCM_CE_FFD1);
0196 volatile uint32_t *ce_ffd2 = (uint32_t*)(ocm_base + OCM_CE_FFD2);
0197 volatile uint32_t *ce_ffd3 = (uint32_t*)(ocm_base + OCM_CE_FFD3);
0198 OCM_Error_Info info;
0199
0200 info.type = OCM_CORRECTABLE;
0201 info.offset = OCM_CE_FFA_ADDR_GET(*ce_ffa);
0202 info.data0 = *ce_ffd0;
0203 info.data1 = *ce_ffd1;
0204 info.data2 = *ce_ffd2;
0205 info.data3 = *ce_ffd3;
0206 info.syndrome = OCM_CE_FFE_SYNDROME_GET(*ce_ffe);
0207 zynqmp_invoke_ecc_handler(OCM_RAM, &info);
0208 }
0209
0210 static void ocm_handle_ue( void )
0211 {
0212 volatile uint32_t *ue_ffa = (uint32_t*)(ocm_base + OCM_UE_FFA);
0213 volatile uint32_t *ue_ffe = (uint32_t*)(ocm_base + OCM_UE_FFA);
0214 volatile uint32_t *ue_ffd0 = (uint32_t*)(ocm_base + OCM_UE_FFD0);
0215 volatile uint32_t *ue_ffd1 = (uint32_t*)(ocm_base + OCM_UE_FFD1);
0216 volatile uint32_t *ue_ffd2 = (uint32_t*)(ocm_base + OCM_UE_FFD2);
0217 volatile uint32_t *ue_ffd3 = (uint32_t*)(ocm_base + OCM_UE_FFD3);
0218 OCM_Error_Info info;
0219
0220 info.type = OCM_UNCORRECTABLE;
0221 info.offset = OCM_UE_FFA_ADDR_GET(*ue_ffa);
0222 info.data0 = *ue_ffd0;
0223 info.data1 = *ue_ffd1;
0224 info.data2 = *ue_ffd2;
0225 info.data3 = *ue_ffd3;
0226 info.syndrome = OCM_UE_FFE_SYNDROME_GET(*ue_ffe);
0227 zynqmp_invoke_ecc_handler(OCM_RAM, &info);
0228 }
0229
0230 static void ocm_handler(void *arg)
0231 {
0232 volatile uint32_t *ocm_is = (uint32_t*)(ocm_base + OCM_IS);
0233 uint32_t ocm_is_value = *ocm_is;
0234 (void) arg;
0235
0236
0237 if ((ocm_is_value & OCM_IS_UE_RMW) != 0) {
0238 ocm_handle_rmw();
0239 *ocm_is = OCM_IS_UE_RMW;
0240 }
0241
0242 if ((ocm_is_value & OCM_IS_CE) != 0) {
0243 ocm_handle_ce();
0244 *ocm_is = OCM_IS_CE;
0245 }
0246
0247 if ((ocm_is_value & OCM_IS_UE) != 0) {
0248 ocm_handle_ue();
0249 *ocm_is = OCM_IS_UE;
0250 }
0251 }
0252
0253 static rtems_interrupt_entry zynqmp_ocm_ecc_entry;
0254
0255 rtems_status_code zynqmp_configure_ocm_ecc( void )
0256 {
0257 volatile uint32_t *err_ctrl = (uint32_t*)(ocm_base + OCM_ERR_CTRL);
0258 volatile uint32_t *ecc_ctrl = (uint32_t*)(ocm_base + OCM_ECC_CTRL);
0259 volatile uint32_t *int_enable = (uint32_t*)(ocm_base + OCM_IE);
0260 rtems_status_code sc;
0261
0262 rtems_interrupt_entry_initialize(
0263 &zynqmp_ocm_ecc_entry,
0264 ocm_handler,
0265 NULL,
0266 "OCM RAM ECC"
0267 );
0268
0269 sc = rtems_interrupt_entry_install(
0270 ZYNQMP_IRQ_OCM,
0271 RTEMS_INTERRUPT_SHARED,
0272 &zynqmp_ocm_ecc_entry
0273 );
0274
0275 if (sc != RTEMS_SUCCESSFUL) {
0276 return sc;
0277 }
0278
0279 if ((*ecc_ctrl & OCM_ECC_CTRL_ECC_ON_OFF) == 0) {
0280
0281
0282
0283
0284 return RTEMS_NOT_CONFIGURED;
0285 }
0286
0287
0288
0289
0290
0291 *err_ctrl &= ~(OCM_ERR_CTRL_UE_RES);
0292
0293
0294 *ecc_ctrl &= ~(OCM_ECC_CTRL_DET_ONLY);
0295
0296
0297 *int_enable = OCM_IE_CE | OCM_IE_UE | OCM_IE_UE_RMW;
0298
0299 return RTEMS_SUCCESSFUL;
0300 }