1 /* 2 * Copyright Altera Corporation (C) 2016. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 #include <linux/delay.h> 17 #include <linux/io.h> 18 #include <linux/genalloc.h> 19 #include <linux/module.h> 20 #include <linux/of_address.h> 21 #include <linux/of_platform.h> 22 23 #include "core.h" 24 25 #define ALTR_OCRAM_CLEAR_ECC 0x00000018 26 #define ALTR_OCRAM_ECC_EN 0x00000019 27 28 void socfpga_init_ocram_ecc(void) 29 { 30 struct device_node *np; 31 void __iomem *mapped_ocr_edac_addr; 32 33 /* Find the OCRAM EDAC device tree node */ 34 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc"); 35 if (!np) { 36 pr_err("Unable to find socfpga-ocram-ecc\n"); 37 return; 38 } 39 40 mapped_ocr_edac_addr = of_iomap(np, 0); 41 of_node_put(np); 42 if (!mapped_ocr_edac_addr) { 43 pr_err("Unable to map OCRAM ecc regs.\n"); 44 return; 45 } 46 47 /* Clear any pending OCRAM ECC interrupts, then enable ECC */ 48 writel(ALTR_OCRAM_CLEAR_ECC, mapped_ocr_edac_addr); 49 writel(ALTR_OCRAM_ECC_EN, mapped_ocr_edac_addr); 50 51 iounmap(mapped_ocr_edac_addr); 52 } 53 54 /* Arria10 OCRAM Section */ 55 #define ALTR_A10_ECC_CTRL_OFST 0x08 56 #define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0)) 57 #define ALTR_A10_ECC_INITA BIT(16) 58 59 #define ALTR_A10_ECC_INITSTAT_OFST 0x0C 60 #define ALTR_A10_ECC_INITCOMPLETEA BIT(0) 61 #define ALTR_A10_ECC_INITCOMPLETEB BIT(8) 62 63 #define ALTR_A10_ECC_ERRINTEN_OFST 0x10 64 #define ALTR_A10_ECC_SERRINTEN BIT(0) 65 66 #define ALTR_A10_ECC_INTSTAT_OFST 0x20 67 #define ALTR_A10_ECC_SERRPENA BIT(0) 68 #define ALTR_A10_ECC_DERRPENA BIT(8) 69 #define ALTR_A10_ECC_ERRPENA_MASK (ALTR_A10_ECC_SERRPENA | \ 70 ALTR_A10_ECC_DERRPENA) 71 /* ECC Manager Defines */ 72 #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 73 #define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98 74 #define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1) 75 76 #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 77 78 static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr) 79 { 80 u32 value = readl(ioaddr); 81 82 value |= bit_mask; 83 writel(value, ioaddr); 84 } 85 86 static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr) 87 { 88 u32 value = readl(ioaddr); 89 90 value &= ~bit_mask; 91 writel(value, ioaddr); 92 } 93 94 static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr) 95 { 96 u32 value = readl(ioaddr); 97 98 return (value & bit_mask) ? 1 : 0; 99 } 100 101 /* 102 * This function uses the memory initialization block in the Arria10 ECC 103 * controller to initialize/clear the entire memory data and ECC data. 104 */ 105 static int altr_init_memory_port(void __iomem *ioaddr) 106 { 107 int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US; 108 109 ecc_set_bits(ALTR_A10_ECC_INITA, (ioaddr + ALTR_A10_ECC_CTRL_OFST)); 110 while (limit--) { 111 if (ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA, 112 (ioaddr + ALTR_A10_ECC_INITSTAT_OFST))) 113 break; 114 udelay(1); 115 } 116 if (limit < 0) 117 return -EBUSY; 118 119 /* Clear any pending ECC interrupts */ 120 writel(ALTR_A10_ECC_ERRPENA_MASK, 121 (ioaddr + ALTR_A10_ECC_INTSTAT_OFST)); 122 123 return 0; 124 } 125 126 void socfpga_init_arria10_ocram_ecc(void) 127 { 128 struct device_node *np; 129 int ret = 0; 130 void __iomem *ecc_block_base; 131 132 if (!sys_manager_base_addr) { 133 pr_err("SOCFPGA: sys-mgr is not initialized\n"); 134 return; 135 } 136 137 /* Find the OCRAM EDAC device tree node */ 138 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-ocram-ecc"); 139 if (!np) { 140 pr_err("Unable to find socfpga-a10-ocram-ecc\n"); 141 return; 142 } 143 144 /* Map the ECC Block */ 145 ecc_block_base = of_iomap(np, 0); 146 of_node_put(np); 147 if (!ecc_block_base) { 148 pr_err("Unable to map OCRAM ECC block\n"); 149 return; 150 } 151 152 /* Disable ECC */ 153 writel(ALTR_A10_OCRAM_ECC_EN_CTL, 154 sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_SET_OFST); 155 ecc_clear_bits(ALTR_A10_ECC_SERRINTEN, 156 (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST)); 157 ecc_clear_bits(ALTR_A10_OCRAM_ECC_EN_CTL, 158 (ecc_block_base + ALTR_A10_ECC_CTRL_OFST)); 159 160 /* Ensure all writes complete */ 161 wmb(); 162 163 /* Use HW initialization block to initialize memory for ECC */ 164 ret = altr_init_memory_port(ecc_block_base); 165 if (ret) { 166 pr_err("ECC: cannot init OCRAM PORTA memory\n"); 167 goto exit; 168 } 169 170 /* Enable ECC */ 171 ecc_set_bits(ALTR_A10_OCRAM_ECC_EN_CTL, 172 (ecc_block_base + ALTR_A10_ECC_CTRL_OFST)); 173 ecc_set_bits(ALTR_A10_ECC_SERRINTEN, 174 (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST)); 175 writel(ALTR_A10_OCRAM_ECC_EN_CTL, 176 sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_CLR_OFST); 177 178 /* Ensure all writes complete */ 179 wmb(); 180 exit: 181 iounmap(ecc_block_base); 182 } 183