diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/denali.c | 107 |
1 files changed, 35 insertions, 72 deletions
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0c76a16..0f9fc5e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -549,7 +549,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali) static void get_toshiba_nand_para(struct denali_nand_info *denali) { - void __iomem *scratch_reg; uint32_t tmp; /* Workaround to fix a controller bug which reports a wrong */ @@ -567,33 +566,14 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) denali_write32(8, denali->flash_reg + ECC_CORRECTION); #endif } - - /* As Toshiba NAND can not provide it's block number, */ - /* so here we need user to provide the correct block */ - /* number in a scratch register before the Linux NAND */ - /* driver is loaded. If no valid value found in the scratch */ - /* register, then we use default block number value */ - scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE); - if (!scratch_reg) { - printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d", - __FILE__, __LINE__); - denali->dev_info.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - } else { - nand_dbg_print(NAND_DBG_WARN, - "Spectra: ioremap reg address: 0x%p\n", scratch_reg); - denali->dev_info.wTotalBlocks = 1 << ioread8(scratch_reg); - if (denali->dev_info.wTotalBlocks < 512) - denali->dev_info.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - iounmap(scratch_reg); - } } -static void get_hynix_nand_para(struct denali_nand_info *denali) +static void get_hynix_nand_para(struct denali_nand_info *denali, + uint8_t device_id) { - void __iomem *scratch_reg; uint32_t main_size, spare_size; - switch (denali->dev_info.wDeviceID) { + switch (device_id) { case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ denali_write32(128, denali->flash_reg + PAGES_PER_BLOCK); @@ -621,20 +601,6 @@ static void get_hynix_nand_para(struct denali_nand_info *denali) "Will use default parameter values instead.\n", denali->dev_info.wDeviceID); } - - scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE); - if (!scratch_reg) { - printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d", - __FILE__, __LINE__); - denali->dev_info.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - } else { - nand_dbg_print(NAND_DBG_WARN, - "Spectra: ioremap reg address: 0x%p\n", scratch_reg); - denali->dev_info.wTotalBlocks = 1 << ioread8(scratch_reg); - if (denali->dev_info.wTotalBlocks < 512) - denali->dev_info.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - iounmap(scratch_reg); - } } /* determines how many NAND chips are connected to the controller. Note for @@ -807,34 +773,35 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) { uint16_t status = PASS; uint8_t no_of_planes; + uint32_t id_bytes[5], addr; + uint8_t i, maf_id, device_id; nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - denali->dev_info.wDeviceMaker = - ioread32(denali->flash_reg + MANUFACTURER_ID); - denali->dev_info.wDeviceID = - ioread32(denali->flash_reg + DEVICE_ID); - denali->dev_info.bDeviceParam0 = - ioread32(denali->flash_reg + DEVICE_PARAM_0); - denali->dev_info.bDeviceParam1 = - ioread32(denali->flash_reg + DEVICE_PARAM_1); - denali->dev_info.bDeviceParam2 = - ioread32(denali->flash_reg + DEVICE_PARAM_2); - - denali->dev_info.MLCDevice = - ioread32(denali->flash_reg + DEVICE_PARAM_0) & 0x0c; + /* Use read id method to get device ID and other + * params. For some NAND chips, controller can't + * report the correct device ID by reading from + * DEVICE_ID register + * */ + addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); + index_addr(denali, (uint32_t)addr | 0, 0x90); + index_addr(denali, (uint32_t)addr | 1, 0); + for (i = 0; i < 5; i++) + index_addr_read_data(denali, addr | 2, &id_bytes[i]); + maf_id = id_bytes[0]; + device_id = id_bytes[1]; if (ioread32(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) & ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ if (FAIL == get_onfi_nand_para(denali)) return FAIL; - } else if (denali->dev_info.wDeviceMaker == 0xEC) { /* Samsung NAND */ + } else if (maf_id == 0xEC) { /* Samsung NAND */ get_samsung_nand_para(denali); - } else if (denali->dev_info.wDeviceMaker == 0x98) { /* Toshiba NAND */ + } else if (maf_id == 0x98) { /* Toshiba NAND */ get_toshiba_nand_para(denali); - } else if (denali->dev_info.wDeviceMaker == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(denali); + } else if (maf_id == 0xAD) { /* Hynix NAND */ + get_hynix_nand_para(denali, device_id); } else { denali->dev_info.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; } @@ -1720,6 +1687,8 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t addr, id; + int i; #if DEBUG_DENALI printk(KERN_INFO "cmdfunc: 0x%x %d %d\n", cmd, col, page); @@ -1732,24 +1701,18 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, break; case NAND_CMD_READID: reset_buf(denali); - if (denali->flash_bank < denali->total_used_banks) { - /* write manufacturer information into nand - buffer for NAND subsystem to fetch. - */ - write_byte_to_buf(denali, - denali->dev_info.wDeviceMaker); - write_byte_to_buf(denali, - denali->dev_info.wDeviceID); - write_byte_to_buf(denali, - denali->dev_info.bDeviceParam0); - write_byte_to_buf(denali, - denali->dev_info.bDeviceParam1); - write_byte_to_buf(denali, - denali->dev_info.bDeviceParam2); - } else { - int i; - for (i = 0; i < 5; i++) - write_byte_to_buf(denali, 0xff); + /*sometimes ManufactureId read from register is not right + * e.g. some of Micron MT29F32G08QAA MLC NAND chips + * So here we send READID cmd to NAND insteand + * */ + addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); + index_addr(denali, (uint32_t)addr | 0, 0x90); + index_addr(denali, (uint32_t)addr | 1, 0); + for (i = 0; i < 5; i++) { + index_addr_read_data(denali, + (uint32_t)addr | 2, + &id); + write_byte_to_buf(denali, id); } break; case NAND_CMD_READ0: |