From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/mtd/nand/raw/atmel/nand-controller.c | 751 +++++++++++++++++++++++++++++++++------------------------ 1 files changed, 429 insertions(+), 322 deletions(-) diff --git a/kernel/drivers/mtd/nand/raw/atmel/nand-controller.c b/kernel/drivers/mtd/nand/raw/atmel/nand-controller.c index 7887629..0d84f81 100644 --- a/kernel/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/kernel/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2017 ATMEL * Copyright 2017 Free Electrons @@ -28,10 +29,6 @@ * * Add Nand Flash Controller support for SAMA5 SoC * Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * A few words about the naming convention in this file. This convention * applies to structure and function names. @@ -65,6 +62,7 @@ #include <linux/iopoll.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <soc/at91/atmel-sfr.h> #include "pmecc.h" @@ -202,8 +200,10 @@ void (*nand_init)(struct atmel_nand_controller *nc, struct atmel_nand *nand); int (*ecc_init)(struct nand_chip *chip); - int (*setup_data_interface)(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf); + int (*setup_interface)(struct atmel_nand *nand, int csline, + const struct nand_interface_config *conf); + int (*exec_op)(struct atmel_nand *nand, + const struct nand_operation *op, bool check_only); }; struct atmel_nand_controller_caps { @@ -211,6 +211,7 @@ bool legacy_of_bindings; u32 ale_offs; u32 cle_offs; + const char *ebi_csa_regmap_name; const struct atmel_nand_controller_ops *ops; }; @@ -231,10 +232,15 @@ return container_of(ctl, struct atmel_nand_controller, base); } +struct atmel_smc_nand_ebi_csa_cfg { + u32 offs; + u32 nfd0_on_d16; +}; + struct atmel_smc_nand_controller { struct atmel_nand_controller base; - struct regmap *matrix; - unsigned int ebi_csa_offs; + struct regmap *ebi_csa_regmap; + struct atmel_smc_nand_ebi_csa_cfg *ebi_csa; }; static inline struct atmel_smc_nand_controller * @@ -255,6 +261,7 @@ struct regmap *io; struct atmel_nfc_op op; struct completion complete; + u32 cfg; int irq; /* Only used when instantiating from legacy DT bindings. */ @@ -398,6 +405,7 @@ dma_async_issue_pending(nc->dmac); wait_for_completion(&finished); + dma_unmap_single(nc->dev, buf_dma, len, dir); return 0; @@ -408,153 +416,6 @@ dev_dbg(nc->dev, "Fall back to CPU I/O\n"); return -EIO; -} - -static u8 atmel_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - return ioread8(nand->activecs->io.virt); -} - -static u16 atmel_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - return ioread16(nand->activecs->io.virt); -} - -static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - if (chip->options & NAND_BUSWIDTH_16) - iowrite16(byte | (byte << 8), nand->activecs->io.virt); - else - iowrite8(byte, nand->activecs->io.virt); -} - -static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - struct atmel_nand_controller *nc; - - nc = to_nand_controller(chip->controller); - - /* - * If the controller supports DMA, the buffer address is DMA-able and - * len is long enough to make DMA transfers profitable, let's trigger - * a DMA transfer. If it fails, fallback to PIO mode. - */ - if (nc->dmac && virt_addr_valid(buf) && - len >= MIN_DMA_LEN && - !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len, - DMA_FROM_DEVICE)) - return; - - if (chip->options & NAND_BUSWIDTH_16) - ioread16_rep(nand->activecs->io.virt, buf, len / 2); - else - ioread8_rep(nand->activecs->io.virt, buf, len); -} - -static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - struct atmel_nand_controller *nc; - - nc = to_nand_controller(chip->controller); - - /* - * If the controller supports DMA, the buffer address is DMA-able and - * len is long enough to make DMA transfers profitable, let's trigger - * a DMA transfer. If it fails, fallback to PIO mode. - */ - if (nc->dmac && virt_addr_valid(buf) && - len >= MIN_DMA_LEN && - !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma, - len, DMA_TO_DEVICE)) - return; - - if (chip->options & NAND_BUSWIDTH_16) - iowrite16_rep(nand->activecs->io.virt, buf, len / 2); - else - iowrite8_rep(nand->activecs->io.virt, buf, len); -} - -static int atmel_nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - return gpiod_get_value(nand->activecs->rb.gpio); -} - -static void atmel_nand_select_chip(struct mtd_info *mtd, int cs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - if (cs < 0 || cs >= nand->numcs) { - nand->activecs = NULL; - chip->dev_ready = NULL; - return; - } - - nand->activecs = &nand->cs[cs]; - - if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB) - chip->dev_ready = atmel_nand_dev_ready; -} - -static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - struct atmel_hsmc_nand_controller *nc; - u32 status; - - nc = to_hsmc_nand_controller(chip->controller); - - regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status); - - return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id); -} - -static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - struct atmel_hsmc_nand_controller *nc; - - nc = to_hsmc_nand_controller(chip->controller); - - atmel_nand_select_chip(mtd, cs); - - if (!nand->activecs) { - regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL, - ATMEL_HSMC_NFC_CTRL_DIS); - return; - } - - if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB) - chip->dev_ready = atmel_hsmc_nand_dev_ready; - - regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG, - ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK | - ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK | - ATMEL_HSMC_NFC_CFG_RSPARE | - ATMEL_HSMC_NFC_CFG_WSPARE, - ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) | - ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) | - ATMEL_HSMC_NFC_CFG_RSPARE); - regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL, - ATMEL_HSMC_NFC_CTRL_EN); } static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll) @@ -607,53 +468,250 @@ return ret; } -static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat, - unsigned int ctrl) +static void atmel_nand_data_in(struct atmel_nand *nand, void *buf, + unsigned int len, bool force_8bit) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct atmel_nand_controller *nc; + + nc = to_nand_controller(nand->base.controller); + + /* + * If the controller supports DMA, the buffer address is DMA-able and + * len is long enough to make DMA transfers profitable, let's trigger + * a DMA transfer. If it fails, fallback to PIO mode. + */ + if (nc->dmac && virt_addr_valid(buf) && + len >= MIN_DMA_LEN && !force_8bit && + !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len, + DMA_FROM_DEVICE)) + return; + + if ((nand->base.options & NAND_BUSWIDTH_16) && !force_8bit) + ioread16_rep(nand->activecs->io.virt, buf, len / 2); + else + ioread8_rep(nand->activecs->io.virt, buf, len); +} + +static void atmel_nand_data_out(struct atmel_nand *nand, const void *buf, + unsigned int len, bool force_8bit) +{ + struct atmel_nand_controller *nc; + + nc = to_nand_controller(nand->base.controller); + + /* + * If the controller supports DMA, the buffer address is DMA-able and + * len is long enough to make DMA transfers profitable, let's trigger + * a DMA transfer. If it fails, fallback to PIO mode. + */ + if (nc->dmac && virt_addr_valid(buf) && + len >= MIN_DMA_LEN && !force_8bit && + !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma, + len, DMA_TO_DEVICE)) + return; + + if ((nand->base.options & NAND_BUSWIDTH_16) && !force_8bit) + iowrite16_rep(nand->activecs->io.virt, buf, len / 2); + else + iowrite8_rep(nand->activecs->io.virt, buf, len); +} + +static int atmel_nand_waitrdy(struct atmel_nand *nand, unsigned int timeout_ms) +{ + if (nand->activecs->rb.type == ATMEL_NAND_NO_RB) + return nand_soft_waitrdy(&nand->base, timeout_ms); + + return nand_gpio_waitrdy(&nand->base, nand->activecs->rb.gpio, + timeout_ms); +} + +static int atmel_hsmc_nand_waitrdy(struct atmel_nand *nand, + unsigned int timeout_ms) +{ + struct atmel_hsmc_nand_controller *nc; + u32 status, mask; + + if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) + return atmel_nand_waitrdy(nand, timeout_ms); + + nc = to_hsmc_nand_controller(nand->base.controller); + mask = ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id); + return regmap_read_poll_timeout_atomic(nc->base.smc, ATMEL_HSMC_NFC_SR, + status, status & mask, + 10, timeout_ms * 1000); +} + +static void atmel_nand_select_target(struct atmel_nand *nand, + unsigned int cs) +{ + nand->activecs = &nand->cs[cs]; +} + +static void atmel_hsmc_nand_select_target(struct atmel_nand *nand, + unsigned int cs) +{ + struct mtd_info *mtd = nand_to_mtd(&nand->base); + struct atmel_hsmc_nand_controller *nc; + u32 cfg = ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) | + ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) | + ATMEL_HSMC_NFC_CFG_RSPARE; + + nand->activecs = &nand->cs[cs]; + nc = to_hsmc_nand_controller(nand->base.controller); + if (nc->cfg == cfg) + return; + + regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG, + ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK | + ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK | + ATMEL_HSMC_NFC_CFG_RSPARE | + ATMEL_HSMC_NFC_CFG_WSPARE, + cfg); + nc->cfg = cfg; +} + +static int atmel_smc_nand_exec_instr(struct atmel_nand *nand, + const struct nand_op_instr *instr) +{ + struct atmel_nand_controller *nc; + unsigned int i; + + nc = to_nand_controller(nand->base.controller); + switch (instr->type) { + case NAND_OP_CMD_INSTR: + writeb(instr->ctx.cmd.opcode, + nand->activecs->io.virt + nc->caps->cle_offs); + return 0; + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb(instr->ctx.addr.addrs[i], + nand->activecs->io.virt + nc->caps->ale_offs); + return 0; + case NAND_OP_DATA_IN_INSTR: + atmel_nand_data_in(nand, instr->ctx.data.buf.in, + instr->ctx.data.len, + instr->ctx.data.force_8bit); + return 0; + case NAND_OP_DATA_OUT_INSTR: + atmel_nand_data_out(nand, instr->ctx.data.buf.out, + instr->ctx.data.len, + instr->ctx.data.force_8bit); + return 0; + case NAND_OP_WAITRDY_INSTR: + return atmel_nand_waitrdy(nand, + instr->ctx.waitrdy.timeout_ms); + default: + break; + } + + return -EINVAL; +} + +static int atmel_smc_nand_exec_op(struct atmel_nand *nand, + const struct nand_operation *op, + bool check_only) +{ + unsigned int i; + int ret = 0; + + if (check_only) + return 0; + + atmel_nand_select_target(nand, op->cs); + gpiod_set_value(nand->activecs->csgpio, 0); + for (i = 0; i < op->ninstrs; i++) { + ret = atmel_smc_nand_exec_instr(nand, &op->instrs[i]); + if (ret) + break; + } + gpiod_set_value(nand->activecs->csgpio, 1); + + return ret; +} + +static int atmel_hsmc_exec_cmd_addr(struct nand_chip *chip, + const struct nand_subop *subop) +{ struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_hsmc_nand_controller *nc; + unsigned int i, j; nc = to_hsmc_nand_controller(chip->controller); - if (ctrl & NAND_ALE) { - if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES) - return; + nc->op.cs = nand->activecs->id; + for (i = 0; i < subop->ninstrs; i++) { + const struct nand_op_instr *instr = &subop->instrs[i]; - nc->op.addrs[nc->op.naddrs++] = dat; - } else if (ctrl & NAND_CLE) { - if (nc->op.ncmds > 1) - return; + if (instr->type == NAND_OP_CMD_INSTR) { + nc->op.cmds[nc->op.ncmds++] = instr->ctx.cmd.opcode; + continue; + } - nc->op.cmds[nc->op.ncmds++] = dat; + for (j = nand_subop_get_addr_start_off(subop, i); + j < nand_subop_get_num_addr_cyc(subop, i); j++) { + nc->op.addrs[nc->op.naddrs] = instr->ctx.addr.addrs[j]; + nc->op.naddrs++; + } } - if (dat == NAND_CMD_NONE) { - nc->op.cs = nand->activecs->id; - atmel_nfc_exec_op(nc, true); - } + return atmel_nfc_exec_op(nc, true); } -static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) +static int atmel_hsmc_exec_rw(struct nand_chip *chip, + const struct nand_subop *subop) { - struct nand_chip *chip = mtd_to_nand(mtd); + const struct nand_op_instr *instr = subop->instrs; struct atmel_nand *nand = to_atmel_nand(chip); - struct atmel_nand_controller *nc; - nc = to_nand_controller(chip->controller); + if (instr->type == NAND_OP_DATA_IN_INSTR) + atmel_nand_data_in(nand, instr->ctx.data.buf.in, + instr->ctx.data.len, + instr->ctx.data.force_8bit); + else + atmel_nand_data_out(nand, instr->ctx.data.buf.out, + instr->ctx.data.len, + instr->ctx.data.force_8bit); - if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) { - if (ctrl & NAND_NCE) - gpiod_set_value(nand->activecs->csgpio, 0); - else - gpiod_set_value(nand->activecs->csgpio, 1); - } + return 0; +} - if (ctrl & NAND_ALE) - writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs); - else if (ctrl & NAND_CLE) - writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs); +static int atmel_hsmc_exec_waitrdy(struct nand_chip *chip, + const struct nand_subop *subop) +{ + const struct nand_op_instr *instr = subop->instrs; + struct atmel_nand *nand = to_atmel_nand(chip); + + return atmel_hsmc_nand_waitrdy(nand, instr->ctx.waitrdy.timeout_ms); +} + +static const struct nand_op_parser atmel_hsmc_op_parser = NAND_OP_PARSER( + NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_cmd_addr, + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5), + NAND_OP_PARSER_PAT_CMD_ELEM(true)), + NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_rw, + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 0)), + NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_rw, + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 0)), + NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_waitrdy, + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), +); + +static int atmel_hsmc_nand_exec_op(struct atmel_nand *nand, + const struct nand_operation *op, + bool check_only) +{ + int ret; + + if (check_only) + return nand_op_parser_exec_op(&nand->base, + &atmel_hsmc_op_parser, op, true); + + atmel_hsmc_nand_select_target(nand, op->cs); + ret = nand_op_parser_exec_op(&nand->base, &atmel_hsmc_op_parser, op, + false); + + return ret; } static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf, @@ -853,7 +911,7 @@ if (ret) return ret; - atmel_nand_write_buf(mtd, buf, mtd->writesize); + nand_write_data_op(chip, buf, mtd->writesize, false); ret = atmel_nand_pmecc_generate_eccbytes(chip, raw); if (ret) { @@ -863,20 +921,18 @@ atmel_nand_pmecc_disable(chip, raw); - atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false); return nand_prog_page_end_op(chip); } -static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false); } -static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -895,25 +951,29 @@ if (ret) return ret; - atmel_nand_read_buf(mtd, buf, mtd->writesize); - atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); + ret = nand_read_data_op(chip, buf, mtd->writesize, false, false); + if (ret) + goto out_disable; + + ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false, false); + if (ret) + goto out_disable; ret = atmel_nand_pmecc_correct_data(chip, buf, raw); +out_disable: atmel_nand_pmecc_disable(chip, raw); return ret; } -static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false); } -static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true); @@ -926,8 +986,9 @@ struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_hsmc_nand_controller *nc; - int ret, status; + int ret; + atmel_hsmc_nand_select_target(nand, chip->cur_cs); nc = to_hsmc_nand_controller(chip->controller); atmel_nfc_copy_to_sram(chip, buf, false); @@ -958,25 +1019,12 @@ if (ret) return ret; - atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false); - nc->op.cmds[0] = NAND_CMD_PAGEPROG; - nc->op.ncmds = 1; - nc->op.cs = nand->activecs->id; - ret = atmel_nfc_exec_op(nc, false); - if (ret) - dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n", - ret); - - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; - - return ret; + return nand_prog_page_end_op(chip); } -static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -984,8 +1032,7 @@ false); } -static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -1002,6 +1049,7 @@ struct atmel_hsmc_nand_controller *nc; int ret; + atmel_hsmc_nand_select_target(nand, chip->cur_cs); nc = to_hsmc_nand_controller(chip->controller); /* @@ -1009,12 +1057,9 @@ * connected to a native SoC R/B pin. If that's not the case, fallback * to the non-optimized one. */ - if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) { - nand_read_page_op(chip, page, 0, NULL, 0); - + if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, raw); - } nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0; @@ -1047,16 +1092,14 @@ return ret; } -static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page, false); } -static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { @@ -1066,7 +1109,10 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) { + const struct nand_ecc_props *requirements = + nanddev_get_ecc_requirements(&chip->base); struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; struct atmel_pmecc_user_req req; @@ -1091,19 +1137,19 @@ chip->ecc.size = val; } - if (chip->ecc.options & NAND_ECC_MAXIMIZE) + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; else if (chip->ecc.strength) req.ecc.strength = chip->ecc.strength; - else if (chip->ecc_strength_ds) - req.ecc.strength = chip->ecc_strength_ds; + else if (requirements->strength) + req.ecc.strength = requirements->strength; else req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; if (chip->ecc.size) req.ecc.sectorsize = chip->ecc.size; - else if (chip->ecc_step_ds) - req.ecc.sectorsize = chip->ecc_step_ds; + else if (requirements->step_size) + req.ecc.sectorsize = requirements->step_size; else req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO; @@ -1122,14 +1168,14 @@ if (IS_ERR(nand->pmecc)) return PTR_ERR(nand->pmecc); - chip->ecc.algo = NAND_ECC_BCH; + chip->ecc.algo = NAND_ECC_ALGO_BCH; chip->ecc.size = req.ecc.sectorsize; chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors; chip->ecc.strength = req.ecc.strength; chip->options |= NAND_NO_SUBPAGE_WRITE; - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); return 0; } @@ -1141,15 +1187,15 @@ nc = to_nand_controller(chip->controller); - switch (chip->ecc.mode) { - case NAND_ECC_NONE: - case NAND_ECC_SOFT: + switch (chip->ecc.engine_type) { + case NAND_ECC_ENGINE_TYPE_NONE: + case NAND_ECC_ENGINE_TYPE_SOFT: /* * Nothing to do, the core will initialize everything for us. */ break; - case NAND_ECC_HW: + case NAND_ECC_ENGINE_TYPE_ON_HOST: ret = atmel_nand_pmecc_init(chip); if (ret) return ret; @@ -1163,7 +1209,7 @@ default: /* Other modes are not supported. */ dev_err(nc->dev, "Unsupported ECC mode: %d\n", - chip->ecc.mode); + chip->ecc.engine_type); return -ENOTSUPP; } @@ -1178,7 +1224,7 @@ if (ret) return ret; - if (chip->ecc.mode != NAND_ECC_HW) + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) return 0; /* Adjust the ECC operations for the HSMC IP. */ @@ -1191,7 +1237,7 @@ } static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, - const struct nand_data_interface *conf, + const struct nand_interface_config *conf, struct atmel_smc_cs_conf *smcconf) { u32 ncycles, totalcycles, timeps, mckperiodps; @@ -1201,7 +1247,7 @@ nc = to_nand_controller(nand->base.controller); /* DDR interface not supported. */ - if (conf->type != NAND_SDR_IFACE) + if (!nand_interface_is_sdr(conf)) return -ENOTSUPP; /* @@ -1420,9 +1466,9 @@ return 0; } -static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand, +static int atmel_smc_nand_setup_interface(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { struct atmel_nand_controller *nc; struct atmel_smc_cs_conf smcconf; @@ -1445,9 +1491,9 @@ return 0; } -static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, +static int atmel_hsmc_nand_setup_interface(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { struct atmel_hsmc_nand_controller *nc; struct atmel_smc_cs_conf smcconf; @@ -1475,10 +1521,9 @@ return 0; } -static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline, - const struct nand_data_interface *conf) +static int atmel_nand_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -1488,7 +1533,19 @@ (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY)) return -EINVAL; - return nc->caps->ops->setup_data_interface(nand, csline, conf); + return nc->caps->ops->setup_interface(nand, csline, conf); +} + +static int atmel_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + struct atmel_nand *nand = to_atmel_nand(chip); + struct atmel_nand_controller *nc; + + nc = to_nand_controller(nand->base.controller); + + return nc->caps->ops->exec_op(nand, op, check_only); } static void atmel_nand_init(struct atmel_nand_controller *nc, @@ -1500,30 +1557,19 @@ mtd->dev.parent = nc->dev; nand->base.controller = &nc->base; - chip->cmd_ctrl = atmel_nand_cmd_ctrl; - chip->read_byte = atmel_nand_read_byte; - chip->read_word = atmel_nand_read_word; - chip->write_byte = atmel_nand_write_byte; - chip->read_buf = atmel_nand_read_buf; - chip->write_buf = atmel_nand_write_buf; - chip->select_chip = atmel_nand_select_chip; - - if (nc->mck && nc->caps->ops->setup_data_interface) - chip->setup_data_interface = atmel_nand_setup_data_interface; - - /* Some NANDs require a longer delay than the default one (20us). */ - chip->chip_delay = 40; + if (!nc->mck || !nc->caps->ops->setup_interface) + chip->options |= NAND_KEEP_TIMINGS; /* * Use a bounce buffer when the buffer passed by the MTD user is not * suitable for DMA. */ if (nc->dmac) - chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->options |= NAND_USES_DMA; /* Default to HW ECC if pmecc is available. */ if (nc->pmecc) - chip->ecc.mode = NAND_ECC_HW; + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; } static void atmel_smc_nand_init(struct atmel_nand_controller *nc, @@ -1536,25 +1582,20 @@ atmel_nand_init(nc, nand); smc_nc = to_smc_nand_controller(chip->controller); - if (!smc_nc->matrix) + if (!smc_nc->ebi_csa_regmap) return; /* Attach the CS to the NAND Flash logic. */ for (i = 0; i < nand->numcs; i++) - regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs, + regmap_update_bits(smc_nc->ebi_csa_regmap, + smc_nc->ebi_csa->offs, BIT(nand->cs[i].id), BIT(nand->cs[i].id)); -} -static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc, - struct atmel_nand *nand) -{ - struct nand_chip *chip = &nand->base; - - atmel_nand_init(nc, nand); - - /* Overload some methods for the HSMC controller. */ - chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl; - chip->select_chip = atmel_hsmc_nand_select_chip; + if (smc_nc->ebi_csa->nfd0_on_d16) + regmap_update_bits(smc_nc->ebi_csa_regmap, + smc_nc->ebi_csa->offs, + smc_nc->ebi_csa->nfd0_on_d16, + smc_nc->ebi_csa->nfd0_on_d16); } static int atmel_nand_controller_remove_nand(struct atmel_nand *nand) @@ -1588,9 +1629,7 @@ return ERR_PTR(-EINVAL); } - nand = devm_kzalloc(nc->dev, - sizeof(*nand) + (numcs * sizeof(*nand->cs)), - GFP_KERNEL); + nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL); if (!nand) { dev_err(nc->dev, "Failed to allocate NAND object\n"); return ERR_PTR(-ENOMEM); @@ -1598,9 +1637,8 @@ nand->numcs = numcs; - gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0, - &np->fwnode, GPIOD_IN, - "nand-det"); + gpio = devm_fwnode_gpiod_get(nc->dev, of_fwnode_handle(np), + "det", GPIOD_IN, "nand-det"); if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { dev_err(nc->dev, "Failed to get detect gpio (err = %ld)\n", @@ -1644,9 +1682,10 @@ nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB; nand->cs[i].rb.id = val; } else { - gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, - "rb", i, &np->fwnode, - GPIOD_IN, "nand-rb"); + gpio = devm_fwnode_gpiod_get_index(nc->dev, + of_fwnode_handle(np), + "rb", i, GPIOD_IN, + "nand-rb"); if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { dev_err(nc->dev, "Failed to get R/B gpio (err = %ld)\n", @@ -1660,10 +1699,10 @@ } } - gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs", - i, &np->fwnode, - GPIOD_OUT_HIGH, - "nand-cs"); + gpio = devm_fwnode_gpiod_get_index(nc->dev, + of_fwnode_handle(np), + "cs", i, GPIOD_OUT_HIGH, + "nand-cs"); if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) { dev_err(nc->dev, "Failed to get CS gpio (err = %ld)\n", @@ -1864,34 +1903,71 @@ clk_put(nc->mck); } -static const struct of_device_id atmel_matrix_of_ids[] = { +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9260_ebi_csa = { + .offs = AT91SAM9260_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9261_ebi_csa = { + .offs = AT91SAM9261_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9263_ebi_csa = { + .offs = AT91SAM9263_MATRIX_EBI0CSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9rl_ebi_csa = { + .offs = AT91SAM9RL_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9g45_ebi_csa = { + .offs = AT91SAM9G45_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9n12_ebi_csa = { + .offs = AT91SAM9N12_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9x5_ebi_csa = { + .offs = AT91SAM9X5_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg sam9x60_ebi_csa = { + .offs = AT91_SFR_CCFG_EBICSA, + .nfd0_on_d16 = AT91_SFR_CCFG_NFD0_ON_D16, +}; + +static const struct of_device_id atmel_ebi_csa_regmap_of_ids[] = { { .compatible = "atmel,at91sam9260-matrix", - .data = (void *)AT91SAM9260_MATRIX_EBICSA, + .data = &at91sam9260_ebi_csa, }, { .compatible = "atmel,at91sam9261-matrix", - .data = (void *)AT91SAM9261_MATRIX_EBICSA, + .data = &at91sam9261_ebi_csa, }, { .compatible = "atmel,at91sam9263-matrix", - .data = (void *)AT91SAM9263_MATRIX_EBI0CSA, + .data = &at91sam9263_ebi_csa, }, { .compatible = "atmel,at91sam9rl-matrix", - .data = (void *)AT91SAM9RL_MATRIX_EBICSA, + .data = &at91sam9rl_ebi_csa, }, { .compatible = "atmel,at91sam9g45-matrix", - .data = (void *)AT91SAM9G45_MATRIX_EBICSA, + .data = &at91sam9g45_ebi_csa, }, { .compatible = "atmel,at91sam9n12-matrix", - .data = (void *)AT91SAM9N12_MATRIX_EBICSA, + .data = &at91sam9n12_ebi_csa, }, { .compatible = "atmel,at91sam9x5-matrix", - .data = (void *)AT91SAM9X5_MATRIX_EBICSA, + .data = &at91sam9x5_ebi_csa, + }, + { + .compatible = "microchip,sam9x60-sfr", + .data = &sam9x60_ebi_csa, }, { /* sentinel */ }, }; @@ -1939,6 +2015,8 @@ static const struct nand_controller_ops atmel_nand_controller_ops = { .attach_chip = atmel_nand_attach_chip, + .setup_interface = atmel_nand_setup_interface, + .exec_op = atmel_nand_exec_op, }; static int atmel_nand_controller_init(struct atmel_nand_controller *nc, @@ -1958,13 +2036,9 @@ platform_set_drvdata(pdev, nc); nc->pmecc = devm_atmel_pmecc_get(dev); - if (IS_ERR(nc->pmecc)) { - ret = PTR_ERR(nc->pmecc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Could not get PMECC object (err = %d)\n", - ret); - return ret; - } + if (IS_ERR(nc->pmecc)) + return dev_err_probe(dev, PTR_ERR(nc->pmecc), + "Could not get PMECC object\n"); if (nc->caps->has_dma && !atmel_nand_avoid_dma) { dma_cap_mask_t mask; @@ -1984,13 +2058,15 @@ nc->mck = of_clk_get(dev->parent->of_node, 0); if (IS_ERR(nc->mck)) { dev_err(dev, "Failed to retrieve MCK clk\n"); - return PTR_ERR(nc->mck); + ret = PTR_ERR(nc->mck); + goto out_release_dma; } np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0); if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); - return -EINVAL; + ret = -EINVAL; + goto out_release_dma; } nc->smc = syscon_node_to_regmap(np); @@ -1998,10 +2074,16 @@ if (IS_ERR(nc->smc)) { ret = PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret); - return ret; + goto out_release_dma; } return 0; + +out_release_dma: + if (nc->dmac) + dma_release_channel(nc->dmac); + + return ret; } static int @@ -2012,37 +2094,38 @@ struct device_node *np; int ret; - /* We do not retrieve the matrix syscon when parsing old DTs. */ + /* We do not retrieve the EBICSA regmap when parsing old DTs. */ if (nc->base.caps->legacy_of_bindings) return 0; - np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0); + np = of_parse_phandle(dev->parent->of_node, + nc->base.caps->ebi_csa_regmap_name, 0); if (!np) return 0; - match = of_match_node(atmel_matrix_of_ids, np); + match = of_match_node(atmel_ebi_csa_regmap_of_ids, np); if (!match) { of_node_put(np); return 0; } - nc->matrix = syscon_node_to_regmap(np); + nc->ebi_csa_regmap = syscon_node_to_regmap(np); of_node_put(np); - if (IS_ERR(nc->matrix)) { - ret = PTR_ERR(nc->matrix); - dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret); + if (IS_ERR(nc->ebi_csa_regmap)) { + ret = PTR_ERR(nc->ebi_csa_regmap); + dev_err(dev, "Could not get EBICSA regmap (err = %d)\n", ret); return ret; } - nc->ebi_csa_offs = (uintptr_t)match->data; + nc->ebi_csa = (struct atmel_smc_nand_ebi_csa_cfg *)match->data; /* * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1 - * add 4 to ->ebi_csa_offs. + * add 4 to ->ebi_csa->offs. */ if (of_device_is_compatible(dev->parent->of_node, "atmel,at91sam9263-ebi1")) - nc->ebi_csa_offs += 4; + nc->ebi_csa->offs += 4; return 0; } @@ -2229,6 +2312,9 @@ return ret; hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base); + regmap_write(hsmc_nc->base.smc, ATMEL_HSMC_NFC_CTRL, + ATMEL_HSMC_NFC_CTRL_DIS); + if (hsmc_nc->sram.pool) gen_pool_free(hsmc_nc->sram.pool, (unsigned long)hsmc_nc->sram.virt, @@ -2281,6 +2367,8 @@ /* Initial NFC configuration. */ regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG, ATMEL_HSMC_NFC_CFG_DTO_MAX); + regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL, + ATMEL_HSMC_NFC_CTRL_EN); ret = atmel_nand_controller_add_nands(&nc->base); if (ret) @@ -2298,8 +2386,9 @@ .probe = atmel_hsmc_nand_controller_probe, .remove = atmel_hsmc_nand_controller_remove, .ecc_init = atmel_hsmc_nand_ecc_init, - .nand_init = atmel_hsmc_nand_init, - .setup_data_interface = atmel_hsmc_nand_setup_data_interface, + .nand_init = atmel_nand_init, + .setup_interface = atmel_hsmc_nand_setup_interface, + .exec_op = atmel_hsmc_nand_exec_op, }; static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = { @@ -2356,21 +2445,23 @@ /* * The SMC reg layout of at91rm9200 is completely different which prevents us - * from re-using atmel_smc_nand_setup_data_interface() for the - * ->setup_data_interface() hook. + * from re-using atmel_smc_nand_setup_interface() for the + * ->setup_interface() hook. * At this point, there's no support for the at91rm9200 SMC IP, so we leave - * ->setup_data_interface() unassigned. + * ->setup_interface() unassigned. */ static const struct atmel_nand_controller_ops at91rm9200_nc_ops = { .probe = atmel_smc_nand_controller_probe, .remove = atmel_smc_nand_controller_remove, .ecc_init = atmel_nand_ecc_init, .nand_init = atmel_smc_nand_init, + .exec_op = atmel_smc_nand_exec_op, }; static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = { .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &at91rm9200_nc_ops, }; @@ -2379,18 +2470,21 @@ .remove = atmel_smc_nand_controller_remove, .ecc_init = atmel_nand_ecc_init, .nand_init = atmel_smc_nand_init, - .setup_data_interface = atmel_smc_nand_setup_data_interface, + .setup_interface = atmel_smc_nand_setup_interface, + .exec_op = atmel_smc_nand_exec_op, }; static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = { .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &atmel_smc_nc_ops, }; static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = { .ale_offs = BIT(22), .cle_offs = BIT(21), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &atmel_smc_nc_ops, }; @@ -2398,6 +2492,15 @@ .has_dma = true, .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", + .ops = &atmel_smc_nc_ops, +}; + +static const struct atmel_nand_controller_caps microchip_sam9x60_nc_caps = { + .has_dma = true, + .ale_offs = BIT(21), + .cle_offs = BIT(22), + .ebi_csa_regmap_name = "microchip,sfr", .ops = &atmel_smc_nc_ops, }; @@ -2445,6 +2548,10 @@ .compatible = "atmel,sama5d3-nand-controller", .data = &atmel_sama5_nc_caps, }, + { + .compatible = "microchip,sam9x60-nand-controller", + .data = µchip_sam9x60_nc_caps, + }, /* Support for old/deprecated bindings: */ { .compatible = "atmel,at91rm9200-nand", -- Gitblit v1.6.2