Merge remote-tracking branch 'omap_dss2/for-next'
[deliverable/linux.git] / drivers / mtd / nand / brcmnand / iproc_nand.c
CommitLineData
ca22f040
BN
1/*
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
a86c947b
BN
25struct iproc_nand_soc {
26 struct brcmnand_soc soc;
27
ca22f040
BN
28 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{
a86c947b
BN
42 struct iproc_nand_soc *priv =
43 container_of(soc, struct iproc_nand_soc, soc);
ca22f040
BN
44 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{
a86c947b
BN
57 struct iproc_nand_soc *priv =
58 container_of(soc, struct iproc_nand_soc, soc);
ca22f040
BN
59 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
d31b5d80
RJ
77static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
78 bool is_param)
ca22f040 79{
a86c947b
BN
80 struct iproc_nand_soc *priv =
81 container_of(soc, struct iproc_nand_soc, soc);
ca22f040
BN
82 void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
83 u32 val;
84 unsigned long flags;
85
86 spin_lock_irqsave(&priv->idm_lock, flags);
87
88 val = brcmnand_readl(mmio);
89
d31b5d80
RJ
90 /*
91 * In the case of BE or when dealing with NAND data, alway configure
92 * the APB bus to LE mode before accessing the FIFO and back to BE mode
93 * after the access is done
94 */
95 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
96 if (prepare)
97 val |= IPROC_NAND_APB_LE_MODE;
98 else
99 val &= ~IPROC_NAND_APB_LE_MODE;
100 } else { /* when in LE accessing the parameter page, keep APB in BE */
ca22f040 101 val &= ~IPROC_NAND_APB_LE_MODE;
d31b5d80 102 }
ca22f040
BN
103
104 brcmnand_writel(val, mmio);
105
106 spin_unlock_irqrestore(&priv->idm_lock, flags);
107}
108
109static int iproc_nand_probe(struct platform_device *pdev)
110{
111 struct device *dev = &pdev->dev;
a86c947b 112 struct iproc_nand_soc *priv;
ca22f040
BN
113 struct brcmnand_soc *soc;
114 struct resource *res;
115
ca22f040
BN
116 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
117 if (!priv)
118 return -ENOMEM;
a86c947b 119 soc = &priv->soc;
ca22f040
BN
120
121 spin_lock_init(&priv->idm_lock);
122
123 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
124 priv->idm_base = devm_ioremap_resource(dev, res);
125 if (IS_ERR(priv->idm_base))
126 return PTR_ERR(priv->idm_base);
127
128 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
129 priv->ext_base = devm_ioremap_resource(dev, res);
130 if (IS_ERR(priv->ext_base))
131 return PTR_ERR(priv->ext_base);
132
ca22f040
BN
133 soc->ctlrdy_ack = iproc_nand_intc_ack;
134 soc->ctlrdy_set_enabled = iproc_nand_intc_set;
135 soc->prepare_data_bus = iproc_nand_apb_access;
136
137 return brcmnand_probe(pdev, soc);
138}
139
140static const struct of_device_id iproc_nand_of_match[] = {
141 { .compatible = "brcm,nand-iproc" },
142 {},
143};
144MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
145
146static struct platform_driver iproc_nand_driver = {
147 .probe = iproc_nand_probe,
148 .remove = brcmnand_remove,
149 .driver = {
150 .name = "iproc_nand",
151 .pm = &brcmnand_pm_ops,
152 .of_match_table = iproc_nand_of_match,
153 }
154};
155module_platform_driver(iproc_nand_driver);
156
157MODULE_LICENSE("GPL v2");
158MODULE_AUTHOR("Brian Norris");
159MODULE_AUTHOR("Ray Jui");
160MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
This page took 0.076876 seconds and 5 git commands to generate.