1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Freescale UPM NAND driver.
5 * Copyright © 2007-2008 MontaVista Software, Inc.
7 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/delay.h>
13 #include <linux/mtd/rawnand.h>
14 #include <linux/mtd/partitions.h>
15 #include <linux/mtd/mtd.h>
16 #include <linux/of_platform.h>
18 #include <linux/slab.h>
19 #include <asm/fsl_lbc.h>
22 struct nand_controller base
;
24 struct nand_chip chip
;
26 uint8_t upm_addr_offset
;
27 uint8_t upm_cmd_offset
;
28 void __iomem
*io_base
;
29 struct gpio_desc
*rnb_gpio
[NAND_MAX_CHIPS
];
30 uint32_t mchip_offsets
[NAND_MAX_CHIPS
];
32 uint32_t mchip_number
;
35 static inline struct fsl_upm_nand
*to_fsl_upm_nand(struct mtd_info
*mtdinfo
)
37 return container_of(mtd_to_nand(mtdinfo
), struct fsl_upm_nand
,
41 static int fun_chip_init(struct fsl_upm_nand
*fun
,
42 const struct device_node
*upm_np
,
43 const struct resource
*io_res
)
45 struct mtd_info
*mtd
= nand_to_mtd(&fun
->chip
);
47 struct device_node
*flash_np
;
49 fun
->chip
.ecc
.engine_type
= NAND_ECC_ENGINE_TYPE_SOFT
;
50 fun
->chip
.ecc
.algo
= NAND_ECC_ALGO_HAMMING
;
51 fun
->chip
.controller
= &fun
->base
;
52 mtd
->dev
.parent
= fun
->dev
;
54 flash_np
= of_get_next_child(upm_np
, NULL
);
58 nand_set_flash_node(&fun
->chip
, flash_np
);
59 mtd
->name
= devm_kasprintf(fun
->dev
, GFP_KERNEL
, "0x%llx.%pOFn",
67 ret
= nand_scan(&fun
->chip
, fun
->mchip_count
);
71 ret
= mtd_device_register(mtd
, NULL
, 0);
73 of_node_put(flash_np
);
77 static int func_exec_instr(struct nand_chip
*chip
,
78 const struct nand_op_instr
*instr
)
80 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(nand_to_mtd(chip
));
81 u32 mar
, reg_offs
= fun
->mchip_offsets
[fun
->mchip_number
];
86 switch (instr
->type
) {
87 case NAND_OP_CMD_INSTR
:
88 fsl_upm_start_pattern(&fun
->upm
, fun
->upm_cmd_offset
);
89 mar
= (instr
->ctx
.cmd
.opcode
<< (32 - fun
->upm
.width
)) |
91 fsl_upm_run_pattern(&fun
->upm
, fun
->io_base
+ reg_offs
, mar
);
92 fsl_upm_end_pattern(&fun
->upm
);
95 case NAND_OP_ADDR_INSTR
:
96 fsl_upm_start_pattern(&fun
->upm
, fun
->upm_addr_offset
);
97 for (i
= 0; i
< instr
->ctx
.addr
.naddrs
; i
++) {
98 mar
= (instr
->ctx
.addr
.addrs
[i
] << (32 - fun
->upm
.width
)) |
100 fsl_upm_run_pattern(&fun
->upm
, fun
->io_base
+ reg_offs
, mar
);
102 fsl_upm_end_pattern(&fun
->upm
);
105 case NAND_OP_DATA_IN_INSTR
:
106 in
= instr
->ctx
.data
.buf
.in
;
107 for (i
= 0; i
< instr
->ctx
.data
.len
; i
++)
108 in
[i
] = in_8(fun
->io_base
+ reg_offs
);
111 case NAND_OP_DATA_OUT_INSTR
:
112 out
= instr
->ctx
.data
.buf
.out
;
113 for (i
= 0; i
< instr
->ctx
.data
.len
; i
++)
114 out_8(fun
->io_base
+ reg_offs
, out
[i
]);
117 case NAND_OP_WAITRDY_INSTR
:
118 if (!fun
->rnb_gpio
[fun
->mchip_number
])
119 return nand_soft_waitrdy(chip
, instr
->ctx
.waitrdy
.timeout_ms
);
121 return nand_gpio_waitrdy(chip
, fun
->rnb_gpio
[fun
->mchip_number
],
122 instr
->ctx
.waitrdy
.timeout_ms
);
131 static int fun_exec_op(struct nand_chip
*chip
, const struct nand_operation
*op
,
134 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(nand_to_mtd(chip
));
138 if (op
->cs
> NAND_MAX_CHIPS
)
144 fun
->mchip_number
= op
->cs
;
146 for (i
= 0; i
< op
->ninstrs
; i
++) {
147 ret
= func_exec_instr(chip
, &op
->instrs
[i
]);
151 if (op
->instrs
[i
].delay_ns
)
152 ndelay(op
->instrs
[i
].delay_ns
);
158 static const struct nand_controller_ops fun_ops
= {
159 .exec_op
= fun_exec_op
,
162 static int fun_probe(struct platform_device
*ofdev
)
164 struct fsl_upm_nand
*fun
;
165 struct resource
*io_res
;
171 fun
= devm_kzalloc(&ofdev
->dev
, sizeof(*fun
), GFP_KERNEL
);
175 io_res
= platform_get_resource(ofdev
, IORESOURCE_MEM
, 0);
176 fun
->io_base
= devm_ioremap_resource(&ofdev
->dev
, io_res
);
177 if (IS_ERR(fun
->io_base
))
178 return PTR_ERR(fun
->io_base
);
180 ret
= fsl_upm_find(io_res
->start
, &fun
->upm
);
182 dev_err(&ofdev
->dev
, "can't find UPM\n");
186 prop
= of_get_property(ofdev
->dev
.of_node
, "fsl,upm-addr-offset",
188 if (!prop
|| size
!= sizeof(uint32_t)) {
189 dev_err(&ofdev
->dev
, "can't get UPM address offset\n");
192 fun
->upm_addr_offset
= *prop
;
194 prop
= of_get_property(ofdev
->dev
.of_node
, "fsl,upm-cmd-offset", &size
);
195 if (!prop
|| size
!= sizeof(uint32_t)) {
196 dev_err(&ofdev
->dev
, "can't get UPM command offset\n");
199 fun
->upm_cmd_offset
= *prop
;
201 prop
= of_get_property(ofdev
->dev
.of_node
,
202 "fsl,upm-addr-line-cs-offsets", &size
);
203 if (prop
&& (size
/ sizeof(uint32_t)) > 0) {
204 fun
->mchip_count
= size
/ sizeof(uint32_t);
205 if (fun
->mchip_count
>= NAND_MAX_CHIPS
) {
206 dev_err(&ofdev
->dev
, "too much multiple chips\n");
209 for (i
= 0; i
< fun
->mchip_count
; i
++)
210 fun
->mchip_offsets
[i
] = be32_to_cpu(prop
[i
]);
212 fun
->mchip_count
= 1;
215 for (i
= 0; i
< fun
->mchip_count
; i
++) {
216 fun
->rnb_gpio
[i
] = devm_gpiod_get_index_optional(&ofdev
->dev
,
219 if (IS_ERR(fun
->rnb_gpio
[i
])) {
220 dev_err(&ofdev
->dev
, "RNB gpio #%d is invalid\n", i
);
221 return PTR_ERR(fun
->rnb_gpio
[i
]);
225 nand_controller_init(&fun
->base
);
226 fun
->base
.ops
= &fun_ops
;
227 fun
->dev
= &ofdev
->dev
;
229 ret
= fun_chip_init(fun
, ofdev
->dev
.of_node
, io_res
);
233 dev_set_drvdata(&ofdev
->dev
, fun
);
238 static int fun_remove(struct platform_device
*ofdev
)
240 struct fsl_upm_nand
*fun
= dev_get_drvdata(&ofdev
->dev
);
241 struct nand_chip
*chip
= &fun
->chip
;
242 struct mtd_info
*mtd
= nand_to_mtd(chip
);
245 ret
= mtd_device_unregister(mtd
);
252 static const struct of_device_id of_fun_match
[] = {
253 { .compatible
= "fsl,upm-nand" },
256 MODULE_DEVICE_TABLE(of
, of_fun_match
);
258 static struct platform_driver of_fun_driver
= {
260 .name
= "fsl,upm-nand",
261 .of_match_table
= of_fun_match
,
264 .remove
= fun_remove
,
267 module_platform_driver(of_fun_driver
);
269 MODULE_LICENSE("GPL");
270 MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
271 MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
272 "LocalBus User-Programmable Machine");