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