blob: eb6f437ca9ec8a38d3fddfb6ed9ecf3506aba26f [file] [log] [blame]
Alexey Korolevc6826472008-12-16 18:20:03 +00001/*
2 * LPDDR flash memory device operations. This module provides read, write,
3 * erase, lock/unlock support for LPDDR flash memories
4 * (C) 2008 Korolev Alexey <akorolev@infradead.org>
5 * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
6 * Many thanks to Roman Borisov for intial enabling
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 * TODO:
23 * Implement VPP management
24 * Implement XIP support
25 * Implement OTP support
26 */
27#include <linux/mtd/pfow.h>
28#include <linux/mtd/qinfo.h>
29
30static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
31 size_t *retlen, u_char *buf);
32static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to,
33 size_t len, size_t *retlen, const u_char *buf);
34static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
35 unsigned long count, loff_t to, size_t *retlen);
36static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr);
37static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
38static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
39static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
40 size_t *retlen, void **mtdbuf, resource_size_t *phys);
41static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
42static int get_chip(struct map_info *map, struct flchip *chip, int mode);
43static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
44static void put_chip(struct map_info *map, struct flchip *chip);
45
46struct mtd_info *lpddr_cmdset(struct map_info *map)
47{
48 struct lpddr_private *lpddr = map->fldrv_priv;
49 struct flchip_shared *shared;
50 struct flchip *chip;
51 struct mtd_info *mtd;
52 int numchips;
53 int i, j;
54
55 mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
56 if (!mtd) {
57 printk(KERN_ERR "Failed to allocate memory for MTD device\n");
58 return NULL;
59 }
60 mtd->priv = map;
61 mtd->type = MTD_NORFLASH;
62
63 /* Fill in the default mtd operations */
64 mtd->read = lpddr_read;
65 mtd->type = MTD_NORFLASH;
66 mtd->flags = MTD_CAP_NORFLASH;
67 mtd->flags &= ~MTD_BIT_WRITEABLE;
68 mtd->erase = lpddr_erase;
69 mtd->write = lpddr_write_buffers;
70 mtd->writev = lpddr_writev;
71 mtd->read_oob = NULL;
72 mtd->write_oob = NULL;
73 mtd->sync = NULL;
74 mtd->lock = lpddr_lock;
75 mtd->unlock = lpddr_unlock;
76 mtd->suspend = NULL;
77 mtd->resume = NULL;
78 if (map_is_linear(map)) {
79 mtd->point = lpddr_point;
80 mtd->unpoint = lpddr_unpoint;
81 }
82 mtd->block_isbad = NULL;
83 mtd->block_markbad = NULL;
84 mtd->size = 1 << lpddr->qinfo->DevSizeShift;
85 mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
86 mtd->writesize = 1 << lpddr->qinfo->BufSizeShift;
87
88 shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips,
89 GFP_KERNEL);
90 if (!shared) {
91 kfree(lpddr);
92 kfree(mtd);
93 return NULL;
94 }
95
96 chip = &lpddr->chips[0];
97 numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum;
98 for (i = 0; i < numchips; i++) {
99 shared[i].writing = shared[i].erasing = NULL;
100 spin_lock_init(&shared[i].lock);
101 for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) {
102 *chip = lpddr->chips[i];
103 chip->start += j << lpddr->chipshift;
104 chip->oldstate = chip->state = FL_READY;
105 chip->priv = &shared[i];
106 /* those should be reset too since
107 they create memory references. */
108 init_waitqueue_head(&chip->wq);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200109 mutex_init(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000110 chip++;
111 }
112 }
113
114 return mtd;
115}
116EXPORT_SYMBOL(lpddr_cmdset);
117
118static int wait_for_ready(struct map_info *map, struct flchip *chip,
119 unsigned int chip_op_time)
120{
121 unsigned int timeo, reset_timeo, sleep_time;
122 unsigned int dsr;
123 flstate_t chip_state = chip->state;
124 int ret = 0;
125
126 /* set our timeout to 8 times the expected delay */
127 timeo = chip_op_time * 8;
128 if (!timeo)
129 timeo = 500000;
130 reset_timeo = timeo;
131 sleep_time = chip_op_time / 2;
132
133 for (;;) {
134 dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
135 if (dsr & DSR_READY_STATUS)
136 break;
137 if (!timeo) {
138 printk(KERN_ERR "%s: Flash timeout error state %d \n",
139 map->name, chip_state);
140 ret = -ETIME;
141 break;
142 }
143
144 /* OK Still waiting. Drop the lock, wait a while and retry. */
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200145 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000146 if (sleep_time >= 1000000/HZ) {
147 /*
148 * Half of the normal delay still remaining
149 * can be performed with a sleeping delay instead
150 * of busy waiting.
151 */
152 msleep(sleep_time/1000);
153 timeo -= sleep_time;
154 sleep_time = 1000000/HZ;
155 } else {
156 udelay(1);
157 cond_resched();
158 timeo--;
159 }
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200160 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000161
162 while (chip->state != chip_state) {
163 /* Someone's suspended the operation: sleep */
164 DECLARE_WAITQUEUE(wait, current);
165 set_current_state(TASK_UNINTERRUPTIBLE);
166 add_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200167 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000168 schedule();
169 remove_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200170 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000171 }
172 if (chip->erase_suspended || chip->write_suspended) {
173 /* Suspend has occured while sleep: reset timeout */
174 timeo = reset_timeo;
175 chip->erase_suspended = chip->write_suspended = 0;
176 }
177 }
178 /* check status for errors */
179 if (dsr & DSR_ERR) {
180 /* Clear DSR*/
181 map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR);
182 printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n",
183 map->name, dsr);
184 print_drs_error(dsr);
185 ret = -EIO;
186 }
187 chip->state = FL_READY;
188 return ret;
189}
190
191static int get_chip(struct map_info *map, struct flchip *chip, int mode)
192{
193 int ret;
194 DECLARE_WAITQUEUE(wait, current);
195
196 retry:
197 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)
198 && chip->state != FL_SYNCING) {
199 /*
200 * OK. We have possibility for contension on the write/erase
201 * operations which are global to the real chip and not per
202 * partition. So let's fight it over in the partition which
203 * currently has authority on the operation.
204 *
205 * The rules are as follows:
206 *
207 * - any write operation must own shared->writing.
208 *
209 * - any erase operation must own _both_ shared->writing and
210 * shared->erasing.
211 *
212 * - contension arbitration is handled in the owner's context.
213 *
214 * The 'shared' struct can be read and/or written only when
215 * its lock is taken.
216 */
217 struct flchip_shared *shared = chip->priv;
218 struct flchip *contender;
219 spin_lock(&shared->lock);
220 contender = shared->writing;
221 if (contender && contender != chip) {
222 /*
223 * The engine to perform desired operation on this
224 * partition is already in use by someone else.
225 * Let's fight over it in the context of the chip
226 * currently using it. If it is possible to suspend,
227 * that other partition will do just that, otherwise
228 * it'll happily send us to sleep. In any case, when
229 * get_chip returns success we're clear to go ahead.
230 */
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200231 ret = mutex_trylock(&contender->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000232 spin_unlock(&shared->lock);
233 if (!ret)
234 goto retry;
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200235 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000236 ret = chip_ready(map, contender, mode);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200237 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000238
239 if (ret == -EAGAIN) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200240 mutex_unlock(&contender->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000241 goto retry;
242 }
243 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200244 mutex_unlock(&contender->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000245 return ret;
246 }
247 spin_lock(&shared->lock);
248
249 /* We should not own chip if it is already in FL_SYNCING
250 * state. Put contender and retry. */
251 if (chip->state == FL_SYNCING) {
252 put_chip(map, contender);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200253 mutex_unlock(&contender->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000254 goto retry;
255 }
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200256 mutex_unlock(&contender->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000257 }
258
259 /* Check if we have suspended erase on this chip.
260 Must sleep in such a case. */
261 if (mode == FL_ERASING && shared->erasing
262 && shared->erasing->oldstate == FL_ERASING) {
263 spin_unlock(&shared->lock);
264 set_current_state(TASK_UNINTERRUPTIBLE);
265 add_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200266 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000267 schedule();
268 remove_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200269 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000270 goto retry;
271 }
272
273 /* We now own it */
274 shared->writing = chip;
275 if (mode == FL_ERASING)
276 shared->erasing = chip;
277 spin_unlock(&shared->lock);
278 }
279
280 ret = chip_ready(map, chip, mode);
281 if (ret == -EAGAIN)
282 goto retry;
283
284 return ret;
285}
286
287static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
288{
289 struct lpddr_private *lpddr = map->fldrv_priv;
290 int ret = 0;
291 DECLARE_WAITQUEUE(wait, current);
292
293 /* Prevent setting state FL_SYNCING for chip in suspended state. */
294 if (FL_SYNCING == mode && FL_READY != chip->oldstate)
295 goto sleep;
296
297 switch (chip->state) {
298 case FL_READY:
299 case FL_JEDEC_QUERY:
300 return 0;
301
302 case FL_ERASING:
303 if (!lpddr->qinfo->SuspEraseSupp ||
304 !(mode == FL_READY || mode == FL_POINT))
305 goto sleep;
306
307 map_write(map, CMD(LPDDR_SUSPEND),
308 map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND);
309 chip->oldstate = FL_ERASING;
310 chip->state = FL_ERASE_SUSPENDING;
311 ret = wait_for_ready(map, chip, 0);
312 if (ret) {
313 /* Oops. something got wrong. */
314 /* Resume and pretend we weren't here. */
315 map_write(map, CMD(LPDDR_RESUME),
316 map->pfow_base + PFOW_COMMAND_CODE);
317 map_write(map, CMD(LPDDR_START_EXECUTION),
318 map->pfow_base + PFOW_COMMAND_EXECUTE);
319 chip->state = FL_ERASING;
320 chip->oldstate = FL_READY;
321 printk(KERN_ERR "%s: suspend operation failed."
322 "State may be wrong \n", map->name);
323 return -EIO;
324 }
325 chip->erase_suspended = 1;
326 chip->state = FL_READY;
327 return 0;
328 /* Erase suspend */
329 case FL_POINT:
330 /* Only if there's no operation suspended... */
331 if (mode == FL_READY && chip->oldstate == FL_READY)
332 return 0;
333
334 default:
335sleep:
336 set_current_state(TASK_UNINTERRUPTIBLE);
337 add_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200338 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000339 schedule();
340 remove_wait_queue(&chip->wq, &wait);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200341 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000342 return -EAGAIN;
343 }
344}
345
346static void put_chip(struct map_info *map, struct flchip *chip)
347{
348 if (chip->priv) {
349 struct flchip_shared *shared = chip->priv;
350 spin_lock(&shared->lock);
351 if (shared->writing == chip && chip->oldstate == FL_READY) {
352 /* We own the ability to write, but we're done */
353 shared->writing = shared->erasing;
354 if (shared->writing && shared->writing != chip) {
355 /* give back the ownership */
356 struct flchip *loaner = shared->writing;
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200357 mutex_lock(&loaner->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000358 spin_unlock(&shared->lock);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200359 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000360 put_chip(map, loaner);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200361 mutex_lock(&chip->mutex);
362 mutex_unlock(&loaner->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000363 wake_up(&chip->wq);
364 return;
365 }
366 shared->erasing = NULL;
367 shared->writing = NULL;
368 } else if (shared->erasing == chip && shared->writing != chip) {
369 /*
370 * We own the ability to erase without the ability
371 * to write, which means the erase was suspended
372 * and some other partition is currently writing.
373 * Don't let the switch below mess things up since
374 * we don't have ownership to resume anything.
375 */
376 spin_unlock(&shared->lock);
377 wake_up(&chip->wq);
378 return;
379 }
380 spin_unlock(&shared->lock);
381 }
382
383 switch (chip->oldstate) {
384 case FL_ERASING:
385 chip->state = chip->oldstate;
386 map_write(map, CMD(LPDDR_RESUME),
387 map->pfow_base + PFOW_COMMAND_CODE);
388 map_write(map, CMD(LPDDR_START_EXECUTION),
389 map->pfow_base + PFOW_COMMAND_EXECUTE);
390 chip->oldstate = FL_READY;
391 chip->state = FL_ERASING;
392 break;
393 case FL_READY:
394 break;
395 default:
396 printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n",
397 map->name, chip->oldstate);
398 }
399 wake_up(&chip->wq);
400}
401
402int do_write_buffer(struct map_info *map, struct flchip *chip,
403 unsigned long adr, const struct kvec **pvec,
404 unsigned long *pvec_seek, int len)
405{
406 struct lpddr_private *lpddr = map->fldrv_priv;
407 map_word datum;
408 int ret, wbufsize, word_gap, words;
409 const struct kvec *vec;
410 unsigned long vec_seek;
411 unsigned long prog_buf_ofs;
412
413 wbufsize = 1 << lpddr->qinfo->BufSizeShift;
414
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200415 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000416 ret = get_chip(map, chip, FL_WRITING);
417 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200418 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000419 return ret;
420 }
421 /* Figure out the number of words to write */
422 word_gap = (-adr & (map_bankwidth(map)-1));
423 words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
424 if (!word_gap) {
425 words--;
426 } else {
427 word_gap = map_bankwidth(map) - word_gap;
428 adr -= word_gap;
429 datum = map_word_ff(map);
430 }
431 /* Write data */
432 /* Get the program buffer offset from PFOW register data first*/
433 prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map,
434 map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET));
435 vec = *pvec;
436 vec_seek = *pvec_seek;
437 do {
438 int n = map_bankwidth(map) - word_gap;
439
440 if (n > vec->iov_len - vec_seek)
441 n = vec->iov_len - vec_seek;
442 if (n > len)
443 n = len;
444
445 if (!word_gap && (len < map_bankwidth(map)))
446 datum = map_word_ff(map);
447
448 datum = map_word_load_partial(map, datum,
449 vec->iov_base + vec_seek, word_gap, n);
450
451 len -= n;
452 word_gap += n;
453 if (!len || word_gap == map_bankwidth(map)) {
454 map_write(map, datum, prog_buf_ofs);
455 prog_buf_ofs += map_bankwidth(map);
456 word_gap = 0;
457 }
458
459 vec_seek += n;
460 if (vec_seek == vec->iov_len) {
461 vec++;
462 vec_seek = 0;
463 }
464 } while (len);
465 *pvec = vec;
466 *pvec_seek = vec_seek;
467
468 /* GO GO GO */
469 send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL);
470 chip->state = FL_WRITING;
471 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime));
472 if (ret) {
473 printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n",
474 map->name, ret, adr);
475 goto out;
476 }
477
478 out: put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200479 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000480 return ret;
481}
482
483int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
484{
485 struct map_info *map = mtd->priv;
486 struct lpddr_private *lpddr = map->fldrv_priv;
487 int chipnum = adr >> lpddr->chipshift;
488 struct flchip *chip = &lpddr->chips[chipnum];
489 int ret;
490
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200491 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000492 ret = get_chip(map, chip, FL_ERASING);
493 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200494 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000495 return ret;
496 }
497 send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL);
498 chip->state = FL_ERASING;
499 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000);
500 if (ret) {
501 printk(KERN_WARNING"%s Erase block error %d at : %llx\n",
502 map->name, ret, adr);
503 goto out;
504 }
505 out: put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200506 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000507 return ret;
508}
509
510static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
511 size_t *retlen, u_char *buf)
512{
513 struct map_info *map = mtd->priv;
514 struct lpddr_private *lpddr = map->fldrv_priv;
515 int chipnum = adr >> lpddr->chipshift;
516 struct flchip *chip = &lpddr->chips[chipnum];
517 int ret = 0;
518
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200519 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000520 ret = get_chip(map, chip, FL_READY);
521 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200522 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000523 return ret;
524 }
525
526 map_copy_from(map, buf, adr, len);
527 *retlen = len;
528
529 put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200530 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000531 return ret;
532}
533
534static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
535 size_t *retlen, void **mtdbuf, resource_size_t *phys)
536{
537 struct map_info *map = mtd->priv;
538 struct lpddr_private *lpddr = map->fldrv_priv;
539 int chipnum = adr >> lpddr->chipshift;
540 unsigned long ofs, last_end = 0;
541 struct flchip *chip = &lpddr->chips[chipnum];
542 int ret = 0;
543
544 if (!map->virt || (adr + len > mtd->size))
545 return -EINVAL;
546
547 /* ofs: offset within the first chip that the first read should start */
548 ofs = adr - (chipnum << lpddr->chipshift);
549
550 *mtdbuf = (void *)map->virt + chip->start + ofs;
551 *retlen = 0;
552
553 while (len) {
554 unsigned long thislen;
555
556 if (chipnum >= lpddr->numchips)
557 break;
558
559 /* We cannot point across chips that are virtually disjoint */
560 if (!last_end)
561 last_end = chip->start;
562 else if (chip->start != last_end)
563 break;
564
565 if ((len + ofs - 1) >> lpddr->chipshift)
566 thislen = (1<<lpddr->chipshift) - ofs;
567 else
568 thislen = len;
569 /* get the chip */
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200570 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000571 ret = get_chip(map, chip, FL_POINT);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200572 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000573 if (ret)
574 break;
575
576 chip->state = FL_POINT;
577 chip->ref_point_counter++;
578 *retlen += thislen;
579 len -= thislen;
580
581 ofs = 0;
582 last_end += 1 << lpddr->chipshift;
583 chipnum++;
584 chip = &lpddr->chips[chipnum];
585 }
586 return 0;
587}
588
589static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
590{
591 struct map_info *map = mtd->priv;
592 struct lpddr_private *lpddr = map->fldrv_priv;
593 int chipnum = adr >> lpddr->chipshift;
594 unsigned long ofs;
595
596 /* ofs: offset within the first chip that the first read should start */
597 ofs = adr - (chipnum << lpddr->chipshift);
598
599 while (len) {
600 unsigned long thislen;
601 struct flchip *chip;
602
603 chip = &lpddr->chips[chipnum];
604 if (chipnum >= lpddr->numchips)
605 break;
606
607 if ((len + ofs - 1) >> lpddr->chipshift)
608 thislen = (1<<lpddr->chipshift) - ofs;
609 else
610 thislen = len;
611
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200612 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000613 if (chip->state == FL_POINT) {
614 chip->ref_point_counter--;
615 if (chip->ref_point_counter == 0)
616 chip->state = FL_READY;
617 } else
618 printk(KERN_WARNING "%s: Warning: unpoint called on non"
619 "pointed region\n", map->name);
620
621 put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200622 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000623
624 len -= thislen;
625 ofs = 0;
626 chipnum++;
627 }
628}
629
630static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
631 size_t *retlen, const u_char *buf)
632{
633 struct kvec vec;
634
635 vec.iov_base = (void *) buf;
636 vec.iov_len = len;
637
638 return lpddr_writev(mtd, &vec, 1, to, retlen);
639}
640
641
642static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
643 unsigned long count, loff_t to, size_t *retlen)
644{
645 struct map_info *map = mtd->priv;
646 struct lpddr_private *lpddr = map->fldrv_priv;
647 int ret = 0;
648 int chipnum;
649 unsigned long ofs, vec_seek, i;
650 int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
651
652 size_t len = 0;
653
654 for (i = 0; i < count; i++)
655 len += vecs[i].iov_len;
656
657 *retlen = 0;
658 if (!len)
659 return 0;
660
661 chipnum = to >> lpddr->chipshift;
662
663 ofs = to;
664 vec_seek = 0;
665
666 do {
667 /* We must not cross write block boundaries */
668 int size = wbufsize - (ofs & (wbufsize-1));
669
670 if (size > len)
671 size = len;
672
673 ret = do_write_buffer(map, &lpddr->chips[chipnum],
674 ofs, &vecs, &vec_seek, size);
675 if (ret)
676 return ret;
677
678 ofs += size;
679 (*retlen) += size;
680 len -= size;
681
682 /* Be nice and reschedule with the chip in a usable
683 * state for other processes */
684 cond_resched();
685
686 } while (len);
687
688 return 0;
689}
690
691static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
692{
693 unsigned long ofs, len;
694 int ret;
695 struct map_info *map = mtd->priv;
696 struct lpddr_private *lpddr = map->fldrv_priv;
697 int size = 1 << lpddr->qinfo->UniformBlockSizeShift;
698
699 ofs = instr->addr;
700 len = instr->len;
701
702 if (ofs > mtd->size || (len + ofs) > mtd->size)
703 return -EINVAL;
704
705 while (len > 0) {
706 ret = do_erase_oneblock(mtd, ofs);
707 if (ret)
708 return ret;
709 ofs += size;
710 len -= size;
711 }
712 instr->state = MTD_ERASE_DONE;
713 mtd_erase_callback(instr);
714
715 return 0;
716}
717
718#define DO_XXLOCK_LOCK 1
719#define DO_XXLOCK_UNLOCK 2
720int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
721{
722 int ret = 0;
723 struct map_info *map = mtd->priv;
724 struct lpddr_private *lpddr = map->fldrv_priv;
725 int chipnum = adr >> lpddr->chipshift;
726 struct flchip *chip = &lpddr->chips[chipnum];
727
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200728 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000729 ret = get_chip(map, chip, FL_LOCKING);
730 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200731 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000732 return ret;
733 }
734
735 if (thunk == DO_XXLOCK_LOCK) {
736 send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL);
737 chip->state = FL_LOCKING;
738 } else if (thunk == DO_XXLOCK_UNLOCK) {
739 send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL);
740 chip->state = FL_UNLOCKING;
741 } else
742 BUG();
743
744 ret = wait_for_ready(map, chip, 1);
745 if (ret) {
746 printk(KERN_ERR "%s: block unlock error status %d \n",
747 map->name, ret);
748 goto out;
749 }
750out: put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200751 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000752 return ret;
753}
754
755static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
756{
757 return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK);
758}
759
760static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
761{
762 return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
763}
764
765int word_program(struct map_info *map, loff_t adr, uint32_t curval)
766{
767 int ret;
768 struct lpddr_private *lpddr = map->fldrv_priv;
769 int chipnum = adr >> lpddr->chipshift;
770 struct flchip *chip = &lpddr->chips[chipnum];
771
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200772 mutex_lock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000773 ret = get_chip(map, chip, FL_WRITING);
774 if (ret) {
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200775 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000776 return ret;
777 }
778
779 send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval);
780
781 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime));
782 if (ret) {
783 printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n",
784 map->name, adr, curval);
785 goto out;
786 }
787
788out: put_chip(map, chip);
Stefani Seiboldc4e77372010-04-18 22:46:44 +0200789 mutex_unlock(&chip->mutex);
Alexey Korolevc6826472008-12-16 18:20:03 +0000790 return ret;
791}
792
793MODULE_LICENSE("GPL");
794MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
795MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");