diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/drivers/mtd/lpddr | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/drivers/mtd/lpddr')
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/lpddr/Kconfig | 20 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/lpddr/Makefile | 6 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/lpddr/lpddr_cmds.c | 781 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/lpddr/qinfo_probe.c | 252 |
4 files changed, 0 insertions, 1059 deletions
diff --git a/ANDROID_3.4.5/drivers/mtd/lpddr/Kconfig b/ANDROID_3.4.5/drivers/mtd/lpddr/Kconfig deleted file mode 100644 index 265f9698..00000000 --- a/ANDROID_3.4.5/drivers/mtd/lpddr/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -menu "LPDDR flash memory drivers" - depends on MTD!=n - -config MTD_LPDDR - tristate "Support for LPDDR flash chips" - select MTD_QINFO_PROBE - help - This option enables support of LPDDR (Low power double data rate) - flash chips. Synonymous with Mobile-DDR. It is a new standard for - DDR memories, intended for battery-operated systems. - -config MTD_QINFO_PROBE - depends on MTD_LPDDR - tristate "Detect flash chips by QINFO probe" - help - Device Information for LPDDR chips is offered through the Overlay - Window QINFO interface, permits software to be used for entire - families of devices. This serves similar purpose of CFI on legacy - Flash products -endmenu diff --git a/ANDROID_3.4.5/drivers/mtd/lpddr/Makefile b/ANDROID_3.4.5/drivers/mtd/lpddr/Makefile deleted file mode 100644 index da48e46b..00000000 --- a/ANDROID_3.4.5/drivers/mtd/lpddr/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# linux/drivers/mtd/lpddr/Makefile -# - -obj-$(CONFIG_MTD_QINFO_PROBE) += qinfo_probe.o -obj-$(CONFIG_MTD_LPDDR) += lpddr_cmds.o diff --git a/ANDROID_3.4.5/drivers/mtd/lpddr/lpddr_cmds.c b/ANDROID_3.4.5/drivers/mtd/lpddr/lpddr_cmds.c deleted file mode 100644 index d3cfe26b..00000000 --- a/ANDROID_3.4.5/drivers/mtd/lpddr/lpddr_cmds.c +++ /dev/null @@ -1,781 +0,0 @@ -/* - * LPDDR flash memory device operations. This module provides read, write, - * erase, lock/unlock support for LPDDR flash memories - * (C) 2008 Korolev Alexey <akorolev@infradead.org> - * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com> - * Many thanks to Roman Borisov for initial enabling - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * TODO: - * Implement VPP management - * Implement XIP support - * Implement OTP support - */ -#include <linux/mtd/pfow.h> -#include <linux/mtd/qinfo.h> -#include <linux/slab.h> -#include <linux/module.h> - -static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, - size_t *retlen, u_char *buf); -static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, - size_t len, size_t *retlen, const u_char *buf); -static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); -static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr); -static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); -static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); -static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, - size_t *retlen, void **mtdbuf, resource_size_t *phys); -static int lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len); -static int get_chip(struct map_info *map, struct flchip *chip, int mode); -static int chip_ready(struct map_info *map, struct flchip *chip, int mode); -static void put_chip(struct map_info *map, struct flchip *chip); - -struct mtd_info *lpddr_cmdset(struct map_info *map) -{ - struct lpddr_private *lpddr = map->fldrv_priv; - struct flchip_shared *shared; - struct flchip *chip; - struct mtd_info *mtd; - int numchips; - int i, j; - - mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); - if (!mtd) { - printk(KERN_ERR "Failed to allocate memory for MTD device\n"); - return NULL; - } - mtd->priv = map; - mtd->type = MTD_NORFLASH; - - /* Fill in the default mtd operations */ - mtd->_read = lpddr_read; - mtd->type = MTD_NORFLASH; - mtd->flags = MTD_CAP_NORFLASH; - mtd->flags &= ~MTD_BIT_WRITEABLE; - mtd->_erase = lpddr_erase; - mtd->_write = lpddr_write_buffers; - mtd->_writev = lpddr_writev; - mtd->_lock = lpddr_lock; - mtd->_unlock = lpddr_unlock; - if (map_is_linear(map)) { - mtd->_point = lpddr_point; - mtd->_unpoint = lpddr_unpoint; - } - mtd->size = 1 << lpddr->qinfo->DevSizeShift; - mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift; - mtd->writesize = 1 << lpddr->qinfo->BufSizeShift; - - shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips, - GFP_KERNEL); - if (!shared) { - kfree(lpddr); - kfree(mtd); - return NULL; - } - - chip = &lpddr->chips[0]; - numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum; - for (i = 0; i < numchips; i++) { - shared[i].writing = shared[i].erasing = NULL; - mutex_init(&shared[i].lock); - for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) { - *chip = lpddr->chips[i]; - chip->start += j << lpddr->chipshift; - chip->oldstate = chip->state = FL_READY; - chip->priv = &shared[i]; - /* those should be reset too since - they create memory references. */ - init_waitqueue_head(&chip->wq); - mutex_init(&chip->mutex); - chip++; - } - } - - return mtd; -} -EXPORT_SYMBOL(lpddr_cmdset); - -static int wait_for_ready(struct map_info *map, struct flchip *chip, - unsigned int chip_op_time) -{ - unsigned int timeo, reset_timeo, sleep_time; - unsigned int dsr; - flstate_t chip_state = chip->state; - int ret = 0; - - /* set our timeout to 8 times the expected delay */ - timeo = chip_op_time * 8; - if (!timeo) - timeo = 500000; - reset_timeo = timeo; - sleep_time = chip_op_time / 2; - - for (;;) { - dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); - if (dsr & DSR_READY_STATUS) - break; - if (!timeo) { - printk(KERN_ERR "%s: Flash timeout error state %d \n", - map->name, chip_state); - ret = -ETIME; - break; - } - - /* OK Still waiting. Drop the lock, wait a while and retry. */ - mutex_unlock(&chip->mutex); - if (sleep_time >= 1000000/HZ) { - /* - * Half of the normal delay still remaining - * can be performed with a sleeping delay instead - * of busy waiting. - */ - msleep(sleep_time/1000); - timeo -= sleep_time; - sleep_time = 1000000/HZ; - } else { - udelay(1); - cond_resched(); - timeo--; - } - mutex_lock(&chip->mutex); - - while (chip->state != chip_state) { - /* Someone's suspended the operation: sleep */ - DECLARE_WAITQUEUE(wait, current); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - mutex_unlock(&chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - mutex_lock(&chip->mutex); - } - if (chip->erase_suspended || chip->write_suspended) { - /* Suspend has occurred while sleep: reset timeout */ - timeo = reset_timeo; - chip->erase_suspended = chip->write_suspended = 0; - } - } - /* check status for errors */ - if (dsr & DSR_ERR) { - /* Clear DSR*/ - map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR); - printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n", - map->name, dsr); - print_drs_error(dsr); - ret = -EIO; - } - chip->state = FL_READY; - return ret; -} - -static int get_chip(struct map_info *map, struct flchip *chip, int mode) -{ - int ret; - DECLARE_WAITQUEUE(wait, current); - - retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING) - && chip->state != FL_SYNCING) { - /* - * OK. We have possibility for contension on the write/erase - * operations which are global to the real chip and not per - * partition. So let's fight it over in the partition which - * currently has authority on the operation. - * - * The rules are as follows: - * - * - any write operation must own shared->writing. - * - * - any erase operation must own _both_ shared->writing and - * shared->erasing. - * - * - contension arbitration is handled in the owner's context. - * - * The 'shared' struct can be read and/or written only when - * its lock is taken. - */ - struct flchip_shared *shared = chip->priv; - struct flchip *contender; - mutex_lock(&shared->lock); - contender = shared->writing; - if (contender && contender != chip) { - /* - * The engine to perform desired operation on this - * partition is already in use by someone else. - * Let's fight over it in the context of the chip - * currently using it. If it is possible to suspend, - * that other partition will do just that, otherwise - * it'll happily send us to sleep. In any case, when - * get_chip returns success we're clear to go ahead. - */ - ret = mutex_trylock(&contender->mutex); - mutex_unlock(&shared->lock); - if (!ret) - goto retry; - mutex_unlock(&chip->mutex); - ret = chip_ready(map, contender, mode); - mutex_lock(&chip->mutex); - - if (ret == -EAGAIN) { - mutex_unlock(&contender->mutex); - goto retry; - } - if (ret) { - mutex_unlock(&contender->mutex); - return ret; - } - mutex_lock(&shared->lock); - - /* We should not own chip if it is already in FL_SYNCING - * state. Put contender and retry. */ - if (chip->state == FL_SYNCING) { - put_chip(map, contender); - mutex_unlock(&contender->mutex); - goto retry; - } - mutex_unlock(&contender->mutex); - } - - /* Check if we have suspended erase on this chip. - Must sleep in such a case. */ - if (mode == FL_ERASING && shared->erasing - && shared->erasing->oldstate == FL_ERASING) { - mutex_unlock(&shared->lock); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - mutex_unlock(&chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - mutex_lock(&chip->mutex); - goto retry; - } - - /* We now own it */ - shared->writing = chip; - if (mode == FL_ERASING) - shared->erasing = chip; - mutex_unlock(&shared->lock); - } - - ret = chip_ready(map, chip, mode); - if (ret == -EAGAIN) - goto retry; - - return ret; -} - -static int chip_ready(struct map_info *map, struct flchip *chip, int mode) -{ - struct lpddr_private *lpddr = map->fldrv_priv; - int ret = 0; - DECLARE_WAITQUEUE(wait, current); - - /* Prevent setting state FL_SYNCING for chip in suspended state. */ - if (FL_SYNCING == mode && FL_READY != chip->oldstate) - goto sleep; - - switch (chip->state) { - case FL_READY: - case FL_JEDEC_QUERY: - return 0; - - case FL_ERASING: - if (!lpddr->qinfo->SuspEraseSupp || - !(mode == FL_READY || mode == FL_POINT)) - goto sleep; - - map_write(map, CMD(LPDDR_SUSPEND), - map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND); - chip->oldstate = FL_ERASING; - chip->state = FL_ERASE_SUSPENDING; - ret = wait_for_ready(map, chip, 0); - if (ret) { - /* Oops. something got wrong. */ - /* Resume and pretend we weren't here. */ - put_chip(map, chip); - printk(KERN_ERR "%s: suspend operation failed." - "State may be wrong \n", map->name); - return -EIO; - } - chip->erase_suspended = 1; - chip->state = FL_READY; - return 0; - /* Erase suspend */ - case FL_POINT: - /* Only if there's no operation suspended... */ - if (mode == FL_READY && chip->oldstate == FL_READY) - return 0; - - default: -sleep: - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - mutex_unlock(&chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - mutex_lock(&chip->mutex); - return -EAGAIN; - } -} - -static void put_chip(struct map_info *map, struct flchip *chip) -{ - if (chip->priv) { - struct flchip_shared *shared = chip->priv; - mutex_lock(&shared->lock); - if (shared->writing == chip && chip->oldstate == FL_READY) { - /* We own the ability to write, but we're done */ - shared->writing = shared->erasing; - if (shared->writing && shared->writing != chip) { - /* give back the ownership */ - struct flchip *loaner = shared->writing; - mutex_lock(&loaner->mutex); - mutex_unlock(&shared->lock); - mutex_unlock(&chip->mutex); - put_chip(map, loaner); - mutex_lock(&chip->mutex); - mutex_unlock(&loaner->mutex); - wake_up(&chip->wq); - return; - } - shared->erasing = NULL; - shared->writing = NULL; - } else if (shared->erasing == chip && shared->writing != chip) { - /* - * We own the ability to erase without the ability - * to write, which means the erase was suspended - * and some other partition is currently writing. - * Don't let the switch below mess things up since - * we don't have ownership to resume anything. - */ - mutex_unlock(&shared->lock); - wake_up(&chip->wq); - return; - } - mutex_unlock(&shared->lock); - } - - switch (chip->oldstate) { - case FL_ERASING: - map_write(map, CMD(LPDDR_RESUME), - map->pfow_base + PFOW_COMMAND_CODE); - map_write(map, CMD(LPDDR_START_EXECUTION), - map->pfow_base + PFOW_COMMAND_EXECUTE); - chip->oldstate = FL_READY; - chip->state = FL_ERASING; - break; - case FL_READY: - break; - default: - printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n", - map->name, chip->oldstate); - } - wake_up(&chip->wq); -} - -int do_write_buffer(struct map_info *map, struct flchip *chip, - unsigned long adr, const struct kvec **pvec, - unsigned long *pvec_seek, int len) -{ - struct lpddr_private *lpddr = map->fldrv_priv; - map_word datum; - int ret, wbufsize, word_gap, words; - const struct kvec *vec; - unsigned long vec_seek; - unsigned long prog_buf_ofs; - - wbufsize = 1 << lpddr->qinfo->BufSizeShift; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_WRITING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - /* Figure out the number of words to write */ - word_gap = (-adr & (map_bankwidth(map)-1)); - words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); - if (!word_gap) { - words--; - } else { - word_gap = map_bankwidth(map) - word_gap; - adr -= word_gap; - datum = map_word_ff(map); - } - /* Write data */ - /* Get the program buffer offset from PFOW register data first*/ - prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map, - map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET)); - vec = *pvec; - vec_seek = *pvec_seek; - do { - int n = map_bankwidth(map) - word_gap; - - if (n > vec->iov_len - vec_seek) - n = vec->iov_len - vec_seek; - if (n > len) - n = len; - - if (!word_gap && (len < map_bankwidth(map))) - datum = map_word_ff(map); - - datum = map_word_load_partial(map, datum, - vec->iov_base + vec_seek, word_gap, n); - - len -= n; - word_gap += n; - if (!len || word_gap == map_bankwidth(map)) { - map_write(map, datum, prog_buf_ofs); - prog_buf_ofs += map_bankwidth(map); - word_gap = 0; - } - - vec_seek += n; - if (vec_seek == vec->iov_len) { - vec++; - vec_seek = 0; - } - } while (len); - *pvec = vec; - *pvec_seek = vec_seek; - - /* GO GO GO */ - send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL); - chip->state = FL_WRITING; - ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime)); - if (ret) { - printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n", - map->name, ret, adr); - goto out; - } - - out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - -int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) -{ - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - int ret; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_ERASING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL); - chip->state = FL_ERASING; - ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000); - if (ret) { - printk(KERN_WARNING"%s Erase block error %d at : %llx\n", - map->name, ret, adr); - goto out; - } - out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - -static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, - size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - int ret = 0; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_READY); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - - map_copy_from(map, buf, adr, len); - *retlen = len; - - put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - -static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, - size_t *retlen, void **mtdbuf, resource_size_t *phys) -{ - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - unsigned long ofs, last_end = 0; - struct flchip *chip = &lpddr->chips[chipnum]; - int ret = 0; - - if (!map->virt) - return -EINVAL; - - /* ofs: offset within the first chip that the first read should start */ - ofs = adr - (chipnum << lpddr->chipshift); - *mtdbuf = (void *)map->virt + chip->start + ofs; - - while (len) { - unsigned long thislen; - - if (chipnum >= lpddr->numchips) - break; - - /* We cannot point across chips that are virtually disjoint */ - if (!last_end) - last_end = chip->start; - else if (chip->start != last_end) - break; - - if ((len + ofs - 1) >> lpddr->chipshift) - thislen = (1<<lpddr->chipshift) - ofs; - else - thislen = len; - /* get the chip */ - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_POINT); - mutex_unlock(&chip->mutex); - if (ret) - break; - - chip->state = FL_POINT; - chip->ref_point_counter++; - *retlen += thislen; - len -= thislen; - - ofs = 0; - last_end += 1 << lpddr->chipshift; - chipnum++; - chip = &lpddr->chips[chipnum]; - } - return 0; -} - -static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len) -{ - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift, err = 0; - unsigned long ofs; - - /* ofs: offset within the first chip that the first read should start */ - ofs = adr - (chipnum << lpddr->chipshift); - - while (len) { - unsigned long thislen; - struct flchip *chip; - - chip = &lpddr->chips[chipnum]; - if (chipnum >= lpddr->numchips) - break; - - if ((len + ofs - 1) >> lpddr->chipshift) - thislen = (1<<lpddr->chipshift) - ofs; - else - thislen = len; - - mutex_lock(&chip->mutex); - if (chip->state == FL_POINT) { - chip->ref_point_counter--; - if (chip->ref_point_counter == 0) - chip->state = FL_READY; - } else { - printk(KERN_WARNING "%s: Warning: unpoint called on non" - "pointed region\n", map->name); - err = -EINVAL; - } - - put_chip(map, chip); - mutex_unlock(&chip->mutex); - - len -= thislen; - ofs = 0; - chipnum++; - } - - return err; -} - -static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct kvec vec; - - vec.iov_base = (void *) buf; - vec.iov_len = len; - - return lpddr_writev(mtd, &vec, 1, to, retlen); -} - - -static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen) -{ - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int ret = 0; - int chipnum; - unsigned long ofs, vec_seek, i; - int wbufsize = 1 << lpddr->qinfo->BufSizeShift; - size_t len = 0; - - for (i = 0; i < count; i++) - len += vecs[i].iov_len; - - if (!len) - return 0; - - chipnum = to >> lpddr->chipshift; - - ofs = to; - vec_seek = 0; - - do { - /* We must not cross write block boundaries */ - int size = wbufsize - (ofs & (wbufsize-1)); - - if (size > len) - size = len; - - ret = do_write_buffer(map, &lpddr->chips[chipnum], - ofs, &vecs, &vec_seek, size); - if (ret) - return ret; - - ofs += size; - (*retlen) += size; - len -= size; - - /* Be nice and reschedule with the chip in a usable - * state for other processes */ - cond_resched(); - - } while (len); - - return 0; -} - -static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - unsigned long ofs, len; - int ret; - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int size = 1 << lpddr->qinfo->UniformBlockSizeShift; - - ofs = instr->addr; - len = instr->len; - - while (len > 0) { - ret = do_erase_oneblock(mtd, ofs); - if (ret) - return ret; - ofs += size; - len -= size; - } - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; -} - -#define DO_XXLOCK_LOCK 1 -#define DO_XXLOCK_UNLOCK 2 -int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk) -{ - int ret = 0; - struct map_info *map = mtd->priv; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_LOCKING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - - if (thunk == DO_XXLOCK_LOCK) { - send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL); - chip->state = FL_LOCKING; - } else if (thunk == DO_XXLOCK_UNLOCK) { - send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL); - chip->state = FL_UNLOCKING; - } else - BUG(); - - ret = wait_for_ready(map, chip, 1); - if (ret) { - printk(KERN_ERR "%s: block unlock error status %d \n", - map->name, ret); - goto out; - } -out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - -static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK); -} - -static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK); -} - -int word_program(struct map_info *map, loff_t adr, uint32_t curval) -{ - int ret; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_WRITING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - - send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval); - - ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime)); - if (ret) { - printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n", - map->name, adr, curval); - goto out; - } - -out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>"); -MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); diff --git a/ANDROID_3.4.5/drivers/mtd/lpddr/qinfo_probe.c b/ANDROID_3.4.5/drivers/mtd/lpddr/qinfo_probe.c deleted file mode 100644 index dbfe17ba..00000000 --- a/ANDROID_3.4.5/drivers/mtd/lpddr/qinfo_probe.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Probing flash chips with QINFO records. - * (C) 2008 Korolev Alexey <akorolev@infradead.org> - * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> - -#include <linux/mtd/xip.h> -#include <linux/mtd/map.h> -#include <linux/mtd/pfow.h> -#include <linux/mtd/qinfo.h> - -static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr); -struct mtd_info *lpddr_probe(struct map_info *map); -static struct lpddr_private *lpddr_probe_chip(struct map_info *map); -static int lpddr_pfow_present(struct map_info *map, - struct lpddr_private *lpddr); - -static struct qinfo_query_info qinfo_array[] = { - /* General device info */ - {0, 0, "DevSizeShift", "Device size 2^n bytes"}, - {0, 3, "BufSizeShift", "Program buffer size 2^n bytes"}, - /* Erase block information */ - {1, 1, "TotalBlocksNum", "Total number of blocks"}, - {1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"}, - /* Partition information */ - {2, 1, "HWPartsNum", "Number of hardware partitions"}, - /* Optional features */ - {5, 1, "SuspEraseSupp", "Suspend erase supported"}, - /* Operation typical time */ - {10, 0, "SingleWordProgTime", "Single word program 2^n u-sec"}, - {10, 1, "ProgBufferTime", "Program buffer write 2^n u-sec"}, - {10, 2, "BlockEraseTime", "Block erase 2^n m-sec"}, - {10, 3, "FullChipEraseTime", "Full chip erase 2^n m-sec"}, -}; - -static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) -{ - int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info); - int i; - int bankwidth = map_bankwidth(map) * 8; - int major, minor; - - for (i = 0; i < qinfo_lines; i++) { - if (strcmp(id_str, qinfo_array[i].id_str) == 0) { - major = qinfo_array[i].major & ((1 << bankwidth) - 1); - minor = qinfo_array[i].minor & ((1 << bankwidth) - 1); - return minor | (major << bankwidth); - } - } - printk(KERN_ERR"%s qinfo id string is wrong! \n", map->name); - BUG(); - return -1; -} - -static uint16_t lpddr_info_query(struct map_info *map, char *id_str) -{ - unsigned int dsr, val; - int bits_per_chip = map_bankwidth(map) * 8; - unsigned long adr = lpddr_get_qinforec_pos(map, id_str); - int attempts = 20; - - /* Write a request for the PFOW record */ - map_write(map, CMD(LPDDR_INFO_QUERY), - map->pfow_base + PFOW_COMMAND_CODE); - map_write(map, CMD(adr & ((1 << bits_per_chip) - 1)), - map->pfow_base + PFOW_COMMAND_ADDRESS_L); - map_write(map, CMD(adr >> bits_per_chip), - map->pfow_base + PFOW_COMMAND_ADDRESS_H); - map_write(map, CMD(LPDDR_START_EXECUTION), - map->pfow_base + PFOW_COMMAND_EXECUTE); - - while ((attempts--) > 0) { - dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); - if (dsr & DSR_READY_STATUS) - break; - udelay(10); - } - - val = CMDVAL(map_read(map, map->pfow_base + PFOW_COMMAND_DATA)); - return val; -} - -static int lpddr_pfow_present(struct map_info *map, struct lpddr_private *lpddr) -{ - map_word pfow_val[4]; - - /* Check identification string */ - pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P); - pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F); - pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O); - pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W); - - if (!map_word_equal(map, CMD('P'), pfow_val[0])) - goto out; - - if (!map_word_equal(map, CMD('F'), pfow_val[1])) - goto out; - - if (!map_word_equal(map, CMD('O'), pfow_val[2])) - goto out; - - if (!map_word_equal(map, CMD('W'), pfow_val[3])) - goto out; - - return 1; /* "PFOW" is found */ -out: - printk(KERN_WARNING"%s: PFOW string at 0x%lx is not found \n", - map->name, map->pfow_base); - return 0; -} - -static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr) -{ - - lpddr->qinfo = kzalloc(sizeof(struct qinfo_chip), GFP_KERNEL); - if (!lpddr->qinfo) { - printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n", - map->name); - return 0; - } - - /* Get the ManuID */ - lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID)); - /* Get the DeviceID */ - lpddr->DevId = CMDVAL(map_read(map, map->pfow_base + PFOW_DEVICE_ID)); - /* read parameters from chip qinfo table */ - lpddr->qinfo->DevSizeShift = lpddr_info_query(map, "DevSizeShift"); - lpddr->qinfo->TotalBlocksNum = lpddr_info_query(map, "TotalBlocksNum"); - lpddr->qinfo->BufSizeShift = lpddr_info_query(map, "BufSizeShift"); - lpddr->qinfo->HWPartsNum = lpddr_info_query(map, "HWPartsNum"); - lpddr->qinfo->UniformBlockSizeShift = - lpddr_info_query(map, "UniformBlockSizeShift"); - lpddr->qinfo->SuspEraseSupp = lpddr_info_query(map, "SuspEraseSupp"); - lpddr->qinfo->SingleWordProgTime = - lpddr_info_query(map, "SingleWordProgTime"); - lpddr->qinfo->ProgBufferTime = lpddr_info_query(map, "ProgBufferTime"); - lpddr->qinfo->BlockEraseTime = lpddr_info_query(map, "BlockEraseTime"); - return 1; -} -static struct lpddr_private *lpddr_probe_chip(struct map_info *map) -{ - struct lpddr_private lpddr; - struct lpddr_private *retlpddr; - int numvirtchips; - - - if ((map->pfow_base + 0x1000) >= map->size) { - printk(KERN_NOTICE"%s Probe at base (0x%08lx) past the end of" - "the map(0x%08lx)\n", map->name, - (unsigned long)map->pfow_base, map->size - 1); - return NULL; - } - memset(&lpddr, 0, sizeof(struct lpddr_private)); - if (!lpddr_pfow_present(map, &lpddr)) - return NULL; - - if (!lpddr_chip_setup(map, &lpddr)) - return NULL; - - /* Ok so we found a chip */ - lpddr.chipshift = lpddr.qinfo->DevSizeShift; - lpddr.numchips = 1; - - numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum; - retlpddr = kzalloc(sizeof(struct lpddr_private) + - numvirtchips * sizeof(struct flchip), GFP_KERNEL); - if (!retlpddr) - return NULL; - - memcpy(retlpddr, &lpddr, sizeof(struct lpddr_private)); - - retlpddr->numchips = numvirtchips; - retlpddr->chipshift = retlpddr->qinfo->DevSizeShift - - __ffs(retlpddr->qinfo->HWPartsNum); - - return retlpddr; -} - -struct mtd_info *lpddr_probe(struct map_info *map) -{ - struct mtd_info *mtd = NULL; - struct lpddr_private *lpddr; - - /* First probe the map to see if we havecan open PFOW here */ - lpddr = lpddr_probe_chip(map); - if (!lpddr) - return NULL; - - map->fldrv_priv = lpddr; - mtd = lpddr_cmdset(map); - if (mtd) { - if (mtd->size > map->size) { - printk(KERN_WARNING "Reducing visibility of %ldKiB chip" - "to %ldKiB\n", (unsigned long)mtd->size >> 10, - (unsigned long)map->size >> 10); - mtd->size = map->size; - } - return mtd; - } - - kfree(lpddr->qinfo); - kfree(lpddr); - map->fldrv_priv = NULL; - return NULL; -} - -static struct mtd_chip_driver lpddr_chipdrv = { - .probe = lpddr_probe, - .name = "qinfo_probe", - .module = THIS_MODULE -}; - -static int __init lpddr_probe_init(void) -{ - register_mtd_chip_driver(&lpddr_chipdrv); - return 0; -} - -static void __exit lpddr_probe_exit(void) -{ - unregister_mtd_chip_driver(&lpddr_chipdrv); -} - -module_init(lpddr_probe_init); -module_exit(lpddr_probe_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Vasiliy Leonenko <vasiliy.leonenko@gmail.com>"); -MODULE_DESCRIPTION("Driver to probe qinfo flash chips"); - |