Merge branch 'for-v4.7/gpmc-mtd-common' of github.com:rogerq/linux into nand/next

Pull NAND/GPMC updates from Roger Quadros:
 "We do a couple of things in this series which result in cleaner device
  tree implementation, faster perfomance and multi-platform support. As
  an added bonus we get to use the GPMC_WAIT pins as GPI/Interrupts.

  - Establish a custom interface between NAND and GPMC driver. This is
    needed because all of the NAND registers sit in the GPMC register
    space.

  - Clean up device tree support so that omap-gpmc IP and the omap2 NAND
    driver can be used on non-OMAP platforms. e.g. Keystone.

  - Implement GPIOCHIP for the GPMC WAITPINS. SoCs can contain 2 to 4 of
    these and most of them would be unused otherwise. It also allows a
    cleaner implementation of NAND Ready pin status for the NAND driver.

  - Implement GPMC IRQ domain to proivde the 2 NAND events and GPMC
    WAITPIN edge interrupts.

  - Implement GPIOlib based NAND ready pin checking for OMAP NAND driver.
    On dra7-evm, Read speed increases from 13768 KiB/ to 17246 KiB/s.
    Write speed was unchanged at 7123 KiB/s."

* 'for-v4.7/gpmc-mtd-common' of github.com:rogerq/linux:
  mtd: nand: omap2: Implement NAND ready using gpiolib
  memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs
  memory: omap-gpmc: Support WAIT pin edge interrupts
  memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring
  memory: omap-gpmc: Support general purpose input for WAITPINs
  memory: omap-gpmc: Move device tree binding to correct location
  memory: omap-gpmc: Prevent mapping into 1st 16MB
  mtd: nand: omap: Update DT binding documentation
  mtd: nand: omap: Clean up device tree support
  mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  mtd: nand: omap: Switch to using GPMC-NAND ops for writebuffer empty check
  mtd: nand: omap: Use gpmc_omap_get_nand_ops() to get NAND registers
  memory: omap-gpmc: Implement IRQ domain for NAND IRQs
  memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status
  memory: omap-gpmc: Introduce GPMC to NAND interface
  ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  ARM: OMAP2+: gpmc: Add platform data
This commit is contained in:
Boris Brezillon 2016-04-19 21:39:22 +02:00
commit 4217ff3509
9 changed files with 821 additions and 436 deletions

View File

@ -32,6 +32,19 @@ Required properties:
bootloader) are used for the physical address decoding.
As this will change in the future, filling correct
values here is a requirement.
- interrupt-controller: The GPMC driver implements and interrupt controller for
the NAND events "fifoevent" and "termcount" plus the
rising/falling edges on the GPMC_WAIT pins.
The interrupt number mapping is as follows
0 - NAND_fifoevent
1 - NAND_termcount
2 - GPMC_WAIT0 pin edge
3 - GPMC_WAIT1 pin edge, and so on.
- interrupt-cells: Must be set to 2
- gpio-controller: The GPMC driver implements a GPIO controller for the
GPMC WAIT pins that can be used as general purpose inputs.
0 maps to GPMC_WAIT0 pin.
- gpio-cells: Must be set to 2
Timing properties for child nodes. All are optional and default to 0.
@ -130,6 +143,10 @@ Example for an AM33xx board:
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
/* child nodes go here */
};

View File

@ -13,7 +13,11 @@ Documentation/devicetree/bindings/mtd/nand.txt
Required properties:
- reg: The CS line the peripheral is connected to
- compatible: "ti,omap2-nand"
- reg: range id (CS number), base offset and length of the
NAND I/O space
- interrupt-parent: must point to gpmc node
- interrupts: Two interrupt specifiers, one for fifoevent, one for termcount.
Optional properties:
@ -44,6 +48,7 @@ Optional properties:
locating ECC errors for BCHx algorithms. SoC devices which have
ELM hardware engines should specify this device node in .dtsi
Using ELM for ECC error correction frees some CPU cycles.
- rb-gpios: GPIO specifier for the ready/busy# pin.
For inline partition table parsing (optional):
@ -55,20 +60,26 @@ Example for an AM33xx board:
gpmc: gpmc@50000000 {
compatible = "ti,am3352-gpmc";
ti,hwmods = "gpmc";
reg = <0x50000000 0x1000000>;
reg = <0x50000000 0x36c>;
interrupts = <100>;
gpmc,num-cs = <8>;
gpmc,num-waitpins = <2>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
ranges = <0 0 0x08000000 0x1000000>; /* CS0 space, 16MB */
elm_id = <&elm>;
interrupt-controller;
#interrupt-cells = <2>;
nand@0,0 {
reg = <0 0 0>; /* CS0, offset 0 */
compatible = "ti,omap2-nand";
reg = <0 0 4>; /* CS0, offset 0, NAND I/O window 4 */
interrupt-parent = <&gpmc>;
interrupts = <0 IRQ_TYPE_NONE>, <1 IRQ_TYPE NONE>;
nand-bus-width = <16>;
ti,nand-ecc-opt = "bch8";
ti,nand-xfer-type = "polled";
rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */
gpmc,sync-clk-ps = <0>;
gpmc,cs-on-ns = <0>;

View File

@ -97,10 +97,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
memset(&s, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data->of_node)
gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
else
gpmc_set_legacy(gpmc_nand_data, &s);
gpmc_set_legacy(gpmc_nand_data, &s);
s.device_nand = true;
@ -121,8 +118,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
if (err < 0)
goto out_free_cs;
gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
pr_err("omap2-nand: Unsupported NAND ECC scheme selected\n");
err = -EINVAL;

View File

@ -51,6 +51,7 @@ config TI_EMIF
config OMAP_GPMC
bool
select GPIOLIB
help
This driver is for the General Purpose Memory Controller (GPMC)
present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows

View File

@ -21,7 +21,9 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
@ -29,7 +31,6 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/omap-gpmc.h>
#include <linux/mtd/nand.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mtd-nand-omap2.h>
@ -81,6 +82,8 @@
#define GPMC_CONFIG_LIMITEDADDRESS BIT(1)
#define GPMC_STATUS_EMPTYWRITEBUFFERSTATUS BIT(0)
#define GPMC_CONFIG2_CSEXTRADELAY BIT(7)
#define GPMC_CONFIG3_ADVEXTRADELAY BIT(7)
#define GPMC_CONFIG4_OEEXTRADELAY BIT(7)
@ -92,6 +95,14 @@
#define GPMC_CS_SIZE 0x30
#define GPMC_BCH_SIZE 0x10
/*
* The first 1MB of GPMC address space is typically mapped to
* the internal ROM. Never allocate the first page, to
* facilitate bug detection; even if we didn't boot from ROM.
* As GPMC minimum partition size is 16MB we can only start from
* there.
*/
#define GPMC_MEM_START 0x1000000
#define GPMC_MEM_END 0x3FFFFFFF
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
@ -125,7 +136,6 @@
#define GPMC_CONFIG_RDY_BSY 0x00000001
#define GPMC_CONFIG_DEV_SIZE 0x00000002
#define GPMC_CONFIG_DEV_TYPE 0x00000003
#define GPMC_SET_IRQ_STATUS 0x00000004
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
@ -174,16 +184,12 @@
#define GPMC_CONFIG_WRITEPROTECT 0x00000010
#define WR_RD_PIN_MONITORING 0x00600000
#define GPMC_ENABLE_IRQ 0x0000000d
/* ECC commands */
#define GPMC_ECC_READ 0 /* Reset Hardware ECC for read */
#define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
#define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */
/* XXX: Only NAND irq has been considered,currently these are the only ones used
*/
#define GPMC_NR_IRQ 2
#define GPMC_NR_NAND_IRQS 2 /* number of NAND specific IRQs */
enum gpmc_clk_domain {
GPMC_CD_FCLK,
@ -199,11 +205,6 @@ struct gpmc_cs_data {
struct resource mem;
};
struct gpmc_client_irq {
unsigned irq;
u32 bitmask;
};
/* Structure to save gpmc cs context */
struct gpmc_cs_config {
u32 config1;
@ -231,9 +232,15 @@ struct omap3_gpmc_regs {
struct gpmc_cs_config cs_context[GPMC_CS_NUM];
};
static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
static struct irq_chip gpmc_irq_chip;
static int gpmc_irq_start;
struct gpmc_device {
struct device *dev;
int irq;
struct irq_chip irq_chip;
struct gpio_chip gpio_chip;
int nirqs;
};
static struct irq_domain *gpmc_irq_domain;
static struct resource gpmc_mem_root;
static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
@ -241,8 +248,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
/* Define chip-selects as reserved by default until probe completes */
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
static unsigned int gpmc_nr_waitpins;
static struct device *gpmc_dev;
static int gpmc_irq;
static resource_size_t phys_base, mem_size;
static unsigned gpmc_capability;
static void __iomem *gpmc_base;
@ -1054,14 +1059,6 @@ int gpmc_configure(int cmd, int wval)
u32 regval;
switch (cmd) {
case GPMC_ENABLE_IRQ:
gpmc_write_reg(GPMC_IRQENABLE, wval);
break;
case GPMC_SET_IRQ_STATUS:
gpmc_write_reg(GPMC_IRQSTATUS, wval);
break;
case GPMC_CONFIG_WP:
regval = gpmc_read_reg(GPMC_CONFIG);
if (wval)
@ -1084,7 +1081,7 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
{
int i;
reg->gpmc_status = gpmc_base + GPMC_STATUS;
reg->gpmc_status = NULL; /* deprecated */
reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
@ -1118,87 +1115,201 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
}
}
int gpmc_get_client_irq(unsigned irq_config)
static bool gpmc_nand_writebuffer_empty(void)
{
int i;
if (gpmc_read_reg(GPMC_STATUS) & GPMC_STATUS_EMPTYWRITEBUFFERSTATUS)
return true;
if (hweight32(irq_config) > 1)
return 0;
for (i = 0; i < GPMC_NR_IRQ; i++)
if (gpmc_client_irq[i].bitmask & irq_config)
return gpmc_client_irq[i].irq;
return 0;
return false;
}
static int gpmc_irq_endis(unsigned irq, bool endis)
static struct gpmc_nand_ops nand_ops = {
.nand_writebuffer_empty = gpmc_nand_writebuffer_empty,
};
/**
* gpmc_omap_get_nand_ops - Get the GPMC NAND interface
* @regs: the GPMC NAND register map exclusive for NAND use.
* @cs: GPMC chip select number on which the NAND sits. The
* register map returned will be specific to this chip select.
*
* Returns NULL on error e.g. invalid cs.
*/
struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
{
if (cs >= gpmc_cs_num)
return NULL;
gpmc_update_nand_reg(reg, cs);
return &nand_ops;
}
EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
int gpmc_get_client_irq(unsigned irq_config)
{
if (!gpmc_irq_domain) {
pr_warn("%s called before GPMC IRQ domain available\n",
__func__);
return 0;
}
/* we restrict this to NAND IRQs only */
if (irq_config >= GPMC_NR_NAND_IRQS)
return 0;
return irq_create_mapping(gpmc_irq_domain, irq_config);
}
static int gpmc_irq_endis(unsigned long hwirq, bool endis)
{
int i;
u32 regval;
for (i = 0; i < GPMC_NR_IRQ; i++)
if (irq == gpmc_client_irq[i].irq) {
regval = gpmc_read_reg(GPMC_IRQENABLE);
if (endis)
regval |= gpmc_client_irq[i].bitmask;
else
regval &= ~gpmc_client_irq[i].bitmask;
gpmc_write_reg(GPMC_IRQENABLE, regval);
break;
}
/* bits GPMC_NR_NAND_IRQS to 8 are reserved */
if (hwirq >= GPMC_NR_NAND_IRQS)
hwirq += 8 - GPMC_NR_NAND_IRQS;
regval = gpmc_read_reg(GPMC_IRQENABLE);
if (endis)
regval |= BIT(hwirq);
else
regval &= ~BIT(hwirq);
gpmc_write_reg(GPMC_IRQENABLE, regval);
return 0;
}
static void gpmc_irq_disable(struct irq_data *p)
{
gpmc_irq_endis(p->irq, false);
gpmc_irq_endis(p->hwirq, false);
}
static void gpmc_irq_enable(struct irq_data *p)
{
gpmc_irq_endis(p->irq, true);
gpmc_irq_endis(p->hwirq, true);
}
static void gpmc_irq_noop(struct irq_data *data) { }
static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
static int gpmc_setup_irq(void)
static void gpmc_irq_mask(struct irq_data *d)
{
gpmc_irq_endis(d->hwirq, false);
}
static void gpmc_irq_unmask(struct irq_data *d)
{
gpmc_irq_endis(d->hwirq, true);
}
static void gpmc_irq_edge_config(unsigned long hwirq, bool rising_edge)
{
int i;
u32 regval;
if (!gpmc_irq)
/* NAND IRQs polarity is not configurable */
if (hwirq < GPMC_NR_NAND_IRQS)
return;
/* WAITPIN starts at BIT 8 */
hwirq += 8 - GPMC_NR_NAND_IRQS;
regval = gpmc_read_reg(GPMC_CONFIG);
if (rising_edge)
regval &= ~BIT(hwirq);
else
regval |= BIT(hwirq);
gpmc_write_reg(GPMC_CONFIG, regval);
}
static void gpmc_irq_ack(struct irq_data *d)
{
unsigned int hwirq = d->hwirq;
/* skip reserved bits */
if (hwirq >= GPMC_NR_NAND_IRQS)
hwirq += 8 - GPMC_NR_NAND_IRQS;
/* Setting bit to 1 clears (or Acks) the interrupt */
gpmc_write_reg(GPMC_IRQSTATUS, BIT(hwirq));
}
static int gpmc_irq_set_type(struct irq_data *d, unsigned int trigger)
{
/* can't set type for NAND IRQs */
if (d->hwirq < GPMC_NR_NAND_IRQS)
return -EINVAL;
gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
if (gpmc_irq_start < 0) {
pr_err("irq_alloc_descs failed\n");
return gpmc_irq_start;
/* We can support either rising or falling edge at a time */
if (trigger == IRQ_TYPE_EDGE_FALLING)
gpmc_irq_edge_config(d->hwirq, false);
else if (trigger == IRQ_TYPE_EDGE_RISING)
gpmc_irq_edge_config(d->hwirq, true);
else
return -EINVAL;
return 0;
}
static int gpmc_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
struct gpmc_device *gpmc = d->host_data;
irq_set_chip_data(virq, gpmc);
if (hw < GPMC_NR_NAND_IRQS) {
irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
irq_set_chip_and_handler(virq, &gpmc->irq_chip,
handle_simple_irq);
} else {
irq_set_chip_and_handler(virq, &gpmc->irq_chip,
handle_edge_irq);
}
gpmc_irq_chip.name = "gpmc";
gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
gpmc_irq_chip.irq_enable = gpmc_irq_enable;
gpmc_irq_chip.irq_disable = gpmc_irq_disable;
gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
gpmc_irq_chip.irq_ack = gpmc_irq_noop;
gpmc_irq_chip.irq_mask = gpmc_irq_noop;
gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
return 0;
}
gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
static const struct irq_domain_ops gpmc_irq_domain_ops = {
.map = gpmc_irq_map,
.xlate = irq_domain_xlate_twocell,
};
for (i = 0; i < GPMC_NR_IRQ; i++) {
gpmc_client_irq[i].irq = gpmc_irq_start + i;
irq_set_chip_and_handler(gpmc_client_irq[i].irq,
&gpmc_irq_chip, handle_simple_irq);
irq_modify_status(gpmc_client_irq[i].irq, IRQ_NOREQUEST,
IRQ_NOAUTOEN);
static irqreturn_t gpmc_handle_irq(int irq, void *data)
{
int hwirq, virq;
u32 regval, regvalx;
struct gpmc_device *gpmc = data;
regval = gpmc_read_reg(GPMC_IRQSTATUS);
regvalx = regval;
if (!regval)
return IRQ_NONE;
for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++) {
/* skip reserved status bits */
if (hwirq == GPMC_NR_NAND_IRQS)
regvalx >>= 8 - GPMC_NR_NAND_IRQS;
if (regvalx & BIT(hwirq)) {
virq = irq_find_mapping(gpmc_irq_domain, hwirq);
if (!virq) {
dev_warn(gpmc->dev,
"spurious irq detected hwirq %d, virq %d\n",
hwirq, virq);
}
generic_handle_irq(virq);
}
}
gpmc_write_reg(GPMC_IRQSTATUS, regval);
return IRQ_HANDLED;
}
static int gpmc_setup_irq(struct gpmc_device *gpmc)
{
u32 regval;
int rc;
/* Disable interrupts */
gpmc_write_reg(GPMC_IRQENABLE, 0);
@ -1206,22 +1317,45 @@ static int gpmc_setup_irq(void)
regval = gpmc_read_reg(GPMC_IRQSTATUS);
gpmc_write_reg(GPMC_IRQSTATUS, regval);
return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
}
gpmc->irq_chip.name = "gpmc";
gpmc->irq_chip.irq_enable = gpmc_irq_enable;
gpmc->irq_chip.irq_disable = gpmc_irq_disable;
gpmc->irq_chip.irq_ack = gpmc_irq_ack;
gpmc->irq_chip.irq_mask = gpmc_irq_mask;
gpmc->irq_chip.irq_unmask = gpmc_irq_unmask;
gpmc->irq_chip.irq_set_type = gpmc_irq_set_type;
static int gpmc_free_irq(void)
{
int i;
if (gpmc_irq)
free_irq(gpmc_irq, NULL);
for (i = 0; i < GPMC_NR_IRQ; i++) {
irq_set_handler(gpmc_client_irq[i].irq, NULL);
irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node,
gpmc->nirqs,
&gpmc_irq_domain_ops,
gpmc);
if (!gpmc_irq_domain) {
dev_err(gpmc->dev, "IRQ domain add failed\n");
return -ENODEV;
}
irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
rc = request_irq(gpmc->irq, gpmc_handle_irq, 0, "gpmc", gpmc);
if (rc) {
dev_err(gpmc->dev, "failed to request irq %d: %d\n",
gpmc->irq, rc);
irq_domain_remove(gpmc_irq_domain);
gpmc_irq_domain = NULL;
}
return rc;
}
static int gpmc_free_irq(struct gpmc_device *gpmc)
{
int hwirq;
free_irq(gpmc->irq, gpmc);
for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++)
irq_dispose_mapping(irq_find_mapping(gpmc_irq_domain, hwirq));
irq_domain_remove(gpmc_irq_domain);
gpmc_irq_domain = NULL;
return 0;
}
@ -1242,12 +1376,7 @@ static void gpmc_mem_init(void)
{
int cs;
/*
* The first 1MB of GPMC address space is typically mapped to
* the internal ROM. Never allocate the first page, to
* facilitate bug detection; even if we didn't boot from ROM.
*/
gpmc_mem_root.start = SZ_1M;
gpmc_mem_root.start = GPMC_MEM_START;
gpmc_mem_root.end = GPMC_MEM_END;
/* Reserve all regions that has been set up by bootloader */
@ -1796,105 +1925,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
of_property_read_bool(np, "gpmc,time-para-granularity");
}
#if IS_ENABLED(CONFIG_MTD_NAND)
static const char * const nand_xfer_types[] = {
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
[NAND_OMAP_POLLED] = "polled",
[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
};
static int gpmc_probe_nand_child(struct platform_device *pdev,
struct device_node *child)
{
u32 val;
const char *s;
struct gpmc_timings gpmc_t;
struct omap_nand_platform_data *gpmc_nand_data;
if (of_property_read_u32(child, "reg", &val) < 0) {
dev_err(&pdev->dev, "%s has no 'reg' property\n",
child->full_name);
return -ENODEV;
}
gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
GFP_KERNEL);
if (!gpmc_nand_data)
return -ENOMEM;
gpmc_nand_data->cs = val;
gpmc_nand_data->of_node = child;
/* Detect availability of ELM module */
gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
if (gpmc_nand_data->elm_of_node == NULL)
gpmc_nand_data->elm_of_node =
of_parse_phandle(child, "elm_id", 0);
/* select ecc-scheme for NAND */
if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
return -ENODEV;
}
if (!strcmp(s, "sw"))
gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
else if (!strcmp(s, "ham1") ||
!strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
gpmc_nand_data->ecc_opt =
OMAP_ECC_HAM1_CODE_HW;
else if (!strcmp(s, "bch4"))
if (gpmc_nand_data->elm_of_node)
gpmc_nand_data->ecc_opt =
OMAP_ECC_BCH4_CODE_HW;
else
gpmc_nand_data->ecc_opt =
OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
else if (!strcmp(s, "bch8"))
if (gpmc_nand_data->elm_of_node)
gpmc_nand_data->ecc_opt =
OMAP_ECC_BCH8_CODE_HW;
else
gpmc_nand_data->ecc_opt =
OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
else if (!strcmp(s, "bch16"))
if (gpmc_nand_data->elm_of_node)
gpmc_nand_data->ecc_opt =
OMAP_ECC_BCH16_CODE_HW;
else
pr_err("%s: BCH16 requires ELM support\n", __func__);
else
pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
/* select data transfer mode for NAND controller */
if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
if (!strcasecmp(s, nand_xfer_types[val])) {
gpmc_nand_data->xfer_type = val;
break;
}
gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
val = of_get_nand_bus_width(child);
if (val == 16)
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
gpmc_read_timings_dt(child, &gpmc_t);
gpmc_nand_init(gpmc_nand_data, &gpmc_t);
return 0;
}
#else
static int gpmc_probe_nand_child(struct platform_device *pdev,
struct device_node *child)
{
return 0;
}
#endif
#if IS_ENABLED(CONFIG_MTD_ONENAND)
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
@ -1950,6 +1980,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
const char *name;
int ret, cs;
u32 val;
struct gpio_desc *waitpin_desc = NULL;
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
if (of_property_read_u32(child, "reg", &cs) < 0) {
dev_err(&pdev->dev, "%s has no 'reg' property\n",
@ -2010,23 +2042,79 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
if (ret < 0) {
dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
cs, &res.start);
if (res.start < GPMC_MEM_START) {
dev_info(&pdev->dev,
"GPMC CS %d start cannot be lesser than 0x%x\n",
cs, GPMC_MEM_START);
} else if (res.end > GPMC_MEM_END) {
dev_info(&pdev->dev,
"GPMC CS %d end cannot be greater than 0x%x\n",
cs, GPMC_MEM_END);
}
goto err;
}
ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
if (ret < 0)
goto err;
if (of_node_cmp(child->name, "nand") == 0) {
/* Warn about older DT blobs with no compatible property */
if (!of_property_read_bool(child, "compatible")) {
dev_warn(&pdev->dev,
"Incompatible NAND node: missing compatible");
ret = -EINVAL;
goto err;
}
}
if (of_device_is_compatible(child, "ti,omap2-nand")) {
/* NAND specific setup */
val = of_get_nand_bus_width(child);
switch (val) {
case 8:
gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
break;
case 16:
gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
break;
default:
dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
child->name);
ret = -EINVAL;
goto err;
}
/* disable write protect */
gpmc_configure(GPMC_CONFIG_WP, 0);
gpmc_s.device_nand = true;
} else {
ret = of_property_read_u32(child, "bank-width",
&gpmc_s.device_width);
if (ret < 0)
goto err;
}
/* Reserve wait pin if it is required and valid */
if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
unsigned int wait_pin = gpmc_s.wait_pin;
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
wait_pin, "WAITPIN");
if (IS_ERR(waitpin_desc)) {
dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
ret = PTR_ERR(waitpin_desc);
goto err;
}
}
gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
ret = gpmc_cs_program_settings(cs, &gpmc_s);
if (ret < 0)
goto err;
goto err_cs;
ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
if (ret) {
dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
child->name);
goto err;
goto err_cs;
}
/* Clear limited address i.e. enable A26-A11 */
@ -2057,16 +2145,81 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
ret = -ENODEV;
err_cs:
if (waitpin_desc)
gpiochip_free_own_desc(waitpin_desc);
err:
gpmc_cs_free(cs);
return ret;
}
static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
return 1; /* we're input only */
}
static int gpmc_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
return 0; /* we're input only */
}
static int gpmc_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
return -EINVAL; /* we're input only */
}
static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
}
static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
u32 reg;
offset += 8;
reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
return !!reg;
}
static int gpmc_gpio_init(struct gpmc_device *gpmc)
{
int ret;
gpmc->gpio_chip.parent = gpmc->dev;
gpmc->gpio_chip.owner = THIS_MODULE;
gpmc->gpio_chip.label = DEVICE_NAME;
gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
gpmc->gpio_chip.set = gpmc_gpio_set;
gpmc->gpio_chip.get = gpmc_gpio_get;
gpmc->gpio_chip.base = -1;
ret = gpiochip_add(&gpmc->gpio_chip);
if (ret < 0) {
dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
return ret;
}
return 0;
}
static void gpmc_gpio_exit(struct gpmc_device *gpmc)
{
gpiochip_remove(&gpmc->gpio_chip);
}
static int gpmc_probe_dt(struct platform_device *pdev)
{
int ret;
struct device_node *child;
const struct of_device_id *of_id =
of_match_device(gpmc_dt_ids, &pdev->dev);
@ -2094,17 +2247,26 @@ static int gpmc_probe_dt(struct platform_device *pdev)
return ret;
}
return 0;
}
static int gpmc_probe_dt_children(struct platform_device *pdev)
{
int ret;
struct device_node *child;
for_each_available_child_of_node(pdev->dev.of_node, child) {
if (!child->name)
continue;
if (of_node_cmp(child->name, "nand") == 0)
ret = gpmc_probe_nand_child(pdev, child);
else if (of_node_cmp(child->name, "onenand") == 0)
if (of_node_cmp(child->name, "onenand") == 0)
ret = gpmc_probe_onenand_child(pdev, child);
else
ret = gpmc_probe_generic_child(pdev, child);
if (ret)
return ret;
}
return 0;
@ -2114,6 +2276,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
{
return 0;
}
static int gpmc_probe_dt_children(struct platform_device *pdev)
{
return 0;
}
#endif
static int gpmc_probe(struct platform_device *pdev)
@ -2121,6 +2288,14 @@ static int gpmc_probe(struct platform_device *pdev)
int rc;
u32 l;
struct resource *res;
struct gpmc_device *gpmc;
gpmc = devm_kzalloc(&pdev->dev, sizeof(*gpmc), GFP_KERNEL);
if (!gpmc)
return -ENOMEM;
gpmc->dev = &pdev->dev;
platform_set_drvdata(pdev, gpmc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
@ -2134,15 +2309,16 @@ static int gpmc_probe(struct platform_device *pdev)
return PTR_ERR(gpmc_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL)
dev_warn(&pdev->dev, "Failed to get resource: irq\n");
else
gpmc_irq = res->start;
if (!res) {
dev_err(&pdev->dev, "Failed to get resource: irq\n");
return -ENOENT;
}
gpmc->irq = res->start;
gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(gpmc_l3_clk)) {
dev_err(&pdev->dev, "Failed to get GPMC fck\n");
gpmc_irq = 0;
return PTR_ERR(gpmc_l3_clk);
}
@ -2151,11 +2327,18 @@ static int gpmc_probe(struct platform_device *pdev)
return -EINVAL;
}
if (pdev->dev.of_node) {
rc = gpmc_probe_dt(pdev);
if (rc)
return rc;
} else {
gpmc_cs_num = GPMC_CS_NUM;
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
}
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
gpmc_dev = &pdev->dev;
l = gpmc_read_reg(GPMC_REVISION);
/*
@ -2174,36 +2357,51 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
if (GPMC_REVISION_MAJOR(l) > 0x5)
gpmc_capability |= GPMC_HAS_MUX_AAD;
dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
dev_info(gpmc->dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
GPMC_REVISION_MINOR(l));
gpmc_mem_init();
rc = gpmc_gpio_init(gpmc);
if (rc)
goto gpio_init_failed;
if (gpmc_setup_irq() < 0)
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
if (!pdev->dev.of_node) {
gpmc_cs_num = GPMC_CS_NUM;
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
gpmc->nirqs = GPMC_NR_NAND_IRQS + gpmc_nr_waitpins;
rc = gpmc_setup_irq(gpmc);
if (rc) {
dev_err(gpmc->dev, "gpmc_setup_irq failed\n");
goto setup_irq_failed;
}
rc = gpmc_probe_dt(pdev);
rc = gpmc_probe_dt_children(pdev);
if (rc < 0) {
pm_runtime_put_sync(&pdev->dev);
dev_err(gpmc_dev, "failed to probe DT parameters\n");
return rc;
dev_err(gpmc->dev, "failed to probe DT children\n");
goto dt_children_failed;
}
return 0;
dt_children_failed:
gpmc_free_irq(gpmc);
setup_irq_failed:
gpmc_gpio_exit(gpmc);
gpio_init_failed:
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return rc;
}
static int gpmc_remove(struct platform_device *pdev)
{
gpmc_free_irq();
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
gpmc_free_irq(gpmc);
gpmc_gpio_exit(gpmc);
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
gpmc_dev = NULL;
return 0;
}
@ -2249,25 +2447,6 @@ static __exit void gpmc_exit(void)
postcore_initcall(gpmc_init);
module_exit(gpmc_exit);
static irqreturn_t gpmc_handle_irq(int irq, void *dev)
{
int i;
u32 regval;
regval = gpmc_read_reg(GPMC_IRQSTATUS);
if (!regval)
return IRQ_NONE;
for (i = 0; i < GPMC_NR_IRQ; i++)
if (regval & gpmc_client_irq[i].bitmask)
generic_handle_irq(gpmc_client_irq[i].irq);
gpmc_write_reg(GPMC_IRQSTATUS, regval);
return IRQ_HANDLED;
}
static struct omap3_gpmc_regs gpmc_context;
void omap3_gpmc_save_context(void)

View File

@ -12,6 +12,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
@ -24,10 +25,12 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mtd.h>
#include <linux/mtd/nand_bch.h>
#include <linux/platform_data/elm.h>
#include <linux/omap-gpmc.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#define DRIVER_NAME "omap2-nand"
@ -151,13 +154,17 @@ static struct nand_hw_control omap_gpmc_controller = {
};
struct omap_nand_info {
struct omap_nand_platform_data *pdata;
struct nand_chip nand;
struct platform_device *pdev;
int gpmc_cs;
unsigned long phys_base;
bool dev_ready;
enum nand_io xfer_type;
int devsize;
enum omap_ecc ecc_opt;
struct device_node *elm_of_node;
unsigned long phys_base;
struct completion comp;
struct dma_chan *dma;
int gpmc_irq_fifo;
@ -168,12 +175,16 @@ struct omap_nand_info {
} iomode;
u_char *buf;
int buf_len;
/* Interface to GPMC */
struct gpmc_nand_regs reg;
struct gpmc_nand_ops *ops;
bool flash_bbt;
/* generated at runtime depending on ECC algorithm and layout selected */
struct nand_ecclayout oobinfo;
/* fields specific for BCHx_HW ECC scheme */
struct device *elm_dev;
struct device_node *of_node;
/* NAND ready gpio */
struct gpio_desc *ready_gpiod;
};
static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@ -288,14 +299,13 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
{
struct omap_nand_info *info = mtd_to_omap(mtd);
u_char *p = (u_char *)buf;
u32 status = 0;
bool status;
while (len--) {
iowrite8(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = readl(info->reg.gpmc_status) &
STATUS_BUFF_EMPTY;
status = info->ops->nand_writebuffer_empty();
} while (!status);
}
}
@ -323,7 +333,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
{
struct omap_nand_info *info = mtd_to_omap(mtd);
u16 *p = (u16 *) buf;
u32 status = 0;
bool status;
/* FIXME try bursts of writesw() or DMA ... */
len >>= 1;
@ -331,8 +341,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
iowrite16(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = readl(info->reg.gpmc_status) &
STATUS_BUFF_EMPTY;
status = info->ops->nand_writebuffer_empty();
} while (!status);
}
}
@ -1017,21 +1026,16 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
}
/**
* omap_dev_ready - calls the platform specific dev_ready function
* omap_dev_ready - checks the NAND Ready GPIO line
* @mtd: MTD device structure
*
* Returns true if ready and false if busy.
*/
static int omap_dev_ready(struct mtd_info *mtd)
{
unsigned int val = 0;
struct omap_nand_info *info = mtd_to_omap(mtd);
val = readl(info->reg.gpmc_status);
if ((val & 0x100) == 0x100) {
return 1;
} else {
return 0;
}
return gpiod_get_value(info->ready_gpiod);
}
/**
@ -1630,7 +1634,7 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
return false;
}
if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) {
if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
dev_err(&info->pdev->dev, "ELM not available\n");
return false;
}
@ -1638,10 +1642,86 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
return true;
}
static const char * const nand_xfer_types[] = {
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
[NAND_OMAP_POLLED] = "polled",
[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
};
static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
{
struct device_node *child = dev->of_node;
int i;
const char *s;
u32 cs;
if (of_property_read_u32(child, "reg", &cs) < 0) {
dev_err(dev, "reg not found in DT\n");
return -EINVAL;
}
info->gpmc_cs = cs;
/* detect availability of ELM module. Won't be present pre-OMAP4 */
info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
if (!info->elm_of_node)
dev_dbg(dev, "ti,elm-id not in DT\n");
/* select ecc-scheme for NAND */
if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
dev_err(dev, "ti,nand-ecc-opt not found\n");
return -EINVAL;
}
if (!strcmp(s, "sw")) {
info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
} else if (!strcmp(s, "ham1") ||
!strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
info->ecc_opt = OMAP_ECC_HAM1_CODE_HW;
} else if (!strcmp(s, "bch4")) {
if (info->elm_of_node)
info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
else
info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
} else if (!strcmp(s, "bch8")) {
if (info->elm_of_node)
info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
else
info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
} else if (!strcmp(s, "bch16")) {
info->ecc_opt = OMAP_ECC_BCH16_CODE_HW;
} else {
dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
return -EINVAL;
}
/* select data transfer mode */
if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
if (!strcasecmp(s, nand_xfer_types[i])) {
info->xfer_type = i;
goto next;
}
}
dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
return -EINVAL;
}
next:
of_get_nand_on_flash_bbt(child);
if (of_get_nand_bus_width(child) == 16)
info->devsize = NAND_BUSWIDTH_16;
return 0;
}
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;
struct omap_nand_platform_data *pdata = NULL;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
struct nand_ecclayout *ecclayout;
@ -1651,30 +1731,49 @@ static int omap_nand_probe(struct platform_device *pdev)
unsigned sig;
unsigned oob_index;
struct resource *res;
pdata = dev_get_platdata(&pdev->dev);
if (pdata == NULL) {
dev_err(&pdev->dev, "platform data missing\n");
return -ENODEV;
}
struct device *dev = &pdev->dev;
info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
platform_set_drvdata(pdev, info);
info->pdev = pdev;
if (dev->of_node) {
if (omap_get_dt_info(dev, info))
return -EINVAL;
} else {
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "platform data missing\n");
return -EINVAL;
}
info->gpmc_cs = pdata->cs;
info->reg = pdata->reg;
info->ecc_opt = pdata->ecc_opt;
if (pdata->dev_ready)
dev_info(&pdev->dev, "pdata->dev_ready is deprecated\n");
info->xfer_type = pdata->xfer_type;
info->devsize = pdata->devsize;
info->elm_of_node = pdata->elm_of_node;
info->flash_bbt = pdata->flash_bbt;
}
platform_set_drvdata(pdev, info);
info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
if (!info->ops) {
dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
return -ENODEV;
}
info->pdev = pdev;
info->gpmc_cs = pdata->cs;
info->reg = pdata->reg;
info->of_node = pdata->of_node;
info->ecc_opt = pdata->ecc_opt;
nand_chip = &info->nand;
mtd = nand_to_mtd(nand_chip);
mtd->dev.parent = &pdev->dev;
nand_chip->ecc.priv = NULL;
nand_set_flash_node(nand_chip, pdata->of_node);
nand_set_flash_node(nand_chip, dev->of_node);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
@ -1688,6 +1787,13 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
nand_chip->cmd_ctrl = omap_hwcontrol;
info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
GPIOD_IN);
if (IS_ERR(info->ready_gpiod)) {
dev_err(dev, "failed to get ready gpio\n");
return PTR_ERR(info->ready_gpiod);
}
/*
* If RDY/BSY line is connected to OMAP then use the omap ready
* function and the generic nand_wait function which reads the status
@ -1695,7 +1801,7 @@ static int omap_nand_probe(struct platform_device *pdev)
* chip delay which is slightly more than tR (AC Timing) of the NAND
* device and read status register until you get a failure or success
*/
if (pdata->dev_ready) {
if (info->ready_gpiod) {
nand_chip->dev_ready = omap_dev_ready;
nand_chip->chip_delay = 0;
} else {
@ -1703,21 +1809,22 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->chip_delay = 50;
}
if (pdata->flash_bbt)
if (info->flash_bbt)
nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
else
nand_chip->options |= NAND_SKIP_BBTSCAN;
/* scan NAND device connected to chip controller */
nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
if (nand_scan_ident(mtd, 1, NULL)) {
dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n");
dev_err(&info->pdev->dev,
"scan failed, may be bus-width mismatch\n");
err = -ENXIO;
goto return_error;
}
/* re-populate low-level callbacks based on xfer modes */
switch (pdata->xfer_type) {
switch (info->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED:
nand_chip->read_buf = omap_read_buf_pref;
nand_chip->write_buf = omap_write_buf_pref;
@ -1797,7 +1904,7 @@ static int omap_nand_probe(struct platform_device *pdev)
default:
dev_err(&pdev->dev,
"xfer_type(%d) not supported!\n", pdata->xfer_type);
"xfer_type(%d) not supported!\n", info->xfer_type);
err = -EINVAL;
goto return_error;
}
@ -2020,7 +2127,10 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}
mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
if (dev->of_node)
mtd_device_register(mtd, NULL, 0);
else
mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
platform_set_drvdata(pdev, mtd);
@ -2051,11 +2161,17 @@ static int omap_nand_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id omap_nand_ids[] = {
{ .compatible = "ti,omap2-nand", },
{},
};
static struct platform_driver omap_nand_driver = {
.probe = omap_nand_probe,
.remove = omap_nand_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(omap_nand_ids),
},
};

View File

@ -7,161 +7,53 @@
* option) any later version.
*/
/* Maximum Number of Chip Selects */
#define GPMC_CS_NUM 8
#include <linux/platform_data/gpmc-omap.h>
#define GPMC_CONFIG_WP 0x00000005
#define GPMC_IRQ_FIFOEVENTENABLE 0x01
#define GPMC_IRQ_COUNT_EVENT 0x02
/* IRQ numbers in GPMC IRQ domain for legacy boot use */
#define GPMC_IRQ_FIFOEVENTENABLE 0
#define GPMC_IRQ_COUNT_EVENT 1
#define GPMC_BURST_4 4 /* 4 word burst */
#define GPMC_BURST_8 8 /* 8 word burst */
#define GPMC_BURST_16 16 /* 16 word burst */
#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */
#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */
#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
/* bool type time settings */
struct gpmc_bool_timings {
bool cycle2cyclediffcsen;
bool cycle2cyclesamecsen;
bool we_extra_delay;
bool oe_extra_delay;
bool adv_extra_delay;
bool cs_extra_delay;
bool time_para_granularity;
};
/*
* Note that all values in this struct are in nanoseconds except sync_clk
* (which is in picoseconds), while the register values are in gpmc_fck cycles.
/**
* gpmc_nand_ops - Interface between NAND and GPMC
* @nand_write_buffer_empty: get the NAND write buffer empty status.
*/
struct gpmc_timings {
/* Minimum clock period for synchronous mode (in picoseconds) */
u32 sync_clk;
/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
u32 cs_on; /* Assertion time */
u32 cs_rd_off; /* Read deassertion time */
u32 cs_wr_off; /* Write deassertion time */
/* ADV signal timings corresponding to GPMC_CONFIG3 */
u32 adv_on; /* Assertion time */
u32 adv_rd_off; /* Read deassertion time */
u32 adv_wr_off; /* Write deassertion time */
u32 adv_aad_mux_on; /* ADV assertion time for AAD */
u32 adv_aad_mux_rd_off; /* ADV read deassertion time for AAD */
u32 adv_aad_mux_wr_off; /* ADV write deassertion time for AAD */
/* WE signals timings corresponding to GPMC_CONFIG4 */
u32 we_on; /* WE assertion time */
u32 we_off; /* WE deassertion time */
/* OE signals timings corresponding to GPMC_CONFIG4 */
u32 oe_on; /* OE assertion time */
u32 oe_off; /* OE deassertion time */
u32 oe_aad_mux_on; /* OE assertion time for AAD */
u32 oe_aad_mux_off; /* OE deassertion time for AAD */
/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
u32 page_burst_access; /* Multiple access word delay */
u32 access; /* Start-cycle to first data valid delay */
u32 rd_cycle; /* Total read cycle time */
u32 wr_cycle; /* Total write cycle time */
u32 bus_turnaround;
u32 cycle2cycle_delay;
u32 wait_monitoring;
u32 clk_activation;
/* The following are only on OMAP3430 */
u32 wr_access; /* WRACCESSTIME */
u32 wr_data_mux_bus; /* WRDATAONADMUXBUS */
struct gpmc_bool_timings bool_timings;
struct gpmc_nand_ops {
bool (*nand_writebuffer_empty)(void);
};
/* Device timings in picoseconds */
struct gpmc_device_timings {
u32 t_ceasu; /* address setup to CS valid */
u32 t_avdasu; /* address setup to ADV valid */
/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
* of tusb using these timings even for sync whilst
* ideally for adv_rd/(wr)_off it should have considered
* t_avdh instead. This indirectly necessitates r/w
* variations of t_avdp as it is possible to have one
* sync & other async
*/
u32 t_avdp_r; /* ADV low time (what about t_cer ?) */
u32 t_avdp_w;
u32 t_aavdh; /* address hold time */
u32 t_oeasu; /* address setup to OE valid */
u32 t_aa; /* access time from ADV assertion */
u32 t_iaa; /* initial access time */
u32 t_oe; /* access time from OE assertion */
u32 t_ce; /* access time from CS asertion */
u32 t_rd_cycle; /* read cycle time */
u32 t_cez_r; /* read CS deassertion to high Z */
u32 t_cez_w; /* write CS deassertion to high Z */
u32 t_oez; /* OE deassertion to high Z */
u32 t_weasu; /* address setup to WE valid */
u32 t_wpl; /* write assertion time */
u32 t_wph; /* write deassertion time */
u32 t_wr_cycle; /* write cycle time */
struct gpmc_nand_regs;
u32 clk;
u32 t_bacc; /* burst access valid clock to output delay */
u32 t_ces; /* CS setup time to clk */
u32 t_avds; /* ADV setup time to clk */
u32 t_avdh; /* ADV hold time from clk */
u32 t_ach; /* address hold time from clk */
u32 t_rdyo; /* clk to ready valid */
#if IS_ENABLED(CONFIG_OMAP_GPMC)
struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
int cs);
#else
static inline gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
int cs)
{
return NULL;
}
#endif /* CONFIG_OMAP_GPMC */
u32 t_ce_rdyz; /* XXX: description ?, or use t_cez instead */
u32 t_ce_avd; /* CS on to ADV on delay */
/*--------------------------------*/
/* XXX: check the possibility of combining
* cyc_aavhd_oe & cyc_aavdh_we
*/
u8 cyc_aavdh_oe;/* read address hold time in cycles */
u8 cyc_aavdh_we;/* write address hold time in cycles */
u8 cyc_oe; /* access time from OE assertion in cycles */
u8 cyc_wpl; /* write deassertion time in cycles */
u32 cyc_iaa; /* initial access time in cycles */
/* extra delays */
bool ce_xdelay;
bool avd_xdelay;
bool oe_xdelay;
bool we_xdelay;
};
struct gpmc_settings {
bool burst_wrap; /* enables wrap bursting */
bool burst_read; /* enables read page/burst mode */
bool burst_write; /* enables write page/burst mode */
bool device_nand; /* device is NAND */
bool sync_read; /* enables synchronous reads */
bool sync_write; /* enables synchronous writes */
bool wait_on_read; /* monitor wait on reads */
bool wait_on_write; /* monitor wait on writes */
u32 burst_len; /* page/burst length */
u32 device_width; /* device bus width (8 or 16 bit) */
u32 mux_add_data; /* multiplex address & data */
u32 wait_pin; /* wait-pin to be used */
};
/* deprecated APIs */
#if IS_ENABLED(CONFIG_OMAP_GPMC)
void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
#else
static inline void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
{
}
#endif /* CONFIG_OMAP_GPMC */
/*--------------------------------*/
extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
struct gpmc_settings *gpmc_s,
struct gpmc_device_timings *dev_t);
struct gpmc_nand_regs;
struct device_node;
extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
extern int gpmc_get_client_irq(unsigned irq_config);
extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);

View File

@ -0,0 +1,172 @@
/*
* OMAP GPMC Platform data
*
* Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
* Roger Quadros <rogerq@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#ifndef _GPMC_OMAP_H_
#define _GPMC_OMAP_H_
/* Maximum Number of Chip Selects */
#define GPMC_CS_NUM 8
/* bool type time settings */
struct gpmc_bool_timings {
bool cycle2cyclediffcsen;
bool cycle2cyclesamecsen;
bool we_extra_delay;
bool oe_extra_delay;
bool adv_extra_delay;
bool cs_extra_delay;
bool time_para_granularity;
};
/*
* Note that all values in this struct are in nanoseconds except sync_clk
* (which is in picoseconds), while the register values are in gpmc_fck cycles.
*/
struct gpmc_timings {
/* Minimum clock period for synchronous mode (in picoseconds) */
u32 sync_clk;
/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
u32 cs_on; /* Assertion time */
u32 cs_rd_off; /* Read deassertion time */
u32 cs_wr_off; /* Write deassertion time */
/* ADV signal timings corresponding to GPMC_CONFIG3 */
u32 adv_on; /* Assertion time */
u32 adv_rd_off; /* Read deassertion time */
u32 adv_wr_off; /* Write deassertion time */
u32 adv_aad_mux_on; /* ADV assertion time for AAD */
u32 adv_aad_mux_rd_off; /* ADV read deassertion time for AAD */
u32 adv_aad_mux_wr_off; /* ADV write deassertion time for AAD */
/* WE signals timings corresponding to GPMC_CONFIG4 */
u32 we_on; /* WE assertion time */
u32 we_off; /* WE deassertion time */
/* OE signals timings corresponding to GPMC_CONFIG4 */
u32 oe_on; /* OE assertion time */
u32 oe_off; /* OE deassertion time */
u32 oe_aad_mux_on; /* OE assertion time for AAD */
u32 oe_aad_mux_off; /* OE deassertion time for AAD */
/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
u32 page_burst_access; /* Multiple access word delay */
u32 access; /* Start-cycle to first data valid delay */
u32 rd_cycle; /* Total read cycle time */
u32 wr_cycle; /* Total write cycle time */
u32 bus_turnaround;
u32 cycle2cycle_delay;
u32 wait_monitoring;
u32 clk_activation;
/* The following are only on OMAP3430 */
u32 wr_access; /* WRACCESSTIME */
u32 wr_data_mux_bus; /* WRDATAONADMUXBUS */
struct gpmc_bool_timings bool_timings;
};
/* Device timings in picoseconds */
struct gpmc_device_timings {
u32 t_ceasu; /* address setup to CS valid */
u32 t_avdasu; /* address setup to ADV valid */
/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
* of tusb using these timings even for sync whilst
* ideally for adv_rd/(wr)_off it should have considered
* t_avdh instead. This indirectly necessitates r/w
* variations of t_avdp as it is possible to have one
* sync & other async
*/
u32 t_avdp_r; /* ADV low time (what about t_cer ?) */
u32 t_avdp_w;
u32 t_aavdh; /* address hold time */
u32 t_oeasu; /* address setup to OE valid */
u32 t_aa; /* access time from ADV assertion */
u32 t_iaa; /* initial access time */
u32 t_oe; /* access time from OE assertion */
u32 t_ce; /* access time from CS asertion */
u32 t_rd_cycle; /* read cycle time */
u32 t_cez_r; /* read CS deassertion to high Z */
u32 t_cez_w; /* write CS deassertion to high Z */
u32 t_oez; /* OE deassertion to high Z */
u32 t_weasu; /* address setup to WE valid */
u32 t_wpl; /* write assertion time */
u32 t_wph; /* write deassertion time */
u32 t_wr_cycle; /* write cycle time */
u32 clk;
u32 t_bacc; /* burst access valid clock to output delay */
u32 t_ces; /* CS setup time to clk */
u32 t_avds; /* ADV setup time to clk */
u32 t_avdh; /* ADV hold time from clk */
u32 t_ach; /* address hold time from clk */
u32 t_rdyo; /* clk to ready valid */
u32 t_ce_rdyz; /* XXX: description ?, or use t_cez instead */
u32 t_ce_avd; /* CS on to ADV on delay */
/* XXX: check the possibility of combining
* cyc_aavhd_oe & cyc_aavdh_we
*/
u8 cyc_aavdh_oe;/* read address hold time in cycles */
u8 cyc_aavdh_we;/* write address hold time in cycles */
u8 cyc_oe; /* access time from OE assertion in cycles */
u8 cyc_wpl; /* write deassertion time in cycles */
u32 cyc_iaa; /* initial access time in cycles */
/* extra delays */
bool ce_xdelay;
bool avd_xdelay;
bool oe_xdelay;
bool we_xdelay;
};
#define GPMC_BURST_4 4 /* 4 word burst */
#define GPMC_BURST_8 8 /* 8 word burst */
#define GPMC_BURST_16 16 /* 16 word burst */
#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */
#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */
#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
struct gpmc_settings {
bool burst_wrap; /* enables wrap bursting */
bool burst_read; /* enables read page/burst mode */
bool burst_write; /* enables write page/burst mode */
bool device_nand; /* device is NAND */
bool sync_read; /* enables synchronous reads */
bool sync_write; /* enables synchronous writes */
bool wait_on_read; /* monitor wait on reads */
bool wait_on_write; /* monitor wait on writes */
u32 burst_len; /* page/burst length */
u32 device_width; /* device bus width (8 or 16 bit) */
u32 mux_add_data; /* multiplex address & data */
u32 wait_pin; /* wait-pin to be used */
};
/* Data for each chip select */
struct gpmc_omap_cs_data {
bool valid; /* data is valid */
bool is_nand; /* device within this CS is NAND */
struct gpmc_settings *settings;
struct gpmc_device_timings *device_timings;
struct gpmc_timings *gpmc_timings;
struct platform_device *pdev; /* device within this CS region */
unsigned int pdata_size;
};
struct gpmc_omap_platform_data {
struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
};
#endif /* _GPMC_OMAP_H */

View File

@ -45,7 +45,6 @@ enum omap_ecc {
};
struct gpmc_nand_regs {
void __iomem *gpmc_status;
void __iomem *gpmc_nand_command;
void __iomem *gpmc_nand_address;
void __iomem *gpmc_nand_data;
@ -64,21 +63,24 @@ struct gpmc_nand_regs {
void __iomem *gpmc_bch_result4[GPMC_BCH_NUM_REMAINDER];
void __iomem *gpmc_bch_result5[GPMC_BCH_NUM_REMAINDER];
void __iomem *gpmc_bch_result6[GPMC_BCH_NUM_REMAINDER];
/* Deprecated. Do not use */
void __iomem *gpmc_status;
};
struct omap_nand_platform_data {
int cs;
struct mtd_partition *parts;
int nr_parts;
bool dev_ready;
bool flash_bbt;
enum nand_io xfer_type;
int devsize;
enum omap_ecc ecc_opt;
struct gpmc_nand_regs reg;
/* for passing the partitions */
struct device_node *of_node;
struct device_node *elm_of_node;
/* deprecated */
struct gpmc_nand_regs reg;
struct device_node *of_node;
bool dev_ready;
};
#endif