aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2009-08-07 05:01:55 -0400
committerTomi Valkeinen <tomi.valkeinen@nokia.com>2009-12-09 05:04:33 -0500
commitafedec183e95bd5e126a7846a644acfdddb86a66 (patch)
tree4e4fdfa45487d450b510d926ec35450dd4bc4ca7
parentdadd2bb931a08a4b6b17f9e82d9bbe7bedebbc98 (diff)
OMAP: Add VRAM manager
Add a Video RAM manager for OMAP 2 and 3 platforms. VRAM manager is used to allocate large continuous blocks of SDRAM or SRAM. The features VRAM manager has that are missing from dma_alloc_* functions are: - Support for OMAP2's SRAM - Allocate without ioremapping - Allocate at defined physical addresses - Allows larger VRAM area and larger allocations The upcoming DSS2 uses VRAM manager. VRAM area size can be defined in kernel config, board file or with kernel boot parameters. Board file definition overrides kernel config, and boot parameter overrides kernel config and board file. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
-rw-r--r--arch/arm/mach-omap2/io.c2
-rw-r--r--arch/arm/plat-omap/include/plat/vram.h62
-rw-r--r--arch/arm/plat-omap/sram.c8
-rw-r--r--drivers/video/Kconfig1
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/omap2/Kconfig2
-rw-r--r--drivers/video/omap2/Makefile1
-rw-r--r--drivers/video/omap2/vram.c655
8 files changed, 732 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 9f22c201ef9d..6a4d8e468703 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -33,6 +33,7 @@
33#include <plat/sdrc.h> 33#include <plat/sdrc.h>
34#include <plat/gpmc.h> 34#include <plat/gpmc.h>
35#include <plat/serial.h> 35#include <plat/serial.h>
36#include <plat/vram.h>
36 37
37#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */ 38#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
38#include "clock.h" 39#include "clock.h"
@@ -264,6 +265,7 @@ void __init omap2_map_common_io(void)
264 omap2_check_revision(); 265 omap2_check_revision();
265 omap_sram_init(); 266 omap_sram_init();
266 omapfb_reserve_sdram(); 267 omapfb_reserve_sdram();
268 omap_vram_reserve_sdram();
267} 269}
268 270
269/* 271/*
diff --git a/arch/arm/plat-omap/include/plat/vram.h b/arch/arm/plat-omap/include/plat/vram.h
new file mode 100644
index 000000000000..edd4987758a6
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/vram.h
@@ -0,0 +1,62 @@
1/*
2 * VRAM manager for OMAP
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#ifndef __OMAP_VRAM_H__
22#define __OMAP_VRAM_H__
23
24#include <linux/types.h>
25
26#define OMAP_VRAM_MEMTYPE_SDRAM 0
27#define OMAP_VRAM_MEMTYPE_SRAM 1
28#define OMAP_VRAM_MEMTYPE_MAX 1
29
30extern int omap_vram_add_region(unsigned long paddr, size_t size);
31extern int omap_vram_free(unsigned long paddr, size_t size);
32extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
33extern int omap_vram_reserve(unsigned long paddr, size_t size);
34extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
35 unsigned long *largest_free_block);
36
37#ifdef CONFIG_OMAP2_VRAM
38extern void omap_vram_set_sdram_vram(u32 size, u32 start);
39extern void omap_vram_set_sram_vram(u32 size, u32 start);
40
41extern void omap_vram_reserve_sdram(void);
42extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
43 unsigned long sram_vstart,
44 unsigned long sram_size,
45 unsigned long pstart_avail,
46 unsigned long size_avail);
47#else
48static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
49static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
50
51static inline void omap_vram_reserve_sdram(void) { }
52static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
53 unsigned long sram_vstart,
54 unsigned long sram_size,
55 unsigned long pstart_avail,
56 unsigned long size_avail)
57{
58 return 0;
59}
60#endif
61
62#endif
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 3e923668778d..ad2bf07d30b5 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -28,6 +28,7 @@
28#include <plat/sram.h> 28#include <plat/sram.h>
29#include <plat/board.h> 29#include <plat/board.h>
30#include <plat/cpu.h> 30#include <plat/cpu.h>
31#include <plat/vram.h>
31 32
32#include <plat/control.h> 33#include <plat/control.h>
33 34
@@ -185,6 +186,13 @@ void __init omap_detect_sram(void)
185 omap_sram_start + SRAM_BOOTLOADER_SZ, 186 omap_sram_start + SRAM_BOOTLOADER_SZ,
186 omap_sram_size - SRAM_BOOTLOADER_SZ); 187 omap_sram_size - SRAM_BOOTLOADER_SZ);
187 omap_sram_size -= reserved; 188 omap_sram_size -= reserved;
189
190 reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
191 omap_sram_size,
192 omap_sram_start + SRAM_BOOTLOADER_SZ,
193 omap_sram_size - SRAM_BOOTLOADER_SZ);
194 omap_sram_size -= reserved;
195
188 omap_sram_ceil = omap_sram_base + omap_sram_size; 196 omap_sram_ceil = omap_sram_base + omap_sram_size;
189} 197}
190 198
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6b89eb55ed32..8be523f9a3f7 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2164,6 +2164,7 @@ config FB_BROADSHEET
2164 a bridge adapter. 2164 a bridge adapter.
2165 2165
2166source "drivers/video/omap/Kconfig" 2166source "drivers/video/omap/Kconfig"
2167source "drivers/video/omap2/Kconfig"
2167 2168
2168source "drivers/video/backlight/Kconfig" 2169source "drivers/video/backlight/Kconfig"
2169source "drivers/video/display/Kconfig" 2170source "drivers/video/display/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 80232e124889..0f8da331ba0f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o
124obj-$(CONFIG_FB_XILINX) += xilinxfb.o 124obj-$(CONFIG_FB_XILINX) += xilinxfb.o
125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o 125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
126obj-$(CONFIG_FB_OMAP) += omap/ 126obj-$(CONFIG_FB_OMAP) += omap/
127obj-y += omap2/
127obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o 128obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
128obj-$(CONFIG_FB_CARMINE) += carminefb.o 129obj-$(CONFIG_FB_CARMINE) += carminefb.o
129obj-$(CONFIG_FB_MB862XX) += mb862xx/ 130obj-$(CONFIG_FB_MB862XX) += mb862xx/
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
new file mode 100644
index 000000000000..7a6c4c9b902c
--- /dev/null
+++ b/drivers/video/omap2/Kconfig
@@ -0,0 +1,2 @@
1config OMAP2_VRAM
2 bool
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
new file mode 100644
index 000000000000..7fdf7bdf9e3b
--- /dev/null
+++ b/drivers/video/omap2/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_OMAP2_VRAM) += vram.o
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
new file mode 100644
index 000000000000..55a4de5e5d10
--- /dev/null
+++ b/drivers/video/omap2/vram.c
@@ -0,0 +1,655 @@
1/*
2 * VRAM manager for OMAP
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*#define DEBUG*/
22
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/list.h>
26#include <linux/seq_file.h>
27#include <linux/bootmem.h>
28#include <linux/completion.h>
29#include <linux/debugfs.h>
30#include <linux/jiffies.h>
31#include <linux/module.h>
32
33#include <asm/setup.h>
34
35#include <plat/sram.h>
36#include <plat/vram.h>
37#include <plat/dma.h>
38
39#ifdef DEBUG
40#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
41#else
42#define DBG(format, ...)
43#endif
44
45#define OMAP2_SRAM_START 0x40200000
46/* Maximum size, in reality this is smaller if SRAM is partially locked. */
47#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
48
49/* postponed regions are used to temporarily store region information at boot
50 * time when we cannot yet allocate the region list */
51#define MAX_POSTPONED_REGIONS 10
52
53static bool vram_initialized;
54static int postponed_cnt;
55static struct {
56 unsigned long paddr;
57 size_t size;
58} postponed_regions[MAX_POSTPONED_REGIONS];
59
60struct vram_alloc {
61 struct list_head list;
62 unsigned long paddr;
63 unsigned pages;
64};
65
66struct vram_region {
67 struct list_head list;
68 struct list_head alloc_list;
69 unsigned long paddr;
70 unsigned pages;
71};
72
73static DEFINE_MUTEX(region_mutex);
74static LIST_HEAD(region_list);
75
76static inline int region_mem_type(unsigned long paddr)
77{
78 if (paddr >= OMAP2_SRAM_START &&
79 paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
80 return OMAP_VRAM_MEMTYPE_SRAM;
81 else
82 return OMAP_VRAM_MEMTYPE_SDRAM;
83}
84
85static struct vram_region *omap_vram_create_region(unsigned long paddr,
86 unsigned pages)
87{
88 struct vram_region *rm;
89
90 rm = kzalloc(sizeof(*rm), GFP_KERNEL);
91
92 if (rm) {
93 INIT_LIST_HEAD(&rm->alloc_list);
94 rm->paddr = paddr;
95 rm->pages = pages;
96 }
97
98 return rm;
99}
100
101#if 0
102static void omap_vram_free_region(struct vram_region *vr)
103{
104 list_del(&vr->list);
105 kfree(vr);
106}
107#endif
108
109static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
110 unsigned long paddr, unsigned pages)
111{
112 struct vram_alloc *va;
113 struct vram_alloc *new;
114
115 new = kzalloc(sizeof(*va), GFP_KERNEL);
116
117 if (!new)
118 return NULL;
119
120 new->paddr = paddr;
121 new->pages = pages;
122
123 list_for_each_entry(va, &vr->alloc_list, list) {
124 if (va->paddr > new->paddr)
125 break;
126 }
127
128 list_add_tail(&new->list, &va->list);
129
130 return new;
131}
132
133static void omap_vram_free_allocation(struct vram_alloc *va)
134{
135 list_del(&va->list);
136 kfree(va);
137}
138
139int omap_vram_add_region(unsigned long paddr, size_t size)
140{
141 struct vram_region *rm;
142 unsigned pages;
143
144 if (vram_initialized) {
145 DBG("adding region paddr %08lx size %d\n",
146 paddr, size);
147
148 size &= PAGE_MASK;
149 pages = size >> PAGE_SHIFT;
150
151 rm = omap_vram_create_region(paddr, pages);
152 if (rm == NULL)
153 return -ENOMEM;
154
155 list_add(&rm->list, &region_list);
156 } else {
157 if (postponed_cnt == MAX_POSTPONED_REGIONS)
158 return -ENOMEM;
159
160 postponed_regions[postponed_cnt].paddr = paddr;
161 postponed_regions[postponed_cnt].size = size;
162
163 ++postponed_cnt;
164 }
165 return 0;
166}
167
168int omap_vram_free(unsigned long paddr, size_t size)
169{
170 struct vram_region *rm;
171 struct vram_alloc *alloc;
172 unsigned start, end;
173
174 DBG("free mem paddr %08lx size %d\n", paddr, size);
175
176 size = PAGE_ALIGN(size);
177
178 mutex_lock(&region_mutex);
179
180 list_for_each_entry(rm, &region_list, list) {
181 list_for_each_entry(alloc, &rm->alloc_list, list) {
182 start = alloc->paddr;
183 end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
184
185 if (start >= paddr && end < paddr + size)
186 goto found;
187 }
188 }
189
190 mutex_unlock(&region_mutex);
191 return -EINVAL;
192
193found:
194 omap_vram_free_allocation(alloc);
195
196 mutex_unlock(&region_mutex);
197 return 0;
198}
199EXPORT_SYMBOL(omap_vram_free);
200
201static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
202{
203 struct vram_region *rm;
204 struct vram_alloc *alloc;
205 size_t size;
206
207 size = pages << PAGE_SHIFT;
208
209 list_for_each_entry(rm, &region_list, list) {
210 unsigned long start, end;
211
212 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
213
214 if (region_mem_type(rm->paddr) != region_mem_type(paddr))
215 continue;
216
217 start = rm->paddr;
218 end = start + (rm->pages << PAGE_SHIFT) - 1;
219 if (start > paddr || end < paddr + size - 1)
220 continue;
221
222 DBG("block ok, checking allocs\n");
223
224 list_for_each_entry(alloc, &rm->alloc_list, list) {
225 end = alloc->paddr - 1;
226
227 if (start <= paddr && end >= paddr + size - 1)
228 goto found;
229
230 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
231 }
232
233 end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
234
235 if (!(start <= paddr && end >= paddr + size - 1))
236 continue;
237found:
238 DBG("found area start %lx, end %lx\n", start, end);
239
240 if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
241 return -ENOMEM;
242
243 return 0;
244 }
245
246 return -ENOMEM;
247}
248
249int omap_vram_reserve(unsigned long paddr, size_t size)
250{
251 unsigned pages;
252 int r;
253
254 DBG("reserve mem paddr %08lx size %d\n", paddr, size);
255
256 size = PAGE_ALIGN(size);
257 pages = size >> PAGE_SHIFT;
258
259 mutex_lock(&region_mutex);
260
261 r = _omap_vram_reserve(paddr, pages);
262
263 mutex_unlock(&region_mutex);
264
265 return r;
266}
267EXPORT_SYMBOL(omap_vram_reserve);
268
269static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
270{
271 struct completion *compl = data;
272 complete(compl);
273}
274
275static int _omap_vram_clear(u32 paddr, unsigned pages)
276{
277 struct completion compl;
278 unsigned elem_count;
279 unsigned frame_count;
280 int r;
281 int lch;
282
283 init_completion(&compl);
284
285 r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
286 _omap_vram_dma_cb,
287 &compl, &lch);
288 if (r) {
289 pr_err("VRAM: request_dma failed for memory clear\n");
290 return -EBUSY;
291 }
292
293 elem_count = pages * PAGE_SIZE / 4;
294 frame_count = 1;
295
296 omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
297 elem_count, frame_count,
298 OMAP_DMA_SYNC_ELEMENT,
299 0, 0);
300
301 omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
302 paddr, 0, 0);
303
304 omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
305
306 omap_start_dma(lch);
307
308 if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
309 omap_stop_dma(lch);
310 pr_err("VRAM: dma timeout while clearing memory\n");
311 r = -EIO;
312 goto err;
313 }
314
315 r = 0;
316err:
317 omap_free_dma(lch);
318
319 return r;
320}
321
322static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
323{
324 struct vram_region *rm;
325 struct vram_alloc *alloc;
326
327 list_for_each_entry(rm, &region_list, list) {
328 unsigned long start, end;
329
330 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
331
332 if (region_mem_type(rm->paddr) != mtype)
333 continue;
334
335 start = rm->paddr;
336
337 list_for_each_entry(alloc, &rm->alloc_list, list) {
338 end = alloc->paddr;
339
340 if (end - start >= pages << PAGE_SHIFT)
341 goto found;
342
343 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
344 }
345
346 end = rm->paddr + (rm->pages << PAGE_SHIFT);
347found:
348 if (end - start < pages << PAGE_SHIFT)
349 continue;
350
351 DBG("found %lx, end %lx\n", start, end);
352
353 alloc = omap_vram_create_allocation(rm, start, pages);
354 if (alloc == NULL)
355 return -ENOMEM;
356
357 *paddr = start;
358
359 _omap_vram_clear(start, pages);
360
361 return 0;
362 }
363
364 return -ENOMEM;
365}
366
367int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
368{
369 unsigned pages;
370 int r;
371
372 BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
373
374 DBG("alloc mem type %d size %d\n", mtype, size);
375
376 size = PAGE_ALIGN(size);
377 pages = size >> PAGE_SHIFT;
378
379 mutex_lock(&region_mutex);
380
381 r = _omap_vram_alloc(mtype, pages, paddr);
382
383 mutex_unlock(&region_mutex);
384
385 return r;
386}
387EXPORT_SYMBOL(omap_vram_alloc);
388
389void omap_vram_get_info(unsigned long *vram,
390 unsigned long *free_vram,
391 unsigned long *largest_free_block)
392{
393 struct vram_region *vr;
394 struct vram_alloc *va;
395
396 *vram = 0;
397 *free_vram = 0;
398 *largest_free_block = 0;
399
400 mutex_lock(&region_mutex);
401
402 list_for_each_entry(vr, &region_list, list) {
403 unsigned free;
404 unsigned long pa;
405
406 pa = vr->paddr;
407 *vram += vr->pages << PAGE_SHIFT;
408
409 list_for_each_entry(va, &vr->alloc_list, list) {
410 free = va->paddr - pa;
411 *free_vram += free;
412 if (free > *largest_free_block)
413 *largest_free_block = free;
414 pa = va->paddr + (va->pages << PAGE_SHIFT);
415 }
416
417 free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
418 *free_vram += free;
419 if (free > *largest_free_block)
420 *largest_free_block = free;
421 }
422
423 mutex_unlock(&region_mutex);
424}
425EXPORT_SYMBOL(omap_vram_get_info);
426
427#if defined(CONFIG_DEBUG_FS)
428static int vram_debug_show(struct seq_file *s, void *unused)
429{
430 struct vram_region *vr;
431 struct vram_alloc *va;
432 unsigned size;
433
434 mutex_lock(&region_mutex);
435
436 list_for_each_entry(vr, &region_list, list) {
437 size = vr->pages << PAGE_SHIFT;
438 seq_printf(s, "%08lx-%08lx (%d bytes)\n",
439 vr->paddr, vr->paddr + size - 1,
440 size);
441
442 list_for_each_entry(va, &vr->alloc_list, list) {
443 size = va->pages << PAGE_SHIFT;
444 seq_printf(s, " %08lx-%08lx (%d bytes)\n",
445 va->paddr, va->paddr + size - 1,
446 size);
447 }
448 }
449
450 mutex_unlock(&region_mutex);
451
452 return 0;
453}
454
455static int vram_debug_open(struct inode *inode, struct file *file)
456{
457 return single_open(file, vram_debug_show, inode->i_private);
458}
459
460static const struct file_operations vram_debug_fops = {
461 .open = vram_debug_open,
462 .read = seq_read,
463 .llseek = seq_lseek,
464 .release = single_release,
465};
466
467static int __init omap_vram_create_debugfs(void)
468{
469 struct dentry *d;
470
471 d = debugfs_create_file("vram", S_IRUGO, NULL,
472 NULL, &vram_debug_fops);
473 if (IS_ERR(d))
474 return PTR_ERR(d);
475
476 return 0;
477}
478#endif
479
480static __init int omap_vram_init(void)
481{
482 int i;
483
484 vram_initialized = 1;
485
486 for (i = 0; i < postponed_cnt; i++)
487 omap_vram_add_region(postponed_regions[i].paddr,
488 postponed_regions[i].size);
489
490#ifdef CONFIG_DEBUG_FS
491 if (omap_vram_create_debugfs())
492 pr_err("VRAM: Failed to create debugfs file\n");
493#endif
494
495 return 0;
496}
497
498arch_initcall(omap_vram_init);
499
500/* boottime vram alloc stuff */
501
502/* set from board file */
503static u32 omap_vram_sram_start __initdata;
504static u32 omap_vram_sram_size __initdata;
505
506/* set from board file */
507static u32 omap_vram_sdram_start __initdata;
508static u32 omap_vram_sdram_size __initdata;
509
510/* set from kernel cmdline */
511static u32 omap_vram_def_sdram_size __initdata;
512static u32 omap_vram_def_sdram_start __initdata;
513
514static void __init omap_vram_early_vram(char **p)
515{
516 omap_vram_def_sdram_size = memparse(*p, p);
517 if (**p == ',')
518 omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
519}
520__early_param("vram=", omap_vram_early_vram);
521
522/*
523 * Called from map_io. We need to call to this early enough so that we
524 * can reserve the fixed SDRAM regions before VM could get hold of them.
525 */
526void __init omap_vram_reserve_sdram(void)
527{
528 struct bootmem_data *bdata;
529 unsigned long sdram_start, sdram_size;
530 u32 paddr;
531 u32 size = 0;
532
533 /* cmdline arg overrides the board file definition */
534 if (omap_vram_def_sdram_size) {
535 size = omap_vram_def_sdram_size;
536 paddr = omap_vram_def_sdram_start;
537 }
538
539 if (!size) {
540 size = omap_vram_sdram_size;
541 paddr = omap_vram_sdram_start;
542 }
543
544#ifdef CONFIG_OMAP2_VRAM_SIZE
545 if (!size) {
546 size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
547 paddr = 0;
548 }
549#endif
550
551 if (!size)
552 return;
553
554 size = PAGE_ALIGN(size);
555
556 bdata = NODE_DATA(0)->bdata;
557 sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
558 sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
559
560 if (paddr) {
561 if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
562 paddr + size > sdram_start + sdram_size) {
563 pr_err("Illegal SDRAM region for VRAM\n");
564 return;
565 }
566
567 if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
568 pr_err("FB: failed to reserve VRAM\n");
569 return;
570 }
571 } else {
572 if (size > sdram_size) {
573 pr_err("Illegal SDRAM size for VRAM\n");
574 return;
575 }
576
577 paddr = virt_to_phys(alloc_bootmem_pages(size));
578 BUG_ON(paddr & ~PAGE_MASK);
579 }
580
581 omap_vram_add_region(paddr, size);
582
583 pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
584}
585
586/*
587 * Called at sram init time, before anything is pushed to the SRAM stack.
588 * Because of the stack scheme, we will allocate everything from the
589 * start of the lowest address region to the end of SRAM. This will also
590 * include padding for page alignment and possible holes between regions.
591 *
592 * As opposed to the SDRAM case, we'll also do any dynamic allocations at
593 * this point, since the driver built as a module would have problem with
594 * freeing / reallocating the regions.
595 */
596unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
597 unsigned long sram_vstart,
598 unsigned long sram_size,
599 unsigned long pstart_avail,
600 unsigned long size_avail)
601{
602 unsigned long pend_avail;
603 unsigned long reserved;
604 u32 paddr;
605 u32 size;
606
607 paddr = omap_vram_sram_start;
608 size = omap_vram_sram_size;
609
610 if (!size)
611 return 0;
612
613 reserved = 0;
614 pend_avail = pstart_avail + size_avail;
615
616 if (!paddr) {
617 /* Dynamic allocation */
618 if ((size_avail & PAGE_MASK) < size) {
619 pr_err("Not enough SRAM for VRAM\n");
620 return 0;
621 }
622 size_avail = (size_avail - size) & PAGE_MASK;
623 paddr = pstart_avail + size_avail;
624 }
625
626 if (paddr < sram_pstart ||
627 paddr + size > sram_pstart + sram_size) {
628 pr_err("Illegal SRAM region for VRAM\n");
629 return 0;
630 }
631
632 /* Reserve everything above the start of the region. */
633 if (pend_avail - paddr > reserved)
634 reserved = pend_avail - paddr;
635 size_avail = pend_avail - reserved - pstart_avail;
636
637 omap_vram_add_region(paddr, size);
638
639 if (reserved)
640 pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
641
642 return reserved;
643}
644
645void __init omap_vram_set_sdram_vram(u32 size, u32 start)
646{
647 omap_vram_sdram_start = start;
648 omap_vram_sdram_size = size;
649}
650
651void __init omap_vram_set_sram_vram(u32 size, u32 start)
652{
653 omap_vram_sram_start = start;
654 omap_vram_sram_size = size;
655}