- ti,davinci-nand-buswidth: buswidth 8 or 16
- ti,davinci-nand-use-bbt: use flash based bad block table support.
-Example (enbw_cmc board):
-aemif@60000000 {
- compatible = "ti,davinci-aemif";
- #address-cells = <2>;
- #size-cells = <1>;
- reg = <0x68000000 0x80000>;
- ranges = <2 0 0x60000000 0x02000000
- 3 0 0x62000000 0x02000000
- 4 0 0x64000000 0x02000000
- 5 0 0x66000000 0x02000000
- 6 0 0x68000000 0x02000000>;
- nand@3,0 {
- compatible = "ti,davinci-nand";
- reg = <3 0x0 0x807ff
- 6 0x0 0x8000>;
- #address-cells = <1>;
- #size-cells = <1>;
- ti,davinci-chipselect = <1>;
- ti,davinci-mask-ale = <0>;
- ti,davinci-mask-cle = <0>;
- ti,davinci-mask-chipsel = <0>;
- ti,davinci-ecc-mode = "hw";
- ti,davinci-ecc-bits = <4>;
- ti,davinci-nand-use-bbt;
+ nand device bindings may contain additional sub-nodes describing
+ partitions of the address space. See partition.txt for more detail.
+
- partition@180000 {
- label = "ubifs";
- reg = <0x180000 0x7e80000>;
- };
+Example(da850 EVM ):
+nand_cs3@62000000 {
+ compatible = "ti,davinci-nand";
+ reg = <0x62000000 0x807ff
+ 0x68000000 0x8000>;
+ ti,davinci-chipselect = <1>;
+ ti,davinci-mask-ale = <0>;
+ ti,davinci-mask-cle = <0>;
+ ti,davinci-mask-chipsel = <0>;
+ ti,davinci-ecc-mode = "hw";
+ ti,davinci-ecc-bits = <4>;
+ ti,davinci-nand-use-bbt;
+
++ partition@180000 {
++ label = "ubifs";
++ reg = <0x180000 0x7e80000>;
+ };
};
bootargs = "console=ttyAMA0,115200";
};
- status = "disable";
+ cpufreq {
+ compatible = "st,cpufreq-spear";
+ cpufreq_tbl = < 166000
+ 200000
+ 250000
+ 300000
+ 400000
+ 500000
+ 600000 >;
++ status = "disabled";
+ };
+
ahb {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges = <0x50000000 0x50000000 0x10000000
0xb0000000 0xb0000000 0x10000000
+ 0xd0000000 0xd0000000 0x02000000
+ 0xd8000000 0xd8000000 0x01000000
0xe0000000 0xe0000000 0x10000000>;
sdhci@b3000000 {
cf@b2800000 {
compatible = "arasan,cf-spear1340";
- reg = <0xb2800000 0x100>;
+ reg = <0xb2800000 0x1000>;
interrupts = <0 29 0x4>;
status = "disabled";
};
compatible = "st,spear600-fsmc-nand";
#address-cells = <1>;
#size-cells = <1>;
- reg = <0xb0000000 0x1000 /* FSMC Register */
- 0xb0800000 0x0010>; /* NAND Base */
- reg-names = "fsmc_regs", "nand_data";
+ reg = <0xb0000000 0x1000 /* FSMC Register*/
+ 0xb0800000 0x0010 /* NAND Base DATA */
+ 0xb0820000 0x0010 /* NAND Base ADDR */
+ 0xb0810000 0x0010>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
interrupts = <0 20 0x4
0 21 0x4
0 22 0x4
0 23 0x4>;
- st,ale-off = <0x20000>;
- st,cle-off = <0x10000>;
+ st,mode = <2>;
status = "disabled";
};
status = "disabled";
};
- status = "disable";
+ pcm {
+ compatible = "st,pcm-audio";
+ #address-cells = <0>;
+ #size-cells = <0>;
++ status = "disabled";
+ };
+
smi: flash@ea000000 {
compatible = "st,spear600-smi";
#address-cells = <1>;
status = "disabled";
};
- spi0: spi@e0100000 {
- compatible = "arm,pl022", "arm,primecell";
- reg = <0xe0100000 0x1000>;
- interrupts = <0 31 0x4>;
- status = "disabled";
- };
-
ehci@e4800000 {
compatible = "st,spear600-ehci", "usb-ehci";
reg = <0xe4800000 0x1000>;
interrupts = <0 64 0x4>;
+ usbh0_id = <0>;
status = "disabled";
};
compatible = "st,spear600-ehci", "usb-ehci";
reg = <0xe5800000 0x1000>;
interrupts = <0 66 0x4>;
+ usbh1_id = <1>;
status = "disabled";
};
compatible = "st,spear600-ohci", "usb-ohci";
reg = <0xe4000000 0x1000>;
interrupts = <0 65 0x4>;
+ usbh0_id = <0>;
status = "disabled";
};
compatible = "st,spear600-ohci", "usb-ohci";
reg = <0xe5000000 0x1000>;
interrupts = <0 67 0x4>;
+ usbh1_id = <1>;
status = "disabled";
};
compatible = "simple-bus";
ranges = <0x50000000 0x50000000 0x10000000
0xb0000000 0xb0000000 0x10000000
+ 0xd0000000 0xd0000000 0x02000000
+ 0xd8000000 0xd8000000 0x01000000
0xe0000000 0xe0000000 0x10000000>;
gpio0: gpio@e0600000 {
status = "disabled";
};
+ i2s@e0180000 {
+ compatible = "st,designware-i2s";
+ reg = <0xe0180000 0x1000>;
+ interrupt-names = "play_irq", "record_irq";
+ interrupts = <0 10 0x4
+ 0 11 0x4 >;
+ status = "disabled";
+ };
+
+ i2s@e0200000 {
+ compatible = "st,designware-i2s";
+ reg = <0xe0200000 0x1000>;
+ interrupt-names = "play_irq", "record_irq";
+ interrupts = <0 26 0x4
+ 0 53 0x4>;
+ status = "disabled";
+ };
+
+ spi0: spi@e0100000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xe0100000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 31 0x4>;
+ status = "disabled";
+ };
+
rtc@e0580000 {
- compatible = "st,spear-rtc";
+ compatible = "st,spear600-rtc";
reg = <0xe0580000 0x1000>;
interrupts = <0 36 0x4>;
status = "disabled";
adc@e0080000 {
compatible = "st,spear600-adc";
reg = <0xe0080000 0x1000>;
- interrupts = <0 44 0x4>;
+ interrupts = <0 12 0x4>;
status = "disabled";
};
timer@ec800600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0xec800600 0x20>;
- interrupts = <1 13 0x301>;
+ interrupts = <1 13 0x4>;
+ status = "disabled";
};
wdt@ec800620 {
thermal@e07008c4 {
compatible = "st,thermal-spear1340";
reg = <0xe07008c4 0x4>;
+ thermal_flags = <0x7000>;
};
};
};
};
clcd@60000000 {
- compatible = "arm,clcd-pl110", "arm,primecell";
+ compatible = "arm,pl110", "arm,primecell";
reg = <0x60000000 0x1000>;
interrupts = <30>;
status = "disabled";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x94000000 0x1000 /* FSMC Register */
- 0x80000000 0x0010>; /* NAND Base */
- reg-names = "fsmc_regs", "nand_data";
- st,ale-off = <0x20000>;
- st,cle-off = <0x10000>;
+ 0x80000000 0x0010 /* NAND Base DATA */
+ 0x80020000 0x0010 /* NAND Base ADDR */
+ 0x80010000 0x0010>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};
status = "disabled";
};
+ shirq: interrupt-controller@0x50000000 {
+ compatible = "st,spear300-shirq";
+ reg = <0x50000000 0x1000>;
+ interrupts = <28>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+
apb {
#address-cells = <1>;
#size-cells = <1>;
compatible = "arm,pl061", "arm,primecell";
gpio-controller;
reg = <0xa9000000 0x1000>;
+ interrupts = <8>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
kbd@a0000000 {
compatible = "st,spear300-kbd";
reg = <0xa0000000 0x1000>;
+ interrupts = <7>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
};
0xb0000000 0xb0000000 0x10000000
0xd0000000 0xd0000000 0x30000000>;
- pinmux@b4000000 {
+ pinmux: pinmux@b4000000 {
compatible = "st,spear310-pinmux";
reg = <0xb4000000 0x1000>;
+ #gpio-range-cells = <2>;
};
fsmc: flash@44000000 {
#address-cells = <1>;
#size-cells = <1>;
reg = <0x44000000 0x1000 /* FSMC Register */
- 0x40000000 0x0010>; /* NAND Base */
- reg-names = "fsmc_regs", "nand_data";
- st,ale-off = <0x10000>;
- st,cle-off = <0x20000>;
+ 0x40000000 0x0010 /* NAND Base DATA */
+ 0x40020000 0x0010 /* NAND Base ADDR */
+ 0x40010000 0x0010>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};
+ shirq: interrupt-controller@0xb4000000 {
+ compatible = "st,spear310-shirq";
+ reg = <0xb4000000 0x1000>;
+ interrupts = <28 29 30 1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+
apb {
#address-cells = <1>;
#size-cells = <1>;
serial@b2000000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xb2000000 0x1000>;
+ interrupts = <8>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@b2080000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xb2080000 0x1000>;
+ interrupts = <9>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@b2100000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xb2100000 0x1000>;
+ interrupts = <10>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@b2180000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xb2180000 0x1000>;
+ interrupts = <11>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@b2200000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xb2200000 0x1000>;
+ interrupts = <12>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
+
+ gpiopinctrl: gpio@b4000000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xb4000000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 102>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <102>;
+ st-plgpio,enb-reg = <0x10>;
+ st-plgpio,wdata-reg = <0x20>;
+ st-plgpio,dir-reg = <0x30>;
+ st-plgpio,ie-reg = <0x50>;
+ st-plgpio,rdata-reg = <0x40>;
+ st-plgpio,mis-reg = <0x60>;
+ };
};
};
};
ranges = <0x40000000 0x40000000 0x80000000
0xd0000000 0xd0000000 0x30000000>;
- pinmux@b3000000 {
+ pinmux: pinmux@b3000000 {
compatible = "st,spear320-pinmux";
reg = <0xb3000000 0x1000>;
+ #gpio-range-cells = <2>;
};
clcd@90000000 {
- compatible = "arm,clcd-pl110", "arm,primecell";
+ compatible = "arm,pl110", "arm,primecell";
reg = <0x90000000 0x1000>;
- interrupts = <33>;
+ interrupts = <8>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
#address-cells = <1>;
#size-cells = <1>;
reg = <0x4c000000 0x1000 /* FSMC Register */
- 0x50000000 0x0010>; /* NAND Base */
- reg-names = "fsmc_regs", "nand_data";
- st,ale-off = <0x20000>;
- st,cle-off = <0x10000>;
+ 0x50000000 0x0010 /* NAND Base DATA */
+ 0x50020000 0x0010 /* NAND Base ADDR */
+ 0x50010000 0x0010>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};
sdhci@70000000 {
compatible = "st,sdhci-spear";
reg = <0x70000000 0x100>;
- interrupts = <29>;
+ interrupts = <10>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
+ shirq: interrupt-controller@0xb3000000 {
+ compatible = "st,spear320-shirq";
+ reg = <0xb3000000 0x1000>;
+ interrupts = <30 28 29 1>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+
spi1: spi@a5000000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0xa5000000 0x1000>;
+ interrupts = <15>;
+ interrupt-parent = <&shirq>;
+ #address-cells = <1>;
+ #size-cells = <0>;
status = "disabled";
};
spi2: spi@a6000000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0xa6000000 0x1000>;
+ interrupts = <16>;
+ interrupt-parent = <&shirq>;
+ #address-cells = <1>;
+ #size-cells = <0>;
status = "disabled";
};
+ pwm: pwm@a8000000 {
+ compatible ="st,spear-pwm";
+ reg = <0xa8000000 0x1000>;
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
apb {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
- ranges = <0xa0000000 0xa0000000 0x10000000
+ ranges = <0xa0000000 0xa0000000 0x20000000
0xd0000000 0xd0000000 0x30000000>;
i2c1: i2c@a7000000 {
#size-cells = <0>;
compatible = "snps,designware-i2c";
reg = <0xa7000000 0x1000>;
+ interrupts = <21>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@a3000000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xa3000000 0x1000>;
+ interrupts = <13>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
serial@a4000000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xa4000000 0x1000>;
+ interrupts = <14>;
+ interrupt-parent = <&shirq>;
status = "disabled";
};
+
+ gpiopinctrl: gpio@b3000000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xb3000000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 102>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <102>;
+ st-plgpio,enb-reg = <0x24>;
+ st-plgpio,wdata-reg = <0x34>;
+ st-plgpio,dir-reg = <0x44>;
+ st-plgpio,ie-reg = <0x64>;
+ st-plgpio,rdata-reg = <0x54>;
+ st-plgpio,mis-reg = <0x84>;
+ st-plgpio,eit-reg = <0x94>;
+ };
};
};
};
#interrupt-cells = <1>;
};
+ clcd@fc200000 {
+ compatible = "arm,pl110", "arm,primecell";
+ reg = <0xfc200000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <12>;
+ status = "disabled";
+ };
+
dma@fc400000 {
compatible = "arm,pl080", "arm,primecell";
reg = <0xfc400000 0x1000>;
interrupt-parent = <&vic1>;
interrupts = <24 23>;
interrupt-names = "macirq", "eth_wake_irq";
+ phy-mode = "gmii";
status = "disabled";
};
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd1800000 0x1000 /* FSMC Register */
- 0xd2000000 0x4000>; /* NAND Base */
- reg-names = "fsmc_regs", "nand_data";
- st,ale-off = <0x20000>;
- st,cle-off = <0x10000>;
+ 0xd2000000 0x0010 /* NAND Base DATA */
+ 0xd2020000 0x0010 /* NAND Base ADDR */
+ 0xd2010000 0x0010>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};
status = "disabled";
};
+ rtc@fc900000 {
+ compatible = "st,spear600-rtc";
+ reg = <0xfc900000 0x1000>;
+ interrupts = <10>;
+ status = "disabled";
+ };
+
timer@f0000000 {
compatible = "st,spear-timer";
reg = <0xf0000000 0x400>;
#include <linux/gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
+ #include <linux/mtd/fsmc.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
+#include <linux/platform_data/clocksource-nomadik-mtu.h>
+#include <linux/platform_data/mtd-nomadik-nand.h>
#include <asm/hardware/vic.h>
#include <asm/sizes.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
- #include <mach/fsmc.h>
-
-#include <plat/gpio-nomadik.h>
-#include <plat/mtu.h>
-#include <plat/pincfg.h>
+#include <mach/irqs.h>
#include "cpu-8815.h"
#define SRC_CR_INIT_MASK 0x00007fff
#define SRC_CR_INIT_VAL 0x2aaa8000
+ #define ALE_OFF 0x1000000
+ #define CLE_OFF 0x800000
+
/* These addresses span 16MB, so use three individual pages */
static struct resource nhk8815_nand_resources[] = {
{
+ .name = "nand_data",
+ .start = 0x40000000,
+ .end = 0x40000000 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
.name = "nand_addr",
- .start = NAND_IO_ADDR,
- .end = NAND_IO_ADDR + 0xfff,
+ .start = 0x40000000 + ALE_OFF,
+ .end = 0x40000000 +ALE_OFF + SZ_16K - 1,
.flags = IORESOURCE_MEM,
}, {
.name = "nand_cmd",
- .start = NAND_IO_CMD,
- .end = NAND_IO_CMD + 0xfff,
+ .start = 0x40000000 + CLE_OFF,
+ .end = 0x40000000 + CLE_OFF + SZ_16K - 1,
.flags = IORESOURCE_MEM,
}, {
- .name = "nand_data",
- .start = NAND_IO_DATA,
- .end = NAND_IO_DATA + 0xfff,
+ .name = "fsmc_regs",
+ .start = NOMADIK_FSMC_BASE,
+ .end = NOMADIK_FSMC_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
- }
+ },
};
- static int nhk8815_nand_init(void)
- {
- /* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
- writel(0x0000000E, FSMC_PCR(0));
- writel(0x000D0A00, FSMC_PMEM(0));
- writel(0x00100A00, FSMC_PATT(0));
-
- /* enable access to the chip select area */
- writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
-
- return 0;
- }
-
/*
* These partitions are the same as those used in the 2.6.20 release
* shipped by the vendor; the first two partitions are mandated
}
};
- static struct nomadik_nand_platform_data nhk8815_nand_data = {
- .parts = nhk8815_partitions,
- .nparts = ARRAY_SIZE(nhk8815_partitions),
- .options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING,
- .init = nhk8815_nand_init,
+ static struct fsmc_nand_timings nhk8815_nand_timings = {
+ .thiz = 0,
+ .thold = 0x10,
+ .twait = 0x0A,
+ .tset = 0,
+ };
+
+ static struct fsmc_nand_platform_data nhk8815_nand_platform_data = {
+ .nand_timings = &nhk8815_nand_timings,
+ .partitions = nhk8815_partitions,
+ .nr_partitions = ARRAY_SIZE(nhk8815_partitions),
+ .width = FSMC_NAND_BW8,
};
static struct platform_device nhk8815_nand_device = {
- .name = "nomadik_nand",
- .dev = {
- .platform_data = &nhk8815_nand_data,
+ .name = "fsmc-nand",
+ .id = -1,
+ .resource = nhk8815_nand_resources,
+ .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
+ .dev = {
+ .platform_data = &nhk8815_nand_platform_data,
},
- .resource = nhk8815_nand_resources,
- .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
};
/* These are the partitions for the OneNand device, different from above */
.num_resources = ARRAY_SIZE(nhk8815_onenand_resource),
};
+ /* bus control reg. and bus timing reg. for CS0..CS3 */
+ #define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3))
+ #define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04)
+
static void __init nhk8815_onenand_init(void)
{
#ifdef CONFIG_MTD_ONENAND
src_cr |= SRC_CR_INIT_VAL;
writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
- nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE));
+ nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE), IRQ_MTU0);
}
static struct sys_timer nomadik_timer = {
static void __init u300_map_io(void)
{
iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
- /* We enable a real big DMA buffer if need be. */
- init_consistent_dma_size(SZ_4M);
}
/*
*/
static struct resource fsmc_resources[] = {
{
+ .name = "nand_addr",
+ .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE,
+ .end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "nand_cmd",
+ .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE,
+ .end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.name = "nand_data",
.start = U300_NAND_CS0_PHYS_BASE,
.end = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1,
static struct u300_gpio_platform u300_gpio_plat = {
.ports = 7,
.gpio_base = 0,
- .gpio_irq_base = IRQ_U300_GPIO_BASE,
- .pinctrl_device = &pinctrl_device,
};
static struct platform_device gpio_device = {
.nr_partitions = ARRAY_SIZE(u300_partitions),
.options = NAND_SKIP_BBTSCAN,
.width = FSMC_NAND_BW8,
- .ale_off = PLAT_NAND_ALE,
- .cle_off = PLAT_NAND_CLE,
};
static struct platform_device nand_device = {
&i2c1_device,
&keypad_device,
&rtc_device,
+ &pinctrl_device,
&gpio_device,
&nand_device,
&wdog_device,
/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
.atag_offset = 0x100,
.map_io = u300_map_io,
- .nr_irqs = NR_IRQS_U300,
+ .nr_irqs = 0,
.init_irq = u300_init_irq,
.handle_irq = vic_handle_irq,
.timer = &u300_timer,
#include <linux/export.h>
#include <linux/bcma/bcma.h>
- static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
{
bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
}
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
{
}
}
-void bcma_pmu_init(struct bcma_drv_cc *cc)
+void bcma_pmu_early_init(struct bcma_drv_cc *cc)
{
u32 pmucap;
bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
cc->pmu.rev, pmucap);
+}
+void bcma_pmu_init(struct bcma_drv_cc *cc)
+{
if (cc->pmu.rev == 1)
bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
~BCMA_CC_PMU_CTL_NOILPONW);
bcma_pmu_workarounds(cc);
}
-u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
/* Find the output of the "m" pll divider given pll controls that start with
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
*/
-static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+static u32 bcma_pmu_pll_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
{
u32 tmp, div, ndiv, p1, p2, fc;
struct bcma_bus *bus = cc->core->bus;
ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
/* Do calculation in Mhz */
- fc = bcma_pmu_alp_clock(cc) / 1000000;
+ fc = bcma_pmu_get_alp_clock(cc) / 1000000;
fc = (p1 * ndiv * fc) / p2;
/* Return clock in Hertz */
return (fc / div) * 1000000;
}
-static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+static u32 bcma_pmu_pll_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
{
u32 tmp, ndiv, p1div, p2div;
u32 clock;
}
/* query bus clock frequency for PMU-enabled chipcommon */
-static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
case BCMA_CHIP_ID_BCM4716:
case BCMA_CHIP_ID_BCM4748:
case BCMA_CHIP_ID_BCM47162:
- return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
- BCMA_CC_PMU5_MAINPLL_SSB);
+ return bcma_pmu_pll_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
case BCMA_CHIP_ID_BCM5356:
- return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
- BCMA_CC_PMU5_MAINPLL_SSB);
+ return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM4749:
- return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
- BCMA_CC_PMU5_MAINPLL_SSB);
+ return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
case BCMA_CHIP_ID_BCM4706:
- return bcma_pmu_clock_bcm4706(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
- BCMA_CC_PMU5_MAINPLL_SSB);
+ return bcma_pmu_pll_clock_bcm4706(cc,
+ BCMA_CC_PMU4706_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
case BCMA_CHIP_ID_BCM53572:
return 75000000;
default:
- bcma_warn(bus, "No backplane clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
+ bcma_warn(bus, "No bus clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
}
return BCMA_CC_PMU_HT_CLOCK;
}
/* query cpu clock frequency for PMU-enabled chipcommon */
-u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
+u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53572)
return 300000000;
+ /* New PMUs can have different clock for bus and CPU */
if (cc->pmu.rev >= 5) {
u32 pll;
switch (bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM4706:
- return bcma_pmu_clock_bcm4706(cc,
+ return bcma_pmu_pll_clock_bcm4706(cc,
BCMA_CC_PMU4706_MAINPLL_PLL0,
BCMA_CC_PMU5_MAINPLL_CPU);
case BCMA_CHIP_ID_BCM5356:
break;
}
- return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
+ return bcma_pmu_pll_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
}
- return bcma_pmu_get_clockcontrol(cc);
+ /* On old PMUs CPU has the same clock as the bus */
+ return bcma_pmu_get_bus_clock(cc);
}
static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
This enables access to the flash chips on the Hitachi SolutionEngine and
similar boards. Say 'Y' if you are building a kernel for such a board.
-config MTD_CDB89712
- tristate "Cirrus CDB89712 evaluation board mappings"
- depends on MTD_CFI && ARCH_CDB89712
- help
- This enables access to the flash or ROM chips on the CDB89712 board.
- If you have such a board, say 'Y'.
-
config MTD_SA1100
tristate "CFI Flash device mapped on StrongARM SA11x0"
depends on MTD_CFI && ARCH_SA1100
IXP2000 based board and would like to use the flash chips on it,
say 'Y'.
- config MTD_FORTUNET
- tristate "CFI Flash device mapped on the FortuNet board"
- depends on MTD_CFI && SA1100_FORTUNET
- help
- This enables access to the Flash on the FortuNet board. If you
- have such a board, say 'Y'.
-
config MTD_AUTCPU12
bool "NV-RAM mapping AUTCPU12 board"
depends on ARCH_AUTCPU12
endif
# Chip mappings
-obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_IMPA7) += impa7.o
- obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
NAND chips (page size 256 byte, erase size 4-8KiB). The IDs
of these chips were reused by later, larger chips.
-config MTD_NAND_AUTCPU12
- tristate "SmartMediaCard on autronix autcpu12 board"
- depends on ARCH_AUTCPU12
- help
- This enables the driver for the autronix autcpu12 board to
- access the SmartMediaCard.
-
config MTD_NAND_DENALI
- depends on PCI
+ tristate "Support Denali NAND controller"
+ help
+ Enable support for the Denali NAND controller. This should be
+ combined with either the PCI or platform drivers to provide device
+ registration.
+
+ config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
+ depends on PCI && MTD_NAND_DENALI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
-
+
+ config MTD_NAND_DENALI_DT
+ tristate "Support Denali NAND controller as a DT device"
+ depends on HAVE_CLK && MTD_NAND_DENALI
+ help
+ Enable the driver for NAND flash on platforms using a Denali NAND
+ controller as a DT device.
+
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
- depends on MTD_NAND_DENALI
+ depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
help
This enables a GPIO based NAND flash driver.
-config MTD_NAND_SPIA
- tristate "NAND Flash device on SPIA board"
- depends on ARCH_P720T
- help
- If you had to ask, you don't have one. Say 'N'.
-
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
block, such as SD card. So pay attention to it when you enable
the GPMI.
+ config MTD_NAND_BCM47XXNFLASH
+ tristate "Support for NAND flash on BCM4706 BCMA bus"
+ depends on BCMA_NFLASH
+ help
+ BCMA bus can have various flash memories attached, they are
+ registered by bcma as platform devices. This enables driver for
+ NAND flash memories. For now only BCM4706 is supported.
+
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
This enables the driver for the NAND flash controller on the
MXC processors.
- config MTD_NAND_NOMADIK
- tristate "ST Nomadik 8815 NAND support"
- depends on ARCH_NOMADIK
- help
- Driver for the NAND flash controller on the Nomadik, with ECC.
-
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || ARCH_SHMOBILE
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
- depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300
+ depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
-obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
-obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
+ obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
+ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
- obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
+ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
nand-objs := nand_base.o nand_bbt.o
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/platform_data/atmel.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/cpu.h>
* 12-bits 20-bytes 21-bytes
* 24-bits 39-bytes 42-bytes
*/
- static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
+ static int pmecc_get_ecc_bytes(int cap, int sector_size)
{
int m = 12 + sector_size / 512;
return (m * cap + 7) / 8;
}
- static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
+ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
int oobsize, int ecc_len)
{
int i;
oobsize - ecc_len - layout->oobfree[0].offset;
}
- static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
+ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
{
int table_size;
kfree(host->pmecc_delta);
}
- static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
+ static int pmecc_data_alloc(struct atmel_nand_host *host)
{
const int cap = host->pmecc_corr_cap;
struct atmel_nand_host *host = nand_chip->priv;
int i, err_nbr, eccbytes;
uint8_t *buf_pos;
+ int total_err = 0;
eccbytes = nand_chip->ecc.bytes;
for (i = 0; i < eccbytes; i++)
pmecc_correct_data(mtd, buf_pos, ecc, i,
host->pmecc_bytes_per_sector, err_nbr);
mtd->ecc_stats.corrected += err_nbr;
+ total_err += err_nbr;
}
}
pmecc_stat >>= 1;
}
- return 0;
+ return total_err;
}
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t stat;
unsigned long end_time;
+ int bitflips = 0;
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
}
stat = pmecc_readl_relaxed(host->ecc, ISR);
- if (stat != 0)
- if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
- return -EIO;
+ if (stat != 0) {
+ bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
+ if (bitflips < 0)
+ /* uncorrectable errors */
+ return 0;
+ }
- return 0;
+ return bitflips;
}
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
}
#if defined(CONFIG_OF)
- static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
u32 val, table_offset;
return 0;
}
#else
- static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
return -EINVAL;
struct resource *mem;
struct mtd_part_parser_data ppdata = {};
int res;
+ struct pinctrl *pinctrl;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(host->dev, "Failed to request pinctrl\n");
+ res = PTR_ERR(pinctrl);
+ goto err_ecc_ioremap;
+ }
+
if (gpio_is_valid(host->board.rdy_pin)) {
res = gpio_request(host->board.rdy_pin, "nand_rdy");
if (res < 0) {
#include <asm/mach/flash.h>
#include <linux/platform_data/mtd-mxc_nand.h>
-#include <mach/hardware.h>
#define DRIVER_NAME "mxc_nand"
-#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
-#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
-#define nfc_is_v3_2a() cpu_is_mx51()
-#define nfc_is_v3_2b() cpu_is_mx53()
-
/* Addresses for NFC registers */
#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
}
};
- static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
+ static const char const *part_probes[] = {
+ "cmdlinepart", "RedBoot", "ofpart", NULL };
static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
{
.ppb_shift = 8,
};
+static inline int is_imx21_nfc(struct mxc_nand_host *host)
+{
+ return host->devtype_data == &imx21_nand_devtype_data;
+}
+
+static inline int is_imx27_nfc(struct mxc_nand_host *host)
+{
+ return host->devtype_data == &imx27_nand_devtype_data;
+}
+
+static inline int is_imx25_nfc(struct mxc_nand_host *host)
+{
+ return host->devtype_data == &imx25_nand_devtype_data;
+}
+
+static inline int is_imx51_nfc(struct mxc_nand_host *host)
+{
+ return host->devtype_data == &imx51_nand_devtype_data;
+}
+
+static inline int is_imx53_nfc(struct mxc_nand_host *host)
+{
+ return host->devtype_data == &imx53_nand_devtype_data;
+}
+
+static struct platform_device_id mxcnd_devtype[] = {
+ {
+ .name = "imx21-nand",
+ .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
+ }, {
+ .name = "imx27-nand",
+ .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
+ }, {
+ .name = "imx25-nand",
+ .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
+ }, {
+ .name = "imx51-nand",
+ .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
+ }, {
+ .name = "imx53-nand",
+ .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
+
#ifdef CONFIG_OF_MTD
static const struct of_device_id mxcnd_dt_ids[] = {
{
}
#endif
- static int __devinit mxcnd_probe(struct platform_device *pdev)
-static int __init mxcnd_probe_pdata(struct mxc_nand_host *host)
-{
- struct mxc_nand_platform_data *pdata = host->dev->platform_data;
-
- if (!pdata)
- return -ENODEV;
-
- host->pdata = *pdata;
-
- if (nfc_is_v1()) {
- if (cpu_is_mx21())
- host->devtype_data = &imx21_nand_devtype_data;
- else
- host->devtype_data = &imx27_nand_devtype_data;
- } else if (nfc_is_v21()) {
- host->devtype_data = &imx25_nand_devtype_data;
- } else if (nfc_is_v3_2a()) {
- host->devtype_data = &imx51_nand_devtype_data;
- } else if (nfc_is_v3_2b()) {
- host->devtype_data = &imx53_nand_devtype_data;
- } else
- BUG();
-
- return 0;
-}
-
+ static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
struct mtd_info *mtd;
return PTR_ERR(host->clk);
err = mxcnd_probe_dt(host);
- if (err > 0)
- err = mxcnd_probe_pdata(host);
+ if (err > 0) {
+ struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
+ if (pdata) {
+ host->pdata = *pdata;
+ host->devtype_data = (struct mxc_nand_devtype_data *)
+ pdev->id_entry->driver_data;
+ } else {
+ err = -ENODEV;
+ }
+ }
if (err < 0)
return err;
}
/* first scan to find the device and get the page size */
- if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) {
+ if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
err = -ENXIO;
goto escan;
}
this->ecc.layout = host->devtype_data->ecclayout_4k;
if (this->ecc.mode == NAND_ECC_HW) {
- if (nfc_is_v1())
+ if (is_imx21_nfc(host) || is_imx27_nfc(host))
this->ecc.strength = 1;
else
this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
return 0;
escan:
- clk_disable_unprepare(host->clk);
+ if (host->clk_act)
+ clk_disable_unprepare(host->clk);
return err;
}
- static int __devexit mxcnd_remove(struct platform_device *pdev)
+ static int mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mxcnd_dt_ids),
},
+ .id_table = mxcnd_devtype,
.probe = mxcnd_probe,
- .remove = __devexit_p(mxcnd_remove),
+ .remove = mxcnd_remove,
};
module_platform_driver(mxcnd_driver);
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+ #include <linux/seq_file.h>
+ #include <linux/debugfs.h>
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
static char *weakpages = NULL;
static unsigned int bitflips = 0;
static char *gravepages = NULL;
- static unsigned int rptwear = 0;
static unsigned int overridesize = 0;
static char *cache_file = NULL;
static unsigned int bbt;
module_param(weakpages, charp, 0400);
module_param(bitflips, uint, 0400);
module_param(gravepages, charp, 0400);
- module_param(rptwear, uint, 0400);
module_param(overridesize, uint, 0400);
module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400);
MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]"
" separated by commas e.g. 1401:2 means page 1401"
" can be read only twice before failing");
- MODULE_PARM_DESC(rptwear, "Number of erases between reporting wear, if not zero");
MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
"The size is specified in erase blocks and as the exponent of a power of two"
" e.g. 5 means a size of 32 erase blocks");
/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
#define NS_MAX_HELD_PAGES 16
+ struct nandsim_debug_info {
+ struct dentry *dfs_root;
+ struct dentry *dfs_wear_report;
+ };
+
/*
* A union to represent flash memory contents and flash buffer.
*/
void *file_buf;
struct page *held_pages[NS_MAX_HELD_PAGES];
int held_cnt;
+
+ struct nandsim_debug_info dbg;
};
/*
static unsigned long *erase_block_wear = NULL;
static unsigned int wear_eb_count = 0;
static unsigned long total_wear = 0;
- static unsigned int rptwear_cnt = 0;
/* MTD structure for NAND controller */
static struct mtd_info *nsmtd;
+ static int nandsim_debugfs_show(struct seq_file *m, void *private)
+ {
+ unsigned long wmin = -1, wmax = 0, avg;
+ unsigned long deciles[10], decile_max[10], tot = 0;
+ unsigned int i;
+
+ /* Calc wear stats */
+ for (i = 0; i < wear_eb_count; ++i) {
+ unsigned long wear = erase_block_wear[i];
+ if (wear < wmin)
+ wmin = wear;
+ if (wear > wmax)
+ wmax = wear;
+ tot += wear;
+ }
+
+ for (i = 0; i < 9; ++i) {
+ deciles[i] = 0;
+ decile_max[i] = (wmax * (i + 1) + 5) / 10;
+ }
+ deciles[9] = 0;
+ decile_max[9] = wmax;
+ for (i = 0; i < wear_eb_count; ++i) {
+ int d;
+ unsigned long wear = erase_block_wear[i];
+ for (d = 0; d < 10; ++d)
+ if (wear <= decile_max[d]) {
+ deciles[d] += 1;
+ break;
+ }
+ }
+ avg = tot / wear_eb_count;
+
+ /* Output wear report */
+ seq_printf(m, "Total numbers of erases: %lu\n", tot);
+ seq_printf(m, "Number of erase blocks: %u\n", wear_eb_count);
+ seq_printf(m, "Average number of erases: %lu\n", avg);
+ seq_printf(m, "Maximum number of erases: %lu\n", wmax);
+ seq_printf(m, "Minimum number of erases: %lu\n", wmin);
+ for (i = 0; i < 10; ++i) {
+ unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+ if (from > decile_max[i])
+ continue;
+ seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
+ from,
+ decile_max[i],
+ deciles[i]);
+ }
+
+ return 0;
+ }
+
+ static int nandsim_debugfs_open(struct inode *inode, struct file *file)
+ {
+ return single_open(file, nandsim_debugfs_show, inode->i_private);
+ }
+
+ static const struct file_operations dfs_fops = {
+ .open = nandsim_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ };
+
+ /**
+ * nandsim_debugfs_create - initialize debugfs
+ * @dev: nandsim device description object
+ *
+ * This function creates all debugfs files for UBI device @ubi. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+ static int nandsim_debugfs_create(struct nandsim *dev)
+ {
+ struct nandsim_debug_info *dbg = &dev->dbg;
+ struct dentry *dent;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return 0;
+
+ dent = debugfs_create_dir("nandsim", NULL);
+ if (IS_ERR_OR_NULL(dent)) {
+ int err = dent ? -ENODEV : PTR_ERR(dent);
+
+ NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+ err);
+ return err;
+ }
+ dbg->dfs_root = dent;
+
+ dent = debugfs_create_file("wear_report", S_IRUSR,
+ dbg->dfs_root, dev, &dfs_fops);
+ if (IS_ERR_OR_NULL(dent))
+ goto out_remove;
+ dbg->dfs_wear_report = dent;
+
+ return 0;
+
+ out_remove:
+ debugfs_remove_recursive(dbg->dfs_root);
+ err = dent ? PTR_ERR(dent) : -ENODEV;
+ return err;
+ }
+
+ /**
+ * nandsim_debugfs_remove - destroy all debugfs files
+ */
+ static void nandsim_debugfs_remove(struct nandsim *ns)
+ {
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ debugfs_remove_recursive(ns->dbg.dfs_root);
+ }
+
/*
* Allocate array of page pointers, create slab allocation for an array
* and initialize the array by NULL pointers.
{
size_t mem;
- if (!rptwear)
- return 0;
wear_eb_count = div_u64(mtd->size, mtd->erasesize);
mem = wear_eb_count * sizeof(unsigned long);
if (mem / sizeof(unsigned long) != wear_eb_count) {
static void update_wear(unsigned int erase_block_no)
{
- unsigned long wmin = -1, wmax = 0, avg;
- unsigned long deciles[10], decile_max[10], tot = 0;
- unsigned int i;
-
if (!erase_block_wear)
return;
total_wear += 1;
+ /*
+ * TODO: Notify this through a debugfs entry,
+ * instead of showing an error message.
+ */
if (total_wear == 0)
NS_ERR("Erase counter total overflow\n");
erase_block_wear[erase_block_no] += 1;
if (erase_block_wear[erase_block_no] == 0)
NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
- rptwear_cnt += 1;
- if (rptwear_cnt < rptwear)
- return;
- rptwear_cnt = 0;
- /* Calc wear stats */
- for (i = 0; i < wear_eb_count; ++i) {
- unsigned long wear = erase_block_wear[i];
- if (wear < wmin)
- wmin = wear;
- if (wear > wmax)
- wmax = wear;
- tot += wear;
- }
- for (i = 0; i < 9; ++i) {
- deciles[i] = 0;
- decile_max[i] = (wmax * (i + 1) + 5) / 10;
- }
- deciles[9] = 0;
- decile_max[9] = wmax;
- for (i = 0; i < wear_eb_count; ++i) {
- int d;
- unsigned long wear = erase_block_wear[i];
- for (d = 0; d < 10; ++d)
- if (wear <= decile_max[d]) {
- deciles[d] += 1;
- break;
- }
- }
- avg = tot / wear_eb_count;
- /* Output wear report */
- NS_INFO("*** Wear Report ***\n");
- NS_INFO("Total numbers of erases: %lu\n", tot);
- NS_INFO("Number of erase blocks: %u\n", wear_eb_count);
- NS_INFO("Average number of erases: %lu\n", avg);
- NS_INFO("Maximum number of erases: %lu\n", wmax);
- NS_INFO("Minimum number of erases: %lu\n", wmin);
- for (i = 0; i < 10; ++i) {
- unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
- if (from > decile_max[i])
- continue;
- NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
- from,
- decile_max[i],
- deciles[i]);
- }
- NS_INFO("*** End of Wear Report ***\n");
}
/*
unsigned int page_no = ns->regs.row;
if (read_error(page_no)) {
- int i;
- memset(ns->buf.byte, 0xFF, num);
- for (i = 0; i < num; ++i)
- ns->buf.byte[i] = random32();
+ prandom_bytes(ns->buf.byte, num);
NS_WARN("simulating read error in page %u\n", page_no);
return 1;
}
if ((retval = setup_wear_reporting(nsmtd)) != 0)
goto err_exit;
+ if ((retval = nandsim_debugfs_create(nand)) != 0)
+ goto err_exit;
+
if ((retval = init_nandsim(nsmtd)) != 0)
goto err_exit;
struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
int i;
+ nandsim_debugfs_remove(ns);
free_nandsim(ns); /* Free nandsim private resources */
nand_release(nsmtd); /* Unregister driver */
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
#include <linux/bch.h>
#endif
-#include <plat/dma.h>
-#include <plat/gpmc.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#define DRIVER_NAME "omap2-nand"
#define CS_MASK 0x7
#define ENABLE_PREFETCH (0x1 << 7)
#define DMA_MPU_MODE_SHIFT 2
+#define ECCSIZE0_SHIFT 12
#define ECCSIZE1_SHIFT 22
#define ECC1RESULTSIZE 0x1
#define ECCCLEAR 0x100
#define ECC1 0x1
+#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
+#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
+#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
+#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
+#define STATUS_BUFF_EMPTY 0x00000001
+
+#define OMAP24XX_DMA_GPMC 4
/* oob info generated runtime depending on ecc algorithm and layout selected */
static struct nand_ecclayout omap_oobinfo;
/* wait until buffer is available for write */
do {
status = readl(info->reg.gpmc_status) &
- GPMC_STATUS_BUFF_EMPTY;
+ STATUS_BUFF_EMPTY;
} while (!status);
}
}
/* wait until buffer is available for write */
do {
status = readl(info->reg.gpmc_status) &
- GPMC_STATUS_BUFF_EMPTY;
+ STATUS_BUFF_EMPTY;
} while (!status);
}
}
} else {
do {
r_count = readl(info->reg.gpmc_prefetch_status);
- r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
+ r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
r_count = r_count >> 2;
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
p += r_count;
} else {
while (len) {
w_count = readl(info->reg.gpmc_prefetch_status);
- w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
+ w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
w_count = w_count >> 1;
for (i = 0; (i < w_count) && len; i++, len -= 2)
iowrite16(*p++, info->nand.IO_ADDR_W);
do {
cpu_relax();
val = readl(info->reg.gpmc_prefetch_status);
- val = GPMC_PREFETCH_STATUS_COUNT(val);
+ val = PREFETCH_STATUS_COUNT(val);
} while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
do {
cpu_relax();
val = readl(info->reg.gpmc_prefetch_status);
- val = GPMC_PREFETCH_STATUS_COUNT(val);
+ val = PREFETCH_STATUS_COUNT(val);
} while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
u32 bytes;
bytes = readl(info->reg.gpmc_prefetch_status);
- bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes);
+ bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */
if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
if (this_irq == info->gpmc_irq_count)
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
do {
val = readl(info->reg.gpmc_prefetch_status);
- val = GPMC_PREFETCH_STATUS_COUNT(val);
+ val = PREFETCH_STATUS_COUNT(val);
cpu_relax();
} while (val && (tim++ < limit));
cond_resched();
}
- status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
+ status = readb(info->reg.gpmc_nand_data);
return status;
}
static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
{
int nerrors;
- unsigned int dev_width;
+ unsigned int dev_width, nsectors;
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
struct nand_chip *chip = mtd->priv;
+ u32 val;
nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4;
dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+ nsectors = 1;
/*
* Program GPMC to perform correction on one 512-byte sector at a time.
* Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and
* gives a slight (5%) performance gain (but requires additional code).
*/
- (void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors);
+
+ writel(ECC1, info->reg.gpmc_ecc_control);
+
+ /*
+ * When using BCH, sector size is hardcoded to 512 bytes.
+ * Here we are using wrapping mode 6 both for reading and writing, with:
+ * size0 = 0 (no additional protected byte in spare area)
+ * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
+ */
+ val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT);
+ writel(val, info->reg.gpmc_ecc_size_config);
+
+ /* BCH configuration */
+ val = ((1 << 16) | /* enable BCH */
+ (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
+ (0x06 << 8) | /* wrap mode = 6 */
+ (dev_width << 7) | /* bus width */
+ (((nsectors-1) & 0x7) << 4) | /* number of sectors */
+ (info->gpmc_cs << 1) | /* ECC CS */
+ (0x1)); /* enable ECC */
+
+ writel(val, info->reg.gpmc_ecc_config);
+
+ /* clear ecc and enable bits */
+ writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
}
/**
{
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
- return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code);
+ unsigned long nsectors, val1, val2;
+ int i;
+
+ nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
+
+ for (i = 0; i < nsectors; i++) {
+
+ /* Read hw-computed remainder */
+ val1 = readl(info->reg.gpmc_bch_result0[i]);
+ val2 = readl(info->reg.gpmc_bch_result1[i]);
+
+ /*
+ * Add constant polynomial to remainder, in order to get an ecc
+ * sequence of 0xFFs for a buffer filled with 0xFFs; and
+ * left-justify the resulting polynomial.
+ */
+ *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF);
+ *ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF);
+ *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
+ *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF);
+ *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF);
+ *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF);
+ *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4);
+ }
+
+ return 0;
}
/**
{
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
- return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code);
+ unsigned long nsectors, val1, val2, val3, val4;
+ int i;
+
+ nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
+
+ for (i = 0; i < nsectors; i++) {
+
+ /* Read hw-computed remainder */
+ val1 = readl(info->reg.gpmc_bch_result0[i]);
+ val2 = readl(info->reg.gpmc_bch_result1[i]);
+ val3 = readl(info->reg.gpmc_bch_result2[i]);
+ val4 = readl(info->reg.gpmc_bch_result3[i]);
+
+ /*
+ * Add constant polynomial to remainder, in order to get an ecc
+ * sequence of 0xFFs for a buffer filled with 0xFFs.
+ */
+ *ecc_code++ = 0xef ^ (val4 & 0xFF);
+ *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF);
+ *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF);
+ *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF);
+ *ecc_code++ = 0xed ^ (val3 & 0xFF);
+ *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF);
+ *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF);
+ *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
+ *ecc_code++ = 0x97 ^ (val2 & 0xFF);
+ *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF);
+ *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
+ *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF);
+ *ecc_code++ = 0xb5 ^ (val1 & 0xFF);
+ }
+
+ return 0;
}
/**
*/
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
{
- int ret, max_errors;
+ int max_errors;
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
#ifdef CONFIG_MTD_NAND_OMAP_BCH8
goto fail;
}
- /* initialize GPMC BCH engine */
- ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors);
- if (ret)
- goto fail;
-
/* software bch library is only used to detect and locate errors */
info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */);
if (!info->bch)
}
#endif /* CONFIG_MTD_NAND_OMAP_BCH */
- static int __devinit omap_nand_probe(struct platform_device *pdev)
+ static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);
iounmap(info->nand.IO_ADDR_R);
- release_mem_region(info->phys_base, NAND_IO_SIZE);
+ release_mem_region(info->phys_base, info->mem_size);
kfree(info);
return 0;
}
struct s3c2410_nand_mtd *mtd,
struct s3c2410_nand_set *set)
{
- if (set)
+ if (set) {
mtd->mtd.name = set->name;
- return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
+ return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
set->partitions, set->nr_partitions);
+ }
+
+ return -ENODEV;
}
/**
if (chip->ecc.mode != NAND_ECC_HW)
return;
- /* change the behaviour depending on wether we are using
+ /* change the behaviour depending on whether we are using
* the large or small page nand device */
if (chip->page_shift > 10) {
#include <linux/module.h>
#include <linux/kernel.h>
+ #include <linux/completion.h>
#include <linux/delay.h>
+ #include <linux/dmaengine.h>
+ #include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_mtd.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+ #include <linux/sh_dma.h>
#include <linux/slab.h>
#include <linux/string.h>
writeb(0x0, FLTRCR(flctl));
}
+ static void flctl_dma_complete(void *param)
+ {
+ struct sh_flctl *flctl = param;
+
+ complete(&flctl->dma_complete);
+ }
+
+ static void flctl_release_dma(struct sh_flctl *flctl)
+ {
+ if (flctl->chan_fifo0_rx) {
+ dma_release_channel(flctl->chan_fifo0_rx);
+ flctl->chan_fifo0_rx = NULL;
+ }
+ if (flctl->chan_fifo0_tx) {
+ dma_release_channel(flctl->chan_fifo0_tx);
+ flctl->chan_fifo0_tx = NULL;
+ }
+ }
+
+ static void flctl_setup_dma(struct sh_flctl *flctl)
+ {
+ dma_cap_mask_t mask;
+ struct dma_slave_config cfg;
+ struct platform_device *pdev = flctl->pdev;
+ struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (!pdata)
+ return;
+
+ if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
+ return;
+
+ /* We can only either use DMA for both Tx and Rx or not use it at all */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
+ (void *)pdata->slave_id_fifo0_tx);
+ dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
+ flctl->chan_fifo0_tx);
+
+ if (!flctl->chan_fifo0_tx)
+ return;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.slave_id = pdata->slave_id_fifo0_tx;
+ cfg.direction = DMA_MEM_TO_DEV;
+ cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+ cfg.src_addr = 0;
+ ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
+ if (ret < 0)
+ goto err;
+
+ flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
+ (void *)pdata->slave_id_fifo0_rx);
+ dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
+ flctl->chan_fifo0_rx);
+
+ if (!flctl->chan_fifo0_rx)
+ goto err;
+
+ cfg.slave_id = pdata->slave_id_fifo0_rx;
+ cfg.direction = DMA_DEV_TO_MEM;
+ cfg.dst_addr = 0;
+ cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+ ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
+ if (ret < 0)
+ goto err;
+
+ init_completion(&flctl->dma_complete);
+
+ return;
+
+ err:
+ flctl_release_dma(flctl);
+ }
+
static void set_addr(struct mtd_info *mtd, int column, int page_addr)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
for (i = 0; i < 3; i++) {
uint8_t org;
- int index;
+ unsigned int index;
data = readl(ecc_reg[i]);
timeout_error(flctl, __func__);
}
+ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
+ int len, enum dma_data_direction dir)
+ {
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan;
+ enum dma_transfer_direction tr_dir;
+ dma_addr_t dma_addr;
+ dma_cookie_t cookie = -EINVAL;
+ uint32_t reg;
+ int ret;
+
+ if (dir == DMA_FROM_DEVICE) {
+ chan = flctl->chan_fifo0_rx;
+ tr_dir = DMA_DEV_TO_MEM;
+ } else {
+ chan = flctl->chan_fifo0_tx;
+ tr_dir = DMA_MEM_TO_DEV;
+ }
+
+ dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+
+ if (dma_addr)
+ desc = dmaengine_prep_slave_single(chan, dma_addr, len,
+ tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+ if (desc) {
+ reg = readl(FLINTDMACR(flctl));
+ reg |= DREQ0EN;
+ writel(reg, FLINTDMACR(flctl));
+
+ desc->callback = flctl_dma_complete;
+ desc->callback_param = flctl;
+ cookie = dmaengine_submit(desc);
+
+ dma_async_issue_pending(chan);
+ } else {
+ /* DMA failed, fall back to PIO */
+ flctl_release_dma(flctl);
+ dev_warn(&flctl->pdev->dev,
+ "DMA failed, falling back to PIO\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ ret =
+ wait_for_completion_timeout(&flctl->dma_complete,
+ msecs_to_jiffies(3000));
+
+ if (ret <= 0) {
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+ }
+
+ out:
+ reg = readl(FLINTDMACR(flctl));
+ reg &= ~DREQ0EN;
+ writel(reg, FLINTDMACR(flctl));
+
+ dma_unmap_single(chan->device->dev, dma_addr, len, dir);
+
+ /* ret > 0 is success */
+ return ret;
+ }
+
static void read_datareg(struct sh_flctl *flctl, int offset)
{
unsigned long data;
len_4align = (rlen + 3) / 4;
+ /* initiate DMA transfer */
+ if (flctl->chan_fifo0_rx && rlen >= 32 &&
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+ goto convert; /* DMA success */
+
+ /* do polling transfer */
for (i = 0; i < len_4align; i++) {
wait_rfifo_ready(flctl);
buf[i] = readl(FLDTFIFO(flctl));
- buf[i] = be32_to_cpu(buf[i]);
}
+
+ convert:
+ for (i = 0; i < len_4align; i++)
+ buf[i] = be32_to_cpu(buf[i]);
}
static enum flctl_ecc_res_t read_ecfiforeg
return res;
}
- static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+ static void write_fiforeg(struct sh_flctl *flctl, int rlen,
+ unsigned int offset)
{
int i, len_4align;
- unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
- void *fifo_addr = (void *)FLDTFIFO(flctl);
+ unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
len_4align = (rlen + 3) / 4;
for (i = 0; i < len_4align; i++) {
wait_wfifo_ready(flctl);
- writel(cpu_to_be32(data[i]), fifo_addr);
+ writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
}
}
- static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
+ unsigned int offset)
{
int i, len_4align;
- unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+ unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
len_4align = (rlen + 3) / 4;
+
+ for (i = 0; i < len_4align; i++)
+ buf[i] = cpu_to_be32(buf[i]);
+
+ /* initiate DMA transfer */
+ if (flctl->chan_fifo0_tx && rlen >= 32 &&
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+ return; /* DMA success */
+
+ /* do polling transfer */
for (i = 0; i < len_4align; i++) {
wait_wecfifo_ready(flctl);
- writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+ writel(buf[i], FLECFIFO(flctl));
}
}
if (!flctl->qos_request) {
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
- &flctl->pm_qos, 100);
+ &flctl->pm_qos,
+ DEV_PM_QOS_LATENCY,
+ 100);
if (ret < 0)
dev_err(&flctl->pdev->dev,
"PM QoS request failed: %d\n", ret);
static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int index = flctl->index;
- memcpy(&flctl->done_buff[index], buf, len);
+ memcpy(&flctl->done_buff[flctl->index], buf, len);
flctl->index += len;
}
static uint8_t flctl_read_byte(struct mtd_info *mtd)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int index = flctl->index;
uint8_t data;
- data = flctl->done_buff[index];
+ data = flctl->done_buff[flctl->index];
flctl->index++;
return data;
}
static uint16_t flctl_read_word(struct mtd_info *mtd)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int index = flctl->index;
- uint16_t data;
- uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
- data = *buf;
- flctl->index += 2;
- return data;
+ flctl->index += 2;
+ return *buf;
}
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int index = flctl->index;
- memcpy(buf, &flctl->done_buff[index], len);
+ memcpy(buf, &flctl->done_buff[flctl->index], len);
flctl->index += len;
}
return IRQ_HANDLED;
}
- static int __devinit flctl_probe(struct platform_device *pdev)
+ #ifdef CONFIG_OF
+ struct flctl_soc_config {
+ unsigned long flcmncr_val;
+ unsigned has_hwecc:1;
+ unsigned use_holden:1;
+ };
+
+ static struct flctl_soc_config flctl_sh7372_config = {
+ .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
+ .has_hwecc = 1,
+ .use_holden = 1,
+ };
+
+ static const struct of_device_id of_flctl_match[] = {
+ { .compatible = "renesas,shmobile-flctl-sh7372",
+ .data = &flctl_sh7372_config },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, of_flctl_match);
+
+ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+ {
+ const struct of_device_id *match;
+ struct flctl_soc_config *config;
+ struct sh_flctl_platform_data *pdata;
+ struct device_node *dn = dev->of_node;
+ int ret;
+
+ match = of_match_device(of_flctl_match, dev);
+ if (match)
+ config = (struct flctl_soc_config *)match->data;
+ else {
+ dev_err(dev, "%s: no OF configuration attached\n", __func__);
+ return NULL;
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "%s: failed to allocate config data\n", __func__);
+ return NULL;
+ }
+
+ /* set SoC specific options */
+ pdata->flcmncr_val = config->flcmncr_val;
+ pdata->has_hwecc = config->has_hwecc;
+ pdata->use_holden = config->use_holden;
+
+ /* parse user defined options */
+ ret = of_get_nand_bus_width(dn);
+ if (ret == 16)
+ pdata->flcmncr_val |= SEL_16BIT;
+ else if (ret != 8) {
+ dev_err(dev, "%s: invalid bus width\n", __func__);
+ return NULL;
+ }
+
+ return pdata;
+ }
+ #else /* CONFIG_OF */
+ #define of_flctl_match NULL
+ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+ {
+ return NULL;
+ }
+ #endif /* CONFIG_OF */
+
+ static int flctl_probe(struct platform_device *pdev)
{
struct resource *res;
struct sh_flctl *flctl;
struct sh_flctl_platform_data *pdata;
int ret = -ENXIO;
int irq;
-
- pdata = pdev->dev.platform_data;
- if (pdata == NULL) {
- dev_err(&pdev->dev, "no platform data defined\n");
- return -EINVAL;
- }
+ struct mtd_part_parser_data ppdata = {};
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
if (!flctl) {
goto err_flste;
}
+ if (pdev->dev.of_node)
+ pdata = flctl_parse_dt(&pdev->dev);
+ else
+ pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no setup data defined\n");
+ ret = -EINVAL;
+ goto err_pdata;
+ }
+
platform_set_drvdata(pdev, flctl);
flctl_mtd = &flctl->mtd;
nand = &flctl->chip;
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
+ flctl_setup_dma(flctl);
+
ret = nand_scan_ident(flctl_mtd, 1, NULL);
if (ret)
goto err_chip;
if (ret)
goto err_chip;
- mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+ ppdata.of_node = pdev->dev.of_node;
+ ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
+ pdata->nr_parts);
return 0;
err_chip:
+ flctl_release_dma(flctl);
pm_runtime_disable(&pdev->dev);
+ err_pdata:
free_irq(irq, flctl);
err_flste:
iounmap(flctl->reg);
return ret;
}
- static int __devexit flctl_remove(struct platform_device *pdev)
+ static int flctl_remove(struct platform_device *pdev)
{
struct sh_flctl *flctl = platform_get_drvdata(pdev);
+ flctl_release_dma(flctl);
nand_release(&flctl->mtd);
pm_runtime_disable(&pdev->dev);
free_irq(platform_get_irq(pdev, 0), flctl);
.driver = {
.name = "sh_flctl",
.owner = THIS_MODULE,
+ .of_match_table = of_flctl_match,
},
};
#include <linux/regulator/consumer.h>
#include <asm/mach/flash.h>
-#include <plat/gpmc.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <asm/gpio.h>
-#include <plat/dma.h>
-#include <plat/cpu.h>
+#include <linux/omap-dma.h>
#define DRIVER_NAME "omap2-onenand"
int freq;
int (*setup)(void __iomem *base, int *freq_ptr);
struct regulator *regulator;
+ u8 flags;
};
static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) {
syscfg |= ONENAND_SYS_CFG1_IOBE;
write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
- if (cpu_is_omap34xx())
+ if (c->flags & ONENAND_IN_OMAP34XX)
/* Add a delay to let GPIO settle */
syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
}
#else
-int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
- unsigned char *buffer, int offset,
- size_t count);
+static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ return -ENOSYS;
+}
-int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
- const unsigned char *buffer,
- int offset, size_t count);
+static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ return -ENOSYS;
+}
#endif
#else
-int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
- unsigned char *buffer, int offset,
- size_t count);
+static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+ unsigned char *buffer, int offset,
+ size_t count)
+{
+ return -ENOSYS;
+}
-int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
- const unsigned char *buffer,
- int offset, size_t count);
+static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer,
+ int offset, size_t count)
+{
+ return -ENOSYS;
+}
#endif
return ret;
}
- static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+ static int omap2_onenand_probe(struct platform_device *pdev)
{
struct omap_onenand_platform_data *pdata;
struct omap2_onenand *c;
init_completion(&c->irq_done);
init_completion(&c->dma_done);
+ c->flags = pdata->flags;
c->gpmc_cs = pdata->cs;
c->gpio_irq = pdata->gpio_irq;
c->dma_channel = pdata->dma_channel;
this = &c->onenand;
if (c->dma_channel >= 0) {
this->wait = omap2_onenand_wait;
- if (cpu_is_omap34xx()) {
+ if (c->flags & ONENAND_IN_OMAP34XX) {
this->read_bufferram = omap3_onenand_read_bufferram;
this->write_bufferram = omap3_onenand_write_bufferram;
} else {
return r;
}
- static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+ static int omap2_onenand_remove(struct platform_device *pdev)
{
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
}
iounmap(c->onenand.base);
release_mem_region(c->phys_base, c->mem_size);
- gpmc_cs_free(c->gpmc_cs);
kfree(c);
return 0;
static struct platform_driver omap2_onenand_driver = {
.probe = omap2_onenand_probe,
- .remove = __devexit_p(omap2_onenand_remove),
+ .remove = omap2_onenand_remove,
.shutdown = omap2_onenand_shutdown,
.driver = {
.name = DRIVER_NAME,
/* Chip IDs of SoCs */
#define BCMA_CHIP_ID_BCM4706 0x5300
+#define BCMA_PKG_ID_BCM4706L 1
#define BCMA_CHIP_ID_BCM4716 0x4716
#define BCMA_PKG_ID_BCM4716 8
#define BCMA_PKG_ID_BCM4717 9
#define BCMA_CHIP_ID_BCM4749 0x4749
#define BCMA_CHIP_ID_BCM5356 0x5356
#define BCMA_CHIP_ID_BCM5357 0x5357
+#define BCMA_PKG_ID_BCM5358 9
+#define BCMA_PKG_ID_BCM47186 10
+#define BCMA_PKG_ID_BCM5357 11
#define BCMA_CHIP_ID_BCM53572 53572
+#define BCMA_PKG_ID_BCM47188 9
struct bcma_device {
struct bcma_bus *bus;
u8 num;
struct bcma_drv_cc drv_cc;
- struct bcma_drv_pci drv_pci;
+ struct bcma_drv_pci drv_pci[2];
struct bcma_drv_mips drv_mips;
struct bcma_drv_gmac_cmn drv_gmac_cmn;
enum bcma_clkmode clkmode);
extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
bool on);
+ extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset);
#define BCMA_DMA_TRANSLATION_MASK 0xC0000000
#define BCMA_DMA_TRANSLATION_NONE 0x00000000
#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */