.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * JZ4780 NAND/external memory controller (NEMC) |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015 Imagination Technologies |
---|
5 | 6 | * Author: Alex Smith <alex@alex-smith.me.uk> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License version 2 as published |
---|
9 | | - * by the Free Software Foundation. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <linux/clk.h> |
---|
13 | 10 | #include <linux/init.h> |
---|
| 11 | +#include <linux/io.h> |
---|
14 | 12 | #include <linux/math64.h> |
---|
15 | 13 | #include <linux/of.h> |
---|
16 | 14 | #include <linux/of_address.h> |
---|
.. | .. |
---|
24 | 22 | |
---|
25 | 23 | #define NEMC_SMCRn(n) (0x14 + (((n) - 1) * 4)) |
---|
26 | 24 | #define NEMC_NFCSR 0x50 |
---|
| 25 | + |
---|
| 26 | +#define NEMC_REG_LEN 0x54 |
---|
27 | 27 | |
---|
28 | 28 | #define NEMC_SMCR_SMT BIT(0) |
---|
29 | 29 | #define NEMC_SMCR_BW_SHIFT 6 |
---|
.. | .. |
---|
44 | 44 | #define NEMC_NFCSR_NFCEn(n) BIT((((n) - 1) << 1) + 1) |
---|
45 | 45 | #define NEMC_NFCSR_TNFEn(n) BIT(16 + (n) - 1) |
---|
46 | 46 | |
---|
| 47 | +struct jz_soc_info { |
---|
| 48 | + u8 tas_tah_cycles_max; |
---|
| 49 | +}; |
---|
| 50 | + |
---|
47 | 51 | struct jz4780_nemc { |
---|
48 | 52 | spinlock_t lock; |
---|
49 | 53 | struct device *dev; |
---|
| 54 | + const struct jz_soc_info *soc_info; |
---|
50 | 55 | void __iomem *base; |
---|
51 | 56 | struct clk *clk; |
---|
52 | 57 | uint32_t clk_period; |
---|
.. | .. |
---|
59 | 64 | * |
---|
60 | 65 | * Return: The number of unique NEMC banks referred to by the specified NEMC |
---|
61 | 66 | * child device. Unique here means that a device that references the same bank |
---|
62 | | - * multiple times in the its "reg" property will only count once. |
---|
| 67 | + * multiple times in its "reg" property will only count once. |
---|
63 | 68 | */ |
---|
64 | 69 | unsigned int jz4780_nemc_num_banks(struct device *dev) |
---|
65 | 70 | { |
---|
.. | .. |
---|
161 | 166 | * Conversion of tBP and tAW cycle counts to values supported by the |
---|
162 | 167 | * hardware (round up to the next supported value). |
---|
163 | 168 | */ |
---|
164 | | - static const uint32_t convert_tBP_tAW[] = { |
---|
| 169 | + static const u8 convert_tBP_tAW[] = { |
---|
165 | 170 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
---|
166 | 171 | |
---|
167 | 172 | /* 11 - 12 -> 12 cycles */ |
---|
.. | .. |
---|
202 | 207 | if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) { |
---|
203 | 208 | smcr &= ~NEMC_SMCR_TAS_MASK; |
---|
204 | 209 | cycles = jz4780_nemc_ns_to_cycles(nemc, val); |
---|
205 | | - if (cycles > 15) { |
---|
| 210 | + if (cycles > nemc->soc_info->tas_tah_cycles_max) { |
---|
206 | 211 | dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n", |
---|
207 | 212 | val, cycles); |
---|
208 | 213 | return false; |
---|
.. | .. |
---|
214 | 219 | if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) { |
---|
215 | 220 | smcr &= ~NEMC_SMCR_TAH_MASK; |
---|
216 | 221 | cycles = jz4780_nemc_ns_to_cycles(nemc, val); |
---|
217 | | - if (cycles > 15) { |
---|
| 222 | + if (cycles > nemc->soc_info->tas_tah_cycles_max) { |
---|
218 | 223 | dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n", |
---|
219 | 224 | val, cycles); |
---|
220 | 225 | return false; |
---|
.. | .. |
---|
278 | 283 | if (!nemc) |
---|
279 | 284 | return -ENOMEM; |
---|
280 | 285 | |
---|
| 286 | + nemc->soc_info = device_get_match_data(dev); |
---|
| 287 | + if (!nemc->soc_info) |
---|
| 288 | + return -EINVAL; |
---|
| 289 | + |
---|
281 | 290 | spin_lock_init(&nemc->lock); |
---|
282 | 291 | nemc->dev = dev; |
---|
283 | 292 | |
---|
284 | 293 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
285 | | - nemc->base = devm_ioremap_resource(dev, res); |
---|
286 | | - if (IS_ERR(nemc->base)) { |
---|
| 294 | + if (!res) |
---|
| 295 | + return -EINVAL; |
---|
| 296 | + |
---|
| 297 | + /* |
---|
| 298 | + * The driver currently only uses the registers up to offset |
---|
| 299 | + * NEMC_REG_LEN. Since the EFUSE registers are in the middle of the |
---|
| 300 | + * NEMC registers, we only request the registers we will use for now; |
---|
| 301 | + * that way the EFUSE driver can probe too. |
---|
| 302 | + */ |
---|
| 303 | + if (!devm_request_mem_region(dev, res->start, NEMC_REG_LEN, dev_name(dev))) { |
---|
| 304 | + dev_err(dev, "unable to request I/O memory region\n"); |
---|
| 305 | + return -EBUSY; |
---|
| 306 | + } |
---|
| 307 | + |
---|
| 308 | + nemc->base = devm_ioremap(dev, res->start, NEMC_REG_LEN); |
---|
| 309 | + if (!nemc->base) { |
---|
287 | 310 | dev_err(dev, "failed to get I/O memory\n"); |
---|
288 | | - return PTR_ERR(nemc->base); |
---|
| 311 | + return -ENOMEM; |
---|
289 | 312 | } |
---|
290 | 313 | |
---|
291 | 314 | writel(0, nemc->base + NEMC_NFCSR); |
---|
.. | .. |
---|
370 | 393 | return 0; |
---|
371 | 394 | } |
---|
372 | 395 | |
---|
| 396 | +static const struct jz_soc_info jz4740_soc_info = { |
---|
| 397 | + .tas_tah_cycles_max = 7, |
---|
| 398 | +}; |
---|
| 399 | + |
---|
| 400 | +static const struct jz_soc_info jz4780_soc_info = { |
---|
| 401 | + .tas_tah_cycles_max = 15, |
---|
| 402 | +}; |
---|
| 403 | + |
---|
373 | 404 | static const struct of_device_id jz4780_nemc_dt_match[] = { |
---|
374 | | - { .compatible = "ingenic,jz4780-nemc" }, |
---|
| 405 | + { .compatible = "ingenic,jz4740-nemc", .data = &jz4740_soc_info, }, |
---|
| 406 | + { .compatible = "ingenic,jz4780-nemc", .data = &jz4780_soc_info, }, |
---|
375 | 407 | {}, |
---|
376 | 408 | }; |
---|
377 | 409 | |
---|