blob: 9b5b21ab136ffa963edf653cb09ac3c10e8001b2 [file] [log] [blame]
Liviu Dudaucaf003f2012-01-18 16:52:04 +00001/*
2 * drivers/video/arm-hdlcd.c
3 *
4 * Copyright (C) 2011 ARM Limited
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 * ARM HDLCD Controller
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/ctype.h>
18#include <linux/mm.h>
19#include <linux/delay.h>
20#include <linux/of.h>
21#include <linux/fb.h>
22#include <linux/clk.h>
23#include <linux/init.h>
24#include <linux/ioport.h>
25#include <linux/dma-mapping.h>
26#include <linux/platform_device.h>
27#include <linux/memblock.h>
28#include <linux/arm-hdlcd.h>
29
30#include "edid.h"
31
Liviu Dudaucaf003f2012-01-18 16:52:04 +000032/* set the DVI output mode using the firmware */
Jon Medhurst51f19112012-07-13 13:32:48 +010033extern int set_dvi_mode(int mode);
34
35#ifdef CONFIG_SERIAL_AMBA_PCU_UART
Liviu Dudaucaf003f2012-01-18 16:52:04 +000036int get_edid(u8 *msgbuf);
Jon Medhurst51f19112012-07-13 13:32:48 +010037#else
Liviu Dudaucaf003f2012-01-18 16:52:04 +000038#endif
39
40#define to_hdlcd_device(info) container_of(info, struct hdlcd_device, fb)
41
42static struct of_device_id hdlcd_of_matches[] = {
43 { .compatible = "arm,hdlcd" },
44 {},
45};
46
47/* Framebuffer size. */
48static unsigned long framebuffer_size;
49
50static char *fb_mode = "1680x1050-32@60\0\0\0\0\0";
51
52static struct fb_var_screeninfo cached_var_screeninfo;
53
54static struct fb_videomode hdlcd_default_mode = {
55 .refresh = 60,
56 .xres = 1680,
57 .yres = 1050,
58 .pixclock = 8403,
59 .left_margin = 80,
60 .right_margin = 48,
61 .upper_margin = 21,
62 .lower_margin = 3,
63 .hsync_len = 32,
64 .vsync_len = 6,
65 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
66 .vmode = FB_VMODE_NONINTERLACED
67};
68
69
70static inline void hdlcd_enable(struct hdlcd_device *hdlcd)
71{
72 dev_dbg(hdlcd->dev, "HDLCD: output enabled\n");
73 writel(1, hdlcd->base + HDLCD_REG_COMMAND);
74}
75
76static inline void hdlcd_disable(struct hdlcd_device *hdlcd)
77{
78 dev_dbg(hdlcd->dev, "HDLCD: output disabled\n");
79 writel(0, hdlcd->base + HDLCD_REG_COMMAND);
80}
81
82static int hdlcd_set_bitfields(struct hdlcd_device *hdlcd,
83 struct fb_var_screeninfo *var)
84{
85 int ret = 0;
86
87 memset(&var->transp, 0, sizeof(var->transp));
88 var->red.msb_right = 0;
89 var->green.msb_right = 0;
90 var->blue.msb_right = 0;
91 var->blue.offset = 0;
92
93 switch (var->bits_per_pixel) {
94 case 8:
95 /* pseudocolor */
96 var->red.length = 8;
97 var->green.length = 8;
98 var->blue.length = 8;
99 break;
100 case 16:
101 /* 565 format */
102 var->red.length = 5;
103 var->green.length = 6;
104 var->blue.length = 5;
105 break;
106 case 32:
107 var->transp.length = 8;
108 case 24:
109 var->red.length = 8;
110 var->green.length = 8;
111 var->blue.length = 8;
112 break;
113 default:
114 ret = -EINVAL;
115 break;
116 }
117
118 if (!ret) {
Chris Redpath58561732012-06-29 13:10:35 +0100119 if(var->bits_per_pixel != 32)
120 {
121 var->green.offset = var->blue.length;
122 var->red.offset = var->green.offset + var->green.length;
123 }
124 else
125 {
126 /* Previously, the byte ordering for 32-bit color was
127 * (msb)<alpha><red><green><blue>(lsb)
128 * but this does not match what android expects and
129 * the colors are odd. Instead, use
130 * <alpha><blue><green><red>
131 * Since we tell fb what we are doing, console
132 * , X and directfb access should work fine.
133 */
134 var->green.offset = var->red.length;
135 var->blue.offset = var->green.offset + var->green.length;
136 var->transp.offset = var->blue.offset + var->blue.length;
137 }
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000138 }
139
140 return ret;
141}
142
143static int hdlcd_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
144{
145 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
146 int bytes_per_pixel = var->bits_per_pixel / 8;
147
148 var->yres_virtual = 2 * var->yres;
149
150 if ((var->xres_virtual * bytes_per_pixel * var->yres_virtual) > hdlcd->fb.fix.smem_len)
151 return -ENOMEM;
152
153 if (var->xres > HDLCD_MAX_XRES || var->yres > HDLCD_MAX_YRES)
154 return -EINVAL;
155
156 /* make sure the bitfields are set appropriately */
157 return hdlcd_set_bitfields(hdlcd, var);
158}
159
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000160static int hdlcd_set_output_mode(int xres, int yres)
161{
Jon Medhurst51f19112012-07-13 13:32:48 +0100162 /* some firmware uses some stupid protocol: 5 bytes (only byte 1 used)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000163 to send 3 bits of information (value between 0 - 5) */
164 u8 msgbuffer[5];
165
166 memset(msgbuffer, 0, sizeof(msgbuffer));
Jon Medhurst51f19112012-07-13 13:32:48 +0100167
168 if (xres < 800 && yres < 600)
169 msgbuffer[0] = 0; /* default resolution: 640 x 480 */
170 else if (xres < 1024 && yres < 768)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000171 msgbuffer[0] = 1; /* SVGA: 800 * 600 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100172 else if (xres < 1280 && yres < 1024)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000173 msgbuffer[0] = 2; /* XGA: 1024 * 768 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100174 else if (xres < 1600 && yres < 1200)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000175 msgbuffer[0] = 3; /* SXGA: 1280 * 1024 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100176 else if (xres < 1920 && yres <= 1200)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000177 msgbuffer[0] = 4; /* UXGA: 1600 * 1200 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100178 else
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000179 msgbuffer[0] = 5; /* WUXGA: 1920 * 1200 */
180
Jon Medhurst51f19112012-07-13 13:32:48 +0100181 return set_dvi_mode(msgbuffer[0]);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000182}
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000183
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100184
185/* prototype */
186static int hdlcd_pan_display(struct fb_var_screeninfo *var,
187 struct fb_info *info);
188
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000189#define WRITE_HDLCD_REG(reg, value) writel((value), hdlcd->base + (reg))
190#define READ_HDLCD_REG(reg) readl(hdlcd->base + (reg))
191
192static int hdlcd_set_par(struct fb_info *info)
193{
194 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
195 int bytes_per_pixel = hdlcd->fb.var.bits_per_pixel / 8;
196 int polarities;
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100197 int old_yoffset;
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000198
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100199 /* check for shortcuts */
200 old_yoffset = cached_var_screeninfo.yoffset;
201 cached_var_screeninfo.yoffset = info->var.yoffset;
202 if (!memcmp(&info->var, &cached_var_screeninfo,
203 sizeof(struct fb_var_screeninfo))) {
204 if(old_yoffset != info->var.yoffset) {
205 /* we only changed yoffset */
206 hdlcd_pan_display(&info->var, info);
207 memcpy(&cached_var_screeninfo, &info->var,
208 sizeof(struct fb_var_screeninfo));
209 }
210 /* or no change */
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000211 return 0;
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100212 }
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000213
214 hdlcd->fb.fix.line_length = hdlcd->fb.var.xres * bytes_per_pixel;
215
216 if (hdlcd->fb.var.bits_per_pixel >= 16)
217 hdlcd->fb.fix.visual = FB_VISUAL_TRUECOLOR;
218 else
219 hdlcd->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
220
221 memcpy(&cached_var_screeninfo, &info->var, sizeof(struct fb_var_screeninfo));
222
223 polarities = HDLCD_POLARITY_DATAEN |
224#ifndef CONFIG_ARCH_TUSCAN
225 HDLCD_POLARITY_PIXELCLK |
226#endif
227 HDLCD_POLARITY_DATA;
228 polarities |= (hdlcd->fb.var.sync & FB_SYNC_HOR_HIGH_ACT) ? HDLCD_POLARITY_HSYNC : 0;
229 polarities |= (hdlcd->fb.var.sync & FB_SYNC_VERT_HIGH_ACT) ? HDLCD_POLARITY_VSYNC : 0;
230
231 hdlcd_disable(hdlcd);
232
233 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_LENGTH, hdlcd->fb.var.xres * bytes_per_pixel);
234 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_PITCH, hdlcd->fb.var.xres * bytes_per_pixel);
235 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_COUNT, hdlcd->fb.var.yres - 1);
236 WRITE_HDLCD_REG(HDLCD_REG_V_SYNC, hdlcd->fb.var.vsync_len - 1);
237 WRITE_HDLCD_REG(HDLCD_REG_V_BACK_PORCH, hdlcd->fb.var.upper_margin - 1);
238 WRITE_HDLCD_REG(HDLCD_REG_V_DATA, hdlcd->fb.var.yres - 1);
239 WRITE_HDLCD_REG(HDLCD_REG_V_FRONT_PORCH, hdlcd->fb.var.lower_margin - 1);
240 WRITE_HDLCD_REG(HDLCD_REG_H_SYNC, hdlcd->fb.var.hsync_len - 1);
241 WRITE_HDLCD_REG(HDLCD_REG_H_BACK_PORCH, hdlcd->fb.var.left_margin - 1);
242 WRITE_HDLCD_REG(HDLCD_REG_H_DATA, hdlcd->fb.var.xres - 1);
243 WRITE_HDLCD_REG(HDLCD_REG_H_FRONT_PORCH, hdlcd->fb.var.right_margin - 1);
244 WRITE_HDLCD_REG(HDLCD_REG_POLARITIES, polarities);
245 WRITE_HDLCD_REG(HDLCD_REG_PIXEL_FORMAT, (bytes_per_pixel - 1) << 3);
246 WRITE_HDLCD_REG(HDLCD_REG_RED_SELECT, ((hdlcd->fb.var.red.length & 0xf) << 8) | hdlcd->fb.var.red.offset);
247 WRITE_HDLCD_REG(HDLCD_REG_GREEN_SELECT, ((hdlcd->fb.var.green.length & 0xf) << 8) | hdlcd->fb.var.green.offset);
248 WRITE_HDLCD_REG(HDLCD_REG_BLUE_SELECT, ((hdlcd->fb.var.blue.length & 0xf) << 8) | hdlcd->fb.var.blue.offset);
249
250 hdlcd_set_output_mode(hdlcd->fb.var.xres, hdlcd->fb.var.yres);
251
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100252 clk_prepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000253 clk_set_rate(hdlcd->clk, (1000000000 / hdlcd->fb.var.pixclock) * 1000);
254 clk_enable(hdlcd->clk);
255
256 hdlcd_enable(hdlcd);
257
258 return 0;
259}
260
261static int hdlcd_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
262 unsigned int blue, unsigned int transp, struct fb_info *info)
263{
264 if (regno < 16) {
265 u32 *pal = info->pseudo_palette;
266
267 pal[regno] = ((red >> 8) << info->var.red.offset) |
268 ((green >> 8) << info->var.green.offset) |
269 ((blue >> 8) << info->var.blue.offset);
270 }
271
272 return 0;
273}
274
275static irqreturn_t hdlcd_irq(int irq, void *data)
276{
277 struct hdlcd_device *hdlcd = data;
278 unsigned long irq_mask, irq_status;
279
280 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
281 irq_status = READ_HDLCD_REG(HDLCD_REG_INT_STATUS);
282
283 /* acknowledge interrupt(s) */
284 WRITE_HDLCD_REG(HDLCD_REG_INT_CLEAR, irq_status);
285
286 if (irq_status & HDLCD_INTERRUPT_VSYNC) {
287 /* disable future VSYNC interrupts */
288 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask & ~HDLCD_INTERRUPT_VSYNC);
289
290 complete(&hdlcd->vsync_completion);
291 }
292
293 return IRQ_HANDLED;
294}
295
296static int hdlcd_wait_for_vsync(struct fb_info *info)
297{
298 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
299 unsigned long irq_mask;
300 int err;
301
302 /* enable VSYNC interrupt */
303 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
304 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask | HDLCD_INTERRUPT_VSYNC);
305
306 err = wait_for_completion_interruptible_timeout(&hdlcd->vsync_completion,
307 msecs_to_jiffies(100));
308
309 if (!err)
310 return -ETIMEDOUT;
311
312 return 0;
313}
314
315static int hdlcd_blank(int blank_mode, struct fb_info *info)
316{
317 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
318
319 switch (blank_mode) {
320 case FB_BLANK_POWERDOWN:
321 clk_disable(hdlcd->clk);
322 case FB_BLANK_NORMAL:
323 hdlcd_disable(hdlcd);
324 break;
325 case FB_BLANK_UNBLANK:
326 clk_enable(hdlcd->clk);
327 hdlcd_enable(hdlcd);
328 break;
329 case FB_BLANK_VSYNC_SUSPEND:
330 case FB_BLANK_HSYNC_SUSPEND:
331 default:
332 return 1;
333 }
334
335 return 0;
336}
337
338static void hdlcd_mmap_open(struct vm_area_struct *vma)
339{
340}
341
342static void hdlcd_mmap_close(struct vm_area_struct *vma)
343{
344}
345
346static struct vm_operations_struct hdlcd_mmap_ops = {
347 .open = hdlcd_mmap_open,
348 .close = hdlcd_mmap_close,
349};
350
351static int hdlcd_mmap(struct fb_info *info, struct vm_area_struct *vma)
352{
353 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
354 unsigned long off;
355 unsigned long start;
356 unsigned long len = hdlcd->fb.fix.smem_len;
357
358 if (vma->vm_end - vma->vm_start == 0)
359 return 0;
360 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
361 return -EINVAL;
362
363 off = vma->vm_pgoff << PAGE_SHIFT;
364 if ((off >= len) || (vma->vm_end - vma->vm_start + off) > len)
365 return -EINVAL;
366
367 start = hdlcd->fb.fix.smem_start;
368 off += start;
369
370 vma->vm_pgoff = off >> PAGE_SHIFT;
371 vma->vm_flags |= VM_IO;
372 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
373 vma->vm_ops = &hdlcd_mmap_ops;
374 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
375 vma->vm_end - vma->vm_start,
376 vma->vm_page_prot))
377 return -EAGAIN;
378
379 return 0;
380}
381
382static int hdlcd_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
383{
384 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
385
386 hdlcd->fb.var.yoffset = var->yoffset;
387 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start +
388 (var->yoffset * hdlcd->fb.fix.line_length));
389
390 hdlcd_wait_for_vsync(info);
391
392 return 0;
393}
394
395static int hdlcd_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
396{
397 int err;
398
399 switch (cmd) {
400 case FBIO_WAITFORVSYNC:
401 err = hdlcd_wait_for_vsync(info);
402 break;
403 default:
404 err = -ENOIOCTLCMD;
405 break;
406 }
407
408 return err;
409}
410
411static struct fb_ops hdlcd_ops = {
412 .owner = THIS_MODULE,
413 .fb_check_var = hdlcd_check_var,
414 .fb_set_par = hdlcd_set_par,
415 .fb_setcolreg = hdlcd_setcolreg,
416 .fb_blank = hdlcd_blank,
417 .fb_fillrect = cfb_fillrect,
418 .fb_copyarea = cfb_copyarea,
419 .fb_imageblit = cfb_imageblit,
420 .fb_mmap = hdlcd_mmap,
421 .fb_pan_display = hdlcd_pan_display,
422 .fb_ioctl = hdlcd_ioctl,
423 .fb_compat_ioctl = hdlcd_ioctl
424};
425
426static int hdlcd_setup(struct hdlcd_device *hdlcd)
427{
428 u32 version;
429 int err = -EFAULT;
430
431 hdlcd->clk = clk_get(hdlcd->dev, NULL);
432 if (IS_ERR(hdlcd->clk)) {
433 dev_err(hdlcd->dev, "HDLCD: unable to find clock data\n");
434 return PTR_ERR(hdlcd->clk);
435 }
436
437 hdlcd->base = ioremap_nocache(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
438 if (!hdlcd->base) {
439 dev_err(hdlcd->dev, "HDLCD: unable to map registers\n");
440 goto remap_err;
441 }
442
443 hdlcd->fb.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
444 if (!hdlcd->fb.pseudo_palette) {
445 dev_err(hdlcd->dev, "HDLCD: unable to allocate pseudo_palette memory\n");
446 err = -ENOMEM;
447 goto kmalloc_err;
448 }
449
450 version = readl(hdlcd->base + HDLCD_REG_VERSION);
451 if ((version & HDLCD_PRODUCT_MASK) != HDLCD_PRODUCT_ID) {
452 dev_err(hdlcd->dev, "HDLCD: unknown product id: 0x%x\n", version);
453 err = -EINVAL;
454 goto kmalloc_err;
455 }
456 dev_info(hdlcd->dev, "HDLCD: found ARM HDLCD version r%dp%d\n",
457 (version & HDLCD_VERSION_MAJOR_MASK) >> 8,
458 version & HDLCD_VERSION_MINOR_MASK);
459
460 strcpy(hdlcd->fb.fix.id, "hdlcd");
461 hdlcd->fb.fbops = &hdlcd_ops;
462 hdlcd->fb.flags = FBINFO_FLAG_DEFAULT/* | FBINFO_VIRTFB*/;
463
464 hdlcd->fb.fix.type = FB_TYPE_PACKED_PIXELS;
465 hdlcd->fb.fix.type_aux = 0;
466 hdlcd->fb.fix.xpanstep = 0;
467 hdlcd->fb.fix.ypanstep = 1;
468 hdlcd->fb.fix.ywrapstep = 0;
469 hdlcd->fb.fix.accel = FB_ACCEL_NONE;
470
471 hdlcd->fb.var.nonstd = 0;
472 hdlcd->fb.var.activate = FB_ACTIVATE_NOW;
473 hdlcd->fb.var.height = -1;
474 hdlcd->fb.var.width = -1;
475 hdlcd->fb.var.accel_flags = 0;
476
477 init_completion(&hdlcd->vsync_completion);
478
479 if (hdlcd->edid) {
480 /* build modedb from EDID */
481 fb_edid_to_monspecs(hdlcd->edid, &hdlcd->fb.monspecs);
482 fb_videomode_to_modelist(hdlcd->fb.monspecs.modedb,
483 hdlcd->fb.monspecs.modedb_len,
484 &hdlcd->fb.modelist);
485 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode,
486 hdlcd->fb.monspecs.modedb,
487 hdlcd->fb.monspecs.modedb_len,
488 &hdlcd_default_mode, 32);
489 } else {
490 hdlcd->fb.monspecs.hfmin = 0;
491 hdlcd->fb.monspecs.hfmax = 100000;
492 hdlcd->fb.monspecs.vfmin = 0;
493 hdlcd->fb.monspecs.vfmax = 400;
494 hdlcd->fb.monspecs.dclkmin = 1000000;
495 hdlcd->fb.monspecs.dclkmax = 100000000;
496 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode, NULL, 0, &hdlcd_default_mode, 32);
497 }
498
499 dev_info(hdlcd->dev, "using %dx%d-%d@%d mode\n", hdlcd->fb.var.xres,
500 hdlcd->fb.var.yres, hdlcd->fb.var.bits_per_pixel,
501 hdlcd->fb.mode ? hdlcd->fb.mode->refresh : 60);
502 hdlcd->fb.var.xres_virtual = hdlcd->fb.var.xres;
503 hdlcd->fb.var.yres_virtual = hdlcd->fb.var.yres * 2;
504
505 /* initialise and set the palette */
506 if (fb_alloc_cmap(&hdlcd->fb.cmap, NR_PALETTE, 0)) {
507 dev_err(hdlcd->dev, "failed to allocate cmap memory\n");
508 err = -ENOMEM;
509 goto setup_err;
510 }
511 fb_set_cmap(&hdlcd->fb.cmap, &hdlcd->fb);
512
513 /* Allow max number of outstanding requests with the largest beat burst */
514 WRITE_HDLCD_REG(HDLCD_REG_BUS_OPTIONS, HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
515 /* Set the framebuffer base to start of allocated memory */
516 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start);
517 /* Ensure interrupts are disabled */
518 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, 0);
519
520 if (!register_framebuffer(&hdlcd->fb)) {
521 fb_set_var(&hdlcd->fb, &hdlcd->fb.var);
522 clk_enable(hdlcd->clk);
523 return 0;
524 }
525
526 dev_err(hdlcd->dev, "HDLCD: cannot register framebuffer\n");
527
528 fb_dealloc_cmap(&hdlcd->fb.cmap);
529setup_err:
530 iounmap(hdlcd->base);
531kmalloc_err:
532 kfree(hdlcd->fb.pseudo_palette);
533remap_err:
534 clk_put(hdlcd->clk);
535 return err;
536}
537
538static inline unsigned char atohex(u8 data)
539{
540 if (!isxdigit(data))
541 return 0;
542 /* truncate the upper nibble and add 9 to non-digit values */
543 return (data > 0x39) ? ((data & 0xf) + 9) : (data & 0xf);
544}
545
546/* EDID data is passed from devicetree in a literal string that can contain spaces and
547 the hexadecimal dump of the data */
548static int parse_edid_data(struct hdlcd_device *hdlcd, const u8 *edid_data, int data_len)
549{
550 int i, j;
551
552 if (!edid_data)
553 return -EINVAL;
554
555 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
556 if (!hdlcd->edid)
557 return -ENOMEM;
558
559 for (i = 0, j = 0; i < data_len; i++) {
560 if (isspace(edid_data[i]))
561 continue;
562 hdlcd->edid[j++] = atohex(edid_data[i]);
563 if (j >= EDID_LENGTH)
564 break;
565 }
566
567 if (j < EDID_LENGTH) {
568 kfree(hdlcd->edid);
569 hdlcd->edid = NULL;
570 return -EINVAL;
571 }
572
573 return 0;
574}
575
576static int hdlcd_probe(struct platform_device *pdev)
577{
578 int err = 0, i;
579 struct hdlcd_device *hdlcd;
580 struct resource *mem;
581#ifdef CONFIG_OF
582 struct device_node *of_node;
583#endif
584
585 memset(&cached_var_screeninfo, 0, sizeof(struct fb_var_screeninfo));
586
587 dev_dbg(&pdev->dev, "HDLCD: probing\n");
588
589 hdlcd = kzalloc(sizeof(*hdlcd), GFP_KERNEL);
590 if (!hdlcd)
591 return -ENOMEM;
592
593#ifdef CONFIG_OF
594 of_node = pdev->dev.of_node;
595 if (of_node) {
596 int len;
597 const u8 *edid;
Jon Medhurst51f19112012-07-13 13:32:48 +0100598 const __be32 *prop = of_get_property(of_node, "mode", &len);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000599 if (prop)
Jon Medhurst51f19112012-07-13 13:32:48 +0100600 strncpy(fb_mode, (char *)prop, len);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000601 prop = of_get_property(of_node, "framebuffer", &len);
602 if (prop) {
Jon Medhurst51f19112012-07-13 13:32:48 +0100603 hdlcd->fb.fix.smem_start = of_read_ulong(prop,
604 of_n_addr_cells(of_node));
605 prop += of_n_addr_cells(of_node);
606 framebuffer_size = of_read_ulong(prop,
607 of_n_size_cells(of_node));
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000608 if (framebuffer_size > HDLCD_MAX_FRAMEBUFFER_SIZE)
609 framebuffer_size = HDLCD_MAX_FRAMEBUFFER_SIZE;
610 dev_dbg(&pdev->dev, "HDLCD: phys_addr = 0x%lx, size = 0x%lx\n",
611 hdlcd->fb.fix.smem_start, framebuffer_size);
612 }
613 edid = of_get_property(of_node, "edid", &len);
614 if (edid) {
615 err = parse_edid_data(hdlcd, edid, len);
616#ifdef CONFIG_SERIAL_AMBA_PCU_UART
617 } else {
618 /* ask the firmware to fetch the EDID */
619 dev_dbg(&pdev->dev, "HDLCD: Requesting EDID data\n");
620 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
621 if (!hdlcd->edid)
622 return -ENOMEM;
623 err = get_edid(hdlcd->edid);
624#endif /* CONFIG_SERIAL_AMBA_PCU_UART */
625 }
626 if (err)
627 dev_info(&pdev->dev, "HDLCD: Failed to parse EDID data\n");
628 }
629#endif /* CONFIG_OF */
630
631 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
632 if (!mem) {
633 dev_err(&pdev->dev, "HDLCD: cannot get platform resources\n");
634 err = -EINVAL;
635 goto resource_err;
636 }
637
638 i = platform_get_irq(pdev, 0);
639 if (i < 0) {
640 dev_err(&pdev->dev, "HDLCD: no irq defined for vsync\n");
641 err = -ENOENT;
642 goto resource_err;
643 } else {
644 err = request_irq(i, hdlcd_irq, 0, dev_name(&pdev->dev), hdlcd);
645 if (err) {
646 dev_err(&pdev->dev, "HDLCD: unable to request irq\n");
647 goto resource_err;
648 }
649 hdlcd->irq = i;
650 }
651
652 if (!request_mem_region(mem->start, resource_size(mem), dev_name(&pdev->dev))) {
653 err = -ENXIO;
654 goto request_err;
655 }
656
657 if (!hdlcd->fb.fix.smem_start) {
658 dev_err(&pdev->dev, "platform did not allocate frame buffer memory\n");
659 err = -ENOMEM;
660 goto memalloc_err;
661 }
662 hdlcd->fb.screen_base = ioremap_wc(hdlcd->fb.fix.smem_start, framebuffer_size);
663 if (!hdlcd->fb.screen_base) {
664 dev_err(&pdev->dev, "unable to ioremap framebuffer\n");
665 err = -ENOMEM;
666 goto probe_err;
667 }
668
669 hdlcd->fb.screen_size = framebuffer_size;
670 hdlcd->fb.fix.smem_len = framebuffer_size;
671 hdlcd->fb.fix.mmio_start = mem->start;
672 hdlcd->fb.fix.mmio_len = resource_size(mem);
673
674 /* Clear the framebuffer */
675 memset(hdlcd->fb.screen_base, 0, framebuffer_size);
676
677 hdlcd->dev = &pdev->dev;
678
679 dev_dbg(&pdev->dev, "HDLCD: framebuffer virt base %p, phys base 0x%lX\n",
680 hdlcd->fb.screen_base, (unsigned long)hdlcd->fb.fix.smem_start);
681
682 err = hdlcd_setup(hdlcd);
683
684 if (err)
685 goto probe_err;
686
687 platform_set_drvdata(pdev, hdlcd);
688 return 0;
689
690probe_err:
691 iounmap(hdlcd->fb.screen_base);
692 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
693
694memalloc_err:
695 release_mem_region(mem->start, resource_size(mem));
696
697request_err:
698 free_irq(hdlcd->irq, hdlcd);
699
700resource_err:
701 kfree(hdlcd);
702
703 return err;
704}
705
706static int hdlcd_remove(struct platform_device *pdev)
707{
708 struct hdlcd_device *hdlcd = platform_get_drvdata(pdev);
709
710 clk_disable(hdlcd->clk);
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100711 clk_unprepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000712 clk_put(hdlcd->clk);
713
714 /* unmap memory */
715 iounmap(hdlcd->fb.screen_base);
716 iounmap(hdlcd->base);
717
718 /* deallocate fb memory */
719 fb_dealloc_cmap(&hdlcd->fb.cmap);
720 kfree(hdlcd->fb.pseudo_palette);
721 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
722 release_mem_region(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
723
724 free_irq(hdlcd->irq, NULL);
725 kfree(hdlcd);
726
727 return 0;
728}
729
730#ifdef CONFIG_PM
731static int hdlcd_suspend(struct platform_device *pdev, pm_message_t state)
732{
733 /* not implemented yet */
734 return 0;
735}
736
737static int hdlcd_resume(struct platform_device *pdev)
738{
739 /* not implemented yet */
740 return 0;
741}
742#else
743#define hdlcd_suspend NULL
744#define hdlcd_resume NULL
745#endif
746
747static struct platform_driver hdlcd_driver = {
748 .probe = hdlcd_probe,
749 .remove = hdlcd_remove,
750 .suspend = hdlcd_suspend,
751 .resume = hdlcd_resume,
752 .driver = {
753 .name = "hdlcd",
754 .owner = THIS_MODULE,
755 .of_match_table = hdlcd_of_matches,
756 },
757};
758
759static int __init hdlcd_init(void)
760{
761 return platform_driver_register(&hdlcd_driver);
762}
763
764void __exit hdlcd_exit(void)
765{
766 platform_driver_unregister(&hdlcd_driver);
767}
768
769module_init(hdlcd_init);
770module_exit(hdlcd_exit);
771
772MODULE_AUTHOR("Liviu Dudau");
773MODULE_DESCRIPTION("ARM HDLCD core driver");
774MODULE_LICENSE("GPL v2");