Blame view
arch/arm/plat-omap/fb.c
10.1 KB
c40fae952 ARM: OMAP: Sync c... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* * File: arch/arm/plat-omap/fb.c * * Framebuffer device registration for TI OMAP platforms * * Copyright (C) 2006 Nokia Corporation * Author: Imre Deak <imre.deak@nokia.com> * * 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 program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * 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., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
0dc5e77c4 [ARM] 3454/1: ARM... |
23 24 |
#include <linux/module.h> #include <linux/kernel.h> |
27ac792ca PAGE_ALIGN(): cor... |
25 |
#include <linux/mm.h> |
0dc5e77c4 [ARM] 3454/1: ARM... |
26 27 |
#include <linux/init.h> #include <linux/platform_device.h> |
98864ff58 ARM: OMAP: Conver... |
28 |
#include <linux/memblock.h> |
fced80c73 [ARM] Convert asm... |
29 |
#include <linux/io.h> |
91773a00f OMAP: OMAPFB: spl... |
30 |
#include <linux/omapfb.h> |
0dc5e77c4 [ARM] 3454/1: ARM... |
31 |
|
a09e64fbc [ARM] Move includ... |
32 |
#include <mach/hardware.h> |
0dc5e77c4 [ARM] 3454/1: ARM... |
33 |
#include <asm/mach/map.h> |
ce491cf85 omap: headers: Mo... |
34 35 |
#include <plat/board.h> #include <plat/sram.h> |
0dc5e77c4 [ARM] 3454/1: ARM... |
36 |
|
b0a330dc5 OMAP: plat-omap: ... |
37 |
#include "fb.h" |
0dc5e77c4 [ARM] 3454/1: ARM... |
38 39 40 |
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) static struct omapfb_platform_data omapfb_config; |
b7cc6d46b ARM: OMAP: FB syn... |
41 42 |
static int config_invalid; static int configured_regions; |
0dc5e77c4 [ARM] 3454/1: ARM... |
43 44 45 46 47 48 49 50 51 52 53 54 55 |
static u64 omap_fb_dma_mask = ~(u32)0; static struct platform_device omap_fb_device = { .name = "omapfb", .id = -1, .dev = { .dma_mask = &omap_fb_dma_mask, .coherent_dma_mask = ~(u32)0, .platform_data = &omapfb_config, }, .num_resources = 0, }; |
b39a982dd OMAP: DSS2: omapf... |
56 57 58 |
void omapfb_set_platform_data(struct omapfb_platform_data *data) { } |
b7cc6d46b ARM: OMAP: FB syn... |
59 60 |
static inline int ranges_overlap(unsigned long start1, unsigned long size1, unsigned long start2, unsigned long size2) |
0dc5e77c4 [ARM] 3454/1: ARM... |
61 |
{ |
b7cc6d46b ARM: OMAP: FB syn... |
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
return (start1 >= start2 && start1 < start2 + size2) || (start2 >= start1 && start2 < start1 + size1); } static inline int range_included(unsigned long start1, unsigned long size1, unsigned long start2, unsigned long size2) { return start1 >= start2 && start1 + size1 <= start2 + size2; } /* Check if there is an overlapping region. */ static int fbmem_region_reserved(unsigned long start, size_t size) { struct omapfb_mem_region *rg; |
c40fae952 ARM: OMAP: Sync c... |
77 |
int i; |
b7cc6d46b ARM: OMAP: FB syn... |
78 79 80 81 82 83 84 |
rg = &omapfb_config.mem_desc.region[0]; for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) { if (!rg->paddr) /* Empty slot. */ continue; if (ranges_overlap(start, size, rg->paddr, rg->size)) return 1; |
c40fae952 ARM: OMAP: Sync c... |
85 |
} |
b7cc6d46b ARM: OMAP: FB syn... |
86 87 |
return 0; } |
c40fae952 ARM: OMAP: Sync c... |
88 |
|
b7cc6d46b ARM: OMAP: FB syn... |
89 90 91 92 |
/* * Get the region_idx`th region from board config/ATAG and convert it to * our internal format. */ |
9dbb7a5da ARM: omap/fb: mov... |
93 |
static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg) |
b7cc6d46b ARM: OMAP: FB syn... |
94 95 96 |
{ const struct omap_fbmem_config *conf; u32 paddr; |
0dc5e77c4 [ARM] 3454/1: ARM... |
97 |
|
b7cc6d46b ARM: OMAP: FB syn... |
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
conf = omap_get_nr_config(OMAP_TAG_FBMEM, struct omap_fbmem_config, region_idx); if (conf == NULL) return -ENOENT; paddr = conf->start; /* * Low bits encode the page allocation mode, if high bits * are zero. Otherwise we need a page aligned fixed * address. */ memset(rg, 0, sizeof(*rg)); rg->type = paddr & ~PAGE_MASK; rg->paddr = paddr & PAGE_MASK; rg->size = PAGE_ALIGN(conf->size); return 0; } static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type, unsigned long mem_start, unsigned long mem_size) { /* * Check if the configuration specifies the type explicitly. * type = 0 && paddr = 0, a default don't care case maps to * the SDRAM type. */ |
e1a75a1aa arm/omap: simplif... |
125 |
if (rg->type || !rg->paddr) |
b7cc6d46b ARM: OMAP: FB syn... |
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
return 0; if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) { rg->type = mem_type; return 0; } /* Can't determine it. */ return -1; } static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg, unsigned long start_avail, unsigned size_avail) { unsigned long paddr = rg->paddr; size_t size = rg->size; if (rg->type > OMAPFB_MEMTYPE_MAX) { printk(KERN_ERR "Invalid start address for FB region %d ", region_idx); return -EINVAL; } if (!rg->size) { printk(KERN_ERR "Zero size for FB region %d ", region_idx); return -EINVAL; } if (!paddr) /* Allocate this dynamically, leave paddr 0 for now. */ return 0; /* * Fixed region for the given RAM range. Check if it's already * reserved by the FB code or someone else. */ if (fbmem_region_reserved(paddr, size) || !range_included(paddr, size, start_avail, size_avail)) { printk(KERN_ERR "Trying to use reserved memory " "for FB region %d ", region_idx); return -EINVAL; } return 0; } |
a1af0fbbb ARM: OMAP: Cleanu... |
172 173 |
static int valid_sdram(unsigned long addr, unsigned long size) { |
5fd03ddab memblock/arm: Fix... |
174 |
return memblock_is_region_memory(addr, size); |
a1af0fbbb ARM: OMAP: Cleanu... |
175 176 177 178 |
} static int reserve_sdram(unsigned long addr, unsigned long size) { |
98864ff58 ARM: OMAP: Conver... |
179 180 181 182 183 |
if (memblock_is_region_reserved(addr, size)) return -EBUSY; if (memblock_reserve(addr, size)) return -ENOMEM; return 0; |
a1af0fbbb ARM: OMAP: Cleanu... |
184 |
} |
b7cc6d46b ARM: OMAP: FB syn... |
185 186 187 188 |
/* * Called from map_io. We need to call to this early enough so that we * can reserve the fixed SDRAM regions before VM could get hold of them. */ |
98864ff58 ARM: OMAP: Conver... |
189 |
void __init omapfb_reserve_sdram_memblock(void) |
b7cc6d46b ARM: OMAP: FB syn... |
190 |
{ |
a1af0fbbb ARM: OMAP: Cleanu... |
191 192 |
unsigned long reserved = 0; int i; |
b7cc6d46b ARM: OMAP: FB syn... |
193 194 195 |
if (config_invalid) return; |
b7cc6d46b ARM: OMAP: FB syn... |
196 |
for (i = 0; ; i++) { |
a1af0fbbb ARM: OMAP: Cleanu... |
197 |
struct omapfb_mem_region rg; |
b7cc6d46b ARM: OMAP: FB syn... |
198 199 |
if (get_fbmem_region(i, &rg) < 0) |
c40fae952 ARM: OMAP: Sync c... |
200 |
break; |
a1af0fbbb ARM: OMAP: Cleanu... |
201 |
|
b7cc6d46b ARM: OMAP: FB syn... |
202 |
if (i == OMAPFB_PLANE_NUM) { |
a1af0fbbb ARM: OMAP: Cleanu... |
203 204 |
pr_err("Extraneous FB mem configuration entries "); |
b7cc6d46b ARM: OMAP: FB syn... |
205 206 |
config_invalid = 1; return; |
0dc5e77c4 [ARM] 3454/1: ARM... |
207 |
} |
a1af0fbbb ARM: OMAP: Cleanu... |
208 |
|
b7cc6d46b ARM: OMAP: FB syn... |
209 |
/* Check if it's our memory type. */ |
a1af0fbbb ARM: OMAP: Cleanu... |
210 211 212 213 214 |
if (rg.type != OMAPFB_MEMTYPE_SDRAM) continue; /* Check if the region falls within SDRAM */ if (rg.paddr && !valid_sdram(rg.paddr, rg.size)) |
b7cc6d46b ARM: OMAP: FB syn... |
215 |
continue; |
a1af0fbbb ARM: OMAP: Cleanu... |
216 217 218 219 |
if (rg.size == 0) { pr_err("Zero size for FB region %d ", i); |
b7cc6d46b ARM: OMAP: FB syn... |
220 221 |
config_invalid = 1; return; |
c40fae952 ARM: OMAP: Sync c... |
222 |
} |
a1af0fbbb ARM: OMAP: Cleanu... |
223 |
|
72af2b363 ARM: OMAP: Fix pr... |
224 |
if (rg.paddr) { |
a1af0fbbb ARM: OMAP: Cleanu... |
225 226 227 228 229 230 231 |
if (reserve_sdram(rg.paddr, rg.size)) { pr_err("Trying to use reserved memory for FB region %d ", i); config_invalid = 1; return; } |
72af2b363 ARM: OMAP: Fix pr... |
232 233 |
reserved += rg.size; } |
a1af0fbbb ARM: OMAP: Cleanu... |
234 235 236 237 238 239 240 |
if (omapfb_config.mem_desc.region[i].size) { pr_err("FB region %d already set ", i); config_invalid = 1; return; } |
b7cc6d46b ARM: OMAP: FB syn... |
241 242 |
omapfb_config.mem_desc.region[i] = rg; configured_regions++; |
0dc5e77c4 [ARM] 3454/1: ARM... |
243 |
} |
c40fae952 ARM: OMAP: Sync c... |
244 |
omapfb_config.mem_desc.region_cnt = i; |
b7cc6d46b ARM: OMAP: FB syn... |
245 |
if (reserved) |
c40fae952 ARM: OMAP: Sync c... |
246 247 |
pr_info("Reserving %lu bytes SDRAM for frame buffer ", |
b7cc6d46b ARM: OMAP: FB syn... |
248 249 250 251 252 253 254 255 256 257 258 259 260 |
reserved); } /* * Called at sram init time, before anything is pushed to the SRAM stack. * Because of the stack scheme, we will allocate everything from the * start of the lowest address region to the end of SRAM. This will also * include padding for page alignment and possible holes between regions. * * As opposed to the SDRAM case, we'll also do any dynamic allocations at * this point, since the driver built as a module would have problem with * freeing / reallocating the regions. */ |
e92840b70 ARM: omap/fb: mov... |
261 |
unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart, |
b7cc6d46b ARM: OMAP: FB syn... |
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
unsigned long sram_vstart, unsigned long sram_size, unsigned long pstart_avail, unsigned long size_avail) { struct omapfb_mem_region rg; unsigned long pend_avail; unsigned long reserved; int i; if (config_invalid) return 0; reserved = 0; pend_avail = pstart_avail + size_avail; for (i = 0; ; i++) { if (get_fbmem_region(i, &rg) < 0) break; if (i == OMAPFB_PLANE_NUM) { printk(KERN_ERR "Extraneous FB mem configuration entries "); config_invalid = 1; return 0; } |
c40fae952 ARM: OMAP: Sync c... |
287 |
|
b7cc6d46b ARM: OMAP: FB syn... |
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
/* Check if it's our memory type. */ if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM, sram_pstart, sram_size) < 0 || (rg.type != OMAPFB_MEMTYPE_SRAM)) continue; BUG_ON(omapfb_config.mem_desc.region[i].size); if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) { config_invalid = 1; return 0; } if (!rg.paddr) { /* Dynamic allocation */ if ((size_avail & PAGE_MASK) < rg.size) { printk("Not enough SRAM for FB region %d ", i); config_invalid = 1; return 0; } size_avail = (size_avail - rg.size) & PAGE_MASK; rg.paddr = pstart_avail + size_avail; } /* Reserve everything above the start of the region. */ if (pend_avail - rg.paddr > reserved) reserved = pend_avail - rg.paddr; size_avail = pend_avail - reserved - pstart_avail; /* * We have a kernel mapping for this already, so the * driver won't have to make one. */ rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart); omapfb_config.mem_desc.region[i] = rg; configured_regions++; } omapfb_config.mem_desc.region_cnt = i; if (reserved) pr_info("Reserving %lu bytes SRAM for frame buffer ", reserved); return reserved; |
0dc5e77c4 [ARM] 3454/1: ARM... |
331 |
} |
771af222e ARM: OMAP: FB: ad... |
332 333 334 335 |
void omapfb_set_ctrl_platform_data(void *data) { omapfb_config.ctrl_platform_data = data; } |
375c324b7 ARM: omap/fb: mov... |
336 |
static int __init omap_init_fb(void) |
0dc5e77c4 [ARM] 3454/1: ARM... |
337 338 |
{ const struct omap_lcd_config *conf; |
b7cc6d46b ARM: OMAP: FB syn... |
339 340 341 342 343 344 345 |
if (config_invalid) return 0; if (configured_regions != omapfb_config.mem_desc.region_cnt) { printk(KERN_ERR "Invalid FB mem configuration entries "); return 0; } |
0dc5e77c4 [ARM] 3454/1: ARM... |
346 |
conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); |
b7cc6d46b ARM: OMAP: FB syn... |
347 348 349 350 351 |
if (conf == NULL) { if (configured_regions) /* FB mem config, but no LCD config? */ printk(KERN_ERR "Missing LCD configuration "); |
0dc5e77c4 [ARM] 3454/1: ARM... |
352 |
return 0; |
b7cc6d46b ARM: OMAP: FB syn... |
353 |
} |
0dc5e77c4 [ARM] 3454/1: ARM... |
354 355 356 357 358 359 |
omapfb_config.lcd = *conf; return platform_device_register(&omap_fb_device); } arch_initcall(omap_init_fb); |
b39a982dd OMAP: DSS2: omapf... |
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) static u64 omap_fb_dma_mask = ~(u32)0; static struct omapfb_platform_data omapfb_config; static struct platform_device omap_fb_device = { .name = "omapfb", .id = -1, .dev = { .dma_mask = &omap_fb_dma_mask, .coherent_dma_mask = ~(u32)0, .platform_data = &omapfb_config, }, .num_resources = 0, }; void omapfb_set_platform_data(struct omapfb_platform_data *data) { omapfb_config = *data; } |
375c324b7 ARM: omap/fb: mov... |
380 |
static int __init omap_init_fb(void) |
b39a982dd OMAP: DSS2: omapf... |
381 382 383 384 385 |
{ return platform_device_register(&omap_fb_device); } arch_initcall(omap_init_fb); |
0dc5e77c4 [ARM] 3454/1: ARM... |
386 |
|
98864ff58 ARM: OMAP: Conver... |
387 388 389 |
void omapfb_reserve_sdram_memblock(void) { } |
e92840b70 ARM: omap/fb: mov... |
390 |
unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart, |
b7cc6d46b ARM: OMAP: FB syn... |
391 392 393 |
unsigned long sram_vstart, unsigned long sram_size, unsigned long start_avail, |
cc150b03a ARM: OMAP: Fix GC... |
394 395 396 397 |
unsigned long size_avail) { return 0; } |
b7cc6d46b ARM: OMAP: FB syn... |
398 |
|
b39a982dd OMAP: DSS2: omapf... |
399 400 401 402 403 |
#else void omapfb_set_platform_data(struct omapfb_platform_data *data) { } |
98864ff58 ARM: OMAP: Conver... |
404 405 406 |
void omapfb_reserve_sdram_memblock(void) { } |
e92840b70 ARM: omap/fb: mov... |
407 |
unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart, |
b39a982dd OMAP: DSS2: omapf... |
408 409 410 411 412 413 414 |
unsigned long sram_vstart, unsigned long sram_size, unsigned long start_avail, unsigned long size_avail) { return 0; } |
0dc5e77c4 [ARM] 3454/1: ARM... |
415 416 |
#endif |