root/drivers/mtd/nand/raw/cs553x_nand.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cs553x_read_buf
  2. cs553x_write_buf
  3. cs553x_read_byte
  4. cs553x_write_byte
  5. cs553x_hwcontrol
  6. cs553x_device_ready
  7. cs_enable_hwecc
  8. cs_calculate_ecc
  9. cs553x_init_one
  10. is_geode
  11. cs553x_init
  12. cs553x_cleanup

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * (C) 2005, 2006 Red Hat Inc.
   4  *
   5  * Author: David Woodhouse <dwmw2@infradead.org>
   6  *         Tom Sylla <tom.sylla@amd.com>
   7  *
   8  *  Overview:
   9  *   This is a device driver for the NAND flash controller found on
  10  *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
  11  *   mtd-id for command line partitioning is cs553x_nand_cs[0-3]
  12  *   where 0-3 reflects the chip select for NAND.
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/slab.h>
  17 #include <linux/init.h>
  18 #include <linux/module.h>
  19 #include <linux/delay.h>
  20 #include <linux/mtd/mtd.h>
  21 #include <linux/mtd/rawnand.h>
  22 #include <linux/mtd/nand_ecc.h>
  23 #include <linux/mtd/partitions.h>
  24 
  25 #include <asm/msr.h>
  26 #include <asm/io.h>
  27 
  28 #define NR_CS553X_CONTROLLERS   4
  29 
  30 #define MSR_DIVIL_GLD_CAP       0x51400000      /* DIVIL capabilitiies */
  31 #define CAP_CS5535              0x2df000ULL
  32 #define CAP_CS5536              0x5df500ULL
  33 
  34 /* NAND Timing MSRs */
  35 #define MSR_NANDF_DATA          0x5140001b      /* NAND Flash Data Timing MSR */
  36 #define MSR_NANDF_CTL           0x5140001c      /* NAND Flash Control Timing */
  37 #define MSR_NANDF_RSVD          0x5140001d      /* Reserved */
  38 
  39 /* NAND BAR MSRs */
  40 #define MSR_DIVIL_LBAR_FLSH0    0x51400010      /* Flash Chip Select 0 */
  41 #define MSR_DIVIL_LBAR_FLSH1    0x51400011      /* Flash Chip Select 1 */
  42 #define MSR_DIVIL_LBAR_FLSH2    0x51400012      /* Flash Chip Select 2 */
  43 #define MSR_DIVIL_LBAR_FLSH3    0x51400013      /* Flash Chip Select 3 */
  44         /* Each made up of... */
  45 #define FLSH_LBAR_EN            (1ULL<<32)
  46 #define FLSH_NOR_NAND           (1ULL<<33)      /* 1 for NAND */
  47 #define FLSH_MEM_IO             (1ULL<<34)      /* 1 for MMIO */
  48         /* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
  49         /* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
  50 
  51 /* Pin function selection MSR (IDE vs. flash on the IDE pins) */
  52 #define MSR_DIVIL_BALL_OPTS     0x51400015
  53 #define PIN_OPT_IDE             (1<<0)  /* 0 for flash, 1 for IDE */
  54 
  55 /* Registers within the NAND flash controller BAR -- memory mapped */
  56 #define MM_NAND_DATA            0x00    /* 0 to 0x7ff, in fact */
  57 #define MM_NAND_CTL             0x800   /* Any even address 0x800-0x80e */
  58 #define MM_NAND_IO              0x801   /* Any odd address 0x801-0x80f */
  59 #define MM_NAND_STS             0x810
  60 #define MM_NAND_ECC_LSB         0x811
  61 #define MM_NAND_ECC_MSB         0x812
  62 #define MM_NAND_ECC_COL         0x813
  63 #define MM_NAND_LAC             0x814
  64 #define MM_NAND_ECC_CTL         0x815
  65 
  66 /* Registers within the NAND flash controller BAR -- I/O mapped */
  67 #define IO_NAND_DATA            0x00    /* 0 to 3, in fact */
  68 #define IO_NAND_CTL             0x04
  69 #define IO_NAND_IO              0x05
  70 #define IO_NAND_STS             0x06
  71 #define IO_NAND_ECC_CTL         0x08
  72 #define IO_NAND_ECC_LSB         0x09
  73 #define IO_NAND_ECC_MSB         0x0a
  74 #define IO_NAND_ECC_COL         0x0b
  75 #define IO_NAND_LAC             0x0c
  76 
  77 #define CS_NAND_CTL_DIST_EN     (1<<4)  /* Enable NAND Distract interrupt */
  78 #define CS_NAND_CTL_RDY_INT_MASK        (1<<3)  /* Enable RDY/BUSY# interrupt */
  79 #define CS_NAND_CTL_ALE         (1<<2)
  80 #define CS_NAND_CTL_CLE         (1<<1)
  81 #define CS_NAND_CTL_CE          (1<<0)  /* Keep low; 1 to reset */
  82 
  83 #define CS_NAND_STS_FLASH_RDY   (1<<3)
  84 #define CS_NAND_CTLR_BUSY       (1<<2)
  85 #define CS_NAND_CMD_COMP        (1<<1)
  86 #define CS_NAND_DIST_ST         (1<<0)
  87 
  88 #define CS_NAND_ECC_PARITY      (1<<2)
  89 #define CS_NAND_ECC_CLRECC      (1<<1)
  90 #define CS_NAND_ECC_ENECC       (1<<0)
  91 
  92 static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len)
  93 {
  94         while (unlikely(len > 0x800)) {
  95                 memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800);
  96                 buf += 0x800;
  97                 len -= 0x800;
  98         }
  99         memcpy_fromio(buf, this->legacy.IO_ADDR_R, len);
 100 }
 101 
 102 static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len)
 103 {
 104         while (unlikely(len > 0x800)) {
 105                 memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800);
 106                 buf += 0x800;
 107                 len -= 0x800;
 108         }
 109         memcpy_toio(this->legacy.IO_ADDR_R, buf, len);
 110 }
 111 
 112 static unsigned char cs553x_read_byte(struct nand_chip *this)
 113 {
 114         return readb(this->legacy.IO_ADDR_R);
 115 }
 116 
 117 static void cs553x_write_byte(struct nand_chip *this, u_char byte)
 118 {
 119         int i = 100000;
 120 
 121         while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
 122                 udelay(1);
 123                 i--;
 124         }
 125         writeb(byte, this->legacy.IO_ADDR_W + 0x801);
 126 }
 127 
 128 static void cs553x_hwcontrol(struct nand_chip *this, int cmd,
 129                              unsigned int ctrl)
 130 {
 131         void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 132         if (ctrl & NAND_CTRL_CHANGE) {
 133                 unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
 134                 writeb(ctl, mmio_base + MM_NAND_CTL);
 135         }
 136         if (cmd != NAND_CMD_NONE)
 137                 cs553x_write_byte(this, cmd);
 138 }
 139 
 140 static int cs553x_device_ready(struct nand_chip *this)
 141 {
 142         void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 143         unsigned char foo = readb(mmio_base + MM_NAND_STS);
 144 
 145         return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
 146 }
 147 
 148 static void cs_enable_hwecc(struct nand_chip *this, int mode)
 149 {
 150         void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 151 
 152         writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
 153 }
 154 
 155 static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
 156                             u_char *ecc_code)
 157 {
 158         uint32_t ecc;
 159         void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 160 
 161         ecc = readl(mmio_base + MM_NAND_STS);
 162 
 163         ecc_code[1] = ecc >> 8;
 164         ecc_code[0] = ecc >> 16;
 165         ecc_code[2] = ecc >> 24;
 166         return 0;
 167 }
 168 
 169 static struct mtd_info *cs553x_mtd[4];
 170 
 171 static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 172 {
 173         int err = 0;
 174         struct nand_chip *this;
 175         struct mtd_info *new_mtd;
 176 
 177         pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n",
 178                   cs, mmio ? "MM" : "P", adr);
 179 
 180         if (!mmio) {
 181                 pr_notice("PIO mode not yet implemented for CS553X NAND controller\n");
 182                 return -ENXIO;
 183         }
 184 
 185         /* Allocate memory for MTD device structure and private data */
 186         this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 187         if (!this) {
 188                 err = -ENOMEM;
 189                 goto out;
 190         }
 191 
 192         new_mtd = nand_to_mtd(this);
 193 
 194         /* Link the private data with the MTD structure */
 195         new_mtd->owner = THIS_MODULE;
 196 
 197         /* map physical address */
 198         this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096);
 199         if (!this->legacy.IO_ADDR_R) {
 200                 pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
 201                 err = -EIO;
 202                 goto out_mtd;
 203         }
 204 
 205         this->legacy.cmd_ctrl = cs553x_hwcontrol;
 206         this->legacy.dev_ready = cs553x_device_ready;
 207         this->legacy.read_byte = cs553x_read_byte;
 208         this->legacy.read_buf = cs553x_read_buf;
 209         this->legacy.write_buf = cs553x_write_buf;
 210 
 211         this->legacy.chip_delay = 0;
 212 
 213         this->ecc.mode = NAND_ECC_HW;
 214         this->ecc.size = 256;
 215         this->ecc.bytes = 3;
 216         this->ecc.hwctl  = cs_enable_hwecc;
 217         this->ecc.calculate = cs_calculate_ecc;
 218         this->ecc.correct  = nand_correct_data;
 219         this->ecc.strength = 1;
 220 
 221         /* Enable the following for a flash based bad block table */
 222         this->bbt_options = NAND_BBT_USE_FLASH;
 223 
 224         new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
 225         if (!new_mtd->name) {
 226                 err = -ENOMEM;
 227                 goto out_ior;
 228         }
 229 
 230         /* Scan to find existence of the device */
 231         err = nand_scan(this, 1);
 232         if (err)
 233                 goto out_free;
 234 
 235         cs553x_mtd[cs] = new_mtd;
 236         goto out;
 237 
 238 out_free:
 239         kfree(new_mtd->name);
 240 out_ior:
 241         iounmap(this->legacy.IO_ADDR_R);
 242 out_mtd:
 243         kfree(this);
 244 out:
 245         return err;
 246 }
 247 
 248 static int is_geode(void)
 249 {
 250         /* These are the CPUs which will have a CS553[56] companion chip */
 251         if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
 252             boot_cpu_data.x86 == 5 &&
 253             boot_cpu_data.x86_model == 10)
 254                 return 1; /* Geode LX */
 255 
 256         if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
 257              boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
 258             boot_cpu_data.x86 == 5 &&
 259             boot_cpu_data.x86_model == 5)
 260                 return 1; /* Geode GX (née GX2) */
 261 
 262         return 0;
 263 }
 264 
 265 static int __init cs553x_init(void)
 266 {
 267         int err = -ENXIO;
 268         int i;
 269         uint64_t val;
 270 
 271         /* If the CPU isn't a Geode GX or LX, abort */
 272         if (!is_geode())
 273                 return -ENXIO;
 274 
 275         /* If it doesn't have the CS553[56], abort */
 276         rdmsrl(MSR_DIVIL_GLD_CAP, val);
 277         val &= ~0xFFULL;
 278         if (val != CAP_CS5535 && val != CAP_CS5536)
 279                 return -ENXIO;
 280 
 281         /* If it doesn't have the NAND controller enabled, abort */
 282         rdmsrl(MSR_DIVIL_BALL_OPTS, val);
 283         if (val & PIN_OPT_IDE) {
 284                 pr_info("CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
 285                 return -ENXIO;
 286         }
 287 
 288         for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
 289                 rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
 290 
 291                 if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
 292                         err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
 293         }
 294 
 295         /* Register all devices together here. This means we can easily hack it to
 296            do mtdconcat etc. if we want to. */
 297         for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
 298                 if (cs553x_mtd[i]) {
 299                         /* If any devices registered, return success. Else the last error. */
 300                         mtd_device_register(cs553x_mtd[i], NULL, 0);
 301                         err = 0;
 302                 }
 303         }
 304 
 305         return err;
 306 }
 307 
 308 module_init(cs553x_init);
 309 
 310 static void __exit cs553x_cleanup(void)
 311 {
 312         int i;
 313 
 314         for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
 315                 struct mtd_info *mtd = cs553x_mtd[i];
 316                 struct nand_chip *this;
 317                 void __iomem *mmio_base;
 318 
 319                 if (!mtd)
 320                         continue;
 321 
 322                 this = mtd_to_nand(mtd);
 323                 mmio_base = this->legacy.IO_ADDR_R;
 324 
 325                 /* Release resources, unregister device */
 326                 nand_release(this);
 327                 kfree(mtd->name);
 328                 cs553x_mtd[i] = NULL;
 329 
 330                 /* unmap physical address */
 331                 iounmap(mmio_base);
 332 
 333                 /* Free the MTD device structure */
 334                 kfree(this);
 335         }
 336 }
 337 
 338 module_exit(cs553x_cleanup);
 339 
 340 MODULE_LICENSE("GPL");
 341 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 342 MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");

/* [<][>][^][v][top][bottom][index][help] */