uboot/drivers/mtd/nand/raw/brcmnand/bcm6368_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/bitops.h>
   8#include <linux/errno.h>
   9#include <linux/io.h>
  10#include <linux/ioport.h>
  11#include <dm.h>
  12
  13#include "brcmnand.h"
  14
  15struct bcm6368_nand_soc {
  16        struct brcmnand_soc soc;
  17        void __iomem *base;
  18};
  19
  20#define soc_to_priv(_soc) container_of(_soc, struct bcm6368_nand_soc, soc)
  21
  22#define BCM6368_NAND_INT                0x00
  23#define  BCM6368_NAND_STATUS_SHIFT      0
  24#define  BCM6368_NAND_STATUS_MASK       (0xfff << BCM6368_NAND_STATUS_SHIFT)
  25#define  BCM6368_NAND_ENABLE_SHIFT      16
  26#define  BCM6368_NAND_ENABLE_MASK       (0xffff << BCM6368_NAND_ENABLE_SHIFT)
  27
  28enum {
  29        BCM6368_NP_READ         = BIT(0),
  30        BCM6368_BLOCK_ERASE     = BIT(1),
  31        BCM6368_COPY_BACK       = BIT(2),
  32        BCM6368_PAGE_PGM        = BIT(3),
  33        BCM6368_CTRL_READY      = BIT(4),
  34        BCM6368_DEV_RBPIN       = BIT(5),
  35        BCM6368_ECC_ERR_UNC     = BIT(6),
  36        BCM6368_ECC_ERR_CORR    = BIT(7),
  37};
  38
  39static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
  40{
  41        struct bcm6368_nand_soc *priv = soc_to_priv(soc);
  42        void __iomem *mmio = priv->base + BCM6368_NAND_INT;
  43        u32 val = brcmnand_readl(mmio);
  44
  45        if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
  46                /* Ack interrupt */
  47                val &= ~BCM6368_NAND_STATUS_MASK;
  48                val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
  49                brcmnand_writel(val, mmio);
  50                return true;
  51        }
  52
  53        return false;
  54}
  55
  56static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
  57{
  58        struct bcm6368_nand_soc *priv = soc_to_priv(soc);
  59        void __iomem *mmio = priv->base + BCM6368_NAND_INT;
  60        u32 val = brcmnand_readl(mmio);
  61
  62        /* Don't ack any interrupts */
  63        val &= ~BCM6368_NAND_STATUS_MASK;
  64
  65        if (en)
  66                val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
  67        else
  68                val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
  69
  70        brcmnand_writel(val, mmio);
  71}
  72
  73static int bcm6368_nand_probe(struct udevice *dev)
  74{
  75        struct bcm6368_nand_soc *priv = dev_get_priv(dev);
  76        struct brcmnand_soc *soc = &priv->soc;
  77
  78        priv->base = dev_remap_addr_name(dev, "nand-int-base");
  79        if (!priv->base)
  80                return -EINVAL;
  81
  82        soc->ctlrdy_ack = bcm6368_nand_intc_ack;
  83        soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
  84
  85        /* Disable and ack all interrupts  */
  86        brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
  87        brcmnand_writel(BCM6368_NAND_STATUS_MASK,
  88                        priv->base + BCM6368_NAND_INT);
  89
  90        return brcmnand_probe(dev, soc);
  91}
  92
  93static const struct udevice_id bcm6368_nand_dt_ids[] = {
  94        {
  95                .compatible = "brcm,nand-bcm6368",
  96        },
  97        { /* sentinel */ }
  98};
  99
 100U_BOOT_DRIVER(bcm6368_nand) = {
 101        .name = "bcm6368-nand",
 102        .id = UCLASS_MTD,
 103        .of_match = bcm6368_nand_dt_ids,
 104        .probe = bcm6368_nand_probe,
 105        .priv_auto_alloc_size = sizeof(struct bcm6368_nand_soc),
 106};
 107
 108void board_nand_init(void)
 109{
 110        struct udevice *dev;
 111        int ret;
 112
 113        ret = uclass_get_device_by_driver(UCLASS_MTD,
 114                                          DM_GET_DRIVER(bcm6368_nand), &dev);
 115        if (ret && ret != -ENODEV)
 116                pr_err("Failed to initialize %s. (error %d)\n", dev->name,
 117                       ret);
 118}
 119