cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ocram.c (4458B)


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