3377405b95deacf6c8e75d8b723a94c3d323395a
[oweals/openwrt.git] /
1 From ea9d3e8b98633b3d449ec0a786be6a95c940b027 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 27 Feb 2019 17:30:33 +0000
4 Subject: [PATCH 367/773] video: bcm2708_fb: Try allocating on the ARM and
5  passing to VPU
6
7 Currently the VPU allocates the contiguous buffer for the
8 framebuffer.
9 Try an alternate path first where we use dma_alloc_coherent
10 and pass the buffer to the VPU. Should the VPU firmware not
11 support that path, then free the buffer and revert to the
12 old behaviour of using the VPU allocation.
13
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
15 ---
16  drivers/video/fbdev/bcm2708_fb.c           | 102 ++++++++++++++++++---
17  include/soc/bcm2835/raspberrypi-firmware.h |   1 +
18  2 files changed, 91 insertions(+), 12 deletions(-)
19
20 --- a/drivers/video/fbdev/bcm2708_fb.c
21 +++ b/drivers/video/fbdev/bcm2708_fb.c
22 @@ -98,6 +98,11 @@ struct bcm2708_fb {
23         struct bcm2708_fb_stats stats;
24         unsigned long fb_bus_address;
25         struct { u32 base, length; } gpu;
26 +
27 +       bool disable_arm_alloc;
28 +       unsigned int image_size;
29 +       dma_addr_t dma_addr;
30 +       void *cpuaddr;
31  };
32  
33  #define to_bcm2708(info)       container_of(info, struct bcm2708_fb, fb)
34 @@ -283,23 +288,88 @@ static int bcm2708_fb_set_par(struct fb_
35                         .xoffset = info->var.xoffset,
36                         .yoffset = info->var.yoffset,
37                 .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
38 -                       .base = 0,
39 -                       .screen_size = 0,
40 -               .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
41 -                       .pitch = 0,
42 +                       /* base and screen_size will be initialised later */
43 +               .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
44 +                       /* pitch will be initialised later */
45         };
46 -       int ret;
47 +       int ret, image_size;
48 +
49  
50         print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
51                     info->var.xres, info->var.yres, info->var.xres_virtual,
52                     info->var.yres_virtual, (int)info->screen_size,
53                     info->var.bits_per_pixel);
54  
55 -       ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
56 +       /* Try allocating our own buffer. We can specify all the parameters */
57 +       image_size = ((info->var.xres * info->var.yres) *
58 +                     info->var.bits_per_pixel) >> 3;
59 +
60 +       if (!fb->disable_arm_alloc &&
61 +           (image_size != fb->image_size || !fb->dma_addr)) {
62 +               if (fb->dma_addr) {
63 +                       dma_free_coherent(info->device, fb->image_size,
64 +                                         fb->cpuaddr, fb->dma_addr);
65 +                       fb->image_size = 0;
66 +                       fb->cpuaddr = NULL;
67 +                       fb->dma_addr = 0;
68 +               }
69 +
70 +               fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
71 +                                                &fb->dma_addr, GFP_KERNEL);
72 +
73 +               if (!fb->cpuaddr) {
74 +                       fb->dma_addr = 0;
75 +                       fb->disable_arm_alloc = true;
76 +               } else {
77 +                       fb->image_size = image_size;
78 +               }
79 +       }
80 +
81 +       if (fb->cpuaddr) {
82 +               fbinfo.base = fb->dma_addr;
83 +               fbinfo.screen_size = image_size;
84 +               fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
85 +
86 +               ret = rpi_firmware_property_list(fb->fw, &fbinfo,
87 +                                                sizeof(fbinfo));
88 +               if (ret || fbinfo.base != fb->dma_addr) {
89 +                       /* Firmware either failed, or assigned a different base
90 +                        * address (ie it doesn't support being passed an FB
91 +                        * allocation).
92 +                        * Destroy the allocation, and don't try again.
93 +                        */
94 +                       dma_free_coherent(info->device, fb->image_size,
95 +                                         fb->cpuaddr, fb->dma_addr);
96 +                       fb->image_size = 0;
97 +                       fb->cpuaddr = NULL;
98 +                       fb->dma_addr = 0;
99 +                       fb->disable_arm_alloc = true;
100 +               }
101 +       } else {
102 +               /* Our allocation failed - drop into the old scheme of
103 +                * allocation by the VPU.
104 +                */
105 +               ret = -ENOMEM;
106 +       }
107 +
108         if (ret) {
109 -               dev_err(info->device,
110 -                       "Failed to allocate GPU framebuffer (%d)\n", ret);
111 -               return ret;
112 +               /* Old scheme:
113 +                * - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
114 +                * - GET_PITCH instead of SET_PITCH.
115 +                */
116 +               fbinfo.base = 0;
117 +               fbinfo.screen_size = 0;
118 +               fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
119 +               fbinfo.pitch = 0;
120 +
121 +               ret = rpi_firmware_property_list(fb->fw, &fbinfo,
122 +                                                sizeof(fbinfo));
123 +               if (ret) {
124 +                       dev_err(info->device,
125 +                               "Failed to allocate GPU framebuffer (%d)\n",
126 +                               ret);
127 +                       return ret;
128 +               }
129         }
130  
131         if (info->var.bits_per_pixel <= 8)
132 @@ -314,9 +384,17 @@ static int bcm2708_fb_set_par(struct fb_
133         fb->fb.fix.smem_start = fbinfo.base;
134         fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
135         fb->fb.screen_size = fbinfo.screen_size;
136 -       if (fb->fb.screen_base)
137 -               iounmap(fb->fb.screen_base);
138 -       fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
139 +
140 +       if (!fb->dma_addr) {
141 +               if (fb->fb.screen_base)
142 +                       iounmap(fb->fb.screen_base);
143 +
144 +               fb->fb.screen_base = ioremap_wc(fbinfo.base,
145 +                                               fb->fb.screen_size);
146 +       } else {
147 +               fb->fb.screen_base = fb->cpuaddr;
148 +       }
149 +
150         if (!fb->fb.screen_base) {
151                 /* the console may currently be locked */
152                 console_trylock();
153 --- a/include/soc/bcm2835/raspberrypi-firmware.h
154 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
155 @@ -128,6 +128,7 @@ enum rpi_firmware_property_tag {
156         RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH =                  0x00048005,
157         RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER =            0x00048006,
158         RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE =             0x00048007,
159 +       RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH =                  0x00048008,
160         RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET =         0x00048009,
161         RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN =               0x0004800a,
162         RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE =                0x0004800b,