blob: 526d771db9911a962ea1103f183c9b8e47357701 [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) {
119 var->green.offset = var->blue.length;
120 var->red.offset = var->green.offset + var->green.length;
121 if (var->bits_per_pixel == 32)
122 var->transp.offset = var->red.offset + var->red.length;
123 }
124
125 return ret;
126}
127
128static int hdlcd_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
129{
130 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
131 int bytes_per_pixel = var->bits_per_pixel / 8;
132
133 var->yres_virtual = 2 * var->yres;
134
135 if ((var->xres_virtual * bytes_per_pixel * var->yres_virtual) > hdlcd->fb.fix.smem_len)
136 return -ENOMEM;
137
138 if (var->xres > HDLCD_MAX_XRES || var->yres > HDLCD_MAX_YRES)
139 return -EINVAL;
140
141 /* make sure the bitfields are set appropriately */
142 return hdlcd_set_bitfields(hdlcd, var);
143}
144
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000145static int hdlcd_set_output_mode(int xres, int yres)
146{
Jon Medhurst51f19112012-07-13 13:32:48 +0100147 /* some firmware uses some stupid protocol: 5 bytes (only byte 1 used)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000148 to send 3 bits of information (value between 0 - 5) */
149 u8 msgbuffer[5];
150
151 memset(msgbuffer, 0, sizeof(msgbuffer));
Jon Medhurst51f19112012-07-13 13:32:48 +0100152
153 if (xres < 800 && yres < 600)
154 msgbuffer[0] = 0; /* default resolution: 640 x 480 */
155 else if (xres < 1024 && yres < 768)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000156 msgbuffer[0] = 1; /* SVGA: 800 * 600 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100157 else if (xres < 1280 && yres < 1024)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000158 msgbuffer[0] = 2; /* XGA: 1024 * 768 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100159 else if (xres < 1600 && yres < 1200)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000160 msgbuffer[0] = 3; /* SXGA: 1280 * 1024 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100161 else if (xres < 1920 && yres <= 1200)
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000162 msgbuffer[0] = 4; /* UXGA: 1600 * 1200 */
Jon Medhurst51f19112012-07-13 13:32:48 +0100163 else
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000164 msgbuffer[0] = 5; /* WUXGA: 1920 * 1200 */
165
Jon Medhurst51f19112012-07-13 13:32:48 +0100166 return set_dvi_mode(msgbuffer[0]);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000167}
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000168
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100169
170/* prototype */
171static int hdlcd_pan_display(struct fb_var_screeninfo *var,
172 struct fb_info *info);
173
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000174#define WRITE_HDLCD_REG(reg, value) writel((value), hdlcd->base + (reg))
175#define READ_HDLCD_REG(reg) readl(hdlcd->base + (reg))
176
177static int hdlcd_set_par(struct fb_info *info)
178{
179 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
180 int bytes_per_pixel = hdlcd->fb.var.bits_per_pixel / 8;
181 int polarities;
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100182 int old_yoffset;
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000183
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100184 /* check for shortcuts */
185 old_yoffset = cached_var_screeninfo.yoffset;
186 cached_var_screeninfo.yoffset = info->var.yoffset;
187 if (!memcmp(&info->var, &cached_var_screeninfo,
188 sizeof(struct fb_var_screeninfo))) {
189 if(old_yoffset != info->var.yoffset) {
190 /* we only changed yoffset */
191 hdlcd_pan_display(&info->var, info);
192 memcpy(&cached_var_screeninfo, &info->var,
193 sizeof(struct fb_var_screeninfo));
194 }
195 /* or no change */
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000196 return 0;
Dietmar Eggemannf03c6632012-06-21 17:16:33 +0100197 }
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000198
199 hdlcd->fb.fix.line_length = hdlcd->fb.var.xres * bytes_per_pixel;
200
201 if (hdlcd->fb.var.bits_per_pixel >= 16)
202 hdlcd->fb.fix.visual = FB_VISUAL_TRUECOLOR;
203 else
204 hdlcd->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
205
206 memcpy(&cached_var_screeninfo, &info->var, sizeof(struct fb_var_screeninfo));
207
208 polarities = HDLCD_POLARITY_DATAEN |
209#ifndef CONFIG_ARCH_TUSCAN
210 HDLCD_POLARITY_PIXELCLK |
211#endif
212 HDLCD_POLARITY_DATA;
213 polarities |= (hdlcd->fb.var.sync & FB_SYNC_HOR_HIGH_ACT) ? HDLCD_POLARITY_HSYNC : 0;
214 polarities |= (hdlcd->fb.var.sync & FB_SYNC_VERT_HIGH_ACT) ? HDLCD_POLARITY_VSYNC : 0;
215
216 hdlcd_disable(hdlcd);
217
218 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_LENGTH, hdlcd->fb.var.xres * bytes_per_pixel);
219 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_PITCH, hdlcd->fb.var.xres * bytes_per_pixel);
220 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_COUNT, hdlcd->fb.var.yres - 1);
221 WRITE_HDLCD_REG(HDLCD_REG_V_SYNC, hdlcd->fb.var.vsync_len - 1);
222 WRITE_HDLCD_REG(HDLCD_REG_V_BACK_PORCH, hdlcd->fb.var.upper_margin - 1);
223 WRITE_HDLCD_REG(HDLCD_REG_V_DATA, hdlcd->fb.var.yres - 1);
224 WRITE_HDLCD_REG(HDLCD_REG_V_FRONT_PORCH, hdlcd->fb.var.lower_margin - 1);
225 WRITE_HDLCD_REG(HDLCD_REG_H_SYNC, hdlcd->fb.var.hsync_len - 1);
226 WRITE_HDLCD_REG(HDLCD_REG_H_BACK_PORCH, hdlcd->fb.var.left_margin - 1);
227 WRITE_HDLCD_REG(HDLCD_REG_H_DATA, hdlcd->fb.var.xres - 1);
228 WRITE_HDLCD_REG(HDLCD_REG_H_FRONT_PORCH, hdlcd->fb.var.right_margin - 1);
229 WRITE_HDLCD_REG(HDLCD_REG_POLARITIES, polarities);
230 WRITE_HDLCD_REG(HDLCD_REG_PIXEL_FORMAT, (bytes_per_pixel - 1) << 3);
231 WRITE_HDLCD_REG(HDLCD_REG_RED_SELECT, ((hdlcd->fb.var.red.length & 0xf) << 8) | hdlcd->fb.var.red.offset);
232 WRITE_HDLCD_REG(HDLCD_REG_GREEN_SELECT, ((hdlcd->fb.var.green.length & 0xf) << 8) | hdlcd->fb.var.green.offset);
233 WRITE_HDLCD_REG(HDLCD_REG_BLUE_SELECT, ((hdlcd->fb.var.blue.length & 0xf) << 8) | hdlcd->fb.var.blue.offset);
234
235 hdlcd_set_output_mode(hdlcd->fb.var.xres, hdlcd->fb.var.yres);
236
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100237 clk_prepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000238 clk_set_rate(hdlcd->clk, (1000000000 / hdlcd->fb.var.pixclock) * 1000);
239 clk_enable(hdlcd->clk);
240
241 hdlcd_enable(hdlcd);
242
243 return 0;
244}
245
246static int hdlcd_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
247 unsigned int blue, unsigned int transp, struct fb_info *info)
248{
249 if (regno < 16) {
250 u32 *pal = info->pseudo_palette;
251
252 pal[regno] = ((red >> 8) << info->var.red.offset) |
253 ((green >> 8) << info->var.green.offset) |
254 ((blue >> 8) << info->var.blue.offset);
255 }
256
257 return 0;
258}
259
260static irqreturn_t hdlcd_irq(int irq, void *data)
261{
262 struct hdlcd_device *hdlcd = data;
263 unsigned long irq_mask, irq_status;
264
265 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
266 irq_status = READ_HDLCD_REG(HDLCD_REG_INT_STATUS);
267
268 /* acknowledge interrupt(s) */
269 WRITE_HDLCD_REG(HDLCD_REG_INT_CLEAR, irq_status);
270
271 if (irq_status & HDLCD_INTERRUPT_VSYNC) {
272 /* disable future VSYNC interrupts */
273 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask & ~HDLCD_INTERRUPT_VSYNC);
274
275 complete(&hdlcd->vsync_completion);
276 }
277
278 return IRQ_HANDLED;
279}
280
281static int hdlcd_wait_for_vsync(struct fb_info *info)
282{
283 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
284 unsigned long irq_mask;
285 int err;
286
287 /* enable VSYNC interrupt */
288 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
289 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask | HDLCD_INTERRUPT_VSYNC);
290
291 err = wait_for_completion_interruptible_timeout(&hdlcd->vsync_completion,
292 msecs_to_jiffies(100));
293
294 if (!err)
295 return -ETIMEDOUT;
296
297 return 0;
298}
299
300static int hdlcd_blank(int blank_mode, struct fb_info *info)
301{
302 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
303
304 switch (blank_mode) {
305 case FB_BLANK_POWERDOWN:
306 clk_disable(hdlcd->clk);
307 case FB_BLANK_NORMAL:
308 hdlcd_disable(hdlcd);
309 break;
310 case FB_BLANK_UNBLANK:
311 clk_enable(hdlcd->clk);
312 hdlcd_enable(hdlcd);
313 break;
314 case FB_BLANK_VSYNC_SUSPEND:
315 case FB_BLANK_HSYNC_SUSPEND:
316 default:
317 return 1;
318 }
319
320 return 0;
321}
322
323static void hdlcd_mmap_open(struct vm_area_struct *vma)
324{
325}
326
327static void hdlcd_mmap_close(struct vm_area_struct *vma)
328{
329}
330
331static struct vm_operations_struct hdlcd_mmap_ops = {
332 .open = hdlcd_mmap_open,
333 .close = hdlcd_mmap_close,
334};
335
336static int hdlcd_mmap(struct fb_info *info, struct vm_area_struct *vma)
337{
338 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
339 unsigned long off;
340 unsigned long start;
341 unsigned long len = hdlcd->fb.fix.smem_len;
342
343 if (vma->vm_end - vma->vm_start == 0)
344 return 0;
345 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
346 return -EINVAL;
347
348 off = vma->vm_pgoff << PAGE_SHIFT;
349 if ((off >= len) || (vma->vm_end - vma->vm_start + off) > len)
350 return -EINVAL;
351
352 start = hdlcd->fb.fix.smem_start;
353 off += start;
354
355 vma->vm_pgoff = off >> PAGE_SHIFT;
356 vma->vm_flags |= VM_IO;
357 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
358 vma->vm_ops = &hdlcd_mmap_ops;
359 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
360 vma->vm_end - vma->vm_start,
361 vma->vm_page_prot))
362 return -EAGAIN;
363
364 return 0;
365}
366
367static int hdlcd_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
368{
369 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
370
371 hdlcd->fb.var.yoffset = var->yoffset;
372 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start +
373 (var->yoffset * hdlcd->fb.fix.line_length));
374
375 hdlcd_wait_for_vsync(info);
376
377 return 0;
378}
379
380static int hdlcd_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
381{
382 int err;
383
384 switch (cmd) {
385 case FBIO_WAITFORVSYNC:
386 err = hdlcd_wait_for_vsync(info);
387 break;
388 default:
389 err = -ENOIOCTLCMD;
390 break;
391 }
392
393 return err;
394}
395
396static struct fb_ops hdlcd_ops = {
397 .owner = THIS_MODULE,
398 .fb_check_var = hdlcd_check_var,
399 .fb_set_par = hdlcd_set_par,
400 .fb_setcolreg = hdlcd_setcolreg,
401 .fb_blank = hdlcd_blank,
402 .fb_fillrect = cfb_fillrect,
403 .fb_copyarea = cfb_copyarea,
404 .fb_imageblit = cfb_imageblit,
405 .fb_mmap = hdlcd_mmap,
406 .fb_pan_display = hdlcd_pan_display,
407 .fb_ioctl = hdlcd_ioctl,
408 .fb_compat_ioctl = hdlcd_ioctl
409};
410
411static int hdlcd_setup(struct hdlcd_device *hdlcd)
412{
413 u32 version;
414 int err = -EFAULT;
415
416 hdlcd->clk = clk_get(hdlcd->dev, NULL);
417 if (IS_ERR(hdlcd->clk)) {
418 dev_err(hdlcd->dev, "HDLCD: unable to find clock data\n");
419 return PTR_ERR(hdlcd->clk);
420 }
421
422 hdlcd->base = ioremap_nocache(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
423 if (!hdlcd->base) {
424 dev_err(hdlcd->dev, "HDLCD: unable to map registers\n");
425 goto remap_err;
426 }
427
428 hdlcd->fb.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
429 if (!hdlcd->fb.pseudo_palette) {
430 dev_err(hdlcd->dev, "HDLCD: unable to allocate pseudo_palette memory\n");
431 err = -ENOMEM;
432 goto kmalloc_err;
433 }
434
435 version = readl(hdlcd->base + HDLCD_REG_VERSION);
436 if ((version & HDLCD_PRODUCT_MASK) != HDLCD_PRODUCT_ID) {
437 dev_err(hdlcd->dev, "HDLCD: unknown product id: 0x%x\n", version);
438 err = -EINVAL;
439 goto kmalloc_err;
440 }
441 dev_info(hdlcd->dev, "HDLCD: found ARM HDLCD version r%dp%d\n",
442 (version & HDLCD_VERSION_MAJOR_MASK) >> 8,
443 version & HDLCD_VERSION_MINOR_MASK);
444
445 strcpy(hdlcd->fb.fix.id, "hdlcd");
446 hdlcd->fb.fbops = &hdlcd_ops;
447 hdlcd->fb.flags = FBINFO_FLAG_DEFAULT/* | FBINFO_VIRTFB*/;
448
449 hdlcd->fb.fix.type = FB_TYPE_PACKED_PIXELS;
450 hdlcd->fb.fix.type_aux = 0;
451 hdlcd->fb.fix.xpanstep = 0;
452 hdlcd->fb.fix.ypanstep = 1;
453 hdlcd->fb.fix.ywrapstep = 0;
454 hdlcd->fb.fix.accel = FB_ACCEL_NONE;
455
456 hdlcd->fb.var.nonstd = 0;
457 hdlcd->fb.var.activate = FB_ACTIVATE_NOW;
458 hdlcd->fb.var.height = -1;
459 hdlcd->fb.var.width = -1;
460 hdlcd->fb.var.accel_flags = 0;
461
462 init_completion(&hdlcd->vsync_completion);
463
464 if (hdlcd->edid) {
465 /* build modedb from EDID */
466 fb_edid_to_monspecs(hdlcd->edid, &hdlcd->fb.monspecs);
467 fb_videomode_to_modelist(hdlcd->fb.monspecs.modedb,
468 hdlcd->fb.monspecs.modedb_len,
469 &hdlcd->fb.modelist);
470 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode,
471 hdlcd->fb.monspecs.modedb,
472 hdlcd->fb.monspecs.modedb_len,
473 &hdlcd_default_mode, 32);
474 } else {
475 hdlcd->fb.monspecs.hfmin = 0;
476 hdlcd->fb.monspecs.hfmax = 100000;
477 hdlcd->fb.monspecs.vfmin = 0;
478 hdlcd->fb.monspecs.vfmax = 400;
479 hdlcd->fb.monspecs.dclkmin = 1000000;
480 hdlcd->fb.monspecs.dclkmax = 100000000;
481 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode, NULL, 0, &hdlcd_default_mode, 32);
482 }
483
484 dev_info(hdlcd->dev, "using %dx%d-%d@%d mode\n", hdlcd->fb.var.xres,
485 hdlcd->fb.var.yres, hdlcd->fb.var.bits_per_pixel,
486 hdlcd->fb.mode ? hdlcd->fb.mode->refresh : 60);
487 hdlcd->fb.var.xres_virtual = hdlcd->fb.var.xres;
488 hdlcd->fb.var.yres_virtual = hdlcd->fb.var.yres * 2;
489
490 /* initialise and set the palette */
491 if (fb_alloc_cmap(&hdlcd->fb.cmap, NR_PALETTE, 0)) {
492 dev_err(hdlcd->dev, "failed to allocate cmap memory\n");
493 err = -ENOMEM;
494 goto setup_err;
495 }
496 fb_set_cmap(&hdlcd->fb.cmap, &hdlcd->fb);
497
498 /* Allow max number of outstanding requests with the largest beat burst */
499 WRITE_HDLCD_REG(HDLCD_REG_BUS_OPTIONS, HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
500 /* Set the framebuffer base to start of allocated memory */
501 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start);
502 /* Ensure interrupts are disabled */
503 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, 0);
504
505 if (!register_framebuffer(&hdlcd->fb)) {
506 fb_set_var(&hdlcd->fb, &hdlcd->fb.var);
507 clk_enable(hdlcd->clk);
508 return 0;
509 }
510
511 dev_err(hdlcd->dev, "HDLCD: cannot register framebuffer\n");
512
513 fb_dealloc_cmap(&hdlcd->fb.cmap);
514setup_err:
515 iounmap(hdlcd->base);
516kmalloc_err:
517 kfree(hdlcd->fb.pseudo_palette);
518remap_err:
519 clk_put(hdlcd->clk);
520 return err;
521}
522
523static inline unsigned char atohex(u8 data)
524{
525 if (!isxdigit(data))
526 return 0;
527 /* truncate the upper nibble and add 9 to non-digit values */
528 return (data > 0x39) ? ((data & 0xf) + 9) : (data & 0xf);
529}
530
531/* EDID data is passed from devicetree in a literal string that can contain spaces and
532 the hexadecimal dump of the data */
533static int parse_edid_data(struct hdlcd_device *hdlcd, const u8 *edid_data, int data_len)
534{
535 int i, j;
536
537 if (!edid_data)
538 return -EINVAL;
539
540 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
541 if (!hdlcd->edid)
542 return -ENOMEM;
543
544 for (i = 0, j = 0; i < data_len; i++) {
545 if (isspace(edid_data[i]))
546 continue;
547 hdlcd->edid[j++] = atohex(edid_data[i]);
548 if (j >= EDID_LENGTH)
549 break;
550 }
551
552 if (j < EDID_LENGTH) {
553 kfree(hdlcd->edid);
554 hdlcd->edid = NULL;
555 return -EINVAL;
556 }
557
558 return 0;
559}
560
561static int hdlcd_probe(struct platform_device *pdev)
562{
563 int err = 0, i;
564 struct hdlcd_device *hdlcd;
565 struct resource *mem;
566#ifdef CONFIG_OF
567 struct device_node *of_node;
568#endif
569
570 memset(&cached_var_screeninfo, 0, sizeof(struct fb_var_screeninfo));
571
572 dev_dbg(&pdev->dev, "HDLCD: probing\n");
573
574 hdlcd = kzalloc(sizeof(*hdlcd), GFP_KERNEL);
575 if (!hdlcd)
576 return -ENOMEM;
577
578#ifdef CONFIG_OF
579 of_node = pdev->dev.of_node;
580 if (of_node) {
581 int len;
582 const u8 *edid;
Jon Medhurst51f19112012-07-13 13:32:48 +0100583 const __be32 *prop = of_get_property(of_node, "mode", &len);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000584 if (prop)
Jon Medhurst51f19112012-07-13 13:32:48 +0100585 strncpy(fb_mode, (char *)prop, len);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000586 prop = of_get_property(of_node, "framebuffer", &len);
587 if (prop) {
Jon Medhurst51f19112012-07-13 13:32:48 +0100588 hdlcd->fb.fix.smem_start = of_read_ulong(prop,
589 of_n_addr_cells(of_node));
590 prop += of_n_addr_cells(of_node);
591 framebuffer_size = of_read_ulong(prop,
592 of_n_size_cells(of_node));
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000593 if (framebuffer_size > HDLCD_MAX_FRAMEBUFFER_SIZE)
594 framebuffer_size = HDLCD_MAX_FRAMEBUFFER_SIZE;
595 dev_dbg(&pdev->dev, "HDLCD: phys_addr = 0x%lx, size = 0x%lx\n",
596 hdlcd->fb.fix.smem_start, framebuffer_size);
597 }
598 edid = of_get_property(of_node, "edid", &len);
599 if (edid) {
600 err = parse_edid_data(hdlcd, edid, len);
601#ifdef CONFIG_SERIAL_AMBA_PCU_UART
602 } else {
603 /* ask the firmware to fetch the EDID */
604 dev_dbg(&pdev->dev, "HDLCD: Requesting EDID data\n");
605 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
606 if (!hdlcd->edid)
607 return -ENOMEM;
608 err = get_edid(hdlcd->edid);
609#endif /* CONFIG_SERIAL_AMBA_PCU_UART */
610 }
611 if (err)
612 dev_info(&pdev->dev, "HDLCD: Failed to parse EDID data\n");
613 }
614#endif /* CONFIG_OF */
615
616 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
617 if (!mem) {
618 dev_err(&pdev->dev, "HDLCD: cannot get platform resources\n");
619 err = -EINVAL;
620 goto resource_err;
621 }
622
623 i = platform_get_irq(pdev, 0);
624 if (i < 0) {
625 dev_err(&pdev->dev, "HDLCD: no irq defined for vsync\n");
626 err = -ENOENT;
627 goto resource_err;
628 } else {
629 err = request_irq(i, hdlcd_irq, 0, dev_name(&pdev->dev), hdlcd);
630 if (err) {
631 dev_err(&pdev->dev, "HDLCD: unable to request irq\n");
632 goto resource_err;
633 }
634 hdlcd->irq = i;
635 }
636
637 if (!request_mem_region(mem->start, resource_size(mem), dev_name(&pdev->dev))) {
638 err = -ENXIO;
639 goto request_err;
640 }
641
642 if (!hdlcd->fb.fix.smem_start) {
643 dev_err(&pdev->dev, "platform did not allocate frame buffer memory\n");
644 err = -ENOMEM;
645 goto memalloc_err;
646 }
647 hdlcd->fb.screen_base = ioremap_wc(hdlcd->fb.fix.smem_start, framebuffer_size);
648 if (!hdlcd->fb.screen_base) {
649 dev_err(&pdev->dev, "unable to ioremap framebuffer\n");
650 err = -ENOMEM;
651 goto probe_err;
652 }
653
654 hdlcd->fb.screen_size = framebuffer_size;
655 hdlcd->fb.fix.smem_len = framebuffer_size;
656 hdlcd->fb.fix.mmio_start = mem->start;
657 hdlcd->fb.fix.mmio_len = resource_size(mem);
658
659 /* Clear the framebuffer */
660 memset(hdlcd->fb.screen_base, 0, framebuffer_size);
661
662 hdlcd->dev = &pdev->dev;
663
664 dev_dbg(&pdev->dev, "HDLCD: framebuffer virt base %p, phys base 0x%lX\n",
665 hdlcd->fb.screen_base, (unsigned long)hdlcd->fb.fix.smem_start);
666
667 err = hdlcd_setup(hdlcd);
668
669 if (err)
670 goto probe_err;
671
672 platform_set_drvdata(pdev, hdlcd);
673 return 0;
674
675probe_err:
676 iounmap(hdlcd->fb.screen_base);
677 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
678
679memalloc_err:
680 release_mem_region(mem->start, resource_size(mem));
681
682request_err:
683 free_irq(hdlcd->irq, hdlcd);
684
685resource_err:
686 kfree(hdlcd);
687
688 return err;
689}
690
691static int hdlcd_remove(struct platform_device *pdev)
692{
693 struct hdlcd_device *hdlcd = platform_get_drvdata(pdev);
694
695 clk_disable(hdlcd->clk);
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100696 clk_unprepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000697 clk_put(hdlcd->clk);
698
699 /* unmap memory */
700 iounmap(hdlcd->fb.screen_base);
701 iounmap(hdlcd->base);
702
703 /* deallocate fb memory */
704 fb_dealloc_cmap(&hdlcd->fb.cmap);
705 kfree(hdlcd->fb.pseudo_palette);
706 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
707 release_mem_region(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
708
709 free_irq(hdlcd->irq, NULL);
710 kfree(hdlcd);
711
712 return 0;
713}
714
715#ifdef CONFIG_PM
716static int hdlcd_suspend(struct platform_device *pdev, pm_message_t state)
717{
718 /* not implemented yet */
719 return 0;
720}
721
722static int hdlcd_resume(struct platform_device *pdev)
723{
724 /* not implemented yet */
725 return 0;
726}
727#else
728#define hdlcd_suspend NULL
729#define hdlcd_resume NULL
730#endif
731
732static struct platform_driver hdlcd_driver = {
733 .probe = hdlcd_probe,
734 .remove = hdlcd_remove,
735 .suspend = hdlcd_suspend,
736 .resume = hdlcd_resume,
737 .driver = {
738 .name = "hdlcd",
739 .owner = THIS_MODULE,
740 .of_match_table = hdlcd_of_matches,
741 },
742};
743
744static int __init hdlcd_init(void)
745{
746 return platform_driver_register(&hdlcd_driver);
747}
748
749void __exit hdlcd_exit(void)
750{
751 platform_driver_unregister(&hdlcd_driver);
752}
753
754module_init(hdlcd_init);
755module_exit(hdlcd_exit);
756
757MODULE_AUTHOR("Liviu Dudau");
758MODULE_DESCRIPTION("ARM HDLCD core driver");
759MODULE_LICENSE("GPL v2");