diff options
author | Imre Deak <imre.deak@solidboot.com> | 2007-03-06 06:16:36 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-05-09 05:39:14 -0400 |
commit | b7cc6d46b4f8157bfc58a6ed143ffa83575e236a (patch) | |
tree | 107a080740734d99d32ee92372fd7a9c6de538f6 /arch/arm/plat-omap/fb.c | |
parent | b01d96d653b1387ee0a91094ee54a8c523c3be09 (diff) |
ARM: OMAP: FB sync with N800 tree (support for dynamic SRAM allocations)
- in addition to fixed FB regions - as passed by the bootloader -
allow dynamic allocations
- do some more checking against overlapping / reserved regions
- move the FB specific parts out from sram.c to fb.c
Signed-off-by: Imre Deak <imre.deak@solidboot.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-omap/fb.c')
-rw-r--r-- | arch/arm/plat-omap/fb.c | 277 |
1 files changed, 247 insertions, 30 deletions
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c index a302d9194f57..469f580ca057 100644 --- a/arch/arm/plat-omap/fb.c +++ b/arch/arm/plat-omap/fb.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) | 39 | #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) |
40 | 40 | ||
41 | static struct omapfb_platform_data omapfb_config; | 41 | static struct omapfb_platform_data omapfb_config; |
42 | static int config_invalid; | ||
43 | static int configured_regions; | ||
42 | 44 | ||
43 | static u64 omap_fb_dma_mask = ~(u32)0; | 45 | static u64 omap_fb_dma_mask = ~(u32)0; |
44 | 46 | ||
@@ -53,46 +55,246 @@ static struct platform_device omap_fb_device = { | |||
53 | .num_resources = 0, | 55 | .num_resources = 0, |
54 | }; | 56 | }; |
55 | 57 | ||
56 | /* called from map_io */ | 58 | static inline int ranges_overlap(unsigned long start1, unsigned long size1, |
57 | void omapfb_reserve_mem(void) | 59 | unsigned long start2, unsigned long size2) |
58 | { | 60 | { |
59 | const struct omap_fbmem_config *fbmem_conf; | 61 | return (start1 >= start2 && start1 < start2 + size2) || |
60 | unsigned long total_size; | 62 | (start2 >= start1 && start2 < start1 + size1); |
63 | } | ||
64 | |||
65 | static inline int range_included(unsigned long start1, unsigned long size1, | ||
66 | unsigned long start2, unsigned long size2) | ||
67 | { | ||
68 | return start1 >= start2 && start1 + size1 <= start2 + size2; | ||
69 | } | ||
70 | |||
71 | |||
72 | /* Check if there is an overlapping region. */ | ||
73 | static int fbmem_region_reserved(unsigned long start, size_t size) | ||
74 | { | ||
75 | struct omapfb_mem_region *rg; | ||
61 | int i; | 76 | int i; |
62 | 77 | ||
63 | if (!omap_fb_sram_valid) { | 78 | rg = &omapfb_config.mem_desc.region[0]; |
64 | /* FBMEM SRAM configuration was already found to be invalid. | 79 | for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) { |
65 | * Ignore the whole configuration block. */ | 80 | if (!rg->paddr) |
66 | omapfb_config.mem_desc.region_cnt = 0; | 81 | /* Empty slot. */ |
67 | return; | 82 | continue; |
83 | if (ranges_overlap(start, size, rg->paddr, rg->size)) | ||
84 | return 1; | ||
68 | } | 85 | } |
86 | return 0; | ||
87 | } | ||
69 | 88 | ||
70 | i = 0; | 89 | /* |
71 | total_size = 0; | 90 | * Get the region_idx`th region from board config/ATAG and convert it to |
72 | while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM, | 91 | * our internal format. |
73 | struct omap_fbmem_config, i)) != NULL) { | 92 | */ |
74 | unsigned long start; | 93 | static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg) |
75 | unsigned long size; | 94 | { |
95 | const struct omap_fbmem_config *conf; | ||
96 | u32 paddr; | ||
76 | 97 | ||
77 | if (i == OMAPFB_PLANE_NUM) { | 98 | conf = omap_get_nr_config(OMAP_TAG_FBMEM, |
78 | printk(KERN_ERR "ignoring extra plane info\n"); | 99 | struct omap_fbmem_config, region_idx); |
100 | if (conf == NULL) | ||
101 | return -ENOENT; | ||
102 | |||
103 | paddr = conf->start; | ||
104 | /* | ||
105 | * Low bits encode the page allocation mode, if high bits | ||
106 | * are zero. Otherwise we need a page aligned fixed | ||
107 | * address. | ||
108 | */ | ||
109 | memset(rg, 0, sizeof(*rg)); | ||
110 | rg->type = paddr & ~PAGE_MASK; | ||
111 | rg->paddr = paddr & PAGE_MASK; | ||
112 | rg->size = PAGE_ALIGN(conf->size); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type, | ||
117 | unsigned long mem_start, | ||
118 | unsigned long mem_size) | ||
119 | { | ||
120 | /* | ||
121 | * Check if the configuration specifies the type explicitly. | ||
122 | * type = 0 && paddr = 0, a default don't care case maps to | ||
123 | * the SDRAM type. | ||
124 | */ | ||
125 | if (rg->type || (!rg->type && !rg->paddr)) | ||
126 | return 0; | ||
127 | if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) { | ||
128 | rg->type = mem_type; | ||
129 | return 0; | ||
130 | } | ||
131 | /* Can't determine it. */ | ||
132 | return -1; | ||
133 | } | ||
134 | |||
135 | static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg, | ||
136 | unsigned long start_avail, unsigned size_avail) | ||
137 | { | ||
138 | unsigned long paddr = rg->paddr; | ||
139 | size_t size = rg->size; | ||
140 | |||
141 | if (rg->type > OMAPFB_MEMTYPE_MAX) { | ||
142 | printk(KERN_ERR | ||
143 | "Invalid start address for FB region %d\n", region_idx); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | if (!rg->size) { | ||
148 | printk(KERN_ERR "Zero size for FB region %d\n", region_idx); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | if (!paddr) | ||
153 | /* Allocate this dynamically, leave paddr 0 for now. */ | ||
154 | return 0; | ||
155 | |||
156 | /* | ||
157 | * Fixed region for the given RAM range. Check if it's already | ||
158 | * reserved by the FB code or someone else. | ||
159 | */ | ||
160 | if (fbmem_region_reserved(paddr, size) || | ||
161 | !range_included(paddr, size, start_avail, size_avail)) { | ||
162 | printk(KERN_ERR "Trying to use reserved memory " | ||
163 | "for FB region %d\n", region_idx); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Called from map_io. We need to call to this early enough so that we | ||
172 | * can reserve the fixed SDRAM regions before VM could get hold of them. | ||
173 | */ | ||
174 | void omapfb_reserve_sdram(void) | ||
175 | { | ||
176 | struct bootmem_data *bdata; | ||
177 | unsigned long sdram_start, sdram_size; | ||
178 | unsigned long reserved; | ||
179 | int i; | ||
180 | |||
181 | if (config_invalid) | ||
182 | return; | ||
183 | |||
184 | bdata = NODE_DATA(0)->bdata; | ||
185 | sdram_start = bdata->node_boot_start; | ||
186 | sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start; | ||
187 | reserved = 0; | ||
188 | for (i = 0; ; i++) { | ||
189 | struct omapfb_mem_region rg; | ||
190 | |||
191 | if (get_fbmem_region(i, &rg) < 0) | ||
79 | break; | 192 | break; |
193 | if (i == OMAPFB_PLANE_NUM) { | ||
194 | printk(KERN_ERR | ||
195 | "Extraneous FB mem configuration entries\n"); | ||
196 | config_invalid = 1; | ||
197 | return; | ||
80 | } | 198 | } |
81 | start = fbmem_conf->start; | 199 | /* Check if it's our memory type. */ |
82 | size = fbmem_conf->size; | 200 | if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM, |
83 | omapfb_config.mem_desc.region[i].paddr = start; | 201 | sdram_start, sdram_size) < 0 || |
84 | omapfb_config.mem_desc.region[i].size = size; | 202 | (rg.type != OMAPFB_MEMTYPE_SDRAM)) |
85 | if (omap_fb_sram_plane != i && start) { | 203 | continue; |
86 | reserve_bootmem(start, size); | 204 | BUG_ON(omapfb_config.mem_desc.region[i].size); |
87 | total_size += size; | 205 | if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) { |
206 | config_invalid = 1; | ||
207 | return; | ||
88 | } | 208 | } |
89 | i++; | 209 | if (rg.paddr) |
210 | reserve_bootmem(rg.paddr, rg.size); | ||
211 | reserved += rg.size; | ||
212 | omapfb_config.mem_desc.region[i] = rg; | ||
213 | configured_regions++; | ||
90 | } | 214 | } |
91 | omapfb_config.mem_desc.region_cnt = i; | 215 | omapfb_config.mem_desc.region_cnt = i; |
92 | if (total_size) | 216 | if (reserved) |
93 | pr_info("Reserving %lu bytes SDRAM for frame buffer\n", | 217 | pr_info("Reserving %lu bytes SDRAM for frame buffer\n", |
94 | total_size); | 218 | reserved); |
219 | } | ||
220 | |||
221 | /* | ||
222 | * Called at sram init time, before anything is pushed to the SRAM stack. | ||
223 | * Because of the stack scheme, we will allocate everything from the | ||
224 | * start of the lowest address region to the end of SRAM. This will also | ||
225 | * include padding for page alignment and possible holes between regions. | ||
226 | * | ||
227 | * As opposed to the SDRAM case, we'll also do any dynamic allocations at | ||
228 | * this point, since the driver built as a module would have problem with | ||
229 | * freeing / reallocating the regions. | ||
230 | */ | ||
231 | unsigned long omapfb_reserve_sram(unsigned long sram_pstart, | ||
232 | unsigned long sram_vstart, | ||
233 | unsigned long sram_size, | ||
234 | unsigned long pstart_avail, | ||
235 | unsigned long size_avail) | ||
236 | { | ||
237 | struct omapfb_mem_region rg; | ||
238 | unsigned long pend_avail; | ||
239 | unsigned long reserved; | ||
240 | int i; | ||
241 | |||
242 | if (config_invalid) | ||
243 | return 0; | ||
244 | |||
245 | reserved = 0; | ||
246 | pend_avail = pstart_avail + size_avail; | ||
247 | for (i = 0; ; i++) { | ||
248 | if (get_fbmem_region(i, &rg) < 0) | ||
249 | break; | ||
250 | if (i == OMAPFB_PLANE_NUM) { | ||
251 | printk(KERN_ERR | ||
252 | "Extraneous FB mem configuration entries\n"); | ||
253 | config_invalid = 1; | ||
254 | return 0; | ||
255 | } | ||
95 | 256 | ||
257 | /* Check if it's our memory type. */ | ||
258 | if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM, | ||
259 | sram_pstart, sram_size) < 0 || | ||
260 | (rg.type != OMAPFB_MEMTYPE_SRAM)) | ||
261 | continue; | ||
262 | BUG_ON(omapfb_config.mem_desc.region[i].size); | ||
263 | |||
264 | if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) { | ||
265 | config_invalid = 1; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | if (!rg.paddr) { | ||
270 | /* Dynamic allocation */ | ||
271 | if ((size_avail & PAGE_MASK) < rg.size) { | ||
272 | printk("Not enough SRAM for FB region %d\n", | ||
273 | i); | ||
274 | config_invalid = 1; | ||
275 | return 0; | ||
276 | } | ||
277 | size_avail = (size_avail - rg.size) & PAGE_MASK; | ||
278 | rg.paddr = pstart_avail + size_avail; | ||
279 | } | ||
280 | /* Reserve everything above the start of the region. */ | ||
281 | if (pend_avail - rg.paddr > reserved) | ||
282 | reserved = pend_avail - rg.paddr; | ||
283 | size_avail = pend_avail - reserved - pstart_avail; | ||
284 | |||
285 | /* | ||
286 | * We have a kernel mapping for this already, so the | ||
287 | * driver won't have to make one. | ||
288 | */ | ||
289 | rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart); | ||
290 | omapfb_config.mem_desc.region[i] = rg; | ||
291 | configured_regions++; | ||
292 | } | ||
293 | omapfb_config.mem_desc.region_cnt = i; | ||
294 | if (reserved) | ||
295 | pr_info("Reserving %lu bytes SRAM for frame buffer\n", | ||
296 | reserved); | ||
297 | return reserved; | ||
96 | } | 298 | } |
97 | 299 | ||
98 | void omapfb_set_ctrl_platform_data(void *data) | 300 | void omapfb_set_ctrl_platform_data(void *data) |
@@ -104,10 +306,19 @@ static inline int omap_init_fb(void) | |||
104 | { | 306 | { |
105 | const struct omap_lcd_config *conf; | 307 | const struct omap_lcd_config *conf; |
106 | 308 | ||
309 | if (config_invalid) | ||
310 | return 0; | ||
311 | if (configured_regions != omapfb_config.mem_desc.region_cnt) { | ||
312 | printk(KERN_ERR "Invalid FB mem configuration entries\n"); | ||
313 | return 0; | ||
314 | } | ||
107 | conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); | 315 | conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); |
108 | if (conf == NULL) | 316 | if (conf == NULL) { |
317 | if (configured_regions) | ||
318 | /* FB mem config, but no LCD config? */ | ||
319 | printk(KERN_ERR "Missing LCD configuration\n"); | ||
109 | return 0; | 320 | return 0; |
110 | 321 | } | |
111 | omapfb_config.lcd = *conf; | 322 | omapfb_config.lcd = *conf; |
112 | 323 | ||
113 | return platform_device_register(&omap_fb_device); | 324 | return platform_device_register(&omap_fb_device); |
@@ -117,7 +328,13 @@ arch_initcall(omap_init_fb); | |||
117 | 328 | ||
118 | #else | 329 | #else |
119 | 330 | ||
120 | void omapfb_reserve_mem(void) {} | 331 | void omapfb_reserve_sdram(void) {} |
332 | unsigned long omapfb_reserve_sram(unsigned long sram_pstart, | ||
333 | unsigned long sram_vstart, | ||
334 | unsigned long sram_size, | ||
335 | unsigned long start_avail, | ||
336 | unsigned long size_avail) {} | ||
337 | |||
121 | 338 | ||
122 | #endif | 339 | #endif |
123 | 340 | ||