aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/altera_edac.c188
-rw-r--r--drivers/edac/altera_edac.h5
3 files changed, 199 insertions, 1 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 72752f460cbb..394cd16dd58f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -426,6 +426,13 @@ config EDAC_ALTERA_QSPI
426 Support for error detection and correction on the 426 Support for error detection and correction on the
427 Altera QSPI FIFO Memory for Altera SoCs. 427 Altera QSPI FIFO Memory for Altera SoCs.
428 428
429config EDAC_ALTERA_SDMMC
430 bool "Altera SDMMC FIFO ECC"
431 depends on EDAC_ALTERA=y && MMC_DW
432 help
433 Support for error detection and correction on the
434 Altera SDMMC FIFO Memory for Altera SoCs.
435
429config EDAC_SYNOPSYS 436config EDAC_SYNOPSYS
430 tristate "Synopsys DDR Memory Controller" 437 tristate "Synopsys DDR Memory Controller"
431 depends on EDAC_MM_EDAC && ARCH_ZYNQ 438 depends on EDAC_MM_EDAC && ARCH_ZYNQ
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 28247f82e1d5..efaf727be25a 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1393,6 +1393,188 @@ early_initcall(socfpga_init_qspi_ecc);
1393 1393
1394#endif /* CONFIG_EDAC_ALTERA_QSPI */ 1394#endif /* CONFIG_EDAC_ALTERA_QSPI */
1395 1395
1396/********************* SDMMC Device Functions **********************/
1397
1398#ifdef CONFIG_EDAC_ALTERA_SDMMC
1399
1400static const struct edac_device_prv_data a10_sdmmceccb_data;
1401static int altr_portb_setup(struct altr_edac_device_dev *device)
1402{
1403 struct edac_device_ctl_info *dci;
1404 struct altr_edac_device_dev *altdev;
1405 char *ecc_name = "sdmmcb-ecc";
1406 int edac_idx, rc;
1407 struct device_node *np;
1408 const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;
1409
1410 rc = altr_check_ecc_deps(device);
1411 if (rc)
1412 return rc;
1413
1414 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc");
1415 if (!np) {
1416 edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n");
1417 return -ENODEV;
1418 }
1419
1420 /* Create the PortB EDAC device */
1421 edac_idx = edac_device_alloc_index();
1422 dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name, 1,
1423 ecc_name, 1, 0, NULL, 0, edac_idx);
1424 if (!dci) {
1425 edac_printk(KERN_ERR, EDAC_DEVICE,
1426 "%s: Unable to allocate PortB EDAC device\n",
1427 ecc_name);
1428 return -ENOMEM;
1429 }
1430
1431 /* Initialize the PortB EDAC device structure from PortA structure */
1432 altdev = dci->pvt_info;
1433 *altdev = *device;
1434
1435 if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL))
1436 return -ENOMEM;
1437
1438 /* Update PortB specific values */
1439 altdev->edac_dev_name = ecc_name;
1440 altdev->edac_idx = edac_idx;
1441 altdev->edac_dev = dci;
1442 altdev->data = prv;
1443 dci->dev = &altdev->ddev;
1444 dci->ctl_name = "Altera ECC Manager";
1445 dci->mod_name = ecc_name;
1446 dci->dev_name = ecc_name;
1447
1448 /* Update the IRQs for PortB */
1449 altdev->sb_irq = irq_of_parse_and_map(np, 2);
1450 if (!altdev->sb_irq) {
1451 edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
1452 rc = -ENODEV;
1453 goto err_release_group_1;
1454 }
1455 rc = devm_request_irq(&altdev->ddev, altdev->sb_irq,
1456 prv->ecc_irq_handler,
1457 IRQF_SHARED, ecc_name, altdev);
1458 if (rc) {
1459 edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n");
1460 goto err_release_group_1;
1461 }
1462
1463 altdev->db_irq = irq_of_parse_and_map(np, 3);
1464 if (!altdev->db_irq) {
1465 edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n");
1466 rc = -ENODEV;
1467 goto err_release_group_1;
1468 }
1469 rc = devm_request_irq(&altdev->ddev, altdev->db_irq,
1470 prv->ecc_irq_handler,
1471 IRQF_SHARED, ecc_name, altdev);
1472 if (rc) {
1473 edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
1474 goto err_release_group_1;
1475 }
1476
1477 rc = edac_device_add_device(dci);
1478 if (rc) {
1479 edac_printk(KERN_ERR, EDAC_DEVICE,
1480 "edac_device_add_device portB failed\n");
1481 rc = -ENOMEM;
1482 goto err_release_group_1;
1483 }
1484 altr_create_edacdev_dbgfs(dci, prv);
1485
1486 list_add(&altdev->next, &altdev->edac->a10_ecc_devices);
1487
1488 devres_remove_group(&altdev->ddev, altr_portb_setup);
1489
1490 return 0;
1491
1492err_release_group_1:
1493 edac_device_free_ctl_info(dci);
1494 devres_release_group(&altdev->ddev, altr_portb_setup);
1495 edac_printk(KERN_ERR, EDAC_DEVICE,
1496 "%s:Error setting up EDAC device: %d\n", ecc_name, rc);
1497 return rc;
1498}
1499
1500static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id)
1501{
1502 struct altr_edac_device_dev *ad = dev_id;
1503 void __iomem *base = ad->base;
1504 const struct edac_device_prv_data *priv = ad->data;
1505
1506 if (irq == ad->sb_irq) {
1507 writel(priv->ce_clear_mask,
1508 base + ALTR_A10_ECC_INTSTAT_OFST);
1509 edac_device_handle_ce(ad->edac_dev, 0, 0, ad->edac_dev_name);
1510 return IRQ_HANDLED;
1511 } else if (irq == ad->db_irq) {
1512 writel(priv->ue_clear_mask,
1513 base + ALTR_A10_ECC_INTSTAT_OFST);
1514 edac_device_handle_ue(ad->edac_dev, 0, 0, ad->edac_dev_name);
1515 return IRQ_HANDLED;
1516 }
1517
1518 WARN_ONCE(1, "Unhandled IRQ%d on Port B.", irq);
1519
1520 return IRQ_NONE;
1521}
1522
1523static const struct edac_device_prv_data a10_sdmmcecca_data = {
1524 .setup = altr_portb_setup,
1525 .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
1526 .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
1527 .dbgfs_name = "altr_trigger",
1528 .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
1529 .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST,
1530 .ce_set_mask = ALTR_A10_ECC_SERRPENA,
1531 .ue_set_mask = ALTR_A10_ECC_DERRPENA,
1532 .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
1533 .ecc_irq_handler = altr_edac_a10_ecc_irq,
1534 .inject_fops = &altr_edac_a10_device_inject_fops,
1535};
1536
1537static const struct edac_device_prv_data a10_sdmmceccb_data = {
1538 .setup = altr_portb_setup,
1539 .ce_clear_mask = ALTR_A10_ECC_SERRPENB,
1540 .ue_clear_mask = ALTR_A10_ECC_DERRPENB,
1541 .dbgfs_name = "altr_trigger",
1542 .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
1543 .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST,
1544 .ce_set_mask = ALTR_A10_ECC_TSERRB,
1545 .ue_set_mask = ALTR_A10_ECC_TDERRB,
1546 .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
1547 .ecc_irq_handler = altr_edac_a10_ecc_irq_portb,
1548 .inject_fops = &altr_edac_a10_device_inject_fops,
1549};
1550
1551static int __init socfpga_init_sdmmc_ecc(void)
1552{
1553 int rc = -ENODEV;
1554 struct device_node *child = of_find_compatible_node(NULL, NULL,
1555 "altr,socfpga-sdmmc-ecc");
1556 if (!child) {
1557 edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n");
1558 return -ENODEV;
1559 }
1560
1561 if (!of_device_is_available(child))
1562 goto exit;
1563
1564 if (validate_parent_available(child))
1565 goto exit;
1566
1567 rc = altr_init_a10_ecc_block(child, ALTR_A10_SDMMC_IRQ_MASK,
1568 a10_sdmmcecca_data.ecc_enable_mask, 1);
1569exit:
1570 of_node_put(child);
1571 return rc;
1572}
1573
1574early_initcall(socfpga_init_sdmmc_ecc);
1575
1576#endif /* CONFIG_EDAC_ALTERA_SDMMC */
1577
1396/********************* Arria10 EDAC Device Functions *************************/ 1578/********************* Arria10 EDAC Device Functions *************************/
1397static const struct of_device_id altr_edac_a10_device_of_match[] = { 1579static const struct of_device_id altr_edac_a10_device_of_match[] = {
1398#ifdef CONFIG_EDAC_ALTERA_L2C 1580#ifdef CONFIG_EDAC_ALTERA_L2C
@@ -1418,6 +1600,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = {
1418#ifdef CONFIG_EDAC_ALTERA_QSPI 1600#ifdef CONFIG_EDAC_ALTERA_QSPI
1419 { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data }, 1601 { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data },
1420#endif 1602#endif
1603#ifdef CONFIG_EDAC_ALTERA_SDMMC
1604 { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data },
1605#endif
1421 {}, 1606 {},
1422}; 1607};
1423MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match); 1608MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match);
@@ -1711,7 +1896,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
1711 of_device_is_compatible(child, "altr,socfpga-nand-ecc") || 1896 of_device_is_compatible(child, "altr,socfpga-nand-ecc") ||
1712 of_device_is_compatible(child, "altr,socfpga-dma-ecc") || 1897 of_device_is_compatible(child, "altr,socfpga-dma-ecc") ||
1713 of_device_is_compatible(child, "altr,socfpga-usb-ecc") || 1898 of_device_is_compatible(child, "altr,socfpga-usb-ecc") ||
1714 of_device_is_compatible(child, "altr,socfpga-qspi-ecc")) 1899 of_device_is_compatible(child, "altr,socfpga-qspi-ecc") ||
1900 of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc"))
1715 1901
1716 altr_edac_a10_device_add(edac, child); 1902 altr_edac_a10_device_add(edac, child);
1717 1903
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 687d8e754d36..cf3a68bec100 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -250,6 +250,8 @@ struct altr_sdram_mc_data {
250#define ALTR_A10_ECC_INTTEST_OFST 0x24 250#define ALTR_A10_ECC_INTTEST_OFST 0x24
251#define ALTR_A10_ECC_TSERRA BIT(0) 251#define ALTR_A10_ECC_TSERRA BIT(0)
252#define ALTR_A10_ECC_TDERRA BIT(8) 252#define ALTR_A10_ECC_TDERRA BIT(8)
253#define ALTR_A10_ECC_TSERRB BIT(16)
254#define ALTR_A10_ECC_TDERRB BIT(24)
253 255
254/* ECC Manager Defines */ 256/* ECC Manager Defines */
255#define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 257#define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94
@@ -288,6 +290,9 @@ struct altr_sdram_mc_data {
288/* Arria 10 Ethernet ECC Management Group Defines */ 290/* Arria 10 Ethernet ECC Management Group Defines */
289#define ALTR_A10_COMMON_ECC_EN_CTL BIT(0) 291#define ALTR_A10_COMMON_ECC_EN_CTL BIT(0)
290 292
293/* Arria 10 SDMMC ECC Management Group Defines */
294#define ALTR_A10_SDMMC_IRQ_MASK (BIT(16) | BIT(15))
295
291/* A10 ECC Controller memory initialization timeout */ 296/* A10 ECC Controller memory initialization timeout */
292#define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 297#define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000
293 298