]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/video/fbdev/bcm2708_fb.c
bcm2708 framebuffer driver
[mirror_ubuntu-artful-kernel.git] / drivers / video / fbdev / bcm2708_fb.c
1 /*
2 * linux/drivers/video/bcm2708_fb.c
3 *
4 * Copyright (C) 2010 Broadcom
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 * Broadcom simple framebuffer driver
11 *
12 * This file is derived from cirrusfb.c
13 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
14 *
15 */
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
20 #include <linux/slab.h>
21 #include <linux/mm.h>
22 #include <linux/fb.h>
23 #include <linux/init.h>
24 #include <linux/interrupt.h>
25 #include <linux/ioport.h>
26 #include <linux/list.h>
27 #include <linux/platform_data/dma-bcm2708.h>
28 #include <linux/platform_device.h>
29 #include <linux/clk.h>
30 #include <linux/printk.h>
31 #include <linux/console.h>
32 #include <linux/debugfs.h>
33 #include <asm/sizes.h>
34 #include <linux/io.h>
35 #include <linux/dma-mapping.h>
36 #include <soc/bcm2835/raspberrypi-firmware.h>
37
38 //#define BCM2708_FB_DEBUG
39 #define MODULE_NAME "bcm2708_fb"
40
41 #ifdef BCM2708_FB_DEBUG
42 #define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
43 #else
44 #define print_debug(fmt,...)
45 #endif
46
47 /* This is limited to 16 characters when displayed by X startup */
48 static const char *bcm2708_name = "BCM2708 FB";
49
50 #define DRIVER_NAME "bcm2708_fb"
51
52 static int fbwidth = 800; /* module parameter */
53 static int fbheight = 480; /* module parameter */
54 static int fbdepth = 32; /* module parameter */
55 static int fbswap = 0; /* module parameter */
56
57 static u32 dma_busy_wait_threshold = 1<<15;
58 module_param(dma_busy_wait_threshold, int, 0644);
59 MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area");
60
61 struct fb_alloc_tags {
62 struct rpi_firmware_property_tag_header tag1;
63 u32 xres, yres;
64 struct rpi_firmware_property_tag_header tag2;
65 u32 xres_virtual, yres_virtual;
66 struct rpi_firmware_property_tag_header tag3;
67 u32 bpp;
68 struct rpi_firmware_property_tag_header tag4;
69 u32 xoffset, yoffset;
70 struct rpi_firmware_property_tag_header tag5;
71 u32 base, screen_size;
72 struct rpi_firmware_property_tag_header tag6;
73 u32 pitch;
74 };
75
76 struct bcm2708_fb_stats {
77 struct debugfs_regset32 regset;
78 u32 dma_copies;
79 u32 dma_irqs;
80 };
81
82 struct bcm2708_fb {
83 struct fb_info fb;
84 struct platform_device *dev;
85 struct rpi_firmware *fw;
86 u32 cmap[16];
87 u32 gpu_cmap[256];
88 int dma_chan;
89 int dma_irq;
90 void __iomem *dma_chan_base;
91 void *cb_base; /* DMA control blocks */
92 dma_addr_t cb_handle;
93 struct dentry *debugfs_dir;
94 wait_queue_head_t dma_waitq;
95 struct bcm2708_fb_stats stats;
96 unsigned long fb_bus_address;
97 };
98
99 #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
100
101 static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
102 {
103 debugfs_remove_recursive(fb->debugfs_dir);
104 fb->debugfs_dir = NULL;
105 }
106
107 static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
108 {
109 static struct debugfs_reg32 stats_registers[] = {
110 {
111 "dma_copies",
112 offsetof(struct bcm2708_fb_stats, dma_copies)
113 },
114 {
115 "dma_irqs",
116 offsetof(struct bcm2708_fb_stats, dma_irqs)
117 },
118 };
119
120 fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
121 if (!fb->debugfs_dir) {
122 pr_warn("%s: could not create debugfs entry\n",
123 __func__);
124 return -EFAULT;
125 }
126
127 fb->stats.regset.regs = stats_registers;
128 fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
129 fb->stats.regset.base = &fb->stats;
130
131 if (!debugfs_create_regset32(
132 "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) {
133 pr_warn("%s: could not create statistics registers\n",
134 __func__);
135 goto fail;
136 }
137 return 0;
138
139 fail:
140 bcm2708_fb_debugfs_deinit(fb);
141 return -EFAULT;
142 }
143
144 static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
145 {
146 int ret = 0;
147
148 memset(&var->transp, 0, sizeof(var->transp));
149
150 var->red.msb_right = 0;
151 var->green.msb_right = 0;
152 var->blue.msb_right = 0;
153
154 switch (var->bits_per_pixel) {
155 case 1:
156 case 2:
157 case 4:
158 case 8:
159 var->red.length = var->bits_per_pixel;
160 var->red.offset = 0;
161 var->green.length = var->bits_per_pixel;
162 var->green.offset = 0;
163 var->blue.length = var->bits_per_pixel;
164 var->blue.offset = 0;
165 break;
166 case 16:
167 var->red.length = 5;
168 var->blue.length = 5;
169 /*
170 * Green length can be 5 or 6 depending whether
171 * we're operating in RGB555 or RGB565 mode.
172 */
173 if (var->green.length != 5 && var->green.length != 6)
174 var->green.length = 6;
175 break;
176 case 24:
177 var->red.length = 8;
178 var->blue.length = 8;
179 var->green.length = 8;
180 break;
181 case 32:
182 var->red.length = 8;
183 var->green.length = 8;
184 var->blue.length = 8;
185 var->transp.length = 8;
186 break;
187 default:
188 ret = -EINVAL;
189 break;
190 }
191
192 /*
193 * >= 16bpp displays have separate colour component bitfields
194 * encoded in the pixel data. Calculate their position from
195 * the bitfield length defined above.
196 */
197 if (ret == 0 && var->bits_per_pixel >= 24 && fbswap) {
198 var->blue.offset = 0;
199 var->green.offset = var->blue.offset + var->blue.length;
200 var->red.offset = var->green.offset + var->green.length;
201 var->transp.offset = var->red.offset + var->red.length;
202 } else if (ret == 0 && var->bits_per_pixel >= 24) {
203 var->red.offset = 0;
204 var->green.offset = var->red.offset + var->red.length;
205 var->blue.offset = var->green.offset + var->green.length;
206 var->transp.offset = var->blue.offset + var->blue.length;
207 } else if (ret == 0 && var->bits_per_pixel >= 16) {
208 var->blue.offset = 0;
209 var->green.offset = var->blue.offset + var->blue.length;
210 var->red.offset = var->green.offset + var->green.length;
211 var->transp.offset = var->red.offset + var->red.length;
212 }
213
214 return ret;
215 }
216
217 static int bcm2708_fb_check_var(struct fb_var_screeninfo *var,
218 struct fb_info *info)
219 {
220 /* info input, var output */
221 print_debug("bcm2708_fb_check_var info(%p) %dx%d (%dx%d), %d, %d\n", info,
222 info->var.xres, info->var.yres, info->var.xres_virtual,
223 info->var.yres_virtual, (int)info->screen_size,
224 info->var.bits_per_pixel);
225 print_debug("bcm2708_fb_check_var var(%p) %dx%d (%dx%d), %d\n", var,
226 var->xres, var->yres, var->xres_virtual, var->yres_virtual,
227 var->bits_per_pixel);
228
229 if (!var->bits_per_pixel)
230 var->bits_per_pixel = 16;
231
232 if (bcm2708_fb_set_bitfields(var) != 0) {
233 pr_err("bcm2708_fb_check_var: invalid bits_per_pixel %d\n",
234 var->bits_per_pixel);
235 return -EINVAL;
236 }
237
238
239 if (var->xres_virtual < var->xres)
240 var->xres_virtual = var->xres;
241 /* use highest possible virtual resolution */
242 if (var->yres_virtual == -1) {
243 var->yres_virtual = 480;
244
245 pr_err
246 ("bcm2708_fb_check_var: virtual resolution set to maximum of %dx%d\n",
247 var->xres_virtual, var->yres_virtual);
248 }
249 if (var->yres_virtual < var->yres)
250 var->yres_virtual = var->yres;
251
252 if (var->xoffset < 0)
253 var->xoffset = 0;
254 if (var->yoffset < 0)
255 var->yoffset = 0;
256
257 /* truncate xoffset and yoffset to maximum if too high */
258 if (var->xoffset > var->xres_virtual - var->xres)
259 var->xoffset = var->xres_virtual - var->xres - 1;
260 if (var->yoffset > var->yres_virtual - var->yres)
261 var->yoffset = var->yres_virtual - var->yres - 1;
262
263 return 0;
264 }
265
266 static int bcm2708_fb_set_par(struct fb_info *info)
267 {
268 struct bcm2708_fb *fb = to_bcm2708(info);
269 struct fb_alloc_tags fbinfo = {
270 .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
271 8, 0, },
272 .xres = info->var.xres,
273 .yres = info->var.yres,
274 .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
275 8, 0, },
276 .xres_virtual = info->var.xres_virtual,
277 .yres_virtual = info->var.yres_virtual,
278 .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
279 .bpp = info->var.bits_per_pixel,
280 .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
281 .xoffset = info->var.xoffset,
282 .yoffset = info->var.yoffset,
283 .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
284 .base = 0,
285 .screen_size = 0,
286 .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
287 .pitch = 0,
288 };
289 int ret;
290
291 print_debug("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info,
292 info->var.xres, info->var.yres, info->var.xres_virtual,
293 info->var.yres_virtual, (int)info->screen_size,
294 info->var.bits_per_pixel);
295
296 ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
297 if (ret) {
298 dev_err(info->device,
299 "Failed to allocate GPU framebuffer (%d)\n", ret);
300 return ret;
301 }
302
303 if (info->var.bits_per_pixel <= 8)
304 fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
305 else
306 fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
307
308 fb->fb.fix.line_length = fbinfo.pitch;
309 fbinfo.base |= 0x40000000;
310 fb->fb_bus_address = fbinfo.base;
311 fbinfo.base &= ~0xc0000000;
312 fb->fb.fix.smem_start = fbinfo.base;
313 fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
314 fb->fb.screen_size = fbinfo.screen_size;
315 if (fb->fb.screen_base)
316 iounmap(fb->fb.screen_base);
317 fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
318 if (!fb->fb.screen_base) {
319 /* the console may currently be locked */
320 console_trylock();
321 console_unlock();
322 dev_err(info->device, "Failed to set screen_base\n");
323 return -ENOMEM;
324 }
325
326 print_debug
327 ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
328 (void *)fb->fb.screen_base, (void *)fb->fb_bus_address,
329 fbinfo.xres, fbinfo.yres, fbinfo.bpp,
330 fbinfo.pitch, (int)fb->fb.screen_size);
331
332 return 0;
333 }
334
335 static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
336 {
337 unsigned int mask = (1 << bf->length) - 1;
338
339 return (val >> (16 - bf->length) & mask) << bf->offset;
340 }
341
342
343 static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
344 unsigned int green, unsigned int blue,
345 unsigned int transp, struct fb_info *info)
346 {
347 struct bcm2708_fb *fb = to_bcm2708(info);
348
349 /*print_debug("BCM2708FB: setcolreg %d:(%02x,%02x,%02x,%02x) %x\n", regno, red, green, blue, transp, fb->fb.fix.visual);*/
350 if (fb->fb.var.bits_per_pixel <= 8) {
351 if (regno < 256) {
352 /* blue [23:16], green [15:8], red [7:0] */
353 fb->gpu_cmap[regno] = ((red >> 8) & 0xff) << 0 |
354 ((green >> 8) & 0xff) << 8 |
355 ((blue >> 8) & 0xff) << 16;
356 }
357 /* 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 */
358 /* So just call it for what looks like the last colour in a list for now. */
359 if (regno == 15 || regno == 255) {
360 struct packet {
361 u32 offset;
362 u32 length;
363 u32 cmap[256];
364 } *packet;
365 int ret;
366
367 packet = kmalloc(sizeof(*packet), GFP_KERNEL);
368 if (!packet)
369 return -ENOMEM;
370 packet->offset = 0;
371 packet->length = regno + 1;
372 memcpy(packet->cmap, fb->gpu_cmap, sizeof(packet->cmap));
373 ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
374 packet, (2 + packet->length) * sizeof(u32));
375 if (ret || packet->offset)
376 dev_err(info->device, "Failed to set palette (%d,%u)\n",
377 ret, packet->offset);
378 kfree(packet);
379 }
380 } else if (regno < 16) {
381 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
382 convert_bitfield(blue, &fb->fb.var.blue) |
383 convert_bitfield(green, &fb->fb.var.green) |
384 convert_bitfield(red, &fb->fb.var.red);
385 }
386 return regno > 255;
387 }
388
389 static int bcm2708_fb_blank(int blank_mode, struct fb_info *info)
390 {
391 struct bcm2708_fb *fb = to_bcm2708(info);
392 u32 value;
393 int ret;
394
395 switch (blank_mode) {
396 case FB_BLANK_UNBLANK:
397 value = 0;
398 break;
399 case FB_BLANK_NORMAL:
400 case FB_BLANK_VSYNC_SUSPEND:
401 case FB_BLANK_HSYNC_SUSPEND:
402 case FB_BLANK_POWERDOWN:
403 value = 1;
404 break;
405 default:
406 return -EINVAL;
407 }
408
409 ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
410 &value, sizeof(value));
411 if (ret)
412 dev_err(info->device, "bcm2708_fb_blank(%d) failed: %d\n",
413 blank_mode, ret);
414
415 return ret;
416 }
417
418 static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
419 {
420 s32 result;
421 info->var.xoffset = var->xoffset;
422 info->var.yoffset = var->yoffset;
423 result = bcm2708_fb_set_par(info);
424 if (result != 0)
425 pr_err("bcm2708_fb_pan_display(%d,%d) returns=%d\n", var->xoffset, var->yoffset, result);
426 return result;
427 }
428
429 static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
430 {
431 struct bcm2708_fb *fb = to_bcm2708(info);
432 u32 dummy = 0;
433 int ret;
434
435 switch (cmd) {
436 case FBIO_WAITFORVSYNC:
437 ret = rpi_firmware_property(fb->fw,
438 RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
439 &dummy, sizeof(dummy));
440 break;
441 default:
442 dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd);
443 return -ENOTTY;
444 }
445
446 if (ret)
447 dev_err(info->device, "ioctl 0x%x failed (%d)\n", cmd, ret);
448
449 return ret;
450 }
451 static void bcm2708_fb_fillrect(struct fb_info *info,
452 const struct fb_fillrect *rect)
453 {
454 /* (is called) print_debug("bcm2708_fb_fillrect\n"); */
455 cfb_fillrect(info, rect);
456 }
457
458 /* A helper function for configuring dma control block */
459 static void set_dma_cb(struct bcm2708_dma_cb *cb,
460 int burst_size,
461 dma_addr_t dst,
462 int dst_stride,
463 dma_addr_t src,
464 int src_stride,
465 int w,
466 int h)
467 {
468 cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
469 BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
470 BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
471 cb->dst = dst;
472 cb->src = src;
473 /*
474 * This is not really obvious from the DMA documentation,
475 * but the top 16 bits must be programmmed to "height -1"
476 * and not "height" in 2D mode.
477 */
478 cb->length = ((h - 1) << 16) | w;
479 cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w);
480 cb->pad[0] = 0;
481 cb->pad[1] = 0;
482 }
483
484 static void bcm2708_fb_copyarea(struct fb_info *info,
485 const struct fb_copyarea *region)
486 {
487 struct bcm2708_fb *fb = to_bcm2708(info);
488 struct bcm2708_dma_cb *cb = fb->cb_base;
489 int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
490 /* Channel 0 supports larger bursts and is a bit faster */
491 int burst_size = (fb->dma_chan == 0) ? 8 : 2;
492 int pixels = region->width * region->height;
493
494 /* Fallback to cfb_copyarea() if we don't like something */
495 if (in_atomic() ||
496 bytes_per_pixel > 4 ||
497 info->var.xres * info->var.yres > 1920 * 1200 ||
498 region->width <= 0 || region->width > info->var.xres ||
499 region->height <= 0 || region->height > info->var.yres ||
500 region->sx < 0 || region->sx >= info->var.xres ||
501 region->sy < 0 || region->sy >= info->var.yres ||
502 region->dx < 0 || region->dx >= info->var.xres ||
503 region->dy < 0 || region->dy >= info->var.yres ||
504 region->sx + region->width > info->var.xres ||
505 region->dx + region->width > info->var.xres ||
506 region->sy + region->height > info->var.yres ||
507 region->dy + region->height > info->var.yres) {
508 cfb_copyarea(info, region);
509 return;
510 }
511
512 if (region->dy == region->sy && region->dx > region->sx) {
513 /*
514 * A difficult case of overlapped copy. Because DMA can't
515 * copy individual scanlines in backwards direction, we need
516 * two-pass processing. We do it by programming a chain of dma
517 * control blocks in the first 16K part of the buffer and use
518 * the remaining 48K as the intermediate temporary scratch
519 * buffer. The buffer size is sufficient to handle up to
520 * 1920x1200 resolution at 32bpp pixel depth.
521 */
522 int y;
523 dma_addr_t control_block_pa = fb->cb_handle;
524 dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
525 int scanline_size = bytes_per_pixel * region->width;
526 int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
527
528 for (y = 0; y < region->height; y += scanlines_per_cb) {
529 dma_addr_t src =
530 fb->fb_bus_address +
531 bytes_per_pixel * region->sx +
532 (region->sy + y) * fb->fb.fix.line_length;
533 dma_addr_t dst =
534 fb->fb_bus_address +
535 bytes_per_pixel * region->dx +
536 (region->dy + y) * fb->fb.fix.line_length;
537
538 if (region->height - y < scanlines_per_cb)
539 scanlines_per_cb = region->height - y;
540
541 set_dma_cb(cb, burst_size, scratchbuf, scanline_size,
542 src, fb->fb.fix.line_length,
543 scanline_size, scanlines_per_cb);
544 control_block_pa += sizeof(struct bcm2708_dma_cb);
545 cb->next = control_block_pa;
546 cb++;
547
548 set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length,
549 scratchbuf, scanline_size,
550 scanline_size, scanlines_per_cb);
551 control_block_pa += sizeof(struct bcm2708_dma_cb);
552 cb->next = control_block_pa;
553 cb++;
554 }
555 /* move the pointer back to the last dma control block */
556 cb--;
557 } else {
558 /* A single dma control block is enough. */
559 int sy, dy, stride;
560 if (region->dy <= region->sy) {
561 /* processing from top to bottom */
562 dy = region->dy;
563 sy = region->sy;
564 stride = fb->fb.fix.line_length;
565 } else {
566 /* processing from bottom to top */
567 dy = region->dy + region->height - 1;
568 sy = region->sy + region->height - 1;
569 stride = -fb->fb.fix.line_length;
570 }
571 set_dma_cb(cb, burst_size,
572 fb->fb_bus_address + dy * fb->fb.fix.line_length +
573 bytes_per_pixel * region->dx,
574 stride,
575 fb->fb_bus_address + sy * fb->fb.fix.line_length +
576 bytes_per_pixel * region->sx,
577 stride,
578 region->width * bytes_per_pixel,
579 region->height);
580 }
581
582 /* end of dma control blocks chain */
583 cb->next = 0;
584
585
586 if (pixels < dma_busy_wait_threshold) {
587 bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
588 bcm_dma_wait_idle(fb->dma_chan_base);
589 } else {
590 void __iomem *dma_chan = fb->dma_chan_base;
591 cb->info |= BCM2708_DMA_INT_EN;
592 bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
593 while (bcm_dma_is_busy(dma_chan)) {
594 wait_event_interruptible(
595 fb->dma_waitq,
596 !bcm_dma_is_busy(dma_chan));
597 }
598 fb->stats.dma_irqs++;
599 }
600 fb->stats.dma_copies++;
601 }
602
603 static void bcm2708_fb_imageblit(struct fb_info *info,
604 const struct fb_image *image)
605 {
606 /* (is called) print_debug("bcm2708_fb_imageblit\n"); */
607 cfb_imageblit(info, image);
608 }
609
610 static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
611 {
612 struct bcm2708_fb *fb = cxt;
613
614 /* FIXME: should read status register to check if this is
615 * actually interrupting us or not, in case this interrupt
616 * ever becomes shared amongst several DMA channels
617 *
618 * readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_IRQ;
619 */
620
621 /* acknowledge the interrupt */
622 writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS);
623
624 wake_up(&fb->dma_waitq);
625 return IRQ_HANDLED;
626 }
627
628 static struct fb_ops bcm2708_fb_ops = {
629 .owner = THIS_MODULE,
630 .fb_check_var = bcm2708_fb_check_var,
631 .fb_set_par = bcm2708_fb_set_par,
632 .fb_setcolreg = bcm2708_fb_setcolreg,
633 .fb_blank = bcm2708_fb_blank,
634 .fb_fillrect = bcm2708_fb_fillrect,
635 .fb_copyarea = bcm2708_fb_copyarea,
636 .fb_imageblit = bcm2708_fb_imageblit,
637 .fb_pan_display = bcm2708_fb_pan_display,
638 .fb_ioctl = bcm2708_ioctl,
639 };
640
641 static int bcm2708_fb_register(struct bcm2708_fb *fb)
642 {
643 int ret;
644
645 fb->fb.fbops = &bcm2708_fb_ops;
646 fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA;
647 fb->fb.pseudo_palette = fb->cmap;
648
649 strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id));
650 fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
651 fb->fb.fix.type_aux = 0;
652 fb->fb.fix.xpanstep = 1;
653 fb->fb.fix.ypanstep = 1;
654 fb->fb.fix.ywrapstep = 0;
655 fb->fb.fix.accel = FB_ACCEL_NONE;
656
657 fb->fb.var.xres = fbwidth;
658 fb->fb.var.yres = fbheight;
659 fb->fb.var.xres_virtual = fbwidth;
660 fb->fb.var.yres_virtual = fbheight;
661 fb->fb.var.bits_per_pixel = fbdepth;
662 fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
663 fb->fb.var.activate = FB_ACTIVATE_NOW;
664 fb->fb.var.nonstd = 0;
665 fb->fb.var.height = -1; /* height of picture in mm */
666 fb->fb.var.width = -1; /* width of picture in mm */
667 fb->fb.var.accel_flags = 0;
668
669 fb->fb.monspecs.hfmin = 0;
670 fb->fb.monspecs.hfmax = 100000;
671 fb->fb.monspecs.vfmin = 0;
672 fb->fb.monspecs.vfmax = 400;
673 fb->fb.monspecs.dclkmin = 1000000;
674 fb->fb.monspecs.dclkmax = 100000000;
675
676 bcm2708_fb_set_bitfields(&fb->fb.var);
677 init_waitqueue_head(&fb->dma_waitq);
678
679 /*
680 * Allocate colourmap.
681 */
682
683 fb_set_var(&fb->fb, &fb->fb.var);
684 ret = bcm2708_fb_set_par(&fb->fb);
685 if (ret)
686 return ret;
687
688 print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth,
689 fbheight, fbdepth, fbswap);
690
691 ret = register_framebuffer(&fb->fb);
692 print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
693 if (ret == 0)
694 goto out;
695
696 print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret);
697 out:
698 return ret;
699 }
700
701 static int bcm2708_fb_probe(struct platform_device *dev)
702 {
703 struct device_node *fw_np;
704 struct rpi_firmware *fw;
705 struct bcm2708_fb *fb;
706 int ret;
707
708 fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0);
709 /* Remove comment when booting without Device Tree is no longer supported
710 if (!fw_np) {
711 dev_err(&dev->dev, "Missing firmware node\n");
712 return -ENOENT;
713 }
714 */
715 fw = rpi_firmware_get(fw_np);
716 if (!fw)
717 return -EPROBE_DEFER;
718
719 fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
720 if (!fb) {
721 dev_err(&dev->dev,
722 "could not allocate new bcm2708_fb struct\n");
723 ret = -ENOMEM;
724 goto free_region;
725 }
726
727 fb->fw = fw;
728 bcm2708_fb_debugfs_init(fb);
729
730 fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
731 &fb->cb_handle, GFP_KERNEL);
732 if (!fb->cb_base) {
733 dev_err(&dev->dev, "cannot allocate DMA CBs\n");
734 ret = -ENOMEM;
735 goto free_fb;
736 }
737
738 pr_info("BCM2708FB: allocated DMA memory %08x\n",
739 fb->cb_handle);
740
741 ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
742 &fb->dma_chan_base, &fb->dma_irq);
743 if (ret < 0) {
744 dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
745 goto free_cb;
746 }
747 fb->dma_chan = ret;
748
749 ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq,
750 0, "bcm2708_fb dma", fb);
751 if (ret) {
752 pr_err("%s: failed to request DMA irq\n", __func__);
753 goto free_dma_chan;
754 }
755
756
757 pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
758 fb->dma_chan, fb->dma_chan_base);
759
760 fb->dev = dev;
761 fb->fb.device = &dev->dev;
762
763 ret = bcm2708_fb_register(fb);
764 if (ret == 0) {
765 platform_set_drvdata(dev, fb);
766 goto out;
767 }
768
769 free_dma_chan:
770 bcm_dma_chan_free(fb->dma_chan);
771 free_cb:
772 dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
773 free_fb:
774 kfree(fb);
775 free_region:
776 dev_err(&dev->dev, "probe failed, err %d\n", ret);
777 out:
778 return ret;
779 }
780
781 static int bcm2708_fb_remove(struct platform_device *dev)
782 {
783 struct bcm2708_fb *fb = platform_get_drvdata(dev);
784
785 platform_set_drvdata(dev, NULL);
786
787 if (fb->fb.screen_base)
788 iounmap(fb->fb.screen_base);
789 unregister_framebuffer(&fb->fb);
790
791 dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
792 bcm_dma_chan_free(fb->dma_chan);
793
794 bcm2708_fb_debugfs_deinit(fb);
795
796 free_irq(fb->dma_irq, fb);
797
798 kfree(fb);
799
800 return 0;
801 }
802
803 static const struct of_device_id bcm2708_fb_of_match_table[] = {
804 { .compatible = "brcm,bcm2708-fb", },
805 {},
806 };
807 MODULE_DEVICE_TABLE(of, bcm2708_fb_of_match_table);
808
809 static struct platform_driver bcm2708_fb_driver = {
810 .probe = bcm2708_fb_probe,
811 .remove = bcm2708_fb_remove,
812 .driver = {
813 .name = DRIVER_NAME,
814 .owner = THIS_MODULE,
815 .of_match_table = bcm2708_fb_of_match_table,
816 },
817 };
818
819 static int __init bcm2708_fb_init(void)
820 {
821 return platform_driver_register(&bcm2708_fb_driver);
822 }
823
824 module_init(bcm2708_fb_init);
825
826 static void __exit bcm2708_fb_exit(void)
827 {
828 platform_driver_unregister(&bcm2708_fb_driver);
829 }
830
831 module_exit(bcm2708_fb_exit);
832
833 module_param(fbwidth, int, 0644);
834 module_param(fbheight, int, 0644);
835 module_param(fbdepth, int, 0644);
836 module_param(fbswap, int, 0644);
837
838 MODULE_DESCRIPTION("BCM2708 framebuffer driver");
839 MODULE_LICENSE("GPL");
840
841 MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer");
842 MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer");
843 MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer");
844 MODULE_PARM_DESC(fbswap, "Swap order of red and blue in 24 and 32 bit modes");