uboot/drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2
   3#include <common.h>
   4#include <asm/io.h>
   5#include <memalign.h>
   6#include <nand.h>
   7#include <linux/errno.h>
   8#include <linux/io.h>
   9#include <linux/ioport.h>
  10#include <dm.h>
  11
  12#include "brcmnand.h"
  13
  14struct bcm6838_nand_soc {
  15        struct brcmnand_soc soc;
  16        void __iomem *base;
  17};
  18
  19#define BCM6838_NAND_INT                0x00
  20#define  BCM6838_NAND_STATUS_SHIFT      0
  21#define  BCM6838_NAND_STATUS_MASK       (0xfff << BCM6838_NAND_STATUS_SHIFT)
  22#define  BCM6838_NAND_ENABLE_SHIFT      16
  23#define  BCM6838_NAND_ENABLE_MASK       (0xffff << BCM6838_NAND_ENABLE_SHIFT)
  24
  25enum {
  26        BCM6838_NP_READ         = BIT(0),
  27        BCM6838_BLOCK_ERASE     = BIT(1),
  28        BCM6838_COPY_BACK       = BIT(2),
  29        BCM6838_PAGE_PGM        = BIT(3),
  30        BCM6838_CTRL_READY      = BIT(4),
  31        BCM6838_DEV_RBPIN       = BIT(5),
  32        BCM6838_ECC_ERR_UNC     = BIT(6),
  33        BCM6838_ECC_ERR_CORR    = BIT(7),
  34};
  35
  36static bool bcm6838_nand_intc_ack(struct brcmnand_soc *soc)
  37{
  38        struct bcm6838_nand_soc *priv =
  39                        container_of(soc, struct bcm6838_nand_soc, soc);
  40        void __iomem *mmio = priv->base + BCM6838_NAND_INT;
  41        u32 val = brcmnand_readl(mmio);
  42
  43        if (val & (BCM6838_CTRL_READY << BCM6838_NAND_STATUS_SHIFT)) {
  44                /* Ack interrupt */
  45                val &= ~BCM6838_NAND_STATUS_MASK;
  46                val |= BCM6838_CTRL_READY << BCM6838_NAND_STATUS_SHIFT;
  47                brcmnand_writel(val, mmio);
  48                return true;
  49        }
  50
  51        return false;
  52}
  53
  54static void bcm6838_nand_intc_set(struct brcmnand_soc *soc, bool en)
  55{
  56        struct bcm6838_nand_soc *priv =
  57                        container_of(soc, struct bcm6838_nand_soc, soc);
  58        void __iomem *mmio = priv->base + BCM6838_NAND_INT;
  59        u32 val = brcmnand_readl(mmio);
  60
  61        /* Don't ack any interrupts */
  62        val &= ~BCM6838_NAND_STATUS_MASK;
  63
  64        if (en)
  65                val |= BCM6838_CTRL_READY << BCM6838_NAND_ENABLE_SHIFT;
  66        else
  67                val &= ~(BCM6838_CTRL_READY << BCM6838_NAND_ENABLE_SHIFT);
  68
  69        brcmnand_writel(val, mmio);
  70}
  71
  72static int bcm6838_nand_probe(struct udevice *dev)
  73{
  74        struct udevice *pdev = dev;
  75        struct bcm6838_nand_soc *priv = dev_get_priv(dev);
  76        struct brcmnand_soc *soc;
  77        struct resource res;
  78
  79        soc = &priv->soc;
  80
  81        dev_read_resource_byname(pdev, "nand-int-base", &res);
  82        priv->base = ioremap(res.start, resource_size(&res));
  83        if (IS_ERR(priv->base))
  84                return PTR_ERR(priv->base);
  85
  86        soc->ctlrdy_ack = bcm6838_nand_intc_ack;
  87        soc->ctlrdy_set_enabled = bcm6838_nand_intc_set;
  88
  89        /* Disable and ack all interrupts  */
  90        brcmnand_writel(0, priv->base + BCM6838_NAND_INT);
  91        brcmnand_writel(BCM6838_NAND_STATUS_MASK,
  92                        priv->base + BCM6838_NAND_INT);
  93
  94        return brcmnand_probe(pdev, soc);
  95}
  96
  97static const struct udevice_id bcm6838_nand_dt_ids[] = {
  98        {
  99                .compatible = "brcm,nand-bcm6838",
 100        },
 101        { /* sentinel */ }
 102};
 103
 104U_BOOT_DRIVER(bcm6838_nand) = {
 105        .name = "bcm6838-nand",
 106        .id = UCLASS_MTD,
 107        .of_match = bcm6838_nand_dt_ids,
 108        .probe = bcm6838_nand_probe,
 109        .priv_auto_alloc_size = sizeof(struct bcm6838_nand_soc),
 110};
 111
 112void board_nand_init(void)
 113{
 114        struct udevice *dev;
 115        int ret;
 116
 117        ret = uclass_get_device_by_driver(UCLASS_MTD,
 118                                          DM_GET_DRIVER(bcm6838_nand), &dev);
 119        if (ret && ret != -ENODEV)
 120                pr_err("Failed to initialize %s. (error %d)\n", dev->name,
 121                       ret);
 122}
 123