blob: 585596c549b296b9a38114d988f7aa589a265cfb [file] [log] [blame]
Brian Norrisca22f042015-05-12 12:12:02 -07001/*
2 * Copyright © 2015 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/device.h>
15#include <linux/io.h>
16#include <linux/ioport.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22
23#include "brcmnand.h"
24
Brian Norrisa86c9472015-05-20 17:05:05 -070025struct iproc_nand_soc {
26 struct brcmnand_soc soc;
27
Brian Norrisca22f042015-05-12 12:12:02 -070028 void __iomem *idm_base;
29 void __iomem *ext_base;
30 spinlock_t idm_lock;
31};
32
33#define IPROC_NAND_CTLR_READY_OFFSET 0x10
34#define IPROC_NAND_CTLR_READY BIT(0)
35
36#define IPROC_NAND_IO_CTRL_OFFSET 0x00
37#define IPROC_NAND_APB_LE_MODE BIT(24)
38#define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6)
39
40static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
41{
Brian Norrisa86c9472015-05-20 17:05:05 -070042 struct iproc_nand_soc *priv =
43 container_of(soc, struct iproc_nand_soc, soc);
Brian Norrisca22f042015-05-12 12:12:02 -070044 void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
45 u32 val = brcmnand_readl(mmio);
46
47 if (val & IPROC_NAND_CTLR_READY) {
48 brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
49 return true;
50 }
51
52 return false;
53}
54
55static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
56{
Brian Norrisa86c9472015-05-20 17:05:05 -070057 struct iproc_nand_soc *priv =
58 container_of(soc, struct iproc_nand_soc, soc);
Brian Norrisca22f042015-05-12 12:12:02 -070059 void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
60 u32 val;
61 unsigned long flags;
62
63 spin_lock_irqsave(&priv->idm_lock, flags);
64
65 val = brcmnand_readl(mmio);
66
67 if (en)
68 val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
69 else
70 val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
71
72 brcmnand_writel(val, mmio);
73
74 spin_unlock_irqrestore(&priv->idm_lock, flags);
75}
76
77static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
78{
Brian Norrisa86c9472015-05-20 17:05:05 -070079 struct iproc_nand_soc *priv =
80 container_of(soc, struct iproc_nand_soc, soc);
Brian Norrisca22f042015-05-12 12:12:02 -070081 void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
82 u32 val;
83 unsigned long flags;
84
85 spin_lock_irqsave(&priv->idm_lock, flags);
86
87 val = brcmnand_readl(mmio);
88
89 if (prepare)
90 val |= IPROC_NAND_APB_LE_MODE;
91 else
92 val &= ~IPROC_NAND_APB_LE_MODE;
93
94 brcmnand_writel(val, mmio);
95
96 spin_unlock_irqrestore(&priv->idm_lock, flags);
97}
98
99static int iproc_nand_probe(struct platform_device *pdev)
100{
101 struct device *dev = &pdev->dev;
Brian Norrisa86c9472015-05-20 17:05:05 -0700102 struct iproc_nand_soc *priv;
Brian Norrisca22f042015-05-12 12:12:02 -0700103 struct brcmnand_soc *soc;
104 struct resource *res;
105
Brian Norrisca22f042015-05-12 12:12:02 -0700106 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
107 if (!priv)
108 return -ENOMEM;
Brian Norrisa86c9472015-05-20 17:05:05 -0700109 soc = &priv->soc;
Brian Norrisca22f042015-05-12 12:12:02 -0700110
111 spin_lock_init(&priv->idm_lock);
112
113 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
114 priv->idm_base = devm_ioremap_resource(dev, res);
115 if (IS_ERR(priv->idm_base))
116 return PTR_ERR(priv->idm_base);
117
118 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
119 priv->ext_base = devm_ioremap_resource(dev, res);
120 if (IS_ERR(priv->ext_base))
121 return PTR_ERR(priv->ext_base);
122
Brian Norrisca22f042015-05-12 12:12:02 -0700123 soc->ctlrdy_ack = iproc_nand_intc_ack;
124 soc->ctlrdy_set_enabled = iproc_nand_intc_set;
125 soc->prepare_data_bus = iproc_nand_apb_access;
126
127 return brcmnand_probe(pdev, soc);
128}
129
130static const struct of_device_id iproc_nand_of_match[] = {
131 { .compatible = "brcm,nand-iproc" },
132 {},
133};
134MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
135
136static struct platform_driver iproc_nand_driver = {
137 .probe = iproc_nand_probe,
138 .remove = brcmnand_remove,
139 .driver = {
140 .name = "iproc_nand",
141 .pm = &brcmnand_pm_ops,
142 .of_match_table = iproc_nand_of_match,
143 }
144};
145module_platform_driver(iproc_nand_driver);
146
147MODULE_LICENSE("GPL v2");
148MODULE_AUTHOR("Brian Norris");
149MODULE_AUTHOR("Ray Jui");
150MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");