@@ -98,6 +98,11 @@ struct bcm2708_fb {
98
98
struct bcm2708_fb_stats stats ;
99
99
unsigned long fb_bus_address ;
100
100
struct { u32 base , length ; } gpu ;
101
+
102
+ bool disable_arm_alloc ;
103
+ unsigned int image_size ;
104
+ dma_addr_t dma_addr ;
105
+ void * cpuaddr ;
101
106
};
102
107
103
108
#define to_bcm2708 (info ) container_of(info, struct bcm2708_fb, fb)
@@ -285,21 +290,102 @@ static int bcm2708_fb_set_par(struct fb_info *info)
285
290
.tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE , 8 , 0 },
286
291
.base = 0 ,
287
292
.screen_size = 0 ,
288
- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH , 4 , 0 },
293
+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH , 4 , 0 },
289
294
.pitch = 0 ,
290
295
};
291
- int ret ;
296
+ int ret , image_size ;
297
+
292
298
293
299
print_debug ("%s(%p) %dx%d (%dx%d), %d, %d\n" , __func__ , info ,
294
300
info -> var .xres , info -> var .yres , info -> var .xres_virtual ,
295
301
info -> var .yres_virtual , (int )info -> screen_size ,
296
302
info -> var .bits_per_pixel );
297
303
298
- ret = rpi_firmware_property_list (fb -> fw , & fbinfo , sizeof (fbinfo ));
304
+ /* Try allocating our own buffer. We can specify all the parameters */
305
+ image_size = ((info -> var .xres * info -> var .yres ) *
306
+ info -> var .bits_per_pixel ) >> 3 ;
307
+
308
+ if (!fb -> disable_arm_alloc &&
309
+ (image_size != fb -> image_size || !fb -> dma_addr )) {
310
+ if (fb -> dma_addr ) {
311
+ dma_free_coherent (info -> device , fb -> image_size ,
312
+ fb -> cpuaddr , fb -> dma_addr );
313
+ fb -> image_size = 0 ;
314
+ fb -> cpuaddr = NULL ;
315
+ fb -> dma_addr = 0 ;
316
+ }
317
+
318
+ fb -> cpuaddr = dma_alloc_coherent (info -> device , image_size ,
319
+ & fb -> dma_addr , GFP_ATOMIC );
320
+
321
+ if (!fb -> cpuaddr ) {
322
+ fb -> dma_addr = 0 ;
323
+ fb -> disable_arm_alloc = true;
324
+ } else {
325
+ fb -> image_size = image_size ;
326
+ }
327
+ }
328
+
329
+ if (fb -> cpuaddr ) {
330
+ fbinfo .base = fb -> dma_addr ;
331
+ fbinfo .screen_size = image_size ;
332
+ fbinfo .pitch = (info -> var .xres * info -> var .bits_per_pixel ) >> 3 ;
333
+
334
+ ret = rpi_firmware_property_list (fb -> fw , & fbinfo ,
335
+ sizeof (fbinfo ));
336
+ if (ret || fbinfo .base != fb -> dma_addr ) {
337
+ /* Firmware either failed, or assigned a different base
338
+ * address (ie it doesn't support being passed an FB
339
+ * allocation).
340
+ * Destroy the allocation, and don't try again.
341
+ */
342
+ dma_free_coherent (info -> device , fb -> image_size ,
343
+ fb -> cpuaddr , fb -> dma_addr );
344
+ fb -> image_size = 0 ;
345
+ fb -> cpuaddr = NULL ;
346
+ fb -> dma_addr = 0 ;
347
+ fb -> disable_arm_alloc = true;
348
+ }
349
+ } else {
350
+ /* Our allocation failed - drop into the old scheme of
351
+ * allocation by the VPU.
352
+ */
353
+ ret = - ENOMEM ;
354
+ }
355
+
299
356
if (ret ) {
300
- dev_err (info -> device ,
301
- "Failed to allocate GPU framebuffer (%d)\n" , ret );
302
- return ret ;
357
+ /* Old scheme */
358
+ const struct fb_alloc_tags fbinfo_old = {
359
+ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT ,
360
+ 8 , 0 , },
361
+ .xres = info -> var .xres ,
362
+ .yres = info -> var .yres ,
363
+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT ,
364
+ 8 , 0 , },
365
+ .xres_virtual = info -> var .xres_virtual ,
366
+ .yres_virtual = info -> var .yres_virtual ,
367
+ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH , 4 , 0 },
368
+ .bpp = info -> var .bits_per_pixel ,
369
+ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET ,
370
+ 8 , 0 },
371
+ .xoffset = info -> var .xoffset ,
372
+ .yoffset = info -> var .yoffset ,
373
+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE , 8 , 0 },
374
+ .base = 0 ,
375
+ .screen_size = 0 ,
376
+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH , 4 , 0 },
377
+ .pitch = 0 ,
378
+ };
379
+ fbinfo = fbinfo_old ;
380
+
381
+ ret = rpi_firmware_property_list (fb -> fw , & fbinfo ,
382
+ sizeof (fbinfo ));
383
+ if (ret ) {
384
+ dev_err (info -> device ,
385
+ "Failed to allocate GPU framebuffer (%d)\n" ,
386
+ ret );
387
+ return ret ;
388
+ }
303
389
}
304
390
305
391
if (info -> var .bits_per_pixel <= 8 )
@@ -314,9 +400,17 @@ static int bcm2708_fb_set_par(struct fb_info *info)
314
400
fb -> fb .fix .smem_start = fbinfo .base ;
315
401
fb -> fb .fix .smem_len = fbinfo .pitch * fbinfo .yres_virtual ;
316
402
fb -> fb .screen_size = fbinfo .screen_size ;
317
- if (fb -> fb .screen_base )
318
- iounmap (fb -> fb .screen_base );
319
- fb -> fb .screen_base = ioremap_wc (fbinfo .base , fb -> fb .screen_size );
403
+
404
+ if (!fb -> dma_addr ) {
405
+ if (fb -> fb .screen_base )
406
+ iounmap (fb -> fb .screen_base );
407
+
408
+ fb -> fb .screen_base = ioremap_wc (fbinfo .base ,
409
+ fb -> fb .screen_size );
410
+ } else {
411
+ fb -> fb .screen_base = fb -> cpuaddr ;
412
+ }
413
+
320
414
if (!fb -> fb .screen_base ) {
321
415
/* the console may currently be locked */
322
416
console_trylock ();
0 commit comments