forked from Imagelibrary/rtems
bsps/aarch64/zynqmp: Add memory error reporting
This adds error reporting for ZynqMP including L1 and L2 cache, on-chip memory (OCM) error correcting code (ECC), and DDR ECC. OCM ECC supports fault injection from within RTEMS. DDR ECC technically supports fault injection as well, but requires that the program injecting faults operate exclusively outside of DDR. The AArch64 port is not currently capable of operating exclusively in OCM due to size constraints and would need to be booted via JTAG or via a non-relocating u-boot to accomplish this.
This commit is contained in:
committed by
Chris Johns
parent
27ec46f11b
commit
b48166b9b6
129
bsps/aarch64/xilinx-zynqmp/ecc/cache.c
Normal file
129
bsps/aarch64/xilinx-zynqmp/ecc/cache.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of zynqmp_ecc_init().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/utility.h>
|
||||
#include <rtems/score/aarch64-system-registers.h>
|
||||
|
||||
static Cache_Error_RAM_ID get_l1_ramid(uint64_t ramid)
|
||||
{
|
||||
switch (ramid) {
|
||||
case 0x0:
|
||||
return RAM_ID_L1I_TAG;
|
||||
case 0x1:
|
||||
return RAM_ID_L1I_DATA;
|
||||
case 0x8:
|
||||
return RAM_ID_L1D_TAG;
|
||||
case 0x9:
|
||||
return RAM_ID_L1D_DATA;
|
||||
case 0xa:
|
||||
return RAM_ID_L1D_DIRTY;
|
||||
case 0x18:
|
||||
return RAM_ID_TLB;
|
||||
default:
|
||||
return RAM_ID_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static Cache_Error_RAM_ID get_l2_ramid(uint64_t ramid)
|
||||
{
|
||||
switch (ramid) {
|
||||
case 0x10:
|
||||
return RAM_ID_L2_TAG;
|
||||
case 0x11:
|
||||
return RAM_ID_L2_DATA;
|
||||
case 0x12:
|
||||
return RAM_ID_SCU;
|
||||
default:
|
||||
return RAM_ID_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_handler(void *arg)
|
||||
{
|
||||
uint64_t l1val = _AArch64_Read_cpumerrsr_el1();
|
||||
_AArch64_Write_cpumerrsr_el1(l1val);
|
||||
uint64_t l2val = _AArch64_Read_l2merrsr_el1();
|
||||
_AArch64_Write_l2merrsr_el1(l2val);
|
||||
|
||||
(void) arg;
|
||||
|
||||
if (l1val & AARCH64_CPUMERRSR_EL1_VALID) {
|
||||
/* parse L1 data */
|
||||
Cache_Error_Event cerr = {0, };
|
||||
cerr.abort = l1val & AARCH64_CPUMERRSR_EL1_FATAL;
|
||||
cerr.repeats = AARCH64_CPUMERRSR_EL1_REPEATERR_GET(l1val);
|
||||
cerr.other_errors = AARCH64_CPUMERRSR_EL1_OTHERERR_GET(l1val);
|
||||
cerr.ramid = get_l1_ramid(AARCH64_CPUMERRSR_EL1_RAMID_GET(l1val));
|
||||
cerr.segment = AARCH64_CPUMERRSR_EL1_CPUIDWAY_GET(l1val);
|
||||
cerr.address = AARCH64_CPUMERRSR_EL1_ADDR_GET(l1val);
|
||||
|
||||
zynqmp_invoke_ecc_handler(L1_CACHE, &cerr);
|
||||
}
|
||||
|
||||
if (l2val & AARCH64_L2MERRSR_EL1_VALID) {
|
||||
/* parse L2 data */
|
||||
Cache_Error_Event cerr = {0, };
|
||||
cerr.abort = l2val & AARCH64_L2MERRSR_EL1_FATAL;
|
||||
cerr.repeats = AARCH64_L2MERRSR_EL1_REPEATERR_GET(l2val);
|
||||
cerr.other_errors = AARCH64_L2MERRSR_EL1_OTHERERR_GET(l2val);
|
||||
cerr.ramid = get_l2_ramid(AARCH64_L2MERRSR_EL1_RAMID_GET(l2val));
|
||||
cerr.segment = AARCH64_L2MERRSR_EL1_CPUIDWAY_GET(l2val);
|
||||
cerr.address = AARCH64_L2MERRSR_EL1_ADDR_GET(l2val);
|
||||
|
||||
zynqmp_invoke_ecc_handler(L2_CACHE, &cerr);
|
||||
}
|
||||
}
|
||||
|
||||
static rtems_interrupt_entry zynqmp_cache_ecc_entry;
|
||||
|
||||
rtems_status_code zynqmp_configure_cache_ecc( void )
|
||||
{
|
||||
rtems_interrupt_entry_initialize(
|
||||
&zynqmp_cache_ecc_entry,
|
||||
cache_handler,
|
||||
NULL,
|
||||
"L1/L2 Cache Errors"
|
||||
);
|
||||
|
||||
return rtems_interrupt_entry_install(
|
||||
ZYNQMP_IRQ_CACHE,
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
&zynqmp_cache_ecc_entry
|
||||
);
|
||||
}
|
||||
906
bsps/aarch64/xilinx-zynqmp/ecc/ddr.c
Normal file
906
bsps/aarch64/xilinx-zynqmp/ecc/ddr.c
Normal file
@@ -0,0 +1,906 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of DDR ECC support.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/utility.h>
|
||||
#include <rtems/rtems/intr.h>
|
||||
|
||||
static uintptr_t ddrc_base = 0xFD070000;
|
||||
|
||||
/*
|
||||
* The upper value expressable by the bits in a field is sometimes used to
|
||||
* indicate different things
|
||||
*/
|
||||
#define DDRC_ADDRMAP_4BIT_SPECIAL 15
|
||||
#define DDRC_ADDRMAP_5BIT_SPECIAL 31
|
||||
|
||||
#define DDRC_MSTR_OFFSET 0x0
|
||||
#define DDRC_MSTR_BURST_RDWR(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_MSTR_BURST_RDWR_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_MSTR_BURST_RDWR_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_MSTR_BURST_RDWR_4 0x2
|
||||
#define DDRC_MSTR_BURST_RDWR_8 0x4
|
||||
#define DDRC_MSTR_BURST_RDWR_16 0x8
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH(val) BSP_FLD32(val, 12, 13)
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH_GET(reg) BSP_FLD32GET(reg, 12, 13)
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH_SET(reg, val) BSP_FLD32SET(reg, val, 12, 13)
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH_FULL 0x0
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH_HALF 0x1
|
||||
#define DDRC_MSTR_DATA_BUS_WIDTH_QUARTER 0x2
|
||||
#define DDRC_MSTR_LPDDR4 BSP_BIT32(5)
|
||||
#define DDRC_MSTR_DDR4 BSP_BIT32(4)
|
||||
#define DDRC_MSTR_LPDDR3 BSP_BIT32(3)
|
||||
#define DDRC_MSTR_DDR3 BSP_BIT32(0)
|
||||
|
||||
/* Address map definitions, DDR4 variant with full bus width expected */
|
||||
#define DDRC_ADDRMAP0_OFFSET 0x200
|
||||
#define DDRC_ADDRMAP0_RANK_B0_BASE 6
|
||||
#define DDRC_ADDRMAP0_RANK_B0_TARGET_BIT(bw, lp3) 0
|
||||
#define DDRC_ADDRMAP0_RANK_B0_TARGET rank
|
||||
#define DDRC_ADDRMAP0_RANK_B0_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP0_RANK_B0(val) BSP_FLD32(val, 0, 4)
|
||||
#define DDRC_ADDRMAP0_RANK_B0_GET(reg) BSP_FLD32GET(reg, 0, 4)
|
||||
#define DDRC_ADDRMAP0_RANK_B0_SET(reg, val) BSP_FLD32SET(reg, val, 0, 4)
|
||||
|
||||
#define DDRC_ADDRMAP1_OFFSET 0x204
|
||||
#define DDRC_ADDRMAP1_BANK_B2_BASE 4
|
||||
#define DDRC_ADDRMAP1_BANK_B2_TARGET_BIT(bw, lp3) 2
|
||||
#define DDRC_ADDRMAP1_BANK_B2_TARGET bank
|
||||
#define DDRC_ADDRMAP1_BANK_B2_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP1_BANK_B2(val) BSP_FLD32(val, 16, 20)
|
||||
#define DDRC_ADDRMAP1_BANK_B2_GET(reg) BSP_FLD32GET(reg, 16, 20)
|
||||
#define DDRC_ADDRMAP1_BANK_B2_SET(reg, val) BSP_FLD32SET(reg, val, 16, 20)
|
||||
#define DDRC_ADDRMAP1_BANK_B1_BASE 3
|
||||
#define DDRC_ADDRMAP1_BANK_B1_TARGET_BIT(bw, lp3) 1
|
||||
#define DDRC_ADDRMAP1_BANK_B1_TARGET bank
|
||||
#define DDRC_ADDRMAP1_BANK_B1_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP1_BANK_B1(val) BSP_FLD32(val, 8, 12)
|
||||
#define DDRC_ADDRMAP1_BANK_B1_GET(reg) BSP_FLD32GET(reg, 8, 12)
|
||||
#define DDRC_ADDRMAP1_BANK_B1_SET(reg, val) BSP_FLD32SET(reg, val, 8, 12)
|
||||
#define DDRC_ADDRMAP1_BANK_B0_BASE 2
|
||||
#define DDRC_ADDRMAP1_BANK_B0_TARGET_BIT(bw, lp3) 0
|
||||
#define DDRC_ADDRMAP1_BANK_B0_TARGET bank
|
||||
#define DDRC_ADDRMAP1_BANK_B0_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP1_BANK_B0(val) BSP_FLD32(val, 0, 4)
|
||||
#define DDRC_ADDRMAP1_BANK_B0_GET(reg) BSP_FLD32GET(reg, 0, 4)
|
||||
#define DDRC_ADDRMAP1_BANK_B0_SET(reg, val) BSP_FLD32SET(reg, val, 0, 4)
|
||||
|
||||
#define DDRC_ADDRMAP2_OFFSET 0x208
|
||||
#define DDRC_ADDRMAP2_COL_B5_BASE 5
|
||||
#define DDRC_ADDRMAP2_COL_B5_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
5 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 6 : 7))
|
||||
#define DDRC_ADDRMAP2_COL_B5_TARGET column
|
||||
#define DDRC_ADDRMAP2_COL_B5_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP2_COL_B5(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP2_COL_B5_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP2_COL_B5_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
#define DDRC_ADDRMAP2_COL_B4_BASE 4
|
||||
#define DDRC_ADDRMAP2_COL_B4_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
4 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 5 : 6))
|
||||
#define DDRC_ADDRMAP2_COL_B4_TARGET column
|
||||
#define DDRC_ADDRMAP2_COL_B4_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP2_COL_B4(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP2_COL_B4_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP2_COL_B4_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP2_COL_B3_BASE 3
|
||||
#define DDRC_ADDRMAP2_COL_B3_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
3 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 4 : 5 ))
|
||||
#define DDRC_ADDRMAP2_COL_B3_TARGET column
|
||||
#define DDRC_ADDRMAP2_COL_B3_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP2_COL_B3(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP2_COL_B3_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP2_COL_B3_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP2_COL_B2_BASE 2
|
||||
#define DDRC_ADDRMAP2_COL_B2_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
2 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 3 : 4))
|
||||
#define DDRC_ADDRMAP2_COL_B2_TARGET column
|
||||
#define DDRC_ADDRMAP2_COL_B2_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP2_COL_B2(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP2_COL_B2_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP2_COL_B2_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP3_OFFSET 0x20c
|
||||
#define DDRC_ADDRMAP3_COL_B9_BASE 9
|
||||
static uint32_t map3_col_b9_target_bit(uint32_t bw, bool lp3)
|
||||
{
|
||||
if (bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) {
|
||||
return 9;
|
||||
}
|
||||
|
||||
if (bw == DDRC_MSTR_DATA_BUS_WIDTH_QUARTER) {
|
||||
return 13;
|
||||
}
|
||||
|
||||
if (lp3) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
return 11;
|
||||
}
|
||||
#define DDRC_ADDRMAP3_COL_B9_TARGET_BIT(bw, lp3) \
|
||||
map3_col_b9_target_bit(bw, lp3)
|
||||
#define DDRC_ADDRMAP3_COL_B9_TARGET column
|
||||
#define DDRC_ADDRMAP3_COL_B9_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP3_COL_B9(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP3_COL_B9_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP3_COL_B9_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
#define DDRC_ADDRMAP3_COL_B8_BASE 8
|
||||
#define DDRC_ADDRMAP3_COL_B8_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
8 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 9 : 11))
|
||||
#define DDRC_ADDRMAP3_COL_B8_TARGET column
|
||||
#define DDRC_ADDRMAP3_COL_B8_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP3_COL_B8(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP3_COL_B8_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP3_COL_B8_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP3_COL_B7_BASE 7
|
||||
#define DDRC_ADDRMAP3_COL_B7_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
7 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 8 : 9))
|
||||
#define DDRC_ADDRMAP3_COL_B7_TARGET column
|
||||
#define DDRC_ADDRMAP3_COL_B7_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP3_COL_B7(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP3_COL_B7_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP3_COL_B7_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP3_COL_B6_BASE 6
|
||||
#define DDRC_ADDRMAP3_COL_B6_TARGET_BIT(bw, lp3) \
|
||||
((bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) ? \
|
||||
6 : ((bw == DDRC_MSTR_DATA_BUS_WIDTH_HALF) ? 7 : 8))
|
||||
#define DDRC_ADDRMAP3_COL_B6_TARGET column
|
||||
#define DDRC_ADDRMAP3_COL_B6_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP3_COL_B6(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP3_COL_B6_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP3_COL_B6_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP4_OFFSET 0x210
|
||||
#define DDRC_ADDRMAP4_COL_B11_BASE 11
|
||||
#define DDRC_ADDRMAP4_COL_B11_TARGET_BIT(bw, lp3) \
|
||||
(lp3?11:13)
|
||||
#define DDRC_ADDRMAP4_COL_B11_TARGET column
|
||||
#define DDRC_ADDRMAP4_COL_B11_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP4_COL_B11(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP4_COL_B11_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP4_COL_B11_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP4_COL_B10_BASE 10
|
||||
static uint32_t map4_col_b10_target_bit(uint32_t bw, bool lp3)
|
||||
{
|
||||
if (bw == DDRC_MSTR_DATA_BUS_WIDTH_FULL) {
|
||||
if (lp3) {
|
||||
return 10;
|
||||
}
|
||||
return 11;
|
||||
}
|
||||
|
||||
/* QUARTER bus mode not valid */
|
||||
if (lp3) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
return 13;
|
||||
}
|
||||
#define DDRC_ADDRMAP4_COL_B10_TARGET_BIT(bw, lp3) \
|
||||
map4_col_b10_target_bit(bw, lp3)
|
||||
#define DDRC_ADDRMAP4_COL_B10_TARGET column
|
||||
#define DDRC_ADDRMAP4_COL_B10_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP4_COL_B10(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP4_COL_B10_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP4_COL_B10_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP5_OFFSET 0x214
|
||||
#define DDRC_ADDRMAP5_ROW_B11_BASE 17
|
||||
#define DDRC_ADDRMAP5_ROW_B11_TARGET_BIT(bw, lp3) 11
|
||||
#define DDRC_ADDRMAP5_ROW_B11_TARGET row
|
||||
#define DDRC_ADDRMAP5_ROW_B11_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP5_ROW_B11(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP5_ROW_B11_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP5_ROW_B11_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
/* This gets mapped into ADDRMAP[9,10,11] */
|
||||
#define DDRC_ADDRMAP5_ROW_B2_10(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP5_ROW_B2_10_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP5_ROW_B2_10_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP5_ROW_B1_BASE 7
|
||||
#define DDRC_ADDRMAP5_ROW_B1_TARGET_BIT(bw, lp3) 1
|
||||
#define DDRC_ADDRMAP5_ROW_B1_TARGET row
|
||||
#define DDRC_ADDRMAP5_ROW_B1_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP5_ROW_B1(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP5_ROW_B1_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP5_ROW_B1_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP5_ROW_B0_BASE 6
|
||||
#define DDRC_ADDRMAP5_ROW_B0_TARGET_BIT(bw, lp3) 0
|
||||
#define DDRC_ADDRMAP5_ROW_B0_TARGET row
|
||||
#define DDRC_ADDRMAP5_ROW_B0_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP5_ROW_B0(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP5_ROW_B0_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP5_ROW_B0_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP6_OFFSET 0x218
|
||||
#define DDRC_ADDRMAP6_LPDDR3_6_12 BSP_BIT(bw, lp3)32(31)
|
||||
#define DDRC_ADDRMAP6_ROW_B15_BASE 21
|
||||
#define DDRC_ADDRMAP6_ROW_B15_TARGET_BIT(bw, lp3) 15
|
||||
#define DDRC_ADDRMAP6_ROW_B15_TARGET row
|
||||
#define DDRC_ADDRMAP6_ROW_B15_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP6_ROW_B15(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP6_ROW_B15_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP6_ROW_B15_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
#define DDRC_ADDRMAP6_ROW_B14_BASE 20
|
||||
#define DDRC_ADDRMAP6_ROW_B14_TARGET_BIT(bw, lp3) 14
|
||||
#define DDRC_ADDRMAP6_ROW_B14_TARGET row
|
||||
#define DDRC_ADDRMAP6_ROW_B14_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP6_ROW_B14(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP6_ROW_B14_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP6_ROW_B14_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP6_ROW_B13_BASE 19
|
||||
#define DDRC_ADDRMAP6_ROW_B13_TARGET_BIT(bw, lp3) 13
|
||||
#define DDRC_ADDRMAP6_ROW_B13_TARGET row
|
||||
#define DDRC_ADDRMAP6_ROW_B13_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP6_ROW_B13(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP6_ROW_B13_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP6_ROW_B13_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP6_ROW_B12_BASE 18
|
||||
#define DDRC_ADDRMAP6_ROW_B12_TARGET_BIT(bw, lp3) 12
|
||||
#define DDRC_ADDRMAP6_ROW_B12_TARGET row
|
||||
#define DDRC_ADDRMAP6_ROW_B12_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP6_ROW_B12(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP6_ROW_B12_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP6_ROW_B12_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP7_OFFSET 0x21c
|
||||
#define DDRC_ADDRMAP7_ROW_B17_BASE 23
|
||||
#define DDRC_ADDRMAP7_ROW_B17_TARGET_BIT(bw, lp3) 17
|
||||
#define DDRC_ADDRMAP7_ROW_B17_TARGET row
|
||||
#define DDRC_ADDRMAP7_ROW_B17_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP7_ROW_B17(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP7_ROW_B17_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP7_ROW_B17_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP7_ROW_B16_BASE 22
|
||||
#define DDRC_ADDRMAP7_ROW_B16_TARGET_BIT(bw, lp3) 16
|
||||
#define DDRC_ADDRMAP7_ROW_B16_TARGET row
|
||||
#define DDRC_ADDRMAP7_ROW_B16_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP7_ROW_B16(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP7_ROW_B16_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP7_ROW_B16_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP8_OFFSET 0x220
|
||||
#define DDRC_ADDRMAP8_BG_B1_BASE 3
|
||||
#define DDRC_ADDRMAP8_BG_B1_TARGET_BIT(bw, lp3) 1
|
||||
#define DDRC_ADDRMAP8_BG_B1_TARGET bank_group
|
||||
#define DDRC_ADDRMAP8_BG_B1_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP8_BG_B1(val) BSP_FLD32(val, 8, 12)
|
||||
#define DDRC_ADDRMAP8_BG_B1_GET(reg) BSP_FLD32GET(reg, 8, 12)
|
||||
#define DDRC_ADDRMAP8_BG_B1_SET(reg, val) BSP_FLD32SET(reg, val, 8, 12)
|
||||
#define DDRC_ADDRMAP8_BG_B0_BASE 2
|
||||
#define DDRC_ADDRMAP8_BG_B0_TARGET_BIT(bw, lp3) 0
|
||||
#define DDRC_ADDRMAP8_BG_B0_TARGET bank_group
|
||||
#define DDRC_ADDRMAP8_BG_B0_SPECIAL DDRC_ADDRMAP_5BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP8_BG_B0(val) BSP_FLD32(val, 0, 4)
|
||||
#define DDRC_ADDRMAP8_BG_B0_GET(reg) BSP_FLD32GET(reg, 0, 4)
|
||||
#define DDRC_ADDRMAP8_BG_B0_SET(reg, val) BSP_FLD32SET(reg, val, 0, 4)
|
||||
|
||||
#define DDRC_ADDRMAP9_OFFSET 0x224
|
||||
#define DDRC_ADDRMAP9_ROW_B5_BASE 11
|
||||
#define DDRC_ADDRMAP9_ROW_B5_TARGET_BIT(bw, lp3) 5
|
||||
#define DDRC_ADDRMAP9_ROW_B5_TARGET row
|
||||
#define DDRC_ADDRMAP9_ROW_B5_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP9_ROW_B5(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP9_ROW_B5_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP9_ROW_B5_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
#define DDRC_ADDRMAP9_ROW_B4_BASE 10
|
||||
#define DDRC_ADDRMAP9_ROW_B4_TARGET_BIT(bw, lp3) 4
|
||||
#define DDRC_ADDRMAP9_ROW_B4_TARGET row
|
||||
#define DDRC_ADDRMAP9_ROW_B4_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP9_ROW_B4(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP9_ROW_B4_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP9_ROW_B4_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP9_ROW_B3_BASE 9
|
||||
#define DDRC_ADDRMAP9_ROW_B3_TARGET_BIT(bw, lp3) 3
|
||||
#define DDRC_ADDRMAP9_ROW_B3_TARGET row
|
||||
#define DDRC_ADDRMAP9_ROW_B3_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP9_ROW_B3(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP9_ROW_B3_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP9_ROW_B3_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP9_ROW_B2_BASE 8
|
||||
#define DDRC_ADDRMAP9_ROW_B2_TARGET_BIT(bw, lp3) 2
|
||||
#define DDRC_ADDRMAP9_ROW_B2_TARGET row
|
||||
#define DDRC_ADDRMAP9_ROW_B2_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP9_ROW_B2(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP9_ROW_B2_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP9_ROW_B2_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP10_OFFSET 0x228
|
||||
#define DDRC_ADDRMAP10_ROW_B9_BASE 15
|
||||
#define DDRC_ADDRMAP10_ROW_B9_TARGET_BIT(bw, lp3) 9
|
||||
#define DDRC_ADDRMAP10_ROW_B9_TARGET row
|
||||
#define DDRC_ADDRMAP10_ROW_B9_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP10_ROW_B9(val) BSP_FLD32(val, 24, 27)
|
||||
#define DDRC_ADDRMAP10_ROW_B9_GET(reg) BSP_FLD32GET(reg, 24, 27)
|
||||
#define DDRC_ADDRMAP10_ROW_B9_SET(reg, val) BSP_FLD32SET(reg, val, 24, 27)
|
||||
#define DDRC_ADDRMAP10_ROW_B8_BASE 14
|
||||
#define DDRC_ADDRMAP10_ROW_B8_TARGET_BIT(bw, lp3) 8
|
||||
#define DDRC_ADDRMAP10_ROW_B8_TARGET row
|
||||
#define DDRC_ADDRMAP10_ROW_B8_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP10_ROW_B8(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ADDRMAP10_ROW_B8_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ADDRMAP10_ROW_B8_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ADDRMAP10_ROW_B7_BASE 13
|
||||
#define DDRC_ADDRMAP10_ROW_B7_TARGET_BIT(bw, lp3) 7
|
||||
#define DDRC_ADDRMAP10_ROW_B7_TARGET row
|
||||
#define DDRC_ADDRMAP10_ROW_B7_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP10_ROW_B7(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ADDRMAP10_ROW_B7_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ADDRMAP10_ROW_B7_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ADDRMAP10_ROW_B6_BASE 12
|
||||
#define DDRC_ADDRMAP10_ROW_B6_TARGET_BIT(bw, lp3) 6
|
||||
#define DDRC_ADDRMAP10_ROW_B6_TARGET row
|
||||
#define DDRC_ADDRMAP10_ROW_B6_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP10_ROW_B6(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP10_ROW_B6_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP10_ROW_B6_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ADDRMAP11_OFFSET 0x22c
|
||||
#define DDRC_ADDRMAP11_ROW_B10_BASE 16
|
||||
#define DDRC_ADDRMAP11_ROW_B10_TARGET_BIT(bw, lp3) 10
|
||||
#define DDRC_ADDRMAP11_ROW_B10_TARGET row
|
||||
#define DDRC_ADDRMAP11_ROW_B10_SPECIAL DDRC_ADDRMAP_4BIT_SPECIAL
|
||||
#define DDRC_ADDRMAP11_ROW_B10(val) BSP_FLD32(val, 0, 3)
|
||||
#define DDRC_ADDRMAP11_ROW_B10_GET(reg) BSP_FLD32GET(reg, 0, 3)
|
||||
#define DDRC_ADDRMAP11_ROW_B10_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
|
||||
|
||||
#define DDRC_ECCPOISONADDR0_OFFSET 0xB8
|
||||
#define DDRC_ECCPOISONADDR0_RANK BSP_BIT32(24)
|
||||
#define DDRC_ECCPOISONADDR0_COL(val) BSP_FLD32(val, 0, 11)
|
||||
#define DDRC_ECCPOISONADDR0_COL_GET(reg) BSP_FLD32GET(reg, 0, 11)
|
||||
#define DDRC_ECCPOISONADDR0_COL_SET(reg, val) BSP_FLD32SET(reg, val, 0, 11)
|
||||
|
||||
#define DDRC_ECCPOISONADDR1_OFFSET 0xBC
|
||||
#define DDRC_ECCPOISONADDR1_BG(val) BSP_FLD32(val, 28, 29)
|
||||
#define DDRC_ECCPOISONADDR1_BG_GET(reg) BSP_FLD32GET(reg, 28, 29)
|
||||
#define DDRC_ECCPOISONADDR1_BG_SET(reg, val) BSP_FLD32SET(reg, val, 28, 29)
|
||||
#define DDRC_ECCPOISONADDR1_BANK(val) BSP_FLD32(val, 24, 26)
|
||||
#define DDRC_ECCPOISONADDR1_BANK_GET(reg) BSP_FLD32GET(reg, 24, 26)
|
||||
#define DDRC_ECCPOISONADDR1_BANK_SET(reg, val) BSP_FLD32SET(reg, val, 24, 26)
|
||||
#define DDRC_ECCPOISONADDR1_ROW(val) BSP_FLD32(val, 0, 17)
|
||||
#define DDRC_ECCPOISONADDR1_ROW_GET(reg) BSP_FLD32GET(reg, 0, 17)
|
||||
#define DDRC_ECCPOISONADDR1_ROW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
|
||||
|
||||
static void homogenize_row(
|
||||
uint32_t *addrmap5,
|
||||
uint32_t *addrmap9,
|
||||
uint32_t *addrmap10,
|
||||
uint32_t *addrmap11
|
||||
)
|
||||
{
|
||||
uint32_t b2_10 = DDRC_ADDRMAP5_ROW_B2_10_GET(*addrmap5);
|
||||
if (b2_10 == DDRC_ADDRMAP_4BIT_SPECIAL) {
|
||||
/* ADDRMAP[9,10,11] already define row[2:10] correctly */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Translate b2_10 to ADDRMAP[9,10,11] to simplify future code */
|
||||
*addrmap9 = DDRC_ADDRMAP9_ROW_B5_SET(*addrmap9, b2_10);
|
||||
*addrmap9 = DDRC_ADDRMAP9_ROW_B4_SET(*addrmap9, b2_10);
|
||||
*addrmap9 = DDRC_ADDRMAP9_ROW_B3_SET(*addrmap9, b2_10);
|
||||
*addrmap9 = DDRC_ADDRMAP9_ROW_B2_SET(*addrmap9, b2_10);
|
||||
|
||||
*addrmap10 = DDRC_ADDRMAP10_ROW_B9_SET(*addrmap10, b2_10);
|
||||
*addrmap10 = DDRC_ADDRMAP10_ROW_B8_SET(*addrmap10, b2_10);
|
||||
*addrmap10 = DDRC_ADDRMAP10_ROW_B7_SET(*addrmap10, b2_10);
|
||||
*addrmap10 = DDRC_ADDRMAP10_ROW_B6_SET(*addrmap10, b2_10);
|
||||
|
||||
*addrmap11 = DDRC_ADDRMAP11_ROW_B10_SET(*addrmap11, b2_10);
|
||||
}
|
||||
|
||||
#define DDRC_READ(offset) (*(uint32_t *)(ddrc_base + offset))
|
||||
|
||||
#define DDRC_MAP_BIT(value, source, target) ((value >> source) & 0x1) << target
|
||||
|
||||
#define DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, BIT_ID, info, addrmap) \
|
||||
({ \
|
||||
uint32_t mapbit = DDRC_ ## BIT_ID ## _GET(addrmap); \
|
||||
uint32_t target_bit = DDRC_ ## BIT_ID ## _TARGET_BIT(bus_width, lpddr3); \
|
||||
if (mapbit != DDRC_ ## BIT_ID ## _SPECIAL) { \
|
||||
mapbit += DDRC_ ## BIT_ID ## _BASE; \
|
||||
/* account for AXI -> HIF shift */ \
|
||||
mapbit += 3; \
|
||||
info->address |= \
|
||||
DDRC_MAP_BIT(info-> DDRC_ ## BIT_ID ## _TARGET, target_bit, mapbit); \
|
||||
} \
|
||||
})
|
||||
|
||||
/*
|
||||
* Steps in mapping an address:
|
||||
* system address -> DDRC -> AXI byte address:
|
||||
* disjoint memory regions are mapped into a monolithic block representing
|
||||
* total available RAM based on configured offsets
|
||||
* AXI byte address -> XPI -> HIF word address:
|
||||
* word-sized shift of 3 bits for 8 byte (word) alignment
|
||||
* HIF word address -> DDRC -> SDRAM address:
|
||||
* addresses are mapped into SDRAM terms by the flexible address mapper using
|
||||
* the ADDRMAP* registers
|
||||
*/
|
||||
static int compose_address(DDR_Error_Info *info)
|
||||
{
|
||||
uint32_t addrmap0 = DDRC_READ(DDRC_ADDRMAP0_OFFSET);
|
||||
uint32_t addrmap1 = DDRC_READ(DDRC_ADDRMAP1_OFFSET);
|
||||
uint32_t addrmap2 = DDRC_READ(DDRC_ADDRMAP2_OFFSET);
|
||||
uint32_t addrmap3 = DDRC_READ(DDRC_ADDRMAP3_OFFSET);
|
||||
uint32_t addrmap4 = DDRC_READ(DDRC_ADDRMAP4_OFFSET);
|
||||
uint32_t addrmap5 = DDRC_READ(DDRC_ADDRMAP5_OFFSET);
|
||||
uint32_t addrmap6 = DDRC_READ(DDRC_ADDRMAP6_OFFSET);
|
||||
uint32_t addrmap7 = DDRC_READ(DDRC_ADDRMAP7_OFFSET);
|
||||
uint32_t addrmap8 = DDRC_READ(DDRC_ADDRMAP8_OFFSET);
|
||||
uint32_t addrmap9 = DDRC_READ(DDRC_ADDRMAP9_OFFSET);
|
||||
uint32_t addrmap10 = DDRC_READ(DDRC_ADDRMAP10_OFFSET);
|
||||
uint32_t addrmap11 = DDRC_READ(DDRC_ADDRMAP11_OFFSET);
|
||||
uint32_t mstr = DDRC_READ(DDRC_MSTR_OFFSET);
|
||||
uint32_t bus_width = DDRC_MSTR_DATA_BUS_WIDTH_GET(mstr);
|
||||
bool lpddr3 = mstr & DDRC_MSTR_LPDDR3;
|
||||
|
||||
homogenize_row(&addrmap5, &addrmap9, &addrmap10, &addrmap11);
|
||||
|
||||
/* Clear items that will be written to */
|
||||
info->address = 0;
|
||||
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP0_RANK_B0, info, addrmap0);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP1_BANK_B2, info, addrmap1);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP1_BANK_B1, info, addrmap1);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP1_BANK_B0, info, addrmap1);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP2_COL_B5, info, addrmap2);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP2_COL_B4, info, addrmap2);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP2_COL_B3, info, addrmap2);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP2_COL_B2, info, addrmap2);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP3_COL_B9, info, addrmap3);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP3_COL_B8, info, addrmap3);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP3_COL_B7, info, addrmap3);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP3_COL_B6, info, addrmap3);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP4_COL_B11, info, addrmap4);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP4_COL_B10, info, addrmap4);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP5_ROW_B11, info, addrmap5);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP5_ROW_B1, info, addrmap5);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP5_ROW_B0, info, addrmap5);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP6_ROW_B15, info, addrmap6);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP6_ROW_B14, info, addrmap6);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP6_ROW_B13, info, addrmap6);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP6_ROW_B12, info, addrmap6);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP7_ROW_B17, info, addrmap7);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP7_ROW_B16, info, addrmap7);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP8_BG_B1, info, addrmap8);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP8_BG_B0, info, addrmap8);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP9_ROW_B5, info, addrmap9);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP9_ROW_B4, info, addrmap9);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP9_ROW_B3, info, addrmap9);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP9_ROW_B2, info, addrmap9);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP10_ROW_B9, info, addrmap10);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP10_ROW_B8, info, addrmap10);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP10_ROW_B7, info, addrmap10);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP10_ROW_B6, info, addrmap10);
|
||||
DDRC_CHECK_AND_UNMAP(bus_width, lpddr3, ADDRMAP11_ROW_B10, info, addrmap11);
|
||||
|
||||
/* Column[0:1] are always statically mapped to HIF[0:1] */
|
||||
info->address |= (info->column & 0x3) << 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uintptr_t ddr_qos_ctrl_base = 0xFD090000;
|
||||
/* DDR QoS CTRL QoS IRQ Status */
|
||||
#define DDR_QIS_OFFSET 0x200
|
||||
#define DDR_QIE_OFFSET 0x208
|
||||
#define DDR_QID_OFFSET 0x20c
|
||||
#define DDR_QI_UNCRERR BSP_BIT32(2)
|
||||
#define DDR_QI_CORERR BSP_BIT32(1)
|
||||
|
||||
#define DDRC_ECCSTAT_OFFSET 0x78
|
||||
#define DDRC_ECCSTAT_UNCR_ERR(val) BSP_FLD32(val, 16, 19)
|
||||
#define DDRC_ECCSTAT_UNCR_ERR_GET(reg) BSP_FLD32GET(reg, 16, 19)
|
||||
#define DDRC_ECCSTAT_UNCR_ERR_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19)
|
||||
#define DDRC_ECCSTAT_CORR_ERR(val) BSP_FLD32(val, 8, 11)
|
||||
#define DDRC_ECCSTAT_CORR_ERR_GET(reg) BSP_FLD32GET(reg, 8, 11)
|
||||
#define DDRC_ECCSTAT_CORR_ERR_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11)
|
||||
#define DDRC_ECCSTAT_CORR_BIT(val) BSP_FLD32(val, 0, 6)
|
||||
#define DDRC_ECCSTAT_CORR_BIT_GET(reg) BSP_FLD32GET(reg, 0, 6)
|
||||
#define DDRC_ECCSTAT_CORR_BIT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 6)
|
||||
|
||||
/* Correctable and uncorrectable error address registers share encodings */
|
||||
#define DDRC_ECCCADDR0_OFFSET 0x84
|
||||
#define DDRC_ECCUADDR0_OFFSET 0xA4
|
||||
#define DDRC_ECCXADDR0_RANK BSP_BIT32(24)
|
||||
#define DDRC_ECCXADDR0_ROW(val) BSP_FLD32(val, 0, 17)
|
||||
#define DDRC_ECCXADDR0_ROW_GET(reg) BSP_FLD32GET(reg, 0, 17)
|
||||
#define DDRC_ECCXADDR0_ROW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
|
||||
|
||||
#define DDRC_ECCCADDR1_OFFSET 0x88
|
||||
#define DDRC_ECCUADDR1_OFFSET 0xA8
|
||||
#define DDRC_ECCXADDR1_BG(val) BSP_FLD32(val, 24, 25)
|
||||
#define DDRC_ECCXADDR1_BG_GET(reg) BSP_FLD32GET(reg, 24, 25)
|
||||
#define DDRC_ECCXADDR1_BG_SET(reg, val) BSP_FLD32SET(reg, val, 24, 25)
|
||||
#define DDRC_ECCXADDR1_BANK(val) BSP_FLD32(val, 16, 18)
|
||||
#define DDRC_ECCXADDR1_BANK_GET(reg) BSP_FLD32GET(reg, 16, 18)
|
||||
#define DDRC_ECCXADDR1_BANK_SET(reg, val) BSP_FLD32SET(reg, val, 16, 18)
|
||||
#define DDRC_ECCXADDR1_COL(val) BSP_FLD32(val, 0, 11)
|
||||
#define DDRC_ECCXADDR1_COL_GET(reg) BSP_FLD32GET(reg, 0, 11)
|
||||
#define DDRC_ECCXADDR1_COL_SET(reg, val) BSP_FLD32SET(reg, val, 0, 11)
|
||||
|
||||
static void extract_ddr_info(
|
||||
DDR_Error_Info *info,
|
||||
uint32_t addr0_val,
|
||||
uint32_t addr1_val
|
||||
)
|
||||
{
|
||||
info->rank = (addr0_val & DDRC_ECCXADDR0_RANK) >> 24;
|
||||
info->bank_group = DDRC_ECCXADDR1_BG_GET(addr1_val);
|
||||
info->bank = DDRC_ECCXADDR1_BANK_GET(addr1_val);
|
||||
info->row = DDRC_ECCXADDR0_ROW_GET(addr0_val);
|
||||
info->column = DDRC_ECCXADDR1_COL_GET(addr1_val);
|
||||
compose_address(info);
|
||||
}
|
||||
|
||||
|
||||
static void ddr_handler(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
volatile uint32_t *qis = (uint32_t *)(ddr_qos_ctrl_base + DDR_QIS_OFFSET);
|
||||
uint32_t qis_value = *qis;
|
||||
DDR_Error_Info info;
|
||||
volatile uint32_t *addr0 = (uint32_t *)(ddrc_base + DDRC_ECCCADDR0_OFFSET);
|
||||
volatile uint32_t *addr1 = (uint32_t *)(ddrc_base + DDRC_ECCCADDR1_OFFSET);
|
||||
|
||||
/* specific data is captured in DDRC.ECCSTAT[corrected_bit_num] */
|
||||
if ((qis_value & DDR_QI_CORERR) != 0) {
|
||||
/* Clear status flag */
|
||||
*qis = DDR_QI_CORERR;
|
||||
|
||||
info.type = DDR_CORRECTABLE;
|
||||
extract_ddr_info(&info, *addr0, *addr1);
|
||||
zynqmp_invoke_ecc_handler(DDR_RAM, &info);
|
||||
}
|
||||
if ((qis_value & DDR_QI_UNCRERR) != 0) {
|
||||
/* Clear status flag */
|
||||
*qis = DDR_QI_UNCRERR;
|
||||
|
||||
info.type = DDR_UNCORRECTABLE;
|
||||
extract_ddr_info(&info, *addr0, *addr1);
|
||||
zynqmp_invoke_ecc_handler(DDR_RAM, &info);
|
||||
}
|
||||
}
|
||||
|
||||
static rtems_interrupt_entry zynqmp_ddr_ecc_entry;
|
||||
|
||||
rtems_status_code zynqmp_configure_ddr_ecc( void )
|
||||
{
|
||||
volatile uint32_t *qie = (uint32_t *)(ddr_qos_ctrl_base + DDR_QIE_OFFSET);
|
||||
rtems_status_code sc;
|
||||
|
||||
rtems_interrupt_entry_initialize(
|
||||
&zynqmp_ddr_ecc_entry,
|
||||
ddr_handler,
|
||||
NULL,
|
||||
"DDR RAM ECC"
|
||||
);
|
||||
|
||||
sc = rtems_interrupt_entry_install(
|
||||
ZYNQMP_IRQ_DDR,
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
&zynqmp_ddr_ecc_entry
|
||||
);
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return sc;
|
||||
}
|
||||
|
||||
/* enable interrupts for ECC in QOS_IRQ_ENABLE */
|
||||
*qie |= DDR_QI_UNCRERR | DDR_QI_CORERR;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
#if RUNNING_FROM_OCM_IS_NOT_CURRENTLY_POSSIBLE
|
||||
/*
|
||||
* Injecting DDR ECC faults requires RTEMS to run from OCM since the DDR will be
|
||||
* partially disabled and re-enabled during the process. RTEMS is too large to
|
||||
* run out of OCM in its current configuration and doing so would require
|
||||
* operation without MMU along with other changes to reduce the memory footprint
|
||||
* to below 256KB. It must be the whole RTEMS executable since stack accesses
|
||||
* would also present a problem.
|
||||
*/
|
||||
|
||||
#define DDRC_PRINT_MAP(BIT_ID, addrmap) \
|
||||
({ \
|
||||
uint32_t mapbit = DDRC_ ## BIT_ID ## _GET(addrmap); \
|
||||
if (mapbit != DDRC_ ## BIT_ID ## _SPECIAL) { \
|
||||
mapbit += DDRC_ ## BIT_ID ## _BASE; \
|
||||
} \
|
||||
})
|
||||
|
||||
static void print_addr_maps( void )
|
||||
{
|
||||
uint32_t addrmap0 = DDRC_READ(DDRC_ADDRMAP0_OFFSET);
|
||||
uint32_t addrmap1 = DDRC_READ(DDRC_ADDRMAP1_OFFSET);
|
||||
uint32_t addrmap2 = DDRC_READ(DDRC_ADDRMAP2_OFFSET);
|
||||
uint32_t addrmap3 = DDRC_READ(DDRC_ADDRMAP3_OFFSET);
|
||||
uint32_t addrmap4 = DDRC_READ(DDRC_ADDRMAP4_OFFSET);
|
||||
uint32_t addrmap5 = DDRC_READ(DDRC_ADDRMAP5_OFFSET);
|
||||
uint32_t addrmap6 = DDRC_READ(DDRC_ADDRMAP6_OFFSET);
|
||||
uint32_t addrmap7 = DDRC_READ(DDRC_ADDRMAP7_OFFSET);
|
||||
uint32_t addrmap8 = DDRC_READ(DDRC_ADDRMAP8_OFFSET);
|
||||
uint32_t addrmap9 = DDRC_READ(DDRC_ADDRMAP9_OFFSET);
|
||||
uint32_t addrmap10 = DDRC_READ(DDRC_ADDRMAP10_OFFSET);
|
||||
uint32_t addrmap11 = DDRC_READ(DDRC_ADDRMAP11_OFFSET);
|
||||
|
||||
homogenize_row(&addrmap5, &addrmap9, &addrmap10, &addrmap11);
|
||||
|
||||
DDRC_PRINT_MAP(ADDRMAP0_RANK_B0, addrmap0);
|
||||
DDRC_PRINT_MAP(ADDRMAP1_BANK_B2, addrmap1);
|
||||
DDRC_PRINT_MAP(ADDRMAP1_BANK_B1, addrmap1);
|
||||
DDRC_PRINT_MAP(ADDRMAP1_BANK_B0, addrmap1);
|
||||
DDRC_PRINT_MAP(ADDRMAP2_COL_B5, addrmap2);
|
||||
DDRC_PRINT_MAP(ADDRMAP2_COL_B4, addrmap2);
|
||||
DDRC_PRINT_MAP(ADDRMAP2_COL_B3, addrmap2);
|
||||
DDRC_PRINT_MAP(ADDRMAP2_COL_B2, addrmap2);
|
||||
DDRC_PRINT_MAP(ADDRMAP3_COL_B9, addrmap3);
|
||||
DDRC_PRINT_MAP(ADDRMAP3_COL_B8, addrmap3);
|
||||
DDRC_PRINT_MAP(ADDRMAP3_COL_B7, addrmap3);
|
||||
DDRC_PRINT_MAP(ADDRMAP3_COL_B6, addrmap3);
|
||||
DDRC_PRINT_MAP(ADDRMAP4_COL_B11, addrmap4);
|
||||
DDRC_PRINT_MAP(ADDRMAP4_COL_B10, addrmap4);
|
||||
DDRC_PRINT_MAP(ADDRMAP5_ROW_B11, addrmap5);
|
||||
DDRC_PRINT_MAP(ADDRMAP5_ROW_B1, addrmap5);
|
||||
DDRC_PRINT_MAP(ADDRMAP5_ROW_B0, addrmap5);
|
||||
DDRC_PRINT_MAP(ADDRMAP6_ROW_B15, addrmap6);
|
||||
DDRC_PRINT_MAP(ADDRMAP6_ROW_B14, addrmap6);
|
||||
DDRC_PRINT_MAP(ADDRMAP6_ROW_B13, addrmap6);
|
||||
DDRC_PRINT_MAP(ADDRMAP6_ROW_B12, addrmap6);
|
||||
DDRC_PRINT_MAP(ADDRMAP7_ROW_B17, addrmap7);
|
||||
DDRC_PRINT_MAP(ADDRMAP7_ROW_B16, addrmap7);
|
||||
DDRC_PRINT_MAP(ADDRMAP8_BG_B1, addrmap8);
|
||||
DDRC_PRINT_MAP(ADDRMAP8_BG_B0, addrmap8);
|
||||
DDRC_PRINT_MAP(ADDRMAP9_ROW_B5, addrmap9);
|
||||
DDRC_PRINT_MAP(ADDRMAP9_ROW_B4, addrmap9);
|
||||
DDRC_PRINT_MAP(ADDRMAP9_ROW_B3, addrmap9);
|
||||
DDRC_PRINT_MAP(ADDRMAP9_ROW_B2, addrmap9);
|
||||
DDRC_PRINT_MAP(ADDRMAP10_ROW_B9, addrmap10);
|
||||
DDRC_PRINT_MAP(ADDRMAP10_ROW_B8, addrmap10);
|
||||
DDRC_PRINT_MAP(ADDRMAP10_ROW_B7, addrmap10);
|
||||
DDRC_PRINT_MAP(ADDRMAP10_ROW_B6, addrmap10);
|
||||
DDRC_PRINT_MAP(ADDRMAP11_ROW_B10, addrmap11);
|
||||
}
|
||||
|
||||
/* Ignore the bitmap if it's the flag value, otherwise map it */
|
||||
#define DDRC_CHECK_AND_MAP(bus_width, lpddr3, BIT_ID, info, addrmap) \
|
||||
({ \
|
||||
uint32_t mapbit = DDRC_ ## BIT_ID ## _GET(addrmap); \
|
||||
uint32_t target_bit = DDRC_ ## BIT_ID ## _TARGET_BIT(bus_width, lpddr3); \
|
||||
if (mapbit != DDRC_ ## BIT_ID ## _SPECIAL) { \
|
||||
mapbit += DDRC_ ## BIT_ID ## _BASE; \
|
||||
/* account for AXI -> HIF shift */ \
|
||||
mapbit += 3; \
|
||||
info-> DDRC_ ## BIT_ID ## _TARGET |= \
|
||||
DDRC_MAP_BIT(info->address, mapbit, target_bit); \
|
||||
} \
|
||||
})
|
||||
|
||||
static int decompose_address(DDR_Error_Info *info)
|
||||
{
|
||||
uint32_t addrmap0 = DDRC_READ(DDRC_ADDRMAP0_OFFSET);
|
||||
uint32_t addrmap1 = DDRC_READ(DDRC_ADDRMAP1_OFFSET);
|
||||
uint32_t addrmap2 = DDRC_READ(DDRC_ADDRMAP2_OFFSET);
|
||||
uint32_t addrmap3 = DDRC_READ(DDRC_ADDRMAP3_OFFSET);
|
||||
uint32_t addrmap4 = DDRC_READ(DDRC_ADDRMAP4_OFFSET);
|
||||
uint32_t addrmap5 = DDRC_READ(DDRC_ADDRMAP5_OFFSET);
|
||||
uint32_t addrmap6 = DDRC_READ(DDRC_ADDRMAP6_OFFSET);
|
||||
uint32_t addrmap7 = DDRC_READ(DDRC_ADDRMAP7_OFFSET);
|
||||
uint32_t addrmap8 = DDRC_READ(DDRC_ADDRMAP8_OFFSET);
|
||||
uint32_t addrmap9 = DDRC_READ(DDRC_ADDRMAP9_OFFSET);
|
||||
uint32_t addrmap10 = DDRC_READ(DDRC_ADDRMAP10_OFFSET);
|
||||
uint32_t addrmap11 = DDRC_READ(DDRC_ADDRMAP11_OFFSET);
|
||||
uint32_t mstr = DDRC_READ(DDRC_MSTR_OFFSET);
|
||||
uint32_t bus_width = DDRC_MSTR_DATA_BUS_WIDTH_GET(mstr);
|
||||
bool lpddr3 = mstr & DDRC_MSTR_LPDDR3;
|
||||
|
||||
homogenize_row(&addrmap5, &addrmap9, &addrmap10, &addrmap11);
|
||||
|
||||
/* Clear items that will be written to */
|
||||
info->rank = 0;
|
||||
info->bank_group = 0;
|
||||
info->bank = 0;
|
||||
info->row = 0;
|
||||
info->column = 0;
|
||||
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP0_RANK_B0, info, addrmap0);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP1_BANK_B2, info, addrmap1);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP1_BANK_B1, info, addrmap1);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP1_BANK_B0, info, addrmap1);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP2_COL_B5, info, addrmap2);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP2_COL_B4, info, addrmap2);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP2_COL_B3, info, addrmap2);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP2_COL_B2, info, addrmap2);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP3_COL_B9, info, addrmap3);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP3_COL_B8, info, addrmap3);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP3_COL_B7, info, addrmap3);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP3_COL_B6, info, addrmap3);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP4_COL_B11, info, addrmap4);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP4_COL_B10, info, addrmap4);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP5_ROW_B11, info, addrmap5);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP5_ROW_B1, info, addrmap5);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP5_ROW_B0, info, addrmap5);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP6_ROW_B15, info, addrmap6);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP6_ROW_B14, info, addrmap6);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP6_ROW_B13, info, addrmap6);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP6_ROW_B12, info, addrmap6);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP7_ROW_B17, info, addrmap7);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP7_ROW_B16, info, addrmap7);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP8_BG_B1, info, addrmap8);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP8_BG_B0, info, addrmap8);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP9_ROW_B5, info, addrmap9);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP9_ROW_B4, info, addrmap9);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP9_ROW_B3, info, addrmap9);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP9_ROW_B2, info, addrmap9);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP10_ROW_B9, info, addrmap10);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP10_ROW_B8, info, addrmap10);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP10_ROW_B7, info, addrmap10);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP10_ROW_B6, info, addrmap10);
|
||||
DDRC_CHECK_AND_MAP(bus_width, lpddr3, ADDRMAP11_ROW_B10, info, addrmap11);
|
||||
|
||||
/* Column[0:1] are always statically mapped to HIF[0:1] */
|
||||
info->column |= (info->address >> 3) & 0x3;
|
||||
|
||||
/* select target address */
|
||||
uint32_t paddr0_val = DDRC_ECCPOISONADDR0_COL_SET(0, info->column);
|
||||
if (info->rank) {
|
||||
paddr0_val |= DDRC_ECCPOISONADDR0_RANK;
|
||||
}
|
||||
|
||||
uint32_t paddr1_val = DDRC_ECCPOISONADDR1_BG_SET(0, info->bank_group);
|
||||
paddr1_val = DDRC_ECCPOISONADDR1_BANK_SET(paddr1_val, info->bank);
|
||||
paddr1_val = DDRC_ECCPOISONADDR1_ROW_SET(paddr1_val, info->row);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DDR Controller (DDRC) ECC Config Register 1 */
|
||||
#define DDRC_ECCCFG1_OFFSET 0x74
|
||||
#define DDRC_ECCCFG1_POISON_SINGLE BSP_BIT32(1)
|
||||
#define DDRC_ECCCFG1_POISON_EN BSP_BIT32(0)
|
||||
|
||||
#define DDRC_SWCTL_OFFSET 0x74
|
||||
#define DDRC_SWSTAT_OFFSET 0x324
|
||||
|
||||
#define DDRC_DBGCAM_OFFSET 0x308
|
||||
#define DDRC_DBGCAM_WR_DATA_PIPELINE_EMPTY BSP_BIT32(28)
|
||||
#define DDRC_DBGCAM_RD_DATA_PIPELINE_EMPTY BSP_BIT32(27)
|
||||
#define DDRC_DBGCAM_DBG_WR_Q_EMPTY BSP_BIT32(26)
|
||||
#define DDRC_DBGCAM_DBG_RD_Q_EMPTY BSP_BIT32(25)
|
||||
|
||||
#define DDRC_DBG1_OFFSET 0x304
|
||||
#define DDRC_DBG1_DIS_DQ BSP_BIT32(0)
|
||||
|
||||
static void set_ecccfg1(volatile uint32_t *ecccfg1, uint32_t ecccfg1_val)
|
||||
{
|
||||
uint32_t dbgcam_mask = DDRC_DBGCAM_WR_DATA_PIPELINE_EMPTY |
|
||||
DDRC_DBGCAM_RD_DATA_PIPELINE_EMPTY | DDRC_DBGCAM_DBG_WR_Q_EMPTY |
|
||||
DDRC_DBGCAM_DBG_RD_Q_EMPTY;
|
||||
volatile uint32_t *dbgcam = (uint32_t *)(ddrc_base + DDRC_DBGCAM_OFFSET);
|
||||
volatile uint32_t *dbg1 = (uint32_t *)(ddrc_base + DDRC_DBG1_OFFSET);
|
||||
|
||||
/* disable dequeueing */
|
||||
*dbg1 |= DDRC_DBG1_DIS_DQ;
|
||||
/* poll for DDRC empty state */
|
||||
while((*dbgcam & dbgcam_mask) != dbgcam_mask);
|
||||
*ecccfg1 = ecccfg1_val;
|
||||
/* enable dequeueing */
|
||||
*dbg1 &= ~DDRC_DBG1_DIS_DQ;
|
||||
}
|
||||
|
||||
void zynqmp_ddr_inject_fault( bool correctable )
|
||||
{
|
||||
uint64_t poison_var;
|
||||
uint64_t read_var;
|
||||
volatile uint64_t *poison_addr = &poison_var;
|
||||
volatile uint32_t *ecccfg1 = (uint32_t *)(ddrc_base + DDRC_ECCCFG1_OFFSET);
|
||||
uint32_t ecccfg1_val = 0;
|
||||
volatile uint32_t *swctl = (uint32_t *)(ddrc_base + DDRC_SWCTL_OFFSET);
|
||||
volatile uint32_t *swstat = (uint32_t *)(ddrc_base + DDRC_SWSTAT_OFFSET);
|
||||
volatile uint32_t *poisonaddr0;
|
||||
uint32_t paddr0_val;
|
||||
volatile uint32_t *poisonaddr1;
|
||||
uint32_t paddr1_val;
|
||||
DDR_Error_Info info;
|
||||
poisonaddr0 = (uint32_t *)(ddrc_base + DDRC_ECCPOISONADDR0_OFFSET);
|
||||
poisonaddr1 = (uint32_t *)(ddrc_base + DDRC_ECCPOISONADDR1_OFFSET);
|
||||
|
||||
info.address = (uint64_t)(uintptr_t)poison_addr;
|
||||
/* convert address to SDRAM address components */
|
||||
decompose_address(&info);
|
||||
|
||||
/* select correctable/uncorrectable */
|
||||
ecccfg1_val &= ~DDRC_ECCCFG1_POISON_SINGLE;
|
||||
if (correctable) {
|
||||
ecccfg1_val |= DDRC_ECCCFG1_POISON_SINGLE;
|
||||
}
|
||||
|
||||
/* enable poisoning */
|
||||
ecccfg1_val |= DDRC_ECCCFG1_POISON_EN;
|
||||
|
||||
uint32_t isr_cookie;
|
||||
rtems_interrupt_local_disable(isr_cookie);
|
||||
/* swctl must be unset to allow modification of ecccfg1 */
|
||||
*swctl = 0;
|
||||
set_ecccfg1(ecccfg1, ecccfg1_val);
|
||||
*swctl = 1;
|
||||
rtems_interrupt_local_enable(isr_cookie);
|
||||
|
||||
/* Wait for swctl propagation to swstat */
|
||||
while ((*swstat & 0x1) == 0);
|
||||
|
||||
/* select target address */
|
||||
paddr0_val = DDRC_ECCPOISONADDR0_COL_SET(0, info.column);
|
||||
if (info.rank) {
|
||||
paddr0_val |= DDRC_ECCPOISONADDR0_RANK;
|
||||
}
|
||||
*poisonaddr0 = paddr0_val;
|
||||
|
||||
paddr1_val = DDRC_ECCPOISONADDR1_BG_SET(0, info.bank_group);
|
||||
paddr1_val = DDRC_ECCPOISONADDR1_BANK_SET(paddr1_val, info.bank);
|
||||
paddr1_val = DDRC_ECCPOISONADDR1_ROW_SET(paddr1_val, info.row);
|
||||
*poisonaddr1 = paddr1_val;
|
||||
|
||||
/* write to poison address */
|
||||
*poison_addr = 0x5555555555555555UL;
|
||||
|
||||
/* flush cache to force write */
|
||||
rtems_cache_flush_multiple_data_lines(poison_addr, sizeof(*poison_addr));
|
||||
|
||||
/* invalidate cache to force read */
|
||||
rtems_cache_invalidate_multiple_data_lines(poison_addr, sizeof(*poison_addr));
|
||||
|
||||
/* Force a data sync barrier */
|
||||
_AARCH64_Data_synchronization_barrier();
|
||||
|
||||
/* read from poison address to generate event */
|
||||
read_var = *poison_addr;
|
||||
read_var++;
|
||||
|
||||
volatile uint32_t *qis = (uint32_t *)(ddr_qos_ctrl_base + DDR_QIS_OFFSET);
|
||||
|
||||
/* disable poisoning */
|
||||
*swctl = 0;
|
||||
*ecccfg1 = 0;
|
||||
*swctl = 1;
|
||||
}
|
||||
#endif
|
||||
300
bsps/aarch64/xilinx-zynqmp/ecc/ocm.c
Normal file
300
bsps/aarch64/xilinx-zynqmp/ecc/ocm.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of OCM ECC support.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/utility.h>
|
||||
#include <libcpu/mmu-vmsav8-64.h>
|
||||
|
||||
static uintptr_t ocm_base = 0xFF960000;
|
||||
|
||||
/* ECC Control */
|
||||
#define OCM_ECC_CTRL 0x14
|
||||
/* 0 -> single error, 1 -> continuous errors */
|
||||
#define OCM_ECC_CTRL_FI_MODE BSP_BIT32(2)
|
||||
/* When bit is set, detection occurs without correction */
|
||||
#define OCM_ECC_CTRL_DET_ONLY BSP_BIT32(1)
|
||||
/* Enable ECC, should only be modified at system boot */
|
||||
#define OCM_ECC_CTRL_ECC_ON_OFF BSP_BIT32(0)
|
||||
|
||||
/* Interrupt Enable */
|
||||
#define OCM_IE 0xc
|
||||
#define OCM_IE_UE_RMW BSP_BIT32(10)
|
||||
#define OCM_IE_UE BSP_BIT32(7)
|
||||
#define OCM_IE_CE BSP_BIT32(6)
|
||||
|
||||
/* Error Response Control */
|
||||
#define OCM_ERR_CTRL 0x0
|
||||
#define OCM_ERR_CTRL_UE_RES BSP_BIT32(3)
|
||||
|
||||
/*
|
||||
* Fault Injection Data, four registers comprising 16 bytes of a data word
|
||||
*
|
||||
* Bits set to 1 toggle the corresponding bits of the next written word during a
|
||||
* fault injection.
|
||||
*/
|
||||
#define OCM_FI_D0 0x4c
|
||||
#define OCM_FI_D1 0x50
|
||||
#define OCM_FI_D2 0x54
|
||||
#define OCM_FI_D3 0x58
|
||||
|
||||
/* Fault Injection Syndrome */
|
||||
#define OCM_FI_SY 0x5c
|
||||
#define OCM_FI_SY_DATA(val) BSP_FLD32(val, 0, 15)
|
||||
#define OCM_FI_SY_DATA_GET(reg) BSP_FLD32GET(reg, 0, 15)
|
||||
#define OCM_FI_SY_DATA_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
|
||||
|
||||
/* Fault Injection Counter */
|
||||
#define OCM_FI_CNTR 0x74
|
||||
#define OCM_FI_CNTR_COUNT(val) BSP_FLD32(val, 0, 23)
|
||||
#define OCM_FI_CNTR_COUNT_GET(reg) BSP_FLD32GET(reg, 0, 23)
|
||||
#define OCM_FI_CNTR_COUNT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 23)
|
||||
|
||||
/* Interrupt Status */
|
||||
#define OCM_IS 0x4
|
||||
#define OCM_IS_UE_RMW BSP_BIT32(10)
|
||||
#define OCM_IS_UE BSP_BIT32(7)
|
||||
#define OCM_IS_CE BSP_BIT32(6)
|
||||
|
||||
/* Interrupt Mask */
|
||||
#define OCM_IM 0x8
|
||||
#define OCM_IM_UE_RMW BSP_BIT32(10)
|
||||
#define OCM_IM_UE BSP_BIT32(7)
|
||||
#define OCM_IM_CE BSP_BIT32(6)
|
||||
|
||||
void zynqmp_ocm_inject_fault( void )
|
||||
{
|
||||
volatile uint32_t *fi_d0 = (uint32_t*)(ocm_base + OCM_FI_D0);
|
||||
volatile uint32_t *fi_cnt = (uint32_t*)(ocm_base + OCM_FI_CNTR);
|
||||
volatile uint64_t *ocm_top = (uint64_t*)0xFFFFFFF0U;
|
||||
volatile uint32_t *ecc_ctrl = (uint32_t*)(ocm_base + OCM_ECC_CTRL);
|
||||
uint64_t ocm_tmp = *ocm_top;
|
||||
|
||||
/* Configure OCM to throw constant errors */
|
||||
*ecc_ctrl |= OCM_ECC_CTRL_FI_MODE;
|
||||
|
||||
/* Inject a single bit error */
|
||||
*fi_d0 = 1;
|
||||
|
||||
/* Configure the clock count after which errors will begin */
|
||||
*fi_cnt = 0;
|
||||
|
||||
/* Insert a memory barrier to ensure that fault injection is active */
|
||||
_AARCH64_Data_synchronization_barrier();
|
||||
|
||||
/* trigger fault with a write of data that was already at the given address */
|
||||
*ocm_top = 0;
|
||||
|
||||
/* Insert a memory barrier to prevent optimization */
|
||||
_AARCH64_Data_synchronization_barrier();
|
||||
|
||||
/* Perform read to force reporting of the error */
|
||||
*ocm_top;
|
||||
|
||||
/* Disable constant fault mode */
|
||||
*ecc_ctrl &= ~(OCM_ECC_CTRL_FI_MODE);
|
||||
|
||||
/* Insert a memory barrier to ensure the mode has changed */
|
||||
_AARCH64_Data_synchronization_barrier();
|
||||
|
||||
/* Reset to original value now that constant errors are disabled */
|
||||
*ocm_top = ocm_tmp;
|
||||
}
|
||||
|
||||
/* Correctable Error First Failing Address */
|
||||
#define OCM_CE_FFA 0x1c
|
||||
#define OCM_CE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
|
||||
#define OCM_CE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
|
||||
#define OCM_CE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
|
||||
|
||||
/* Correctable Error First Failing Data, four registers comprising 16 bytes */
|
||||
#define OCM_CE_FFD0 0x20
|
||||
#define OCM_CE_FFD1 0x24
|
||||
#define OCM_CE_FFD2 0x28
|
||||
#define OCM_CE_FFD3 0x2c
|
||||
|
||||
/* Correctable Error First Failing ECC */
|
||||
#define OCM_CE_FFE 0x1c
|
||||
#define OCM_CE_FFE_SYNDROME(val) BSP_FLD32(val, 0, 15)
|
||||
#define OCM_CE_FFE_SYNDROME_GET(reg) BSP_FLD32GET(reg, 0, 15)
|
||||
#define OCM_CE_FFE_SYNDROME_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
|
||||
|
||||
/* Uncorrectable Error First Failing Address */
|
||||
#define OCM_UE_FFA 0x34
|
||||
#define OCM_UE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
|
||||
#define OCM_UE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
|
||||
#define OCM_UE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
|
||||
|
||||
/* Uncorrectable Error First Failing Data, four registers comprising 16 bytes */
|
||||
#define OCM_UE_FFD0 0x38
|
||||
#define OCM_UE_FFD1 0x3c
|
||||
#define OCM_UE_FFD2 0x40
|
||||
#define OCM_UE_FFD3 0x44
|
||||
|
||||
/* Uncorrectable Error First Failing ECC */
|
||||
#define OCM_UE_FFE 0x48
|
||||
#define OCM_UE_FFE_SYNDROME(val) BSP_FLD32(val, 0, 15)
|
||||
#define OCM_UE_FFE_SYNDROME_GET(reg) BSP_FLD32GET(reg, 0, 15)
|
||||
#define OCM_UE_FFE_SYNDROME_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15)
|
||||
|
||||
/* Read/Modify/Write Uncorrectable Error First Failing Address */
|
||||
#define OCM_RMW_UE_FFA 0x70
|
||||
#define OCM_RMW_UE_FFA_ADDR(val) BSP_FLD32(val, 0, 17)
|
||||
#define OCM_RMW_UE_FFA_ADDR_GET(reg) BSP_FLD32GET(reg, 0, 17)
|
||||
#define OCM_RMW_UE_FFA_ADDR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 17)
|
||||
|
||||
static void ocm_handle_rmw( void )
|
||||
{
|
||||
volatile uint32_t *rmw_ffa = (uint32_t*)(ocm_base + OCM_RMW_UE_FFA);
|
||||
OCM_Error_Info info;
|
||||
|
||||
info.type = OCM_UNCORRECTABLE_RMW;
|
||||
info.offset = OCM_RMW_UE_FFA_ADDR_GET(*rmw_ffa);
|
||||
zynqmp_invoke_ecc_handler(OCM_RAM, &info);
|
||||
}
|
||||
|
||||
static void ocm_handle_ce( void )
|
||||
{
|
||||
volatile uint32_t *ce_ffa = (uint32_t*)(ocm_base + OCM_CE_FFA);
|
||||
volatile uint32_t *ce_ffe = (uint32_t*)(ocm_base + OCM_CE_FFA);
|
||||
volatile uint32_t *ce_ffd0 = (uint32_t*)(ocm_base + OCM_CE_FFD0);
|
||||
volatile uint32_t *ce_ffd1 = (uint32_t*)(ocm_base + OCM_CE_FFD1);
|
||||
volatile uint32_t *ce_ffd2 = (uint32_t*)(ocm_base + OCM_CE_FFD2);
|
||||
volatile uint32_t *ce_ffd3 = (uint32_t*)(ocm_base + OCM_CE_FFD3);
|
||||
OCM_Error_Info info;
|
||||
|
||||
info.type = OCM_CORRECTABLE;
|
||||
info.offset = OCM_CE_FFA_ADDR_GET(*ce_ffa);
|
||||
info.data0 = *ce_ffd0;
|
||||
info.data1 = *ce_ffd1;
|
||||
info.data2 = *ce_ffd2;
|
||||
info.data3 = *ce_ffd3;
|
||||
info.syndrome = OCM_CE_FFE_SYNDROME_GET(*ce_ffe);
|
||||
zynqmp_invoke_ecc_handler(OCM_RAM, &info);
|
||||
}
|
||||
|
||||
static void ocm_handle_ue( void )
|
||||
{
|
||||
volatile uint32_t *ue_ffa = (uint32_t*)(ocm_base + OCM_UE_FFA);
|
||||
volatile uint32_t *ue_ffe = (uint32_t*)(ocm_base + OCM_UE_FFA);
|
||||
volatile uint32_t *ue_ffd0 = (uint32_t*)(ocm_base + OCM_UE_FFD0);
|
||||
volatile uint32_t *ue_ffd1 = (uint32_t*)(ocm_base + OCM_UE_FFD1);
|
||||
volatile uint32_t *ue_ffd2 = (uint32_t*)(ocm_base + OCM_UE_FFD2);
|
||||
volatile uint32_t *ue_ffd3 = (uint32_t*)(ocm_base + OCM_UE_FFD3);
|
||||
OCM_Error_Info info;
|
||||
|
||||
info.type = OCM_UNCORRECTABLE;
|
||||
info.offset = OCM_UE_FFA_ADDR_GET(*ue_ffa);
|
||||
info.data0 = *ue_ffd0;
|
||||
info.data1 = *ue_ffd1;
|
||||
info.data2 = *ue_ffd2;
|
||||
info.data3 = *ue_ffd3;
|
||||
info.syndrome = OCM_UE_FFE_SYNDROME_GET(*ue_ffe);
|
||||
zynqmp_invoke_ecc_handler(OCM_RAM, &info);
|
||||
}
|
||||
|
||||
static void ocm_handler(void *arg)
|
||||
{
|
||||
volatile uint32_t *ocm_is = (uint32_t*)(ocm_base + OCM_IS);
|
||||
uint32_t ocm_is_value = *ocm_is;
|
||||
(void) arg;
|
||||
|
||||
/* Check and clear each error type after handling */
|
||||
if ((ocm_is_value & OCM_IS_UE_RMW) != 0) {
|
||||
ocm_handle_rmw();
|
||||
*ocm_is = OCM_IS_UE_RMW;
|
||||
}
|
||||
|
||||
if ((ocm_is_value & OCM_IS_CE) != 0) {
|
||||
ocm_handle_ce();
|
||||
*ocm_is = OCM_IS_CE;
|
||||
}
|
||||
|
||||
if ((ocm_is_value & OCM_IS_UE) != 0) {
|
||||
ocm_handle_ue();
|
||||
*ocm_is = OCM_IS_UE;
|
||||
}
|
||||
}
|
||||
|
||||
static rtems_interrupt_entry zynqmp_ocm_ecc_entry;
|
||||
|
||||
rtems_status_code zynqmp_configure_ocm_ecc( void )
|
||||
{
|
||||
volatile uint32_t *err_ctrl = (uint32_t*)(ocm_base + OCM_ERR_CTRL);
|
||||
volatile uint32_t *ecc_ctrl = (uint32_t*)(ocm_base + OCM_ECC_CTRL);
|
||||
volatile uint32_t *int_enable = (uint32_t*)(ocm_base + OCM_IE);
|
||||
rtems_status_code sc;
|
||||
|
||||
rtems_interrupt_entry_initialize(
|
||||
&zynqmp_ocm_ecc_entry,
|
||||
ocm_handler,
|
||||
NULL,
|
||||
"OCM RAM ECC"
|
||||
);
|
||||
|
||||
sc = rtems_interrupt_entry_install(
|
||||
ZYNQMP_IRQ_OCM,
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
&zynqmp_ocm_ecc_entry
|
||||
);
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return sc;
|
||||
}
|
||||
|
||||
if ((*ecc_ctrl & OCM_ECC_CTRL_ECC_ON_OFF) == 0) {
|
||||
/*
|
||||
* ECC is not enabled and should already have been by BOOT.bin. Enabling it
|
||||
* now could corrupt existing data in the OCM.
|
||||
*/
|
||||
return RTEMS_NOT_CONFIGURED;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCM_ERR_CTRL.UE_RES forces generation of a synchronous external abort
|
||||
* instead of using interrupts to signal the fault
|
||||
*/
|
||||
*err_ctrl &= ~(OCM_ERR_CTRL_UE_RES);
|
||||
|
||||
/* Ensure ECC_CTRL is in the right state */
|
||||
*ecc_ctrl &= ~(OCM_ECC_CTRL_DET_ONLY);
|
||||
|
||||
/* enable correctable and uncorrectable error interrupts */
|
||||
*int_enable = OCM_IE_CE | OCM_IE_UE | OCM_IE_UE_RMW;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
209
bsps/aarch64/xilinx-zynqmp/include/bsp/ecc.h
Normal file
209
bsps/aarch64/xilinx-zynqmp/include/bsp/ecc.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This header file provides internal APIs for managing ECC events.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_H
|
||||
#define LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_H
|
||||
|
||||
/**
|
||||
* @addtogroup RTEMSBSPsAArch64
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
//#include <bspopts.h>
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Enumeration describing the possible types of ECC events
|
||||
*/
|
||||
typedef enum {
|
||||
/* L1 Cache event information is delivered via Cache_Error_Event struct. */
|
||||
L1_CACHE,
|
||||
/* L2 Cache event information is delivered via Cache_Error_Event struct. */
|
||||
L2_CACHE,
|
||||
/*
|
||||
* L1 and L2 cache are on a combined interrupt on ZynqMP. They are enabled as
|
||||
* a single unit. The above individual L1 and L2 cache definitions will be
|
||||
* used for reporting. Attempting to enable L1 or L2 individually will enable
|
||||
* both.
|
||||
*/
|
||||
L1_L2_CACHE,
|
||||
OCM_RAM,
|
||||
DDR_RAM,
|
||||
} ECC_Event_Type;
|
||||
|
||||
/**
|
||||
* @brief The specific locations where a cache error can originate
|
||||
*/
|
||||
typedef enum {
|
||||
RAM_ID_L1I_TAG,
|
||||
RAM_ID_L1I_DATA,
|
||||
RAM_ID_L1D_TAG,
|
||||
RAM_ID_L1D_DATA,
|
||||
RAM_ID_L1D_DIRTY,
|
||||
RAM_ID_TLB,
|
||||
RAM_ID_L2_TAG,
|
||||
RAM_ID_L2_DATA,
|
||||
RAM_ID_SCU,
|
||||
RAM_ID_UNKNOWN
|
||||
} Cache_Error_RAM_ID;
|
||||
|
||||
/**
|
||||
* @brief Structure containing information about a Cache error
|
||||
*/
|
||||
typedef struct {
|
||||
/* Indicates the RAM index address */
|
||||
uint64_t address;
|
||||
/* Indicates the type of RAM where the error originated */
|
||||
Cache_Error_RAM_ID ramid;
|
||||
/*
|
||||
* Indicates the segment (way or bank) of the RAM where the error originated.
|
||||
* Does not apply to L1D_DIRTY RAM ID. For SCU errors, this also indicates the
|
||||
* associated CPU.
|
||||
*/
|
||||
uint8_t segment;
|
||||
/* The number of times this specific error has occurred since last reset */
|
||||
uint8_t repeats;
|
||||
/* The number of times other errors have occurred since last reset */
|
||||
uint8_t other_errors;
|
||||
/* Whether any of the errors represented have caused a data abort */
|
||||
bool abort;
|
||||
} Cache_Error_Event;
|
||||
|
||||
/**
|
||||
* @brief Typedef for ECC handlers
|
||||
*
|
||||
* Functions matching this prototype can be registered as the handler for ECC
|
||||
* event callbacks. The data argument is a struct describing the event that
|
||||
* occurred.
|
||||
*/
|
||||
typedef void (*zynqmp_ecc_handler)( ECC_Event_Type event, void *data );
|
||||
|
||||
/**
|
||||
* @brief Enumeration describing the possible types of ECC events
|
||||
*
|
||||
* Note that the provided handler may be called from interrupt context.
|
||||
*
|
||||
* @param handler The handler to be called for all ECC error events
|
||||
*/
|
||||
void zynqmp_ecc_register_handler( zynqmp_ecc_handler handler );
|
||||
|
||||
/**
|
||||
* @brief Enable ECC error reporting
|
||||
*
|
||||
* Enables ECC error reporting for the specified subsystem.
|
||||
*
|
||||
* @param event The ECC error event type to enable
|
||||
*/
|
||||
int zynqmp_ecc_enable( ECC_Event_Type event );
|
||||
|
||||
/**
|
||||
* @brief Injects an ECC fault in the On-Chip Memory (OCM)
|
||||
*/
|
||||
void zynqmp_ocm_inject_fault( void );
|
||||
|
||||
/**
|
||||
* @brief The types of OCM ECC errors
|
||||
*/
|
||||
typedef enum {
|
||||
OCM_UNCORRECTABLE,
|
||||
OCM_UNCORRECTABLE_RMW,
|
||||
OCM_CORRECTABLE
|
||||
} OCM_Error_Type;
|
||||
|
||||
/**
|
||||
* @brief Structure containing information about a OCM ECC error
|
||||
*/
|
||||
typedef struct {
|
||||
/* Describes the type of error being reported */
|
||||
OCM_Error_Type type;
|
||||
/* The offset into OCM where the error occurred */
|
||||
uint32_t offset;
|
||||
/* The data relevant to the error. Does not apply to RMW errors */
|
||||
uint32_t data0;
|
||||
uint32_t data1;
|
||||
uint32_t data2;
|
||||
uint32_t data3;
|
||||
/* The ECC syndrome relevant to the error. Does not apply to RMW errors */
|
||||
uint16_t syndrome;
|
||||
} OCM_Error_Info;
|
||||
|
||||
/**
|
||||
* @brief The types of DDR ECC errors
|
||||
*/
|
||||
typedef enum {
|
||||
DDR_UNCORRECTABLE,
|
||||
DDR_CORRECTABLE
|
||||
} DDR_Error_Type;
|
||||
|
||||
/**
|
||||
* @brief Structure containing information about a DDR ECC error
|
||||
*/
|
||||
typedef struct {
|
||||
/* Describes the type of error being reported */
|
||||
DDR_Error_Type type;
|
||||
/* The DDR Rank where the error occurred */
|
||||
uint32_t rank;
|
||||
/* The DDR Bank Group where the error occurred */
|
||||
uint32_t bank_group;
|
||||
/* The DDR Bank where the error occurred */
|
||||
uint32_t bank;
|
||||
/* The DDR Row where the error occurred */
|
||||
uint32_t row;
|
||||
/* The DDR Column where the error occurred */
|
||||
uint32_t column;
|
||||
/*
|
||||
* When mapping from SDRAM addressing back to AXI addressing, this is will
|
||||
* only be a close approximation of the source address since bits can be
|
||||
* discarded when converting from AXI to SDRAM.
|
||||
*/
|
||||
uint64_t address;
|
||||
} DDR_Error_Info;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_H */
|
||||
104
bsps/aarch64/xilinx-zynqmp/include/bsp/ecc_priv.h
Normal file
104
bsps/aarch64/xilinx-zynqmp/include/bsp/ecc_priv.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This header file provides internal APIs for managing ECC events.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_PRIV_H
|
||||
#define LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_PRIV_H
|
||||
|
||||
/**
|
||||
* @addtogroup RTEMSBSPsAArch64
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <bspopts.h>
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <bsp/ecc.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize ECC reporting support
|
||||
*
|
||||
* This initializes the base ECC event reporting support for the platform.
|
||||
*/
|
||||
void zynqmp_ecc_init( void );
|
||||
|
||||
/**
|
||||
* @brief Initialize BSP-specific ECC reporting
|
||||
*
|
||||
* Various BSPs may have different ECC capabilities. This allows those BSPs to
|
||||
* initialize those facilities as necessary.
|
||||
*/
|
||||
void zynqmp_ecc_init_bsp( void );
|
||||
|
||||
/**
|
||||
* @brief Configure Cache ECC reporting
|
||||
*/
|
||||
rtems_status_code zynqmp_configure_cache_ecc( void );
|
||||
|
||||
/**
|
||||
* @brief Configure On-Chip Memory (OCM) ECC reporting
|
||||
*/
|
||||
rtems_status_code zynqmp_configure_ocm_ecc( void );
|
||||
|
||||
/**
|
||||
* @brief Configure DDR Memory ECC reporting
|
||||
*/
|
||||
rtems_status_code zynqmp_configure_ddr_ecc( void );
|
||||
|
||||
/**
|
||||
* @brief Invoke the ECC error handler
|
||||
*
|
||||
* @param event The ECC error event type to be raised
|
||||
* @param data The details associated with the raised ECC error
|
||||
*/
|
||||
void zynqmp_invoke_ecc_handler( ECC_Event_Type event, void *data );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* LIBBSP_AARCH64_XILINX_ZYNQMP_BSP_ECC_PRIV_H */
|
||||
@@ -52,6 +52,7 @@ extern "C" {
|
||||
/* Interrupts vectors */
|
||||
#define BSP_TIMER_VIRT_PPI 27
|
||||
#define BSP_TIMER_PHYS_NS_PPI 30
|
||||
#define ZYNQMP_IRQ_OCM 42
|
||||
#define ZYNQMP_IRQ_QSPI 47
|
||||
#define ZYNQMP_IRQ_I2C_0 49
|
||||
#define ZYNQMP_IRQ_I2C_1 50
|
||||
@@ -61,6 +62,8 @@ extern "C" {
|
||||
#define ZYNQMP_IRQ_ETHERNET_1 91
|
||||
#define ZYNQMP_IRQ_ETHERNET_2 93
|
||||
#define ZYNQMP_IRQ_ETHERNET_3 95
|
||||
#define ZYNQMP_IRQ_DDR 144
|
||||
#define ZYNQMP_IRQ_CACHE 183
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/bootcard.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#include <bsp/linker-symbols.h>
|
||||
|
||||
@@ -56,4 +57,5 @@ void bsp_start( void )
|
||||
bsp_section_nocacheheap_begin,
|
||||
(uintptr_t) bsp_section_nocacheheap_size
|
||||
);
|
||||
zynqmp_ecc_init();
|
||||
}
|
||||
|
||||
44
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_cfc400x.c
Normal file
44
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_cfc400x.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of zynqmp_ecc_init_bsp().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
|
||||
void zynqmp_ecc_init_bsp( void )
|
||||
{
|
||||
zynqmp_ecc_enable( DDR_RAM );
|
||||
}
|
||||
|
||||
92
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_hw.c
Normal file
92
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_hw.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of zynqmp_ecc_init().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <bsp/utility.h>
|
||||
|
||||
zynqmp_ecc_handler saved_handler = NULL;
|
||||
|
||||
void zynqmp_ecc_register_handler( zynqmp_ecc_handler handler )
|
||||
{
|
||||
saved_handler = handler;
|
||||
}
|
||||
|
||||
void zynqmp_invoke_ecc_handler( ECC_Event_Type event, void *data )
|
||||
{
|
||||
if (saved_handler == NULL) {
|
||||
bsp_fatal( BSP_FATAL_MEMORY_ECC_ERROR );
|
||||
}
|
||||
|
||||
saved_handler(event, data);
|
||||
}
|
||||
|
||||
int zynqmp_ecc_enable( ECC_Event_Type event )
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
switch (event) {
|
||||
case L1_CACHE:
|
||||
case L2_CACHE:
|
||||
case L1_L2_CACHE:
|
||||
sc = zynqmp_configure_cache_ecc();
|
||||
break;
|
||||
case OCM_RAM:
|
||||
sc = zynqmp_configure_ocm_ecc();
|
||||
break;
|
||||
case DDR_RAM:
|
||||
sc = zynqmp_configure_ddr_ecc();
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zynqmp_ecc_init( void )
|
||||
{
|
||||
/* Do something on hardware */
|
||||
zynqmp_ecc_enable( L1_L2_CACHE );
|
||||
zynqmp_ecc_enable( OCM_RAM );
|
||||
|
||||
/* Call BSP-specific init function */
|
||||
zynqmp_ecc_init_bsp();
|
||||
}
|
||||
55
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_qemu.c
Normal file
55
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_qemu.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of zynqmp_ecc_init().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
|
||||
void zynqmp_ecc_register_handler( zynqmp_ecc_handler handler )
|
||||
{
|
||||
(void) handler;
|
||||
/* Do nothing on QEMU */
|
||||
}
|
||||
|
||||
int zynqmp_ecc_enable( ECC_Event_Type event )
|
||||
{
|
||||
(void) event;
|
||||
/* Do nothing on QEMU */
|
||||
return 0;
|
||||
}
|
||||
void zynqmp_ecc_init( void )
|
||||
{
|
||||
/* Do nothing on QEMU */
|
||||
}
|
||||
43
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_zu3eg.c
Normal file
43
bsps/aarch64/xilinx-zynqmp/start/bspstartecc_zu3eg.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsAArch64XilinxZynqMP
|
||||
*
|
||||
* @brief This source file contains the implementation of zynqmp_ecc_init_bsp().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
|
||||
* Written by Kinsey Moore <kinsey.moore@oarcorp.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/ecc_priv.h>
|
||||
|
||||
void zynqmp_ecc_init_bsp( void )
|
||||
{
|
||||
/* Do nothing special for ZU3EG BSPs */
|
||||
}
|
||||
@@ -50,6 +50,11 @@ zynqmp_mmu_config_table[] = {
|
||||
.begin = 0xfd000000U,
|
||||
.end = 0xffc00000U,
|
||||
.flags = AARCH64_MMU_DEVICE
|
||||
/* Map OCM space */
|
||||
}, {
|
||||
.begin = 0xfffc0000U,
|
||||
.end = 0x100000000U,
|
||||
.flags = AARCH64_MMU_DATA_RW
|
||||
}, {
|
||||
.begin = 0x80000000U,
|
||||
.end = 0x80100000U,
|
||||
|
||||
@@ -74,6 +74,7 @@ typedef enum {
|
||||
BSP_FATAL_CONSOLE_REGISTER_DEV_2,
|
||||
BSP_FATAL_MMU_ADDRESS_INVALID,
|
||||
BSP_FATAL_HEAP_EXTEND_ERROR,
|
||||
BSP_FATAL_MEMORY_ECC_ERROR,
|
||||
|
||||
/* ARM fatal codes */
|
||||
BSP_ARM_A9MPCORE_FATAL_CLOCK_IRQ_INSTALL = BSP_FATAL_CODE_BLOCK(1),
|
||||
|
||||
@@ -17,5 +17,7 @@ links:
|
||||
uid: linkcmds_lp64
|
||||
- role: build-dependency
|
||||
uid: objfdtcfc400x
|
||||
source: []
|
||||
source:
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_hw.c
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_cfc400x.c
|
||||
type: build
|
||||
|
||||
@@ -19,5 +19,6 @@ links:
|
||||
uid: linkcmds_ilp32
|
||||
- role: build-dependency
|
||||
uid: objfdtzynqmp
|
||||
source: []
|
||||
source:
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_qemu.c
|
||||
type: build
|
||||
|
||||
@@ -19,5 +19,6 @@ links:
|
||||
uid: linkcmds_lp64
|
||||
- role: build-dependency
|
||||
uid: objfdtzynqmp
|
||||
source: []
|
||||
source:
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_qemu.c
|
||||
type: build
|
||||
|
||||
@@ -17,5 +17,7 @@ links:
|
||||
uid: linkcmds_ilp32
|
||||
- role: build-dependency
|
||||
uid: objfdtzynqmp
|
||||
source: []
|
||||
source:
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_hw.c
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_zu3eg.c
|
||||
type: build
|
||||
|
||||
@@ -17,5 +17,7 @@ links:
|
||||
uid: linkcmds_lp64
|
||||
- role: build-dependency
|
||||
uid: objfdtzynqmp
|
||||
source: []
|
||||
source:
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_hw.c
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstartecc_zu3eg.c
|
||||
type: build
|
||||
|
||||
@@ -20,6 +20,9 @@ source:
|
||||
- bsps/aarch64/shared/cache/cache.c
|
||||
- bsps/aarch64/shared/mmu/vmsav8-64.c
|
||||
- bsps/aarch64/xilinx-zynqmp/console/console.c
|
||||
- bsps/aarch64/xilinx-zynqmp/ecc/cache.c
|
||||
- bsps/aarch64/xilinx-zynqmp/ecc/ddr.c
|
||||
- bsps/aarch64/xilinx-zynqmp/ecc/ocm.c
|
||||
- bsps/aarch64/xilinx-zynqmp/fdt/bsp_fdt.c
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstart.c
|
||||
- bsps/aarch64/xilinx-zynqmp/start/bspstarthooks.c
|
||||
|
||||
Reference in New Issue
Block a user