linux/arch/arm/mach-socfpga/ocram.c
<<
>>
Prefs
   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}
 183