422 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 on10 * 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/partitions.h>23#include <linux/iopoll.h>24 25#include <asm/msr.h>26 27#define NR_CS553X_CONTROLLERS 428 29#define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilitiies */30#define CAP_CS5535 0x2df000ULL31#define CAP_CS5536 0x5df500ULL32 33/* NAND Timing MSRs */34#define MSR_NANDF_DATA 0x5140001b /* NAND Flash Data Timing MSR */35#define MSR_NANDF_CTL 0x5140001c /* NAND Flash Control Timing */36#define MSR_NANDF_RSVD 0x5140001d /* Reserved */37 38/* NAND BAR MSRs */39#define MSR_DIVIL_LBAR_FLSH0 0x51400010 /* Flash Chip Select 0 */40#define MSR_DIVIL_LBAR_FLSH1 0x51400011 /* Flash Chip Select 1 */41#define MSR_DIVIL_LBAR_FLSH2 0x51400012 /* Flash Chip Select 2 */42#define MSR_DIVIL_LBAR_FLSH3 0x51400013 /* Flash Chip Select 3 */43 /* Each made up of... */44#define FLSH_LBAR_EN (1ULL<<32)45#define FLSH_NOR_NAND (1ULL<<33) /* 1 for NAND */46#define FLSH_MEM_IO (1ULL<<34) /* 1 for MMIO */47 /* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */48 /* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */49 50/* Pin function selection MSR (IDE vs. flash on the IDE pins) */51#define MSR_DIVIL_BALL_OPTS 0x5140001552#define PIN_OPT_IDE (1<<0) /* 0 for flash, 1 for IDE */53 54/* Registers within the NAND flash controller BAR -- memory mapped */55#define MM_NAND_DATA 0x00 /* 0 to 0x7ff, in fact */56#define MM_NAND_CTL 0x800 /* Any even address 0x800-0x80e */57#define MM_NAND_IO 0x801 /* Any odd address 0x801-0x80f */58#define MM_NAND_STS 0x81059#define MM_NAND_ECC_LSB 0x81160#define MM_NAND_ECC_MSB 0x81261#define MM_NAND_ECC_COL 0x81362#define MM_NAND_LAC 0x81463#define MM_NAND_ECC_CTL 0x81564 65/* Registers within the NAND flash controller BAR -- I/O mapped */66#define IO_NAND_DATA 0x00 /* 0 to 3, in fact */67#define IO_NAND_CTL 0x0468#define IO_NAND_IO 0x0569#define IO_NAND_STS 0x0670#define IO_NAND_ECC_CTL 0x0871#define IO_NAND_ECC_LSB 0x0972#define IO_NAND_ECC_MSB 0x0a73#define IO_NAND_ECC_COL 0x0b74#define IO_NAND_LAC 0x0c75 76#define CS_NAND_CTL_DIST_EN (1<<4) /* Enable NAND Distract interrupt */77#define CS_NAND_CTL_RDY_INT_MASK (1<<3) /* Enable RDY/BUSY# interrupt */78#define CS_NAND_CTL_ALE (1<<2)79#define CS_NAND_CTL_CLE (1<<1)80#define CS_NAND_CTL_CE (1<<0) /* Keep low; 1 to reset */81 82#define CS_NAND_STS_FLASH_RDY (1<<3)83#define CS_NAND_CTLR_BUSY (1<<2)84#define CS_NAND_CMD_COMP (1<<1)85#define CS_NAND_DIST_ST (1<<0)86 87#define CS_NAND_ECC_PARITY (1<<2)88#define CS_NAND_ECC_CLRECC (1<<1)89#define CS_NAND_ECC_ENECC (1<<0)90 91struct cs553x_nand_controller {92 struct nand_controller base;93 struct nand_chip chip;94 void __iomem *mmio;95};96 97static struct cs553x_nand_controller *98to_cs553x(struct nand_controller *controller)99{100 return container_of(controller, struct cs553x_nand_controller, base);101}102 103static int cs553x_write_ctrl_byte(struct cs553x_nand_controller *cs553x,104 u32 ctl, u8 data)105{106 u8 status;107 108 writeb(ctl, cs553x->mmio + MM_NAND_CTL);109 writeb(data, cs553x->mmio + MM_NAND_IO);110 return readb_poll_timeout_atomic(cs553x->mmio + MM_NAND_STS, status,111 !(status & CS_NAND_CTLR_BUSY), 1,112 100000);113}114 115static void cs553x_data_in(struct cs553x_nand_controller *cs553x, void *buf,116 unsigned int len)117{118 writeb(0, cs553x->mmio + MM_NAND_CTL);119 while (unlikely(len > 0x800)) {120 memcpy_fromio(buf, cs553x->mmio, 0x800);121 buf += 0x800;122 len -= 0x800;123 }124 memcpy_fromio(buf, cs553x->mmio, len);125}126 127static void cs553x_data_out(struct cs553x_nand_controller *cs553x,128 const void *buf, unsigned int len)129{130 writeb(0, cs553x->mmio + MM_NAND_CTL);131 while (unlikely(len > 0x800)) {132 memcpy_toio(cs553x->mmio, buf, 0x800);133 buf += 0x800;134 len -= 0x800;135 }136 memcpy_toio(cs553x->mmio, buf, len);137}138 139static int cs553x_wait_ready(struct cs553x_nand_controller *cs553x,140 unsigned int timeout_ms)141{142 u8 mask = CS_NAND_CTLR_BUSY | CS_NAND_STS_FLASH_RDY;143 u8 status;144 145 return readb_poll_timeout(cs553x->mmio + MM_NAND_STS, status,146 (status & mask) == CS_NAND_STS_FLASH_RDY, 100,147 timeout_ms * 1000);148}149 150static int cs553x_exec_instr(struct cs553x_nand_controller *cs553x,151 const struct nand_op_instr *instr)152{153 unsigned int i;154 int ret = 0;155 156 switch (instr->type) {157 case NAND_OP_CMD_INSTR:158 ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_CLE,159 instr->ctx.cmd.opcode);160 break;161 162 case NAND_OP_ADDR_INSTR:163 for (i = 0; i < instr->ctx.addr.naddrs; i++) {164 ret = cs553x_write_ctrl_byte(cs553x, CS_NAND_CTL_ALE,165 instr->ctx.addr.addrs[i]);166 if (ret)167 break;168 }169 break;170 171 case NAND_OP_DATA_IN_INSTR:172 cs553x_data_in(cs553x, instr->ctx.data.buf.in,173 instr->ctx.data.len);174 break;175 176 case NAND_OP_DATA_OUT_INSTR:177 cs553x_data_out(cs553x, instr->ctx.data.buf.out,178 instr->ctx.data.len);179 break;180 181 case NAND_OP_WAITRDY_INSTR:182 ret = cs553x_wait_ready(cs553x, instr->ctx.waitrdy.timeout_ms);183 break;184 }185 186 if (instr->delay_ns)187 ndelay(instr->delay_ns);188 189 return ret;190}191 192static int cs553x_exec_op(struct nand_chip *this,193 const struct nand_operation *op,194 bool check_only)195{196 struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);197 unsigned int i;198 int ret;199 200 if (check_only)201 return true;202 203 /* De-assert the CE pin */204 writeb(0, cs553x->mmio + MM_NAND_CTL);205 for (i = 0; i < op->ninstrs; i++) {206 ret = cs553x_exec_instr(cs553x, &op->instrs[i]);207 if (ret)208 break;209 }210 211 /* Re-assert the CE pin. */212 writeb(CS_NAND_CTL_CE, cs553x->mmio + MM_NAND_CTL);213 214 return ret;215}216 217static void cs_enable_hwecc(struct nand_chip *this, int mode)218{219 struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);220 221 writeb(0x07, cs553x->mmio + MM_NAND_ECC_CTL);222}223 224static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,225 u_char *ecc_code)226{227 struct cs553x_nand_controller *cs553x = to_cs553x(this->controller);228 uint32_t ecc;229 230 ecc = readl(cs553x->mmio + MM_NAND_STS);231 232 ecc_code[1] = ecc >> 8;233 ecc_code[0] = ecc >> 16;234 ecc_code[2] = ecc >> 24;235 return 0;236}237 238static struct cs553x_nand_controller *controllers[4];239 240static int cs553x_attach_chip(struct nand_chip *chip)241{242 if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)243 return 0;244 245 chip->ecc.size = 256;246 chip->ecc.bytes = 3;247 chip->ecc.hwctl = cs_enable_hwecc;248 chip->ecc.calculate = cs_calculate_ecc;249 chip->ecc.correct = rawnand_sw_hamming_correct;250 chip->ecc.strength = 1;251 252 return 0;253}254 255static const struct nand_controller_ops cs553x_nand_controller_ops = {256 .exec_op = cs553x_exec_op,257 .attach_chip = cs553x_attach_chip,258};259 260static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)261{262 struct cs553x_nand_controller *controller;263 int err = 0;264 struct nand_chip *this;265 struct mtd_info *new_mtd;266 267 pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n",268 cs, mmio ? "MM" : "P", adr);269 270 if (!mmio) {271 pr_notice("PIO mode not yet implemented for CS553X NAND controller\n");272 return -ENXIO;273 }274 275 /* Allocate memory for MTD device structure and private data */276 controller = kzalloc(sizeof(*controller), GFP_KERNEL);277 if (!controller) {278 err = -ENOMEM;279 goto out;280 }281 282 this = &controller->chip;283 nand_controller_init(&controller->base);284 controller->base.ops = &cs553x_nand_controller_ops;285 this->controller = &controller->base;286 new_mtd = nand_to_mtd(this);287 288 /* Link the private data with the MTD structure */289 new_mtd->owner = THIS_MODULE;290 291 /* map physical address */292 controller->mmio = ioremap(adr, 4096);293 if (!controller->mmio) {294 pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);295 err = -EIO;296 goto out_mtd;297 }298 299 /* Enable the following for a flash based bad block table */300 this->bbt_options = NAND_BBT_USE_FLASH;301 302 new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);303 if (!new_mtd->name) {304 err = -ENOMEM;305 goto out_ior;306 }307 308 /* Scan to find existence of the device */309 err = nand_scan(this, 1);310 if (err)311 goto out_free;312 313 controllers[cs] = controller;314 goto out;315 316out_free:317 kfree(new_mtd->name);318out_ior:319 iounmap(controller->mmio);320out_mtd:321 kfree(controller);322out:323 return err;324}325 326static int is_geode(void)327{328 /* These are the CPUs which will have a CS553[56] companion chip */329 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&330 boot_cpu_data.x86 == 5 &&331 boot_cpu_data.x86_model == 10)332 return 1; /* Geode LX */333 334 if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||335 boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&336 boot_cpu_data.x86 == 5 &&337 boot_cpu_data.x86_model == 5)338 return 1; /* Geode GX (née GX2) */339 340 return 0;341}342 343static int __init cs553x_init(void)344{345 int err = -ENXIO;346 int i;347 uint64_t val;348 349 /* If the CPU isn't a Geode GX or LX, abort */350 if (!is_geode())351 return -ENXIO;352 353 /* If it doesn't have the CS553[56], abort */354 rdmsrl(MSR_DIVIL_GLD_CAP, val);355 val &= ~0xFFULL;356 if (val != CAP_CS5535 && val != CAP_CS5536)357 return -ENXIO;358 359 /* If it doesn't have the NAND controller enabled, abort */360 rdmsrl(MSR_DIVIL_BALL_OPTS, val);361 if (val & PIN_OPT_IDE) {362 pr_info("CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");363 return -ENXIO;364 }365 366 for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {367 rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);368 369 if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))370 err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);371 }372 373 /* Register all devices together here. This means we can easily hack it to374 do mtdconcat etc. if we want to. */375 for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {376 if (controllers[i]) {377 /* If any devices registered, return success. Else the last error. */378 mtd_device_register(nand_to_mtd(&controllers[i]->chip),379 NULL, 0);380 err = 0;381 }382 }383 384 return err;385}386 387module_init(cs553x_init);388 389static void __exit cs553x_cleanup(void)390{391 int i;392 393 for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {394 struct cs553x_nand_controller *controller = controllers[i];395 struct nand_chip *this = &controller->chip;396 struct mtd_info *mtd = nand_to_mtd(this);397 int ret;398 399 if (!mtd)400 continue;401 402 /* Release resources, unregister device */403 ret = mtd_device_unregister(mtd);404 WARN_ON(ret);405 nand_cleanup(this);406 kfree(mtd->name);407 controllers[i] = NULL;408 409 /* unmap physical address */410 iounmap(controller->mmio);411 412 /* Free the MTD device structure */413 kfree(controller);414 }415}416 417module_exit(cs553x_cleanup);418 419MODULE_LICENSE("GPL");420MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");421MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");422