aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/onenand/omap-onenand.c271
-rw-r--r--include/linux/mtd/onenand.h8
2 files changed, 97 insertions, 182 deletions
diff --git a/drivers/mtd/onenand/omap-onenand.c b/drivers/mtd/onenand/omap-onenand.c
index 7c89549f7f58..57e69f184d33 100644
--- a/drivers/mtd/onenand/omap-onenand.c
+++ b/drivers/mtd/onenand/omap-onenand.c
@@ -4,236 +4,143 @@
4 * Copyright (c) 2005 Samsung Electronics 4 * Copyright (c) 2005 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com> 5 * Kyungmin Park <kyungmin.park@samsung.com>
6 * 6 *
7 * Derived from linux/drivers/mtd/nand/omap-nand-flash.c
8 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
12 * 10 *
13 * Overview: 11 * Overview:
14 * This is a device driver for the OneNAND flash device for TI OMAP boards. 12 * This is a device driver for the OneNAND flash for OMAP boards.
15 */ 13 */
16 14
17#include <linux/slab.h> 15#include <linux/device.h>
18#include <linux/init.h>
19#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/init.h>
20#include <linux/mtd/mtd.h> 18#include <linux/mtd/mtd.h>
21#include <linux/mtd/onenand.h> 19#include <linux/mtd/onenand.h>
22#include <linux/mtd/partitions.h> 20#include <linux/mtd/partitions.h>
23 21
24#include <asm/io.h> 22#include <asm/io.h>
25#include <asm/arch/hardware.h> 23#include <asm/mach/flash.h>
26#include <asm/arch/tc.h>
27#include <asm/sizes.h>
28#include <asm/mach-types.h>
29 24
30#define OMAP_ONENAND_FLASH_START1 OMAP_CS2A_PHYS 25#define DRIVER_NAME "onenand"
31#define OMAP_ONENAND_FLASH_START2 omap_cs3_phys()
32/*
33 * MTD structure for OMAP board
34 */
35static struct mtd_info *omap_onenand_mtd = NULL;
36 26
37/*
38 * Define partitions for flash devices
39 */
40 27
41#ifdef CONFIG_MTD_PARTITIONS 28#ifdef CONFIG_MTD_PARTITIONS
42static struct mtd_partition static_partition[] = {
43 {
44 .name = "X-Loader + U-Boot",
45 .offset = 0,
46 .size = SZ_128K,
47 .mask_flags = MTD_WRITEABLE /* force read-only */
48 },
49 {
50 .name = "U-Boot Environment",
51 .offset = MTDPART_OFS_APPEND,
52 .size = SZ_128K,
53 .mask_flags = MTD_WRITEABLE /* force read-only */
54 },
55 {
56 .name = "kernel",
57 .offset = MTDPART_OFS_APPEND,
58 .size = 2 * SZ_1M
59 },
60 {
61 .name = "filesystem0",
62 .offset = MTDPART_OFS_APPEND,
63 .size = SZ_16M,
64 },
65 {
66 .name = "filesystem1",
67 .offset = MTDPART_OFS_APPEND,
68 .size = MTDPART_SIZ_FULL,
69 },
70};
71
72static const char *part_probes[] = { "cmdlinepart", NULL, }; 29static const char *part_probes[] = { "cmdlinepart", NULL, };
73
74#endif 30#endif
75 31
76#ifdef CONFIG_MTD_ONENAND_SYNC_READ 32struct omap_onenand_info {
77static unsigned int omap_emifs_cs; 33 struct mtd_info mtd;
34 struct mtd_partition *parts;
35 struct onenand_chip onenand;
36};
78 37
79static void omap_find_emifs_cs(unsigned int addr) 38static int __devinit omap_onenand_probe(struct device *dev)
80{ 39{
81 /* Check CS3 */ 40 struct omap_onenand_info *info;
82 if (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM && addr == 0x0) { 41 struct platform_device *pdev = to_platform_device(dev);
83 omap_emifs_cs = 3; 42 struct onenand_platform_data *pdata = pdev->dev.platform_data;
84 } else { 43 struct resource *res = pdev->resource;
85 omap_emifs_cs = (addr >> 26); 44 unsigned long size = res->end - res->start + 1;
45 int err;
46
47 info = kmalloc(sizeof(struct omap_onenand_info), GFP_KERNEL);
48 if (!info)
49 return -ENOMEM;
50
51 memset(info, 0, sizeof(struct omap_onenand_info));
52
53 if (!request_mem_region(res->start, size, dev->driver->name)) {
54 err = -EBUSY;
55 goto out_free_info;
86 } 56 }
87}
88 57
89/** 58 info->onenand.base = ioremap(res->start, size);
90 * omap_onenand_mmcontrol - Control OMAP EMIFS 59 if (!info->onenand.base) {
91 */ 60 err = -ENOMEM;
92static void omap_onenand_mmcontrol(struct mtd_info *mtd, int sync_read) 61 goto out_release_mem_region;
93{
94 struct onenand_chip *this = mtd->priv;
95 static unsigned long omap_emifs_ccs, omap_emifs_acs;
96 static unsigned long onenand_sys_cfg1;
97 int config, emifs_ccs, emifs_acs;
98
99 if (sync_read) {
100 /*
101 * Note: BRL and RDWST is equal
102 */
103 omap_emifs_ccs = EMIFS_CCS(omap_emifs_cs);
104 omap_emifs_acs = EMIFS_ACS(omap_emifs_cs);
105
106 emifs_ccs = 0x41141;
107 emifs_acs = 0x1;
108
109 /* OneNAND System Configuration 1 */
110 onenand_sys_cfg1 = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
111 config = (onenand_sys_cfg1
112 & ~(0x3f << ONENAND_SYS_CFG1_BL_SHIFT))
113 | ONENAND_SYS_CFG1_SYNC_READ
114 | ONENAND_SYS_CFG1_BRL_4
115 | ONENAND_SYS_CFG1_BL_8;
116 } else {
117 emifs_ccs = omap_emifs_ccs;
118 emifs_acs = omap_emifs_acs;
119 config = onenand_sys_cfg1;
120 } 62 }
121 63
122 this->write_word(config, this->base + ONENAND_REG_SYS_CFG1); 64 info->onenand.mmcontrol = pdata->mmcontrol;
123 EMIFS_CCS(omap_emifs_cs) = emifs_ccs;
124 EMIFS_ACS(omap_emifs_cs) = emifs_acs;
125}
126#else
127#define omap_find_emifs_cs(x) do { } while (0)
128#define omap_onenand_mmcontrol NULL
129#endif
130 65
66 info->mtd.name = pdev->dev.bus_id;
67 info->mtd.priv = &info->onenand;
68 info->mtd.owner = THIS_MODULE;
131 69
132/* Scan to find existance of the device at base. 70 if (onenand_scan(&info->mtd, 1)) {
133 This also allocates oob and data internal buffers */ 71 err = -ENXIO;
134static char onenand_name[] = "onenand"; 72 goto out_iounmap;
135
136/*
137 * Main initialization routine
138 */
139static int __init omap_onenand_init (void)
140{
141 struct onenand_chip *this;
142 struct mtd_partition *dynamic_partition = 0;
143 int err = 0;
144
145 /* Allocate memory for MTD device structure and private data */
146 omap_onenand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct onenand_chip),
147 GFP_KERNEL);
148 if (!omap_onenand_mtd) {
149 printk (KERN_WARNING "Unable to allocate OneNAND MTD device structure.\n");
150 err = -ENOMEM;
151 goto out;
152 } 73 }
153 74
154 /* Get pointer to private data */ 75#ifdef CONFIG_MTD_PARTITIONS
155 this = (struct onenand_chip *) (&omap_onenand_mtd[1]); 76 err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
77 if (err > 0)
78 add_mtd_partitions(&info->mtd, info->parts, err);
79 else if (err < 0 && pdata->parts)
80 add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
81 else
82#endif
83 err = add_mtd_device(&info->mtd);
156 84
157 /* Initialize structures */ 85 dev_set_drvdata(&pdev->dev, info);
158 memset((char *) omap_onenand_mtd, 0, sizeof(struct mtd_info) + sizeof(struct onenand_chip));
159 86
160 /* Link the private data with the MTD structure */ 87 return 0;
161 omap_onenand_mtd->priv = this;
162 this->mmcontrol = omap_onenand_mmcontrol;
163 88
164 /* try the first address */ 89out_iounmap:
165 this->base = ioremap(OMAP_ONENAND_FLASH_START1, SZ_128K); 90 iounmap(info->onenand.base);
166 omap_find_emifs_cs(OMAP_ONENAND_FLASH_START1); 91out_release_mem_region:
92 release_mem_region(res->start, size);
93out_free_info:
94 kfree(info);
167 95
168 omap_onenand_mtd->name = onenand_name; 96 return err;
169 if (onenand_scan(omap_onenand_mtd, 1)){ 97}
170 /* try the second address */
171 iounmap(this->base);
172 this->base = ioremap(OMAP_ONENAND_FLASH_START2, SZ_128K);
173 omap_find_emifs_cs(OMAP_ONENAND_FLASH_START2);
174 98
175 if (onenand_scan(omap_onenand_mtd, 1)) { 99static int __devexit omap_onenand_remove(struct device *dev)
176 iounmap(this->base); 100{
177 err = -ENXIO; 101 struct platform_device *pdev = to_platform_device(dev);
178 goto out_mtd; 102 struct omap_onenand_info *info = dev_get_drvdata(&pdev->dev);
179 } 103 struct resource *res = pdev->resource;
180 } 104 unsigned long size = res->end - res->start + 1;
181 105
182 /* Register the partitions */ 106 dev_set_drvdata(&pdev->dev, NULL);
183 switch (omap_onenand_mtd->size) { 107
184 case SZ_128M: 108 if (info) {
185 case SZ_64M: 109 if (info->parts)
186 case SZ_32M: 110 del_mtd_partitions(&info->mtd);
187#ifdef CONFIG_MTD_PARTITIONS
188 err = parse_mtd_partitions(omap_onenand_mtd, part_probes,
189 &dynamic_partition, 0);
190 if (err > 0)
191 err = add_mtd_partitions(omap_onenand_mtd,
192 dynamic_partition, err);
193 else if (1)
194 err = add_mtd_partitions(omap_onenand_mtd,
195 static_partition,
196 ARRAY_SIZE(static_partition));
197 else 111 else
198#endif 112 del_mtd_device(&info->mtd);
199 err = add_mtd_device(omap_onenand_mtd);
200 if (err)
201 goto out_buf;
202 break;
203 113
204 default: 114 onenand_release(&info->mtd);
205 printk(KERN_WARNING "Unsupported OneNAND device\n"); 115 release_mem_region(res->start, size);
206 err = -ENXIO; 116 iounmap(info->onenand.base);
207 goto out_buf; 117 kfree(info);
208 } 118 }
209 119
210 return 0; 120 return 0;
211
212out_buf:
213 onenand_release(omap_onenand_mtd);
214 iounmap(this->base);
215out_mtd:
216 kfree(omap_onenand_mtd);
217out:
218 return err;
219} 121}
220 122
221/* 123static struct device_driver omap_onenand_driver = {
222 * Clean up routine 124 .name = DRIVER_NAME,
223 */ 125 .bus = &platform_bus_type,
224static void __exit omap_onenand_cleanup (void) 126 .probe = omap_onenand_probe,
127 .remove = __devexit_p(omap_onenand_remove),
128};
129
130MODULE_ALIAS(DRIVER_NAME);
131
132static int __init omap_onenand_init(void)
225{ 133{
226 struct onenand_chip *this = omap_onenand_mtd->priv; 134 return driver_register(&omap_onenand_driver);
135}
227 136
228 /* onenand_release frees MTD partitions, MTD structure 137static void __exit omap_onenand_exit(void)
229 and onenand internal buffers */ 138{
230 onenand_release(omap_onenand_mtd); 139 driver_unregister(&omap_onenand_driver);
231 iounmap(this->base);
232 kfree(omap_onenand_mtd);
233} 140}
234 141
235module_init(omap_onenand_init); 142module_init(omap_onenand_init);
236module_exit(omap_onenand_cleanup); 143module_exit(omap_onenand_exit);
237 144
238MODULE_LICENSE("GPL"); 145MODULE_LICENSE("GPL");
239MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 146MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 89aaffbc9576..2c29a5ca2c91 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -115,10 +115,18 @@ struct onenand_chip {
115 void *priv; 115 void *priv;
116}; 116};
117 117
118/*
119 * Helper macros
120 */
118#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) 121#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index)
119#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) 122#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1)
120#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) 123#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)
121 124
125#define ONENAND_GET_SYS_CFG1(this) \
126 (this->read_word(this->base + ONENAND_REG_SYS_CFG1))
127#define ONENAND_SET_SYS_CFG1(v, this) \
128 (this->write_word(v, this->base + ONENAND_REG_SYS_CFG1))
129
122/* 130/*
123 * Options bits 131 * Options bits
124 */ 132 */