blob: 69711d98ce1b24df075faa826fad13132a7650c8 [file] [log] [blame]
Linus Walleij2306c332023-03-08 22:42:31 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Code borrowed from the Linux driver
4 * Copyright (C) 2015 Broadcom Corporation
5 */
6
7#include <common.h>
8#include <asm/io.h>
9#include <memalign.h>
10#include <nand.h>
11#include <linux/bitops.h>
12#include <linux/err.h>
13#include <linux/errno.h>
14#include <linux/io.h>
15#include <linux/ioport.h>
16#include <dm.h>
17
18#include "brcmnand.h"
19
20struct iproc_nand_soc {
21 struct brcmnand_soc soc;
22 void __iomem *idm_base;
23 void __iomem *ext_base;
24};
25
26#define IPROC_NAND_CTLR_READY_OFFSET 0x10
27#define IPROC_NAND_CTLR_READY BIT(0)
28
29#define IPROC_NAND_IO_CTRL_OFFSET 0x00
30#define IPROC_NAND_APB_LE_MODE BIT(24)
31#define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6)
32
33static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
34{
35 struct iproc_nand_soc *priv =
36 container_of(soc, struct iproc_nand_soc, soc);
37 void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
38 u32 val = brcmnand_readl(mmio);
39
40 if (val & IPROC_NAND_CTLR_READY) {
41 brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
42 return true;
43 }
44
45 return false;
46}
47
48static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
49{
50 struct iproc_nand_soc *priv =
51 container_of(soc, struct iproc_nand_soc, soc);
52 void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
53 u32 val = brcmnand_readl(mmio);
54
55 if (en)
56 val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
57 else
58 val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
59
60 brcmnand_writel(val, mmio);
61}
62
63static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
64 bool is_param)
65{
66 struct iproc_nand_soc *priv =
67 container_of(soc, struct iproc_nand_soc, soc);
68 void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
69 u32 val;
70
71 val = brcmnand_readl(mmio);
72
73 /*
74 * In the case of BE or when dealing with NAND data, always configure
75 * the APB bus to LE mode before accessing the FIFO and back to BE mode
76 * after the access is done
77 */
78 if (IS_ENABLED(CONFIG_SYS_BIG_ENDIAN) || !is_param) {
79 if (prepare)
80 val |= IPROC_NAND_APB_LE_MODE;
81 else
82 val &= ~IPROC_NAND_APB_LE_MODE;
83 } else { /* when in LE accessing the parameter page, keep APB in BE */
84 val &= ~IPROC_NAND_APB_LE_MODE;
85 }
86
87 brcmnand_writel(val, mmio);
88}
89
90static int iproc_nand_probe(struct udevice *dev)
91{
92 struct udevice *pdev = dev;
93 struct iproc_nand_soc *priv = dev_get_priv(dev);
94 struct brcmnand_soc *soc;
95 struct resource res;
96 int ret;
97
98 soc = &priv->soc;
99
100 ret = dev_read_resource_byname(pdev, "iproc-idm", &res);
101 if (ret)
102 return ret;
103
104 priv->idm_base = devm_ioremap(dev, res.start, resource_size(&res));
105 if (IS_ERR(priv->idm_base))
106 return PTR_ERR(priv->idm_base);
107
108 ret = dev_read_resource_byname(pdev, "iproc-ext", &res);
109 if (ret)
110 return ret;
111
112 priv->ext_base = devm_ioremap(dev, res.start, resource_size(&res));
113 if (IS_ERR(priv->ext_base))
114 return PTR_ERR(priv->ext_base);
115
116 soc->ctlrdy_ack = iproc_nand_intc_ack;
117 soc->ctlrdy_set_enabled = iproc_nand_intc_set;
118 soc->prepare_data_bus = iproc_nand_apb_access;
119
120 return brcmnand_probe(pdev, soc);
121}
122
123static const struct udevice_id iproc_nand_dt_ids[] = {
124 {
125 .compatible = "brcm,nand-iproc",
126 },
127 { /* sentinel */ }
128};
129
130U_BOOT_DRIVER(iproc_nand) = {
131 .name = "iproc-nand",
132 .id = UCLASS_MTD,
133 .of_match = iproc_nand_dt_ids,
134 .probe = iproc_nand_probe,
135 .priv_auto = sizeof(struct iproc_nand_soc),
136};
137
138void board_nand_init(void)
139{
140 struct udevice *dev;
141 int ret;
142
143 ret = uclass_get_device_by_driver(UCLASS_MTD,
144 DM_DRIVER_GET(iproc_nand), &dev);
145 if (ret && ret != -ENODEV)
146 pr_err("Failed to initialize %s. (error %d)\n", dev->name,
147 ret);
148}