162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright Altera Corporation (C) 2016. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/io.h>
662306a36Sopenharmony_ci#include <linux/of.h>
762306a36Sopenharmony_ci#include <linux/of_address.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "core.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* A10 System Manager L2 ECC Control register */
1262306a36Sopenharmony_ci#define A10_MPU_CTRL_L2_ECC_OFST          0x0
1362306a36Sopenharmony_ci#define A10_MPU_CTRL_L2_ECC_EN            BIT(0)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* A10 System Manager Global IRQ Mask register */
1662306a36Sopenharmony_ci#define A10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
1762306a36Sopenharmony_ci#define A10_SYSMGR_ECC_INTMASK_CLR_L2     BIT(0)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* A10 System Manager L2 ECC IRQ Clear register */
2062306a36Sopenharmony_ci#define A10_SYSMGR_MPU_CLEAR_L2_ECC_OFST  0xA8
2162306a36Sopenharmony_ci#define A10_SYSMGR_MPU_CLEAR_L2_ECC       (BIT(31) | BIT(15))
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid socfpga_init_l2_ecc(void)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct device_node *np;
2662306a36Sopenharmony_ci	void __iomem *mapped_l2_edac_addr;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-l2-ecc");
2962306a36Sopenharmony_ci	if (!np) {
3062306a36Sopenharmony_ci		pr_err("Unable to find socfpga-l2-ecc in dtb\n");
3162306a36Sopenharmony_ci		return;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	mapped_l2_edac_addr = of_iomap(np, 0);
3562306a36Sopenharmony_ci	of_node_put(np);
3662306a36Sopenharmony_ci	if (!mapped_l2_edac_addr) {
3762306a36Sopenharmony_ci		pr_err("Unable to find L2 ECC mapping in dtb\n");
3862306a36Sopenharmony_ci		return;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/* Enable ECC */
4262306a36Sopenharmony_ci	writel(0x01, mapped_l2_edac_addr);
4362306a36Sopenharmony_ci	iounmap(mapped_l2_edac_addr);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_civoid socfpga_init_arria10_l2_ecc(void)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct device_node *np;
4962306a36Sopenharmony_ci	void __iomem *mapped_l2_edac_addr;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Find the L2 EDAC device tree node */
5262306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-l2-ecc");
5362306a36Sopenharmony_ci	if (!np) {
5462306a36Sopenharmony_ci		pr_err("Unable to find socfpga-a10-l2-ecc in dtb\n");
5562306a36Sopenharmony_ci		return;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	mapped_l2_edac_addr = of_iomap(np, 0);
5962306a36Sopenharmony_ci	of_node_put(np);
6062306a36Sopenharmony_ci	if (!mapped_l2_edac_addr) {
6162306a36Sopenharmony_ci		pr_err("Unable to find L2 ECC mapping in dtb\n");
6262306a36Sopenharmony_ci		return;
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (!sys_manager_base_addr) {
6662306a36Sopenharmony_ci		pr_err("System Manager not mapped for L2 ECC\n");
6762306a36Sopenharmony_ci		goto exit;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	/* Clear any pending IRQs */
7062306a36Sopenharmony_ci	writel(A10_SYSMGR_MPU_CLEAR_L2_ECC, (sys_manager_base_addr +
7162306a36Sopenharmony_ci	       A10_SYSMGR_MPU_CLEAR_L2_ECC_OFST));
7262306a36Sopenharmony_ci	/* Enable ECC */
7362306a36Sopenharmony_ci	writel(A10_SYSMGR_ECC_INTMASK_CLR_L2, sys_manager_base_addr +
7462306a36Sopenharmony_ci	       A10_SYSMGR_ECC_INTMASK_CLR_OFST);
7562306a36Sopenharmony_ci	writel(A10_MPU_CTRL_L2_ECC_EN, mapped_l2_edac_addr +
7662306a36Sopenharmony_ci	       A10_MPU_CTRL_L2_ECC_OFST);
7762306a36Sopenharmony_ciexit:
7862306a36Sopenharmony_ci	iounmap(mapped_l2_edac_addr);
7962306a36Sopenharmony_ci}
80