From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/mtd/nand/raw/gpio.c | 148 ++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 115 insertions(+), 33 deletions(-) diff --git a/kernel/drivers/mtd/nand/raw/gpio.c b/kernel/drivers/mtd/nand/raw/gpio.c index 0e7d00f..fdf073d 100644 --- a/kernel/drivers/mtd/nand/raw/gpio.c +++ b/kernel/drivers/mtd/nand/raw/gpio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Updated, and converted to generic GPIO based driver by Russell King. * @@ -9,11 +10,6 @@ * Device driver for NAND flash that uses a memory mapped interface to * read/write the NAND commands and data, and GPIO pins for control signals * (the DT binding refers to this as "GPIO assisted NAND flash") - * - * 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. - * */ #include <linux/kernel.h> @@ -29,8 +25,11 @@ #include <linux/mtd/nand-gpio.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/delay.h> struct gpiomtd { + struct nand_controller base; + void __iomem *io; void __iomem *io_sync; struct nand_chip nand_chip; struct gpio_nand_platdata plat; @@ -73,32 +72,108 @@ static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} #endif -static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static int gpio_nand_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) { - struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); + unsigned int i; - gpio_nand_dosync(gpiomtd); - - if (ctrl & NAND_CTRL_CHANGE) { - if (gpiomtd->nce) - gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE)); - gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE)); - gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE)); + switch (instr->type) { + case NAND_OP_CMD_INSTR: gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->cle, 1); + gpio_nand_dosync(gpiomtd); + writeb(instr->ctx.cmd.opcode, gpiomtd->io); + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->cle, 0); + return 0; + + case NAND_OP_ADDR_INSTR: + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->ale, 1); + gpio_nand_dosync(gpiomtd); + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb(instr->ctx.addr.addrs[i], gpiomtd->io); + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->ale, 0); + return 0; + + case NAND_OP_DATA_IN_INSTR: + gpio_nand_dosync(gpiomtd); + if ((chip->options & NAND_BUSWIDTH_16) && + !instr->ctx.data.force_8bit) + ioread16_rep(gpiomtd->io, instr->ctx.data.buf.in, + instr->ctx.data.len / 2); + else + ioread8_rep(gpiomtd->io, instr->ctx.data.buf.in, + instr->ctx.data.len); + return 0; + + case NAND_OP_DATA_OUT_INSTR: + gpio_nand_dosync(gpiomtd); + if ((chip->options & NAND_BUSWIDTH_16) && + !instr->ctx.data.force_8bit) + iowrite16_rep(gpiomtd->io, instr->ctx.data.buf.out, + instr->ctx.data.len / 2); + else + iowrite8_rep(gpiomtd->io, instr->ctx.data.buf.out, + instr->ctx.data.len); + return 0; + + case NAND_OP_WAITRDY_INSTR: + if (!gpiomtd->rdy) + return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); + + return nand_gpio_waitrdy(chip, gpiomtd->rdy, + instr->ctx.waitrdy.timeout_ms); + + default: + return -EINVAL; } - if (cmd == NAND_CMD_NONE) - return; - writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W); - gpio_nand_dosync(gpiomtd); + return 0; } -static int gpio_nand_devready(struct mtd_info *mtd) +static int gpio_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) { - struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); + unsigned int i; + int ret = 0; - return gpiod_get_value(gpiomtd->rdy); + if (check_only) + return 0; + + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->nce, 0); + for (i = 0; i < op->ninstrs; i++) { + ret = gpio_nand_exec_instr(chip, &op->instrs[i]); + if (ret) + break; + + if (op->instrs[i].delay_ns) + ndelay(op->instrs[i].delay_ns); + } + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->nce, 1); + + return ret; } + +static int gpio_nand_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT && + chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops gpio_nand_ops = { + .exec_op = gpio_nand_exec_op, + .attach_chip = gpio_nand_attach_chip, +}; #ifdef CONFIG_OF static const struct of_device_id gpio_nand_id_table[] = { @@ -193,8 +268,12 @@ static int gpio_nand_remove(struct platform_device *pdev) { struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); + struct nand_chip *chip = &gpiomtd->nand_chip; + int ret; - nand_release(&gpiomtd->nand_chip); + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); /* Enable write protection and disable the chip */ if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) @@ -224,9 +303,9 @@ chip = &gpiomtd->nand_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->IO_ADDR_R = devm_ioremap_resource(dev, res); - if (IS_ERR(chip->IO_ADDR_R)) - return PTR_ERR(chip->IO_ADDR_R); + gpiomtd->io = devm_ioremap_resource(dev, res); + if (IS_ERR(gpiomtd->io)) + return PTR_ERR(gpiomtd->io); res = gpio_nand_get_io_sync(pdev); if (res) { @@ -268,17 +347,13 @@ ret = PTR_ERR(gpiomtd->rdy); goto out_ce; } - /* Using RDY pin */ - if (gpiomtd->rdy) - chip->dev_ready = gpio_nand_devready; + + nand_controller_init(&gpiomtd->base); + gpiomtd->base.ops = &gpio_nand_ops; nand_set_flash_node(chip, pdev->dev.of_node); - chip->IO_ADDR_W = chip->IO_ADDR_R; - chip->ecc.mode = NAND_ECC_SOFT; - chip->ecc.algo = NAND_ECC_HAMMING; chip->options = gpiomtd->plat.options; - chip->chip_delay = gpiomtd->plat.chip_delay; - chip->cmd_ctrl = gpio_nand_cmd_ctrl; + chip->controller = &gpiomtd->base; mtd = nand_to_mtd(chip); mtd->dev.parent = dev; @@ -289,6 +364,13 @@ if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) gpiod_direction_output(gpiomtd->nwp, 1); + /* + * This driver assumes that the default ECC engine should be TYPE_SOFT. + * Set ->engine_type before registering the NAND devices in order to + * provide a driver specific default value. + */ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + ret = nand_scan(chip, 1); if (ret) goto err_wp; -- Gitblit v1.6.2