1231 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright © 2004-2008 Simtec Electronics4 * http://armlinux.simtec.co.uk/5 * Ben Dooks <ben@simtec.co.uk>6 *7 * Samsung S3C2410/S3C2440/S3C2412 NAND driver8*/9 10#define pr_fmt(fmt) "nand-s3c2410: " fmt11 12#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG13#define DEBUG14#endif15 16#include <linux/module.h>17#include <linux/types.h>18#include <linux/kernel.h>19#include <linux/string.h>20#include <linux/io.h>21#include <linux/ioport.h>22#include <linux/platform_device.h>23#include <linux/delay.h>24#include <linux/err.h>25#include <linux/slab.h>26#include <linux/clk.h>27#include <linux/cpufreq.h>28#include <linux/of.h>29 30#include <linux/mtd/mtd.h>31#include <linux/mtd/rawnand.h>32#include <linux/mtd/partitions.h>33 34#include <linux/platform_data/mtd-nand-s3c2410.h>35 36#define S3C2410_NFREG(x) (x)37 38#define S3C2410_NFCONF S3C2410_NFREG(0x00)39#define S3C2410_NFCMD S3C2410_NFREG(0x04)40#define S3C2410_NFADDR S3C2410_NFREG(0x08)41#define S3C2410_NFDATA S3C2410_NFREG(0x0C)42#define S3C2410_NFSTAT S3C2410_NFREG(0x10)43#define S3C2410_NFECC S3C2410_NFREG(0x14)44#define S3C2440_NFCONT S3C2410_NFREG(0x04)45#define S3C2440_NFCMD S3C2410_NFREG(0x08)46#define S3C2440_NFADDR S3C2410_NFREG(0x0C)47#define S3C2440_NFDATA S3C2410_NFREG(0x10)48#define S3C2440_NFSTAT S3C2410_NFREG(0x20)49#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C)50#define S3C2412_NFSTAT S3C2410_NFREG(0x28)51#define S3C2412_NFMECC0 S3C2410_NFREG(0x34)52#define S3C2410_NFCONF_EN (1<<15)53#define S3C2410_NFCONF_INITECC (1<<12)54#define S3C2410_NFCONF_nFCE (1<<11)55#define S3C2410_NFCONF_TACLS(x) ((x)<<8)56#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)57#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)58#define S3C2410_NFSTAT_BUSY (1<<0)59#define S3C2440_NFCONF_TACLS(x) ((x)<<12)60#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)61#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)62#define S3C2440_NFCONT_INITECC (1<<4)63#define S3C2440_NFCONT_nFCE (1<<1)64#define S3C2440_NFCONT_ENABLE (1<<0)65#define S3C2440_NFSTAT_READY (1<<0)66#define S3C2412_NFCONF_NANDBOOT (1<<31)67#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5)68#define S3C2412_NFCONT_nFCE0 (1<<1)69#define S3C2412_NFSTAT_READY (1<<0)70 71/* new oob placement block for use with hardware ecc generation72 */73static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,74 struct mtd_oob_region *oobregion)75{76 if (section)77 return -ERANGE;78 79 oobregion->offset = 0;80 oobregion->length = 3;81 82 return 0;83}84 85static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,86 struct mtd_oob_region *oobregion)87{88 if (section)89 return -ERANGE;90 91 oobregion->offset = 8;92 oobregion->length = 8;93 94 return 0;95}96 97static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {98 .ecc = s3c2410_ooblayout_ecc,99 .free = s3c2410_ooblayout_free,100};101 102/* controller and mtd information */103 104struct s3c2410_nand_info;105 106/**107 * struct s3c2410_nand_mtd - driver MTD structure108 * @chip: The NAND chip information.109 * @set: The platform information supplied for this set of NAND chips.110 * @info: Link back to the hardware information.111*/112struct s3c2410_nand_mtd {113 struct nand_chip chip;114 struct s3c2410_nand_set *set;115 struct s3c2410_nand_info *info;116};117 118enum s3c_cpu_type {119 TYPE_S3C2410,120 TYPE_S3C2412,121 TYPE_S3C2440,122};123 124enum s3c_nand_clk_state {125 CLOCK_DISABLE = 0,126 CLOCK_ENABLE,127 CLOCK_SUSPEND,128};129 130/* overview of the s3c2410 nand state */131 132/**133 * struct s3c2410_nand_info - NAND controller state.134 * @controller: Base controller structure.135 * @mtds: An array of MTD instances on this controller.136 * @platform: The platform data for this board.137 * @device: The platform device we bound to.138 * @clk: The clock resource for this controller.139 * @regs: The area mapped for the hardware registers.140 * @sel_reg: Pointer to the register controlling the NAND selection.141 * @sel_bit: The bit in @sel_reg to select the NAND chip.142 * @mtd_count: The number of MTDs created from this controller.143 * @save_sel: The contents of @sel_reg to be saved over suspend.144 * @clk_rate: The clock rate from @clk.145 * @clk_state: The current clock state.146 * @cpu_type: The exact type of this controller.147 */148struct s3c2410_nand_info {149 /* mtd info */150 struct nand_controller controller;151 struct s3c2410_nand_mtd *mtds;152 struct s3c2410_platform_nand *platform;153 154 /* device info */155 struct device *device;156 struct clk *clk;157 void __iomem *regs;158 void __iomem *sel_reg;159 int sel_bit;160 int mtd_count;161 unsigned long save_sel;162 unsigned long clk_rate;163 enum s3c_nand_clk_state clk_state;164 165 enum s3c_cpu_type cpu_type;166};167 168struct s3c24XX_nand_devtype_data {169 enum s3c_cpu_type type;170};171 172static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {173 .type = TYPE_S3C2410,174};175 176static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {177 .type = TYPE_S3C2412,178};179 180static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {181 .type = TYPE_S3C2440,182};183 184/* conversion functions */185 186static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)187{188 return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,189 chip);190}191 192static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)193{194 return s3c2410_nand_mtd_toours(mtd)->info;195}196 197static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)198{199 return platform_get_drvdata(dev);200}201 202static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)203{204 return dev_get_platdata(&dev->dev);205}206 207static inline int allow_clk_suspend(struct s3c2410_nand_info *info)208{209#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP210 return 1;211#else212 return 0;213#endif214}215 216/**217 * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.218 * @info: The controller instance.219 * @new_state: State to which clock should be set.220 */221static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,222 enum s3c_nand_clk_state new_state)223{224 if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)225 return;226 227 if (info->clk_state == CLOCK_ENABLE) {228 if (new_state != CLOCK_ENABLE)229 clk_disable_unprepare(info->clk);230 } else {231 if (new_state == CLOCK_ENABLE)232 clk_prepare_enable(info->clk);233 }234 235 info->clk_state = new_state;236}237 238/* timing calculations */239 240#define NS_IN_KHZ 1000000241 242/**243 * s3c_nand_calc_rate - calculate timing data.244 * @wanted: The cycle time in nanoseconds.245 * @clk: The clock rate in kHz.246 * @max: The maximum divider value.247 *248 * Calculate the timing value from the given parameters.249 */250static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)251{252 int result;253 254 result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);255 256 pr_debug("result %d from %ld, %d\n", result, clk, wanted);257 258 if (result > max) {259 pr_err("%d ns is too big for current clock rate %ld\n",260 wanted, clk);261 return -1;262 }263 264 if (result < 1)265 result = 1;266 267 return result;268}269 270#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))271 272/* controller setup */273 274/**275 * s3c2410_nand_setrate - setup controller timing information.276 * @info: The controller instance.277 *278 * Given the information supplied by the platform, calculate and set279 * the necessary timing registers in the hardware to generate the280 * necessary timing cycles to the hardware.281 */282static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)283{284 struct s3c2410_platform_nand *plat = info->platform;285 int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;286 int tacls, twrph0, twrph1;287 unsigned long clkrate = clk_get_rate(info->clk);288 unsigned long set, cfg, mask;289 unsigned long flags;290 291 /* calculate the timing information for the controller */292 293 info->clk_rate = clkrate;294 clkrate /= 1000; /* turn clock into kHz for ease of use */295 296 if (plat != NULL) {297 tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);298 twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);299 twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);300 } else {301 /* default timings */302 tacls = tacls_max;303 twrph0 = 8;304 twrph1 = 8;305 }306 307 if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {308 dev_err(info->device, "cannot get suitable timings\n");309 return -EINVAL;310 }311 312 dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",313 tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),314 twrph1, to_ns(twrph1, clkrate));315 316 switch (info->cpu_type) {317 case TYPE_S3C2410:318 mask = (S3C2410_NFCONF_TACLS(3) |319 S3C2410_NFCONF_TWRPH0(7) |320 S3C2410_NFCONF_TWRPH1(7));321 set = S3C2410_NFCONF_EN;322 set |= S3C2410_NFCONF_TACLS(tacls - 1);323 set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);324 set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);325 break;326 327 case TYPE_S3C2440:328 case TYPE_S3C2412:329 mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |330 S3C2440_NFCONF_TWRPH0(7) |331 S3C2440_NFCONF_TWRPH1(7));332 333 set = S3C2440_NFCONF_TACLS(tacls - 1);334 set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);335 set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);336 break;337 338 default:339 BUG();340 }341 342 local_irq_save(flags);343 344 cfg = readl(info->regs + S3C2410_NFCONF);345 cfg &= ~mask;346 cfg |= set;347 writel(cfg, info->regs + S3C2410_NFCONF);348 349 local_irq_restore(flags);350 351 dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);352 353 return 0;354}355 356/**357 * s3c2410_nand_inithw - basic hardware initialisation358 * @info: The hardware state.359 *360 * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()361 * to setup the hardware access speeds and set the controller to be enabled.362*/363static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)364{365 int ret;366 367 ret = s3c2410_nand_setrate(info);368 if (ret < 0)369 return ret;370 371 switch (info->cpu_type) {372 case TYPE_S3C2410:373 default:374 break;375 376 case TYPE_S3C2440:377 case TYPE_S3C2412:378 /* enable the controller and de-assert nFCE */379 380 writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);381 }382 383 return 0;384}385 386/**387 * s3c2410_nand_select_chip - select the given nand chip388 * @this: NAND chip object.389 * @chip: The chip number.390 *391 * This is called by the MTD layer to either select a given chip for the392 * @mtd instance, or to indicate that the access has finished and the393 * chip can be de-selected.394 *395 * The routine ensures that the nFCE line is correctly setup, and any396 * platform specific selection code is called to route nFCE to the specific397 * chip.398 */399static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)400{401 struct s3c2410_nand_info *info;402 struct s3c2410_nand_mtd *nmtd;403 unsigned long cur;404 405 nmtd = nand_get_controller_data(this);406 info = nmtd->info;407 408 if (chip != -1)409 s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);410 411 cur = readl(info->sel_reg);412 413 if (chip == -1) {414 cur |= info->sel_bit;415 } else {416 if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {417 dev_err(info->device, "invalid chip %d\n", chip);418 return;419 }420 421 if (info->platform != NULL) {422 if (info->platform->select_chip != NULL)423 (info->platform->select_chip) (nmtd->set, chip);424 }425 426 cur &= ~info->sel_bit;427 }428 429 writel(cur, info->sel_reg);430 431 if (chip == -1)432 s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);433}434 435/* s3c2410_nand_hwcontrol436 *437 * Issue command and address cycles to the chip438*/439 440static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,441 unsigned int ctrl)442{443 struct mtd_info *mtd = nand_to_mtd(chip);444 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);445 446 if (cmd == NAND_CMD_NONE)447 return;448 449 if (ctrl & NAND_CLE)450 writeb(cmd, info->regs + S3C2410_NFCMD);451 else452 writeb(cmd, info->regs + S3C2410_NFADDR);453}454 455/* command and control functions */456 457static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,458 unsigned int ctrl)459{460 struct mtd_info *mtd = nand_to_mtd(chip);461 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);462 463 if (cmd == NAND_CMD_NONE)464 return;465 466 if (ctrl & NAND_CLE)467 writeb(cmd, info->regs + S3C2440_NFCMD);468 else469 writeb(cmd, info->regs + S3C2440_NFADDR);470}471 472/* s3c2410_nand_devready()473 *474 * returns 0 if the nand is busy, 1 if it is ready475*/476 477static int s3c2410_nand_devready(struct nand_chip *chip)478{479 struct mtd_info *mtd = nand_to_mtd(chip);480 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);481 return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;482}483 484static int s3c2440_nand_devready(struct nand_chip *chip)485{486 struct mtd_info *mtd = nand_to_mtd(chip);487 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);488 return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;489}490 491static int s3c2412_nand_devready(struct nand_chip *chip)492{493 struct mtd_info *mtd = nand_to_mtd(chip);494 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);495 return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;496}497 498/* ECC handling functions */499 500static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,501 u_char *read_ecc, u_char *calc_ecc)502{503 struct mtd_info *mtd = nand_to_mtd(chip);504 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);505 unsigned int diff0, diff1, diff2;506 unsigned int bit, byte;507 508 pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);509 510 diff0 = read_ecc[0] ^ calc_ecc[0];511 diff1 = read_ecc[1] ^ calc_ecc[1];512 diff2 = read_ecc[2] ^ calc_ecc[2];513 514 pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",515 __func__, 3, read_ecc, 3, calc_ecc,516 diff0, diff1, diff2);517 518 if (diff0 == 0 && diff1 == 0 && diff2 == 0)519 return 0; /* ECC is ok */520 521 /* sometimes people do not think about using the ECC, so check522 * to see if we have an 0xff,0xff,0xff read ECC and then ignore523 * the error, on the assumption that this is an un-eccd page.524 */525 if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff526 && info->platform->ignore_unset_ecc)527 return 0;528 529 /* Can we correct this ECC (ie, one row and column change).530 * Note, this is similar to the 256 error code on smartmedia */531 532 if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&533 ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&534 ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {535 /* calculate the bit position of the error */536 537 bit = ((diff2 >> 3) & 1) |538 ((diff2 >> 4) & 2) |539 ((diff2 >> 5) & 4);540 541 /* calculate the byte position of the error */542 543 byte = ((diff2 << 7) & 0x100) |544 ((diff1 << 0) & 0x80) |545 ((diff1 << 1) & 0x40) |546 ((diff1 << 2) & 0x20) |547 ((diff1 << 3) & 0x10) |548 ((diff0 >> 4) & 0x08) |549 ((diff0 >> 3) & 0x04) |550 ((diff0 >> 2) & 0x02) |551 ((diff0 >> 1) & 0x01);552 553 dev_dbg(info->device, "correcting error bit %d, byte %d\n",554 bit, byte);555 556 dat[byte] ^= (1 << bit);557 return 1;558 }559 560 /* if there is only one bit difference in the ECC, then561 * one of only a row or column parity has changed, which562 * means the error is most probably in the ECC itself */563 564 diff0 |= (diff1 << 8);565 diff0 |= (diff2 << 16);566 567 /* equal to "(diff0 & ~(1 << __ffs(diff0)))" */568 if ((diff0 & (diff0 - 1)) == 0)569 return 1;570 571 return -1;572}573 574/* ECC functions575 *576 * These allow the s3c2410 and s3c2440 to use the controller's ECC577 * generator block to ECC the data as it passes through]578*/579 580static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)581{582 struct s3c2410_nand_info *info;583 unsigned long ctrl;584 585 info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));586 ctrl = readl(info->regs + S3C2410_NFCONF);587 ctrl |= S3C2410_NFCONF_INITECC;588 writel(ctrl, info->regs + S3C2410_NFCONF);589}590 591static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)592{593 struct s3c2410_nand_info *info;594 unsigned long ctrl;595 596 info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));597 ctrl = readl(info->regs + S3C2440_NFCONT);598 writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,599 info->regs + S3C2440_NFCONT);600}601 602static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)603{604 struct s3c2410_nand_info *info;605 unsigned long ctrl;606 607 info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));608 ctrl = readl(info->regs + S3C2440_NFCONT);609 writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);610}611 612static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,613 const u_char *dat, u_char *ecc_code)614{615 struct mtd_info *mtd = nand_to_mtd(chip);616 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);617 618 ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);619 ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);620 ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);621 622 pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);623 624 return 0;625}626 627static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,628 const u_char *dat, u_char *ecc_code)629{630 struct mtd_info *mtd = nand_to_mtd(chip);631 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);632 unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);633 634 ecc_code[0] = ecc;635 ecc_code[1] = ecc >> 8;636 ecc_code[2] = ecc >> 16;637 638 pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);639 640 return 0;641}642 643static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,644 const u_char *dat, u_char *ecc_code)645{646 struct mtd_info *mtd = nand_to_mtd(chip);647 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);648 unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);649 650 ecc_code[0] = ecc;651 ecc_code[1] = ecc >> 8;652 ecc_code[2] = ecc >> 16;653 654 pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);655 656 return 0;657}658 659/* over-ride the standard functions for a little more speed. We can660 * use read/write block to move the data buffers to/from the controller661*/662 663static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)664{665 readsb(this->legacy.IO_ADDR_R, buf, len);666}667 668static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)669{670 struct mtd_info *mtd = nand_to_mtd(this);671 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);672 673 readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);674 675 /* cleanup if we've got less than a word to do */676 if (len & 3) {677 buf += len & ~3;678 679 for (; len & 3; len--)680 *buf++ = readb(info->regs + S3C2440_NFDATA);681 }682}683 684static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,685 int len)686{687 writesb(this->legacy.IO_ADDR_W, buf, len);688}689 690static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,691 int len)692{693 struct mtd_info *mtd = nand_to_mtd(this);694 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);695 696 writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);697 698 /* cleanup any fractional write */699 if (len & 3) {700 buf += len & ~3;701 702 for (; len & 3; len--, buf++)703 writeb(*buf, info->regs + S3C2440_NFDATA);704 }705}706 707/* device management functions */708 709static void s3c24xx_nand_remove(struct platform_device *pdev)710{711 struct s3c2410_nand_info *info = to_nand_info(pdev);712 713 if (info == NULL)714 return;715 716 /* Release all our mtds and their partitions, then go through717 * freeing the resources used718 */719 720 if (info->mtds != NULL) {721 struct s3c2410_nand_mtd *ptr = info->mtds;722 int mtdno;723 724 for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {725 pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);726 WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip)));727 nand_cleanup(&ptr->chip);728 }729 }730 731 /* free the common resources */732 733 if (!IS_ERR(info->clk))734 s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);735}736 737static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,738 struct s3c2410_nand_mtd *mtd,739 struct s3c2410_nand_set *set)740{741 if (set) {742 struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);743 744 mtdinfo->name = set->name;745 746 return mtd_device_register(mtdinfo, set->partitions,747 set->nr_partitions);748 }749 750 return -ENODEV;751}752 753static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,754 const struct nand_interface_config *conf)755{756 struct mtd_info *mtd = nand_to_mtd(chip);757 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);758 struct s3c2410_platform_nand *pdata = info->platform;759 const struct nand_sdr_timings *timings;760 int tacls;761 762 timings = nand_get_sdr_timings(conf);763 if (IS_ERR(timings))764 return -ENOTSUPP;765 766 tacls = timings->tCLS_min - timings->tWP_min;767 if (tacls < 0)768 tacls = 0;769 770 pdata->tacls = DIV_ROUND_UP(tacls, 1000);771 pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);772 pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);773 774 return s3c2410_nand_setrate(info);775}776 777/**778 * s3c2410_nand_init_chip - initialise a single instance of an chip779 * @info: The base NAND controller the chip is on.780 * @nmtd: The new controller MTD instance to fill in.781 * @set: The information passed from the board specific platform data.782 *783 * Initialise the given @nmtd from the information in @info and @set. This784 * readies the structure for use with the MTD layer functions by ensuring785 * all pointers are setup and the necessary control routines selected.786 */787static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,788 struct s3c2410_nand_mtd *nmtd,789 struct s3c2410_nand_set *set)790{791 struct device_node *np = info->device->of_node;792 struct nand_chip *chip = &nmtd->chip;793 void __iomem *regs = info->regs;794 795 nand_set_flash_node(chip, set->of_node);796 797 chip->legacy.write_buf = s3c2410_nand_write_buf;798 chip->legacy.read_buf = s3c2410_nand_read_buf;799 chip->legacy.select_chip = s3c2410_nand_select_chip;800 chip->legacy.chip_delay = 50;801 nand_set_controller_data(chip, nmtd);802 chip->options = set->options;803 chip->controller = &info->controller;804 805 /*806 * let's keep behavior unchanged for legacy boards booting via pdata and807 * auto-detect timings only when booting with a device tree.808 */809 if (!np)810 chip->options |= NAND_KEEP_TIMINGS;811 812 switch (info->cpu_type) {813 case TYPE_S3C2410:814 chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;815 info->sel_reg = regs + S3C2410_NFCONF;816 info->sel_bit = S3C2410_NFCONF_nFCE;817 chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol;818 chip->legacy.dev_ready = s3c2410_nand_devready;819 break;820 821 case TYPE_S3C2440:822 chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;823 info->sel_reg = regs + S3C2440_NFCONT;824 info->sel_bit = S3C2440_NFCONT_nFCE;825 chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;826 chip->legacy.dev_ready = s3c2440_nand_devready;827 chip->legacy.read_buf = s3c2440_nand_read_buf;828 chip->legacy.write_buf = s3c2440_nand_write_buf;829 break;830 831 case TYPE_S3C2412:832 chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;833 info->sel_reg = regs + S3C2440_NFCONT;834 info->sel_bit = S3C2412_NFCONT_nFCE0;835 chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;836 chip->legacy.dev_ready = s3c2412_nand_devready;837 838 if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)839 dev_info(info->device, "System booted from NAND\n");840 841 break;842 }843 844 chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;845 846 nmtd->info = info;847 nmtd->set = set;848 849 chip->ecc.engine_type = info->platform->engine_type;850 851 /*852 * If you use u-boot BBT creation code, specifying this flag will853 * let the kernel fish out the BBT from the NAND.854 */855 if (set->flash_bbt)856 chip->bbt_options |= NAND_BBT_USE_FLASH;857}858 859/**860 * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan861 * @chip: The NAND chip862 *863 * This hook is called by the core after the identification of the NAND chip,864 * once the relevant per-chip information is up to date.. This call ensure that865 * we update the internal state accordingly.866 *867 * The internal state is currently limited to the ECC state information.868*/869static int s3c2410_nand_attach_chip(struct nand_chip *chip)870{871 struct mtd_info *mtd = nand_to_mtd(chip);872 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);873 874 switch (chip->ecc.engine_type) {875 876 case NAND_ECC_ENGINE_TYPE_NONE:877 dev_info(info->device, "ECC disabled\n");878 break;879 880 case NAND_ECC_ENGINE_TYPE_SOFT:881 /*882 * This driver expects Hamming based ECC when engine_type is set883 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to884 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field885 * to s3c2410_platform_nand.886 */887 chip->ecc.algo = NAND_ECC_ALGO_HAMMING;888 dev_info(info->device, "soft ECC\n");889 break;890 891 case NAND_ECC_ENGINE_TYPE_ON_HOST:892 chip->ecc.calculate = s3c2410_nand_calculate_ecc;893 chip->ecc.correct = s3c2410_nand_correct_data;894 chip->ecc.strength = 1;895 896 switch (info->cpu_type) {897 case TYPE_S3C2410:898 chip->ecc.hwctl = s3c2410_nand_enable_hwecc;899 chip->ecc.calculate = s3c2410_nand_calculate_ecc;900 break;901 902 case TYPE_S3C2412:903 chip->ecc.hwctl = s3c2412_nand_enable_hwecc;904 chip->ecc.calculate = s3c2412_nand_calculate_ecc;905 break;906 907 case TYPE_S3C2440:908 chip->ecc.hwctl = s3c2440_nand_enable_hwecc;909 chip->ecc.calculate = s3c2440_nand_calculate_ecc;910 break;911 }912 913 dev_dbg(info->device, "chip %p => page shift %d\n",914 chip, chip->page_shift);915 916 /* change the behaviour depending on whether we are using917 * the large or small page nand device */918 if (chip->page_shift > 10) {919 chip->ecc.size = 256;920 chip->ecc.bytes = 3;921 } else {922 chip->ecc.size = 512;923 chip->ecc.bytes = 3;924 mtd_set_ooblayout(nand_to_mtd(chip),925 &s3c2410_ooblayout_ops);926 }927 928 dev_info(info->device, "hardware ECC\n");929 break;930 931 default:932 dev_err(info->device, "invalid ECC mode!\n");933 return -EINVAL;934 }935 936 if (chip->bbt_options & NAND_BBT_USE_FLASH)937 chip->options |= NAND_SKIP_BBTSCAN;938 939 return 0;940}941 942static const struct nand_controller_ops s3c24xx_nand_controller_ops = {943 .attach_chip = s3c2410_nand_attach_chip,944 .setup_interface = s3c2410_nand_setup_interface,945};946 947static const struct of_device_id s3c24xx_nand_dt_ids[] = {948 {949 .compatible = "samsung,s3c2410-nand",950 .data = &s3c2410_nand_devtype_data,951 }, {952 /* also compatible with s3c6400 */953 .compatible = "samsung,s3c2412-nand",954 .data = &s3c2412_nand_devtype_data,955 }, {956 .compatible = "samsung,s3c2440-nand",957 .data = &s3c2440_nand_devtype_data,958 },959 { /* sentinel */ }960};961MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);962 963static int s3c24xx_nand_probe_dt(struct platform_device *pdev)964{965 const struct s3c24XX_nand_devtype_data *devtype_data;966 struct s3c2410_platform_nand *pdata;967 struct s3c2410_nand_info *info = platform_get_drvdata(pdev);968 struct device_node *np = pdev->dev.of_node, *child;969 struct s3c2410_nand_set *sets;970 971 devtype_data = of_device_get_match_data(&pdev->dev);972 if (!devtype_data)973 return -ENODEV;974 975 info->cpu_type = devtype_data->type;976 977 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);978 if (!pdata)979 return -ENOMEM;980 981 pdev->dev.platform_data = pdata;982 983 pdata->nr_sets = of_get_child_count(np);984 if (!pdata->nr_sets)985 return 0;986 987 sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets),988 GFP_KERNEL);989 if (!sets)990 return -ENOMEM;991 992 pdata->sets = sets;993 994 for_each_available_child_of_node(np, child) {995 sets->name = (char *)child->name;996 sets->of_node = child;997 sets->nr_chips = 1;998 999 of_node_get(child);1000 1001 sets++;1002 }1003 1004 return 0;1005}1006 1007static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)1008{1009 struct s3c2410_nand_info *info = platform_get_drvdata(pdev);1010 1011 info->cpu_type = platform_get_device_id(pdev)->driver_data;1012 1013 return 0;1014}1015 1016/* s3c24xx_nand_probe1017 *1018 * called by device layer when it finds a device matching1019 * one our driver can handled. This code checks to see if1020 * it can allocate all necessary resources then calls the1021 * nand layer to look for devices1022*/1023static int s3c24xx_nand_probe(struct platform_device *pdev)1024{1025 struct s3c2410_platform_nand *plat;1026 struct s3c2410_nand_info *info;1027 struct s3c2410_nand_mtd *nmtd;1028 struct s3c2410_nand_set *sets;1029 struct resource *res;1030 int err = 0;1031 int size;1032 int nr_sets;1033 int setno;1034 1035 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);1036 if (info == NULL) {1037 err = -ENOMEM;1038 goto exit_error;1039 }1040 1041 platform_set_drvdata(pdev, info);1042 1043 nand_controller_init(&info->controller);1044 info->controller.ops = &s3c24xx_nand_controller_ops;1045 1046 /* get the clock source and enable it */1047 1048 info->clk = devm_clk_get(&pdev->dev, "nand");1049 if (IS_ERR(info->clk)) {1050 dev_err(&pdev->dev, "failed to get clock\n");1051 err = -ENOENT;1052 goto exit_error;1053 }1054 1055 s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);1056 1057 if (pdev->dev.of_node)1058 err = s3c24xx_nand_probe_dt(pdev);1059 else1060 err = s3c24xx_nand_probe_pdata(pdev);1061 1062 if (err)1063 goto exit_error;1064 1065 plat = to_nand_plat(pdev);1066 1067 /* allocate and map the resource */1068 1069 /* currently we assume we have the one resource */1070 res = pdev->resource;1071 size = resource_size(res);1072 1073 info->device = &pdev->dev;1074 info->platform = plat;1075 1076 info->regs = devm_ioremap_resource(&pdev->dev, res);1077 if (IS_ERR(info->regs)) {1078 err = PTR_ERR(info->regs);1079 goto exit_error;1080 }1081 1082 dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);1083 1084 if (!plat->sets || plat->nr_sets < 1) {1085 err = -EINVAL;1086 goto exit_error;1087 }1088 1089 sets = plat->sets;1090 nr_sets = plat->nr_sets;1091 1092 info->mtd_count = nr_sets;1093 1094 /* allocate our information */1095 1096 size = nr_sets * sizeof(*info->mtds);1097 info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);1098 if (info->mtds == NULL) {1099 err = -ENOMEM;1100 goto exit_error;1101 }1102 1103 /* initialise all possible chips */1104 1105 nmtd = info->mtds;1106 1107 for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) {1108 struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);1109 1110 pr_debug("initialising set %d (%p, info %p)\n",1111 setno, nmtd, info);1112 1113 mtd->dev.parent = &pdev->dev;1114 s3c2410_nand_init_chip(info, nmtd, sets);1115 1116 err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);1117 if (err)1118 goto exit_error;1119 1120 s3c2410_nand_add_partition(info, nmtd, sets);1121 }1122 1123 /* initialise the hardware */1124 err = s3c2410_nand_inithw(info);1125 if (err != 0)1126 goto exit_error;1127 1128 if (allow_clk_suspend(info)) {1129 dev_info(&pdev->dev, "clock idle support enabled\n");1130 s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);1131 }1132 1133 return 0;1134 1135 exit_error:1136 s3c24xx_nand_remove(pdev);1137 1138 if (err == 0)1139 err = -EINVAL;1140 return err;1141}1142 1143/* PM Support */1144#ifdef CONFIG_PM1145 1146static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)1147{1148 struct s3c2410_nand_info *info = platform_get_drvdata(dev);1149 1150 if (info) {1151 info->save_sel = readl(info->sel_reg);1152 1153 /* For the moment, we must ensure nFCE is high during1154 * the time we are suspended. This really should be1155 * handled by suspending the MTDs we are using, but1156 * that is currently not the case. */1157 1158 writel(info->save_sel | info->sel_bit, info->sel_reg);1159 1160 s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);1161 }1162 1163 return 0;1164}1165 1166static int s3c24xx_nand_resume(struct platform_device *dev)1167{1168 struct s3c2410_nand_info *info = platform_get_drvdata(dev);1169 unsigned long sel;1170 1171 if (info) {1172 s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);1173 s3c2410_nand_inithw(info);1174 1175 /* Restore the state of the nFCE line. */1176 1177 sel = readl(info->sel_reg);1178 sel &= ~info->sel_bit;1179 sel |= info->save_sel & info->sel_bit;1180 writel(sel, info->sel_reg);1181 1182 s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);1183 }1184 1185 return 0;1186}1187 1188#else1189#define s3c24xx_nand_suspend NULL1190#define s3c24xx_nand_resume NULL1191#endif1192 1193/* driver device registration */1194 1195static const struct platform_device_id s3c24xx_driver_ids[] = {1196 {1197 .name = "s3c2410-nand",1198 .driver_data = TYPE_S3C2410,1199 }, {1200 .name = "s3c2440-nand",1201 .driver_data = TYPE_S3C2440,1202 }, {1203 .name = "s3c2412-nand",1204 .driver_data = TYPE_S3C2412,1205 }, {1206 .name = "s3c6400-nand",1207 .driver_data = TYPE_S3C2412, /* compatible with 2412 */1208 },1209 { }1210};1211 1212MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);1213 1214static struct platform_driver s3c24xx_nand_driver = {1215 .probe = s3c24xx_nand_probe,1216 .remove_new = s3c24xx_nand_remove,1217 .suspend = s3c24xx_nand_suspend,1218 .resume = s3c24xx_nand_resume,1219 .id_table = s3c24xx_driver_ids,1220 .driver = {1221 .name = "s3c24xx-nand",1222 .of_match_table = s3c24xx_nand_dt_ids,1223 },1224};1225 1226module_platform_driver(s3c24xx_nand_driver);1227 1228MODULE_LICENSE("GPL");1229MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");1230MODULE_DESCRIPTION("S3C24XX MTD NAND driver");1231