33 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/errno.h>
37 #include <linux/string.h>
42 #include <linux/ctype.h>
44 #include <linux/slab.h>
50 #define DRIVER_NAME "au1200fb"
51 #define DRIVER_DESC "LCD controller driver for AU1200 processors"
55 #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
56 #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
57 #define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
60 #define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
62 #define print_dbg(f, arg...) do {} while (0)
66 #define AU1200_LCD_FB_IOCTL 0x46FF
68 #define AU1200_LCD_SET_SCREEN 1
69 #define AU1200_LCD_GET_SCREEN 2
70 #define AU1200_LCD_SET_WINDOW 3
71 #define AU1200_LCD_GET_WINDOW 4
72 #define AU1200_LCD_SET_PANEL 5
73 #define AU1200_LCD_GET_PANEL 6
75 #define SCREEN_SIZE (1<< 1)
76 #define SCREEN_BACKCOLOR (1<< 2)
77 #define SCREEN_BRIGHTNESS (1<< 3)
78 #define SCREEN_COLORKEY (1<< 4)
79 #define SCREEN_MASK (1<< 5)
94 #define WIN_POSITION (1<< 0)
95 #define WIN_ALPHA_COLOR (1<< 1)
96 #define WIN_ALPHA_MODE (1<< 2)
97 #define WIN_PRIORITY (1<< 3)
98 #define WIN_CHANNEL (1<< 4)
99 #define WIN_BUFFER_FORMAT (1<< 5)
100 #define WIN_COLOR_ORDER (1<< 6)
101 #define WIN_PIXEL_ORDER (1<< 7)
102 #define WIN_SIZE (1<< 8)
103 #define WIN_COLORKEY_MODE (1<< 9)
104 #define WIN_DOUBLE_BUFFER_MODE (1<< 10)
105 #define WIN_RAM_ARRAY_MODE (1<< 11)
106 #define WIN_BUFFER_SCALE (1<< 12)
107 #define WIN_ENABLE (1<< 13)
137 #if defined(__BIG_ENDIAN)
138 #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
140 #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
142 #define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
158 #define AU1200_LCD_MAX_XRES 1280
159 #define AU1200_LCD_MAX_YRES 1024
160 #define AU1200_LCD_MAX_BPP 32
161 #define AU1200_LCD_MAX_CLK 96000000
162 #define AU1200_LCD_NBR_PALETTE_ENTRIES 256
165 #define AU1200FB_NBR_VIDEO_BUFFERS 1
168 #define MAX_DEVICE_COUNT 4
171 #define DEFAULT_WINDOW_INDEX 2
179 static int panel_index = 2;
182 static int noblanking = 1;
183 static int nohwcursor = 0;
200 #if defined(__BIG_ENDIAN)
201 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
203 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
211 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
245 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
278 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
336 #define Xres min_xres
337 #define Yres min_yres
361 .name =
"QVGA_320x240",
375 .mode_horztiming = 0x00c4623b,
376 .mode_verttiming = 0x00502814,
377 .mode_clkcontrol = 0x00020002,
378 .mode_pwmdiv = 0x00000000,
379 .mode_pwmhi = 0x00000000,
380 .mode_outmask = 0x00FFFFFF,
381 .mode_fifoctrl = 0x2f2f2f2f,
382 .mode_toyclksrc = 0x00000004,
383 .mode_backlight = 0x00000000,
390 .name =
"VGA_640x480",
402 .mode_screen = 0x13f9df80,
403 .mode_horztiming = 0x003c5859,
404 .mode_verttiming = 0x00741201,
405 .mode_clkcontrol = 0x00020001,
406 .mode_pwmdiv = 0x00000000,
407 .mode_pwmhi = 0x00000000,
408 .mode_outmask = 0x00FFFFFF,
409 .mode_fifoctrl = 0x2f2f2f2f,
410 .mode_toyclksrc = 0x00000004,
411 .mode_backlight = 0x00000000,
418 .name =
"SVGA_800x600",
430 .mode_screen = 0x18fa5780,
431 .mode_horztiming = 0x00dc7e77,
432 .mode_verttiming = 0x00584805,
433 .mode_clkcontrol = 0x00020000,
434 .mode_pwmdiv = 0x00000000,
435 .mode_pwmhi = 0x00000000,
436 .mode_outmask = 0x00FFFFFF,
437 .mode_fifoctrl = 0x2f2f2f2f,
438 .mode_toyclksrc = 0x00000004,
439 .mode_backlight = 0x00000000,
446 .name =
"XVGA_1024x768",
458 .mode_screen = 0x1ffaff80,
459 .mode_horztiming = 0x007d0e57,
460 .mode_verttiming = 0x00740a01,
461 .mode_clkcontrol = 0x000A0000,
462 .mode_pwmdiv = 0x00000000,
463 .mode_pwmhi = 0x00000000,
464 .mode_outmask = 0x00FFFFFF,
465 .mode_fifoctrl = 0x2f2f2f2f,
466 .mode_toyclksrc = 0x00000004,
467 .mode_backlight = 0x00000000,
474 .name =
"XVGA_1280x1024",
486 .mode_screen = 0x27fbff80,
487 .mode_horztiming = 0x00cdb2c7,
488 .mode_verttiming = 0x00600002,
489 .mode_clkcontrol = 0x000A0000,
490 .mode_pwmdiv = 0x00000000,
491 .mode_pwmhi = 0x00000000,
492 .mode_outmask = 0x00FFFFFF,
493 .mode_fifoctrl = 0x2f2f2f2f,
494 .mode_toyclksrc = 0x00000004,
495 .mode_backlight = 0x00000000,
502 .name =
"Samsung_1024x768_TFT",
514 .mode_screen = 0x1ffaff80,
515 .mode_horztiming = 0x018cc677,
516 .mode_verttiming = 0x00241217,
517 .mode_clkcontrol = 0x00000000,
518 .mode_pwmdiv = 0x8000063f,
519 .mode_pwmhi = 0x03400000,
520 .mode_outmask = 0x00FFFFFF,
521 .mode_fifoctrl = 0x2f2f2f2f,
522 .mode_toyclksrc = 0x00000004,
523 .mode_backlight = 0x00000000,
530 .name =
"Toshiba_640x480_TFT",
548 .mode_clkcontrol = 0x00000000,
549 .mode_pwmdiv = 0x8000063f,
550 .mode_pwmhi = 0x03400000,
551 .mode_outmask = 0x00fcfcfc,
552 .mode_fifoctrl = 0x2f2f2f2f,
553 .mode_toyclksrc = 0x00000004,
554 .mode_backlight = 0x00000000,
561 .name =
"Sharp_320x240_TFT",
580 .mode_pwmdiv = 0x8000063f,
581 .mode_pwmhi = 0x03400000,
582 .mode_outmask = 0x00fcfcfc,
583 .mode_fifoctrl = 0x2f2f2f2f,
584 .mode_toyclksrc = 0x00000004,
585 .mode_backlight = 0x00000000,
592 .name =
"Toppoly_TD070WGCB2",
610 .mode_clkcontrol = 0x00020001,
611 .mode_pwmdiv = 0x8000063f,
612 .mode_pwmhi = 0x03400000,
613 .mode_outmask = 0x00fcfcfc,
614 .mode_fifoctrl = 0x2f2f2f2f,
615 .mode_toyclksrc = 0x00000004,
616 .mode_backlight = 0x00000000,
622 .name =
"DB1300_800x480",
645 .mode_pwmdiv = 0x00000000,
646 .mode_pwmhi = 0x00000000,
647 .mode_outmask = 0x00FFFFFF,
648 .mode_fifoctrl = 0x2f2f2f2f,
649 .mode_toyclksrc = 0x00000004,
650 .mode_backlight = 0x00000000,
651 .mode_auxpll = (48/12) * 2,
657 #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
661 static int winbpp (
unsigned int winctrl1)
702 for (i = 0; i < device_count; ++
i) {
703 if (fb_info == _au1200fb_infos[i])
706 printk(
"au1200fb: ERROR: fbinfo2index failed!\n");
713 uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
726 if ((xpos + win->
w[plane].xres) > panel->Xres) {
728 xsz = panel->Xres - xpos;
732 if ((ypos + win->
w[plane].yres) > panel->Yres) {
734 ysz = panel->Yres - ypos;
740 xsz = win->
w[
plane].xres + xpos;
741 fb_offset += (((0 - xpos) * winbpp(lcd->
window[plane].winctrl1))/8);
748 ysz = win->
w[
plane].yres + ypos;
755 win->
w[
plane].xpos = xpos;
756 win->
w[
plane].ypos = ypos;
760 winctrl0 |= (xpos << 21);
761 winctrl0 |= (ypos << 10);
762 winctrl1 |= (xsz << 11);
763 winctrl1 |= (ysz << 0);
820 if (newpanel ==
NULL)
825 printk(
"Panel(%s), %dx%d\n", panel->
name, panel->Xres, panel->Yres);
834 sys_clksrc = au_readl(
SYS_CLKSRC) & ~0x0000001f;
855 au1200_setlocation(fbdev, 0, win->
w[0].xpos, win->
w[0].ypos);
856 au1200_setlocation(fbdev, 1, win->
w[1].xpos, win->
w[1].ypos);
857 au1200_setlocation(fbdev, 2, win->
w[2].xpos, win->
w[2].ypos);
858 au1200_setlocation(fbdev, 3, win->
w[3].xpos, win->
w[3].ypos);
882 lcd->
hwc.cursorctrl = 0;
883 lcd->
hwc.cursorpos = 0;
884 lcd->
hwc.cursorcolor0 = 0;
885 lcd->
hwc.cursorcolor1 = 0;
886 lcd->
hwc.cursorcolor2 = 0;
887 lcd->
hwc.cursorcolor3 = 0;
891 #define D(X) printk("%25s: %08X\n", #X, X)
931 D(lcd->
hwc.cursorctrl);
932 D(lcd->
hwc.cursorpos);
933 D(lcd->
hwc.cursorcolor0);
934 D(lcd->
hwc.cursorcolor1);
935 D(lcd->
hwc.cursorcolor2);
936 D(lcd->
hwc.cursorcolor3);
942 int plane = fbdev->
plane;
946 | win->
w[
plane].mode_winctrl1
949 au1200_setlocation(fbdev, plane, win->
w[plane].xpos, win->
w[plane].ypos);
968 #define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
974 { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
977 { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
980 { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
983 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
986 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
989 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
992 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
995 { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
998 { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
1005 static void au1200fb_update_fbinfo(
struct fb_info *fbi)
1011 if (fbi->
var.bits_per_pixel <= 8) {
1014 fbi->
fix.line_length = fbi->
var.xres_virtual /
1015 (8/fbi->
var.bits_per_pixel);
1019 fbi->
fix.line_length = fbi->
var.xres_virtual * (fbi->
var.bits_per_pixel / 8);
1024 fbi->
fix.line_length = fbi->
var.xres_virtual / 8;
1029 print_dbg(
"bits_per_pixel: %d\n", fbi->
var.bits_per_pixel);
1040 struct fb_info *fbi)
1044 int screen_size,
plane;
1046 plane = fbdev->
plane;
1063 if (fbdev->
fb_len < screen_size)
1101 var->
red = rgb_bitfields[
idx][0];
1102 var->
green = rgb_bitfields[
idx][1];
1103 var->
blue = rgb_bitfields[
idx][2];
1114 var->
red = rgb_bitfields[
idx][0];
1115 var->
green = rgb_bitfields[
idx][1];
1116 var->
blue = rgb_bitfields[
idx][2];
1132 static int au1200fb_fb_set_par(
struct fb_info *fbi)
1136 au1200fb_update_fbinfo(fbi);
1137 au1200_setmode(fbdev);
1145 static int au1200fb_fb_setcolreg(
unsigned regno,
unsigned red,
unsigned green,
1146 unsigned blue,
unsigned transp,
struct fb_info *fbi)
1154 if (fbi->
var.grayscale) {
1156 red = green = blue =
1157 (19595 * red + 38470 * green + 7471 *
blue) >> 16;
1167 red >>= (16 - fbi->
var.red.length);
1168 green >>= (16 - fbi->
var.green.length);
1169 blue >>= (16 - fbi->
var.blue.length);
1171 value = (red << fbi->
var.red.offset) |
1172 (green << fbi->
var.green.offset)|
1173 (blue << fbi->
var.blue.offset);
1178 value = (red & 0xF800)|((green >> 5) &
1179 0x07E0)|((blue >> 11) & 0x001F);
1188 value = (green >> 12) & 0x000F;
1192 palette[regno] =
value;
1201 static int au1200fb_fb_blank(
int blank_mode,
struct fb_info *fbi)
1209 switch (blank_mode) {
1214 au1200_setpanel(panel, fbdev->
pd);
1220 au1200_setpanel(
NULL, fbdev->
pd);
1239 unsigned long start=0, off;
1273 unsigned int hi1, divider;
1286 divider = (lcd->
pwmdiv & 0x3FFFF) + 1;
1287 hi1 = (lcd->
pwmhi >> 16) + 1;
1288 hi1 = (((pdata->
brightness & 0xFF)+1) * divider >> 8);
1289 lcd->
pwmhi &= 0xFFFF;
1290 lcd->
pwmhi |= (hi1 << 16);
1303 unsigned int hi1, divider;
1313 hi1 = (lcd->
pwmhi >> 16) + 1;
1314 divider = (lcd->
pwmdiv & 0x3FFFF) + 1;
1315 pdata->
brightness = ((hi1 << 8) / divider) - 1;
1319 static void set_window(
unsigned int plane,
1376 bpp = winbpp(val) / 8;
1412 val |= (pdata->
enable & 1) << plane;
1418 static void get_window(
unsigned int plane,
1445 static int au1200fb_ioctl(
struct fb_info *info,
unsigned int cmd,
1452 plane = fbinfo2index(info);
1453 print_dbg(
"au1200fb: ioctl %d on plane %d\n", cmd, plane);
1458 if (
copy_from_user(&iodata, (
void __user *) arg,
sizeof(iodata)))
1463 switch (iodata.subcmd) {
1466 set_global(cmd, &iodata.global);
1471 get_global(cmd, &iodata.global);
1476 set_window(plane, &iodata.window);
1481 get_window(plane, &iodata.window);
1486 if ((iodata.global.panel_choice >= 0) &&
1487 (iodata.global.panel_choice <
1491 panel_index = iodata.global.panel_choice;
1492 newpanel = &known_lcd_panels[panel_index];
1493 au1200_setpanel(newpanel, fbdev->
pd);
1499 iodata.global.panel_choice = panel_index;
1506 val =
copy_to_user((
void __user *) arg, &iodata,
sizeof(iodata));
1508 print_dbg(
"error: could not copy %d bytes\n", val);
1517 static struct fb_ops au1200fb_fb_ops = {
1519 .fb_check_var = au1200fb_fb_check_var,
1520 .fb_set_par = au1200fb_fb_set_par,
1521 .fb_setcolreg = au1200fb_fb_setcolreg,
1522 .fb_blank = au1200fb_fb_blank,
1529 .fb_ioctl = au1200fb_ioctl,
1530 .fb_mmap = au1200fb_fb_mmap,
1550 struct fb_info *fbi = fbdev->
fb_info;
1553 fbi->
fbops = &au1200fb_fb_ops;
1555 bpp = winbpp(win->
w[fbdev->
plane].mode_winctrl1);
1574 print_err(
"Cannot find valid mode for panel %s", panel->
name);
1584 print_err(
"Fail to allocate colormap (%d entries)",
1594 fbi->
fix.xpanstep = 0;
1595 fbi->
fix.ypanstep = 0;
1596 fbi->
fix.mmio_start = 0;
1597 fbi->
fix.mmio_len = 0;
1602 au1200fb_update_fbinfo(fbi);
1613 char *this_opt, *endptr;
1614 int num_panels =
ARRAY_SIZE(known_lcd_panels);
1622 while ((this_opt =
strsep(&options,
",")) !=
NULL) {
1625 if (!
strncmp(this_opt,
"panel:", 6)) {
1633 if (*endptr ==
'\0')
1634 panel_idx = (
int)li;
1635 else if (
strcmp(this_opt,
"bs") == 0)
1638 for (i = 0; i < num_panels; i++) {
1640 known_lcd_panels[i].
name)) {
1646 if ((panel_idx < 0) || (panel_idx >= num_panels))
1647 print_warn(
"Panel %s not supported!", this_opt);
1649 panel_index = panel_idx;
1651 }
else if (
strncmp(this_opt,
"nohwcursor", 10) == 0)
1653 else if (
strncmp(this_opt,
"devices:", 8) == 0) {
1656 if ((device_count < 0) ||
1659 }
else if (
strncmp(this_opt,
"wincfg:", 7) == 0) {
1662 if ((window_index < 0) ||
1665 }
else if (
strncmp(this_opt,
"off", 3) == 0)
1668 print_warn(
"Unsupported option \"%s\"", this_opt);
1680 struct fb_info *fbi =
NULL;
1686 pd = dev->
dev.platform_data;
1691 if (au1200fb_setup(pd))
1695 panel = &known_lcd_panels[panel_index];
1696 win = &windows[window_index];
1705 for (plane = 0; plane < device_count; ++
plane) {
1706 bpp = winbpp(win->
w[plane].mode_winctrl1);
1707 if (win->
w[plane].xres == 0)
1708 win->
w[
plane].xres = panel->Xres;
1709 if (win->
w[plane].yres == 0)
1710 win->
w[
plane].yres = panel->Yres;
1717 _au1200fb_infos[
plane] = fbi;
1731 print_err(
"fail to allocate frambuffer (size: %dK))",
1740 for (page = (
unsigned long)fbdev->
fb_phys;
1750 if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
1756 print_err(
"cannot register new framebuffer");
1760 au1200fb_fb_set_par(fbi);
1762 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
1777 print_err(
"fail to request interrupt line %d (err: %d)",
1782 platform_set_drvdata(dev, pd);
1785 au1200_setpanel(panel, pd);
1792 if (fbi->
cmap.len != 0)
1805 struct fb_info *fbi;
1809 au1200_setpanel(
NULL, pd);
1811 for (plane = 0; plane < device_count; ++
plane) {
1812 fbi = _au1200fb_infos[
plane];
1817 if (fbi->
cmap.len != 0)
1831 static int au1200fb_drv_suspend(
struct device *dev)
1834 au1200_setpanel(
NULL, pd);
1842 static int au1200fb_drv_resume(
struct device *dev)
1845 struct fb_info *fbi;
1849 au1200_setpanel(panel, pd);
1851 for (i = 0; i < device_count; i++) {
1852 fbi = _au1200fb_infos[
i];
1853 au1200fb_fb_set_par(fbi);
1859 static const struct dev_pm_ops au1200fb_pmops = {
1860 .
suspend = au1200fb_drv_suspend,
1861 .resume = au1200fb_drv_resume,
1862 .freeze = au1200fb_drv_suspend,
1863 .thaw = au1200fb_drv_resume,
1866 #define AU1200FB_PMOPS (&au1200fb_pmops)
1869 #define AU1200FB_PMOPS NULL
1874 .name =
"au1200-lcd",
1878 .probe = au1200fb_drv_probe,
1884 static int __init au1200fb_init(
void)
1889 static void __exit au1200fb_cleanup(
void)