Skip to content

Commit

Permalink
video: bcm2708_fb: Try allocating on the ARM and passing to VPU
Browse files Browse the repository at this point in the history
Currently the VPU allocates the contiguous buffer for the
framebuffer.
Try an alternate path first where we use dma_alloc_coherent
and pass the buffer to the VPU. Should the VPU firmware not
support that path, then free the buffer and revert to the
old behaviour of using the VPU allocation.

Signed-off-by: Dave Stevenson <[email protected]>
  • Loading branch information
6by9 authored and popcornmix committed May 7, 2019
1 parent 8b55beb commit ca36c70
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 12 deletions.
102 changes: 90 additions & 12 deletions drivers/video/fbdev/bcm2708_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ struct bcm2708_fb {
struct bcm2708_fb_stats stats;
unsigned long fb_bus_address;
struct { u32 base, length; } gpu;

bool disable_arm_alloc;
unsigned int image_size;
dma_addr_t dma_addr;
void *cpuaddr;
};

#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
Expand Down Expand Up @@ -283,23 +288,88 @@ static int bcm2708_fb_set_par(struct fb_info *info)
.xoffset = info->var.xoffset,
.yoffset = info->var.yoffset,
.tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
.base = 0,
.screen_size = 0,
.tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
.pitch = 0,
/* base and screen_size will be initialised later */
.tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
/* pitch will be initialised later */
};
int ret;
int ret, image_size;


print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
info->var.xres, info->var.yres, info->var.xres_virtual,
info->var.yres_virtual, (int)info->screen_size,
info->var.bits_per_pixel);

ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
/* Try allocating our own buffer. We can specify all the parameters */
image_size = ((info->var.xres * info->var.yres) *
info->var.bits_per_pixel) >> 3;

if (!fb->disable_arm_alloc &&
(image_size != fb->image_size || !fb->dma_addr)) {
if (fb->dma_addr) {
dma_free_coherent(info->device, fb->image_size,
fb->cpuaddr, fb->dma_addr);
fb->image_size = 0;
fb->cpuaddr = NULL;
fb->dma_addr = 0;
}

fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
&fb->dma_addr, GFP_KERNEL);

if (!fb->cpuaddr) {
fb->dma_addr = 0;
fb->disable_arm_alloc = true;
} else {
fb->image_size = image_size;
}
}

if (fb->cpuaddr) {
fbinfo.base = fb->dma_addr;
fbinfo.screen_size = image_size;
fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;

ret = rpi_firmware_property_list(fb->fw, &fbinfo,
sizeof(fbinfo));
if (ret || fbinfo.base != fb->dma_addr) {
/* Firmware either failed, or assigned a different base
* address (ie it doesn't support being passed an FB
* allocation).
* Destroy the allocation, and don't try again.
*/
dma_free_coherent(info->device, fb->image_size,
fb->cpuaddr, fb->dma_addr);
fb->image_size = 0;
fb->cpuaddr = NULL;
fb->dma_addr = 0;
fb->disable_arm_alloc = true;
}
} else {
/* Our allocation failed - drop into the old scheme of
* allocation by the VPU.
*/
ret = -ENOMEM;
}

if (ret) {
dev_err(info->device,
"Failed to allocate GPU framebuffer (%d)\n", ret);
return ret;
/* Old scheme:
* - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
* - GET_PITCH instead of SET_PITCH.
*/
fbinfo.base = 0;
fbinfo.screen_size = 0;
fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
fbinfo.pitch = 0;

ret = rpi_firmware_property_list(fb->fw, &fbinfo,
sizeof(fbinfo));
if (ret) {
dev_err(info->device,
"Failed to allocate GPU framebuffer (%d)\n",
ret);
return ret;
}
}

if (info->var.bits_per_pixel <= 8)
Expand All @@ -314,9 +384,17 @@ static int bcm2708_fb_set_par(struct fb_info *info)
fb->fb.fix.smem_start = fbinfo.base;
fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
fb->fb.screen_size = fbinfo.screen_size;
if (fb->fb.screen_base)
iounmap(fb->fb.screen_base);
fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);

if (!fb->dma_addr) {
if (fb->fb.screen_base)
iounmap(fb->fb.screen_base);

fb->fb.screen_base = ioremap_wc(fbinfo.base,
fb->fb.screen_size);
} else {
fb->fb.screen_base = fb->cpuaddr;
}

if (!fb->fb.screen_base) {
/* the console may currently be locked */
console_trylock();
Expand Down
1 change: 1 addition & 0 deletions include/soc/bcm2835/raspberrypi-firmware.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
Expand Down

0 comments on commit ca36c70

Please sign in to comment.