| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ST Microelectronics |
|---|
| 3 | 4 | * Flexible Static Memory Controller (FSMC) |
|---|
| .. | .. |
|---|
| 10 | 11 | * Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8) |
|---|
| 11 | 12 | * Copyright © 2007 STMicroelectronics Pvt. Ltd. |
|---|
| 12 | 13 | * Copyright © 2009 Alessandro Rubini |
|---|
| 13 | | - * |
|---|
| 14 | | - * This file is licensed under the terms of the GNU General Public |
|---|
| 15 | | - * License version 2. This program is licensed "as is" without any |
|---|
| 16 | | - * warranty of any kind, whether express or implied. |
|---|
| 17 | 14 | */ |
|---|
| 18 | 15 | |
|---|
| 19 | 16 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 42 | 39 | /* fsmc controller registers for NOR flash */ |
|---|
| 43 | 40 | #define CTRL 0x0 |
|---|
| 44 | 41 | /* ctrl register definitions */ |
|---|
| 45 | | - #define BANK_ENABLE (1 << 0) |
|---|
| 46 | | - #define MUXED (1 << 1) |
|---|
| 42 | + #define BANK_ENABLE BIT(0) |
|---|
| 43 | + #define MUXED BIT(1) |
|---|
| 47 | 44 | #define NOR_DEV (2 << 2) |
|---|
| 48 | | - #define WIDTH_8 (0 << 4) |
|---|
| 49 | | - #define WIDTH_16 (1 << 4) |
|---|
| 50 | | - #define RSTPWRDWN (1 << 6) |
|---|
| 51 | | - #define WPROT (1 << 7) |
|---|
| 52 | | - #define WRT_ENABLE (1 << 12) |
|---|
| 53 | | - #define WAIT_ENB (1 << 13) |
|---|
| 45 | + #define WIDTH_16 BIT(4) |
|---|
| 46 | + #define RSTPWRDWN BIT(6) |
|---|
| 47 | + #define WPROT BIT(7) |
|---|
| 48 | + #define WRT_ENABLE BIT(12) |
|---|
| 49 | + #define WAIT_ENB BIT(13) |
|---|
| 54 | 50 | |
|---|
| 55 | 51 | #define CTRL_TIM 0x4 |
|---|
| 56 | 52 | /* ctrl_tim register definitions */ |
|---|
| .. | .. |
|---|
| 58 | 54 | #define FSMC_NOR_BANK_SZ 0x8 |
|---|
| 59 | 55 | #define FSMC_NOR_REG_SIZE 0x40 |
|---|
| 60 | 56 | |
|---|
| 61 | | -#define FSMC_NOR_REG(base, bank, reg) (base + \ |
|---|
| 62 | | - FSMC_NOR_BANK_SZ * (bank) + \ |
|---|
| 63 | | - reg) |
|---|
| 57 | +#define FSMC_NOR_REG(base, bank, reg) ((base) + \ |
|---|
| 58 | + (FSMC_NOR_BANK_SZ * (bank)) + \ |
|---|
| 59 | + (reg)) |
|---|
| 64 | 60 | |
|---|
| 65 | 61 | /* fsmc controller registers for NAND flash */ |
|---|
| 66 | 62 | #define FSMC_PC 0x00 |
|---|
| 67 | 63 | /* pc register definitions */ |
|---|
| 68 | | - #define FSMC_RESET (1 << 0) |
|---|
| 69 | | - #define FSMC_WAITON (1 << 1) |
|---|
| 70 | | - #define FSMC_ENABLE (1 << 2) |
|---|
| 71 | | - #define FSMC_DEVTYPE_NAND (1 << 3) |
|---|
| 72 | | - #define FSMC_DEVWID_8 (0 << 4) |
|---|
| 73 | | - #define FSMC_DEVWID_16 (1 << 4) |
|---|
| 74 | | - #define FSMC_ECCEN (1 << 6) |
|---|
| 75 | | - #define FSMC_ECCPLEN_512 (0 << 7) |
|---|
| 76 | | - #define FSMC_ECCPLEN_256 (1 << 7) |
|---|
| 77 | | - #define FSMC_TCLR_1 (1) |
|---|
| 64 | + #define FSMC_RESET BIT(0) |
|---|
| 65 | + #define FSMC_WAITON BIT(1) |
|---|
| 66 | + #define FSMC_ENABLE BIT(2) |
|---|
| 67 | + #define FSMC_DEVTYPE_NAND BIT(3) |
|---|
| 68 | + #define FSMC_DEVWID_16 BIT(4) |
|---|
| 69 | + #define FSMC_ECCEN BIT(6) |
|---|
| 70 | + #define FSMC_ECCPLEN_256 BIT(7) |
|---|
| 78 | 71 | #define FSMC_TCLR_SHIFT (9) |
|---|
| 79 | 72 | #define FSMC_TCLR_MASK (0xF) |
|---|
| 80 | | - #define FSMC_TAR_1 (1) |
|---|
| 81 | 73 | #define FSMC_TAR_SHIFT (13) |
|---|
| 82 | 74 | #define FSMC_TAR_MASK (0xF) |
|---|
| 83 | 75 | #define STS 0x04 |
|---|
| 84 | 76 | /* sts register definitions */ |
|---|
| 85 | | - #define FSMC_CODE_RDY (1 << 15) |
|---|
| 77 | + #define FSMC_CODE_RDY BIT(15) |
|---|
| 86 | 78 | #define COMM 0x08 |
|---|
| 87 | 79 | /* comm register definitions */ |
|---|
| 88 | | - #define FSMC_TSET_0 0 |
|---|
| 89 | 80 | #define FSMC_TSET_SHIFT 0 |
|---|
| 90 | 81 | #define FSMC_TSET_MASK 0xFF |
|---|
| 91 | | - #define FSMC_TWAIT_6 6 |
|---|
| 92 | 82 | #define FSMC_TWAIT_SHIFT 8 |
|---|
| 93 | 83 | #define FSMC_TWAIT_MASK 0xFF |
|---|
| 94 | | - #define FSMC_THOLD_4 4 |
|---|
| 95 | 84 | #define FSMC_THOLD_SHIFT 16 |
|---|
| 96 | 85 | #define FSMC_THOLD_MASK 0xFF |
|---|
| 97 | | - #define FSMC_THIZ_1 1 |
|---|
| 98 | 86 | #define FSMC_THIZ_SHIFT 24 |
|---|
| 99 | 87 | #define FSMC_THIZ_MASK 0xFF |
|---|
| 100 | 88 | #define ATTRIB 0x0C |
|---|
| .. | .. |
|---|
| 106 | 94 | |
|---|
| 107 | 95 | #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ) |
|---|
| 108 | 96 | |
|---|
| 97 | +/* |
|---|
| 98 | + * According to SPEAr300 Reference Manual (RM0082) |
|---|
| 99 | + * TOUDEL = 7ns (Output delay from the flip-flops to the board) |
|---|
| 100 | + * TINDEL = 5ns (Input delay from the board to the flipflop) |
|---|
| 101 | + */ |
|---|
| 102 | +#define TOUTDEL 7000 |
|---|
| 103 | +#define TINDEL 5000 |
|---|
| 104 | + |
|---|
| 109 | 105 | struct fsmc_nand_timings { |
|---|
| 110 | | - uint8_t tclr; |
|---|
| 111 | | - uint8_t tar; |
|---|
| 112 | | - uint8_t thiz; |
|---|
| 113 | | - uint8_t thold; |
|---|
| 114 | | - uint8_t twait; |
|---|
| 115 | | - uint8_t tset; |
|---|
| 106 | + u8 tclr; |
|---|
| 107 | + u8 tar; |
|---|
| 108 | + u8 thiz; |
|---|
| 109 | + u8 thold; |
|---|
| 110 | + u8 twait; |
|---|
| 111 | + u8 tset; |
|---|
| 116 | 112 | }; |
|---|
| 117 | 113 | |
|---|
| 118 | 114 | enum access_mode { |
|---|
| .. | .. |
|---|
| 123 | 119 | /** |
|---|
| 124 | 120 | * struct fsmc_nand_data - structure for FSMC NAND device state |
|---|
| 125 | 121 | * |
|---|
| 122 | + * @base: Inherit from the nand_controller struct |
|---|
| 126 | 123 | * @pid: Part ID on the AMBA PrimeCell format |
|---|
| 127 | | - * @mtd: MTD info for a NAND flash. |
|---|
| 128 | 124 | * @nand: Chip related info for a NAND flash. |
|---|
| 129 | | - * @partitions: Partition info for a NAND Flash. |
|---|
| 130 | | - * @nr_partitions: Total number of partition of a NAND flash. |
|---|
| 131 | 125 | * |
|---|
| 132 | 126 | * @bank: Bank number for probed device. |
|---|
| 127 | + * @dev: Parent device |
|---|
| 128 | + * @mode: Access mode |
|---|
| 133 | 129 | * @clk: Clock structure for FSMC. |
|---|
| 134 | 130 | * |
|---|
| 135 | 131 | * @read_dma_chan: DMA channel for read access |
|---|
| 136 | 132 | * @write_dma_chan: DMA channel for write access to NAND |
|---|
| 137 | 133 | * @dma_access_complete: Completion structure |
|---|
| 134 | + * |
|---|
| 135 | + * @dev_timings: NAND timings |
|---|
| 138 | 136 | * |
|---|
| 139 | 137 | * @data_pa: NAND Physical port for Data. |
|---|
| 140 | 138 | * @data_va: NAND port for Data. |
|---|
| .. | .. |
|---|
| 143 | 141 | * @regs_va: Registers base address for a given bank. |
|---|
| 144 | 142 | */ |
|---|
| 145 | 143 | struct fsmc_nand_data { |
|---|
| 144 | + struct nand_controller base; |
|---|
| 146 | 145 | u32 pid; |
|---|
| 147 | 146 | struct nand_chip nand; |
|---|
| 148 | 147 | |
|---|
| .. | .. |
|---|
| 249 | 248 | .free = fsmc_ecc4_ooblayout_free, |
|---|
| 250 | 249 | }; |
|---|
| 251 | 250 | |
|---|
| 252 | | -static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd) |
|---|
| 251 | +static inline struct fsmc_nand_data *nand_to_fsmc(struct nand_chip *chip) |
|---|
| 253 | 252 | { |
|---|
| 254 | | - return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand); |
|---|
| 253 | + return container_of(chip, struct fsmc_nand_data, nand); |
|---|
| 255 | 254 | } |
|---|
| 256 | 255 | |
|---|
| 257 | 256 | /* |
|---|
| .. | .. |
|---|
| 263 | 262 | static void fsmc_nand_setup(struct fsmc_nand_data *host, |
|---|
| 264 | 263 | struct fsmc_nand_timings *tims) |
|---|
| 265 | 264 | { |
|---|
| 266 | | - uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; |
|---|
| 267 | | - uint32_t tclr, tar, thiz, thold, twait, tset; |
|---|
| 265 | + u32 value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; |
|---|
| 266 | + u32 tclr, tar, thiz, thold, twait, tset; |
|---|
| 268 | 267 | |
|---|
| 269 | 268 | tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT; |
|---|
| 270 | 269 | tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT; |
|---|
| .. | .. |
|---|
| 274 | 273 | tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; |
|---|
| 275 | 274 | |
|---|
| 276 | 275 | if (host->nand.options & NAND_BUSWIDTH_16) |
|---|
| 277 | | - writel_relaxed(value | FSMC_DEVWID_16, |
|---|
| 278 | | - host->regs_va + FSMC_PC); |
|---|
| 279 | | - else |
|---|
| 280 | | - writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + FSMC_PC); |
|---|
| 276 | + value |= FSMC_DEVWID_16; |
|---|
| 281 | 277 | |
|---|
| 282 | | - writel_relaxed(readl(host->regs_va + FSMC_PC) | tclr | tar, |
|---|
| 283 | | - host->regs_va + FSMC_PC); |
|---|
| 278 | + writel_relaxed(value | tclr | tar, host->regs_va + FSMC_PC); |
|---|
| 284 | 279 | writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM); |
|---|
| 285 | 280 | writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB); |
|---|
| 286 | 281 | } |
|---|
| .. | .. |
|---|
| 291 | 286 | { |
|---|
| 292 | 287 | unsigned long hclk = clk_get_rate(host->clk); |
|---|
| 293 | 288 | unsigned long hclkn = NSEC_PER_SEC / hclk; |
|---|
| 294 | | - uint32_t thiz, thold, twait, tset; |
|---|
| 289 | + u32 thiz, thold, twait, tset, twait_min; |
|---|
| 295 | 290 | |
|---|
| 296 | 291 | if (sdrt->tRC_min < 30000) |
|---|
| 297 | 292 | return -EOPNOTSUPP; |
|---|
| .. | .. |
|---|
| 323 | 318 | else if (tims->thold > FSMC_THOLD_MASK) |
|---|
| 324 | 319 | tims->thold = FSMC_THOLD_MASK; |
|---|
| 325 | 320 | |
|---|
| 326 | | - twait = max(sdrt->tRP_min, sdrt->tWP_min); |
|---|
| 327 | | - tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1; |
|---|
| 328 | | - if (tims->twait == 0) |
|---|
| 329 | | - tims->twait = 1; |
|---|
| 330 | | - else if (tims->twait > FSMC_TWAIT_MASK) |
|---|
| 331 | | - tims->twait = FSMC_TWAIT_MASK; |
|---|
| 332 | | - |
|---|
| 333 | 321 | tset = max(sdrt->tCS_min - sdrt->tWP_min, |
|---|
| 334 | 322 | sdrt->tCEA_max - sdrt->tREA_max); |
|---|
| 335 | 323 | tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1; |
|---|
| .. | .. |
|---|
| 338 | 326 | else if (tims->tset > FSMC_TSET_MASK) |
|---|
| 339 | 327 | tims->tset = FSMC_TSET_MASK; |
|---|
| 340 | 328 | |
|---|
| 329 | + /* |
|---|
| 330 | + * According to SPEAr300 Reference Manual (RM0082) which gives more |
|---|
| 331 | + * information related to FSMSC timings than the SPEAr600 one (RM0305), |
|---|
| 332 | + * twait >= tCEA - (tset * TCLK) + TOUTDEL + TINDEL |
|---|
| 333 | + */ |
|---|
| 334 | + twait_min = sdrt->tCEA_max - ((tims->tset + 1) * hclkn * 1000) |
|---|
| 335 | + + TOUTDEL + TINDEL; |
|---|
| 336 | + twait = max3(sdrt->tRP_min, sdrt->tWP_min, twait_min); |
|---|
| 337 | + |
|---|
| 338 | + tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1; |
|---|
| 339 | + if (tims->twait == 0) |
|---|
| 340 | + tims->twait = 1; |
|---|
| 341 | + else if (tims->twait > FSMC_TWAIT_MASK) |
|---|
| 342 | + tims->twait = FSMC_TWAIT_MASK; |
|---|
| 343 | + |
|---|
| 341 | 344 | return 0; |
|---|
| 342 | 345 | } |
|---|
| 343 | 346 | |
|---|
| 344 | | -static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline, |
|---|
| 345 | | - const struct nand_data_interface *conf) |
|---|
| 347 | +static int fsmc_setup_interface(struct nand_chip *nand, int csline, |
|---|
| 348 | + const struct nand_interface_config *conf) |
|---|
| 346 | 349 | { |
|---|
| 347 | | - struct nand_chip *nand = mtd_to_nand(mtd); |
|---|
| 348 | | - struct fsmc_nand_data *host = nand_get_controller_data(nand); |
|---|
| 350 | + struct fsmc_nand_data *host = nand_to_fsmc(nand); |
|---|
| 349 | 351 | struct fsmc_nand_timings tims; |
|---|
| 350 | 352 | const struct nand_sdr_timings *sdrt; |
|---|
| 351 | 353 | int ret; |
|---|
| .. | .. |
|---|
| 369 | 371 | /* |
|---|
| 370 | 372 | * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers |
|---|
| 371 | 373 | */ |
|---|
| 372 | | -static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) |
|---|
| 374 | +static void fsmc_enable_hwecc(struct nand_chip *chip, int mode) |
|---|
| 373 | 375 | { |
|---|
| 374 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 376 | + struct fsmc_nand_data *host = nand_to_fsmc(chip); |
|---|
| 375 | 377 | |
|---|
| 376 | 378 | writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256, |
|---|
| 377 | 379 | host->regs_va + FSMC_PC); |
|---|
| .. | .. |
|---|
| 386 | 388 | * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to |
|---|
| 387 | 389 | * max of 8-bits) |
|---|
| 388 | 390 | */ |
|---|
| 389 | | -static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, |
|---|
| 390 | | - uint8_t *ecc) |
|---|
| 391 | +static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const u8 *data, |
|---|
| 392 | + u8 *ecc) |
|---|
| 391 | 393 | { |
|---|
| 392 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 393 | | - uint32_t ecc_tmp; |
|---|
| 394 | + struct fsmc_nand_data *host = nand_to_fsmc(chip); |
|---|
| 395 | + u32 ecc_tmp; |
|---|
| 394 | 396 | unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; |
|---|
| 395 | 397 | |
|---|
| 396 | 398 | do { |
|---|
| 397 | 399 | if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY) |
|---|
| 398 | 400 | break; |
|---|
| 399 | | - else |
|---|
| 400 | | - cond_resched(); |
|---|
| 401 | + |
|---|
| 402 | + cond_resched(); |
|---|
| 401 | 403 | } while (!time_after_eq(jiffies, deadline)); |
|---|
| 402 | 404 | |
|---|
| 403 | 405 | if (time_after_eq(jiffies, deadline)) { |
|---|
| .. | .. |
|---|
| 406 | 408 | } |
|---|
| 407 | 409 | |
|---|
| 408 | 410 | ecc_tmp = readl_relaxed(host->regs_va + ECC1); |
|---|
| 409 | | - ecc[0] = (uint8_t) (ecc_tmp >> 0); |
|---|
| 410 | | - ecc[1] = (uint8_t) (ecc_tmp >> 8); |
|---|
| 411 | | - ecc[2] = (uint8_t) (ecc_tmp >> 16); |
|---|
| 412 | | - ecc[3] = (uint8_t) (ecc_tmp >> 24); |
|---|
| 411 | + ecc[0] = ecc_tmp; |
|---|
| 412 | + ecc[1] = ecc_tmp >> 8; |
|---|
| 413 | + ecc[2] = ecc_tmp >> 16; |
|---|
| 414 | + ecc[3] = ecc_tmp >> 24; |
|---|
| 413 | 415 | |
|---|
| 414 | 416 | ecc_tmp = readl_relaxed(host->regs_va + ECC2); |
|---|
| 415 | | - ecc[4] = (uint8_t) (ecc_tmp >> 0); |
|---|
| 416 | | - ecc[5] = (uint8_t) (ecc_tmp >> 8); |
|---|
| 417 | | - ecc[6] = (uint8_t) (ecc_tmp >> 16); |
|---|
| 418 | | - ecc[7] = (uint8_t) (ecc_tmp >> 24); |
|---|
| 417 | + ecc[4] = ecc_tmp; |
|---|
| 418 | + ecc[5] = ecc_tmp >> 8; |
|---|
| 419 | + ecc[6] = ecc_tmp >> 16; |
|---|
| 420 | + ecc[7] = ecc_tmp >> 24; |
|---|
| 419 | 421 | |
|---|
| 420 | 422 | ecc_tmp = readl_relaxed(host->regs_va + ECC3); |
|---|
| 421 | | - ecc[8] = (uint8_t) (ecc_tmp >> 0); |
|---|
| 422 | | - ecc[9] = (uint8_t) (ecc_tmp >> 8); |
|---|
| 423 | | - ecc[10] = (uint8_t) (ecc_tmp >> 16); |
|---|
| 424 | | - ecc[11] = (uint8_t) (ecc_tmp >> 24); |
|---|
| 423 | + ecc[8] = ecc_tmp; |
|---|
| 424 | + ecc[9] = ecc_tmp >> 8; |
|---|
| 425 | + ecc[10] = ecc_tmp >> 16; |
|---|
| 426 | + ecc[11] = ecc_tmp >> 24; |
|---|
| 425 | 427 | |
|---|
| 426 | 428 | ecc_tmp = readl_relaxed(host->regs_va + STS); |
|---|
| 427 | | - ecc[12] = (uint8_t) (ecc_tmp >> 16); |
|---|
| 429 | + ecc[12] = ecc_tmp >> 16; |
|---|
| 428 | 430 | |
|---|
| 429 | 431 | return 0; |
|---|
| 430 | 432 | } |
|---|
| .. | .. |
|---|
| 434 | 436 | * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to |
|---|
| 435 | 437 | * max of 1-bit) |
|---|
| 436 | 438 | */ |
|---|
| 437 | | -static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, |
|---|
| 438 | | - uint8_t *ecc) |
|---|
| 439 | +static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const u8 *data, |
|---|
| 440 | + u8 *ecc) |
|---|
| 439 | 441 | { |
|---|
| 440 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 441 | | - uint32_t ecc_tmp; |
|---|
| 442 | + struct fsmc_nand_data *host = nand_to_fsmc(chip); |
|---|
| 443 | + u32 ecc_tmp; |
|---|
| 442 | 444 | |
|---|
| 443 | 445 | ecc_tmp = readl_relaxed(host->regs_va + ECC1); |
|---|
| 444 | | - ecc[0] = (uint8_t) (ecc_tmp >> 0); |
|---|
| 445 | | - ecc[1] = (uint8_t) (ecc_tmp >> 8); |
|---|
| 446 | | - ecc[2] = (uint8_t) (ecc_tmp >> 16); |
|---|
| 446 | + ecc[0] = ecc_tmp; |
|---|
| 447 | + ecc[1] = ecc_tmp >> 8; |
|---|
| 448 | + ecc[2] = ecc_tmp >> 16; |
|---|
| 447 | 449 | |
|---|
| 448 | 450 | return 0; |
|---|
| 449 | 451 | } |
|---|
| 450 | 452 | |
|---|
| 451 | 453 | /* Count the number of 0's in buff upto a max of max_bits */ |
|---|
| 452 | | -static int count_written_bits(uint8_t *buff, int size, int max_bits) |
|---|
| 454 | +static int count_written_bits(u8 *buff, int size, int max_bits) |
|---|
| 453 | 455 | { |
|---|
| 454 | 456 | int k, written_bits = 0; |
|---|
| 455 | 457 | |
|---|
| .. | .. |
|---|
| 470 | 472 | } |
|---|
| 471 | 473 | |
|---|
| 472 | 474 | static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, |
|---|
| 473 | | - enum dma_data_direction direction) |
|---|
| 475 | + enum dma_data_direction direction) |
|---|
| 474 | 476 | { |
|---|
| 475 | 477 | struct dma_chan *chan; |
|---|
| 476 | 478 | struct dma_device *dma_dev; |
|---|
| .. | .. |
|---|
| 521 | 523 | |
|---|
| 522 | 524 | time_left = |
|---|
| 523 | 525 | wait_for_completion_timeout(&host->dma_access_complete, |
|---|
| 524 | | - msecs_to_jiffies(3000)); |
|---|
| 526 | + msecs_to_jiffies(3000)); |
|---|
| 525 | 527 | if (time_left == 0) { |
|---|
| 526 | 528 | dmaengine_terminate_all(chan); |
|---|
| 527 | 529 | dev_err(host->dev, "wait_for_completion_timeout\n"); |
|---|
| .. | .. |
|---|
| 539 | 541 | |
|---|
| 540 | 542 | /* |
|---|
| 541 | 543 | * fsmc_write_buf - write buffer to chip |
|---|
| 542 | | - * @mtd: MTD device structure |
|---|
| 544 | + * @host: FSMC NAND controller |
|---|
| 543 | 545 | * @buf: data buffer |
|---|
| 544 | 546 | * @len: number of bytes to write |
|---|
| 545 | 547 | */ |
|---|
| 546 | | -static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
|---|
| 548 | +static void fsmc_write_buf(struct fsmc_nand_data *host, const u8 *buf, |
|---|
| 549 | + int len) |
|---|
| 547 | 550 | { |
|---|
| 548 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 549 | 551 | int i; |
|---|
| 550 | 552 | |
|---|
| 551 | | - if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) && |
|---|
| 552 | | - IS_ALIGNED(len, sizeof(uint32_t))) { |
|---|
| 553 | | - uint32_t *p = (uint32_t *)buf; |
|---|
| 553 | + if (IS_ALIGNED((uintptr_t)buf, sizeof(u32)) && |
|---|
| 554 | + IS_ALIGNED(len, sizeof(u32))) { |
|---|
| 555 | + u32 *p = (u32 *)buf; |
|---|
| 556 | + |
|---|
| 554 | 557 | len = len >> 2; |
|---|
| 555 | 558 | for (i = 0; i < len; i++) |
|---|
| 556 | 559 | writel_relaxed(p[i], host->data_va); |
|---|
| .. | .. |
|---|
| 562 | 565 | |
|---|
| 563 | 566 | /* |
|---|
| 564 | 567 | * fsmc_read_buf - read chip data into buffer |
|---|
| 565 | | - * @mtd: MTD device structure |
|---|
| 568 | + * @host: FSMC NAND controller |
|---|
| 566 | 569 | * @buf: buffer to store date |
|---|
| 567 | 570 | * @len: number of bytes to read |
|---|
| 568 | 571 | */ |
|---|
| 569 | | -static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
|---|
| 572 | +static void fsmc_read_buf(struct fsmc_nand_data *host, u8 *buf, int len) |
|---|
| 570 | 573 | { |
|---|
| 571 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 572 | 574 | int i; |
|---|
| 573 | 575 | |
|---|
| 574 | | - if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) && |
|---|
| 575 | | - IS_ALIGNED(len, sizeof(uint32_t))) { |
|---|
| 576 | | - uint32_t *p = (uint32_t *)buf; |
|---|
| 576 | + if (IS_ALIGNED((uintptr_t)buf, sizeof(u32)) && |
|---|
| 577 | + IS_ALIGNED(len, sizeof(u32))) { |
|---|
| 578 | + u32 *p = (u32 *)buf; |
|---|
| 579 | + |
|---|
| 577 | 580 | len = len >> 2; |
|---|
| 578 | 581 | for (i = 0; i < len; i++) |
|---|
| 579 | 582 | p[i] = readl_relaxed(host->data_va); |
|---|
| .. | .. |
|---|
| 585 | 588 | |
|---|
| 586 | 589 | /* |
|---|
| 587 | 590 | * fsmc_read_buf_dma - read chip data into buffer |
|---|
| 588 | | - * @mtd: MTD device structure |
|---|
| 591 | + * @host: FSMC NAND controller |
|---|
| 589 | 592 | * @buf: buffer to store date |
|---|
| 590 | 593 | * @len: number of bytes to read |
|---|
| 591 | 594 | */ |
|---|
| 592 | | -static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len) |
|---|
| 595 | +static void fsmc_read_buf_dma(struct fsmc_nand_data *host, u8 *buf, |
|---|
| 596 | + int len) |
|---|
| 593 | 597 | { |
|---|
| 594 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 595 | | - |
|---|
| 596 | 598 | dma_xfer(host, buf, len, DMA_FROM_DEVICE); |
|---|
| 597 | 599 | } |
|---|
| 598 | 600 | |
|---|
| 599 | 601 | /* |
|---|
| 600 | 602 | * fsmc_write_buf_dma - write buffer to chip |
|---|
| 601 | | - * @mtd: MTD device structure |
|---|
| 603 | + * @host: FSMC NAND controller |
|---|
| 602 | 604 | * @buf: data buffer |
|---|
| 603 | 605 | * @len: number of bytes to write |
|---|
| 604 | 606 | */ |
|---|
| 605 | | -static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, |
|---|
| 606 | | - int len) |
|---|
| 607 | +static void fsmc_write_buf_dma(struct fsmc_nand_data *host, const u8 *buf, |
|---|
| 608 | + int len) |
|---|
| 607 | 609 | { |
|---|
| 608 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 609 | | - |
|---|
| 610 | 610 | dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); |
|---|
| 611 | | -} |
|---|
| 612 | | - |
|---|
| 613 | | -/* fsmc_select_chip - assert or deassert nCE */ |
|---|
| 614 | | -static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) |
|---|
| 615 | | -{ |
|---|
| 616 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 617 | | - u32 pc; |
|---|
| 618 | | - |
|---|
| 619 | | - /* Support only one CS */ |
|---|
| 620 | | - if (chipnr > 0) |
|---|
| 621 | | - return; |
|---|
| 622 | | - |
|---|
| 623 | | - pc = readl(host->regs_va + FSMC_PC); |
|---|
| 624 | | - if (chipnr < 0) |
|---|
| 625 | | - writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC); |
|---|
| 626 | | - else |
|---|
| 627 | | - writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC); |
|---|
| 628 | | - |
|---|
| 629 | | - /* nCE line must be asserted before starting any operation */ |
|---|
| 630 | | - mb(); |
|---|
| 631 | 611 | } |
|---|
| 632 | 612 | |
|---|
| 633 | 613 | /* |
|---|
| .. | .. |
|---|
| 639 | 619 | static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, |
|---|
| 640 | 620 | bool check_only) |
|---|
| 641 | 621 | { |
|---|
| 642 | | - struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 643 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 622 | + struct fsmc_nand_data *host = nand_to_fsmc(chip); |
|---|
| 644 | 623 | const struct nand_op_instr *instr = NULL; |
|---|
| 645 | 624 | int ret = 0; |
|---|
| 646 | 625 | unsigned int op_id; |
|---|
| 647 | 626 | int i; |
|---|
| 648 | 627 | |
|---|
| 628 | + if (check_only) |
|---|
| 629 | + return 0; |
|---|
| 630 | + |
|---|
| 649 | 631 | pr_debug("Executing operation [%d instructions]:\n", op->ninstrs); |
|---|
| 632 | + |
|---|
| 650 | 633 | for (op_id = 0; op_id < op->ninstrs; op_id++) { |
|---|
| 651 | 634 | instr = &op->instrs[op_id]; |
|---|
| 652 | 635 | |
|---|
| 636 | + nand_op_trace(" ", instr); |
|---|
| 637 | + |
|---|
| 653 | 638 | switch (instr->type) { |
|---|
| 654 | 639 | case NAND_OP_CMD_INSTR: |
|---|
| 655 | | - pr_debug(" ->CMD [0x%02x]\n", |
|---|
| 656 | | - instr->ctx.cmd.opcode); |
|---|
| 657 | | - |
|---|
| 658 | 640 | writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va); |
|---|
| 659 | 641 | break; |
|---|
| 660 | 642 | |
|---|
| 661 | 643 | case NAND_OP_ADDR_INSTR: |
|---|
| 662 | | - pr_debug(" ->ADDR [%d cyc]", |
|---|
| 663 | | - instr->ctx.addr.naddrs); |
|---|
| 664 | | - |
|---|
| 665 | 644 | for (i = 0; i < instr->ctx.addr.naddrs; i++) |
|---|
| 666 | 645 | writeb_relaxed(instr->ctx.addr.addrs[i], |
|---|
| 667 | 646 | host->addr_va); |
|---|
| 668 | 647 | break; |
|---|
| 669 | 648 | |
|---|
| 670 | 649 | case NAND_OP_DATA_IN_INSTR: |
|---|
| 671 | | - pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len, |
|---|
| 672 | | - instr->ctx.data.force_8bit ? |
|---|
| 673 | | - ", force 8-bit" : ""); |
|---|
| 674 | | - |
|---|
| 675 | 650 | if (host->mode == USE_DMA_ACCESS) |
|---|
| 676 | | - fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in, |
|---|
| 651 | + fsmc_read_buf_dma(host, instr->ctx.data.buf.in, |
|---|
| 677 | 652 | instr->ctx.data.len); |
|---|
| 678 | 653 | else |
|---|
| 679 | | - fsmc_read_buf(mtd, instr->ctx.data.buf.in, |
|---|
| 654 | + fsmc_read_buf(host, instr->ctx.data.buf.in, |
|---|
| 680 | 655 | instr->ctx.data.len); |
|---|
| 681 | 656 | break; |
|---|
| 682 | 657 | |
|---|
| 683 | 658 | case NAND_OP_DATA_OUT_INSTR: |
|---|
| 684 | | - pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len, |
|---|
| 685 | | - instr->ctx.data.force_8bit ? |
|---|
| 686 | | - ", force 8-bit" : ""); |
|---|
| 687 | | - |
|---|
| 688 | 659 | if (host->mode == USE_DMA_ACCESS) |
|---|
| 689 | | - fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out, |
|---|
| 660 | + fsmc_write_buf_dma(host, |
|---|
| 661 | + instr->ctx.data.buf.out, |
|---|
| 690 | 662 | instr->ctx.data.len); |
|---|
| 691 | 663 | else |
|---|
| 692 | | - fsmc_write_buf(mtd, instr->ctx.data.buf.out, |
|---|
| 664 | + fsmc_write_buf(host, instr->ctx.data.buf.out, |
|---|
| 693 | 665 | instr->ctx.data.len); |
|---|
| 694 | 666 | break; |
|---|
| 695 | 667 | |
|---|
| 696 | 668 | case NAND_OP_WAITRDY_INSTR: |
|---|
| 697 | | - pr_debug(" ->WAITRDY [max %d ms]\n", |
|---|
| 698 | | - instr->ctx.waitrdy.timeout_ms); |
|---|
| 699 | | - |
|---|
| 700 | 669 | ret = nand_soft_waitrdy(chip, |
|---|
| 701 | 670 | instr->ctx.waitrdy.timeout_ms); |
|---|
| 702 | 671 | break; |
|---|
| .. | .. |
|---|
| 711 | 680 | |
|---|
| 712 | 681 | /* |
|---|
| 713 | 682 | * fsmc_read_page_hwecc |
|---|
| 714 | | - * @mtd: mtd info structure |
|---|
| 715 | 683 | * @chip: nand chip info structure |
|---|
| 716 | 684 | * @buf: buffer to store read data |
|---|
| 717 | 685 | * @oob_required: caller expects OOB data read to chip->oob_poi |
|---|
| .. | .. |
|---|
| 723 | 691 | * After this read, fsmc hardware generates and reports error data bits(up to a |
|---|
| 724 | 692 | * max of 8 bits) |
|---|
| 725 | 693 | */ |
|---|
| 726 | | -static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
|---|
| 727 | | - uint8_t *buf, int oob_required, int page) |
|---|
| 694 | +static int fsmc_read_page_hwecc(struct nand_chip *chip, u8 *buf, |
|---|
| 695 | + int oob_required, int page) |
|---|
| 728 | 696 | { |
|---|
| 697 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 729 | 698 | int i, j, s, stat, eccsize = chip->ecc.size; |
|---|
| 730 | 699 | int eccbytes = chip->ecc.bytes; |
|---|
| 731 | 700 | int eccsteps = chip->ecc.steps; |
|---|
| 732 | | - uint8_t *p = buf; |
|---|
| 733 | | - uint8_t *ecc_calc = chip->ecc.calc_buf; |
|---|
| 734 | | - uint8_t *ecc_code = chip->ecc.code_buf; |
|---|
| 735 | | - int off, len, group = 0; |
|---|
| 701 | + u8 *p = buf; |
|---|
| 702 | + u8 *ecc_calc = chip->ecc.calc_buf; |
|---|
| 703 | + u8 *ecc_code = chip->ecc.code_buf; |
|---|
| 704 | + int off, len, ret, group = 0; |
|---|
| 736 | 705 | /* |
|---|
| 737 | | - * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we |
|---|
| 706 | + * ecc_oob is intentionally taken as u16. In 16bit devices, we |
|---|
| 738 | 707 | * end up reading 14 bytes (7 words) from oob. The local array is |
|---|
| 739 | 708 | * to maintain word alignment |
|---|
| 740 | 709 | */ |
|---|
| 741 | | - uint16_t ecc_oob[7]; |
|---|
| 742 | | - uint8_t *oob = (uint8_t *)&ecc_oob[0]; |
|---|
| 710 | + u16 ecc_oob[7]; |
|---|
| 711 | + u8 *oob = (u8 *)&ecc_oob[0]; |
|---|
| 743 | 712 | unsigned int max_bitflips = 0; |
|---|
| 744 | 713 | |
|---|
| 745 | 714 | for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { |
|---|
| 746 | 715 | nand_read_page_op(chip, page, s * eccsize, NULL, 0); |
|---|
| 747 | | - chip->ecc.hwctl(mtd, NAND_ECC_READ); |
|---|
| 748 | | - nand_read_data_op(chip, p, eccsize, false); |
|---|
| 716 | + chip->ecc.hwctl(chip, NAND_ECC_READ); |
|---|
| 717 | + ret = nand_read_data_op(chip, p, eccsize, false, false); |
|---|
| 718 | + if (ret) |
|---|
| 719 | + return ret; |
|---|
| 749 | 720 | |
|---|
| 750 | 721 | for (j = 0; j < eccbytes;) { |
|---|
| 751 | 722 | struct mtd_oob_region oobregion; |
|---|
| 752 | | - int ret; |
|---|
| 753 | 723 | |
|---|
| 754 | 724 | ret = mtd_ooblayout_ecc(mtd, group++, &oobregion); |
|---|
| 755 | 725 | if (ret) |
|---|
| .. | .. |
|---|
| 771 | 741 | } |
|---|
| 772 | 742 | |
|---|
| 773 | 743 | memcpy(&ecc_code[i], oob, chip->ecc.bytes); |
|---|
| 774 | | - chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
|---|
| 744 | + chip->ecc.calculate(chip, p, &ecc_calc[i]); |
|---|
| 775 | 745 | |
|---|
| 776 | | - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); |
|---|
| 746 | + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); |
|---|
| 777 | 747 | if (stat < 0) { |
|---|
| 778 | 748 | mtd->ecc_stats.failed++; |
|---|
| 779 | 749 | } else { |
|---|
| .. | .. |
|---|
| 793 | 763 | * @calc_ecc: ecc calculated from read data |
|---|
| 794 | 764 | * |
|---|
| 795 | 765 | * calc_ecc is a 104 bit information containing maximum of 8 error |
|---|
| 796 | | - * offset informations of 13 bits each in 512 bytes of read data. |
|---|
| 766 | + * offset information of 13 bits each in 512 bytes of read data. |
|---|
| 797 | 767 | */ |
|---|
| 798 | | -static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, |
|---|
| 799 | | - uint8_t *read_ecc, uint8_t *calc_ecc) |
|---|
| 768 | +static int fsmc_bch8_correct_data(struct nand_chip *chip, u8 *dat, |
|---|
| 769 | + u8 *read_ecc, u8 *calc_ecc) |
|---|
| 800 | 770 | { |
|---|
| 801 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 802 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 803 | | - uint32_t err_idx[8]; |
|---|
| 804 | | - uint32_t num_err, i; |
|---|
| 805 | | - uint32_t ecc1, ecc2, ecc3, ecc4; |
|---|
| 771 | + struct fsmc_nand_data *host = nand_to_fsmc(chip); |
|---|
| 772 | + u32 err_idx[8]; |
|---|
| 773 | + u32 num_err, i; |
|---|
| 774 | + u32 ecc1, ecc2, ecc3, ecc4; |
|---|
| 806 | 775 | |
|---|
| 807 | 776 | num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF; |
|---|
| 808 | 777 | |
|---|
| .. | .. |
|---|
| 843 | 812 | * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--| |
|---|
| 844 | 813 | * |
|---|
| 845 | 814 | * calc_ecc is a 104 bit information containing maximum of 8 error |
|---|
| 846 | | - * offset informations of 13 bits each. calc_ecc is copied into a |
|---|
| 847 | | - * uint64_t array and error offset indexes are populated in err_idx |
|---|
| 815 | + * offset information of 13 bits each. calc_ecc is copied into a |
|---|
| 816 | + * u64 array and error offset indexes are populated in err_idx |
|---|
| 848 | 817 | * array |
|---|
| 849 | 818 | */ |
|---|
| 850 | 819 | ecc1 = readl_relaxed(host->regs_va + ECC1); |
|---|
| .. | .. |
|---|
| 863 | 832 | |
|---|
| 864 | 833 | i = 0; |
|---|
| 865 | 834 | while (num_err--) { |
|---|
| 866 | | - change_bit(0, (unsigned long *)&err_idx[i]); |
|---|
| 867 | | - change_bit(1, (unsigned long *)&err_idx[i]); |
|---|
| 835 | + err_idx[i] ^= 3; |
|---|
| 868 | 836 | |
|---|
| 869 | 837 | if (err_idx[i] < chip->ecc.size * 8) { |
|---|
| 870 | | - change_bit(err_idx[i], (unsigned long *)dat); |
|---|
| 838 | + int err = err_idx[i]; |
|---|
| 839 | + |
|---|
| 840 | + dat[err >> 3] ^= BIT(err & 7); |
|---|
| 871 | 841 | i++; |
|---|
| 872 | 842 | } |
|---|
| 873 | 843 | } |
|---|
| .. | .. |
|---|
| 903 | 873 | nand->options |= NAND_SKIP_BBTSCAN; |
|---|
| 904 | 874 | |
|---|
| 905 | 875 | host->dev_timings = devm_kzalloc(&pdev->dev, |
|---|
| 906 | | - sizeof(*host->dev_timings), GFP_KERNEL); |
|---|
| 876 | + sizeof(*host->dev_timings), |
|---|
| 877 | + GFP_KERNEL); |
|---|
| 907 | 878 | if (!host->dev_timings) |
|---|
| 908 | 879 | return -ENOMEM; |
|---|
| 880 | + |
|---|
| 909 | 881 | ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings, |
|---|
| 910 | | - sizeof(*host->dev_timings)); |
|---|
| 882 | + sizeof(*host->dev_timings)); |
|---|
| 911 | 883 | if (ret) |
|---|
| 912 | 884 | host->dev_timings = NULL; |
|---|
| 913 | 885 | |
|---|
| .. | .. |
|---|
| 926 | 898 | static int fsmc_nand_attach_chip(struct nand_chip *nand) |
|---|
| 927 | 899 | { |
|---|
| 928 | 900 | struct mtd_info *mtd = nand_to_mtd(nand); |
|---|
| 929 | | - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); |
|---|
| 901 | + struct fsmc_nand_data *host = nand_to_fsmc(nand); |
|---|
| 902 | + |
|---|
| 903 | + if (nand->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID) |
|---|
| 904 | + nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; |
|---|
| 905 | + |
|---|
| 906 | + if (!nand->ecc.size) |
|---|
| 907 | + nand->ecc.size = 512; |
|---|
| 908 | + |
|---|
| 909 | + if (AMBA_REV_BITS(host->pid) >= 8) { |
|---|
| 910 | + nand->ecc.read_page = fsmc_read_page_hwecc; |
|---|
| 911 | + nand->ecc.calculate = fsmc_read_hwecc_ecc4; |
|---|
| 912 | + nand->ecc.correct = fsmc_bch8_correct_data; |
|---|
| 913 | + nand->ecc.bytes = 13; |
|---|
| 914 | + nand->ecc.strength = 8; |
|---|
| 915 | + } |
|---|
| 930 | 916 | |
|---|
| 931 | 917 | if (AMBA_REV_BITS(host->pid) >= 8) { |
|---|
| 932 | 918 | switch (mtd->oobsize) { |
|---|
| .. | .. |
|---|
| 948 | 934 | return 0; |
|---|
| 949 | 935 | } |
|---|
| 950 | 936 | |
|---|
| 951 | | - switch (nand->ecc.mode) { |
|---|
| 952 | | - case NAND_ECC_HW: |
|---|
| 937 | + switch (nand->ecc.engine_type) { |
|---|
| 938 | + case NAND_ECC_ENGINE_TYPE_ON_HOST: |
|---|
| 953 | 939 | dev_info(host->dev, "Using 1-bit HW ECC scheme\n"); |
|---|
| 954 | 940 | nand->ecc.calculate = fsmc_read_hwecc_ecc1; |
|---|
| 955 | 941 | nand->ecc.correct = nand_correct_data; |
|---|
| 942 | + nand->ecc.hwctl = fsmc_enable_hwecc; |
|---|
| 956 | 943 | nand->ecc.bytes = 3; |
|---|
| 957 | 944 | nand->ecc.strength = 1; |
|---|
| 945 | + nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; |
|---|
| 958 | 946 | break; |
|---|
| 959 | 947 | |
|---|
| 960 | | - case NAND_ECC_SOFT: |
|---|
| 961 | | - if (nand->ecc.algo == NAND_ECC_BCH) { |
|---|
| 948 | + case NAND_ECC_ENGINE_TYPE_SOFT: |
|---|
| 949 | + if (nand->ecc.algo == NAND_ECC_ALGO_BCH) { |
|---|
| 962 | 950 | dev_info(host->dev, |
|---|
| 963 | 951 | "Using 4-bit SW BCH ECC scheme\n"); |
|---|
| 964 | 952 | break; |
|---|
| 965 | 953 | } |
|---|
| 966 | 954 | |
|---|
| 967 | | - case NAND_ECC_ON_DIE: |
|---|
| 955 | + case NAND_ECC_ENGINE_TYPE_ON_DIE: |
|---|
| 968 | 956 | break; |
|---|
| 969 | 957 | |
|---|
| 970 | 958 | default: |
|---|
| .. | .. |
|---|
| 976 | 964 | * Don't set layout for BCH4 SW ECC. This will be |
|---|
| 977 | 965 | * generated later in nand_bch_init() later. |
|---|
| 978 | 966 | */ |
|---|
| 979 | | - if (nand->ecc.mode == NAND_ECC_HW) { |
|---|
| 967 | + if (nand->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) { |
|---|
| 980 | 968 | switch (mtd->oobsize) { |
|---|
| 981 | 969 | case 16: |
|---|
| 982 | 970 | case 64: |
|---|
| .. | .. |
|---|
| 997 | 985 | |
|---|
| 998 | 986 | static const struct nand_controller_ops fsmc_nand_controller_ops = { |
|---|
| 999 | 987 | .attach_chip = fsmc_nand_attach_chip, |
|---|
| 988 | + .exec_op = fsmc_exec_op, |
|---|
| 989 | + .setup_interface = fsmc_setup_interface, |
|---|
| 1000 | 990 | }; |
|---|
| 991 | + |
|---|
| 992 | +/** |
|---|
| 993 | + * fsmc_nand_disable() - Disables the NAND bank |
|---|
| 994 | + * @host: The instance to disable |
|---|
| 995 | + */ |
|---|
| 996 | +static void fsmc_nand_disable(struct fsmc_nand_data *host) |
|---|
| 997 | +{ |
|---|
| 998 | + u32 val; |
|---|
| 999 | + |
|---|
| 1000 | + val = readl(host->regs_va + FSMC_PC); |
|---|
| 1001 | + val &= ~FSMC_ENABLE; |
|---|
| 1002 | + writel(val, host->regs_va + FSMC_PC); |
|---|
| 1003 | +} |
|---|
| 1001 | 1004 | |
|---|
| 1002 | 1005 | /* |
|---|
| 1003 | 1006 | * fsmc_nand_probe - Probe function |
|---|
| .. | .. |
|---|
| 1066 | 1069 | * AMBA PrimeCell bus. However it is not a PrimeCell. |
|---|
| 1067 | 1070 | */ |
|---|
| 1068 | 1071 | for (pid = 0, i = 0; i < 4; i++) |
|---|
| 1069 | | - pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); |
|---|
| 1072 | + pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & |
|---|
| 1073 | + 255) << (i * 8); |
|---|
| 1074 | + |
|---|
| 1070 | 1075 | host->pid = pid; |
|---|
| 1071 | | - dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, " |
|---|
| 1072 | | - "revision %02x, config %02x\n", |
|---|
| 1076 | + |
|---|
| 1077 | + dev_info(&pdev->dev, |
|---|
| 1078 | + "FSMC device partno %03x, manufacturer %02x, revision %02x, config %02x\n", |
|---|
| 1073 | 1079 | AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid), |
|---|
| 1074 | 1080 | AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); |
|---|
| 1075 | 1081 | |
|---|
| .. | .. |
|---|
| 1080 | 1086 | |
|---|
| 1081 | 1087 | /* Link all private pointers */ |
|---|
| 1082 | 1088 | mtd = nand_to_mtd(&host->nand); |
|---|
| 1083 | | - nand_set_controller_data(nand, host); |
|---|
| 1084 | 1089 | nand_set_flash_node(nand, pdev->dev.of_node); |
|---|
| 1085 | 1090 | |
|---|
| 1086 | 1091 | mtd->dev.parent = &pdev->dev; |
|---|
| 1087 | | - nand->exec_op = fsmc_exec_op; |
|---|
| 1088 | | - nand->select_chip = fsmc_select_chip; |
|---|
| 1089 | | - nand->chip_delay = 30; |
|---|
| 1090 | 1092 | |
|---|
| 1091 | | - /* |
|---|
| 1092 | | - * Setup default ECC mode. nand_dt_init() called from nand_scan_ident() |
|---|
| 1093 | | - * can overwrite this value if the DT provides a different value. |
|---|
| 1094 | | - */ |
|---|
| 1095 | | - nand->ecc.mode = NAND_ECC_HW; |
|---|
| 1096 | | - nand->ecc.hwctl = fsmc_enable_hwecc; |
|---|
| 1097 | | - nand->ecc.size = 512; |
|---|
| 1098 | 1093 | nand->badblockbits = 7; |
|---|
| 1099 | 1094 | |
|---|
| 1100 | 1095 | if (host->mode == USE_DMA_ACCESS) { |
|---|
| .. | .. |
|---|
| 1114 | 1109 | } |
|---|
| 1115 | 1110 | } |
|---|
| 1116 | 1111 | |
|---|
| 1117 | | - if (host->dev_timings) |
|---|
| 1112 | + if (host->dev_timings) { |
|---|
| 1118 | 1113 | fsmc_nand_setup(host, host->dev_timings); |
|---|
| 1119 | | - else |
|---|
| 1120 | | - nand->setup_data_interface = fsmc_setup_data_interface; |
|---|
| 1121 | | - |
|---|
| 1122 | | - if (AMBA_REV_BITS(host->pid) >= 8) { |
|---|
| 1123 | | - nand->ecc.read_page = fsmc_read_page_hwecc; |
|---|
| 1124 | | - nand->ecc.calculate = fsmc_read_hwecc_ecc4; |
|---|
| 1125 | | - nand->ecc.correct = fsmc_bch8_correct_data; |
|---|
| 1126 | | - nand->ecc.bytes = 13; |
|---|
| 1127 | | - nand->ecc.strength = 8; |
|---|
| 1114 | + nand->options |= NAND_KEEP_TIMINGS; |
|---|
| 1128 | 1115 | } |
|---|
| 1116 | + |
|---|
| 1117 | + nand_controller_init(&host->base); |
|---|
| 1118 | + host->base.ops = &fsmc_nand_controller_ops; |
|---|
| 1119 | + nand->controller = &host->base; |
|---|
| 1129 | 1120 | |
|---|
| 1130 | 1121 | /* |
|---|
| 1131 | 1122 | * Scan to find existence of the device |
|---|
| 1132 | 1123 | */ |
|---|
| 1133 | | - nand->dummy_controller.ops = &fsmc_nand_controller_ops; |
|---|
| 1134 | 1124 | ret = nand_scan(nand, 1); |
|---|
| 1135 | 1125 | if (ret) |
|---|
| 1136 | 1126 | goto release_dma_write_chan; |
|---|
| .. | .. |
|---|
| 1154 | 1144 | if (host->mode == USE_DMA_ACCESS) |
|---|
| 1155 | 1145 | dma_release_channel(host->read_dma_chan); |
|---|
| 1156 | 1146 | disable_clk: |
|---|
| 1147 | + fsmc_nand_disable(host); |
|---|
| 1157 | 1148 | clk_disable_unprepare(host->clk); |
|---|
| 1158 | 1149 | |
|---|
| 1159 | 1150 | return ret; |
|---|
| .. | .. |
|---|
| 1167 | 1158 | struct fsmc_nand_data *host = platform_get_drvdata(pdev); |
|---|
| 1168 | 1159 | |
|---|
| 1169 | 1160 | if (host) { |
|---|
| 1170 | | - nand_release(&host->nand); |
|---|
| 1161 | + struct nand_chip *chip = &host->nand; |
|---|
| 1162 | + int ret; |
|---|
| 1163 | + |
|---|
| 1164 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 1165 | + WARN_ON(ret); |
|---|
| 1166 | + nand_cleanup(chip); |
|---|
| 1167 | + fsmc_nand_disable(host); |
|---|
| 1171 | 1168 | |
|---|
| 1172 | 1169 | if (host->mode == USE_DMA_ACCESS) { |
|---|
| 1173 | 1170 | dma_release_channel(host->write_dma_chan); |
|---|
| .. | .. |
|---|
| 1183 | 1180 | static int fsmc_nand_suspend(struct device *dev) |
|---|
| 1184 | 1181 | { |
|---|
| 1185 | 1182 | struct fsmc_nand_data *host = dev_get_drvdata(dev); |
|---|
| 1183 | + |
|---|
| 1186 | 1184 | if (host) |
|---|
| 1187 | 1185 | clk_disable_unprepare(host->clk); |
|---|
| 1186 | + |
|---|
| 1188 | 1187 | return 0; |
|---|
| 1189 | 1188 | } |
|---|
| 1190 | 1189 | |
|---|
| 1191 | 1190 | static int fsmc_nand_resume(struct device *dev) |
|---|
| 1192 | 1191 | { |
|---|
| 1193 | 1192 | struct fsmc_nand_data *host = dev_get_drvdata(dev); |
|---|
| 1193 | + |
|---|
| 1194 | 1194 | if (host) { |
|---|
| 1195 | 1195 | clk_prepare_enable(host->clk); |
|---|
| 1196 | 1196 | if (host->dev_timings) |
|---|
| 1197 | 1197 | fsmc_nand_setup(host, host->dev_timings); |
|---|
| 1198 | + nand_reset(&host->nand, 0); |
|---|
| 1198 | 1199 | } |
|---|
| 1200 | + |
|---|
| 1199 | 1201 | return 0; |
|---|
| 1200 | 1202 | } |
|---|
| 1201 | 1203 | #endif |
|---|
| .. | .. |
|---|
| 1220 | 1222 | |
|---|
| 1221 | 1223 | module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe); |
|---|
| 1222 | 1224 | |
|---|
| 1223 | | -MODULE_LICENSE("GPL"); |
|---|
| 1225 | +MODULE_LICENSE("GPL v2"); |
|---|
| 1224 | 1226 | MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi"); |
|---|
| 1225 | 1227 | MODULE_DESCRIPTION("NAND driver for SPEAr Platforms"); |
|---|