Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Imre Deak and committed by
Tony Lindgren
f37e4580 2eaff915

+180 -4
+178 -2
arch/arm/mach-omap2/gpmc.c
··· 13 13 #include <linux/init.h> 14 14 #include <linux/err.h> 15 15 #include <linux/clk.h> 16 + #include <linux/ioport.h> 17 + #include <linux/spinlock.h> 16 18 17 19 #include <asm/io.h> 18 20 #include <asm/arch/gpmc.h> ··· 42 40 43 41 #define GPMC_CS0 0x60 44 42 #define GPMC_CS_SIZE 0x30 43 + 44 + #define GPMC_CS_NUM 8 45 + #define GPMC_MEM_START 0x00000000 46 + #define GPMC_MEM_END 0x3FFFFFFF 47 + #define BOOT_ROM_SPACE 0x100000 /* 1MB */ 48 + 49 + #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ 50 + #define GPMC_SECTION_SHIFT 28 /* 128 MB */ 51 + 52 + static struct resource gpmc_mem_root; 53 + static struct resource gpmc_cs_mem[GPMC_CS_NUM]; 54 + static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED; 55 + static unsigned gpmc_cs_map; 45 56 46 57 static void __iomem *gpmc_base = 47 58 (void __iomem *) IO_ADDRESS(GPMC_BASE); ··· 202 187 return 0; 203 188 } 204 189 205 - unsigned long gpmc_cs_get_base_addr(int cs) 190 + static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) 206 191 { 207 - return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24; 192 + u32 l; 193 + u32 mask; 194 + 195 + mask = (1 << GPMC_SECTION_SHIFT) - size; 196 + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); 197 + l &= ~0x3f; 198 + l = (base >> GPMC_CHUNK_SHIFT) & 0x3f; 199 + l &= ~(0x0f << 8); 200 + l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; 201 + l |= 1 << 6; /* CSVALID */ 202 + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); 203 + } 204 + 205 + static void gpmc_cs_disable_mem(int cs) 206 + { 207 + u32 l; 208 + 209 + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); 210 + l &= ~(1 << 6); /* CSVALID */ 211 + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); 212 + } 213 + 214 + static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size) 215 + { 216 + u32 l; 217 + u32 mask; 218 + 219 + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); 220 + *base = (l & 0x3f) << GPMC_CHUNK_SHIFT; 221 + mask = (l >> 8) & 0x0f; 222 + *size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT); 223 + } 224 + 225 + static int gpmc_cs_mem_enabled(int cs) 226 + { 227 + u32 l; 228 + 229 + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); 230 + return l & (1 << 6); 231 + } 232 + 233 + static void gpmc_cs_set_reserved(int cs, int reserved) 234 + { 235 + gpmc_cs_map &= ~(1 << cs); 236 + gpmc_cs_map |= (reserved ? 1 : 0) << cs; 237 + } 238 + 239 + static int gpmc_cs_reserved(int cs) 240 + { 241 + return gpmc_cs_map & (1 << cs); 242 + } 243 + 244 + static unsigned long gpmc_mem_align(unsigned long size) 245 + { 246 + int order; 247 + 248 + size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1); 249 + order = GPMC_CHUNK_SHIFT - 1; 250 + do { 251 + size >>= 1; 252 + order++; 253 + } while (size); 254 + size = 1 << order; 255 + return size; 256 + } 257 + 258 + static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size) 259 + { 260 + struct resource *res = &gpmc_cs_mem[cs]; 261 + int r; 262 + 263 + size = gpmc_mem_align(size); 264 + spin_lock(&gpmc_mem_lock); 265 + res->start = base; 266 + res->end = base + size - 1; 267 + r = request_resource(&gpmc_mem_root, res); 268 + spin_unlock(&gpmc_mem_lock); 269 + 270 + return r; 271 + } 272 + 273 + int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) 274 + { 275 + struct resource *res = &gpmc_cs_mem[cs]; 276 + int r = -1; 277 + 278 + if (cs > GPMC_CS_NUM) 279 + return -ENODEV; 280 + 281 + size = gpmc_mem_align(size); 282 + if (size > (1 << GPMC_SECTION_SHIFT)) 283 + return -ENOMEM; 284 + 285 + spin_lock(&gpmc_mem_lock); 286 + if (gpmc_cs_reserved(cs)) { 287 + r = -EBUSY; 288 + goto out; 289 + } 290 + if (gpmc_cs_mem_enabled(cs)) 291 + r = adjust_resource(res, res->start & ~(size - 1), size); 292 + if (r < 0) 293 + r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0, 294 + size, NULL, NULL); 295 + if (r < 0) 296 + goto out; 297 + 298 + gpmc_cs_enable_mem(cs, res->start, res->end - res->start + 1); 299 + *base = res->start; 300 + gpmc_cs_set_reserved(cs, 1); 301 + out: 302 + spin_unlock(&gpmc_mem_lock); 303 + return r; 304 + } 305 + 306 + void gpmc_cs_free(int cs) 307 + { 308 + spin_lock(&gpmc_mem_lock); 309 + if (cs >= GPMC_CS_NUM || !gpmc_cs_reserved(cs)) { 310 + printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs); 311 + BUG(); 312 + spin_unlock(&gpmc_mem_lock); 313 + return; 314 + } 315 + gpmc_cs_disable_mem(cs); 316 + release_resource(&gpmc_cs_mem[cs]); 317 + gpmc_cs_set_reserved(cs, 0); 318 + spin_unlock(&gpmc_mem_lock); 319 + } 320 + 321 + void __init gpmc_mem_init(void) 322 + { 323 + int cs; 324 + unsigned long boot_rom_space = 0; 325 + 326 + if (cpu_is_omap242x()) { 327 + u32 l; 328 + l = omap_readl(OMAP242X_CONTROL_STATUS); 329 + /* In case of internal boot the 1st MB is redirected to the 330 + * boot ROM memory space. 331 + */ 332 + if (l & (1 << 3)) 333 + boot_rom_space = BOOT_ROM_SPACE; 334 + } else 335 + /* We assume internal boot if the mode can't be 336 + * determined. 337 + */ 338 + boot_rom_space = BOOT_ROM_SPACE; 339 + gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space; 340 + gpmc_mem_root.end = GPMC_MEM_END; 341 + 342 + /* Reserve all regions that has been set up by bootloader */ 343 + for (cs = 0; cs < GPMC_CS_NUM; cs++) { 344 + u32 base, size; 345 + 346 + if (!gpmc_cs_mem_enabled(cs)) 347 + continue; 348 + gpmc_cs_get_memconf(cs, &base, &size); 349 + if (gpmc_cs_insert_mem(cs, base, size) < 0) 350 + BUG(); 351 + } 208 352 } 209 353 210 354 void __init gpmc_init(void) ··· 380 206 l &= 0x03 << 3; 381 207 l |= (0x02 << 3) | (1 << 0); 382 208 gpmc_write_reg(GPMC_SYSCONFIG, l); 209 + 210 + gpmc_mem_init(); 383 211 }
+2 -2
include/asm-arm/arch-omap/gpmc.h
··· 85 85 extern u32 gpmc_cs_read_reg(int cs, int idx); 86 86 extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk); 87 87 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); 88 - extern unsigned long gpmc_cs_get_base_addr(int cs); 89 - 88 + extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); 89 + extern void gpmc_cs_free(int cs); 90 90 91 91 #endif