diff options
author | Imre Deak <imre.deak@solidboot.com> | 2006-09-25 05:41:33 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2006-09-25 05:41:33 -0400 |
commit | f37e4580c409e290f6e482007c3573cdb4470bf9 (patch) | |
tree | 7d5741defdda9bf6edb554a541f2d5478ed6b413 /arch | |
parent | 2eaff915744b6c8db7770fa9e841fd1c0105fb0b (diff) |
ARM: OMAP2: Dynamic allocator for GPMC memory space
Add support for assigning memory regions dynamically to peripherals
attached to GPMC interface. Platform specific code should now call
gpmc_cs_request to get a free GPMC memory region instead of using
a fixed address.
Make the H4 and Apollon platform initialization use the new API.
Signed-off-by: Imre Deak <imre.deak@solidboot.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 180 |
1 files changed, 178 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index c7a48f921fef..f4f04d87df32 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/ioport.h> | ||
17 | #include <linux/spinlock.h> | ||
16 | 18 | ||
17 | #include <asm/io.h> | 19 | #include <asm/io.h> |
18 | #include <asm/arch/gpmc.h> | 20 | #include <asm/arch/gpmc.h> |
@@ -41,6 +43,19 @@ | |||
41 | #define GPMC_CS0 0x60 | 43 | #define GPMC_CS0 0x60 |
42 | #define GPMC_CS_SIZE 0x30 | 44 | #define GPMC_CS_SIZE 0x30 |
43 | 45 | ||
46 | #define GPMC_CS_NUM 8 | ||
47 | #define GPMC_MEM_START 0x00000000 | ||
48 | #define GPMC_MEM_END 0x3FFFFFFF | ||
49 | #define BOOT_ROM_SPACE 0x100000 /* 1MB */ | ||
50 | |||
51 | #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ | ||
52 | #define GPMC_SECTION_SHIFT 28 /* 128 MB */ | ||
53 | |||
54 | static struct resource gpmc_mem_root; | ||
55 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; | ||
56 | static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED; | ||
57 | static unsigned gpmc_cs_map; | ||
58 | |||
44 | static void __iomem *gpmc_base = | 59 | static void __iomem *gpmc_base = |
45 | (void __iomem *) IO_ADDRESS(GPMC_BASE); | 60 | (void __iomem *) IO_ADDRESS(GPMC_BASE); |
46 | static void __iomem *gpmc_cs_base = | 61 | static void __iomem *gpmc_cs_base = |
@@ -187,9 +202,168 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) | |||
187 | return 0; | 202 | return 0; |
188 | } | 203 | } |
189 | 204 | ||
190 | unsigned long gpmc_cs_get_base_addr(int cs) | 205 | static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) |
206 | { | ||
207 | u32 l; | ||
208 | u32 mask; | ||
209 | |||
210 | mask = (1 << GPMC_SECTION_SHIFT) - size; | ||
211 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | ||
212 | l &= ~0x3f; | ||
213 | l = (base >> GPMC_CHUNK_SHIFT) & 0x3f; | ||
214 | l &= ~(0x0f << 8); | ||
215 | l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; | ||
216 | l |= 1 << 6; /* CSVALID */ | ||
217 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); | ||
218 | } | ||
219 | |||
220 | static void gpmc_cs_disable_mem(int cs) | ||
221 | { | ||
222 | u32 l; | ||
223 | |||
224 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | ||
225 | l &= ~(1 << 6); /* CSVALID */ | ||
226 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); | ||
227 | } | ||
228 | |||
229 | static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size) | ||
230 | { | ||
231 | u32 l; | ||
232 | u32 mask; | ||
233 | |||
234 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | ||
235 | *base = (l & 0x3f) << GPMC_CHUNK_SHIFT; | ||
236 | mask = (l >> 8) & 0x0f; | ||
237 | *size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT); | ||
238 | } | ||
239 | |||
240 | static int gpmc_cs_mem_enabled(int cs) | ||
241 | { | ||
242 | u32 l; | ||
243 | |||
244 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | ||
245 | return l & (1 << 6); | ||
246 | } | ||
247 | |||
248 | static void gpmc_cs_set_reserved(int cs, int reserved) | ||
191 | { | 249 | { |
192 | return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24; | 250 | gpmc_cs_map &= ~(1 << cs); |
251 | gpmc_cs_map |= (reserved ? 1 : 0) << cs; | ||
252 | } | ||
253 | |||
254 | static int gpmc_cs_reserved(int cs) | ||
255 | { | ||
256 | return gpmc_cs_map & (1 << cs); | ||
257 | } | ||
258 | |||
259 | static unsigned long gpmc_mem_align(unsigned long size) | ||
260 | { | ||
261 | int order; | ||
262 | |||
263 | size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1); | ||
264 | order = GPMC_CHUNK_SHIFT - 1; | ||
265 | do { | ||
266 | size >>= 1; | ||
267 | order++; | ||
268 | } while (size); | ||
269 | size = 1 << order; | ||
270 | return size; | ||
271 | } | ||
272 | |||
273 | static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size) | ||
274 | { | ||
275 | struct resource *res = &gpmc_cs_mem[cs]; | ||
276 | int r; | ||
277 | |||
278 | size = gpmc_mem_align(size); | ||
279 | spin_lock(&gpmc_mem_lock); | ||
280 | res->start = base; | ||
281 | res->end = base + size - 1; | ||
282 | r = request_resource(&gpmc_mem_root, res); | ||
283 | spin_unlock(&gpmc_mem_lock); | ||
284 | |||
285 | return r; | ||
286 | } | ||
287 | |||
288 | int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) | ||
289 | { | ||
290 | struct resource *res = &gpmc_cs_mem[cs]; | ||
291 | int r = -1; | ||
292 | |||
293 | if (cs > GPMC_CS_NUM) | ||
294 | return -ENODEV; | ||
295 | |||
296 | size = gpmc_mem_align(size); | ||
297 | if (size > (1 << GPMC_SECTION_SHIFT)) | ||
298 | return -ENOMEM; | ||
299 | |||
300 | spin_lock(&gpmc_mem_lock); | ||
301 | if (gpmc_cs_reserved(cs)) { | ||
302 | r = -EBUSY; | ||
303 | goto out; | ||
304 | } | ||
305 | if (gpmc_cs_mem_enabled(cs)) | ||
306 | r = adjust_resource(res, res->start & ~(size - 1), size); | ||
307 | if (r < 0) | ||
308 | r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0, | ||
309 | size, NULL, NULL); | ||
310 | if (r < 0) | ||
311 | goto out; | ||
312 | |||
313 | gpmc_cs_enable_mem(cs, res->start, res->end - res->start + 1); | ||
314 | *base = res->start; | ||
315 | gpmc_cs_set_reserved(cs, 1); | ||
316 | out: | ||
317 | spin_unlock(&gpmc_mem_lock); | ||
318 | return r; | ||
319 | } | ||
320 | |||
321 | void gpmc_cs_free(int cs) | ||
322 | { | ||
323 | spin_lock(&gpmc_mem_lock); | ||
324 | if (cs >= GPMC_CS_NUM || !gpmc_cs_reserved(cs)) { | ||
325 | printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs); | ||
326 | BUG(); | ||
327 | spin_unlock(&gpmc_mem_lock); | ||
328 | return; | ||
329 | } | ||
330 | gpmc_cs_disable_mem(cs); | ||
331 | release_resource(&gpmc_cs_mem[cs]); | ||
332 | gpmc_cs_set_reserved(cs, 0); | ||
333 | spin_unlock(&gpmc_mem_lock); | ||
334 | } | ||
335 | |||
336 | void __init gpmc_mem_init(void) | ||
337 | { | ||
338 | int cs; | ||
339 | unsigned long boot_rom_space = 0; | ||
340 | |||
341 | if (cpu_is_omap242x()) { | ||
342 | u32 l; | ||
343 | l = omap_readl(OMAP242X_CONTROL_STATUS); | ||
344 | /* In case of internal boot the 1st MB is redirected to the | ||
345 | * boot ROM memory space. | ||
346 | */ | ||
347 | if (l & (1 << 3)) | ||
348 | boot_rom_space = BOOT_ROM_SPACE; | ||
349 | } else | ||
350 | /* We assume internal boot if the mode can't be | ||
351 | * determined. | ||
352 | */ | ||
353 | boot_rom_space = BOOT_ROM_SPACE; | ||
354 | gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space; | ||
355 | gpmc_mem_root.end = GPMC_MEM_END; | ||
356 | |||
357 | /* Reserve all regions that has been set up by bootloader */ | ||
358 | for (cs = 0; cs < GPMC_CS_NUM; cs++) { | ||
359 | u32 base, size; | ||
360 | |||
361 | if (!gpmc_cs_mem_enabled(cs)) | ||
362 | continue; | ||
363 | gpmc_cs_get_memconf(cs, &base, &size); | ||
364 | if (gpmc_cs_insert_mem(cs, base, size) < 0) | ||
365 | BUG(); | ||
366 | } | ||
193 | } | 367 | } |
194 | 368 | ||
195 | void __init gpmc_init(void) | 369 | void __init gpmc_init(void) |
@@ -206,4 +380,6 @@ void __init gpmc_init(void) | |||
206 | l &= 0x03 << 3; | 380 | l &= 0x03 << 3; |
207 | l |= (0x02 << 3) | (1 << 0); | 381 | l |= (0x02 << 3) | (1 << 0); |
208 | gpmc_write_reg(GPMC_SYSCONFIG, l); | 382 | gpmc_write_reg(GPMC_SYSCONFIG, l); |
383 | |||
384 | gpmc_mem_init(); | ||
209 | } | 385 | } |