0001
0002
0003
0004
0005 #include <linux/delay.h>
0006 #include <linux/io.h>
0007 #include <linux/genalloc.h>
0008 #include <linux/module.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_platform.h>
0011
0012 #include "core.h"
0013
0014 #define ALTR_OCRAM_CLEAR_ECC 0x00000018
0015 #define ALTR_OCRAM_ECC_EN 0x00000019
0016
0017 void socfpga_init_ocram_ecc(void)
0018 {
0019 struct device_node *np;
0020 void __iomem *mapped_ocr_edac_addr;
0021
0022
0023 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc");
0024 if (!np) {
0025 pr_err("Unable to find socfpga-ocram-ecc\n");
0026 return;
0027 }
0028
0029 mapped_ocr_edac_addr = of_iomap(np, 0);
0030 of_node_put(np);
0031 if (!mapped_ocr_edac_addr) {
0032 pr_err("Unable to map OCRAM ecc regs.\n");
0033 return;
0034 }
0035
0036
0037 writel(ALTR_OCRAM_CLEAR_ECC, mapped_ocr_edac_addr);
0038 writel(ALTR_OCRAM_ECC_EN, mapped_ocr_edac_addr);
0039
0040 iounmap(mapped_ocr_edac_addr);
0041 }
0042
0043
0044 #define ALTR_A10_ECC_CTRL_OFST 0x08
0045 #define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0))
0046 #define ALTR_A10_ECC_INITA BIT(16)
0047
0048 #define ALTR_A10_ECC_INITSTAT_OFST 0x0C
0049 #define ALTR_A10_ECC_INITCOMPLETEA BIT(0)
0050 #define ALTR_A10_ECC_INITCOMPLETEB BIT(8)
0051
0052 #define ALTR_A10_ECC_ERRINTEN_OFST 0x10
0053 #define ALTR_A10_ECC_SERRINTEN BIT(0)
0054
0055 #define ALTR_A10_ECC_INTSTAT_OFST 0x20
0056 #define ALTR_A10_ECC_SERRPENA BIT(0)
0057 #define ALTR_A10_ECC_DERRPENA BIT(8)
0058 #define ALTR_A10_ECC_ERRPENA_MASK (ALTR_A10_ECC_SERRPENA | \
0059 ALTR_A10_ECC_DERRPENA)
0060
0061 #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94
0062 #define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98
0063 #define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1)
0064
0065 #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000
0066
0067 static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr)
0068 {
0069 u32 value = readl(ioaddr);
0070
0071 value |= bit_mask;
0072 writel(value, ioaddr);
0073 }
0074
0075 static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr)
0076 {
0077 u32 value = readl(ioaddr);
0078
0079 value &= ~bit_mask;
0080 writel(value, ioaddr);
0081 }
0082
0083 static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr)
0084 {
0085 u32 value = readl(ioaddr);
0086
0087 return (value & bit_mask) ? 1 : 0;
0088 }
0089
0090
0091
0092
0093
0094 static int altr_init_memory_port(void __iomem *ioaddr)
0095 {
0096 int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US;
0097
0098 ecc_set_bits(ALTR_A10_ECC_INITA, (ioaddr + ALTR_A10_ECC_CTRL_OFST));
0099 while (limit--) {
0100 if (ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
0101 (ioaddr + ALTR_A10_ECC_INITSTAT_OFST)))
0102 break;
0103 udelay(1);
0104 }
0105 if (limit < 0)
0106 return -EBUSY;
0107
0108
0109 writel(ALTR_A10_ECC_ERRPENA_MASK,
0110 (ioaddr + ALTR_A10_ECC_INTSTAT_OFST));
0111
0112 return 0;
0113 }
0114
0115 void socfpga_init_arria10_ocram_ecc(void)
0116 {
0117 struct device_node *np;
0118 int ret = 0;
0119 void __iomem *ecc_block_base;
0120
0121 if (!sys_manager_base_addr) {
0122 pr_err("SOCFPGA: sys-mgr is not initialized\n");
0123 return;
0124 }
0125
0126
0127 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-ocram-ecc");
0128 if (!np) {
0129 pr_err("Unable to find socfpga-a10-ocram-ecc\n");
0130 return;
0131 }
0132
0133
0134 ecc_block_base = of_iomap(np, 0);
0135 of_node_put(np);
0136 if (!ecc_block_base) {
0137 pr_err("Unable to map OCRAM ECC block\n");
0138 return;
0139 }
0140
0141
0142 writel(ALTR_A10_OCRAM_ECC_EN_CTL,
0143 sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_SET_OFST);
0144 ecc_clear_bits(ALTR_A10_ECC_SERRINTEN,
0145 (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
0146 ecc_clear_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
0147 (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
0148
0149
0150 wmb();
0151
0152
0153 ret = altr_init_memory_port(ecc_block_base);
0154 if (ret) {
0155 pr_err("ECC: cannot init OCRAM PORTA memory\n");
0156 goto exit;
0157 }
0158
0159
0160 ecc_set_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
0161 (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
0162 ecc_set_bits(ALTR_A10_ECC_SERRINTEN,
0163 (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
0164 writel(ALTR_A10_OCRAM_ECC_EN_CTL,
0165 sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_CLR_OFST);
0166
0167
0168 wmb();
0169 exit:
0170 iounmap(ecc_block_base);
0171 }