ndfc.c (6819B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Overview: 4 * Platform independent driver for NDFC (NanD Flash Controller) 5 * integrated into EP440 cores 6 * 7 * Ported to an OF platform driver by Sean MacLennan 8 * 9 * The NDFC supports multiple chips, but this driver only supports a 10 * single chip since I do not have access to any boards with 11 * multiple chips. 12 * 13 * Author: Thomas Gleixner 14 * 15 * Copyright 2006 IBM 16 * Copyright 2008 PIKA Technologies 17 * Sean MacLennan <smaclennan@pikatech.com> 18 */ 19#include <linux/module.h> 20#include <linux/mtd/rawnand.h> 21#include <linux/mtd/partitions.h> 22#include <linux/mtd/ndfc.h> 23#include <linux/slab.h> 24#include <linux/mtd/mtd.h> 25#include <linux/of_address.h> 26#include <linux/of_platform.h> 27#include <asm/io.h> 28 29#define NDFC_MAX_CS 4 30 31struct ndfc_controller { 32 struct platform_device *ofdev; 33 void __iomem *ndfcbase; 34 struct nand_chip chip; 35 int chip_select; 36 struct nand_controller ndfc_control; 37}; 38 39static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; 40 41static void ndfc_select_chip(struct nand_chip *nchip, int chip) 42{ 43 uint32_t ccr; 44 struct ndfc_controller *ndfc = nand_get_controller_data(nchip); 45 46 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); 47 if (chip >= 0) { 48 ccr &= ~NDFC_CCR_BS_MASK; 49 ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); 50 } else 51 ccr |= NDFC_CCR_RESET_CE; 52 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 53} 54 55static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) 56{ 57 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 58 59 if (cmd == NAND_CMD_NONE) 60 return; 61 62 if (ctrl & NAND_CLE) 63 writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD); 64 else 65 writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE); 66} 67 68static int ndfc_ready(struct nand_chip *chip) 69{ 70 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 71 72 return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; 73} 74 75static void ndfc_enable_hwecc(struct nand_chip *chip, int mode) 76{ 77 uint32_t ccr; 78 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 79 80 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); 81 ccr |= NDFC_CCR_RESET_ECC; 82 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 83 wmb(); 84} 85 86static int ndfc_calculate_ecc(struct nand_chip *chip, 87 const u_char *dat, u_char *ecc_code) 88{ 89 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 90 uint32_t ecc; 91 uint8_t *p = (uint8_t *)&ecc; 92 93 wmb(); 94 ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); 95 /* The NDFC uses Smart Media (SMC) bytes order */ 96 ecc_code[0] = p[1]; 97 ecc_code[1] = p[2]; 98 ecc_code[2] = p[3]; 99 100 return 0; 101} 102 103/* 104 * Speedups for buffer read/write/verify 105 * 106 * NDFC allows 32bit read/write of data. So we can speed up the buffer 107 * functions. No further checking, as nand_base will always read/write 108 * page aligned. 109 */ 110static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) 111{ 112 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 113 uint32_t *p = (uint32_t *) buf; 114 115 for(;len > 0; len -= 4) 116 *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); 117} 118 119static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) 120{ 121 struct ndfc_controller *ndfc = nand_get_controller_data(chip); 122 uint32_t *p = (uint32_t *) buf; 123 124 for(;len > 0; len -= 4) 125 out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); 126} 127 128/* 129 * Initialize chip structure 130 */ 131static int ndfc_chip_init(struct ndfc_controller *ndfc, 132 struct device_node *node) 133{ 134 struct device_node *flash_np; 135 struct nand_chip *chip = &ndfc->chip; 136 struct mtd_info *mtd = nand_to_mtd(chip); 137 int ret; 138 139 chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; 140 chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; 141 chip->legacy.cmd_ctrl = ndfc_hwcontrol; 142 chip->legacy.dev_ready = ndfc_ready; 143 chip->legacy.select_chip = ndfc_select_chip; 144 chip->legacy.chip_delay = 50; 145 chip->controller = &ndfc->ndfc_control; 146 chip->legacy.read_buf = ndfc_read_buf; 147 chip->legacy.write_buf = ndfc_write_buf; 148 chip->ecc.correct = rawnand_sw_hamming_correct; 149 chip->ecc.hwctl = ndfc_enable_hwecc; 150 chip->ecc.calculate = ndfc_calculate_ecc; 151 chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; 152 chip->ecc.size = 256; 153 chip->ecc.bytes = 3; 154 chip->ecc.strength = 1; 155 nand_set_controller_data(chip, ndfc); 156 157 mtd->dev.parent = &ndfc->ofdev->dev; 158 159 flash_np = of_get_next_child(node, NULL); 160 if (!flash_np) 161 return -ENODEV; 162 nand_set_flash_node(chip, flash_np); 163 164 mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev), 165 flash_np); 166 if (!mtd->name) { 167 ret = -ENOMEM; 168 goto err; 169 } 170 171 ret = nand_scan(chip, 1); 172 if (ret) 173 goto err; 174 175 ret = mtd_device_register(mtd, NULL, 0); 176 177err: 178 of_node_put(flash_np); 179 if (ret) 180 kfree(mtd->name); 181 return ret; 182} 183 184static int ndfc_probe(struct platform_device *ofdev) 185{ 186 struct ndfc_controller *ndfc; 187 const __be32 *reg; 188 u32 ccr; 189 u32 cs; 190 int err, len; 191 192 /* Read the reg property to get the chip select */ 193 reg = of_get_property(ofdev->dev.of_node, "reg", &len); 194 if (reg == NULL || len != 12) { 195 dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); 196 return -ENOENT; 197 } 198 199 cs = be32_to_cpu(reg[0]); 200 if (cs >= NDFC_MAX_CS) { 201 dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs); 202 return -EINVAL; 203 } 204 205 ndfc = &ndfc_ctrl[cs]; 206 ndfc->chip_select = cs; 207 208 nand_controller_init(&ndfc->ndfc_control); 209 ndfc->ofdev = ofdev; 210 dev_set_drvdata(&ofdev->dev, ndfc); 211 212 ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); 213 if (!ndfc->ndfcbase) { 214 dev_err(&ofdev->dev, "failed to get memory\n"); 215 return -EIO; 216 } 217 218 ccr = NDFC_CCR_BS(ndfc->chip_select); 219 220 /* It is ok if ccr does not exist - just default to 0 */ 221 reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); 222 if (reg) 223 ccr |= be32_to_cpup(reg); 224 225 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 226 227 /* Set the bank settings if given */ 228 reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); 229 if (reg) { 230 int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); 231 out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); 232 } 233 234 err = ndfc_chip_init(ndfc, ofdev->dev.of_node); 235 if (err) { 236 iounmap(ndfc->ndfcbase); 237 return err; 238 } 239 240 return 0; 241} 242 243static int ndfc_remove(struct platform_device *ofdev) 244{ 245 struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); 246 struct nand_chip *chip = &ndfc->chip; 247 struct mtd_info *mtd = nand_to_mtd(chip); 248 int ret; 249 250 ret = mtd_device_unregister(mtd); 251 WARN_ON(ret); 252 nand_cleanup(chip); 253 kfree(mtd->name); 254 255 return 0; 256} 257 258static const struct of_device_id ndfc_match[] = { 259 { .compatible = "ibm,ndfc", }, 260 {} 261}; 262MODULE_DEVICE_TABLE(of, ndfc_match); 263 264static struct platform_driver ndfc_driver = { 265 .driver = { 266 .name = "ndfc", 267 .of_match_table = ndfc_match, 268 }, 269 .probe = ndfc_probe, 270 .remove = ndfc_remove, 271}; 272 273module_platform_driver(ndfc_driver); 274 275MODULE_LICENSE("GPL"); 276MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); 277MODULE_DESCRIPTION("OF Platform driver for NDFC");