aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorThor Thayer <tthayer@opensource.altera.com>2015-06-04 10:28:47 -0400
committerBorislav Petkov <bp@suse.de>2015-06-24 12:16:09 -0400
commit73bcc942f4271fab2ea41e6a3992d3c2164faaa8 (patch)
tree39c58082936af48d8d20485f989f6b3b90b27e5f /drivers/edac
parent143f4a5ac5af82a4055100c8f40b26187d5c20ba (diff)
EDAC, altera: Add Arria10 EDAC support
The Arria10 SDRAM and ECC system differs significantly from the Cyclone5 and Arria5 SoCs. This patch adds support for the Arria10 SoC. 1) IRQ handler needs to support SHARED IRQ 2) Support sberr and dberr address reporting. Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: galak@codeaurora.org Cc: grant.likely@linaro.org Cc: ijc+devicetree@hellion.org.uk Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac <linux-edac@vger.kernel.org> Cc: m.chehab@samsung.com Cc: mark.rutland@arm.com Cc: pawel.moll@arm.com Cc: robh+dt@kernel.org Cc: tthayer.linux@gmail.com Link: http://lkml.kernel.org/r/1433428128-7292-4-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/altera_edac.c135
-rw-r--r--drivers/edac/altera_edac.h85
2 files changed, 204 insertions, 16 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 4ac4e6c11ece..182c741adf3e 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -42,6 +42,7 @@ static const struct altr_sdram_prv_data c5_data = {
42 .ecc_stat_ce_mask = CV_DRAMSTS_SBEERR, 42 .ecc_stat_ce_mask = CV_DRAMSTS_SBEERR,
43 .ecc_stat_ue_mask = CV_DRAMSTS_DBEERR, 43 .ecc_stat_ue_mask = CV_DRAMSTS_DBEERR,
44 .ecc_saddr_offset = CV_ERRADDR_OFST, 44 .ecc_saddr_offset = CV_ERRADDR_OFST,
45 .ecc_daddr_offset = CV_ERRADDR_OFST,
45 .ecc_cecnt_offset = CV_SBECOUNT_OFST, 46 .ecc_cecnt_offset = CV_SBECOUNT_OFST,
46 .ecc_uecnt_offset = CV_DBECOUNT_OFST, 47 .ecc_uecnt_offset = CV_DBECOUNT_OFST,
47 .ecc_irq_en_offset = CV_DRAMINTR_OFST, 48 .ecc_irq_en_offset = CV_DRAMINTR_OFST,
@@ -57,37 +58,62 @@ static const struct altr_sdram_prv_data c5_data = {
57#endif 58#endif
58}; 59};
59 60
61static const struct altr_sdram_prv_data a10_data = {
62 .ecc_ctrl_offset = A10_ECCCTRL1_OFST,
63 .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN,
64 .ecc_stat_offset = A10_INTSTAT_OFST,
65 .ecc_stat_ce_mask = A10_INTSTAT_SBEERR,
66 .ecc_stat_ue_mask = A10_INTSTAT_DBEERR,
67 .ecc_saddr_offset = A10_SERRADDR_OFST,
68 .ecc_daddr_offset = A10_DERRADDR_OFST,
69 .ecc_irq_en_offset = A10_ERRINTEN_OFST,
70 .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK,
71 .ecc_irq_clr_offset = A10_INTSTAT_OFST,
72 .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR),
73 .ecc_cnt_rst_offset = A10_ECCCTRL1_OFST,
74 .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK,
75#ifdef CONFIG_EDAC_DEBUG
76 .ce_ue_trgr_offset = A10_DIAGINTTEST_OFST,
77 .ce_set_mask = A10_DIAGINT_TSERRA_MASK,
78 .ue_set_mask = A10_DIAGINT_TDERRA_MASK,
79#endif
80};
81
60static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) 82static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
61{ 83{
62 struct mem_ctl_info *mci = dev_id; 84 struct mem_ctl_info *mci = dev_id;
63 struct altr_sdram_mc_data *drvdata = mci->pvt_info; 85 struct altr_sdram_mc_data *drvdata = mci->pvt_info;
64 const struct altr_sdram_prv_data *priv = drvdata->data; 86 const struct altr_sdram_prv_data *priv = drvdata->data;
65 u32 status, err_count, err_addr; 87 u32 status, err_count = 1, err_addr;
66
67 /* Error Address is shared by both SBE & DBE */
68 regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset, &err_addr);
69 88
70 regmap_read(drvdata->mc_vbase, priv->ecc_stat_offset, &status); 89 regmap_read(drvdata->mc_vbase, priv->ecc_stat_offset, &status);
71 90
72 if (status & priv->ecc_stat_ue_mask) { 91 if (status & priv->ecc_stat_ue_mask) {
73 regmap_read(drvdata->mc_vbase, priv->ecc_uecnt_offset, 92 regmap_read(drvdata->mc_vbase, priv->ecc_daddr_offset,
74 &err_count); 93 &err_addr);
94 if (priv->ecc_uecnt_offset)
95 regmap_read(drvdata->mc_vbase, priv->ecc_uecnt_offset,
96 &err_count);
75 panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n", 97 panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n",
76 err_count, err_addr); 98 err_count, err_addr);
77 } 99 }
78 if (status & priv->ecc_stat_ce_mask) { 100 if (status & priv->ecc_stat_ce_mask) {
79 regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset, 101 regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset,
80 &err_count); 102 &err_addr);
103 if (priv->ecc_uecnt_offset)
104 regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset,
105 &err_count);
81 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count, 106 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
82 err_addr >> PAGE_SHIFT, 107 err_addr >> PAGE_SHIFT,
83 err_addr & ~PAGE_MASK, 0, 108 err_addr & ~PAGE_MASK, 0,
84 0, 0, -1, mci->ctl_name, ""); 109 0, 0, -1, mci->ctl_name, "");
85 } 110 /* Clear IRQ to resume */
86 111 regmap_write(drvdata->mc_vbase, priv->ecc_irq_clr_offset,
87 regmap_write(drvdata->mc_vbase, priv->ecc_irq_clr_offset, 112 priv->ecc_irq_clr_mask);
88 priv->ecc_irq_clr_mask);
89 113
90 return IRQ_HANDLED; 114 return IRQ_HANDLED;
115 }
116 return IRQ_NONE;
91} 117}
92 118
93#ifdef CONFIG_EDAC_DEBUG 119#ifdef CONFIG_EDAC_DEBUG
@@ -203,10 +229,60 @@ static unsigned long get_total_mem(void)
203 229
204static const struct of_device_id altr_sdram_ctrl_of_match[] = { 230static const struct of_device_id altr_sdram_ctrl_of_match[] = {
205 { .compatible = "altr,sdram-edac", .data = (void *)&c5_data}, 231 { .compatible = "altr,sdram-edac", .data = (void *)&c5_data},
232 { .compatible = "altr,sdram-edac-a10", .data = (void *)&a10_data},
206 {}, 233 {},
207}; 234};
208MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); 235MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
209 236
237static int a10_init(struct regmap *mc_vbase)
238{
239 if (regmap_update_bits(mc_vbase, A10_INTMODE_OFST,
240 A10_INTMODE_SB_INT, A10_INTMODE_SB_INT)) {
241 edac_printk(KERN_ERR, EDAC_MC,
242 "Error setting SB IRQ mode\n");
243 return -ENODEV;
244 }
245
246 if (regmap_write(mc_vbase, A10_SERRCNTREG_OFST, 1)) {
247 edac_printk(KERN_ERR, EDAC_MC,
248 "Error setting trigger count\n");
249 return -ENODEV;
250 }
251
252 return 0;
253}
254
255static int a10_unmask_irq(struct platform_device *pdev, u32 mask)
256{
257 void __iomem *sm_base;
258 int ret = 0;
259
260 if (!request_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32),
261 dev_name(&pdev->dev))) {
262 edac_printk(KERN_ERR, EDAC_MC,
263 "Unable to request mem region\n");
264 return -EBUSY;
265 }
266
267 sm_base = ioremap(A10_SYMAN_INTMASK_CLR, sizeof(u32));
268 if (!sm_base) {
269 edac_printk(KERN_ERR, EDAC_MC,
270 "Unable to ioremap device\n");
271
272 ret = -ENOMEM;
273 goto release;
274 }
275
276 iowrite32(mask, sm_base);
277
278 iounmap(sm_base);
279
280release:
281 release_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32));
282
283 return ret;
284}
285
210static int altr_sdram_probe(struct platform_device *pdev) 286static int altr_sdram_probe(struct platform_device *pdev)
211{ 287{
212 const struct of_device_id *id; 288 const struct of_device_id *id;
@@ -217,8 +293,8 @@ static int altr_sdram_probe(struct platform_device *pdev)
217 struct regmap *mc_vbase; 293 struct regmap *mc_vbase;
218 struct dimm_info *dimm; 294 struct dimm_info *dimm;
219 u32 read_reg; 295 u32 read_reg;
220 int irq, res = 0; 296 int irq, irq2, res = 0;
221 unsigned long mem_size; 297 unsigned long mem_size, irqflags = 0;
222 298
223 id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); 299 id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev);
224 if (!id) 300 if (!id)
@@ -283,6 +359,9 @@ static int altr_sdram_probe(struct platform_device *pdev)
283 return -ENODEV; 359 return -ENODEV;
284 } 360 }
285 361
362 /* Arria10 has a 2nd IRQ */
363 irq2 = platform_get_irq(pdev, 1);
364
286 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 365 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
287 layers[0].size = 1; 366 layers[0].size = 1;
288 layers[0].is_virt_csrow = true; 367 layers[0].is_virt_csrow = true;
@@ -327,8 +406,32 @@ static int altr_sdram_probe(struct platform_device *pdev)
327 if (res < 0) 406 if (res < 0)
328 goto err; 407 goto err;
329 408
409 /* Only the Arria10 has separate IRQs */
410 if (irq2 > 0) {
411 /* Arria10 specific initialization */
412 res = a10_init(mc_vbase);
413 if (res < 0)
414 goto err2;
415
416 res = devm_request_irq(&pdev->dev, irq2,
417 altr_sdram_mc_err_handler,
418 IRQF_SHARED, dev_name(&pdev->dev), mci);
419 if (res < 0) {
420 edac_mc_printk(mci, KERN_ERR,
421 "Unable to request irq %d\n", irq2);
422 res = -ENODEV;
423 goto err2;
424 }
425
426 res = a10_unmask_irq(pdev, A10_DDR0_IRQ_MASK);
427 if (res < 0)
428 goto err2;
429
430 irqflags = IRQF_SHARED;
431 }
432
330 res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, 433 res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
331 0, dev_name(&pdev->dev), mci); 434 irqflags, dev_name(&pdev->dev), mci);
332 if (res < 0) { 435 if (res < 0) {
333 edac_mc_printk(mci, KERN_ERR, 436 edac_mc_printk(mci, KERN_ERR,
334 "Unable to request irq %d\n", irq); 437 "Unable to request irq %d\n", irq);
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index b744d914d976..7b64dc7c4eb7 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -80,6 +80,91 @@
80/* SDRAM Controller ECC Error Address Register */ 80/* SDRAM Controller ECC Error Address Register */
81#define CV_ERRADDR_OFST 0x48 81#define CV_ERRADDR_OFST 0x48
82 82
83/*-----------------------------------------*/
84
85/* SDRAM Controller EccCtrl Register */
86#define A10_ECCCTRL1_OFST 0x00
87
88/* SDRAM Controller EccCtrl Register Bit Masks */
89#define A10_ECCCTRL1_ECC_EN 0x001
90#define A10_ECCCTRL1_CNT_RST 0x010
91#define A10_ECCCTRL1_AWB_CNT_RST 0x100
92#define A10_ECC_CNT_RESET_MASK (A10_ECCCTRL1_CNT_RST | \
93 A10_ECCCTRL1_AWB_CNT_RST)
94
95/* SDRAM Controller Address Width Register */
96#define CV_DRAMADDRW 0xFFC2502C
97#define A10_DRAMADDRW 0xFFCFA0A8
98
99/* SDRAM Controller Address Widths Field Register */
100#define DRAMADDRW_COLBIT_MASK 0x001F
101#define DRAMADDRW_COLBIT_SHIFT 0
102#define DRAMADDRW_ROWBIT_MASK 0x03E0
103#define DRAMADDRW_ROWBIT_SHIFT 5
104#define CV_DRAMADDRW_BANKBIT_MASK 0x1C00
105#define CV_DRAMADDRW_BANKBIT_SHIFT 10
106#define CV_DRAMADDRW_CSBIT_MASK 0xE000
107#define CV_DRAMADDRW_CSBIT_SHIFT 13
108
109#define A10_DRAMADDRW_BANKBIT_MASK 0x3C00
110#define A10_DRAMADDRW_BANKBIT_SHIFT 10
111#define A10_DRAMADDRW_GRPBIT_MASK 0xC000
112#define A10_DRAMADDRW_GRPBIT_SHIFT 14
113#define A10_DRAMADDRW_CSBIT_MASK 0x70000
114#define A10_DRAMADDRW_CSBIT_SHIFT 16
115
116/* SDRAM Controller Interface Data Width Register */
117#define CV_DRAMIFWIDTH 0xFFC25030
118#define A10_DRAMIFWIDTH 0xFFCFB008
119
120/* SDRAM Controller Interface Data Width Defines */
121#define CV_DRAMIFWIDTH_16B_ECC 24
122#define CV_DRAMIFWIDTH_32B_ECC 40
123
124#define A10_DRAMIFWIDTH_16B 0x0
125#define A10_DRAMIFWIDTH_32B 0x1
126#define A10_DRAMIFWIDTH_64B 0x2
127
128/* SDRAM Controller DRAM IRQ Register */
129#define A10_ERRINTEN_OFST 0x10
130
131/* SDRAM Controller DRAM IRQ Register Bit Masks */
132#define A10_ERRINTEN_SERRINTEN 0x01
133#define A10_ERRINTEN_DERRINTEN 0x02
134#define A10_ECC_IRQ_EN_MASK (A10_ERRINTEN_SERRINTEN | \
135 A10_ERRINTEN_DERRINTEN)
136
137/* SDRAM Interrupt Mode Register */
138#define A10_INTMODE_OFST 0x1C
139#define A10_INTMODE_SB_INT 1
140
141/* SDRAM Controller Error Status Register */
142#define A10_INTSTAT_OFST 0x20
143
144/* SDRAM Controller Error Status Register Bit Masks */
145#define A10_INTSTAT_SBEERR 0x01
146#define A10_INTSTAT_DBEERR 0x02
147
148/* SDRAM Controller ECC Error Address Register */
149#define A10_DERRADDR_OFST 0x2C
150#define A10_SERRADDR_OFST 0x30
151
152/* SDRAM Controller ECC Diagnostic Register */
153#define A10_DIAGINTTEST_OFST 0x24
154
155#define A10_DIAGINT_TSERRA_MASK 0x0001
156#define A10_DIAGINT_TDERRA_MASK 0x0100
157
158#define A10_SBERR_IRQ 34
159#define A10_DBERR_IRQ 32
160
161/* SDRAM Single Bit Error Count Compare Set Register */
162#define A10_SERRCNTREG_OFST 0x3C
163
164#define A10_SYMAN_INTMASK_CLR 0xFFD06098
165#define A10_INTMASK_CLR_OFST 0x10
166#define A10_DDR0_IRQ_MASK BIT(17)
167
83struct altr_sdram_prv_data { 168struct altr_sdram_prv_data {
84 int ecc_ctrl_offset; 169 int ecc_ctrl_offset;
85 int ecc_ctl_en_mask; 170 int ecc_ctl_en_mask;