diff options
-rw-r--r-- | arch/arm/mach-omap2/io.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/vram.h | 62 | ||||
-rw-r--r-- | arch/arm/plat-omap/sram.c | 8 | ||||
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/omap2/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/omap2/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/omap2/vram.c | 655 |
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 | |||
30 | extern int omap_vram_add_region(unsigned long paddr, size_t size); | ||
31 | extern int omap_vram_free(unsigned long paddr, size_t size); | ||
32 | extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr); | ||
33 | extern int omap_vram_reserve(unsigned long paddr, size_t size); | ||
34 | extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram, | ||
35 | unsigned long *largest_free_block); | ||
36 | |||
37 | #ifdef CONFIG_OMAP2_VRAM | ||
38 | extern void omap_vram_set_sdram_vram(u32 size, u32 start); | ||
39 | extern void omap_vram_set_sram_vram(u32 size, u32 start); | ||
40 | |||
41 | extern void omap_vram_reserve_sdram(void); | ||
42 | extern 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 | ||
48 | static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { } | ||
49 | static inline void omap_vram_set_sram_vram(u32 size, u32 start) { } | ||
50 | |||
51 | static inline void omap_vram_reserve_sdram(void) { } | ||
52 | static 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 | ||
2166 | source "drivers/video/omap/Kconfig" | 2166 | source "drivers/video/omap/Kconfig" |
2167 | source "drivers/video/omap2/Kconfig" | ||
2167 | 2168 | ||
2168 | source "drivers/video/backlight/Kconfig" | 2169 | source "drivers/video/backlight/Kconfig" |
2169 | source "drivers/video/display/Kconfig" | 2170 | source "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 | |||
124 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 124 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
125 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o | 125 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o |
126 | obj-$(CONFIG_FB_OMAP) += omap/ | 126 | obj-$(CONFIG_FB_OMAP) += omap/ |
127 | obj-y += omap2/ | ||
127 | obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o | 128 | obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o |
128 | obj-$(CONFIG_FB_CARMINE) += carminefb.o | 129 | obj-$(CONFIG_FB_CARMINE) += carminefb.o |
129 | obj-$(CONFIG_FB_MB862XX) += mb862xx/ | 130 | obj-$(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 @@ | |||
1 | config 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 | |||
53 | static bool vram_initialized; | ||
54 | static int postponed_cnt; | ||
55 | static struct { | ||
56 | unsigned long paddr; | ||
57 | size_t size; | ||
58 | } postponed_regions[MAX_POSTPONED_REGIONS]; | ||
59 | |||
60 | struct vram_alloc { | ||
61 | struct list_head list; | ||
62 | unsigned long paddr; | ||
63 | unsigned pages; | ||
64 | }; | ||
65 | |||
66 | struct vram_region { | ||
67 | struct list_head list; | ||
68 | struct list_head alloc_list; | ||
69 | unsigned long paddr; | ||
70 | unsigned pages; | ||
71 | }; | ||
72 | |||
73 | static DEFINE_MUTEX(region_mutex); | ||
74 | static LIST_HEAD(region_list); | ||
75 | |||
76 | static 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 | |||
85 | static 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 | ||
102 | static void omap_vram_free_region(struct vram_region *vr) | ||
103 | { | ||
104 | list_del(&vr->list); | ||
105 | kfree(vr); | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | static 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 | |||
133 | static void omap_vram_free_allocation(struct vram_alloc *va) | ||
134 | { | ||
135 | list_del(&va->list); | ||
136 | kfree(va); | ||
137 | } | ||
138 | |||
139 | int 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, ®ion_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 | |||
168 | int 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(®ion_mutex); | ||
179 | |||
180 | list_for_each_entry(rm, ®ion_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(®ion_mutex); | ||
191 | return -EINVAL; | ||
192 | |||
193 | found: | ||
194 | omap_vram_free_allocation(alloc); | ||
195 | |||
196 | mutex_unlock(®ion_mutex); | ||
197 | return 0; | ||
198 | } | ||
199 | EXPORT_SYMBOL(omap_vram_free); | ||
200 | |||
201 | static 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, ®ion_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; | ||
237 | found: | ||
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 | |||
249 | int 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(®ion_mutex); | ||
260 | |||
261 | r = _omap_vram_reserve(paddr, pages); | ||
262 | |||
263 | mutex_unlock(®ion_mutex); | ||
264 | |||
265 | return r; | ||
266 | } | ||
267 | EXPORT_SYMBOL(omap_vram_reserve); | ||
268 | |||
269 | static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data) | ||
270 | { | ||
271 | struct completion *compl = data; | ||
272 | complete(compl); | ||
273 | } | ||
274 | |||
275 | static 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; | ||
316 | err: | ||
317 | omap_free_dma(lch); | ||
318 | |||
319 | return r; | ||
320 | } | ||
321 | |||
322 | static 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, ®ion_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); | ||
347 | found: | ||
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 | |||
367 | int 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(®ion_mutex); | ||
380 | |||
381 | r = _omap_vram_alloc(mtype, pages, paddr); | ||
382 | |||
383 | mutex_unlock(®ion_mutex); | ||
384 | |||
385 | return r; | ||
386 | } | ||
387 | EXPORT_SYMBOL(omap_vram_alloc); | ||
388 | |||
389 | void 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(®ion_mutex); | ||
401 | |||
402 | list_for_each_entry(vr, ®ion_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(®ion_mutex); | ||
424 | } | ||
425 | EXPORT_SYMBOL(omap_vram_get_info); | ||
426 | |||
427 | #if defined(CONFIG_DEBUG_FS) | ||
428 | static 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(®ion_mutex); | ||
435 | |||
436 | list_for_each_entry(vr, ®ion_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(®ion_mutex); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int vram_debug_open(struct inode *inode, struct file *file) | ||
456 | { | ||
457 | return single_open(file, vram_debug_show, inode->i_private); | ||
458 | } | ||
459 | |||
460 | static 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 | |||
467 | static 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 | |||
480 | static __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 | |||
498 | arch_initcall(omap_vram_init); | ||
499 | |||
500 | /* boottime vram alloc stuff */ | ||
501 | |||
502 | /* set from board file */ | ||
503 | static u32 omap_vram_sram_start __initdata; | ||
504 | static u32 omap_vram_sram_size __initdata; | ||
505 | |||
506 | /* set from board file */ | ||
507 | static u32 omap_vram_sdram_start __initdata; | ||
508 | static u32 omap_vram_sdram_size __initdata; | ||
509 | |||
510 | /* set from kernel cmdline */ | ||
511 | static u32 omap_vram_def_sdram_size __initdata; | ||
512 | static u32 omap_vram_def_sdram_start __initdata; | ||
513 | |||
514 | static 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 | */ | ||
526 | void __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 | */ | ||
596 | unsigned 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 | |||
645 | void __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 | |||
651 | void __init omap_vram_set_sram_vram(u32 size, u32 start) | ||
652 | { | ||
653 | omap_vram_sram_start = start; | ||
654 | omap_vram_sram_size = size; | ||
655 | } | ||