2 * drivers/mtd/devices/goldfish_nand.c
4 * Copyright (C) 2007 Google, Inc.
5 * Copyright (C) 2012 Intel, Inc.
6 * Copyright (C) 2013 Intel, Inc.
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
20 #include <linux/device.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/ioport.h>
24 #include <linux/vmalloc.h>
25 #include <linux/mtd/mtd.h>
26 #include <linux/platform_device.h>
27 #include <linux/mutex.h>
28 #include <linux/goldfish.h>
29 #include <asm/div64.h>
31 #include "goldfish_nand_reg.h"
33 struct goldfish_nand
{
34 /* lock protects access to the device registers */
36 unsigned char __iomem
*base
;
37 struct cmd_params
*cmd_params
;
39 struct mtd_info mtd
[0];
42 static u32
goldfish_nand_cmd_with_params(struct mtd_info
*mtd
,
43 enum nand_cmd cmd
, u64 addr
, u32 len
,
47 struct goldfish_nand
*nand
= mtd
->priv
;
48 struct cmd_params
*cps
= nand
->cmd_params
;
49 unsigned char __iomem
*base
= nand
->base
;
56 cmdp
= NAND_CMD_ERASE_WITH_PARAMS
;
59 cmdp
= NAND_CMD_READ_WITH_PARAMS
;
62 cmdp
= NAND_CMD_WRITE_WITH_PARAMS
;
67 cps
->dev
= mtd
- nand
->mtd
;
68 cps
->addr_high
= (u32
)(addr
>> 32);
69 cps
->addr_low
= (u32
)addr
;
70 cps
->transfer_size
= len
;
71 cps
->data
= (unsigned long)ptr
;
72 writel(cmdp
, base
+ NAND_COMMAND
);
77 static u32
goldfish_nand_cmd(struct mtd_info
*mtd
, enum nand_cmd cmd
,
78 u64 addr
, u32 len
, void *ptr
)
80 struct goldfish_nand
*nand
= mtd
->priv
;
82 unsigned char __iomem
*base
= nand
->base
;
84 mutex_lock(&nand
->lock
);
85 if (goldfish_nand_cmd_with_params(mtd
, cmd
, addr
, len
, ptr
, &rv
)) {
86 writel(mtd
- nand
->mtd
, base
+ NAND_DEV
);
87 writel((u32
)(addr
>> 32), base
+ NAND_ADDR_HIGH
);
88 writel((u32
)addr
, base
+ NAND_ADDR_LOW
);
89 writel(len
, base
+ NAND_TRANSFER_SIZE
);
90 gf_write_ptr(ptr
, base
+ NAND_DATA
, base
+ NAND_DATA_HIGH
);
91 writel(cmd
, base
+ NAND_COMMAND
);
92 rv
= readl(base
+ NAND_RESULT
);
94 mutex_unlock(&nand
->lock
);
98 static int goldfish_nand_erase(struct mtd_info
*mtd
, struct erase_info
*instr
)
100 loff_t ofs
= instr
->addr
;
101 u32 len
= instr
->len
;
104 if (ofs
+ len
> mtd
->size
)
106 rem
= do_div(ofs
, mtd
->writesize
);
109 ofs
*= (mtd
->writesize
+ mtd
->oobsize
);
111 if (len
% mtd
->writesize
)
113 len
= len
/ mtd
->writesize
* (mtd
->writesize
+ mtd
->oobsize
);
115 if (goldfish_nand_cmd(mtd
, NAND_CMD_ERASE
, ofs
, len
, NULL
) != len
) {
116 pr_err("goldfish_nand_erase: erase failed, start %llx, len %x, dev_size %llx, erase_size %x\n",
117 ofs
, len
, mtd
->size
, mtd
->erasesize
);
121 instr
->state
= MTD_ERASE_DONE
;
122 mtd_erase_callback(instr
);
127 pr_err("goldfish_nand_erase: invalid erase, start %llx, len %x, dev_size %llx, erase_size %x\n",
128 ofs
, len
, mtd
->size
, mtd
->erasesize
);
132 static int goldfish_nand_read_oob(struct mtd_info
*mtd
, loff_t ofs
,
133 struct mtd_oob_ops
*ops
)
137 if (ofs
+ ops
->len
> mtd
->size
)
139 if (ops
->datbuf
&& ops
->len
&& ops
->len
!= mtd
->writesize
)
141 if (ops
->ooblen
+ ops
->ooboffs
> mtd
->oobsize
)
144 rem
= do_div(ofs
, mtd
->writesize
);
147 ofs
*= (mtd
->writesize
+ mtd
->oobsize
);
150 ops
->retlen
= goldfish_nand_cmd(mtd
, NAND_CMD_READ
, ofs
,
151 ops
->len
, ops
->datbuf
);
152 ofs
+= mtd
->writesize
+ ops
->ooboffs
;
154 ops
->oobretlen
= goldfish_nand_cmd(mtd
, NAND_CMD_READ
, ofs
,
155 ops
->ooblen
, ops
->oobbuf
);
159 pr_err("goldfish_nand_read_oob: invalid read, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n",
160 ofs
, ops
->len
, ops
->ooblen
, mtd
->size
, mtd
->writesize
);
164 static int goldfish_nand_write_oob(struct mtd_info
*mtd
, loff_t ofs
,
165 struct mtd_oob_ops
*ops
)
169 if (ofs
+ ops
->len
> mtd
->size
)
171 if (ops
->len
&& ops
->len
!= mtd
->writesize
)
173 if (ops
->ooblen
+ ops
->ooboffs
> mtd
->oobsize
)
176 rem
= do_div(ofs
, mtd
->writesize
);
179 ofs
*= (mtd
->writesize
+ mtd
->oobsize
);
182 ops
->retlen
= goldfish_nand_cmd(mtd
, NAND_CMD_WRITE
, ofs
,
183 ops
->len
, ops
->datbuf
);
184 ofs
+= mtd
->writesize
+ ops
->ooboffs
;
186 ops
->oobretlen
= goldfish_nand_cmd(mtd
, NAND_CMD_WRITE
, ofs
,
187 ops
->ooblen
, ops
->oobbuf
);
191 pr_err("goldfish_nand_write_oob: invalid write, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n",
192 ofs
, ops
->len
, ops
->ooblen
, mtd
->size
, mtd
->writesize
);
196 static int goldfish_nand_read(struct mtd_info
*mtd
, loff_t from
, size_t len
,
197 size_t *retlen
, u_char
*buf
)
201 if (from
+ len
> mtd
->size
)
204 rem
= do_div(from
, mtd
->writesize
);
207 from
*= (mtd
->writesize
+ mtd
->oobsize
);
209 *retlen
= goldfish_nand_cmd(mtd
, NAND_CMD_READ
, from
, len
, buf
);
213 pr_err("goldfish_nand_read: invalid read, start %llx, len %zx, dev_size %llx, write_size %x\n",
214 from
, len
, mtd
->size
, mtd
->writesize
);
218 static int goldfish_nand_write(struct mtd_info
*mtd
, loff_t to
, size_t len
,
219 size_t *retlen
, const u_char
*buf
)
223 if (to
+ len
> mtd
->size
)
226 rem
= do_div(to
, mtd
->writesize
);
229 to
*= (mtd
->writesize
+ mtd
->oobsize
);
231 *retlen
= goldfish_nand_cmd(mtd
, NAND_CMD_WRITE
, to
, len
, (void *)buf
);
235 pr_err("goldfish_nand_write: invalid write, start %llx, len %zx, dev_size %llx, write_size %x\n",
236 to
, len
, mtd
->size
, mtd
->writesize
);
240 static int goldfish_nand_block_isbad(struct mtd_info
*mtd
, loff_t ofs
)
244 if (ofs
>= mtd
->size
)
247 rem
= do_div(ofs
, mtd
->erasesize
);
250 ofs
*= mtd
->erasesize
/ mtd
->writesize
;
251 ofs
*= (mtd
->writesize
+ mtd
->oobsize
);
253 return goldfish_nand_cmd(mtd
, NAND_CMD_BLOCK_BAD_GET
, ofs
, 0, NULL
);
256 pr_err("goldfish_nand_block_isbad: invalid arg, ofs %llx, dev_size %llx, write_size %x\n",
257 ofs
, mtd
->size
, mtd
->writesize
);
261 static int goldfish_nand_block_markbad(struct mtd_info
*mtd
, loff_t ofs
)
265 if (ofs
>= mtd
->size
)
268 rem
= do_div(ofs
, mtd
->erasesize
);
271 ofs
*= mtd
->erasesize
/ mtd
->writesize
;
272 ofs
*= (mtd
->writesize
+ mtd
->oobsize
);
274 if (goldfish_nand_cmd(mtd
, NAND_CMD_BLOCK_BAD_SET
, ofs
, 0, NULL
) != 1)
279 pr_err("goldfish_nand_block_markbad: invalid arg, ofs %llx, dev_size %llx, write_size %x\n",
280 ofs
, mtd
->size
, mtd
->writesize
);
284 static int nand_setup_cmd_params(struct platform_device
*pdev
,
285 struct goldfish_nand
*nand
)
288 unsigned char __iomem
*base
= nand
->base
;
290 nand
->cmd_params
= devm_kzalloc(&pdev
->dev
,
291 sizeof(struct cmd_params
), GFP_KERNEL
);
292 if (!nand
->cmd_params
)
295 paddr
= __pa(nand
->cmd_params
);
296 writel((u32
)(paddr
>> 32), base
+ NAND_CMD_PARAMS_ADDR_HIGH
);
297 writel((u32
)paddr
, base
+ NAND_CMD_PARAMS_ADDR_LOW
);
301 static int goldfish_nand_init_device(struct platform_device
*pdev
,
302 struct goldfish_nand
*nand
, int id
)
307 unsigned char __iomem
*base
= nand
->base
;
308 struct mtd_info
*mtd
= &nand
->mtd
[id
];
311 mutex_lock(&nand
->lock
);
312 writel(id
, base
+ NAND_DEV
);
313 flags
= readl(base
+ NAND_DEV_FLAGS
);
314 name_len
= readl(base
+ NAND_DEV_NAME_LEN
);
315 mtd
->writesize
= readl(base
+ NAND_DEV_PAGE_SIZE
);
316 mtd
->size
= readl(base
+ NAND_DEV_SIZE_LOW
);
317 mtd
->size
|= (u64
)readl(base
+ NAND_DEV_SIZE_HIGH
) << 32;
318 mtd
->oobsize
= readl(base
+ NAND_DEV_EXTRA_SIZE
);
319 mtd
->oobavail
= mtd
->oobsize
;
320 mtd
->erasesize
= readl(base
+ NAND_DEV_ERASE_SIZE
) /
321 (mtd
->writesize
+ mtd
->oobsize
) * mtd
->writesize
;
322 do_div(mtd
->size
, mtd
->writesize
+ mtd
->oobsize
);
323 mtd
->size
*= mtd
->writesize
;
325 "goldfish nand dev%d: size %llx, page %d, extra %d, erase %d\n",
326 id
, mtd
->size
, mtd
->writesize
,
327 mtd
->oobsize
, mtd
->erasesize
);
328 mutex_unlock(&nand
->lock
);
332 name
= devm_kzalloc(&pdev
->dev
, name_len
+ 1, GFP_KERNEL
);
337 result
= goldfish_nand_cmd(mtd
, NAND_CMD_GET_DEV_NAME
, 0, name_len
,
339 if (result
!= name_len
) {
341 "goldfish_nand_init_device failed to get dev name %d != %d\n",
345 ((char *)mtd
->name
)[name_len
] = '\0';
347 /* Setup the MTD structure */
348 mtd
->type
= MTD_NANDFLASH
;
349 mtd
->flags
= MTD_CAP_NANDFLASH
;
350 if (flags
& NAND_DEV_FLAG_READ_ONLY
)
351 mtd
->flags
&= ~MTD_WRITEABLE
;
352 if (flags
& NAND_DEV_FLAG_CMD_PARAMS_CAP
)
353 nand_setup_cmd_params(pdev
, nand
);
355 mtd
->owner
= THIS_MODULE
;
356 mtd
->_erase
= goldfish_nand_erase
;
357 mtd
->_read
= goldfish_nand_read
;
358 mtd
->_write
= goldfish_nand_write
;
359 mtd
->_read_oob
= goldfish_nand_read_oob
;
360 mtd
->_write_oob
= goldfish_nand_write_oob
;
361 mtd
->_block_isbad
= goldfish_nand_block_isbad
;
362 mtd
->_block_markbad
= goldfish_nand_block_markbad
;
364 if (mtd_device_register(mtd
, NULL
, 0))
370 static int goldfish_nand_probe(struct platform_device
*pdev
)
378 struct goldfish_nand
*nand
;
379 unsigned char __iomem
*base
;
381 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
385 base
= devm_ioremap(&pdev
->dev
, r
->start
, PAGE_SIZE
);
389 version
= readl(base
+ NAND_VERSION
);
390 if (version
!= NAND_VERSION_CURRENT
) {
392 "goldfish_nand_init: version mismatch, got %d, expected %d\n",
393 version
, NAND_VERSION_CURRENT
);
396 num_dev
= readl(base
+ NAND_NUM_DEV
);
400 nand
= devm_kzalloc(&pdev
->dev
, sizeof(*nand
) +
401 sizeof(struct mtd_info
) * num_dev
, GFP_KERNEL
);
405 mutex_init(&nand
->lock
);
407 nand
->mtd_count
= num_dev
;
408 platform_set_drvdata(pdev
, nand
);
411 for (i
= 0; i
< num_dev
; i
++) {
412 err
= goldfish_nand_init_device(pdev
, nand
, i
);
416 if (num_dev_working
== 0)
421 static int goldfish_nand_remove(struct platform_device
*pdev
)
423 struct goldfish_nand
*nand
= platform_get_drvdata(pdev
);
426 for (i
= 0; i
< nand
->mtd_count
; i
++) {
427 if (nand
->mtd
[i
].name
)
428 mtd_device_unregister(&nand
->mtd
[i
]);
433 static struct platform_driver goldfish_nand_driver
= {
434 .probe
= goldfish_nand_probe
,
435 .remove
= goldfish_nand_remove
,
437 .name
= "goldfish_nand"
441 module_platform_driver(goldfish_nand_driver
);
442 MODULE_LICENSE("GPL");