Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Driver for Blackfin on-chip NAND controller. |
| 3 | * |
| 4 | * Enter bugs at http://blackfin.uclinux.org/ |
| 5 | * |
| 6 | * Copyright (c) 2007-2008 Analog Devices Inc. |
| 7 | * |
| 8 | * Licensed under the GPL-2 or later. |
| 9 | */ |
| 10 | |
| 11 | /* TODO: |
| 12 | * - move bit defines into mach-common/bits/nand.h |
| 13 | * - try and replace all IRQSTAT usage with STAT polling |
| 14 | * - have software ecc mode use same algo as hw ecc ? |
| 15 | */ |
| 16 | |
| 17 | #include <common.h> |
Simon Glass | 24b852a | 2015-11-08 23:47:45 -0700 | [diff] [blame] | 18 | #include <console.h> |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 19 | #include <asm/io.h> |
| 20 | |
| 21 | #ifdef DEBUG |
| 22 | # define pr_stamp() printf("%s:%s:%i: here i am\n", __FILE__, __func__, __LINE__) |
| 23 | #else |
| 24 | # define pr_stamp() |
| 25 | #endif |
| 26 | |
| 27 | #include <nand.h> |
| 28 | |
| 29 | #include <asm/blackfin.h> |
Mike Frysinger | 253f47f | 2010-06-02 05:59:06 -0400 | [diff] [blame] | 30 | #include <asm/portmux.h> |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 31 | |
| 32 | /* Bit masks for NFC_CTL */ |
| 33 | |
| 34 | #define WR_DLY 0xf /* Write Strobe Delay */ |
| 35 | #define RD_DLY 0xf0 /* Read Strobe Delay */ |
| 36 | #define NWIDTH 0x100 /* NAND Data Width */ |
| 37 | #define PG_SIZE 0x200 /* Page Size */ |
| 38 | |
| 39 | /* Bit masks for NFC_STAT */ |
| 40 | |
| 41 | #define NBUSY 0x1 /* Not Busy */ |
| 42 | #define WB_FULL 0x2 /* Write Buffer Full */ |
| 43 | #define PG_WR_STAT 0x4 /* Page Write Pending */ |
| 44 | #define PG_RD_STAT 0x8 /* Page Read Pending */ |
| 45 | #define WB_EMPTY 0x10 /* Write Buffer Empty */ |
| 46 | |
| 47 | /* Bit masks for NFC_IRQSTAT */ |
| 48 | |
| 49 | #define NBUSYIRQ 0x1 /* Not Busy IRQ */ |
| 50 | #define WB_OVF 0x2 /* Write Buffer Overflow */ |
| 51 | #define WB_EDGE 0x4 /* Write Buffer Edge Detect */ |
| 52 | #define RD_RDY 0x8 /* Read Data Ready */ |
| 53 | #define WR_DONE 0x10 /* Page Write Done */ |
| 54 | |
| 55 | #define NAND_IS_512() (CONFIG_BFIN_NFC_CTL_VAL & 0x200) |
| 56 | |
| 57 | /* |
| 58 | * hardware specific access to control-lines |
| 59 | */ |
| 60 | static void bfin_nfc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
| 61 | { |
| 62 | pr_stamp(); |
| 63 | |
| 64 | if (cmd == NAND_CMD_NONE) |
| 65 | return; |
| 66 | |
| 67 | while (bfin_read_NFC_STAT() & WB_FULL) |
| 68 | continue; |
| 69 | |
| 70 | if (ctrl & NAND_CLE) |
| 71 | bfin_write_NFC_CMD(cmd); |
| 72 | else |
| 73 | bfin_write_NFC_ADDR(cmd); |
| 74 | SSYNC(); |
| 75 | } |
| 76 | |
Mike Frysinger | 3f54108 | 2012-02-02 18:54:20 -0500 | [diff] [blame] | 77 | static int bfin_nfc_devready(struct mtd_info *mtd) |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 78 | { |
| 79 | pr_stamp(); |
Andrew Caldwell | c941b77 | 2010-05-07 15:10:07 -0400 | [diff] [blame] | 80 | return (bfin_read_NFC_STAT() & NBUSY) ? 1 : 0; |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | /* |
| 84 | * PIO mode for buffer writing and reading |
| 85 | */ |
| 86 | static void bfin_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
| 87 | { |
| 88 | pr_stamp(); |
| 89 | |
| 90 | int i; |
| 91 | |
| 92 | /* |
| 93 | * Data reads are requested by first writing to NFC_DATA_RD |
| 94 | * and then reading back from NFC_READ. |
| 95 | */ |
| 96 | for (i = 0; i < len; ++i) { |
| 97 | while (bfin_read_NFC_STAT() & WB_FULL) |
| 98 | if (ctrlc()) |
| 99 | return; |
| 100 | |
| 101 | /* Contents do not matter */ |
| 102 | bfin_write_NFC_DATA_RD(0x0000); |
Graf Yang | a343ba8 | 2009-04-04 07:45:57 -0400 | [diff] [blame] | 103 | SSYNC(); |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 104 | |
| 105 | while (!(bfin_read_NFC_IRQSTAT() & RD_RDY)) |
| 106 | if (ctrlc()) |
| 107 | return; |
| 108 | |
| 109 | buf[i] = bfin_read_NFC_READ(); |
| 110 | |
| 111 | bfin_write_NFC_IRQSTAT(RD_RDY); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | static uint8_t bfin_nfc_read_byte(struct mtd_info *mtd) |
| 116 | { |
| 117 | pr_stamp(); |
| 118 | |
| 119 | uint8_t val; |
| 120 | bfin_nfc_read_buf(mtd, &val, 1); |
| 121 | return val; |
| 122 | } |
| 123 | |
| 124 | static void bfin_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
| 125 | { |
| 126 | pr_stamp(); |
| 127 | |
| 128 | int i; |
| 129 | |
| 130 | for (i = 0; i < len; ++i) { |
| 131 | while (bfin_read_NFC_STAT() & WB_FULL) |
| 132 | if (ctrlc()) |
| 133 | return; |
| 134 | |
| 135 | bfin_write_NFC_DATA_WR(buf[i]); |
| 136 | } |
Andrew Caldwell | c941b77 | 2010-05-07 15:10:07 -0400 | [diff] [blame] | 137 | |
| 138 | /* Wait for the buffer to drain before we return */ |
| 139 | while (!(bfin_read_NFC_STAT() & WB_EMPTY)) |
| 140 | if (ctrlc()) |
| 141 | return; |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | /* |
| 145 | * ECC functions |
| 146 | * These allow the bfin to use the controller's ECC |
| 147 | * generator block to ECC the data as it passes through |
| 148 | */ |
| 149 | |
| 150 | /* |
| 151 | * ECC error correction function |
| 152 | */ |
| 153 | static int bfin_nfc_correct_data_256(struct mtd_info *mtd, u_char *dat, |
| 154 | u_char *read_ecc, u_char *calc_ecc) |
| 155 | { |
| 156 | u32 syndrome[5]; |
| 157 | u32 calced, stored; |
| 158 | unsigned short failing_bit, failing_byte; |
| 159 | u_char data; |
| 160 | |
| 161 | pr_stamp(); |
| 162 | |
| 163 | calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); |
| 164 | stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); |
| 165 | |
| 166 | syndrome[0] = (calced ^ stored); |
| 167 | |
| 168 | /* |
| 169 | * syndrome 0: all zero |
| 170 | * No error in data |
| 171 | * No action |
| 172 | */ |
| 173 | if (!syndrome[0] || !calced || !stored) |
| 174 | return 0; |
| 175 | |
| 176 | /* |
| 177 | * sysdrome 0: only one bit is one |
| 178 | * ECC data was incorrect |
| 179 | * No action |
| 180 | */ |
| 181 | if (hweight32(syndrome[0]) == 1) |
| 182 | return 1; |
| 183 | |
| 184 | syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); |
| 185 | syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); |
| 186 | syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); |
| 187 | syndrome[4] = syndrome[2] ^ syndrome[3]; |
| 188 | |
| 189 | /* |
| 190 | * sysdrome 0: exactly 11 bits are one, each parity |
| 191 | * and parity' pair is 1 & 0 or 0 & 1. |
| 192 | * 1-bit correctable error |
| 193 | * Correct the error |
| 194 | */ |
| 195 | if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { |
| 196 | failing_bit = syndrome[1] & 0x7; |
| 197 | failing_byte = syndrome[1] >> 0x3; |
| 198 | data = *(dat + failing_byte); |
| 199 | data = data ^ (0x1 << failing_bit); |
| 200 | *(dat + failing_byte) = data; |
| 201 | |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | /* |
| 206 | * sysdrome 0: random data |
| 207 | * More than 1-bit error, non-correctable error |
| 208 | * Discard data, mark bad block |
| 209 | */ |
| 210 | |
| 211 | return 1; |
| 212 | } |
| 213 | |
| 214 | static int bfin_nfc_correct_data(struct mtd_info *mtd, u_char *dat, |
| 215 | u_char *read_ecc, u_char *calc_ecc) |
| 216 | { |
| 217 | int ret; |
| 218 | |
| 219 | pr_stamp(); |
| 220 | |
| 221 | ret = bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); |
| 222 | |
| 223 | /* If page size is 512, correct second 256 bytes */ |
| 224 | if (NAND_IS_512()) { |
| 225 | dat += 256; |
| 226 | read_ecc += 8; |
| 227 | calc_ecc += 8; |
| 228 | ret |= bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); |
| 229 | } |
| 230 | |
| 231 | return ret; |
| 232 | } |
| 233 | |
| 234 | static void reset_ecc(void) |
| 235 | { |
| 236 | bfin_write_NFC_RST(0x1); |
| 237 | while (bfin_read_NFC_RST() & 1) |
| 238 | continue; |
| 239 | } |
| 240 | |
| 241 | static void bfin_nfc_enable_hwecc(struct mtd_info *mtd, int mode) |
| 242 | { |
| 243 | reset_ecc(); |
| 244 | } |
| 245 | |
| 246 | static int bfin_nfc_calculate_ecc(struct mtd_info *mtd, |
| 247 | const u_char *dat, u_char *ecc_code) |
| 248 | { |
| 249 | u16 ecc0, ecc1; |
| 250 | u32 code[2]; |
| 251 | u8 *p; |
| 252 | |
| 253 | pr_stamp(); |
| 254 | |
| 255 | /* first 4 bytes ECC code for 256 page size */ |
| 256 | ecc0 = bfin_read_NFC_ECC0(); |
| 257 | ecc1 = bfin_read_NFC_ECC1(); |
| 258 | |
| 259 | code[0] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); |
| 260 | |
| 261 | /* first 3 bytes in ecc_code for 256 page size */ |
| 262 | p = (u8 *) code; |
| 263 | memcpy(ecc_code, p, 3); |
| 264 | |
| 265 | /* second 4 bytes ECC code for 512 page size */ |
| 266 | if (NAND_IS_512()) { |
| 267 | ecc0 = bfin_read_NFC_ECC2(); |
| 268 | ecc1 = bfin_read_NFC_ECC3(); |
| 269 | code[1] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); |
| 270 | |
| 271 | /* second 3 bytes in ecc_code for second 256 |
| 272 | * bytes of 512 page size |
| 273 | */ |
| 274 | p = (u8 *) (code + 1); |
| 275 | memcpy((ecc_code + 3), p, 3); |
| 276 | } |
| 277 | |
| 278 | reset_ecc(); |
| 279 | |
| 280 | return 0; |
| 281 | } |
| 282 | |
| 283 | #ifdef CONFIG_BFIN_NFC_BOOTROM_ECC |
| 284 | # define BOOTROM_ECC 1 |
| 285 | #else |
| 286 | # define BOOTROM_ECC 0 |
| 287 | #endif |
| 288 | |
| 289 | static uint8_t bbt_pattern[] = { 0xff }; |
| 290 | |
| 291 | static struct nand_bbt_descr bootrom_bbt = { |
| 292 | .options = 0, |
| 293 | .offs = 63, |
| 294 | .len = 1, |
| 295 | .pattern = bbt_pattern, |
| 296 | }; |
| 297 | |
| 298 | static struct nand_ecclayout bootrom_ecclayout = { |
| 299 | .eccbytes = 24, |
| 300 | .eccpos = { |
| 301 | 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, |
| 302 | 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, |
| 303 | 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, |
| 304 | 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, |
| 305 | 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, |
| 306 | 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, |
| 307 | 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, |
| 308 | 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 |
| 309 | }, |
| 310 | .oobfree = { |
| 311 | { 0x8 * 0 + 3, 5 }, |
| 312 | { 0x8 * 1 + 3, 5 }, |
| 313 | { 0x8 * 2 + 3, 5 }, |
| 314 | { 0x8 * 3 + 3, 5 }, |
| 315 | { 0x8 * 4 + 3, 5 }, |
| 316 | { 0x8 * 5 + 3, 5 }, |
| 317 | { 0x8 * 6 + 3, 5 }, |
| 318 | { 0x8 * 7 + 3, 5 }, |
| 319 | } |
| 320 | }; |
| 321 | |
| 322 | /* |
| 323 | * Board-specific NAND initialization. The following members of the |
| 324 | * argument are board-specific (per include/linux/mtd/nand.h): |
| 325 | * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device |
| 326 | * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device |
| 327 | * - cmd_ctrl: hardwarespecific function for accesing control-lines |
| 328 | * - dev_ready: hardwarespecific function for accesing device ready/busy line |
| 329 | * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must |
| 330 | * only be provided if a hardware ECC is available |
| 331 | * - ecc.mode: mode of ecc, see defines |
| 332 | * - chip_delay: chip dependent delay for transfering data from array to |
| 333 | * read regs (tR) |
| 334 | * - options: various chip options. They can partly be set to inform |
| 335 | * nand_scan about special functionality. See the defines for further |
| 336 | * explanation |
| 337 | * Members with a "?" were not set in the merged testing-NAND branch, |
| 338 | * so they are not set here either. |
| 339 | */ |
| 340 | int board_nand_init(struct nand_chip *chip) |
| 341 | { |
Mike Frysinger | 253f47f | 2010-06-02 05:59:06 -0400 | [diff] [blame] | 342 | const unsigned short pins[] = { |
| 343 | P_NAND_CE, P_NAND_RB, P_NAND_D0, P_NAND_D1, P_NAND_D2, |
| 344 | P_NAND_D3, P_NAND_D4, P_NAND_D5, P_NAND_D6, P_NAND_D7, |
| 345 | P_NAND_WE, P_NAND_RE, P_NAND_CLE, P_NAND_ALE, 0, |
| 346 | }; |
| 347 | |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 348 | pr_stamp(); |
| 349 | |
| 350 | /* set width/ecc/timings/etc... */ |
| 351 | bfin_write_NFC_CTL(CONFIG_BFIN_NFC_CTL_VAL); |
| 352 | |
| 353 | /* clear interrupt status */ |
| 354 | bfin_write_NFC_IRQMASK(0x0); |
| 355 | bfin_write_NFC_IRQSTAT(0xffff); |
| 356 | |
| 357 | /* enable GPIO function enable register */ |
Mike Frysinger | 253f47f | 2010-06-02 05:59:06 -0400 | [diff] [blame] | 358 | peripheral_request_list(pins, "bfin_nand"); |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 359 | |
| 360 | chip->cmd_ctrl = bfin_nfc_cmd_ctrl; |
| 361 | chip->read_buf = bfin_nfc_read_buf; |
| 362 | chip->write_buf = bfin_nfc_write_buf; |
| 363 | chip->read_byte = bfin_nfc_read_byte; |
| 364 | |
| 365 | #ifdef CONFIG_BFIN_NFC_NO_HW_ECC |
| 366 | # define ECC_HW 0 |
| 367 | #else |
| 368 | # define ECC_HW 1 |
| 369 | #endif |
| 370 | if (ECC_HW) { |
| 371 | if (BOOTROM_ECC) { |
| 372 | chip->badblock_pattern = &bootrom_bbt; |
| 373 | chip->ecc.layout = &bootrom_ecclayout; |
| 374 | } |
| 375 | if (!NAND_IS_512()) { |
| 376 | chip->ecc.bytes = 3; |
| 377 | chip->ecc.size = 256; |
Sergey Lapin | dfe64e2 | 2013-01-14 03:46:50 +0000 | [diff] [blame] | 378 | chip->ecc.strength = 1; |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 379 | } else { |
| 380 | chip->ecc.bytes = 6; |
| 381 | chip->ecc.size = 512; |
Sergey Lapin | dfe64e2 | 2013-01-14 03:46:50 +0000 | [diff] [blame] | 382 | chip->ecc.strength = 2; |
Mike Frysinger | be9d8c7 | 2008-11-26 21:43:06 -0500 | [diff] [blame] | 383 | } |
| 384 | chip->ecc.mode = NAND_ECC_HW; |
| 385 | chip->ecc.calculate = bfin_nfc_calculate_ecc; |
| 386 | chip->ecc.correct = bfin_nfc_correct_data; |
| 387 | chip->ecc.hwctl = bfin_nfc_enable_hwecc; |
| 388 | } else |
| 389 | chip->ecc.mode = NAND_ECC_SOFT; |
| 390 | chip->dev_ready = bfin_nfc_devready; |
| 391 | chip->chip_delay = 0; |
| 392 | |
| 393 | return 0; |
| 394 | } |