diff options
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
| -rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 783 |
1 files changed, 296 insertions, 487 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 65b26d5a5c0d..45dec5770da0 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
| @@ -33,9 +33,13 @@ | |||
| 33 | 33 | ||
| 34 | #include <asm/mach/flash.h> | 34 | #include <asm/mach/flash.h> |
| 35 | #include <mach/mxc_nand.h> | 35 | #include <mach/mxc_nand.h> |
| 36 | #include <mach/hardware.h> | ||
| 36 | 37 | ||
| 37 | #define DRIVER_NAME "mxc_nand" | 38 | #define DRIVER_NAME "mxc_nand" |
| 38 | 39 | ||
| 40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | ||
| 41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27()) | ||
| 42 | |||
| 39 | /* Addresses for NFC registers */ | 43 | /* Addresses for NFC registers */ |
| 40 | #define NFC_BUF_SIZE 0xE00 | 44 | #define NFC_BUF_SIZE 0xE00 |
| 41 | #define NFC_BUF_ADDR 0xE04 | 45 | #define NFC_BUF_ADDR 0xE04 |
| @@ -46,24 +50,14 @@ | |||
| 46 | #define NFC_RSLTMAIN_AREA 0xE0E | 50 | #define NFC_RSLTMAIN_AREA 0xE0E |
| 47 | #define NFC_RSLTSPARE_AREA 0xE10 | 51 | #define NFC_RSLTSPARE_AREA 0xE10 |
| 48 | #define NFC_WRPROT 0xE12 | 52 | #define NFC_WRPROT 0xE12 |
| 49 | #define NFC_UNLOCKSTART_BLKADDR 0xE14 | 53 | #define NFC_V1_UNLOCKSTART_BLKADDR 0xe14 |
| 50 | #define NFC_UNLOCKEND_BLKADDR 0xE16 | 54 | #define NFC_V1_UNLOCKEND_BLKADDR 0xe16 |
| 55 | #define NFC_V21_UNLOCKSTART_BLKADDR 0xe20 | ||
| 56 | #define NFC_V21_UNLOCKEND_BLKADDR 0xe22 | ||
| 51 | #define NFC_NF_WRPRST 0xE18 | 57 | #define NFC_NF_WRPRST 0xE18 |
| 52 | #define NFC_CONFIG1 0xE1A | 58 | #define NFC_CONFIG1 0xE1A |
| 53 | #define NFC_CONFIG2 0xE1C | 59 | #define NFC_CONFIG2 0xE1C |
| 54 | 60 | ||
| 55 | /* Addresses for NFC RAM BUFFER Main area 0 */ | ||
| 56 | #define MAIN_AREA0 0x000 | ||
| 57 | #define MAIN_AREA1 0x200 | ||
| 58 | #define MAIN_AREA2 0x400 | ||
| 59 | #define MAIN_AREA3 0x600 | ||
| 60 | |||
| 61 | /* Addresses for NFC SPARE BUFFER Spare area 0 */ | ||
| 62 | #define SPARE_AREA0 0x800 | ||
| 63 | #define SPARE_AREA1 0x810 | ||
| 64 | #define SPARE_AREA2 0x820 | ||
| 65 | #define SPARE_AREA3 0x830 | ||
| 66 | |||
| 67 | /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register | 61 | /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register |
| 68 | * for Command operation */ | 62 | * for Command operation */ |
| 69 | #define NFC_CMD 0x1 | 63 | #define NFC_CMD 0x1 |
| @@ -106,48 +100,66 @@ struct mxc_nand_host { | |||
| 106 | struct mtd_partition *parts; | 100 | struct mtd_partition *parts; |
| 107 | struct device *dev; | 101 | struct device *dev; |
| 108 | 102 | ||
| 103 | void *spare0; | ||
| 104 | void *main_area0; | ||
| 105 | void *main_area1; | ||
| 106 | |||
| 107 | void __iomem *base; | ||
| 109 | void __iomem *regs; | 108 | void __iomem *regs; |
| 110 | int spare_only; | ||
| 111 | int status_request; | 109 | int status_request; |
| 112 | int pagesize_2k; | ||
| 113 | uint16_t col_addr; | ||
| 114 | struct clk *clk; | 110 | struct clk *clk; |
| 115 | int clk_act; | 111 | int clk_act; |
| 116 | int irq; | 112 | int irq; |
| 117 | 113 | ||
| 118 | wait_queue_head_t irq_waitq; | 114 | wait_queue_head_t irq_waitq; |
| 119 | }; | ||
| 120 | |||
| 121 | /* Define delays in microsec for NAND device operations */ | ||
| 122 | #define TROP_US_DELAY 2000 | ||
| 123 | /* Macros to get byte and bit positions of ECC */ | ||
| 124 | #define COLPOS(x) ((x) >> 3) | ||
| 125 | #define BITPOS(x) ((x) & 0xf) | ||
| 126 | 115 | ||
| 127 | /* Define single bit Error positions in Main & Spare area */ | 116 | uint8_t *data_buf; |
| 128 | #define MAIN_SINGLEBIT_ERROR 0x4 | 117 | unsigned int buf_start; |
| 129 | #define SPARE_SINGLEBIT_ERROR 0x1 | 118 | int spare_len; |
| 130 | |||
| 131 | /* OOB placement block for use with hardware ecc generation */ | ||
| 132 | static struct nand_ecclayout nand_hw_eccoob_8 = { | ||
| 133 | .eccbytes = 5, | ||
| 134 | .eccpos = {6, 7, 8, 9, 10}, | ||
| 135 | .oobfree = {{0, 5}, {11, 5}, } | ||
| 136 | }; | 119 | }; |
| 137 | 120 | ||
| 138 | static struct nand_ecclayout nand_hw_eccoob_16 = { | 121 | /* OOB placement block for use with hardware ecc generation */ |
| 122 | static struct nand_ecclayout nandv1_hw_eccoob_smallpage = { | ||
| 139 | .eccbytes = 5, | 123 | .eccbytes = 5, |
| 140 | .eccpos = {6, 7, 8, 9, 10}, | 124 | .eccpos = {6, 7, 8, 9, 10}, |
| 141 | .oobfree = {{0, 5}, {11, 5}, } | 125 | .oobfree = {{0, 5}, {12, 4}, } |
| 142 | }; | 126 | }; |
| 143 | 127 | ||
| 144 | static struct nand_ecclayout nand_hw_eccoob_64 = { | 128 | static struct nand_ecclayout nandv1_hw_eccoob_largepage = { |
| 145 | .eccbytes = 20, | 129 | .eccbytes = 20, |
| 146 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, | 130 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, |
| 147 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, | 131 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, |
| 148 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } | 132 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } |
| 149 | }; | 133 | }; |
| 150 | 134 | ||
| 135 | /* OOB description for 512 byte pages with 16 byte OOB */ | ||
| 136 | static struct nand_ecclayout nandv2_hw_eccoob_smallpage = { | ||
| 137 | .eccbytes = 1 * 9, | ||
| 138 | .eccpos = { | ||
| 139 | 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 140 | }, | ||
| 141 | .oobfree = { | ||
| 142 | {.offset = 0, .length = 5} | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 146 | /* OOB description for 2048 byte pages with 64 byte OOB */ | ||
| 147 | static struct nand_ecclayout nandv2_hw_eccoob_largepage = { | ||
| 148 | .eccbytes = 4 * 9, | ||
| 149 | .eccpos = { | ||
| 150 | 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 151 | 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
| 152 | 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
| 153 | 55, 56, 57, 58, 59, 60, 61, 62, 63 | ||
| 154 | }, | ||
| 155 | .oobfree = { | ||
| 156 | {.offset = 2, .length = 4}, | ||
| 157 | {.offset = 16, .length = 7}, | ||
| 158 | {.offset = 32, .length = 7}, | ||
| 159 | {.offset = 48, .length = 7} | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 151 | #ifdef CONFIG_MTD_PARTITIONS | 163 | #ifdef CONFIG_MTD_PARTITIONS |
| 152 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 164 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; |
| 153 | #endif | 165 | #endif |
| @@ -170,10 +182,10 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
| 170 | /* This function polls the NANDFC to wait for the basic operation to | 182 | /* This function polls the NANDFC to wait for the basic operation to |
| 171 | * complete by checking the INT bit of config2 register. | 183 | * complete by checking the INT bit of config2 register. |
| 172 | */ | 184 | */ |
| 173 | static void wait_op_done(struct mxc_nand_host *host, int max_retries, | 185 | static void wait_op_done(struct mxc_nand_host *host, int useirq) |
| 174 | uint16_t param, int useirq) | ||
| 175 | { | 186 | { |
| 176 | uint32_t tmp; | 187 | uint32_t tmp; |
| 188 | int max_retries = 2000; | ||
| 177 | 189 | ||
| 178 | if (useirq) { | 190 | if (useirq) { |
| 179 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { | 191 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { |
| @@ -200,8 +212,8 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, | |||
| 200 | udelay(1); | 212 | udelay(1); |
| 201 | } | 213 | } |
| 202 | if (max_retries < 0) | 214 | if (max_retries < 0) |
| 203 | DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", | 215 | DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", |
| 204 | __func__, param); | 216 | __func__); |
| 205 | } | 217 | } |
| 206 | } | 218 | } |
| 207 | 219 | ||
| @@ -215,7 +227,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
| 215 | writew(NFC_CMD, host->regs + NFC_CONFIG2); | 227 | writew(NFC_CMD, host->regs + NFC_CONFIG2); |
| 216 | 228 | ||
| 217 | /* Wait for operation to complete */ | 229 | /* Wait for operation to complete */ |
| 218 | wait_op_done(host, TROP_US_DELAY, cmd, useirq); | 230 | wait_op_done(host, useirq); |
| 219 | } | 231 | } |
| 220 | 232 | ||
| 221 | /* This function sends an address (or partial address) to the | 233 | /* This function sends an address (or partial address) to the |
| @@ -229,82 +241,47 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) | |||
| 229 | writew(NFC_ADDR, host->regs + NFC_CONFIG2); | 241 | writew(NFC_ADDR, host->regs + NFC_CONFIG2); |
| 230 | 242 | ||
| 231 | /* Wait for operation to complete */ | 243 | /* Wait for operation to complete */ |
| 232 | wait_op_done(host, TROP_US_DELAY, addr, islast); | 244 | wait_op_done(host, islast); |
| 233 | } | 245 | } |
| 234 | 246 | ||
| 235 | /* This function requests the NANDFC to initate the transfer | 247 | static void send_page(struct mtd_info *mtd, unsigned int ops) |
| 236 | * of data currently in the NANDFC RAM buffer to the NAND device. */ | ||
| 237 | static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
| 238 | int spare_only) | ||
| 239 | { | 248 | { |
| 240 | DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only); | 249 | struct nand_chip *nand_chip = mtd->priv; |
| 241 | 250 | struct mxc_nand_host *host = nand_chip->priv; | |
| 242 | /* NANDFC buffer 0 is used for page read/write */ | 251 | int bufs, i; |
| 243 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
| 244 | |||
| 245 | /* Configure spare or page+spare access */ | ||
| 246 | if (!host->pagesize_2k) { | ||
| 247 | uint16_t config1 = readw(host->regs + NFC_CONFIG1); | ||
| 248 | if (spare_only) | ||
| 249 | config1 |= NFC_SP_EN; | ||
| 250 | else | ||
| 251 | config1 &= ~(NFC_SP_EN); | ||
| 252 | writew(config1, host->regs + NFC_CONFIG1); | ||
| 253 | } | ||
| 254 | 252 | ||
| 255 | writew(NFC_INPUT, host->regs + NFC_CONFIG2); | 253 | if (nfc_is_v1() && mtd->writesize > 512) |
| 254 | bufs = 4; | ||
| 255 | else | ||
| 256 | bufs = 1; | ||
| 256 | 257 | ||
| 257 | /* Wait for operation to complete */ | 258 | for (i = 0; i < bufs; i++) { |
| 258 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
| 259 | } | ||
| 260 | 259 | ||
| 261 | /* Requests NANDFC to initated the transfer of data from the | 260 | /* NANDFC buffer 0 is used for page read/write */ |
| 262 | * NAND device into in the NANDFC ram buffer. */ | 261 | writew(i, host->regs + NFC_BUF_ADDR); |
| 263 | static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
| 264 | int spare_only) | ||
| 265 | { | ||
| 266 | DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); | ||
| 267 | 262 | ||
| 268 | /* NANDFC buffer 0 is used for page read/write */ | 263 | writew(ops, host->regs + NFC_CONFIG2); |
| 269 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
| 270 | 264 | ||
| 271 | /* Configure spare or page+spare access */ | 265 | /* Wait for operation to complete */ |
| 272 | if (!host->pagesize_2k) { | 266 | wait_op_done(host, true); |
| 273 | uint32_t config1 = readw(host->regs + NFC_CONFIG1); | ||
| 274 | if (spare_only) | ||
| 275 | config1 |= NFC_SP_EN; | ||
| 276 | else | ||
| 277 | config1 &= ~NFC_SP_EN; | ||
| 278 | writew(config1, host->regs + NFC_CONFIG1); | ||
| 279 | } | 267 | } |
| 280 | |||
| 281 | writew(NFC_OUTPUT, host->regs + NFC_CONFIG2); | ||
| 282 | |||
| 283 | /* Wait for operation to complete */ | ||
| 284 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
| 285 | } | 268 | } |
| 286 | 269 | ||
| 287 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 270 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
| 288 | static void send_read_id(struct mxc_nand_host *host) | 271 | static void send_read_id(struct mxc_nand_host *host) |
| 289 | { | 272 | { |
| 290 | struct nand_chip *this = &host->nand; | 273 | struct nand_chip *this = &host->nand; |
| 291 | uint16_t tmp; | ||
| 292 | 274 | ||
| 293 | /* NANDFC buffer 0 is used for device ID output */ | 275 | /* NANDFC buffer 0 is used for device ID output */ |
| 294 | writew(0x0, host->regs + NFC_BUF_ADDR); | 276 | writew(0x0, host->regs + NFC_BUF_ADDR); |
| 295 | 277 | ||
| 296 | /* Read ID into main buffer */ | ||
| 297 | tmp = readw(host->regs + NFC_CONFIG1); | ||
| 298 | tmp &= ~NFC_SP_EN; | ||
| 299 | writew(tmp, host->regs + NFC_CONFIG1); | ||
| 300 | |||
| 301 | writew(NFC_ID, host->regs + NFC_CONFIG2); | 278 | writew(NFC_ID, host->regs + NFC_CONFIG2); |
| 302 | 279 | ||
| 303 | /* Wait for operation to complete */ | 280 | /* Wait for operation to complete */ |
| 304 | wait_op_done(host, TROP_US_DELAY, 0, true); | 281 | wait_op_done(host, true); |
| 305 | 282 | ||
| 306 | if (this->options & NAND_BUSWIDTH_16) { | 283 | if (this->options & NAND_BUSWIDTH_16) { |
| 307 | void __iomem *main_buf = host->regs + MAIN_AREA0; | 284 | void __iomem *main_buf = host->main_area0; |
| 308 | /* compress the ID info */ | 285 | /* compress the ID info */ |
| 309 | writeb(readb(main_buf + 2), main_buf + 1); | 286 | writeb(readb(main_buf + 2), main_buf + 1); |
| 310 | writeb(readb(main_buf + 4), main_buf + 2); | 287 | writeb(readb(main_buf + 4), main_buf + 2); |
| @@ -312,15 +289,16 @@ static void send_read_id(struct mxc_nand_host *host) | |||
| 312 | writeb(readb(main_buf + 8), main_buf + 4); | 289 | writeb(readb(main_buf + 8), main_buf + 4); |
| 313 | writeb(readb(main_buf + 10), main_buf + 5); | 290 | writeb(readb(main_buf + 10), main_buf + 5); |
| 314 | } | 291 | } |
| 292 | memcpy(host->data_buf, host->main_area0, 16); | ||
| 315 | } | 293 | } |
| 316 | 294 | ||
| 317 | /* This function requests the NANDFC to perform a read of the | 295 | /* This function requests the NANDFC to perform a read of the |
| 318 | * NAND device status and returns the current status. */ | 296 | * NAND device status and returns the current status. */ |
| 319 | static uint16_t get_dev_status(struct mxc_nand_host *host) | 297 | static uint16_t get_dev_status(struct mxc_nand_host *host) |
| 320 | { | 298 | { |
| 321 | void __iomem *main_buf = host->regs + MAIN_AREA1; | 299 | void __iomem *main_buf = host->main_area1; |
| 322 | uint32_t store; | 300 | uint32_t store; |
| 323 | uint16_t ret, tmp; | 301 | uint16_t ret; |
| 324 | /* Issue status request to NAND device */ | 302 | /* Issue status request to NAND device */ |
| 325 | 303 | ||
| 326 | /* store the main area1 first word, later do recovery */ | 304 | /* store the main area1 first word, later do recovery */ |
| @@ -329,15 +307,10 @@ static uint16_t get_dev_status(struct mxc_nand_host *host) | |||
| 329 | * corruption of read/write buffer on status requests. */ | 307 | * corruption of read/write buffer on status requests. */ |
| 330 | writew(1, host->regs + NFC_BUF_ADDR); | 308 | writew(1, host->regs + NFC_BUF_ADDR); |
| 331 | 309 | ||
| 332 | /* Read status into main buffer */ | ||
| 333 | tmp = readw(host->regs + NFC_CONFIG1); | ||
| 334 | tmp &= ~NFC_SP_EN; | ||
| 335 | writew(tmp, host->regs + NFC_CONFIG1); | ||
| 336 | |||
| 337 | writew(NFC_STATUS, host->regs + NFC_CONFIG2); | 310 | writew(NFC_STATUS, host->regs + NFC_CONFIG2); |
| 338 | 311 | ||
| 339 | /* Wait for operation to complete */ | 312 | /* Wait for operation to complete */ |
| 340 | wait_op_done(host, TROP_US_DELAY, 0, true); | 313 | wait_op_done(host, true); |
| 341 | 314 | ||
| 342 | /* Status is placed in first word of main buffer */ | 315 | /* Status is placed in first word of main buffer */ |
| 343 | /* get status, then recovery area 1 data */ | 316 | /* get status, then recovery area 1 data */ |
| @@ -397,32 +370,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
| 397 | { | 370 | { |
| 398 | struct nand_chip *nand_chip = mtd->priv; | 371 | struct nand_chip *nand_chip = mtd->priv; |
| 399 | struct mxc_nand_host *host = nand_chip->priv; | 372 | struct mxc_nand_host *host = nand_chip->priv; |
| 400 | uint8_t ret = 0; | 373 | uint8_t ret; |
| 401 | uint16_t col, rd_word; | ||
| 402 | uint16_t __iomem *main_buf = host->regs + MAIN_AREA0; | ||
| 403 | uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0; | ||
| 404 | 374 | ||
| 405 | /* Check for status request */ | 375 | /* Check for status request */ |
| 406 | if (host->status_request) | 376 | if (host->status_request) |
| 407 | return get_dev_status(host) & 0xFF; | 377 | return get_dev_status(host) & 0xFF; |
| 408 | 378 | ||
| 409 | /* Get column for 16-bit access */ | 379 | ret = *(uint8_t *)(host->data_buf + host->buf_start); |
| 410 | col = host->col_addr >> 1; | 380 | host->buf_start++; |
| 411 | |||
| 412 | /* If we are accessing the spare region */ | ||
| 413 | if (host->spare_only) | ||
| 414 | rd_word = readw(&spare_buf[col]); | ||
| 415 | else | ||
| 416 | rd_word = readw(&main_buf[col]); | ||
| 417 | |||
| 418 | /* Pick upper/lower byte of word from RAM buffer */ | ||
| 419 | if (host->col_addr & 0x1) | ||
| 420 | ret = (rd_word >> 8) & 0xFF; | ||
| 421 | else | ||
| 422 | ret = rd_word & 0xFF; | ||
| 423 | |||
| 424 | /* Update saved column address */ | ||
| 425 | host->col_addr++; | ||
| 426 | 381 | ||
| 427 | return ret; | 382 | return ret; |
| 428 | } | 383 | } |
| @@ -431,33 +386,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd) | |||
| 431 | { | 386 | { |
| 432 | struct nand_chip *nand_chip = mtd->priv; | 387 | struct nand_chip *nand_chip = mtd->priv; |
| 433 | struct mxc_nand_host *host = nand_chip->priv; | 388 | struct mxc_nand_host *host = nand_chip->priv; |
| 434 | uint16_t col, rd_word, ret; | 389 | uint16_t ret; |
| 435 | uint16_t __iomem *p; | ||
| 436 | |||
| 437 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 438 | "mxc_nand_read_word(col = %d)\n", host->col_addr); | ||
| 439 | |||
| 440 | col = host->col_addr; | ||
| 441 | /* Adjust saved column address */ | ||
| 442 | if (col < mtd->writesize && host->spare_only) | ||
| 443 | col += mtd->writesize; | ||
| 444 | 390 | ||
| 445 | if (col < mtd->writesize) | 391 | ret = *(uint16_t *)(host->data_buf + host->buf_start); |
| 446 | p = (host->regs + MAIN_AREA0) + (col >> 1); | 392 | host->buf_start += 2; |
| 447 | else | ||
| 448 | p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1); | ||
| 449 | |||
| 450 | if (col & 1) { | ||
| 451 | rd_word = readw(p); | ||
| 452 | ret = (rd_word >> 8) & 0xff; | ||
| 453 | rd_word = readw(&p[1]); | ||
| 454 | ret |= (rd_word << 8) & 0xff00; | ||
| 455 | |||
| 456 | } else | ||
| 457 | ret = readw(p); | ||
| 458 | |||
| 459 | /* Update saved column address */ | ||
| 460 | host->col_addr = col + 2; | ||
| 461 | 393 | ||
| 462 | return ret; | 394 | return ret; |
| 463 | } | 395 | } |
| @@ -470,94 +402,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd, | |||
| 470 | { | 402 | { |
| 471 | struct nand_chip *nand_chip = mtd->priv; | 403 | struct nand_chip *nand_chip = mtd->priv; |
| 472 | struct mxc_nand_host *host = nand_chip->priv; | 404 | struct mxc_nand_host *host = nand_chip->priv; |
| 473 | int n, col, i = 0; | 405 | u16 col = host->buf_start; |
| 474 | 406 | int n = mtd->oobsize + mtd->writesize - col; | |
| 475 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 476 | "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, | ||
| 477 | len); | ||
| 478 | |||
| 479 | col = host->col_addr; | ||
| 480 | 407 | ||
| 481 | /* Adjust saved column address */ | 408 | n = min(n, len); |
| 482 | if (col < mtd->writesize && host->spare_only) | ||
| 483 | col += mtd->writesize; | ||
| 484 | 409 | ||
| 485 | n = mtd->writesize + mtd->oobsize - col; | 410 | memcpy(host->data_buf + col, buf, n); |
| 486 | n = min(len, n); | ||
| 487 | |||
| 488 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 489 | "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); | ||
| 490 | |||
| 491 | while (n) { | ||
| 492 | void __iomem *p; | ||
| 493 | |||
| 494 | if (col < mtd->writesize) | ||
| 495 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
| 496 | else | ||
| 497 | p = host->regs + SPARE_AREA0 - | ||
| 498 | mtd->writesize + (col & ~3); | ||
| 499 | |||
| 500 | DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, | ||
| 501 | __LINE__, p); | ||
| 502 | |||
| 503 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
| 504 | uint32_t data = 0; | ||
| 505 | |||
| 506 | if (col & 3 || n < 4) | ||
| 507 | data = readl(p); | ||
| 508 | |||
| 509 | switch (col & 3) { | ||
| 510 | case 0: | ||
| 511 | if (n) { | ||
| 512 | data = (data & 0xffffff00) | | ||
| 513 | (buf[i++] << 0); | ||
| 514 | n--; | ||
| 515 | col++; | ||
| 516 | } | ||
| 517 | case 1: | ||
| 518 | if (n) { | ||
| 519 | data = (data & 0xffff00ff) | | ||
| 520 | (buf[i++] << 8); | ||
| 521 | n--; | ||
| 522 | col++; | ||
| 523 | } | ||
| 524 | case 2: | ||
| 525 | if (n) { | ||
| 526 | data = (data & 0xff00ffff) | | ||
| 527 | (buf[i++] << 16); | ||
| 528 | n--; | ||
| 529 | col++; | ||
| 530 | } | ||
| 531 | case 3: | ||
| 532 | if (n) { | ||
| 533 | data = (data & 0x00ffffff) | | ||
| 534 | (buf[i++] << 24); | ||
| 535 | n--; | ||
| 536 | col++; | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | writel(data, p); | ||
| 541 | } else { | ||
| 542 | int m = mtd->writesize - col; | ||
| 543 | 411 | ||
| 544 | if (col >= mtd->writesize) | 412 | host->buf_start += n; |
| 545 | m += mtd->oobsize; | ||
| 546 | |||
| 547 | m = min(n, m) & ~3; | ||
| 548 | |||
| 549 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 550 | "%s:%d: n = %d, m = %d, i = %d, col = %d\n", | ||
| 551 | __func__, __LINE__, n, m, i, col); | ||
| 552 | |||
| 553 | memcpy(p, &buf[i], m); | ||
| 554 | col += m; | ||
| 555 | i += m; | ||
| 556 | n -= m; | ||
| 557 | } | ||
| 558 | } | ||
| 559 | /* Update saved column address */ | ||
| 560 | host->col_addr = col; | ||
| 561 | } | 413 | } |
| 562 | 414 | ||
| 563 | /* Read the data buffer from the NAND Flash. To read the data from NAND | 415 | /* Read the data buffer from the NAND Flash. To read the data from NAND |
| @@ -568,75 +420,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
| 568 | { | 420 | { |
| 569 | struct nand_chip *nand_chip = mtd->priv; | 421 | struct nand_chip *nand_chip = mtd->priv; |
| 570 | struct mxc_nand_host *host = nand_chip->priv; | 422 | struct mxc_nand_host *host = nand_chip->priv; |
| 571 | int n, col, i = 0; | 423 | u16 col = host->buf_start; |
| 572 | 424 | int n = mtd->oobsize + mtd->writesize - col; | |
| 573 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 574 | "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); | ||
| 575 | |||
| 576 | col = host->col_addr; | ||
| 577 | 425 | ||
| 578 | /* Adjust saved column address */ | 426 | n = min(n, len); |
| 579 | if (col < mtd->writesize && host->spare_only) | ||
| 580 | col += mtd->writesize; | ||
| 581 | 427 | ||
| 582 | n = mtd->writesize + mtd->oobsize - col; | 428 | memcpy(buf, host->data_buf + col, len); |
| 583 | n = min(len, n); | ||
| 584 | |||
| 585 | while (n) { | ||
| 586 | void __iomem *p; | ||
| 587 | |||
| 588 | if (col < mtd->writesize) | ||
| 589 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
| 590 | else | ||
| 591 | p = host->regs + SPARE_AREA0 - | ||
| 592 | mtd->writesize + (col & ~3); | ||
| 593 | |||
| 594 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
| 595 | uint32_t data; | ||
| 596 | |||
| 597 | data = readl(p); | ||
| 598 | switch (col & 3) { | ||
| 599 | case 0: | ||
| 600 | if (n) { | ||
| 601 | buf[i++] = (uint8_t) (data); | ||
| 602 | n--; | ||
| 603 | col++; | ||
| 604 | } | ||
| 605 | case 1: | ||
| 606 | if (n) { | ||
| 607 | buf[i++] = (uint8_t) (data >> 8); | ||
| 608 | n--; | ||
| 609 | col++; | ||
| 610 | } | ||
| 611 | case 2: | ||
| 612 | if (n) { | ||
| 613 | buf[i++] = (uint8_t) (data >> 16); | ||
| 614 | n--; | ||
| 615 | col++; | ||
| 616 | } | ||
| 617 | case 3: | ||
| 618 | if (n) { | ||
| 619 | buf[i++] = (uint8_t) (data >> 24); | ||
| 620 | n--; | ||
| 621 | col++; | ||
| 622 | } | ||
| 623 | } | ||
| 624 | } else { | ||
| 625 | int m = mtd->writesize - col; | ||
| 626 | |||
| 627 | if (col >= mtd->writesize) | ||
| 628 | m += mtd->oobsize; | ||
| 629 | |||
| 630 | m = min(n, m) & ~3; | ||
| 631 | memcpy(&buf[i], p, m); | ||
| 632 | col += m; | ||
| 633 | i += m; | ||
| 634 | n -= m; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | /* Update saved column address */ | ||
| 638 | host->col_addr = col; | ||
| 639 | 429 | ||
| 430 | host->buf_start += len; | ||
| 640 | } | 431 | } |
| 641 | 432 | ||
| 642 | /* Used by the upper layer to verify the data in NAND Flash | 433 | /* Used by the upper layer to verify the data in NAND Flash |
| @@ -654,23 +445,6 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |||
| 654 | struct nand_chip *nand_chip = mtd->priv; | 445 | struct nand_chip *nand_chip = mtd->priv; |
| 655 | struct mxc_nand_host *host = nand_chip->priv; | 446 | struct mxc_nand_host *host = nand_chip->priv; |
| 656 | 447 | ||
| 657 | #ifdef CONFIG_MTD_NAND_MXC_FORCE_CE | ||
| 658 | if (chip > 0) { | ||
| 659 | DEBUG(MTD_DEBUG_LEVEL0, | ||
| 660 | "ERROR: Illegal chip select (chip = %d)\n", chip); | ||
| 661 | return; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (chip == -1) { | ||
| 665 | writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE, | ||
| 666 | host->regs + NFC_CONFIG1); | ||
| 667 | return; | ||
| 668 | } | ||
| 669 | |||
| 670 | writew(readw(host->regs + NFC_CONFIG1) | NFC_CE, | ||
| 671 | host->regs + NFC_CONFIG1); | ||
| 672 | #endif | ||
| 673 | |||
| 674 | switch (chip) { | 448 | switch (chip) { |
| 675 | case -1: | 449 | case -1: |
| 676 | /* Disable the NFC clock */ | 450 | /* Disable the NFC clock */ |
| @@ -692,94 +466,40 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |||
| 692 | } | 466 | } |
| 693 | } | 467 | } |
| 694 | 468 | ||
| 695 | /* Used by the upper layer to write command to NAND Flash for | 469 | /* |
| 696 | * different operations to be carried out on NAND Flash */ | 470 | * Function to transfer data to/from spare area. |
| 697 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | 471 | */ |
| 698 | int column, int page_addr) | 472 | static void copy_spare(struct mtd_info *mtd, bool bfrom) |
| 699 | { | 473 | { |
| 700 | struct nand_chip *nand_chip = mtd->priv; | 474 | struct nand_chip *this = mtd->priv; |
| 701 | struct mxc_nand_host *host = nand_chip->priv; | 475 | struct mxc_nand_host *host = this->priv; |
| 702 | int useirq = true; | 476 | u16 i, j; |
| 703 | 477 | u16 n = mtd->writesize >> 9; | |
| 704 | DEBUG(MTD_DEBUG_LEVEL3, | 478 | u8 *d = host->data_buf + mtd->writesize; |
| 705 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | 479 | u8 *s = host->spare0; |
| 706 | command, column, page_addr); | 480 | u16 t = host->spare_len; |
| 707 | 481 | ||
| 708 | /* Reset command state information */ | 482 | j = (mtd->oobsize / n >> 1) << 1; |
| 709 | host->status_request = false; | 483 | |
| 710 | 484 | if (bfrom) { | |
| 711 | /* Command pre-processing step */ | 485 | for (i = 0; i < n - 1; i++) |
| 712 | switch (command) { | 486 | memcpy(d + i * j, s + i * t, j); |
| 713 | 487 | ||
| 714 | case NAND_CMD_STATUS: | 488 | /* the last section */ |
| 715 | host->col_addr = 0; | 489 | memcpy(d + i * j, s + i * t, mtd->oobsize - i * j); |
| 716 | host->status_request = true; | 490 | } else { |
| 717 | break; | 491 | for (i = 0; i < n - 1; i++) |
| 718 | 492 | memcpy(&s[i * t], &d[i * j], j); | |
| 719 | case NAND_CMD_READ0: | ||
| 720 | host->col_addr = column; | ||
| 721 | host->spare_only = false; | ||
| 722 | useirq = false; | ||
| 723 | break; | ||
| 724 | |||
| 725 | case NAND_CMD_READOOB: | ||
| 726 | host->col_addr = column; | ||
| 727 | host->spare_only = true; | ||
| 728 | useirq = false; | ||
| 729 | if (host->pagesize_2k) | ||
| 730 | command = NAND_CMD_READ0; /* only READ0 is valid */ | ||
| 731 | break; | ||
| 732 | |||
| 733 | case NAND_CMD_SEQIN: | ||
| 734 | if (column >= mtd->writesize) { | ||
| 735 | /* | ||
| 736 | * FIXME: before send SEQIN command for write OOB, | ||
| 737 | * We must read one page out. | ||
| 738 | * For K9F1GXX has no READ1 command to set current HW | ||
| 739 | * pointer to spare area, we must write the whole page | ||
| 740 | * including OOB together. | ||
| 741 | */ | ||
| 742 | if (host->pagesize_2k) | ||
| 743 | /* call ourself to read a page */ | ||
| 744 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | ||
| 745 | page_addr); | ||
| 746 | |||
| 747 | host->col_addr = column - mtd->writesize; | ||
| 748 | host->spare_only = true; | ||
| 749 | |||
| 750 | /* Set program pointer to spare region */ | ||
| 751 | if (!host->pagesize_2k) | ||
| 752 | send_cmd(host, NAND_CMD_READOOB, false); | ||
| 753 | } else { | ||
| 754 | host->spare_only = false; | ||
| 755 | host->col_addr = column; | ||
| 756 | |||
| 757 | /* Set program pointer to page start */ | ||
| 758 | if (!host->pagesize_2k) | ||
| 759 | send_cmd(host, NAND_CMD_READ0, false); | ||
| 760 | } | ||
| 761 | useirq = false; | ||
| 762 | break; | ||
| 763 | |||
| 764 | case NAND_CMD_PAGEPROG: | ||
| 765 | send_prog_page(host, 0, host->spare_only); | ||
| 766 | |||
| 767 | if (host->pagesize_2k) { | ||
| 768 | /* data in 4 areas datas */ | ||
| 769 | send_prog_page(host, 1, host->spare_only); | ||
| 770 | send_prog_page(host, 2, host->spare_only); | ||
| 771 | send_prog_page(host, 3, host->spare_only); | ||
| 772 | } | ||
| 773 | |||
| 774 | break; | ||
| 775 | 493 | ||
| 776 | case NAND_CMD_ERASE1: | 494 | /* the last section */ |
| 777 | useirq = false; | 495 | memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j); |
| 778 | break; | ||
| 779 | } | 496 | } |
| 497 | } | ||
| 780 | 498 | ||
| 781 | /* Write out the command to the device. */ | 499 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) |
| 782 | send_cmd(host, command, useirq); | 500 | { |
| 501 | struct nand_chip *nand_chip = mtd->priv; | ||
| 502 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 783 | 503 | ||
| 784 | /* Write out column address, if necessary */ | 504 | /* Write out column address, if necessary */ |
| 785 | if (column != -1) { | 505 | if (column != -1) { |
| @@ -791,7 +511,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 791 | * the full page. | 511 | * the full page. |
| 792 | */ | 512 | */ |
| 793 | send_addr(host, 0, page_addr == -1); | 513 | send_addr(host, 0, page_addr == -1); |
| 794 | if (host->pagesize_2k) | 514 | if (mtd->writesize > 512) |
| 795 | /* another col addr cycle for 2k page */ | 515 | /* another col addr cycle for 2k page */ |
| 796 | send_addr(host, 0, false); | 516 | send_addr(host, 0, false); |
| 797 | } | 517 | } |
| @@ -801,7 +521,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 801 | /* paddr_0 - p_addr_7 */ | 521 | /* paddr_0 - p_addr_7 */ |
| 802 | send_addr(host, (page_addr & 0xff), false); | 522 | send_addr(host, (page_addr & 0xff), false); |
| 803 | 523 | ||
| 804 | if (host->pagesize_2k) { | 524 | if (mtd->writesize > 512) { |
| 805 | if (mtd->size >= 0x10000000) { | 525 | if (mtd->size >= 0x10000000) { |
| 806 | /* paddr_8 - paddr_15 */ | 526 | /* paddr_8 - paddr_15 */ |
| 807 | send_addr(host, (page_addr >> 8) & 0xff, false); | 527 | send_addr(host, (page_addr >> 8) & 0xff, false); |
| @@ -820,52 +540,136 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 820 | send_addr(host, (page_addr >> 8) & 0xff, true); | 540 | send_addr(host, (page_addr >> 8) & 0xff, true); |
| 821 | } | 541 | } |
| 822 | } | 542 | } |
| 543 | } | ||
| 544 | |||
| 545 | /* Used by the upper layer to write command to NAND Flash for | ||
| 546 | * different operations to be carried out on NAND Flash */ | ||
| 547 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | ||
| 548 | int column, int page_addr) | ||
| 549 | { | ||
| 550 | struct nand_chip *nand_chip = mtd->priv; | ||
| 551 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 552 | |||
| 553 | DEBUG(MTD_DEBUG_LEVEL3, | ||
| 554 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | ||
| 555 | command, column, page_addr); | ||
| 556 | |||
| 557 | /* Reset command state information */ | ||
| 558 | host->status_request = false; | ||
| 823 | 559 | ||
| 824 | /* Command post-processing step */ | 560 | /* Command pre-processing step */ |
| 825 | switch (command) { | 561 | switch (command) { |
| 826 | 562 | ||
| 827 | case NAND_CMD_RESET: | 563 | case NAND_CMD_STATUS: |
| 564 | host->buf_start = 0; | ||
| 565 | host->status_request = true; | ||
| 566 | |||
| 567 | send_cmd(host, command, true); | ||
| 568 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 828 | break; | 569 | break; |
| 829 | 570 | ||
| 830 | case NAND_CMD_READOOB: | ||
| 831 | case NAND_CMD_READ0: | 571 | case NAND_CMD_READ0: |
| 832 | if (host->pagesize_2k) { | 572 | case NAND_CMD_READOOB: |
| 833 | /* send read confirm command */ | 573 | if (command == NAND_CMD_READ0) |
| 574 | host->buf_start = column; | ||
| 575 | else | ||
| 576 | host->buf_start = column + mtd->writesize; | ||
| 577 | |||
| 578 | if (mtd->writesize > 512) | ||
| 579 | command = NAND_CMD_READ0; /* only READ0 is valid */ | ||
| 580 | |||
| 581 | send_cmd(host, command, false); | ||
| 582 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 583 | |||
| 584 | if (mtd->writesize > 512) | ||
| 834 | send_cmd(host, NAND_CMD_READSTART, true); | 585 | send_cmd(host, NAND_CMD_READSTART, true); |
| 835 | /* read for each AREA */ | 586 | |
| 836 | send_read_page(host, 0, host->spare_only); | 587 | send_page(mtd, NFC_OUTPUT); |
| 837 | send_read_page(host, 1, host->spare_only); | 588 | |
| 838 | send_read_page(host, 2, host->spare_only); | 589 | memcpy(host->data_buf, host->main_area0, mtd->writesize); |
| 839 | send_read_page(host, 3, host->spare_only); | 590 | copy_spare(mtd, true); |
| 840 | } else | ||
| 841 | send_read_page(host, 0, host->spare_only); | ||
| 842 | break; | 591 | break; |
| 843 | 592 | ||
| 844 | case NAND_CMD_READID: | 593 | case NAND_CMD_SEQIN: |
| 845 | host->col_addr = 0; | 594 | if (column >= mtd->writesize) { |
| 846 | send_read_id(host); | 595 | /* |
| 596 | * FIXME: before send SEQIN command for write OOB, | ||
| 597 | * We must read one page out. | ||
| 598 | * For K9F1GXX has no READ1 command to set current HW | ||
| 599 | * pointer to spare area, we must write the whole page | ||
| 600 | * including OOB together. | ||
| 601 | */ | ||
| 602 | if (mtd->writesize > 512) | ||
| 603 | /* call ourself to read a page */ | ||
| 604 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | ||
| 605 | page_addr); | ||
| 606 | |||
| 607 | host->buf_start = column; | ||
| 608 | |||
| 609 | /* Set program pointer to spare region */ | ||
| 610 | if (mtd->writesize == 512) | ||
| 611 | send_cmd(host, NAND_CMD_READOOB, false); | ||
| 612 | } else { | ||
| 613 | host->buf_start = column; | ||
| 614 | |||
| 615 | /* Set program pointer to page start */ | ||
| 616 | if (mtd->writesize == 512) | ||
| 617 | send_cmd(host, NAND_CMD_READ0, false); | ||
| 618 | } | ||
| 619 | |||
| 620 | send_cmd(host, command, false); | ||
| 621 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 847 | break; | 622 | break; |
| 848 | 623 | ||
| 849 | case NAND_CMD_PAGEPROG: | 624 | case NAND_CMD_PAGEPROG: |
| 625 | memcpy(host->main_area0, host->data_buf, mtd->writesize); | ||
| 626 | copy_spare(mtd, false); | ||
| 627 | send_page(mtd, NFC_INPUT); | ||
| 628 | send_cmd(host, command, true); | ||
| 629 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 850 | break; | 630 | break; |
| 851 | 631 | ||
| 852 | case NAND_CMD_STATUS: | 632 | case NAND_CMD_READID: |
| 633 | send_cmd(host, command, true); | ||
| 634 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 635 | send_read_id(host); | ||
| 636 | host->buf_start = column; | ||
| 853 | break; | 637 | break; |
| 854 | 638 | ||
| 639 | case NAND_CMD_ERASE1: | ||
| 855 | case NAND_CMD_ERASE2: | 640 | case NAND_CMD_ERASE2: |
| 641 | send_cmd(host, command, false); | ||
| 642 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 643 | |||
| 856 | break; | 644 | break; |
| 857 | } | 645 | } |
| 858 | } | 646 | } |
| 859 | 647 | ||
| 860 | /* Define some generic bad / good block scan pattern which are used | 648 | /* |
| 861 | * while scanning a device for factory marked good / bad blocks. */ | 649 | * The generic flash bbt decriptors overlap with our ecc |
| 862 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 650 | * hardware, so define some i.MX specific ones. |
| 651 | */ | ||
| 652 | static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; | ||
| 653 | static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; | ||
| 654 | |||
| 655 | static struct nand_bbt_descr bbt_main_descr = { | ||
| 656 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ||
| 657 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | ||
| 658 | .offs = 0, | ||
| 659 | .len = 4, | ||
| 660 | .veroffs = 4, | ||
| 661 | .maxblocks = 4, | ||
| 662 | .pattern = bbt_pattern, | ||
| 663 | }; | ||
| 863 | 664 | ||
| 864 | static struct nand_bbt_descr smallpage_memorybased = { | 665 | static struct nand_bbt_descr bbt_mirror_descr = { |
| 865 | .options = NAND_BBT_SCAN2NDPAGE, | 666 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
| 866 | .offs = 5, | 667 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, |
| 867 | .len = 1, | 668 | .offs = 0, |
| 868 | .pattern = scan_ff_pattern | 669 | .len = 4, |
| 670 | .veroffs = 4, | ||
| 671 | .maxblocks = 4, | ||
| 672 | .pattern = mirror_pattern, | ||
| 869 | }; | 673 | }; |
| 870 | 674 | ||
| 871 | static int __init mxcnd_probe(struct platform_device *pdev) | 675 | static int __init mxcnd_probe(struct platform_device *pdev) |
| @@ -877,12 +681,16 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 877 | struct resource *res; | 681 | struct resource *res; |
| 878 | uint16_t tmp; | 682 | uint16_t tmp; |
| 879 | int err = 0, nr_parts = 0; | 683 | int err = 0, nr_parts = 0; |
| 684 | struct nand_ecclayout *oob_smallpage, *oob_largepage; | ||
| 880 | 685 | ||
| 881 | /* Allocate memory for MTD device structure and private data */ | 686 | /* Allocate memory for MTD device structure and private data */ |
| 882 | host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL); | 687 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + |
| 688 | NAND_MAX_OOBSIZE, GFP_KERNEL); | ||
| 883 | if (!host) | 689 | if (!host) |
| 884 | return -ENOMEM; | 690 | return -ENOMEM; |
| 885 | 691 | ||
| 692 | host->data_buf = (uint8_t *)(host + 1); | ||
| 693 | |||
| 886 | host->dev = &pdev->dev; | 694 | host->dev = &pdev->dev; |
| 887 | /* structures must be linked */ | 695 | /* structures must be linked */ |
| 888 | this = &host->nand; | 696 | this = &host->nand; |
| @@ -890,7 +698,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 890 | mtd->priv = this; | 698 | mtd->priv = this; |
| 891 | mtd->owner = THIS_MODULE; | 699 | mtd->owner = THIS_MODULE; |
| 892 | mtd->dev.parent = &pdev->dev; | 700 | mtd->dev.parent = &pdev->dev; |
| 893 | mtd->name = "mxc_nand"; | 701 | mtd->name = DRIVER_NAME; |
| 894 | 702 | ||
| 895 | /* 50 us command delay time */ | 703 | /* 50 us command delay time */ |
| 896 | this->chip_delay = 5; | 704 | this->chip_delay = 5; |
| @@ -920,62 +728,93 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 920 | goto eres; | 728 | goto eres; |
| 921 | } | 729 | } |
| 922 | 730 | ||
| 923 | host->regs = ioremap(res->start, res->end - res->start + 1); | 731 | host->base = ioremap(res->start, resource_size(res)); |
| 924 | if (!host->regs) { | 732 | if (!host->base) { |
| 925 | err = -ENOMEM; | 733 | err = -ENOMEM; |
| 926 | goto eres; | 734 | goto eres; |
| 927 | } | 735 | } |
| 928 | 736 | ||
| 737 | host->main_area0 = host->base; | ||
| 738 | host->main_area1 = host->base + 0x200; | ||
| 739 | |||
| 740 | if (nfc_is_v21()) { | ||
| 741 | host->regs = host->base + 0x1000; | ||
| 742 | host->spare0 = host->base + 0x1000; | ||
| 743 | host->spare_len = 64; | ||
| 744 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
| 745 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
| 746 | } else if (nfc_is_v1()) { | ||
| 747 | host->regs = host->base; | ||
| 748 | host->spare0 = host->base + 0x800; | ||
| 749 | host->spare_len = 16; | ||
| 750 | oob_smallpage = &nandv1_hw_eccoob_smallpage; | ||
| 751 | oob_largepage = &nandv1_hw_eccoob_largepage; | ||
| 752 | } else | ||
| 753 | BUG(); | ||
| 754 | |||
| 755 | /* disable interrupt and spare enable */ | ||
| 929 | tmp = readw(host->regs + NFC_CONFIG1); | 756 | tmp = readw(host->regs + NFC_CONFIG1); |
| 930 | tmp |= NFC_INT_MSK; | 757 | tmp |= NFC_INT_MSK; |
| 758 | tmp &= ~NFC_SP_EN; | ||
| 931 | writew(tmp, host->regs + NFC_CONFIG1); | 759 | writew(tmp, host->regs + NFC_CONFIG1); |
| 932 | 760 | ||
| 933 | init_waitqueue_head(&host->irq_waitq); | 761 | init_waitqueue_head(&host->irq_waitq); |
| 934 | 762 | ||
| 935 | host->irq = platform_get_irq(pdev, 0); | 763 | host->irq = platform_get_irq(pdev, 0); |
| 936 | 764 | ||
| 937 | err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host); | 765 | err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); |
| 938 | if (err) | 766 | if (err) |
| 939 | goto eirq; | 767 | goto eirq; |
| 940 | 768 | ||
| 769 | /* Reset NAND */ | ||
| 770 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
| 771 | |||
| 772 | /* preset operation */ | ||
| 773 | /* Unlock the internal RAM Buffer */ | ||
| 774 | writew(0x2, host->regs + NFC_CONFIG); | ||
| 775 | |||
| 776 | /* Blocks to be unlocked */ | ||
| 777 | if (nfc_is_v21()) { | ||
| 778 | writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); | ||
| 779 | writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); | ||
| 780 | this->ecc.bytes = 9; | ||
| 781 | } else if (nfc_is_v1()) { | ||
| 782 | writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); | ||
| 783 | writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); | ||
| 784 | this->ecc.bytes = 3; | ||
| 785 | } else | ||
| 786 | BUG(); | ||
| 787 | |||
| 788 | /* Unlock Block Command for given address range */ | ||
| 789 | writew(0x4, host->regs + NFC_WRPROT); | ||
| 790 | |||
| 791 | this->ecc.size = 512; | ||
| 792 | this->ecc.layout = oob_smallpage; | ||
| 793 | |||
| 941 | if (pdata->hw_ecc) { | 794 | if (pdata->hw_ecc) { |
| 942 | this->ecc.calculate = mxc_nand_calculate_ecc; | 795 | this->ecc.calculate = mxc_nand_calculate_ecc; |
| 943 | this->ecc.hwctl = mxc_nand_enable_hwecc; | 796 | this->ecc.hwctl = mxc_nand_enable_hwecc; |
| 944 | this->ecc.correct = mxc_nand_correct_data; | 797 | this->ecc.correct = mxc_nand_correct_data; |
| 945 | this->ecc.mode = NAND_ECC_HW; | 798 | this->ecc.mode = NAND_ECC_HW; |
| 946 | this->ecc.size = 512; | ||
| 947 | this->ecc.bytes = 3; | ||
| 948 | tmp = readw(host->regs + NFC_CONFIG1); | 799 | tmp = readw(host->regs + NFC_CONFIG1); |
| 949 | tmp |= NFC_ECC_EN; | 800 | tmp |= NFC_ECC_EN; |
| 950 | writew(tmp, host->regs + NFC_CONFIG1); | 801 | writew(tmp, host->regs + NFC_CONFIG1); |
| 951 | } else { | 802 | } else { |
| 952 | this->ecc.size = 512; | ||
| 953 | this->ecc.bytes = 3; | ||
| 954 | this->ecc.layout = &nand_hw_eccoob_8; | ||
| 955 | this->ecc.mode = NAND_ECC_SOFT; | 803 | this->ecc.mode = NAND_ECC_SOFT; |
| 956 | tmp = readw(host->regs + NFC_CONFIG1); | 804 | tmp = readw(host->regs + NFC_CONFIG1); |
| 957 | tmp &= ~NFC_ECC_EN; | 805 | tmp &= ~NFC_ECC_EN; |
| 958 | writew(tmp, host->regs + NFC_CONFIG1); | 806 | writew(tmp, host->regs + NFC_CONFIG1); |
| 959 | } | 807 | } |
| 960 | 808 | ||
| 961 | /* Reset NAND */ | ||
| 962 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
| 963 | |||
| 964 | /* preset operation */ | ||
| 965 | /* Unlock the internal RAM Buffer */ | ||
| 966 | writew(0x2, host->regs + NFC_CONFIG); | ||
| 967 | |||
| 968 | /* Blocks to be unlocked */ | ||
| 969 | writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); | ||
| 970 | writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); | ||
| 971 | |||
| 972 | /* Unlock Block Command for given address range */ | ||
| 973 | writew(0x4, host->regs + NFC_WRPROT); | ||
| 974 | |||
| 975 | /* NAND bus width determines access funtions used by upper layer */ | 809 | /* NAND bus width determines access funtions used by upper layer */ |
| 976 | if (pdata->width == 2) { | 810 | if (pdata->width == 2) |
| 977 | this->options |= NAND_BUSWIDTH_16; | 811 | this->options |= NAND_BUSWIDTH_16; |
| 978 | this->ecc.layout = &nand_hw_eccoob_16; | 812 | |
| 813 | if (pdata->flash_bbt) { | ||
| 814 | this->bbt_td = &bbt_main_descr; | ||
| 815 | this->bbt_md = &bbt_mirror_descr; | ||
| 816 | /* update flash based bbt */ | ||
| 817 | this->options |= NAND_USE_FLASH_BBT; | ||
| 979 | } | 818 | } |
| 980 | 819 | ||
| 981 | /* first scan to find the device and get the page size */ | 820 | /* first scan to find the device and get the page size */ |
| @@ -984,38 +823,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 984 | goto escan; | 823 | goto escan; |
| 985 | } | 824 | } |
| 986 | 825 | ||
| 987 | if (mtd->writesize == 2048) { | 826 | if (mtd->writesize == 2048) |
| 988 | host->pagesize_2k = 1; | 827 | this->ecc.layout = oob_largepage; |
| 989 | this->badblock_pattern = &smallpage_memorybased; | ||
| 990 | } | ||
| 991 | |||
| 992 | if (this->ecc.mode == NAND_ECC_HW) { | ||
| 993 | switch (mtd->oobsize) { | ||
| 994 | case 8: | ||
| 995 | this->ecc.layout = &nand_hw_eccoob_8; | ||
| 996 | break; | ||
| 997 | case 16: | ||
| 998 | this->ecc.layout = &nand_hw_eccoob_16; | ||
| 999 | break; | ||
| 1000 | case 64: | ||
| 1001 | this->ecc.layout = &nand_hw_eccoob_64; | ||
| 1002 | break; | ||
| 1003 | default: | ||
| 1004 | /* page size not handled by HW ECC */ | ||
| 1005 | /* switching back to soft ECC */ | ||
| 1006 | this->ecc.size = 512; | ||
| 1007 | this->ecc.bytes = 3; | ||
| 1008 | this->ecc.layout = &nand_hw_eccoob_8; | ||
| 1009 | this->ecc.mode = NAND_ECC_SOFT; | ||
| 1010 | this->ecc.calculate = NULL; | ||
| 1011 | this->ecc.correct = NULL; | ||
| 1012 | this->ecc.hwctl = NULL; | ||
| 1013 | tmp = readw(host->regs + NFC_CONFIG1); | ||
| 1014 | tmp &= ~NFC_ECC_EN; | ||
| 1015 | writew(tmp, host->regs + NFC_CONFIG1); | ||
| 1016 | break; | ||
| 1017 | } | ||
| 1018 | } | ||
| 1019 | 828 | ||
| 1020 | /* second phase scan */ | 829 | /* second phase scan */ |
| 1021 | if (nand_scan_tail(mtd)) { | 830 | if (nand_scan_tail(mtd)) { |
| @@ -1043,7 +852,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1043 | escan: | 852 | escan: |
| 1044 | free_irq(host->irq, host); | 853 | free_irq(host->irq, host); |
| 1045 | eirq: | 854 | eirq: |
| 1046 | iounmap(host->regs); | 855 | iounmap(host->base); |
| 1047 | eres: | 856 | eres: |
| 1048 | clk_put(host->clk); | 857 | clk_put(host->clk); |
| 1049 | eclk: | 858 | eclk: |
| @@ -1062,7 +871,7 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
| 1062 | 871 | ||
| 1063 | nand_release(&host->mtd); | 872 | nand_release(&host->mtd); |
| 1064 | free_irq(host->irq, host); | 873 | free_irq(host->irq, host); |
| 1065 | iounmap(host->regs); | 874 | iounmap(host->base); |
| 1066 | kfree(host); | 875 | kfree(host); |
| 1067 | 876 | ||
| 1068 | return 0; | 877 | return 0; |
| @@ -1113,7 +922,7 @@ static struct platform_driver mxcnd_driver = { | |||
| 1113 | .driver = { | 922 | .driver = { |
| 1114 | .name = DRIVER_NAME, | 923 | .name = DRIVER_NAME, |
| 1115 | }, | 924 | }, |
| 1116 | .remove = __exit_p(mxcnd_remove), | 925 | .remove = __devexit_p(mxcnd_remove), |
| 1117 | .suspend = mxcnd_suspend, | 926 | .suspend = mxcnd_suspend, |
| 1118 | .resume = mxcnd_resume, | 927 | .resume = mxcnd_resume, |
| 1119 | }; | 928 | }; |
