Merge branch 'for-next/onfi'
This commit is contained in:
commit
b1a4e722c3
|
@ -1026,6 +1026,108 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sanitize ONFI strings so we can safely print them
|
||||||
|
*/
|
||||||
|
static void sanitize_string(char *s, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t i;
|
||||||
|
|
||||||
|
/* null terminate */
|
||||||
|
s[len - 1] = 0;
|
||||||
|
|
||||||
|
/* remove non printable chars */
|
||||||
|
for (i = 0; i < len - 1; i++) {
|
||||||
|
if (s[i] < ' ' || s[i] > 127)
|
||||||
|
s[i] = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove trailing spaces */
|
||||||
|
strim(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
while (len--) {
|
||||||
|
crc ^= *p++ << 8;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
int *busw)
|
||||||
|
{
|
||||||
|
struct nand_onfi_params *p = &chip->onfi_params;
|
||||||
|
int i;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
/* try ONFI for unknow chip or LP */
|
||||||
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
||||||
|
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
||||||
|
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
printk(KERN_INFO "ONFI flash detected ... ");
|
||||||
|
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
||||||
|
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
||||||
|
le16_to_cpu(p->crc)) {
|
||||||
|
printk(KERN_INFO "ONFI param page %d valid\n", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
printk(KERN_INFO "no valid ONFI param page found\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check version */
|
||||||
|
val = le16_to_cpu(p->revision);
|
||||||
|
if (val & (1 << 5))
|
||||||
|
chip->onfi_version = 23;
|
||||||
|
else if (val & (1 << 4))
|
||||||
|
chip->onfi_version = 22;
|
||||||
|
else if (val & (1 << 3))
|
||||||
|
chip->onfi_version = 21;
|
||||||
|
else if (val & (1 << 2))
|
||||||
|
chip->onfi_version = 20;
|
||||||
|
else if (val & (1 << 1))
|
||||||
|
chip->onfi_version = 10;
|
||||||
|
else
|
||||||
|
chip->onfi_version = 0;
|
||||||
|
|
||||||
|
if (!chip->onfi_version) {
|
||||||
|
printk(KERN_INFO "unsupported ONFI version: %d\n", val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
||||||
|
sanitize_string(p->model, sizeof(p->model));
|
||||||
|
if (!mtd->name)
|
||||||
|
mtd->name = p->model;
|
||||||
|
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||||
|
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||||||
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||||
|
chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
|
||||||
|
*busw = 0;
|
||||||
|
if (le16_to_cpu(p->features) & 1)
|
||||||
|
*busw = NAND_BUSWIDTH_16;
|
||||||
|
|
||||||
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
||||||
|
chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the flash and manufacturer id and lookup if the type is supported
|
* Get the flash and manufacturer id and lookup if the type is supported
|
||||||
*/
|
*/
|
||||||
|
@ -1036,6 +1138,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
struct nand_flash_dev *type = NULL;
|
struct nand_flash_dev *type = NULL;
|
||||||
int i, dev_id, maf_idx;
|
int i, dev_id, maf_idx;
|
||||||
int tmp_id, tmp_manf;
|
int tmp_id, tmp_manf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Select the device */
|
/* Select the device */
|
||||||
chip->select_chip(mtd, 0);
|
chip->select_chip(mtd, 0);
|
||||||
|
@ -1081,9 +1184,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chip->onfi_version = 0;
|
||||||
if (!type) {
|
if (!type) {
|
||||||
printk(KERN_ERR "NAND type unknown: %02x,%02x\n", *maf_id, dev_id);
|
/* Check is chip is ONFI compliant */
|
||||||
return ERR_PTR(-ENODEV);
|
ret = nand_flash_detect_onfi(mtd, chip, &busw);
|
||||||
|
if (ret)
|
||||||
|
goto ident_done;
|
||||||
|
else {
|
||||||
|
printk(KERN_ERR "NAND type unknown: %02x,%02x\n", *maf_id, dev_id);
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mtd->name)
|
if (!mtd->name)
|
||||||
|
@ -1126,17 +1236,39 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get chip options, preserve non chip based options */
|
||||||
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
||||||
|
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
|
||||||
|
|
||||||
|
/* Check if chip is a not a samsung device. Do not clear the
|
||||||
|
* options for chips which are not having an extended id.
|
||||||
|
*/
|
||||||
|
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
||||||
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
||||||
|
|
||||||
|
ident_done:
|
||||||
|
/*
|
||||||
|
* Set chip as a default. Board drivers can override it, if necessary
|
||||||
|
*/
|
||||||
|
chip->options |= NAND_NO_AUTOINCR;
|
||||||
|
|
||||||
|
/* Try to identify manufacturer */
|
||||||
|
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
|
||||||
|
if (nand_manuf_ids[maf_idx].id == *maf_id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check, if buswidth is correct. Hardware drivers should set
|
* Check, if buswidth is correct. Hardware drivers should set
|
||||||
* chip correct !
|
* chip correct !
|
||||||
*/
|
*/
|
||||||
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
|
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
|
||||||
printk(KERN_INFO "NAND device: Manufacturer ID:"
|
printk(KERN_INFO "NAND device: Manufacturer ID:"
|
||||||
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
|
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
|
||||||
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
|
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
|
||||||
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
|
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
|
||||||
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
||||||
busw ? 16 : 8);
|
busw ? 16 : 8);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1147,27 +1279,17 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
|
|
||||||
chip->bbt_erase_shift = chip->phys_erase_shift =
|
chip->bbt_erase_shift = chip->phys_erase_shift =
|
||||||
ffs(mtd->erasesize) - 1;
|
ffs(mtd->erasesize) - 1;
|
||||||
chip->chip_shift = ffs(chip->chipsize) - 1;
|
if (chip->chipsize & 0xffffffff)
|
||||||
|
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
|
||||||
|
else {
|
||||||
|
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
|
||||||
|
chip->chip_shift += 32 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the bad block position */
|
/* Set the bad block position */
|
||||||
chip->badblockpos = mtd->writesize > 512 ?
|
chip->badblockpos = mtd->writesize > 512 ?
|
||||||
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
|
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
|
||||||
|
|
||||||
/* Get chip options, preserve non chip based options */
|
|
||||||
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
|
||||||
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set chip as a default. Board drivers can override it, if necessary
|
|
||||||
*/
|
|
||||||
chip->options |= NAND_NO_AUTOINCR;
|
|
||||||
|
|
||||||
/* Check if chip is a not a samsung device. Do not clear the
|
|
||||||
* options for chips which are not having an extended id.
|
|
||||||
*/
|
|
||||||
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
|
||||||
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_WRITE
|
#ifdef CONFIG_MTD_WRITE
|
||||||
/* Check for AND chips with 4 page planes */
|
/* Check for AND chips with 4 page planes */
|
||||||
if (chip->options & NAND_4PAGE_ARRAY)
|
if (chip->options & NAND_4PAGE_ARRAY)
|
||||||
|
@ -1179,9 +1301,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
||||||
chip->cmdfunc = nand_command_lp;
|
chip->cmdfunc = nand_command_lp;
|
||||||
|
|
||||||
printk(KERN_INFO "NAND device: Manufacturer ID:"
|
printk("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
|
||||||
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
|
" page size: %d, OOB size: %d\n",
|
||||||
nand_manuf_ids[maf_idx].name, type->name);
|
*maf_id, dev_id, nand_manuf_ids[maf_idx].name,
|
||||||
|
chip->onfi_version ? chip->onfi_params.model : type->name,
|
||||||
|
mtd->writesize, mtd->oobsize);
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct imx_nand_host {
|
||||||
void (*send_addr)(struct imx_nand_host *, uint16_t);
|
void (*send_addr)(struct imx_nand_host *, uint16_t);
|
||||||
void (*send_page)(struct imx_nand_host *, unsigned int);
|
void (*send_page)(struct imx_nand_host *, unsigned int);
|
||||||
void (*send_read_id)(struct imx_nand_host *);
|
void (*send_read_id)(struct imx_nand_host *);
|
||||||
|
void (*send_read_param)(struct imx_nand_host *);
|
||||||
uint16_t (*get_dev_status)(struct imx_nand_host *);
|
uint16_t (*get_dev_status)(struct imx_nand_host *);
|
||||||
int (*check_int)(struct imx_nand_host *);
|
int (*check_int)(struct imx_nand_host *);
|
||||||
};
|
};
|
||||||
|
@ -154,6 +155,31 @@ static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* OOB description for 4096 byte pages with 128 byte OOB */
|
||||||
|
static struct nand_ecclayout nandv2_hw_eccoob_4k = {
|
||||||
|
.eccbytes = 8 * 9,
|
||||||
|
.eccpos = {
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||||
|
55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||||
|
71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||||
|
87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||||
|
103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||||
|
119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||||
|
},
|
||||||
|
.oobfree = {
|
||||||
|
{.offset = 2, .length = 4},
|
||||||
|
{.offset = 16, .length = 7},
|
||||||
|
{.offset = 32, .length = 7},
|
||||||
|
{.offset = 48, .length = 7},
|
||||||
|
{.offset = 64, .length = 7},
|
||||||
|
{.offset = 80, .length = 7},
|
||||||
|
{.offset = 96, .length = 7},
|
||||||
|
{.offset = 112, .length = 7},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void memcpy32(void *trg, const void *src, int size)
|
static void memcpy32(void *trg, const void *src, int size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -335,6 +361,16 @@ static void send_read_id_v3(struct imx_nand_host *host)
|
||||||
memcpy(host->data_buf, host->main_area0, 16);
|
memcpy(host->data_buf, host->main_area0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void send_read_param_v3(struct imx_nand_host *host)
|
||||||
|
{
|
||||||
|
/* Read ID into main buffer */
|
||||||
|
writel(NFC_OUTPUT, NFC_V3_LAUNCH);
|
||||||
|
|
||||||
|
wait_op_done(host);
|
||||||
|
|
||||||
|
memcpy(host->data_buf, host->main_area0, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
static void send_read_id_v1_v2(struct imx_nand_host *host)
|
static void send_read_id_v1_v2(struct imx_nand_host *host)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = &host->nand;
|
struct nand_chip *this = &host->nand;
|
||||||
|
@ -363,6 +399,34 @@ static void send_read_id_v1_v2(struct imx_nand_host *host)
|
||||||
memcpy32(host->data_buf, host->main_area0, 16);
|
memcpy32(host->data_buf, host->main_area0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME : to check on real HW */
|
||||||
|
static void send_read_param_v1_v2(struct imx_nand_host *host)
|
||||||
|
{
|
||||||
|
struct nand_chip *this = &host->nand;
|
||||||
|
|
||||||
|
/* NANDFC buffer 0 is used for device ID output */
|
||||||
|
writew(0x0, host->regs + NFC_V1_V2_BUF_ADDR);
|
||||||
|
|
||||||
|
writew(NFC_OUTPUT, host->regs + NFC_V1_V2_CONFIG2);
|
||||||
|
|
||||||
|
/* Wait for operation to complete */
|
||||||
|
wait_op_done(host);
|
||||||
|
|
||||||
|
if (this->options & NAND_BUSWIDTH_16) {
|
||||||
|
volatile u16 *mainbuf = host->main_area0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pack the every-other-byte result for 16-bit ID reads
|
||||||
|
* into every-byte as the generic code expects and various
|
||||||
|
* chips implement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mainbuf[0] = (mainbuf[0] & 0xff) | ((mainbuf[1] & 0xff) << 8);
|
||||||
|
mainbuf[1] = (mainbuf[2] & 0xff) | ((mainbuf[3] & 0xff) << 8);
|
||||||
|
mainbuf[2] = (mainbuf[4] & 0xff) | ((mainbuf[5] & 0xff) << 8);
|
||||||
|
}
|
||||||
|
memcpy32(host->data_buf, host->main_area0, 1024);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* This function requests the NANDFC to perform a read of the
|
* This function requests the NANDFC to perform a read of the
|
||||||
* NAND device status and returns the current status.
|
* NAND device status and returns the current status.
|
||||||
|
@ -579,6 +643,10 @@ static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len)
|
||||||
|
|
||||||
n = min(n, len);
|
n = min(n, len);
|
||||||
|
|
||||||
|
/* handle the read param special case */
|
||||||
|
if ((mtd->writesize == 0) && (len != 0))
|
||||||
|
n = len;
|
||||||
|
|
||||||
memcpy(buf, host->data_buf + col, n);
|
memcpy(buf, host->data_buf + col, n);
|
||||||
|
|
||||||
host->buf_start += n;
|
host->buf_start += n;
|
||||||
|
@ -677,8 +745,11 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
|
||||||
* layers perform a read/write buf operation,
|
* layers perform a read/write buf operation,
|
||||||
* we will used the saved column adress to index into
|
* we will used the saved column adress to index into
|
||||||
* the full page.
|
* the full page.
|
||||||
|
*
|
||||||
|
* The colum address must be sent to the flash in
|
||||||
|
* order to get the ONFI header (0x20)
|
||||||
*/
|
*/
|
||||||
host->send_addr(host, 0);
|
host->send_addr(host, column);
|
||||||
if (host->pagesize_2k)
|
if (host->pagesize_2k)
|
||||||
/* another col addr cycle for 2k page */
|
/* another col addr cycle for 2k page */
|
||||||
host->send_addr(host, 0);
|
host->send_addr(host, 0);
|
||||||
|
@ -790,9 +861,11 @@ static void preset_v3(struct mtd_info *mtd)
|
||||||
|
|
||||||
writel(0, NFC_V3_IPC);
|
writel(0, NFC_V3_IPC);
|
||||||
|
|
||||||
|
/* if the flash has a 224 oob, the NFC must be configured to 218 */
|
||||||
config2 = NFC_V3_CONFIG2_ONE_CYCLE |
|
config2 = NFC_V3_CONFIG2_ONE_CYCLE |
|
||||||
NFC_V3_CONFIG2_2CMD_PHASES |
|
NFC_V3_CONFIG2_2CMD_PHASES |
|
||||||
NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
|
NFC_V3_CONFIG2_SPAS(((mtd->oobsize > 218) ?
|
||||||
|
218 : mtd->oobsize) >> 1) |
|
||||||
NFC_V3_CONFIG2_ST_CMD(0x70) |
|
NFC_V3_CONFIG2_ST_CMD(0x70) |
|
||||||
NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
|
NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
|
||||||
|
|
||||||
|
@ -944,8 +1017,15 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command,
|
||||||
case NAND_CMD_READID:
|
case NAND_CMD_READID:
|
||||||
host->send_cmd(host, command);
|
host->send_cmd(host, command);
|
||||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||||
host->buf_start = 0;
|
|
||||||
host->send_read_id(host);
|
host->send_read_id(host);
|
||||||
|
host->buf_start = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAND_CMD_PARAM:
|
||||||
|
host->send_cmd(host, command);
|
||||||
|
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||||
|
host->send_read_param(host);
|
||||||
|
host->buf_start = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CMD_ERASE1:
|
case NAND_CMD_ERASE1:
|
||||||
|
@ -1024,7 +1104,7 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
struct mtd_info *mtd;
|
struct mtd_info *mtd;
|
||||||
struct imx_nand_platform_data *pdata = dev->platform_data;
|
struct imx_nand_platform_data *pdata = dev->platform_data;
|
||||||
struct imx_nand_host *host;
|
struct imx_nand_host *host;
|
||||||
struct nand_ecclayout *oob_smallpage, *oob_largepage;
|
struct nand_ecclayout *oob_smallpage, *oob_largepage, *oob_4kpage;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_IMX27
|
#ifdef CONFIG_ARCH_IMX27
|
||||||
|
@ -1047,6 +1127,7 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
host->send_addr = send_addr_v1_v2;
|
host->send_addr = send_addr_v1_v2;
|
||||||
host->send_page = send_page_v1_v2;
|
host->send_page = send_page_v1_v2;
|
||||||
host->send_read_id = send_read_id_v1_v2;
|
host->send_read_id = send_read_id_v1_v2;
|
||||||
|
host->send_read_param = send_read_param_v1_v2; /* FIXME : to check */
|
||||||
host->get_dev_status = get_dev_status_v1_v2;
|
host->get_dev_status = get_dev_status_v1_v2;
|
||||||
host->check_int = check_int_v1_v2;
|
host->check_int = check_int_v1_v2;
|
||||||
}
|
}
|
||||||
|
@ -1059,6 +1140,7 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
host->spare_len = 64;
|
host->spare_len = 64;
|
||||||
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
||||||
oob_largepage = &nandv2_hw_eccoob_largepage;
|
oob_largepage = &nandv2_hw_eccoob_largepage;
|
||||||
|
oob_4kpage = &nandv2_hw_eccoob_4k; /* FIXME : to check */
|
||||||
} else if (nfc_is_v1()) {
|
} else if (nfc_is_v1()) {
|
||||||
host->base = dev_request_mem_region(dev, 0);
|
host->base = dev_request_mem_region(dev, 0);
|
||||||
host->main_area0 = host->base;
|
host->main_area0 = host->base;
|
||||||
|
@ -1067,6 +1149,7 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
host->spare_len = 16;
|
host->spare_len = 16;
|
||||||
oob_smallpage = &nandv1_hw_eccoob_smallpage;
|
oob_smallpage = &nandv1_hw_eccoob_smallpage;
|
||||||
oob_largepage = &nandv1_hw_eccoob_largepage;
|
oob_largepage = &nandv1_hw_eccoob_largepage;
|
||||||
|
oob_4kpage = &nandv1_hw_eccoob_smallpage; /* FIXME : to check */
|
||||||
} else if (nfc_is_v3_2()) {
|
} else if (nfc_is_v3_2()) {
|
||||||
host->regs_ip = dev_request_mem_region(dev, 0);
|
host->regs_ip = dev_request_mem_region(dev, 0);
|
||||||
host->base = dev_request_mem_region(dev, 1);
|
host->base = dev_request_mem_region(dev, 1);
|
||||||
|
@ -1086,10 +1169,12 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
host->send_addr = send_addr_v3;
|
host->send_addr = send_addr_v3;
|
||||||
host->send_page = send_page_v3;
|
host->send_page = send_page_v3;
|
||||||
host->send_read_id = send_read_id_v3;
|
host->send_read_id = send_read_id_v3;
|
||||||
|
host->send_read_param = send_read_param_v3;
|
||||||
host->get_dev_status = get_dev_status_v3;
|
host->get_dev_status = get_dev_status_v3;
|
||||||
host->check_int = check_int_v3;
|
host->check_int = check_int_v3;
|
||||||
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
||||||
oob_largepage = &nandv2_hw_eccoob_largepage;
|
oob_largepage = &nandv2_hw_eccoob_largepage;
|
||||||
|
oob_4kpage = &nandv2_hw_eccoob_4k;
|
||||||
}
|
}
|
||||||
|
|
||||||
host->dev = dev;
|
host->dev = dev;
|
||||||
|
@ -1161,7 +1246,10 @@ static int __init imxnd_probe(struct device_d *dev)
|
||||||
imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8);
|
imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8);
|
||||||
|
|
||||||
if (mtd->writesize >= 2048) {
|
if (mtd->writesize >= 2048) {
|
||||||
this->ecc.layout = oob_largepage;
|
if (mtd->writesize == 2048)
|
||||||
|
this->ecc.layout = oob_largepage;
|
||||||
|
else
|
||||||
|
this->ecc.layout = oob_4kpage;
|
||||||
host->pagesize_2k = 1;
|
host->pagesize_2k = 1;
|
||||||
if (nfc_is_v21())
|
if (nfc_is_v21())
|
||||||
writew(NFC_V2_SPAS_SPARESIZE(64), host->regs + NFC_V2_SPAS);
|
writew(NFC_V2_SPAS_SPARESIZE(64), host->regs + NFC_V2_SPAS);
|
||||||
|
|
|
@ -115,16 +115,17 @@ struct nand_oobfree {
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MTD_MAX_OOBFREE_ENTRIES 8
|
#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
|
||||||
|
#define MTD_MAX_ECCPOS_ENTRIES_LARGE 128 /* FIXME : understand why 448 is not working */
|
||||||
/*
|
/*
|
||||||
* ECC layout control structure. Exported to userspace for
|
* ECC layout control structure. Exported to userspace for
|
||||||
* diagnosis and to allow creation of raw images
|
* diagnosis and to allow creation of raw images
|
||||||
*/
|
*/
|
||||||
struct nand_ecclayout {
|
struct nand_ecclayout {
|
||||||
uint32_t eccbytes;
|
uint32_t eccbytes;
|
||||||
uint32_t eccpos[64];
|
uint32_t eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
|
||||||
uint32_t oobavail;
|
uint32_t oobavail;
|
||||||
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
|
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,6 +80,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||||
#define NAND_CMD_RNDIN 0x85
|
#define NAND_CMD_RNDIN 0x85
|
||||||
#define NAND_CMD_READID 0x90
|
#define NAND_CMD_READID 0x90
|
||||||
#define NAND_CMD_ERASE2 0xd0
|
#define NAND_CMD_ERASE2 0xd0
|
||||||
|
#define NAND_CMD_PARAM 0xec
|
||||||
#define NAND_CMD_RESET 0xff
|
#define NAND_CMD_RESET 0xff
|
||||||
|
|
||||||
/* Extended commands for large page devices */
|
/* Extended commands for large page devices */
|
||||||
|
@ -217,6 +218,70 @@ typedef enum {
|
||||||
/* Keep gcc happy */
|
/* Keep gcc happy */
|
||||||
struct nand_chip;
|
struct nand_chip;
|
||||||
|
|
||||||
|
struct nand_onfi_params {
|
||||||
|
/* rev info and features block */
|
||||||
|
/* 'O' 'N' 'F' 'I' */
|
||||||
|
u8 sig[4];
|
||||||
|
__le16 revision;
|
||||||
|
__le16 features;
|
||||||
|
__le16 opt_cmd;
|
||||||
|
u8 reserved[22];
|
||||||
|
|
||||||
|
/* manufacturer information block */
|
||||||
|
char manufacturer[12];
|
||||||
|
char model[20];
|
||||||
|
u8 jedec_id;
|
||||||
|
__le16 date_code;
|
||||||
|
u8 reserved2[13];
|
||||||
|
|
||||||
|
/* memory organization block */
|
||||||
|
__le32 byte_per_page;
|
||||||
|
__le16 spare_bytes_per_page;
|
||||||
|
__le32 data_bytes_per_ppage;
|
||||||
|
__le16 spare_bytes_per_ppage;
|
||||||
|
__le32 pages_per_block;
|
||||||
|
__le32 blocks_per_lun;
|
||||||
|
u8 lun_count;
|
||||||
|
u8 addr_cycles;
|
||||||
|
u8 bits_per_cell;
|
||||||
|
__le16 bb_per_lun;
|
||||||
|
__le16 block_endurance;
|
||||||
|
u8 guaranteed_good_blocks;
|
||||||
|
__le16 guaranteed_block_endurance;
|
||||||
|
u8 programs_per_page;
|
||||||
|
u8 ppage_attr;
|
||||||
|
u8 ecc_bits;
|
||||||
|
u8 interleaved_bits;
|
||||||
|
u8 interleaved_ops;
|
||||||
|
u8 reserved3[13];
|
||||||
|
|
||||||
|
/* electrical parameter block */
|
||||||
|
u8 io_pin_capacitance_max;
|
||||||
|
__le16 async_timing_mode;
|
||||||
|
__le16 program_cache_timing_mode;
|
||||||
|
__le16 t_prog;
|
||||||
|
__le16 t_bers;
|
||||||
|
__le16 t_r;
|
||||||
|
__le16 t_ccs;
|
||||||
|
__le16 src_sync_timing_mode;
|
||||||
|
__le16 src_ssync_features;
|
||||||
|
__le16 clk_pin_capacitance_typ;
|
||||||
|
__le16 io_pin_capacitance_typ;
|
||||||
|
__le16 input_pin_capacitance_typ;
|
||||||
|
u8 input_pin_capacitance_max;
|
||||||
|
u8 driver_strenght_support;
|
||||||
|
__le16 t_int_r;
|
||||||
|
__le16 t_ald;
|
||||||
|
u8 reserved4[7];
|
||||||
|
|
||||||
|
/* vendor */
|
||||||
|
u8 reserved5[90];
|
||||||
|
|
||||||
|
__le16 crc;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define ONFI_CRC_BASE 0x4F4E
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
||||||
* @lock: protection lock
|
* @lock: protection lock
|
||||||
|
@ -347,6 +412,10 @@ struct nand_buffers {
|
||||||
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
||||||
* @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
|
* @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
|
||||||
* @subpagesize: [INTERN] holds the subpagesize
|
* @subpagesize: [INTERN] holds the subpagesize
|
||||||
|
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
|
||||||
|
* non 0 if ONFI supported.
|
||||||
|
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
||||||
|
* supported, 0 otherwise.
|
||||||
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
||||||
* @bbt: [INTERN] bad block table pointer
|
* @bbt: [INTERN] bad block table pointer
|
||||||
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
|
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
|
||||||
|
@ -391,13 +460,16 @@ struct nand_chip {
|
||||||
int bbt_erase_shift;
|
int bbt_erase_shift;
|
||||||
int chip_shift;
|
int chip_shift;
|
||||||
int numchips;
|
int numchips;
|
||||||
unsigned long chipsize;
|
uint64_t chipsize;
|
||||||
int pagemask;
|
int pagemask;
|
||||||
int pagebuf;
|
int pagebuf;
|
||||||
int subpagesize;
|
int subpagesize;
|
||||||
uint8_t cellinfo;
|
uint8_t cellinfo;
|
||||||
int badblockpos;
|
int badblockpos;
|
||||||
|
|
||||||
|
int onfi_version;
|
||||||
|
struct nand_onfi_params onfi_params;
|
||||||
|
|
||||||
nand_state_t state;
|
nand_state_t state;
|
||||||
|
|
||||||
uint8_t *oob_poi;
|
uint8_t *oob_poi;
|
||||||
|
|
|
@ -93,6 +93,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
|
||||||
#ifndef __HAVE_ARCH_MEMCHR
|
#ifndef __HAVE_ARCH_MEMCHR
|
||||||
extern void * memchr(const void *,int,__kernel_size_t);
|
extern void * memchr(const void *,int,__kernel_size_t);
|
||||||
#endif
|
#endif
|
||||||
|
extern char * skip_spaces(const char *);
|
||||||
|
|
||||||
|
extern char *strim(char *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
39
lib/string.c
39
lib/string.c
|
@ -567,3 +567,42 @@ void *memchr(const void *s, int c, size_t n)
|
||||||
#endif
|
#endif
|
||||||
EXPORT_SYMBOL(memchr);
|
EXPORT_SYMBOL(memchr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* skip_spaces - Removes leading whitespace from @str.
|
||||||
|
* @str: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the first non-whitespace character in @str.
|
||||||
|
*/
|
||||||
|
char *skip_spaces(const char *str)
|
||||||
|
{
|
||||||
|
while (isspace(*str))
|
||||||
|
++str;
|
||||||
|
return (char *)str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strim - Removes leading and trailing whitespace from @s.
|
||||||
|
* @s: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
||||||
|
* in the given string @s. Returns a pointer to the first non-whitespace
|
||||||
|
* character in @s.
|
||||||
|
*/
|
||||||
|
char *strim(char *s)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
s = skip_spaces(s);
|
||||||
|
size = strlen(s);
|
||||||
|
if (!size)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
end = s + size - 1;
|
||||||
|
while (end >= s && isspace(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(strim);
|
||||||
|
|
Loading…
Reference in New Issue