1// SPDX-License-Identifier: GPL-2.0
2/*
3 * NAND Flash Controller Device Driver for DT
4 *
5 * Copyright © 2011, Picochip.
6 */
7
8#include <linux/clk.h>
9#include <linux/delay.h>
10#include <linux/err.h>
11#include <linux/io.h>
12#include <linux/ioport.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/of_device.h>
17#include <linux/platform_device.h>
18#include <linux/reset.h>
19
20#include "denali.h"
21
22struct denali_dt {
23	struct denali_controller controller;
24	struct clk *clk;	/* core clock */
25	struct clk *clk_x;	/* bus interface clock */
26	struct clk *clk_ecc;	/* ECC circuit clock */
27	struct reset_control *rst;	/* core reset */
28	struct reset_control *rst_reg;	/* register reset */
29};
30
31struct denali_dt_data {
32	unsigned int revision;
33	unsigned int caps;
34	unsigned int oob_skip_bytes;
35	const struct nand_ecc_caps *ecc_caps;
36};
37
38NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
39		     512, 8, 15);
40static const struct denali_dt_data denali_socfpga_data = {
41	.caps = DENALI_CAP_HW_ECC_FIXUP,
42	.oob_skip_bytes = 2,
43	.ecc_caps = &denali_socfpga_ecc_caps,
44};
45
46NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
47		     1024, 8, 16, 24);
48static const struct denali_dt_data denali_uniphier_v5a_data = {
49	.caps = DENALI_CAP_HW_ECC_FIXUP |
50		DENALI_CAP_DMA_64BIT,
51	.oob_skip_bytes = 8,
52	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
53};
54
55NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
56		     1024, 8, 16);
57static const struct denali_dt_data denali_uniphier_v5b_data = {
58	.revision = 0x0501,
59	.caps = DENALI_CAP_HW_ECC_FIXUP |
60		DENALI_CAP_DMA_64BIT,
61	.oob_skip_bytes = 8,
62	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
63};
64
65static const struct of_device_id denali_nand_dt_ids[] = {
66	{
67		.compatible = "altr,socfpga-denali-nand",
68		.data = &denali_socfpga_data,
69	},
70	{
71		.compatible = "socionext,uniphier-denali-nand-v5a",
72		.data = &denali_uniphier_v5a_data,
73	},
74	{
75		.compatible = "socionext,uniphier-denali-nand-v5b",
76		.data = &denali_uniphier_v5b_data,
77	},
78	{ /* sentinel */ }
79};
80MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
81
82static int denali_dt_chip_init(struct denali_controller *denali,
83			       struct device_node *chip_np)
84{
85	struct denali_chip *dchip;
86	u32 bank;
87	int nsels, i, ret;
88
89	nsels = of_property_count_u32_elems(chip_np, "reg");
90	if (nsels < 0)
91		return nsels;
92
93	dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
94			     GFP_KERNEL);
95	if (!dchip)
96		return -ENOMEM;
97
98	dchip->nsels = nsels;
99
100	for (i = 0; i < nsels; i++) {
101		ret = of_property_read_u32_index(chip_np, "reg", i, &bank);
102		if (ret)
103			return ret;
104
105		dchip->sels[i].bank = bank;
106
107		nand_set_flash_node(&dchip->chip, chip_np);
108	}
109
110	return denali_chip_init(denali, dchip);
111}
112
113static int denali_dt_probe(struct platform_device *pdev)
114{
115	struct device *dev = &pdev->dev;
116	struct resource *res;
117	struct denali_dt *dt;
118	const struct denali_dt_data *data;
119	struct denali_controller *denali;
120	struct device_node *np;
121	int ret;
122
123	dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
124	if (!dt)
125		return -ENOMEM;
126	denali = &dt->controller;
127
128	data = of_device_get_match_data(dev);
129	if (WARN_ON(!data))
130		return -EINVAL;
131
132	denali->revision = data->revision;
133	denali->caps = data->caps;
134	denali->oob_skip_bytes = data->oob_skip_bytes;
135	denali->ecc_caps = data->ecc_caps;
136
137	denali->dev = dev;
138	denali->irq = platform_get_irq(pdev, 0);
139	if (denali->irq < 0)
140		return denali->irq;
141
142	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
143	denali->reg = devm_ioremap_resource(dev, res);
144	if (IS_ERR(denali->reg))
145		return PTR_ERR(denali->reg);
146
147	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
148	denali->host = devm_ioremap_resource(dev, res);
149	if (IS_ERR(denali->host))
150		return PTR_ERR(denali->host);
151
152	dt->clk = devm_clk_get(dev, "nand");
153	if (IS_ERR(dt->clk))
154		return PTR_ERR(dt->clk);
155
156	dt->clk_x = devm_clk_get(dev, "nand_x");
157	if (IS_ERR(dt->clk_x))
158		return PTR_ERR(dt->clk_x);
159
160	dt->clk_ecc = devm_clk_get(dev, "ecc");
161	if (IS_ERR(dt->clk_ecc))
162		return PTR_ERR(dt->clk_ecc);
163
164	dt->rst = devm_reset_control_get_optional_shared(dev, "nand");
165	if (IS_ERR(dt->rst))
166		return PTR_ERR(dt->rst);
167
168	dt->rst_reg = devm_reset_control_get_optional_shared(dev, "reg");
169	if (IS_ERR(dt->rst_reg))
170		return PTR_ERR(dt->rst_reg);
171
172	ret = clk_prepare_enable(dt->clk);
173	if (ret)
174		return ret;
175
176	ret = clk_prepare_enable(dt->clk_x);
177	if (ret)
178		goto out_disable_clk;
179
180	ret = clk_prepare_enable(dt->clk_ecc);
181	if (ret)
182		goto out_disable_clk_x;
183
184	denali->clk_rate = clk_get_rate(dt->clk);
185	denali->clk_x_rate = clk_get_rate(dt->clk_x);
186
187	/*
188	 * Deassert the register reset, and the core reset in this order.
189	 * Deasserting the core reset while the register reset is asserted
190	 * will cause unpredictable behavior in the controller.
191	 */
192	ret = reset_control_deassert(dt->rst_reg);
193	if (ret)
194		goto out_disable_clk_ecc;
195
196	ret = reset_control_deassert(dt->rst);
197	if (ret)
198		goto out_assert_rst_reg;
199
200	/*
201	 * When the reset is deasserted, the initialization sequence is kicked
202	 * (bootstrap process). The driver must wait until it finished.
203	 * Otherwise, it will result in unpredictable behavior.
204	 */
205	usleep_range(200, 1000);
206
207	ret = denali_init(denali);
208	if (ret)
209		goto out_assert_rst;
210
211	for_each_child_of_node(dev->of_node, np) {
212		ret = denali_dt_chip_init(denali, np);
213		if (ret) {
214			of_node_put(np);
215			goto out_remove_denali;
216		}
217	}
218
219	platform_set_drvdata(pdev, dt);
220
221	return 0;
222
223out_remove_denali:
224	denali_remove(denali);
225out_assert_rst:
226	reset_control_assert(dt->rst);
227out_assert_rst_reg:
228	reset_control_assert(dt->rst_reg);
229out_disable_clk_ecc:
230	clk_disable_unprepare(dt->clk_ecc);
231out_disable_clk_x:
232	clk_disable_unprepare(dt->clk_x);
233out_disable_clk:
234	clk_disable_unprepare(dt->clk);
235
236	return ret;
237}
238
239static int denali_dt_remove(struct platform_device *pdev)
240{
241	struct denali_dt *dt = platform_get_drvdata(pdev);
242
243	denali_remove(&dt->controller);
244	reset_control_assert(dt->rst);
245	reset_control_assert(dt->rst_reg);
246	clk_disable_unprepare(dt->clk_ecc);
247	clk_disable_unprepare(dt->clk_x);
248	clk_disable_unprepare(dt->clk);
249
250	return 0;
251}
252
253static struct platform_driver denali_dt_driver = {
254	.probe		= denali_dt_probe,
255	.remove		= denali_dt_remove,
256	.driver		= {
257		.name	= "denali-nand-dt",
258		.of_match_table	= denali_nand_dt_ids,
259	},
260};
261module_platform_driver(denali_dt_driver);
262
263MODULE_LICENSE("GPL v2");
264MODULE_AUTHOR("Jamie Iles");
265MODULE_DESCRIPTION("DT driver for Denali NAND controller");
266