Commit afffc245 authored by Imre Deak's avatar Imre Deak Committed by Juha Yrjola

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: default avatarImre Deak <imre.deak@solidboot.com>
Signed-off-by: default avatarJuha Yrjola <juha.yrjola@solidboot.com>
parent f0067987
......@@ -35,6 +35,7 @@
#include <asm/arch/usb.h>
#include <asm/arch/board.h>
#include <asm/arch/common.h>
#include <asm/arch/gpmc.h>
#include "prcm-regs.h"
/* LED & Switch macros */
......@@ -45,6 +46,9 @@
#define SW_UP_GPIO17 17
#define SW_DOWN_GPIO58 58
#define APOLLON_FLASH_CS 0
#define APOLLON_ETH_CS 1
static struct mtd_partition apollon_partitions[] = {
{
.name = "X-Loader + U-Boot",
......@@ -84,10 +88,10 @@ static struct flash_platform_data apollon_flash_data = {
.nr_parts = ARRAY_SIZE(apollon_partitions),
};
static struct resource apollon_flash_resource = {
.start = APOLLON_CS0_BASE,
.end = APOLLON_CS0_BASE + SZ_128K,
.flags = IORESOURCE_MEM,
static struct resource apollon_flash_resource[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
};
static struct platform_device apollon_onenand_device = {
......@@ -96,14 +100,24 @@ static struct platform_device apollon_onenand_device = {
.dev = {
.platform_data = &apollon_flash_data,
},
.num_resources = ARRAY_SIZE(&apollon_flash_resource),
.resource = &apollon_flash_resource,
.num_resources = ARRAY_SIZE(apollon_flash_resource),
.resource = apollon_flash_resource,
};
static void __init apollon_flash_init(void)
{
unsigned long base;
if (gpmc_cs_request(APOLLON_FLASH_CS, SZ_128K, &base) < 0) {
printk(KERN_ERR "Cannot request OneNAND GPMC CS\n");
return;
}
apollon_flash_resource[0].start = base;
apollon_flash_resource[0].end = base + SZ_128K - 1;
}
static struct resource apollon_smc91x_resources[] = {
[0] = {
.start = APOLLON_ETHR_START, /* Physical */
.end = APOLLON_ETHR_START + 0xf,
.flags = IORESOURCE_MEM,
},
[1] = {
......@@ -133,6 +147,8 @@ static struct platform_device *apollon_devices[] __initdata = {
static inline void __init apollon_init_smc91x(void)
{
unsigned long base;
/* Make sure CS1 timings are correct */
GPMC_CONFIG1_1 = 0x00011203;
GPMC_CONFIG2_1 = 0x001f1f01;
......@@ -140,13 +156,20 @@ static inline void __init apollon_init_smc91x(void)
GPMC_CONFIG4_1 = 0x1c091c09;
GPMC_CONFIG5_1 = 0x041f1f1f;
GPMC_CONFIG6_1 = 0x000004c4;
GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24);
if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) {
printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
return;
}
apollon_smc91x_resources[0].start = base + 0x300;
apollon_smc91x_resources[1].end = base + 0x30f;
udelay(100);
omap_cfg_reg(W4__24XX_GPIO74);
if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
APOLLON_ETHR_GPIO_IRQ);
gpmc_cs_free(APOLLON_ETH_CS);
return;
}
omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
......@@ -253,6 +276,7 @@ static void __init omap_apollon_init(void)
{
apollon_led_init();
apollon_sw_init();
apollon_flash_init();
/* REVISIT: where's the correct place */
omap_cfg_reg(W19_24XX_SYS_NIRQ);
......
......@@ -44,6 +44,9 @@
#include <asm/io.h>
#include <asm/delay.h>
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 };
static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 };
......@@ -120,8 +123,6 @@ static struct flash_platform_data h4_flash_data = {
};
static struct resource h4_flash_resource = {
.start = H4_CS0_BASE,
.end = H4_CS0_BASE + SZ_64M - 1,
.flags = IORESOURCE_MEM,
};
......@@ -297,15 +298,14 @@ static u32 is_gpmc_muxed(void)
return 0;
}
#define SMC91X_CS 1
static inline void __init h4_init_smc91x(void)
{
int eth_cs;
unsigned long cs_mem_base;
unsigned int muxed, rate;
struct clk *l3ck;
eth_cs = SMC91X_CS;
eth_cs = H4_SMC91X_CS;
l3ck = clk_get(NULL, "core_l3_ck");
if (IS_ERR(l3ck))
......@@ -342,20 +342,35 @@ static inline void __init h4_init_smc91x(void)
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG7,
0x00000f40 | (0x08000000 >> 24));
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
return;
}
h4_smc91x_resources[0].start = cs_mem_base + 0x300;
h4_smc91x_resources[0].end = cs_mem_base + 0x30f;
udelay(100);
omap_cfg_reg(M15_24XX_GPIO92);
if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
OMAP24XX_ETHR_GPIO_IRQ);
gpmc_cs_free(eth_cs);
return;
}
omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
h4_smc91x_resources[0].start = gpmc_cs_get_base_addr(1) + 0x300;
h4_smc91x_resources[0].end = h4_smc91x_resources[0].start + 0xf;
}
static void __init h4_init_flash(void)
{
unsigned long base;
if (gpmc_cs_request(H4_FLASH_CS, SZ_64M, &base) < 0) {
printk("Can't request GPMC CS for flash\n");
return;
}
h4_flash_resource.start = base;
h4_flash_resource.end = base + SZ_64M - 1;
}
static void __init omap_h4_init_irq(void)
......@@ -364,6 +379,7 @@ static void __init omap_h4_init_irq(void)
omap_init_irq();
omap_gpio_init();
h4_init_smc91x();
h4_init_flash();
}
static struct omap_uart_config h4_uart_config __initdata = {
......
......@@ -13,6 +13,8 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/arch/gpmc.h>
......@@ -41,6 +43,19 @@
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
#define GPMC_CS_NUM 8
#define GPMC_MEM_START 0x00000000
#define GPMC_MEM_END 0x3FFFFFFF
#define BOOT_ROM_SPACE 0x100000 /* 1MB */
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
static struct resource gpmc_mem_root;
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED;
static unsigned gpmc_cs_map;
static void __iomem *gpmc_base =
(void __iomem *) IO_ADDRESS(GPMC_BASE);
static void __iomem *gpmc_cs_base =
......@@ -195,9 +210,168 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
return 0;
}
unsigned long gpmc_cs_get_base_addr(int cs)
static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
{
u32 l;
u32 mask;
mask = (1 << GPMC_SECTION_SHIFT) - size;
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
l &= ~0x3f;
l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
l &= ~(0x0f << 8);
l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
l |= 1 << 6; /* CSVALID */
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
}
static void gpmc_cs_disable_mem(int cs)
{
u32 l;
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
l &= ~(1 << 6); /* CSVALID */
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
}
static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
{
u32 l;
u32 mask;
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
mask = (l >> 8) & 0x0f;
*size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
}
static int gpmc_cs_mem_enabled(int cs)
{
u32 l;
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
return l & (1 << 6);
}
static void gpmc_cs_set_reserved(int cs, int reserved)
{
return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24;
gpmc_cs_map &= ~(1 << cs);
gpmc_cs_map |= (reserved ? 1 : 0) << cs;
}
static int gpmc_cs_reserved(int cs)
{
return gpmc_cs_map & (1 << cs);
}
static unsigned long gpmc_mem_align(unsigned long size)
{
int order;
size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
order = GPMC_CHUNK_SHIFT - 1;
do {
size >>= 1;
order++;
} while (size);
size = 1 << order;
return size;
}
static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
{
struct resource *res = &gpmc_cs_mem[cs];
int r;
size = gpmc_mem_align(size);
spin_lock(&gpmc_mem_lock);
res->start = base;
res->end = base + size - 1;
r = request_resource(&gpmc_mem_root, res);
spin_unlock(&gpmc_mem_lock);
return r;
}
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{
struct resource *res = &gpmc_cs_mem[cs];
int r = -1;
if (cs > GPMC_CS_NUM)
return -ENODEV;
size = gpmc_mem_align(size);
if (size > (1 << GPMC_SECTION_SHIFT))
return -ENOMEM;
spin_lock(&gpmc_mem_lock);
if (gpmc_cs_reserved(cs)) {
r = -EBUSY;
goto out;
}
if (gpmc_cs_mem_enabled(cs))
r = adjust_resource(res, res->start & ~(size - 1), size);
if (r < 0)
r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
size, NULL, NULL);
if (r < 0)
goto out;
gpmc_cs_enable_mem(cs, res->start, res->end - res->start + 1);
*base = res->start;
gpmc_cs_set_reserved(cs, 1);
out:
spin_unlock(&gpmc_mem_lock);
return r;
}
void gpmc_cs_free(int cs)
{
spin_lock(&gpmc_mem_lock);
if (cs >= GPMC_CS_NUM || !gpmc_cs_reserved(cs)) {
printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
BUG();
spin_unlock(&gpmc_mem_lock);
return;
}
gpmc_cs_disable_mem(cs);
release_resource(&gpmc_cs_mem[cs]);
gpmc_cs_set_reserved(cs, 0);
spin_unlock(&gpmc_mem_lock);
}
void __init gpmc_mem_init(void)
{
int cs;
unsigned long boot_rom_space = 0;
if (cpu_is_omap242x()) {
u32 l;
l = omap_readl(OMAP242X_CONTROL_STATUS);
/* In case of internal boot the 1st MB is redirected to the
* boot ROM memory space.
*/
if (l & (1 << 3))
boot_rom_space = BOOT_ROM_SPACE;
} else
/* We assume internal boot if the mode can't be
* determined.
*/
boot_rom_space = BOOT_ROM_SPACE;
gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
gpmc_mem_root.end = GPMC_MEM_END;
/* Reserve all regions that has been set up by bootloader */
for (cs = 0; cs < GPMC_CS_NUM; cs++) {
u32 base, size;
if (!gpmc_cs_mem_enabled(cs))
continue;
gpmc_cs_get_memconf(cs, &base, &size);
if (gpmc_cs_insert_mem(cs, base, size) < 0)
BUG();
}
}
void __init gpmc_init(void)
......@@ -214,4 +388,6 @@ void __init gpmc_init(void)
l &= 0x03 << 3;
l |= (0x02 << 3) | (1 << 0);
gpmc_write_reg(GPMC_SYSCONFIG, l);
gpmc_mem_init();
}
......@@ -30,16 +30,7 @@
#define __ASM_ARCH_OMAP_APOLLON_H
/* Placeholder for APOLLON specific defines */
/* GPMC CS0 */
#define APOLLON_CS0_BASE 0x00000000
/* GPMC CS1 */
#define APOLLON_CS1_BASE 0x08000000
#define APOLLON_ETHR_START (APOLLON_CS1_BASE + 0x300)
#define APOLLON_ETHR_GPIO_IRQ 74
/* GPMC CS2 - reserved for OneNAND */
#define APOLLON_CS2_BASE 0x10000000
/* GPMC CS3 - reserved for NOR or NAND */
#define APOLLON_CS3_BASE 0x18000000
#endif /* __ASM_ARCH_OMAP_APOLLON_H */
......@@ -31,6 +31,5 @@
/* Placeholder for H4 specific defines */
#define OMAP24XX_ETHR_GPIO_IRQ 92
#define H4_CS0_BASE 0x04000000
#endif /* __ASM_ARCH_OMAP_H4_H */
......@@ -87,7 +87,7 @@ extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
extern u32 gpmc_cs_read_reg(int cs, int idx);
extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
extern unsigned long gpmc_cs_get_base_addr(int cs);
extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
extern void gpmc_cs_free(int cs);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment