ar71xx: rename NETGEAR_ variables to their netgear names
[oweals/openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0137-fbdev-bcm2708-Use-firmware-API.patch
1 From b436501db9136833c1e213d6efdb3b1c6e711bf1 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
3 Date: Mon, 20 Jul 2015 12:20:59 +0200
4 Subject: [PATCH 137/148] fbdev: bcm2708: Use firmware API
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 Use the new firmware API instead of the legacy mailbox API.
10
11 Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
12 ---
13  arch/arm/boot/dts/bcm2708_common.dtsi |   1 +
14  drivers/video/fbdev/bcm2708_fb.c      | 273 +++++++++++++++++++---------------
15  2 files changed, 152 insertions(+), 122 deletions(-)
16
17 --- a/arch/arm/boot/dts/bcm2708_common.dtsi
18 +++ b/arch/arm/boot/dts/bcm2708_common.dtsi
19 @@ -217,6 +217,7 @@
20  
21                 fb: fb {
22                         compatible = "brcm,bcm2708-fb";
23 +                       firmware = <&firmware>;
24                         status = "disabled";
25                 };
26  
27 --- a/drivers/video/fbdev/bcm2708_fb.c
28 +++ b/drivers/video/fbdev/bcm2708_fb.c
29 @@ -25,7 +25,6 @@
30  #include <linux/ioport.h>
31  #include <linux/list.h>
32  #include <linux/platform_data/dma-bcm2708.h>
33 -#include <linux/platform_data/mailbox-bcm2708.h>
34  #include <linux/platform_device.h>
35  #include <linux/clk.h>
36  #include <linux/printk.h>
37 @@ -34,6 +33,7 @@
38  #include <asm/sizes.h>
39  #include <linux/io.h>
40  #include <linux/dma-mapping.h>
41 +#include <soc/bcm2835/raspberrypi-firmware.h>
42  
43  //#define BCM2708_FB_DEBUG
44  #define MODULE_NAME "bcm2708_fb"
45 @@ -58,15 +58,19 @@ static u32 dma_busy_wait_threshold = 1<<
46  module_param(dma_busy_wait_threshold, int, 0644);
47  MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area");
48  
49 -/* this data structure describes each frame buffer device we find */
50 -
51 -struct fbinfo_s {
52 -       u32 xres, yres, xres_virtual, yres_virtual;
53 -       u32 pitch, bpp;
54 +struct fb_alloc_tags {
55 +       struct rpi_firmware_property_tag_header tag1;
56 +       u32 xres, yres;
57 +       struct rpi_firmware_property_tag_header tag2;
58 +       u32 xres_virtual, yres_virtual;
59 +       struct rpi_firmware_property_tag_header tag3;
60 +       u32 bpp;
61 +       struct rpi_firmware_property_tag_header tag4;
62         u32 xoffset, yoffset;
63 -       u32 base;
64 -       u32 screen_size;
65 -       u16 cmap[256];
66 +       struct rpi_firmware_property_tag_header tag5;
67 +       u32 base, screen_size;
68 +       struct rpi_firmware_property_tag_header tag6;
69 +       u32 pitch;
70  };
71  
72  struct bcm2708_fb_stats {
73 @@ -78,9 +82,9 @@ struct bcm2708_fb_stats {
74  struct bcm2708_fb {
75         struct fb_info fb;
76         struct platform_device *dev;
77 -       struct fbinfo_s *info;
78 -       dma_addr_t dma;
79 +       struct rpi_firmware *fw;
80         u32 cmap[16];
81 +       u32 gpu_cmap[256];
82         int dma_chan;
83         int dma_irq;
84         void __iomem *dma_chan_base;
85 @@ -270,69 +274,71 @@ static int bcm2708_fb_check_var(struct f
86  
87  static int bcm2708_fb_set_par(struct fb_info *info)
88  {
89 -       uint32_t val = 0;
90         struct bcm2708_fb *fb = to_bcm2708(info);
91 -       volatile struct fbinfo_s *fbinfo = fb->info;
92 -       fbinfo->xres = info->var.xres;
93 -       fbinfo->yres = info->var.yres;
94 -       fbinfo->xres_virtual = info->var.xres_virtual;
95 -       fbinfo->yres_virtual = info->var.yres_virtual;
96 -       fbinfo->bpp = info->var.bits_per_pixel;
97 -       fbinfo->xoffset = info->var.xoffset;
98 -       fbinfo->yoffset = info->var.yoffset;
99 -       fbinfo->base = 0;       /* filled in by VC */
100 -       fbinfo->pitch = 0;      /* filled in by VC */
101 +       struct fb_alloc_tags fbinfo = {
102 +               .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
103 +                         8, 0, },
104 +                       .xres = info->var.xres,
105 +                       .yres = info->var.yres,
106 +               .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
107 +                         8, 0, },
108 +                       .xres_virtual = info->var.xres_virtual,
109 +                       .yres_virtual = info->var.yres_virtual,
110 +               .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
111 +                       .bpp = info->var.bits_per_pixel,
112 +               .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
113 +                       .xoffset = info->var.xoffset,
114 +                       .yoffset = info->var.yoffset,
115 +               .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
116 +                       .base = 0,
117 +                       .screen_size = 0,
118 +               .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
119 +                       .pitch = 0,
120 +       };
121 +       int ret;
122  
123         print_debug("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info,
124                 info->var.xres, info->var.yres, info->var.xres_virtual,
125                 info->var.yres_virtual, (int)info->screen_size,
126                 info->var.bits_per_pixel);
127  
128 -       /* ensure last write to fbinfo is visible to GPU */
129 -       wmb();
130 -
131 -       /* inform vc about new framebuffer */
132 -       bcm_mailbox_write(MBOX_CHAN_FB, fb->dma);
133 +       ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
134 +       if (ret) {
135 +               dev_err(info->device,
136 +                       "Failed to allocate GPU framebuffer (%d)\n", ret);
137 +               return ret;
138 +       }
139  
140 -       /* TODO: replace fb driver with vchiq version */
141 -       /* wait for response */
142 -       bcm_mailbox_read(MBOX_CHAN_FB, &val);
143 -
144 -       /* ensure GPU writes are visible to us */
145 -       rmb();
146 -
147 -        if (val == 0) {
148 -               fb->fb.fix.line_length = fbinfo->pitch;
149 -
150 -               if (info->var.bits_per_pixel <= 8)
151 -                       fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
152 -               else
153 -                       fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
154 -
155 -               fb->fb_bus_address = fbinfo->base;
156 -               fbinfo->base &= ~0xc0000000;
157 -               fb->fb.fix.smem_start = fbinfo->base;
158 -               fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual;
159 -               fb->fb.screen_size = fbinfo->screen_size;
160 -               if (fb->fb.screen_base)
161 -                       iounmap(fb->fb.screen_base);
162 -               fb->fb.screen_base =
163 -                       (void *)ioremap_wc(fbinfo->base, fb->fb.screen_size);
164 -               if (!fb->fb.screen_base) {
165 -                       /* the console may currently be locked */
166 -                       console_trylock();
167 -                       console_unlock();
168 -                       pr_err("bcm2708_fb_set_par: Failed to set screen_base\n");
169 -                       return -EIO;
170 -               }
171 +       if (info->var.bits_per_pixel <= 8)
172 +               fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
173 +       else
174 +               fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
175 +
176 +       fb->fb.fix.line_length = fbinfo.pitch;
177 +       fbinfo.base |= 0x40000000;
178 +       fb->fb_bus_address = fbinfo.base;
179 +       fbinfo.base &= ~0xc0000000;
180 +       fb->fb.fix.smem_start = fbinfo.base;
181 +       fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
182 +       fb->fb.screen_size = fbinfo.screen_size;
183 +       if (fb->fb.screen_base)
184 +               iounmap(fb->fb.screen_base);
185 +       fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
186 +       if (!fb->fb.screen_base) {
187 +               /* the console may currently be locked */
188 +               console_trylock();
189 +               console_unlock();
190 +               dev_err(info->device, "Failed to set screen_base\n");
191 +               return -ENOMEM;
192         }
193 +
194         print_debug
195 -           ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n",
196 +           ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
197              (void *)fb->fb.screen_base, (void *)fb->fb_bus_address,
198 -            fbinfo->xres, fbinfo->yres, fbinfo->bpp,
199 -            fbinfo->pitch, (int)fb->fb.screen_size, val);
200 +            fbinfo.xres, fbinfo.yres, fbinfo.bpp,
201 +            fbinfo.pitch, (int)fb->fb.screen_size);
202  
203 -       return val;
204 +       return 0;
205  }
206  
207  static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
208 @@ -352,15 +358,34 @@ static int bcm2708_fb_setcolreg(unsigned
209         /*print_debug("BCM2708FB: setcolreg %d:(%02x,%02x,%02x,%02x) %x\n", regno, red, green, blue, transp, fb->fb.fix.visual);*/
210         if (fb->fb.var.bits_per_pixel <= 8) {
211                 if (regno < 256) {
212 -                       /* blue [0:4], green [5:10], red [11:15] */
213 -                       fb->info->cmap[regno] = ((red   >> (16-5)) & 0x1f) << 11 |
214 -                                               ((green >> (16-6)) & 0x3f) << 5 |
215 -                                               ((blue  >> (16-5)) & 0x1f) << 0;
216 +                       /* blue [23:16], green [15:8], red [7:0] */
217 +                       fb->gpu_cmap[regno] = ((red   >> 8) & 0xff) << 0 |
218 +                                             ((green >> 8) & 0xff) << 8 |
219 +                                             ((blue  >> 8) & 0xff) << 16;
220                 }
221                 /* Hack: we need to tell GPU the palette has changed, but currently bcm2708_fb_set_par takes noticable time when called for every (256) colour */
222                 /* So just call it for what looks like the last colour in a list for now. */
223 -               if (regno == 15 || regno == 255)
224 -                       bcm2708_fb_set_par(info);
225 +               if (regno == 15 || regno == 255) {
226 +                       struct packet {
227 +                               u32 offset;
228 +                               u32 length;
229 +                               u32 cmap[256];
230 +                       } *packet;
231 +                       int ret;
232 +
233 +                       packet = kmalloc(sizeof(*packet), GFP_KERNEL);
234 +                       if (!packet)
235 +                               return -ENOMEM;
236 +                       packet->offset = 0;
237 +                       packet->length = regno + 1;
238 +                       memcpy(packet->cmap, fb->gpu_cmap, sizeof(packet->cmap));
239 +                       ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
240 +                                                   packet, (2 + packet->length) * sizeof(u32));
241 +                       if (ret || packet->offset)
242 +                               dev_err(info->device, "Failed to set palette (%d,%u)\n",
243 +                                       ret, packet->offset);
244 +                       kfree(packet);
245 +               }
246          } else if (regno < 16) {
247                 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
248                     convert_bitfield(blue, &fb->fb.var.blue) |
249 @@ -372,27 +397,31 @@ static int bcm2708_fb_setcolreg(unsigned
250  
251  static int bcm2708_fb_blank(int blank_mode, struct fb_info *info)
252  {
253 -       s32 result = -1;
254 -       u32 p[7];
255 -       if (    (blank_mode == FB_BLANK_NORMAL) ||
256 -               (blank_mode == FB_BLANK_UNBLANK)) {
257 -
258 -               p[0] = 28; //  size = sizeof u32 * length of p
259 -               p[1] = VCMSG_PROCESS_REQUEST; // process request
260 -               p[2] = VCMSG_SET_BLANK_SCREEN; // (the tag id)
261 -               p[3] = 4; // (size of the response buffer)
262 -               p[4] = 4; // (size of the request data)
263 -               p[5] = blank_mode;
264 -               p[6] = VCMSG_PROPERTY_END; // end tag
265 -
266 -               bcm_mailbox_property(&p, p[0]);
267 -
268 -               if ( p[1] == VCMSG_REQUEST_SUCCESSFUL )
269 -                       result = 0;
270 -               else
271 -                       pr_err("bcm2708_fb_blank(%d) returns=%d p[1]=0x%x\n", blank_mode, p[5], p[1]);
272 +       struct bcm2708_fb *fb = to_bcm2708(info);
273 +       u32 value;
274 +       int ret;
275 +
276 +       switch (blank_mode) {
277 +       case FB_BLANK_UNBLANK:
278 +               value = 0;
279 +               break;
280 +       case FB_BLANK_NORMAL:
281 +       case FB_BLANK_VSYNC_SUSPEND:
282 +       case FB_BLANK_HSYNC_SUSPEND:
283 +       case FB_BLANK_POWERDOWN:
284 +               value = 1;
285 +               break;
286 +       default:
287 +               return -EINVAL;
288         }
289 -       return result;
290 +
291 +       ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
292 +                                   &value, sizeof(value));
293 +       if (ret)
294 +               dev_err(info->device, "bcm2708_fb_blank(%d) failed: %d\n",
295 +                       blank_mode, ret);
296 +
297 +       return ret;
298  }
299  
300  static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
301 @@ -408,25 +437,25 @@ static int bcm2708_fb_pan_display(struct
302  
303  static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
304  {
305 -       s32 result = -1;
306 -       u32 p[7];
307 -       if (cmd == FBIO_WAITFORVSYNC) {
308 -               p[0] = 28; //  size = sizeof u32 * length of p
309 -               p[1] = VCMSG_PROCESS_REQUEST; // process request
310 -               p[2] = VCMSG_SET_VSYNC; // (the tag id)
311 -               p[3] = 4; // (size of the response buffer)
312 -               p[4] = 4; // (size of the request data)
313 -               p[5] = 0; // dummy
314 -               p[6] = VCMSG_PROPERTY_END; // end tag
315 -
316 -               bcm_mailbox_property(&p, p[0]);
317 -
318 -               if ( p[1] == VCMSG_REQUEST_SUCCESSFUL )
319 -                       result = 0;
320 -               else
321 -                       pr_err("bcm2708_fb_ioctl %x,%lx returns=%d p[1]=0x%x\n", cmd, arg, p[5], p[1]);
322 +       struct bcm2708_fb *fb = to_bcm2708(info);
323 +       u32 dummy = 0;
324 +       int ret;
325 +
326 +       switch (cmd) {
327 +       case FBIO_WAITFORVSYNC:
328 +               ret = rpi_firmware_property(fb->fw,
329 +                                           RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
330 +                                           &dummy, sizeof(dummy));
331 +               break;
332 +       default:
333 +               dev_err(info->device, "Unknown ioctl 0x%x\n", cmd);
334 +               return -EINVAL;
335         }
336 -       return result;
337 +
338 +       if (ret)
339 +               dev_err(info->device, "ioctl 0x%x failed (%d)\n", cmd, ret);
340 +
341 +       return ret;
342  }
343  static void bcm2708_fb_fillrect(struct fb_info *info,
344                                 const struct fb_fillrect *rect)
345 @@ -621,20 +650,7 @@ static struct fb_ops bcm2708_fb_ops = {
346  static int bcm2708_fb_register(struct bcm2708_fb *fb)
347  {
348         int ret;
349 -       dma_addr_t dma;
350 -       void *mem;
351  
352 -       mem =
353 -           dma_alloc_coherent(&fb->dev->dev, PAGE_ALIGN(sizeof(*fb->info)), &dma,
354 -                              GFP_KERNEL);
355 -
356 -       if (NULL == mem) {
357 -               pr_err(": unable to allocate fbinfo buffer\n");
358 -               ret = -ENOMEM;
359 -       } else {
360 -               fb->info = (struct fbinfo_s *)mem;
361 -               fb->dma = dma;
362 -       }
363         fb->fb.fbops = &bcm2708_fb_ops;
364         fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA;
365         fb->fb.pseudo_palette = fb->cmap;
366 @@ -693,9 +709,22 @@ out:
367  
368  static int bcm2708_fb_probe(struct platform_device *dev)
369  {
370 +       struct device_node *fw_np;
371 +       struct rpi_firmware *fw;
372         struct bcm2708_fb *fb;
373         int ret;
374  
375 +       fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0);
376 +/* Remove comment when booting without Device Tree is no longer supported
377 +       if (!fw_np) {
378 +               dev_err(&dev->dev, "Missing firmware node\n");
379 +               return -ENOENT;
380 +       }
381 +*/
382 +       fw = rpi_firmware_get(fw_np);
383 +       if (!fw)
384 +               return -EPROBE_DEFER;
385 +
386         fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
387         if (!fb) {
388                 dev_err(&dev->dev,
389 @@ -704,6 +733,7 @@ static int bcm2708_fb_probe(struct platf
390                 goto free_region;
391         }
392  
393 +       fb->fw = fw;
394         bcm2708_fb_debugfs_init(fb);
395  
396         fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
397 @@ -737,6 +767,7 @@ static int bcm2708_fb_probe(struct platf
398                fb->dma_chan, fb->dma_chan_base);
399  
400         fb->dev = dev;
401 +       fb->fb.device = &dev->dev;
402  
403         ret = bcm2708_fb_register(fb);
404         if (ret == 0) {
405 @@ -769,8 +800,6 @@ static int bcm2708_fb_remove(struct plat
406         dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
407         bcm_dma_chan_free(fb->dma_chan);
408  
409 -       dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info,
410 -                         fb->dma);
411         bcm2708_fb_debugfs_deinit(fb);
412  
413         free_irq(fb->dma_irq, fb);