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