uboot/drivers/mtd/nand/raw/brcmnand/bcm68360_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 bcm68360_nand_soc {
  16        struct brcmnand_soc soc;
  17        void __iomem *base;
  18};
  19
  20#define BCM68360_NAND_INT               0x00
  21#define BCM68360_NAND_STATUS_SHIFT      0
  22#define BCM68360_NAND_STATUS_MASK       (0xfff << BCM68360_NAND_STATUS_SHIFT)
  23
  24#define BCM68360_NAND_INT_EN            0x04
  25#define BCM68360_NAND_ENABLE_SHIFT      0
  26#define BCM68360_NAND_ENABLE_MASK       (0xffff << BCM68360_NAND_ENABLE_SHIFT)
  27
  28enum {
  29        BCM68360_NP_READ                = BIT(0),
  30        BCM68360_BLOCK_ERASE    = BIT(1),
  31        BCM68360_COPY_BACK      = BIT(2),
  32        BCM68360_PAGE_PGM       = BIT(3),
  33        BCM68360_CTRL_READY     = BIT(4),
  34        BCM68360_DEV_RBPIN      = BIT(5),
  35        BCM68360_ECC_ERR_UNC    = BIT(6),
  36        BCM68360_ECC_ERR_CORR   = BIT(7),
  37};
  38
  39static bool bcm68360_nand_intc_ack(struct brcmnand_soc *soc)
  40{
  41        struct bcm68360_nand_soc *priv =
  42                        container_of(soc, struct bcm68360_nand_soc, soc);
  43        void __iomem *mmio = priv->base + BCM68360_NAND_INT;
  44        u32 val = brcmnand_readl(mmio);
  45
  46        if (val & (BCM68360_CTRL_READY << BCM68360_NAND_STATUS_SHIFT)) {
  47                /* Ack interrupt */
  48                val &= ~BCM68360_NAND_STATUS_MASK;
  49                val |= BCM68360_CTRL_READY << BCM68360_NAND_STATUS_SHIFT;
  50                brcmnand_writel(val, mmio);
  51                return true;
  52        }
  53
  54        return false;
  55}
  56
  57static void bcm68360_nand_intc_set(struct brcmnand_soc *soc, bool en)
  58{
  59        struct bcm68360_nand_soc *priv =
  60                        container_of(soc, struct bcm68360_nand_soc, soc);
  61        void __iomem *mmio = priv->base + BCM68360_NAND_INT_EN;
  62        u32 val = brcmnand_readl(mmio);
  63
  64        /* Don't ack any interrupts */
  65        val &= ~BCM68360_NAND_STATUS_MASK;
  66
  67        if (en)
  68                val |= BCM68360_CTRL_READY << BCM68360_NAND_ENABLE_SHIFT;
  69        else
  70                val &= ~(BCM68360_CTRL_READY << BCM68360_NAND_ENABLE_SHIFT);
  71
  72        brcmnand_writel(val, mmio);
  73}
  74
  75static int bcm68360_nand_probe(struct udevice *dev)
  76{
  77        struct udevice *pdev = dev;
  78        struct bcm68360_nand_soc *priv = dev_get_priv(dev);
  79        struct brcmnand_soc *soc;
  80        struct resource res;
  81
  82        soc = &priv->soc;
  83
  84        dev_read_resource_byname(pdev, "nand-int-base", &res);
  85        priv->base = devm_ioremap(dev, res.start, resource_size(&res));
  86        if (IS_ERR(priv->base))
  87                return PTR_ERR(priv->base);
  88
  89        soc->ctlrdy_ack = bcm68360_nand_intc_ack;
  90        soc->ctlrdy_set_enabled = bcm68360_nand_intc_set;
  91
  92        /* Disable and ack all interrupts  */
  93        brcmnand_writel(0, priv->base + BCM68360_NAND_INT_EN);
  94        brcmnand_writel(0, priv->base + BCM68360_NAND_INT);
  95
  96        return brcmnand_probe(pdev, soc);
  97}
  98
  99static const struct udevice_id bcm68360_nand_dt_ids[] = {
 100        {
 101                .compatible = "brcm,nand-bcm68360",
 102        },
 103        { /* sentinel */ }
 104};
 105
 106U_BOOT_DRIVER(bcm68360_nand) = {
 107        .name = "bcm68360-nand",
 108        .id = UCLASS_MTD,
 109        .of_match = bcm68360_nand_dt_ids,
 110        .probe = bcm68360_nand_probe,
 111        .priv_auto      = sizeof(struct bcm68360_nand_soc),
 112};
 113
 114void board_nand_init(void)
 115{
 116        struct udevice *dev;
 117        int ret;
 118
 119        ret = uclass_get_device_by_driver(UCLASS_MTD,
 120                                          DM_DRIVER_GET(bcm68360_nand), &dev);
 121        if (ret && ret != -ENODEV)
 122                pr_err("Failed to initialize %s. (error %d)\n", dev->name,
 123                       ret);
 124}
 125