aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.c139
-rw-r--r--arch/arm/plat-omap/include/plat/nand.h10
-rw-r--r--drivers/mtd/nand/omap2.c35
4 files changed, 155 insertions, 32 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 492cf164e000..0b17dca695fd 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -135,5 +135,8 @@ obj-y += usb-ehci.o
135onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o 135onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o
136obj-y += $(onenand-m) $(onenand-y) 136obj-y += $(onenand-m) $(onenand-y)
137 137
138nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o
139obj-y += $(nand-m) $(nand-y)
140
138smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o 141smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
139obj-y += $(smc91x-m) $(smc91x-y) 142obj-y += $(smc91x-m) $(smc91x-y)
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
new file mode 100644
index 000000000000..64d74f05abbe
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -0,0 +1,139 @@
1/*
2 * gpmc-nand.c
3 *
4 * Copyright (C) 2009 Texas Instruments
5 * Vimal Singh <vimalsingh@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/platform_device.h>
14#include <linux/io.h>
15
16#include <asm/mach/flash.h>
17
18#include <plat/nand.h>
19#include <plat/board.h>
20#include <plat/gpmc.h>
21
22#define WR_RD_PIN_MONITORING 0x00600000
23
24static struct omap_nand_platform_data *gpmc_nand_data;
25
26static struct resource gpmc_nand_resource = {
27 .flags = IORESOURCE_MEM,
28};
29
30static struct platform_device gpmc_nand_device = {
31 .name = "omap2-nand",
32 .id = 0,
33 .num_resources = 1,
34 .resource = &gpmc_nand_resource,
35};
36
37static int omap2_nand_gpmc_retime(void)
38{
39 struct gpmc_timings t;
40 int err;
41
42 memset(&t, 0, sizeof(t));
43 t.sync_clk = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->sync_clk);
44 t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on);
45 t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on);
46
47 /* Read */
48 t.adv_rd_off = gpmc_round_ns_to_ticks(
49 gpmc_nand_data->gpmc_t->adv_rd_off);
50 t.oe_on = t.adv_on;
51 t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access);
52 t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off);
53 t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off);
54 t.rd_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle);
55
56 /* Write */
57 t.adv_wr_off = gpmc_round_ns_to_ticks(
58 gpmc_nand_data->gpmc_t->adv_wr_off);
59 t.we_on = t.oe_on;
60 if (cpu_is_omap34xx()) {
61 t.wr_data_mux_bus = gpmc_round_ns_to_ticks(
62 gpmc_nand_data->gpmc_t->wr_data_mux_bus);
63 t.wr_access = gpmc_round_ns_to_ticks(
64 gpmc_nand_data->gpmc_t->wr_access);
65 }
66 t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off);
67 t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off);
68 t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
69
70 /* Configure GPMC */
71 gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
72 GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
73 GPMC_CONFIG1_DEVICETYPE_NAND);
74
75 err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
76 if (err)
77 return err;
78
79 return 0;
80}
81
82static int gpmc_nand_setup(void)
83{
84 struct device *dev = &gpmc_nand_device.dev;
85
86 /* Set timings in GPMC */
87 if (omap2_nand_gpmc_retime() < 0) {
88 dev_err(dev, "Unable to set gpmc timings\n");
89 return -EINVAL;
90 }
91
92 return 0;
93}
94
95int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
96{
97 unsigned int val;
98 int err = 0;
99 struct device *dev = &gpmc_nand_device.dev;
100
101 gpmc_nand_data = _nand_data;
102 gpmc_nand_data->nand_setup = gpmc_nand_setup;
103 gpmc_nand_device.dev.platform_data = gpmc_nand_data;
104
105 err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
106 &gpmc_nand_data->phys_base);
107 if (err < 0) {
108 dev_err(dev, "Cannot request GPMC CS\n");
109 return err;
110 }
111
112 err = gpmc_nand_setup();
113 if (err < 0) {
114 dev_err(dev, "NAND platform setup failed: %d\n", err);
115 return err;
116 }
117
118 /* Enable RD PIN Monitoring Reg */
119 if (gpmc_nand_data->dev_ready) {
120 val = gpmc_cs_read_reg(gpmc_nand_data->cs,
121 GPMC_CS_CONFIG1);
122 val |= WR_RD_PIN_MONITORING;
123 gpmc_cs_write_reg(gpmc_nand_data->cs,
124 GPMC_CS_CONFIG1, val);
125 }
126
127 err = platform_device_register(&gpmc_nand_device);
128 if (err < 0) {
129 dev_err(dev, "Unable to register NAND device\n");
130 goto out_free_cs;
131 }
132
133 return 0;
134
135out_free_cs:
136 gpmc_cs_free(gpmc_nand_data->cs);
137
138 return err;
139}
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index 631a7bed1eef..6ba88d2630d9 100644
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -15,10 +15,18 @@ struct omap_nand_platform_data {
15 int cs; 15 int cs;
16 int gpio_irq; 16 int gpio_irq;
17 struct mtd_partition *parts; 17 struct mtd_partition *parts;
18 struct gpmc_timings *gpmc_t;
18 int nr_parts; 19 int nr_parts;
19 int (*nand_setup)(void __iomem *); 20 int (*nand_setup)(void);
20 int (*dev_ready)(struct omap_nand_platform_data *); 21 int (*dev_ready)(struct omap_nand_platform_data *);
21 int dma_channel; 22 int dma_channel;
23 unsigned long phys_base;
22 void __iomem *gpmc_cs_baseaddr; 24 void __iomem *gpmc_cs_baseaddr;
23 void __iomem *gpmc_baseaddr; 25 void __iomem *gpmc_baseaddr;
26 int devsize;
24}; 27};
28
29/* size (4 KiB) for IO mapping */
30#define NAND_IO_SIZE SZ_4K
31
32extern int gpmc_nand_init(struct omap_nand_platform_data *d);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 1bb799f0125c..26aec0080184 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -30,12 +30,8 @@
30 30
31#define DRIVER_NAME "omap2-nand" 31#define DRIVER_NAME "omap2-nand"
32 32
33/* size (4 KiB) for IO mapping */
34#define NAND_IO_SIZE SZ_4K
35
36#define NAND_WP_OFF 0 33#define NAND_WP_OFF 0
37#define NAND_WP_BIT 0x00000010 34#define NAND_WP_BIT 0x00000010
38#define WR_RD_PIN_MONITORING 0x00600000
39 35
40#define GPMC_BUF_FULL 0x00000001 36#define GPMC_BUF_FULL 0x00000001
41#define GPMC_BUF_EMPTY 0x00000000 37#define GPMC_BUF_EMPTY 0x00000000
@@ -882,8 +878,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
882 struct omap_nand_info *info; 878 struct omap_nand_info *info;
883 struct omap_nand_platform_data *pdata; 879 struct omap_nand_platform_data *pdata;
884 int err; 880 int err;
885 unsigned long val;
886
887 881
888 pdata = pdev->dev.platform_data; 882 pdata = pdev->dev.platform_data;
889 if (pdata == NULL) { 883 if (pdata == NULL) {
@@ -905,28 +899,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
905 info->gpmc_cs = pdata->cs; 899 info->gpmc_cs = pdata->cs;
906 info->gpmc_baseaddr = pdata->gpmc_baseaddr; 900 info->gpmc_baseaddr = pdata->gpmc_baseaddr;
907 info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr; 901 info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr;
902 info->phys_base = pdata->phys_base;
908 903
909 info->mtd.priv = &info->nand; 904 info->mtd.priv = &info->nand;
910 info->mtd.name = dev_name(&pdev->dev); 905 info->mtd.name = dev_name(&pdev->dev);
911 info->mtd.owner = THIS_MODULE; 906 info->mtd.owner = THIS_MODULE;
912 907
913 err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base); 908 info->nand.options |= pdata->devsize ? NAND_BUSWIDTH_16 : 0;
914 if (err < 0) { 909 info->nand.options |= NAND_SKIP_BBTSCAN;
915 dev_err(&pdev->dev, "Cannot request GPMC CS\n");
916 goto out_free_info;
917 }
918
919 /* Enable RD PIN Monitoring Reg */
920 if (pdata->dev_ready) {
921 val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1);
922 val |= WR_RD_PIN_MONITORING;
923 gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val);
924 }
925
926 val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7);
927 val &= ~(0xf << 8);
928 val |= (0xc & 0xf) << 8;
929 gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val);
930 910
931 /* NAND write protect off */ 911 /* NAND write protect off */
932 omap_nand_wp(&info->mtd, NAND_WP_OFF); 912 omap_nand_wp(&info->mtd, NAND_WP_OFF);
@@ -934,7 +914,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
934 if (!request_mem_region(info->phys_base, NAND_IO_SIZE, 914 if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
935 pdev->dev.driver->name)) { 915 pdev->dev.driver->name)) {
936 err = -EBUSY; 916 err = -EBUSY;
937 goto out_free_cs; 917 goto out_free_info;
938 } 918 }
939 919
940 info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE); 920 info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
@@ -963,11 +943,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
963 info->nand.chip_delay = 50; 943 info->nand.chip_delay = 50;
964 } 944 }
965 945
966 info->nand.options |= NAND_SKIP_BBTSCAN;
967 if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000)
968 == 0x1000)
969 info->nand.options |= NAND_BUSWIDTH_16;
970
971 if (use_prefetch) { 946 if (use_prefetch) {
972 /* copy the virtual address of nand base for fifo access */ 947 /* copy the virtual address of nand base for fifo access */
973 info->nand_pref_fifo_add = info->nand.IO_ADDR_R; 948 info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
@@ -1043,8 +1018,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
1043 1018
1044out_release_mem_region: 1019out_release_mem_region:
1045 release_mem_region(info->phys_base, NAND_IO_SIZE); 1020 release_mem_region(info->phys_base, NAND_IO_SIZE);
1046out_free_cs:
1047 gpmc_cs_free(info->gpmc_cs);
1048out_free_info: 1021out_free_info:
1049 kfree(info); 1022 kfree(info);
1050 1023