Blame view

drivers/mtd/maps/pmcmsp-flash.c 6.1 KB
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
1
2
3
4
5
  /*
   * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
   * Config with both CFI and JEDEC device support.
   *
   * Basically physmap.c with the addition of partitions and
25985edce   Lucas De Marchi   Fix common misspe...
6
   * an array of mapping info to accommodate more than one flash type per board.
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   *
   * Copyright 2005-2007 PMC-Sierra, Inc.
   *
   *  This program is free software; you can redistribute  it and/or modify it
   *  under  the terms of  the GNU General  Public License as published by the
   *  Free Software Foundation;  either version 2 of the  License, or (at your
   *  option) any later version.
   *
   *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
   *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
   *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
   *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
   *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
   *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
   *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   *  You should have received a copy of the  GNU General Public License along
   *  with this program; if not, write  to the Free Software Foundation, Inc.,
   *  675 Mass Ave, Cambridge, MA 02139, USA.
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/slab.h>
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/map.h>
  #include <linux/mtd/partitions.h>
  
  #include <asm/io.h>
  
  #include <msp_prom.h>
  #include <msp_regs.h>
  
  
  static struct mtd_info **msp_flash;
  static struct mtd_partition **msp_parts;
  static struct map_info *msp_maps;
  static int fcnt;
cb53b3b99   Harvey Harrison   [MTD] replace rem...
48
49
  #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]
  ", __func__, __LINE__)
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
50

6127cfcd3   Dmitri Vorobiev   [MTD] Make init_m...
51
  static int __init init_msp_flash(void)
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
52
  {
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
53
  	int i, j, ret = -ENOMEM;
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  	int offset, coff;
  	char *env;
  	int pcnt;
  	char flash_name[] = "flash0";
  	char part_name[] = "flash0_0";
  	unsigned addr, size;
  
  	/* If ELB is disabled by "ful-mux" mode, we can't get at flash */
  	if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) &&
  	    (*ELB_1PC_EN_REG & SINGLE_PCCARD)) {
  		printk(KERN_NOTICE "Single PC Card mode: no flash access
  ");
  		return -ENXIO;
  	}
  
  	/* examine the prom environment for flash devices */
  	for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++)
  		flash_name[5] = '0' + fcnt + 1;
  
  	if (fcnt < 1)
  		return -ENXIO;
  
  	printk(KERN_NOTICE "Found %d PMC flash devices
  ", fcnt);
4fb4caa63   Mariusz Kozlowski   [MTD] pmcmsp-flas...
78
79
  
  	msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
80
81
  	if (!msp_flash)
  		return -ENOMEM;
4fb4caa63   Mariusz Kozlowski   [MTD] pmcmsp-flas...
82
  	msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
83
84
  	if (!msp_parts)
  		goto free_msp_flash;
4fb4caa63   Mariusz Kozlowski   [MTD] pmcmsp-flas...
85
  	msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
86
87
  	if (!msp_maps)
  		goto free_msp_parts;
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  
  	/* loop over the flash devices, initializing each */
  	for (i = 0; i < fcnt; i++) {
  		/* examine the prom environment for flash partititions */
  		part_name[5] = '0' + i;
  		part_name[7] = '0';
  		for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++)
  			part_name[7] = '0' + pcnt + 1;
  
  		if (pcnt == 0) {
  			printk(KERN_NOTICE "Skipping flash device %d "
  				"(no partitions defined)
  ", i);
  			continue;
  		}
4fb4caa63   Mariusz Kozlowski   [MTD] pmcmsp-flas...
103
104
  		msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition),
  				       GFP_KERNEL);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
105
106
  		if (!msp_parts[i])
  			goto cleanup_loop;
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
107
108
109
110
  
  		/* now initialize the devices proper */
  		flash_name[5] = '0' + i;
  		env = prom_getenv(flash_name);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
111
112
113
114
115
  		if (sscanf(env, "%x:%x", &addr, &size) < 2) {
  			ret = -ENXIO;
  			kfree(msp_parts[i]);
  			goto cleanup_loop;
  		}
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  		addr = CPHYSADDR(addr);
  
  		printk(KERN_NOTICE
  			"MSP flash device \"%s\": 0x%08x at 0x%08x
  ",
  			flash_name, size, addr);
  		/* This must matchs the actual size of the flash chip */
  		msp_maps[i].size = size;
  		msp_maps[i].phys = addr;
  
  		/*
  		 * Platforms have a specific limit of the size of memory
  		 * which may be mapped for flash:
  		 */
  		if (size > CONFIG_MSP_FLASH_MAP_LIMIT)
  			size = CONFIG_MSP_FLASH_MAP_LIMIT;
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
132

68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
133
  		msp_maps[i].virt = ioremap(addr, size);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
134
135
136
137
138
  		if (msp_maps[i].virt == NULL) {
  			ret = -ENXIO;
  			kfree(msp_parts[i]);
  			goto cleanup_loop;
  		}
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
139
  		msp_maps[i].bankwidth = 1;
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
140
141
142
143
144
145
  		msp_maps[i].name = kmalloc(7, GFP_KERNEL);
  		if (!msp_maps[i].name) {
  			iounmap(msp_maps[i].virt);
  			kfree(msp_parts[i]);
  			goto cleanup_loop;
  		}
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
146

2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
147
  		msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7);
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
148
149
150
151
152
153
  
  		for (j = 0; j < pcnt; j++) {
  			part_name[5] = '0' + i;
  			part_name[7] = '0' + j;
  
  			env = prom_getenv(part_name);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
154
155
156
157
158
159
160
161
  			if (sscanf(env, "%x:%x:%n", &offset, &size,
  						&coff) < 2) {
  				ret = -ENXIO;
  				kfree(msp_maps[i].name);
  				iounmap(msp_maps[i].virt);
  				kfree(msp_parts[i]);
  				goto cleanup_loop;
  			}
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
162
163
164
165
166
167
168
169
170
171
172
  
  			msp_parts[i][j].size = size;
  			msp_parts[i][j].offset = offset;
  			msp_parts[i][j].name = env + coff;
  		}
  
  		/* now probe and add the device */
  		simple_map_init(&msp_maps[i]);
  		msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]);
  		if (msp_flash[i]) {
  			msp_flash[i]->owner = THIS_MODULE;
ee0e87b17   Jamie Iles   mtd: convert rema...
173
  			mtd_device_register(msp_flash[i], msp_parts[i], pcnt);
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
174
175
176
  		} else {
  			printk(KERN_ERR "map probe failed for flash
  ");
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
177
178
179
180
181
  			ret = -ENXIO;
  			kfree(msp_maps[i].name);
  			iounmap(msp_maps[i].virt);
  			kfree(msp_parts[i]);
  			goto cleanup_loop;
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
182
183
184
185
  		}
  	}
  
  	return 0;
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
186
187
188
  
  cleanup_loop:
  	while (i--) {
ee0e87b17   Jamie Iles   mtd: convert rema...
189
  		mtd_device_unregister(msp_flash[i]);
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
190
191
192
193
194
195
196
197
198
199
200
  		map_destroy(msp_flash[i]);
  		kfree(msp_maps[i].name);
  		iounmap(msp_maps[i].virt);
  		kfree(msp_parts[i]);
  	}
  	kfree(msp_maps);
  free_msp_parts:
  	kfree(msp_parts);
  free_msp_flash:
  	kfree(msp_flash);
  	return ret;
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
201
202
203
204
205
  }
  
  static void __exit cleanup_msp_flash(void)
  {
  	int i;
2c78c4436   Roel Kluin   mtd: pmcmsp-flash...
206
  	for (i = 0; i < fcnt; i++) {
ee0e87b17   Jamie Iles   mtd: convert rema...
207
  		mtd_device_unregister(msp_flash[i]);
68aa0fa87   Marc St-Jean   [MTD] PMC MSP71xx...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  		map_destroy(msp_flash[i]);
  		iounmap((void *)msp_maps[i].virt);
  
  		/* free the memory */
  		kfree(msp_maps[i].name);
  		kfree(msp_parts[i]);
  	}
  
  	kfree(msp_flash);
  	kfree(msp_parts);
  	kfree(msp_maps);
  }
  
  MODULE_AUTHOR("PMC-Sierra, Inc");
  MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards");
  MODULE_LICENSE("GPL");
  
  module_init(init_msp_flash);
  module_exit(cleanup_msp_flash);