xref: /openbmc/linux/arch/arm/mach-socfpga/ocram.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27cc5a5d3SThor Thayer /*
37cc5a5d3SThor Thayer  * Copyright Altera Corporation (C) 2016. All rights reserved.
47cc5a5d3SThor Thayer  */
52364d423SThor Thayer #include <linux/delay.h>
67cc5a5d3SThor Thayer #include <linux/io.h>
7*37e2d7d2SRob Herring #include <linux/of.h>
87cc5a5d3SThor Thayer #include <linux/of_address.h>
97cc5a5d3SThor Thayer 
102364d423SThor Thayer #include "core.h"
112364d423SThor Thayer 
127cc5a5d3SThor Thayer #define ALTR_OCRAM_CLEAR_ECC          0x00000018
137cc5a5d3SThor Thayer #define ALTR_OCRAM_ECC_EN             0x00000019
147cc5a5d3SThor Thayer 
socfpga_init_ocram_ecc(void)157cc5a5d3SThor Thayer void socfpga_init_ocram_ecc(void)
167cc5a5d3SThor Thayer {
177cc5a5d3SThor Thayer 	struct device_node *np;
187cc5a5d3SThor Thayer 	void __iomem *mapped_ocr_edac_addr;
197cc5a5d3SThor Thayer 
207cc5a5d3SThor Thayer 	/* Find the OCRAM EDAC device tree node */
217cc5a5d3SThor Thayer 	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc");
227cc5a5d3SThor Thayer 	if (!np) {
237cc5a5d3SThor Thayer 		pr_err("Unable to find socfpga-ocram-ecc\n");
247cc5a5d3SThor Thayer 		return;
257cc5a5d3SThor Thayer 	}
267cc5a5d3SThor Thayer 
277cc5a5d3SThor Thayer 	mapped_ocr_edac_addr = of_iomap(np, 0);
287cc5a5d3SThor Thayer 	of_node_put(np);
297cc5a5d3SThor Thayer 	if (!mapped_ocr_edac_addr) {
307cc5a5d3SThor Thayer 		pr_err("Unable to map OCRAM ecc regs.\n");
317cc5a5d3SThor Thayer 		return;
327cc5a5d3SThor Thayer 	}
337cc5a5d3SThor Thayer 
347cc5a5d3SThor Thayer 	/* Clear any pending OCRAM ECC interrupts, then enable ECC */
357cc5a5d3SThor Thayer 	writel(ALTR_OCRAM_CLEAR_ECC, mapped_ocr_edac_addr);
367cc5a5d3SThor Thayer 	writel(ALTR_OCRAM_ECC_EN, mapped_ocr_edac_addr);
377cc5a5d3SThor Thayer 
387cc5a5d3SThor Thayer 	iounmap(mapped_ocr_edac_addr);
397cc5a5d3SThor Thayer }
402364d423SThor Thayer 
412364d423SThor Thayer /* Arria10 OCRAM Section */
422364d423SThor Thayer #define ALTR_A10_ECC_CTRL_OFST          0x08
432364d423SThor Thayer #define ALTR_A10_OCRAM_ECC_EN_CTL       (BIT(1) | BIT(0))
442364d423SThor Thayer #define ALTR_A10_ECC_INITA              BIT(16)
452364d423SThor Thayer 
462364d423SThor Thayer #define ALTR_A10_ECC_INITSTAT_OFST      0x0C
472364d423SThor Thayer #define ALTR_A10_ECC_INITCOMPLETEA      BIT(0)
482364d423SThor Thayer #define ALTR_A10_ECC_INITCOMPLETEB      BIT(8)
492364d423SThor Thayer 
502364d423SThor Thayer #define ALTR_A10_ECC_ERRINTEN_OFST      0x10
512364d423SThor Thayer #define ALTR_A10_ECC_SERRINTEN          BIT(0)
522364d423SThor Thayer 
532364d423SThor Thayer #define ALTR_A10_ECC_INTSTAT_OFST       0x20
542364d423SThor Thayer #define ALTR_A10_ECC_SERRPENA           BIT(0)
552364d423SThor Thayer #define ALTR_A10_ECC_DERRPENA           BIT(8)
562364d423SThor Thayer #define ALTR_A10_ECC_ERRPENA_MASK       (ALTR_A10_ECC_SERRPENA | \
572364d423SThor Thayer 					 ALTR_A10_ECC_DERRPENA)
582364d423SThor Thayer /* ECC Manager Defines */
592364d423SThor Thayer #define A10_SYSMGR_ECC_INTMASK_SET_OFST   0x94
602364d423SThor Thayer #define A10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
612364d423SThor Thayer #define A10_SYSMGR_ECC_INTMASK_OCRAM      BIT(1)
622364d423SThor Thayer 
632364d423SThor Thayer #define ALTR_A10_ECC_INIT_WATCHDOG_10US   10000
642364d423SThor Thayer 
ecc_set_bits(u32 bit_mask,void __iomem * ioaddr)652364d423SThor Thayer static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr)
662364d423SThor Thayer {
672364d423SThor Thayer 	u32 value = readl(ioaddr);
682364d423SThor Thayer 
692364d423SThor Thayer 	value |= bit_mask;
702364d423SThor Thayer 	writel(value, ioaddr);
712364d423SThor Thayer }
722364d423SThor Thayer 
ecc_clear_bits(u32 bit_mask,void __iomem * ioaddr)732364d423SThor Thayer static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr)
742364d423SThor Thayer {
752364d423SThor Thayer 	u32 value = readl(ioaddr);
762364d423SThor Thayer 
772364d423SThor Thayer 	value &= ~bit_mask;
782364d423SThor Thayer 	writel(value, ioaddr);
792364d423SThor Thayer }
802364d423SThor Thayer 
ecc_test_bits(u32 bit_mask,void __iomem * ioaddr)812364d423SThor Thayer static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr)
822364d423SThor Thayer {
832364d423SThor Thayer 	u32 value = readl(ioaddr);
842364d423SThor Thayer 
852364d423SThor Thayer 	return (value & bit_mask) ? 1 : 0;
862364d423SThor Thayer }
872364d423SThor Thayer 
882364d423SThor Thayer /*
892364d423SThor Thayer  * This function uses the memory initialization block in the Arria10 ECC
902364d423SThor Thayer  * controller to initialize/clear the entire memory data and ECC data.
912364d423SThor Thayer  */
altr_init_memory_port(void __iomem * ioaddr)922364d423SThor Thayer static int altr_init_memory_port(void __iomem *ioaddr)
932364d423SThor Thayer {
942364d423SThor Thayer 	int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US;
952364d423SThor Thayer 
962364d423SThor Thayer 	ecc_set_bits(ALTR_A10_ECC_INITA, (ioaddr + ALTR_A10_ECC_CTRL_OFST));
972364d423SThor Thayer 	while (limit--) {
982364d423SThor Thayer 		if (ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
992364d423SThor Thayer 				  (ioaddr + ALTR_A10_ECC_INITSTAT_OFST)))
1002364d423SThor Thayer 			break;
1012364d423SThor Thayer 		udelay(1);
1022364d423SThor Thayer 	}
1032364d423SThor Thayer 	if (limit < 0)
1042364d423SThor Thayer 		return -EBUSY;
1052364d423SThor Thayer 
1062364d423SThor Thayer 	/* Clear any pending ECC interrupts */
1072364d423SThor Thayer 	writel(ALTR_A10_ECC_ERRPENA_MASK,
1082364d423SThor Thayer 	       (ioaddr + ALTR_A10_ECC_INTSTAT_OFST));
1092364d423SThor Thayer 
1102364d423SThor Thayer 	return 0;
1112364d423SThor Thayer }
1122364d423SThor Thayer 
socfpga_init_arria10_ocram_ecc(void)1132364d423SThor Thayer void socfpga_init_arria10_ocram_ecc(void)
1142364d423SThor Thayer {
1152364d423SThor Thayer 	struct device_node *np;
1162364d423SThor Thayer 	int ret = 0;
1172364d423SThor Thayer 	void __iomem *ecc_block_base;
1182364d423SThor Thayer 
1192364d423SThor Thayer 	if (!sys_manager_base_addr) {
1202364d423SThor Thayer 		pr_err("SOCFPGA: sys-mgr is not initialized\n");
1212364d423SThor Thayer 		return;
1222364d423SThor Thayer 	}
1232364d423SThor Thayer 
1242364d423SThor Thayer 	/* Find the OCRAM EDAC device tree node */
1252364d423SThor Thayer 	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-ocram-ecc");
1262364d423SThor Thayer 	if (!np) {
1272364d423SThor Thayer 		pr_err("Unable to find socfpga-a10-ocram-ecc\n");
1282364d423SThor Thayer 		return;
1292364d423SThor Thayer 	}
1302364d423SThor Thayer 
1312364d423SThor Thayer 	/* Map the ECC Block */
1322364d423SThor Thayer 	ecc_block_base = of_iomap(np, 0);
1332364d423SThor Thayer 	of_node_put(np);
1342364d423SThor Thayer 	if (!ecc_block_base) {
1352364d423SThor Thayer 		pr_err("Unable to map OCRAM ECC block\n");
1362364d423SThor Thayer 		return;
1372364d423SThor Thayer 	}
1382364d423SThor Thayer 
1392364d423SThor Thayer 	/* Disable ECC */
1402364d423SThor Thayer 	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
1412364d423SThor Thayer 	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_SET_OFST);
1422364d423SThor Thayer 	ecc_clear_bits(ALTR_A10_ECC_SERRINTEN,
1432364d423SThor Thayer 		       (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
1442364d423SThor Thayer 	ecc_clear_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
1452364d423SThor Thayer 		       (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
1462364d423SThor Thayer 
1472364d423SThor Thayer 	/* Ensure all writes complete */
1482364d423SThor Thayer 	wmb();
1492364d423SThor Thayer 
1502364d423SThor Thayer 	/* Use HW initialization block to initialize memory for ECC */
1512364d423SThor Thayer 	ret = altr_init_memory_port(ecc_block_base);
1522364d423SThor Thayer 	if (ret) {
1532364d423SThor Thayer 		pr_err("ECC: cannot init OCRAM PORTA memory\n");
1542364d423SThor Thayer 		goto exit;
1552364d423SThor Thayer 	}
1562364d423SThor Thayer 
1572364d423SThor Thayer 	/* Enable ECC */
1582364d423SThor Thayer 	ecc_set_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
1592364d423SThor Thayer 		     (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
1602364d423SThor Thayer 	ecc_set_bits(ALTR_A10_ECC_SERRINTEN,
1612364d423SThor Thayer 		     (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
1622364d423SThor Thayer 	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
1632364d423SThor Thayer 	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_CLR_OFST);
1642364d423SThor Thayer 
1652364d423SThor Thayer 	/* Ensure all writes complete */
1662364d423SThor Thayer 	wmb();
1672364d423SThor Thayer exit:
1682364d423SThor Thayer 	iounmap(ecc_block_base);
1692364d423SThor Thayer }
170