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