Linux Audio

Check our new training course

Loading...
v4.10.11
 
  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
 28void 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
 78static 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
 86static 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
 94static 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 */
105static 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
126void 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();
180exit:
181	iounmap(ecc_block_base);
182}
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright Altera Corporation (C) 2016. All rights reserved.
 
 
 
 
 
 
 
 
 
 
 
 
  4 */
  5#include <linux/delay.h>
  6#include <linux/io.h>
  7#include <linux/of.h>
 
  8#include <linux/of_address.h>
 
  9
 10#include "core.h"
 11
 12#define ALTR_OCRAM_CLEAR_ECC          0x00000018
 13#define ALTR_OCRAM_ECC_EN             0x00000019
 14
 15void socfpga_init_ocram_ecc(void)
 16{
 17	struct device_node *np;
 18	void __iomem *mapped_ocr_edac_addr;
 19
 20	/* Find the OCRAM EDAC device tree node */
 21	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc");
 22	if (!np) {
 23		pr_err("Unable to find socfpga-ocram-ecc\n");
 24		return;
 25	}
 26
 27	mapped_ocr_edac_addr = of_iomap(np, 0);
 28	of_node_put(np);
 29	if (!mapped_ocr_edac_addr) {
 30		pr_err("Unable to map OCRAM ecc regs.\n");
 31		return;
 32	}
 33
 34	/* Clear any pending OCRAM ECC interrupts, then enable ECC */
 35	writel(ALTR_OCRAM_CLEAR_ECC, mapped_ocr_edac_addr);
 36	writel(ALTR_OCRAM_ECC_EN, mapped_ocr_edac_addr);
 37
 38	iounmap(mapped_ocr_edac_addr);
 39}
 40
 41/* Arria10 OCRAM Section */
 42#define ALTR_A10_ECC_CTRL_OFST          0x08
 43#define ALTR_A10_OCRAM_ECC_EN_CTL       (BIT(1) | BIT(0))
 44#define ALTR_A10_ECC_INITA              BIT(16)
 45
 46#define ALTR_A10_ECC_INITSTAT_OFST      0x0C
 47#define ALTR_A10_ECC_INITCOMPLETEA      BIT(0)
 48#define ALTR_A10_ECC_INITCOMPLETEB      BIT(8)
 49
 50#define ALTR_A10_ECC_ERRINTEN_OFST      0x10
 51#define ALTR_A10_ECC_SERRINTEN          BIT(0)
 52
 53#define ALTR_A10_ECC_INTSTAT_OFST       0x20
 54#define ALTR_A10_ECC_SERRPENA           BIT(0)
 55#define ALTR_A10_ECC_DERRPENA           BIT(8)
 56#define ALTR_A10_ECC_ERRPENA_MASK       (ALTR_A10_ECC_SERRPENA | \
 57					 ALTR_A10_ECC_DERRPENA)
 58/* ECC Manager Defines */
 59#define A10_SYSMGR_ECC_INTMASK_SET_OFST   0x94
 60#define A10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
 61#define A10_SYSMGR_ECC_INTMASK_OCRAM      BIT(1)
 62
 63#define ALTR_A10_ECC_INIT_WATCHDOG_10US   10000
 64
 65static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr)
 66{
 67	u32 value = readl(ioaddr);
 68
 69	value |= bit_mask;
 70	writel(value, ioaddr);
 71}
 72
 73static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr)
 74{
 75	u32 value = readl(ioaddr);
 76
 77	value &= ~bit_mask;
 78	writel(value, ioaddr);
 79}
 80
 81static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr)
 82{
 83	u32 value = readl(ioaddr);
 84
 85	return (value & bit_mask) ? 1 : 0;
 86}
 87
 88/*
 89 * This function uses the memory initialization block in the Arria10 ECC
 90 * controller to initialize/clear the entire memory data and ECC data.
 91 */
 92static int altr_init_memory_port(void __iomem *ioaddr)
 93{
 94	int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US;
 95
 96	ecc_set_bits(ALTR_A10_ECC_INITA, (ioaddr + ALTR_A10_ECC_CTRL_OFST));
 97	while (limit--) {
 98		if (ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
 99				  (ioaddr + ALTR_A10_ECC_INITSTAT_OFST)))
100			break;
101		udelay(1);
102	}
103	if (limit < 0)
104		return -EBUSY;
105
106	/* Clear any pending ECC interrupts */
107	writel(ALTR_A10_ECC_ERRPENA_MASK,
108	       (ioaddr + ALTR_A10_ECC_INTSTAT_OFST));
109
110	return 0;
111}
112
113void socfpga_init_arria10_ocram_ecc(void)
114{
115	struct device_node *np;
116	int ret = 0;
117	void __iomem *ecc_block_base;
118
119	if (!sys_manager_base_addr) {
120		pr_err("SOCFPGA: sys-mgr is not initialized\n");
121		return;
122	}
123
124	/* Find the OCRAM EDAC device tree node */
125	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-ocram-ecc");
126	if (!np) {
127		pr_err("Unable to find socfpga-a10-ocram-ecc\n");
128		return;
129	}
130
131	/* Map the ECC Block */
132	ecc_block_base = of_iomap(np, 0);
133	of_node_put(np);
134	if (!ecc_block_base) {
135		pr_err("Unable to map OCRAM ECC block\n");
136		return;
137	}
138
139	/* Disable ECC */
140	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
141	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_SET_OFST);
142	ecc_clear_bits(ALTR_A10_ECC_SERRINTEN,
143		       (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
144	ecc_clear_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
145		       (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
146
147	/* Ensure all writes complete */
148	wmb();
149
150	/* Use HW initialization block to initialize memory for ECC */
151	ret = altr_init_memory_port(ecc_block_base);
152	if (ret) {
153		pr_err("ECC: cannot init OCRAM PORTA memory\n");
154		goto exit;
155	}
156
157	/* Enable ECC */
158	ecc_set_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
159		     (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
160	ecc_set_bits(ALTR_A10_ECC_SERRINTEN,
161		     (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
162	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
163	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_CLR_OFST);
164
165	/* Ensure all writes complete */
166	wmb();
167exit:
168	iounmap(ecc_block_base);
169}