Blame view

arch/arm/plat-omap/fb.c 10.1 KB
c40fae952   Tony Lindgren   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   Tony Lindgren   [ARM] 3454/1: ARM...
23
24
  #include <linux/module.h>
  #include <linux/kernel.h>
27ac792ca   Andrea Righi   PAGE_ALIGN(): cor...
25
  #include <linux/mm.h>
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
26
27
  #include <linux/init.h>
  #include <linux/platform_device.h>
98864ff58   Russell King   ARM: OMAP: Conver...
28
  #include <linux/memblock.h>
fced80c73   Russell King   [ARM] Convert asm...
29
  #include <linux/io.h>
91773a00f   Tomi Valkeinen   OMAP: OMAPFB: spl...
30
  #include <linux/omapfb.h>
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
31

a09e64fbc   Russell King   [ARM] Move includ...
32
  #include <mach/hardware.h>
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
33
  #include <asm/mach/map.h>
ce491cf85   Tony Lindgren   omap: headers: Mo...
34
35
  #include <plat/board.h>
  #include <plat/sram.h>
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
36

b0a330dc5   Manjunath Kondaiah G   OMAP: plat-omap: ...
37
  #include "fb.h"
0dc5e77c4   Tony Lindgren   [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   Imre Deak   ARM: OMAP: FB syn...
41
42
  static int config_invalid;
  static int configured_regions;
0dc5e77c4   Tony Lindgren   [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   Tomi Valkeinen   OMAP: DSS2: omapf...
56
57
58
  void omapfb_set_platform_data(struct omapfb_platform_data *data)
  {
  }
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
59
60
  static inline int ranges_overlap(unsigned long start1, unsigned long size1,
  				 unsigned long start2, unsigned long size2)
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
61
  {
b7cc6d46b   Imre Deak   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   Tony Lindgren   ARM: OMAP: Sync c...
77
  	int i;
b7cc6d46b   Imre Deak   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   Tony Lindgren   ARM: OMAP: Sync c...
85
  	}
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
86
87
  	return 0;
  }
c40fae952   Tony Lindgren   ARM: OMAP: Sync c...
88

b7cc6d46b   Imre Deak   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   Uwe Kleine-König   ARM: omap/fb: mov...
93
  static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
94
95
96
  {
  	const struct omap_fbmem_config	*conf;
  	u32				paddr;
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
97

b7cc6d46b   Imre Deak   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   Nicolas Kaiser   arm/omap: simplif...
125
  	if (rg->type || !rg->paddr)
b7cc6d46b   Imre Deak   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   Russell King   ARM: OMAP: Cleanu...
172
173
  static int valid_sdram(unsigned long addr, unsigned long size)
  {
5fd03ddab   Yinghai Lu   memblock/arm: Fix...
174
  	return memblock_is_region_memory(addr, size);
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
175
176
177
178
  }
  
  static int reserve_sdram(unsigned long addr, unsigned long size)
  {
98864ff58   Russell King   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   Russell King   ARM: OMAP: Cleanu...
184
  }
b7cc6d46b   Imre Deak   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   Russell King   ARM: OMAP: Conver...
189
  void __init omapfb_reserve_sdram_memblock(void)
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
190
  {
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
191
192
  	unsigned long reserved = 0;
  	int i;
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
193
194
195
  
  	if (config_invalid)
  		return;
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
196
  	for (i = 0; ; i++) {
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
197
  		struct omapfb_mem_region rg;
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
198
199
  
  		if (get_fbmem_region(i, &rg) < 0)
c40fae952   Tony Lindgren   ARM: OMAP: Sync c...
200
  			break;
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
201

b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
202
  		if (i == OMAPFB_PLANE_NUM) {
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
203
204
  			pr_err("Extraneous FB mem configuration entries
  ");
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
205
206
  			config_invalid = 1;
  			return;
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
207
  		}
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
208

b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
209
  		/* Check if it's our memory type. */
a1af0fbbb   Russell King   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   Imre Deak   ARM: OMAP: FB syn...
215
  			continue;
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
216
217
218
219
  
  		if (rg.size == 0) {
  			pr_err("Zero size for FB region %d
  ", i);
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
220
221
  			config_invalid = 1;
  			return;
c40fae952   Tony Lindgren   ARM: OMAP: Sync c...
222
  		}
a1af0fbbb   Russell King   ARM: OMAP: Cleanu...
223

72af2b363   Tomi Valkeinen   ARM: OMAP: Fix pr...
224
  		if (rg.paddr) {
a1af0fbbb   Russell King   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   Tomi Valkeinen   ARM: OMAP: Fix pr...
232
233
  			reserved += rg.size;
  		}
a1af0fbbb   Russell King   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   Imre Deak   ARM: OMAP: FB syn...
241
242
  		omapfb_config.mem_desc.region[i] = rg;
  		configured_regions++;
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
243
  	}
c40fae952   Tony Lindgren   ARM: OMAP: Sync c...
244
  	omapfb_config.mem_desc.region_cnt = i;
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
245
  	if (reserved)
c40fae952   Tony Lindgren   ARM: OMAP: Sync c...
246
247
  		pr_info("Reserving %lu bytes SDRAM for frame buffer
  ",
b7cc6d46b   Imre Deak   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   Uwe Kleine-König   ARM: omap/fb: mov...
261
  unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
b7cc6d46b   Imre Deak   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   Tony Lindgren   ARM: OMAP: Sync c...
287

b7cc6d46b   Imre Deak   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   Tony Lindgren   [ARM] 3454/1: ARM...
331
  }
771af222e   Imre Deak   ARM: OMAP: FB: ad...
332
333
334
335
  void omapfb_set_ctrl_platform_data(void *data)
  {
  	omapfb_config.ctrl_platform_data = data;
  }
375c324b7   Uwe Kleine-König   ARM: omap/fb: mov...
336
  static int __init omap_init_fb(void)
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
337
338
  {
  	const struct omap_lcd_config *conf;
b7cc6d46b   Imre Deak   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   Tony Lindgren   [ARM] 3454/1: ARM...
346
  	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
b7cc6d46b   Imre Deak   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   Tony Lindgren   [ARM] 3454/1: ARM...
352
  		return 0;
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
353
  	}
0dc5e77c4   Tony Lindgren   [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   Tomi Valkeinen   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   Uwe Kleine-König   ARM: omap/fb: mov...
380
  static int __init omap_init_fb(void)
b39a982dd   Tomi Valkeinen   OMAP: DSS2: omapf...
381
382
383
384
385
  {
  	return platform_device_register(&omap_fb_device);
  }
  
  arch_initcall(omap_init_fb);
0dc5e77c4   Tony Lindgren   [ARM] 3454/1: ARM...
386

98864ff58   Russell King   ARM: OMAP: Conver...
387
388
389
  void omapfb_reserve_sdram_memblock(void)
  {
  }
e92840b70   Uwe Kleine-König   ARM: omap/fb: mov...
390
  unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
391
392
393
  				  unsigned long sram_vstart,
  				  unsigned long sram_size,
  				  unsigned long start_avail,
cc150b03a   David Brownell   ARM: OMAP: Fix GC...
394
395
396
397
  				  unsigned long size_avail)
  {
  	return 0;
  }
b7cc6d46b   Imre Deak   ARM: OMAP: FB syn...
398

b39a982dd   Tomi Valkeinen   OMAP: DSS2: omapf...
399
400
401
402
403
  #else
  
  void omapfb_set_platform_data(struct omapfb_platform_data *data)
  {
  }
98864ff58   Russell King   ARM: OMAP: Conver...
404
405
406
  void omapfb_reserve_sdram_memblock(void)
  {
  }
e92840b70   Uwe Kleine-König   ARM: omap/fb: mov...
407
  unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
b39a982dd   Tomi Valkeinen   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   Tony Lindgren   [ARM] 3454/1: ARM...
415
416
  
  #endif