diff options
author | Jon Hunter <jon-hunter@ti.com> | 2013-03-06 13:00:10 -0500 |
---|---|---|
committer | Jon Hunter <jon-hunter@ti.com> | 2013-04-03 21:13:39 -0400 |
commit | c71f8e9bef8a3e022537361505c09f8c357ffd18 (patch) | |
tree | 0e7307933173ecd17a19b7a671729885a4d14bd9 /arch/arm/mach-omap2/gpmc.c | |
parent | 32cde0b5141030030f950a3c7e971018c81a9360 (diff) |
ARM: OMAP2+: Detect incorrectly aligned GPMC base address
Each GPMC chip-select can be configured to map 16MB, 32MB, 64MB or 128MB
of address space. The physical base address where a chip-select starts
is also configurable and must be aligned on a boundary that is equal to
or greater than the size of the address space mapped bt the chip-select.
When enabling a GPMC chip-select, ensure that the base address is aligned
to the appropriate boundary.
Reported-by: Mark Jackson <mpfj-list@mimc.co.uk>
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Tested-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index c7bf6ddf04ed..5c22b5adaeb5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -403,11 +403,18 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) | |||
403 | return 0; | 403 | return 0; |
404 | } | 404 | } |
405 | 405 | ||
406 | static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) | 406 | static int gpmc_cs_enable_mem(int cs, u32 base, u32 size) |
407 | { | 407 | { |
408 | u32 l; | 408 | u32 l; |
409 | u32 mask; | 409 | u32 mask; |
410 | 410 | ||
411 | /* | ||
412 | * Ensure that base address is aligned on a | ||
413 | * boundary equal to or greater than size. | ||
414 | */ | ||
415 | if (base & (size - 1)) | ||
416 | return -EINVAL; | ||
417 | |||
411 | mask = (1 << GPMC_SECTION_SHIFT) - size; | 418 | mask = (1 << GPMC_SECTION_SHIFT) - size; |
412 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | 419 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); |
413 | l &= ~0x3f; | 420 | l &= ~0x3f; |
@@ -416,6 +423,8 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) | |||
416 | l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; | 423 | l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; |
417 | l |= GPMC_CONFIG7_CSVALID; | 424 | l |= GPMC_CONFIG7_CSVALID; |
418 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); | 425 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); |
426 | |||
427 | return 0; | ||
419 | } | 428 | } |
420 | 429 | ||
421 | static void gpmc_cs_disable_mem(int cs) | 430 | static void gpmc_cs_disable_mem(int cs) |
@@ -526,7 +535,9 @@ static int gpmc_cs_remap(int cs, u32 base) | |||
526 | ret = gpmc_cs_insert_mem(cs, base, size); | 535 | ret = gpmc_cs_insert_mem(cs, base, size); |
527 | if (ret < 0) | 536 | if (ret < 0) |
528 | return ret; | 537 | return ret; |
529 | gpmc_cs_enable_mem(cs, base, size); | 538 | ret = gpmc_cs_enable_mem(cs, base, size); |
539 | if (ret < 0) | ||
540 | return ret; | ||
530 | 541 | ||
531 | return 0; | 542 | return 0; |
532 | } | 543 | } |
@@ -556,7 +567,12 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) | |||
556 | if (r < 0) | 567 | if (r < 0) |
557 | goto out; | 568 | goto out; |
558 | 569 | ||
559 | gpmc_cs_enable_mem(cs, res->start, resource_size(res)); | 570 | r = gpmc_cs_enable_mem(cs, res->start, resource_size(res)); |
571 | if (r < 0) { | ||
572 | release_resource(res); | ||
573 | goto out; | ||
574 | } | ||
575 | |||
560 | *base = res->start; | 576 | *base = res->start; |
561 | gpmc_cs_set_reserved(cs, 1); | 577 | gpmc_cs_set_reserved(cs, 1); |
562 | out: | 578 | out: |