0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/clk.h>
0034 #include <linux/module.h>
0035 #include <linux/platform_device.h>
0036 #include <linux/kernel.h>
0037 #include <linux/errno.h>
0038 #include <linux/string.h>
0039 #include <linux/mm.h>
0040 #include <linux/fb.h>
0041 #include <linux/init.h>
0042 #include <linux/interrupt.h>
0043 #include <linux/ctype.h>
0044 #include <linux/dma-mapping.h>
0045 #include <linux/slab.h>
0046 #include <linux/uaccess.h>
0047
0048 #include <asm/mach-au1x00/au1000.h>
0049 #include <asm/mach-au1x00/au1200fb.h> /* platform_data */
0050 #include "au1200fb.h"
0051
0052 #define DRIVER_NAME "au1200fb"
0053 #define DRIVER_DESC "LCD controller driver for AU1200 processors"
0054
0055 #define DEBUG 0
0056
0057 #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
0058 #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
0059 #define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
0060
0061 #if DEBUG
0062 #define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
0063 #else
0064 #define print_dbg(f, arg...) do {} while (0)
0065 #endif
0066
0067
0068 #define AU1200_LCD_FB_IOCTL 0x46FF
0069
0070 #define AU1200_LCD_SET_SCREEN 1
0071 #define AU1200_LCD_GET_SCREEN 2
0072 #define AU1200_LCD_SET_WINDOW 3
0073 #define AU1200_LCD_GET_WINDOW 4
0074 #define AU1200_LCD_SET_PANEL 5
0075 #define AU1200_LCD_GET_PANEL 6
0076
0077 #define SCREEN_SIZE (1<< 1)
0078 #define SCREEN_BACKCOLOR (1<< 2)
0079 #define SCREEN_BRIGHTNESS (1<< 3)
0080 #define SCREEN_COLORKEY (1<< 4)
0081 #define SCREEN_MASK (1<< 5)
0082
0083 struct au1200_lcd_global_regs_t {
0084 unsigned int flags;
0085 unsigned int xsize;
0086 unsigned int ysize;
0087 unsigned int backcolor;
0088 unsigned int brightness;
0089 unsigned int colorkey;
0090 unsigned int mask;
0091 unsigned int panel_choice;
0092 char panel_desc[80];
0093
0094 };
0095
0096 #define WIN_POSITION (1<< 0)
0097 #define WIN_ALPHA_COLOR (1<< 1)
0098 #define WIN_ALPHA_MODE (1<< 2)
0099 #define WIN_PRIORITY (1<< 3)
0100 #define WIN_CHANNEL (1<< 4)
0101 #define WIN_BUFFER_FORMAT (1<< 5)
0102 #define WIN_COLOR_ORDER (1<< 6)
0103 #define WIN_PIXEL_ORDER (1<< 7)
0104 #define WIN_SIZE (1<< 8)
0105 #define WIN_COLORKEY_MODE (1<< 9)
0106 #define WIN_DOUBLE_BUFFER_MODE (1<< 10)
0107 #define WIN_RAM_ARRAY_MODE (1<< 11)
0108 #define WIN_BUFFER_SCALE (1<< 12)
0109 #define WIN_ENABLE (1<< 13)
0110
0111 struct au1200_lcd_window_regs_t {
0112 unsigned int flags;
0113 unsigned int xpos;
0114 unsigned int ypos;
0115 unsigned int alpha_color;
0116 unsigned int alpha_mode;
0117 unsigned int priority;
0118 unsigned int channel;
0119 unsigned int buffer_format;
0120 unsigned int color_order;
0121 unsigned int pixel_order;
0122 unsigned int xsize;
0123 unsigned int ysize;
0124 unsigned int colorkey_mode;
0125 unsigned int double_buffer_mode;
0126 unsigned int ram_array_mode;
0127 unsigned int xscale;
0128 unsigned int yscale;
0129 unsigned int enable;
0130 };
0131
0132
0133 struct au1200_lcd_iodata_t {
0134 unsigned int subcmd;
0135 struct au1200_lcd_global_regs_t global;
0136 struct au1200_lcd_window_regs_t window;
0137 };
0138
0139 #if defined(__BIG_ENDIAN)
0140 #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
0141 #else
0142 #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
0143 #endif
0144 #define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
0145
0146
0147 struct au1200fb_device {
0148 struct fb_info *fb_info;
0149 struct au1200fb_platdata *pd;
0150 struct device *dev;
0151
0152 int plane;
0153 unsigned char* fb_mem;
0154 unsigned int fb_len;
0155 dma_addr_t fb_phys;
0156 };
0157
0158
0159
0160
0161 #define AU1200_LCD_MAX_XRES 1280
0162 #define AU1200_LCD_MAX_YRES 1024
0163 #define AU1200_LCD_MAX_BPP 32
0164 #define AU1200_LCD_MAX_CLK 96000000
0165 #define AU1200_LCD_NBR_PALETTE_ENTRIES 256
0166
0167
0168 #define AU1200FB_NBR_VIDEO_BUFFERS 1
0169
0170
0171 #define MAX_DEVICE_COUNT 4
0172
0173
0174 #define DEFAULT_WINDOW_INDEX 2
0175
0176
0177
0178 static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
0179 static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
0180 static int device_count = MAX_DEVICE_COUNT;
0181 static int window_index = DEFAULT_WINDOW_INDEX;
0182 static int panel_index = 2;
0183 static struct window_settings *win;
0184 static struct panel_settings *panel;
0185 static int noblanking = 1;
0186 static int nohwcursor = 0;
0187
0188 struct window_settings {
0189 unsigned char name[64];
0190 uint32 mode_backcolor;
0191 uint32 mode_colorkey;
0192 uint32 mode_colorkeymsk;
0193 struct {
0194 int xres;
0195 int yres;
0196 int xpos;
0197 int ypos;
0198 uint32 mode_winctrl1;
0199 uint32 mode_winenable;
0200 } w[4];
0201 };
0202
0203 #if defined(__BIG_ENDIAN)
0204 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
0205 #else
0206 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
0207 #endif
0208
0209
0210
0211
0212 static struct window_settings windows[] = {
0213 {
0214 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
0215 0x006600ff,
0216 0, 0,
0217 {
0218 {
0219 0, 0, 0, 0,
0220 LCD_WINCTRL1_FRM_16BPP565 |
0221 LCD_WINCTRL1_PO_16BPP,
0222 LCD_WINENABLE_WEN0,
0223 },
0224 {
0225 100, 100, 100, 100,
0226 LCD_WINCTRL1_FRM_16BPP565 |
0227 LCD_WINCTRL1_PO_16BPP |
0228 LCD_WINCTRL1_PIPE,
0229 LCD_WINENABLE_WEN1,
0230 },
0231 {
0232 0, 0, 0, 0,
0233 LCD_WINCTRL1_FRM_16BPP565 |
0234 LCD_WINCTRL1_PO_16BPP,
0235 0,
0236 },
0237 {
0238 0, 0, 0, 0,
0239 LCD_WINCTRL1_FRM_16BPP565 |
0240 LCD_WINCTRL1_PO_16BPP |
0241 LCD_WINCTRL1_PIPE,
0242 0,
0243 },
0244 },
0245 },
0246
0247 {
0248 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
0249 0x006600ff,
0250 0, 0,
0251 {
0252 {
0253 320, 240, 5, 5,
0254 LCD_WINCTRL1_FRM_24BPP |
0255 LCD_WINCTRL1_PO_00,
0256 LCD_WINENABLE_WEN0,
0257 },
0258 {
0259 0, 0, 0, 0,
0260 LCD_WINCTRL1_FRM_16BPP565
0261 | LCD_WINCTRL1_PO_16BPP,
0262 0,
0263 },
0264 {
0265 100, 100, 0, 0,
0266 LCD_WINCTRL1_FRM_16BPP565 |
0267 LCD_WINCTRL1_PO_16BPP |
0268 LCD_WINCTRL1_PIPE,
0269 0,
0270 },
0271 {
0272 200, 25, 0, 0,
0273 LCD_WINCTRL1_FRM_16BPP565 |
0274 LCD_WINCTRL1_PO_16BPP |
0275 LCD_WINCTRL1_PIPE,
0276 0,
0277 },
0278 },
0279 },
0280 {
0281 "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
0282 0x006600ff,
0283 0, 0,
0284 {
0285 {
0286 0, 0, 0, 0,
0287 LCD_WINCTRL1_FRM_16BPP565 |
0288 LCD_WINCTRL1_PO_16BPP,
0289 LCD_WINENABLE_WEN0,
0290 },
0291 {
0292 0, 0, 0, 0,
0293 LCD_WINCTRL1_FRM_16BPP565 |
0294 LCD_WINCTRL1_PO_16BPP,
0295 0,
0296 },
0297 {
0298 0, 0, 0, 0,
0299 LCD_WINCTRL1_FRM_32BPP |
0300 LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
0301 0,
0302 },
0303 {
0304 0, 0, 0, 0,
0305 LCD_WINCTRL1_FRM_16BPP565 |
0306 LCD_WINCTRL1_PO_16BPP |
0307 LCD_WINCTRL1_PIPE,
0308 0,
0309 },
0310 },
0311 },
0312
0313
0314
0315 };
0316
0317
0318
0319
0320
0321 struct panel_settings
0322 {
0323 const char name[25];
0324
0325 struct fb_monspecs monspecs;
0326
0327
0328 uint32 mode_screen;
0329 uint32 mode_horztiming;
0330 uint32 mode_verttiming;
0331 uint32 mode_clkcontrol;
0332 uint32 mode_pwmdiv;
0333 uint32 mode_pwmhi;
0334 uint32 mode_outmask;
0335 uint32 mode_fifoctrl;
0336 uint32 mode_backlight;
0337 uint32 lcdclk;
0338 #define Xres min_xres
0339 #define Yres min_yres
0340 u32 min_xres;
0341 u32 max_xres;
0342 u32 min_yres;
0343 u32 max_yres;
0344 };
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360 static struct panel_settings known_lcd_panels[] =
0361 {
0362 [0] = {
0363 .name = "QVGA_320x240",
0364 .monspecs = {
0365 .modedb = NULL,
0366 .modedb_len = 0,
0367 .hfmin = 30000,
0368 .hfmax = 70000,
0369 .vfmin = 60,
0370 .vfmax = 60,
0371 .dclkmin = 6000000,
0372 .dclkmax = 28000000,
0373 .input = FB_DISP_RGB,
0374 },
0375 .mode_screen = LCD_SCREEN_SX_N(320) |
0376 LCD_SCREEN_SY_N(240),
0377 .mode_horztiming = 0x00c4623b,
0378 .mode_verttiming = 0x00502814,
0379 .mode_clkcontrol = 0x00020002,
0380 .mode_pwmdiv = 0x00000000,
0381 .mode_pwmhi = 0x00000000,
0382 .mode_outmask = 0x00FFFFFF,
0383 .mode_fifoctrl = 0x2f2f2f2f,
0384 .mode_backlight = 0x00000000,
0385 .lcdclk = 96,
0386 320, 320,
0387 240, 240,
0388 },
0389
0390 [1] = {
0391 .name = "VGA_640x480",
0392 .monspecs = {
0393 .modedb = NULL,
0394 .modedb_len = 0,
0395 .hfmin = 30000,
0396 .hfmax = 70000,
0397 .vfmin = 60,
0398 .vfmax = 60,
0399 .dclkmin = 6000000,
0400 .dclkmax = 28000000,
0401 .input = FB_DISP_RGB,
0402 },
0403 .mode_screen = 0x13f9df80,
0404 .mode_horztiming = 0x003c5859,
0405 .mode_verttiming = 0x00741201,
0406 .mode_clkcontrol = 0x00020001,
0407 .mode_pwmdiv = 0x00000000,
0408 .mode_pwmhi = 0x00000000,
0409 .mode_outmask = 0x00FFFFFF,
0410 .mode_fifoctrl = 0x2f2f2f2f,
0411 .mode_backlight = 0x00000000,
0412 .lcdclk = 96,
0413 640, 480,
0414 640, 480,
0415 },
0416
0417 [2] = {
0418 .name = "SVGA_800x600",
0419 .monspecs = {
0420 .modedb = NULL,
0421 .modedb_len = 0,
0422 .hfmin = 30000,
0423 .hfmax = 70000,
0424 .vfmin = 60,
0425 .vfmax = 60,
0426 .dclkmin = 6000000,
0427 .dclkmax = 28000000,
0428 .input = FB_DISP_RGB,
0429 },
0430 .mode_screen = 0x18fa5780,
0431 .mode_horztiming = 0x00dc7e77,
0432 .mode_verttiming = 0x00584805,
0433 .mode_clkcontrol = 0x00020000,
0434 .mode_pwmdiv = 0x00000000,
0435 .mode_pwmhi = 0x00000000,
0436 .mode_outmask = 0x00FFFFFF,
0437 .mode_fifoctrl = 0x2f2f2f2f,
0438 .mode_backlight = 0x00000000,
0439 .lcdclk = 96,
0440 800, 800,
0441 600, 600,
0442 },
0443
0444 [3] = {
0445 .name = "XVGA_1024x768",
0446 .monspecs = {
0447 .modedb = NULL,
0448 .modedb_len = 0,
0449 .hfmin = 30000,
0450 .hfmax = 70000,
0451 .vfmin = 60,
0452 .vfmax = 60,
0453 .dclkmin = 6000000,
0454 .dclkmax = 28000000,
0455 .input = FB_DISP_RGB,
0456 },
0457 .mode_screen = 0x1ffaff80,
0458 .mode_horztiming = 0x007d0e57,
0459 .mode_verttiming = 0x00740a01,
0460 .mode_clkcontrol = 0x000A0000,
0461 .mode_pwmdiv = 0x00000000,
0462 .mode_pwmhi = 0x00000000,
0463 .mode_outmask = 0x00FFFFFF,
0464 .mode_fifoctrl = 0x2f2f2f2f,
0465 .mode_backlight = 0x00000000,
0466 .lcdclk = 72,
0467 1024, 1024,
0468 768, 768,
0469 },
0470
0471 [4] = {
0472 .name = "XVGA_1280x1024",
0473 .monspecs = {
0474 .modedb = NULL,
0475 .modedb_len = 0,
0476 .hfmin = 30000,
0477 .hfmax = 70000,
0478 .vfmin = 60,
0479 .vfmax = 60,
0480 .dclkmin = 6000000,
0481 .dclkmax = 28000000,
0482 .input = FB_DISP_RGB,
0483 },
0484 .mode_screen = 0x27fbff80,
0485 .mode_horztiming = 0x00cdb2c7,
0486 .mode_verttiming = 0x00600002,
0487 .mode_clkcontrol = 0x000A0000,
0488 .mode_pwmdiv = 0x00000000,
0489 .mode_pwmhi = 0x00000000,
0490 .mode_outmask = 0x00FFFFFF,
0491 .mode_fifoctrl = 0x2f2f2f2f,
0492 .mode_backlight = 0x00000000,
0493 .lcdclk = 120,
0494 1280, 1280,
0495 1024, 1024,
0496 },
0497
0498 [5] = {
0499 .name = "Samsung_1024x768_TFT",
0500 .monspecs = {
0501 .modedb = NULL,
0502 .modedb_len = 0,
0503 .hfmin = 30000,
0504 .hfmax = 70000,
0505 .vfmin = 60,
0506 .vfmax = 60,
0507 .dclkmin = 6000000,
0508 .dclkmax = 28000000,
0509 .input = FB_DISP_RGB,
0510 },
0511 .mode_screen = 0x1ffaff80,
0512 .mode_horztiming = 0x018cc677,
0513 .mode_verttiming = 0x00241217,
0514 .mode_clkcontrol = 0x00000000,
0515 .mode_pwmdiv = 0x8000063f,
0516 .mode_pwmhi = 0x03400000,
0517 .mode_outmask = 0x00FFFFFF,
0518 .mode_fifoctrl = 0x2f2f2f2f,
0519 .mode_backlight = 0x00000000,
0520 .lcdclk = 96,
0521 1024, 1024,
0522 768, 768,
0523 },
0524
0525 [6] = {
0526 .name = "Toshiba_640x480_TFT",
0527 .monspecs = {
0528 .modedb = NULL,
0529 .modedb_len = 0,
0530 .hfmin = 30000,
0531 .hfmax = 70000,
0532 .vfmin = 60,
0533 .vfmax = 60,
0534 .dclkmin = 6000000,
0535 .dclkmax = 28000000,
0536 .input = FB_DISP_RGB,
0537 },
0538 .mode_screen = LCD_SCREEN_SX_N(640) |
0539 LCD_SCREEN_SY_N(480),
0540 .mode_horztiming = LCD_HORZTIMING_HPW_N(96) |
0541 LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
0542 .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
0543 LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
0544 .mode_clkcontrol = 0x00000000,
0545 .mode_pwmdiv = 0x8000063f,
0546 .mode_pwmhi = 0x03400000,
0547 .mode_outmask = 0x00fcfcfc,
0548 .mode_fifoctrl = 0x2f2f2f2f,
0549 .mode_backlight = 0x00000000,
0550 .lcdclk = 96,
0551 640, 480,
0552 640, 480,
0553 },
0554
0555 [7] = {
0556 .name = "Sharp_320x240_TFT",
0557 .monspecs = {
0558 .modedb = NULL,
0559 .modedb_len = 0,
0560 .hfmin = 12500,
0561 .hfmax = 20000,
0562 .vfmin = 38,
0563 .vfmax = 81,
0564 .dclkmin = 4500000,
0565 .dclkmax = 6800000,
0566 .input = FB_DISP_RGB,
0567 },
0568 .mode_screen = LCD_SCREEN_SX_N(320) |
0569 LCD_SCREEN_SY_N(240),
0570 .mode_horztiming = LCD_HORZTIMING_HPW_N(60) |
0571 LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
0572 .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
0573 LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
0574 .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7),
0575 .mode_pwmdiv = 0x8000063f,
0576 .mode_pwmhi = 0x03400000,
0577 .mode_outmask = 0x00fcfcfc,
0578 .mode_fifoctrl = 0x2f2f2f2f,
0579 .mode_backlight = 0x00000000,
0580 .lcdclk = 96,
0581 320, 320,
0582 240, 240,
0583 },
0584
0585 [8] = {
0586 .name = "Toppoly_TD070WGCB2",
0587 .monspecs = {
0588 .modedb = NULL,
0589 .modedb_len = 0,
0590 .hfmin = 30000,
0591 .hfmax = 70000,
0592 .vfmin = 60,
0593 .vfmax = 60,
0594 .dclkmin = 6000000,
0595 .dclkmax = 28000000,
0596 .input = FB_DISP_RGB,
0597 },
0598 .mode_screen = LCD_SCREEN_SX_N(856) |
0599 LCD_SCREEN_SY_N(480),
0600 .mode_horztiming = LCD_HORZTIMING_HND2_N(43) |
0601 LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
0602 .mode_verttiming = LCD_VERTTIMING_VND2_N(20) |
0603 LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
0604 .mode_clkcontrol = 0x00020001,
0605 .mode_pwmdiv = 0x8000063f,
0606 .mode_pwmhi = 0x03400000,
0607 .mode_outmask = 0x00fcfcfc,
0608 .mode_fifoctrl = 0x2f2f2f2f,
0609 .mode_backlight = 0x00000000,
0610 .lcdclk = 96,
0611 856, 856,
0612 480, 480,
0613 },
0614 [9] = {
0615 .name = "DB1300_800x480",
0616 .monspecs = {
0617 .modedb = NULL,
0618 .modedb_len = 0,
0619 .hfmin = 30000,
0620 .hfmax = 70000,
0621 .vfmin = 60,
0622 .vfmax = 60,
0623 .dclkmin = 6000000,
0624 .dclkmax = 28000000,
0625 .input = FB_DISP_RGB,
0626 },
0627 .mode_screen = LCD_SCREEN_SX_N(800) |
0628 LCD_SCREEN_SY_N(480),
0629 .mode_horztiming = LCD_HORZTIMING_HPW_N(5) |
0630 LCD_HORZTIMING_HND1_N(16) |
0631 LCD_HORZTIMING_HND2_N(8),
0632 .mode_verttiming = LCD_VERTTIMING_VPW_N(4) |
0633 LCD_VERTTIMING_VND1_N(8) |
0634 LCD_VERTTIMING_VND2_N(5),
0635 .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(1) |
0636 LCD_CLKCONTROL_IV |
0637 LCD_CLKCONTROL_IH,
0638 .mode_pwmdiv = 0x00000000,
0639 .mode_pwmhi = 0x00000000,
0640 .mode_outmask = 0x00FFFFFF,
0641 .mode_fifoctrl = 0x2f2f2f2f,
0642 .mode_backlight = 0x00000000,
0643 .lcdclk = 96,
0644 800, 800,
0645 480, 480,
0646 },
0647 };
0648
0649 #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
0650
0651
0652
0653 static int winbpp (unsigned int winctrl1)
0654 {
0655 int bits = 0;
0656
0657
0658 switch (winctrl1 & LCD_WINCTRL1_FRM) {
0659 case LCD_WINCTRL1_FRM_1BPP:
0660 bits = 1;
0661 break;
0662 case LCD_WINCTRL1_FRM_2BPP:
0663 bits = 2;
0664 break;
0665 case LCD_WINCTRL1_FRM_4BPP:
0666 bits = 4;
0667 break;
0668 case LCD_WINCTRL1_FRM_8BPP:
0669 bits = 8;
0670 break;
0671 case LCD_WINCTRL1_FRM_12BPP:
0672 case LCD_WINCTRL1_FRM_16BPP655:
0673 case LCD_WINCTRL1_FRM_16BPP565:
0674 case LCD_WINCTRL1_FRM_16BPP556:
0675 case LCD_WINCTRL1_FRM_16BPPI1555:
0676 case LCD_WINCTRL1_FRM_16BPPI5551:
0677 case LCD_WINCTRL1_FRM_16BPPA1555:
0678 case LCD_WINCTRL1_FRM_16BPPA5551:
0679 bits = 16;
0680 break;
0681 case LCD_WINCTRL1_FRM_24BPP:
0682 case LCD_WINCTRL1_FRM_32BPP:
0683 bits = 32;
0684 break;
0685 }
0686
0687 return bits;
0688 }
0689
0690 static int fbinfo2index (struct fb_info *fb_info)
0691 {
0692 int i;
0693
0694 for (i = 0; i < device_count; ++i) {
0695 if (fb_info == _au1200fb_infos[i])
0696 return i;
0697 }
0698 printk("au1200fb: ERROR: fbinfo2index failed!\n");
0699 return -1;
0700 }
0701
0702 static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
0703 int xpos, int ypos)
0704 {
0705 uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
0706 int xsz, ysz;
0707
0708
0709
0710 winctrl0 = lcd->window[plane].winctrl0;
0711 winctrl1 = lcd->window[plane].winctrl1;
0712 winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
0713 winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
0714
0715
0716 xsz = win->w[plane].xres;
0717 ysz = win->w[plane].yres;
0718 if ((xpos + win->w[plane].xres) > panel->Xres) {
0719
0720 xsz = panel->Xres - xpos;
0721
0722 }
0723
0724 if ((ypos + win->w[plane].yres) > panel->Yres) {
0725
0726 ysz = panel->Yres - ypos;
0727
0728 }
0729
0730 if (xpos < 0) {
0731
0732 xsz = win->w[plane].xres + xpos;
0733 fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
0734 xpos = 0;
0735
0736 }
0737
0738 if (ypos < 0) {
0739
0740 ysz = win->w[plane].yres + ypos;
0741
0742 ypos = 0;
0743
0744 }
0745
0746
0747 win->w[plane].xpos = xpos;
0748 win->w[plane].ypos = ypos;
0749
0750 xsz -= 1;
0751 ysz -= 1;
0752 winctrl0 |= (xpos << 21);
0753 winctrl0 |= (ypos << 10);
0754 winctrl1 |= (xsz << 11);
0755 winctrl1 |= (ysz << 0);
0756
0757
0758 winenable = lcd->winenable & (1 << plane);
0759 wmb();
0760 lcd->winenable &= ~(1 << plane);
0761 lcd->window[plane].winctrl0 = winctrl0;
0762 lcd->window[plane].winctrl1 = winctrl1;
0763 lcd->window[plane].winbuf0 =
0764 lcd->window[plane].winbuf1 = fbdev->fb_phys;
0765 lcd->window[plane].winbufctrl = 0;
0766 lcd->winenable |= winenable;
0767 wmb();
0768
0769 return 0;
0770 }
0771
0772 static void au1200_setpanel(struct panel_settings *newpanel,
0773 struct au1200fb_platdata *pd)
0774 {
0775
0776
0777
0778 uint32 winenable;
0779
0780
0781 winenable = lcd->winenable;
0782 lcd->winenable = 0;
0783 wmb();
0784
0785
0786
0787 if (lcd->screen & LCD_SCREEN_SEN) {
0788
0789 lcd->intstatus = LCD_INT_SS;
0790 while ((lcd->intstatus & LCD_INT_SS) == 0)
0791 ;
0792
0793 lcd->screen &= ~LCD_SCREEN_SEN;
0794
0795 do {
0796 lcd->intstatus = lcd->intstatus;
0797 wmb();
0798
0799 } while ((lcd->intstatus & LCD_INT_SD) == 0);
0800
0801
0802
0803
0804
0805
0806 if (pd->panel_shutdown)
0807 pd->panel_shutdown();
0808 }
0809
0810
0811 if (newpanel == NULL)
0812 return;
0813
0814 panel = newpanel;
0815
0816 printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
0817
0818
0819
0820
0821 if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
0822 {
0823 struct clk *c = clk_get(NULL, "lcd_intclk");
0824 long r, pc = panel->lcdclk * 1000000;
0825
0826 if (!IS_ERR(c)) {
0827 r = clk_round_rate(c, pc);
0828 if ((pc - r) < (pc / 10)) {
0829 clk_set_rate(c, r);
0830 clk_prepare_enable(c);
0831 }
0832 clk_put(c);
0833 }
0834 }
0835
0836
0837
0838
0839 lcd->screen = panel->mode_screen;
0840 lcd->horztiming = panel->mode_horztiming;
0841 lcd->verttiming = panel->mode_verttiming;
0842 lcd->clkcontrol = panel->mode_clkcontrol;
0843 lcd->pwmdiv = panel->mode_pwmdiv;
0844 lcd->pwmhi = panel->mode_pwmhi;
0845 lcd->outmask = panel->mode_outmask;
0846 lcd->fifoctrl = panel->mode_fifoctrl;
0847 wmb();
0848
0849
0850
0851 #if 0
0852 au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
0853 au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
0854 au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
0855 au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
0856 #endif
0857 lcd->winenable = winenable;
0858
0859
0860
0861
0862 lcd->screen |= LCD_SCREEN_SEN;
0863 wmb();
0864
0865
0866 if (pd->panel_init)
0867 pd->panel_init();
0868
0869
0870 lcd->intenable = 0;
0871 lcd->intstatus = ~0;
0872 lcd->backcolor = win->mode_backcolor;
0873
0874
0875 lcd->colorkey = win->mode_colorkey;
0876 lcd->colorkeymsk = win->mode_colorkeymsk;
0877
0878
0879 lcd->hwc.cursorctrl = 0;
0880 lcd->hwc.cursorpos = 0;
0881 lcd->hwc.cursorcolor0 = 0;
0882 lcd->hwc.cursorcolor1 = 0;
0883 lcd->hwc.cursorcolor2 = 0;
0884 lcd->hwc.cursorcolor3 = 0;
0885
0886
0887 #if 0
0888 #define D(X) printk("%25s: %08X\n", #X, X)
0889 D(lcd->screen);
0890 D(lcd->horztiming);
0891 D(lcd->verttiming);
0892 D(lcd->clkcontrol);
0893 D(lcd->pwmdiv);
0894 D(lcd->pwmhi);
0895 D(lcd->outmask);
0896 D(lcd->fifoctrl);
0897 D(lcd->window[0].winctrl0);
0898 D(lcd->window[0].winctrl1);
0899 D(lcd->window[0].winctrl2);
0900 D(lcd->window[0].winbuf0);
0901 D(lcd->window[0].winbuf1);
0902 D(lcd->window[0].winbufctrl);
0903 D(lcd->window[1].winctrl0);
0904 D(lcd->window[1].winctrl1);
0905 D(lcd->window[1].winctrl2);
0906 D(lcd->window[1].winbuf0);
0907 D(lcd->window[1].winbuf1);
0908 D(lcd->window[1].winbufctrl);
0909 D(lcd->window[2].winctrl0);
0910 D(lcd->window[2].winctrl1);
0911 D(lcd->window[2].winctrl2);
0912 D(lcd->window[2].winbuf0);
0913 D(lcd->window[2].winbuf1);
0914 D(lcd->window[2].winbufctrl);
0915 D(lcd->window[3].winctrl0);
0916 D(lcd->window[3].winctrl1);
0917 D(lcd->window[3].winctrl2);
0918 D(lcd->window[3].winbuf0);
0919 D(lcd->window[3].winbuf1);
0920 D(lcd->window[3].winbufctrl);
0921 D(lcd->winenable);
0922 D(lcd->intenable);
0923 D(lcd->intstatus);
0924 D(lcd->backcolor);
0925 D(lcd->winenable);
0926 D(lcd->colorkey);
0927 D(lcd->colorkeymsk);
0928 D(lcd->hwc.cursorctrl);
0929 D(lcd->hwc.cursorpos);
0930 D(lcd->hwc.cursorcolor0);
0931 D(lcd->hwc.cursorcolor1);
0932 D(lcd->hwc.cursorcolor2);
0933 D(lcd->hwc.cursorcolor3);
0934 #endif
0935 }
0936
0937 static void au1200_setmode(struct au1200fb_device *fbdev)
0938 {
0939 int plane = fbdev->plane;
0940
0941 lcd->window[plane].winctrl1 = ( 0
0942 | LCD_WINCTRL1_PRI_N(plane)
0943 | win->w[plane].mode_winctrl1
0944 ) ;
0945
0946 au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
0947
0948 lcd->window[plane].winctrl2 = ( 0
0949 | LCD_WINCTRL2_CKMODE_00
0950 | LCD_WINCTRL2_DBM
0951 | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
0952 | LCD_WINCTRL2_SCX_1
0953 | LCD_WINCTRL2_SCY_1
0954 ) ;
0955 lcd->winenable |= win->w[plane].mode_winenable;
0956 wmb();
0957 }
0958
0959
0960
0961
0962
0963
0964
0965 #define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
0966
0967
0968 static struct fb_bitfield rgb_bitfields[][4] = {
0969
0970 [LCD_WINCTRL1_FRM_16BPP655 >> 25] =
0971 { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
0972
0973 [LCD_WINCTRL1_FRM_16BPP565 >> 25] =
0974 { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
0975
0976 [LCD_WINCTRL1_FRM_16BPP556 >> 25] =
0977 { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
0978
0979 [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
0980 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
0981
0982 [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
0983 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
0984
0985 [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
0986 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
0987
0988 [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
0989 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
0990
0991 [LCD_WINCTRL1_FRM_24BPP >> 25] =
0992 { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
0993
0994 [LCD_WINCTRL1_FRM_32BPP >> 25] =
0995 { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
0996 };
0997
0998
0999
1000
1001
1002 static void au1200fb_update_fbinfo(struct fb_info *fbi)
1003 {
1004
1005
1006
1007 if (panel_is_color(panel)) {
1008 if (fbi->var.bits_per_pixel <= 8) {
1009
1010 fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1011 fbi->fix.line_length = fbi->var.xres_virtual /
1012 (8/fbi->var.bits_per_pixel);
1013 } else {
1014
1015 fbi->fix.visual = FB_VISUAL_TRUECOLOR;
1016 fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
1017 }
1018 } else {
1019
1020 fbi->fix.visual = FB_VISUAL_MONO10;
1021 fbi->fix.line_length = fbi->var.xres_virtual / 8;
1022 }
1023
1024 fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
1025 print_dbg("line length: %d\n", fbi->fix.line_length);
1026 print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
1027 }
1028
1029
1030
1031
1032
1033
1034
1035
1036 static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
1037 struct fb_info *fbi)
1038 {
1039 struct au1200fb_device *fbdev = fbi->par;
1040 u32 pixclock;
1041 int screen_size, plane;
1042
1043 plane = fbdev->plane;
1044
1045
1046
1047 var->xres = win->w[plane].xres;
1048 var->yres = win->w[plane].yres;
1049
1050
1051 var->xres_virtual = var->xres;
1052 var->yres_virtual = var->yres;
1053
1054 var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
1055
1056 screen_size = var->xres_virtual * var->yres_virtual;
1057 if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
1058 else screen_size /= (8/var->bits_per_pixel);
1059
1060 if (fbdev->fb_len < screen_size)
1061 return -EINVAL;
1062
1063
1064
1065
1066
1067 pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
1068 pixclock = min3(pixclock, fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2);
1069
1070 if (AU1200_LCD_MAX_CLK % pixclock) {
1071 int diff = AU1200_LCD_MAX_CLK % pixclock;
1072 pixclock -= diff;
1073 }
1074
1075 var->pixclock = KHZ2PICOS(pixclock/1000);
1076 #if 0
1077 if (!panel_is_active(panel)) {
1078 int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
1079
1080 if (!panel_is_color(panel)
1081 && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
1082
1083 var->pixclock = KHZ2PICOS(6000);
1084 } else if (!pcd) {
1085
1086 var->pixclock = KHZ2PICOS(12000);
1087 }
1088 }
1089 #endif
1090
1091 switch (var->bits_per_pixel) {
1092 case 16:
1093 {
1094
1095
1096 int idx;
1097 idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1098 var->red = rgb_bitfields[idx][0];
1099 var->green = rgb_bitfields[idx][1];
1100 var->blue = rgb_bitfields[idx][2];
1101 var->transp = rgb_bitfields[idx][3];
1102 break;
1103 }
1104
1105 case 32:
1106 {
1107
1108
1109 int idx;
1110 idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1111 var->red = rgb_bitfields[idx][0];
1112 var->green = rgb_bitfields[idx][1];
1113 var->blue = rgb_bitfields[idx][2];
1114 var->transp = rgb_bitfields[idx][3];
1115 break;
1116 }
1117 default:
1118 print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
1119 return -EINVAL;
1120 }
1121
1122 return 0;
1123 }
1124
1125
1126
1127
1128
1129 static int au1200fb_fb_set_par(struct fb_info *fbi)
1130 {
1131 struct au1200fb_device *fbdev = fbi->par;
1132
1133 au1200fb_update_fbinfo(fbi);
1134 au1200_setmode(fbdev);
1135
1136 return 0;
1137 }
1138
1139
1140
1141
1142 static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
1143 unsigned blue, unsigned transp, struct fb_info *fbi)
1144 {
1145 volatile u32 *palette = lcd->palette;
1146 u32 value;
1147
1148 if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
1149 return -EINVAL;
1150
1151 if (fbi->var.grayscale) {
1152
1153 red = green = blue =
1154 (19595 * red + 38470 * green + 7471 * blue) >> 16;
1155 }
1156
1157 if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
1158
1159 if (regno > 16)
1160 return -EINVAL;
1161
1162 palette = (u32*) fbi->pseudo_palette;
1163
1164 red >>= (16 - fbi->var.red.length);
1165 green >>= (16 - fbi->var.green.length);
1166 blue >>= (16 - fbi->var.blue.length);
1167
1168 value = (red << fbi->var.red.offset) |
1169 (green << fbi->var.green.offset)|
1170 (blue << fbi->var.blue.offset);
1171 value &= 0xFFFF;
1172
1173 } else if (1 ) {
1174
1175 value = (red & 0xF800)|((green >> 5) &
1176 0x07E0)|((blue >> 11) & 0x001F);
1177 value &= 0xFFFF;
1178
1179 } else if (0 ) {
1180
1181 value = 0x1234;
1182 value &= 0xFFF;
1183 } else {
1184
1185 value = (green >> 12) & 0x000F;
1186 value &= 0xF;
1187 }
1188
1189 palette[regno] = value;
1190
1191 return 0;
1192 }
1193
1194
1195
1196
1197
1198 static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
1199 {
1200 struct au1200fb_device *fbdev = fbi->par;
1201
1202
1203 if (noblanking)
1204 return 0;
1205
1206 switch (blank_mode) {
1207
1208 case FB_BLANK_UNBLANK:
1209 case FB_BLANK_NORMAL:
1210
1211 au1200_setpanel(panel, fbdev->pd);
1212 break;
1213 case FB_BLANK_VSYNC_SUSPEND:
1214 case FB_BLANK_HSYNC_SUSPEND:
1215 case FB_BLANK_POWERDOWN:
1216
1217 au1200_setpanel(NULL, fbdev->pd);
1218 break;
1219 default:
1220 break;
1221
1222 }
1223
1224
1225 return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
1226 }
1227
1228
1229
1230
1231
1232 static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1233 {
1234 struct au1200fb_device *fbdev = info->par;
1235
1236 return dma_mmap_coherent(fbdev->dev, vma,
1237 fbdev->fb_mem, fbdev->fb_phys, fbdev->fb_len);
1238 }
1239
1240 static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
1241 {
1242
1243 unsigned int hi1, divider;
1244
1245
1246
1247 if (pdata->flags & SCREEN_BACKCOLOR)
1248 lcd->backcolor = pdata->backcolor;
1249
1250 if (pdata->flags & SCREEN_BRIGHTNESS) {
1251
1252
1253 if (pdata->brightness < 30) {
1254 pdata->brightness = 30;
1255 }
1256 divider = (lcd->pwmdiv & 0x3FFFF) + 1;
1257 hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
1258 lcd->pwmhi &= 0xFFFF;
1259 lcd->pwmhi |= (hi1 << 16);
1260 }
1261
1262 if (pdata->flags & SCREEN_COLORKEY)
1263 lcd->colorkey = pdata->colorkey;
1264
1265 if (pdata->flags & SCREEN_MASK)
1266 lcd->colorkeymsk = pdata->mask;
1267 wmb();
1268 }
1269
1270 static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
1271 {
1272 unsigned int hi1, divider;
1273
1274 pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
1275 pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
1276
1277 pdata->backcolor = lcd->backcolor;
1278 pdata->colorkey = lcd->colorkey;
1279 pdata->mask = lcd->colorkeymsk;
1280
1281
1282 hi1 = (lcd->pwmhi >> 16) + 1;
1283 divider = (lcd->pwmdiv & 0x3FFFF) + 1;
1284 pdata->brightness = ((hi1 << 8) / divider) - 1;
1285 wmb();
1286 }
1287
1288 static void set_window(unsigned int plane,
1289 struct au1200_lcd_window_regs_t *pdata)
1290 {
1291 unsigned int val, bpp;
1292
1293
1294 if (pdata->flags & WIN_POSITION) {
1295 val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
1296 LCD_WINCTRL0_OY);
1297 val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
1298 val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
1299 lcd->window[plane].winctrl0 = val;
1300 }
1301 if (pdata->flags & WIN_ALPHA_COLOR) {
1302 val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
1303 val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
1304 lcd->window[plane].winctrl0 = val;
1305 }
1306 if (pdata->flags & WIN_ALPHA_MODE) {
1307 val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
1308 val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
1309 lcd->window[plane].winctrl0 = val;
1310 }
1311
1312
1313 if (pdata->flags & WIN_PRIORITY) {
1314 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
1315 val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
1316 lcd->window[plane].winctrl1 = val;
1317 }
1318 if (pdata->flags & WIN_CHANNEL) {
1319 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
1320 val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
1321 lcd->window[plane].winctrl1 = val;
1322 }
1323 if (pdata->flags & WIN_BUFFER_FORMAT) {
1324 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
1325 val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
1326 lcd->window[plane].winctrl1 = val;
1327 }
1328 if (pdata->flags & WIN_COLOR_ORDER) {
1329 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
1330 val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
1331 lcd->window[plane].winctrl1 = val;
1332 }
1333 if (pdata->flags & WIN_PIXEL_ORDER) {
1334 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
1335 val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
1336 lcd->window[plane].winctrl1 = val;
1337 }
1338 if (pdata->flags & WIN_SIZE) {
1339 val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
1340 LCD_WINCTRL1_SZY);
1341 val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
1342 val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
1343 lcd->window[plane].winctrl1 = val;
1344
1345 bpp = winbpp(val) / 8;
1346 val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
1347 val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
1348 lcd->window[plane].winctrl2 = val;
1349 }
1350
1351
1352 if (pdata->flags & WIN_COLORKEY_MODE) {
1353 val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
1354 val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
1355 lcd->window[plane].winctrl2 = val;
1356 }
1357 if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
1358 val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
1359 val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
1360 lcd->window[plane].winctrl2 = val;
1361 }
1362 if (pdata->flags & WIN_RAM_ARRAY_MODE) {
1363 val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
1364 val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
1365 lcd->window[plane].winctrl2 = val;
1366 }
1367
1368
1369
1370 if (pdata->flags & WIN_BUFFER_SCALE) {
1371 val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
1372 LCD_WINCTRL2_SCY);
1373 val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
1374 val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
1375 lcd->window[plane].winctrl2 = val;
1376 }
1377
1378 if (pdata->flags & WIN_ENABLE) {
1379 val = lcd->winenable;
1380 val &= ~(1<<plane);
1381 val |= (pdata->enable & 1) << plane;
1382 lcd->winenable = val;
1383 }
1384 wmb();
1385 }
1386
1387 static void get_window(unsigned int plane,
1388 struct au1200_lcd_window_regs_t *pdata)
1389 {
1390
1391 pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
1392 pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
1393 pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
1394 pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
1395
1396
1397 pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
1398 pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
1399 pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1400 pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
1401 pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
1402 pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
1403 pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
1404
1405
1406 pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
1407 pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
1408 pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
1409
1410 pdata->enable = (lcd->winenable >> plane) & 1;
1411 wmb();
1412 }
1413
1414 static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
1415 unsigned long arg)
1416 {
1417 struct au1200fb_device *fbdev = info->par;
1418 int plane;
1419 int val;
1420
1421 plane = fbinfo2index(info);
1422 print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
1423
1424 if (cmd == AU1200_LCD_FB_IOCTL) {
1425 struct au1200_lcd_iodata_t iodata;
1426
1427 if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
1428 return -EFAULT;
1429
1430 print_dbg("FB IOCTL called\n");
1431
1432 switch (iodata.subcmd) {
1433 case AU1200_LCD_SET_SCREEN:
1434 print_dbg("AU1200_LCD_SET_SCREEN\n");
1435 set_global(cmd, &iodata.global);
1436 break;
1437
1438 case AU1200_LCD_GET_SCREEN:
1439 print_dbg("AU1200_LCD_GET_SCREEN\n");
1440 get_global(cmd, &iodata.global);
1441 break;
1442
1443 case AU1200_LCD_SET_WINDOW:
1444 print_dbg("AU1200_LCD_SET_WINDOW\n");
1445 set_window(plane, &iodata.window);
1446 break;
1447
1448 case AU1200_LCD_GET_WINDOW:
1449 print_dbg("AU1200_LCD_GET_WINDOW\n");
1450 get_window(plane, &iodata.window);
1451 break;
1452
1453 case AU1200_LCD_SET_PANEL:
1454 print_dbg("AU1200_LCD_SET_PANEL\n");
1455 if ((iodata.global.panel_choice >= 0) &&
1456 (iodata.global.panel_choice <
1457 NUM_PANELS))
1458 {
1459 struct panel_settings *newpanel;
1460 panel_index = iodata.global.panel_choice;
1461 newpanel = &known_lcd_panels[panel_index];
1462 au1200_setpanel(newpanel, fbdev->pd);
1463 }
1464 break;
1465
1466 case AU1200_LCD_GET_PANEL:
1467 print_dbg("AU1200_LCD_GET_PANEL\n");
1468 iodata.global.panel_choice = panel_index;
1469 break;
1470
1471 default:
1472 return -EINVAL;
1473 }
1474
1475 val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
1476 if (val) {
1477 print_dbg("error: could not copy %d bytes\n", val);
1478 return -EFAULT;
1479 }
1480 }
1481
1482 return 0;
1483 }
1484
1485
1486 static const struct fb_ops au1200fb_fb_ops = {
1487 .owner = THIS_MODULE,
1488 .fb_check_var = au1200fb_fb_check_var,
1489 .fb_set_par = au1200fb_fb_set_par,
1490 .fb_setcolreg = au1200fb_fb_setcolreg,
1491 .fb_blank = au1200fb_fb_blank,
1492 .fb_fillrect = sys_fillrect,
1493 .fb_copyarea = sys_copyarea,
1494 .fb_imageblit = sys_imageblit,
1495 .fb_read = fb_sys_read,
1496 .fb_write = fb_sys_write,
1497 .fb_sync = NULL,
1498 .fb_ioctl = au1200fb_ioctl,
1499 .fb_mmap = au1200fb_fb_mmap,
1500 };
1501
1502
1503
1504 static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
1505 {
1506
1507 lcd->intstatus = lcd->intstatus;
1508 wmb();
1509
1510 return IRQ_HANDLED;
1511 }
1512
1513
1514
1515
1516
1517 static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
1518 {
1519 struct fb_info *fbi = fbdev->fb_info;
1520 int bpp, ret;
1521
1522 fbi->fbops = &au1200fb_fb_ops;
1523
1524 bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
1525
1526
1527
1528
1529
1530 memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
1531
1532
1533
1534
1535 if (!fb_find_mode(&fbi->var,
1536 fbi,
1537 NULL,
1538 fbi->monspecs.modedb,
1539 fbi->monspecs.modedb_len,
1540 fbi->monspecs.modedb,
1541 bpp)) {
1542
1543 print_err("Cannot find valid mode for panel %s", panel->name);
1544 return -EFAULT;
1545 }
1546
1547 fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
1548 if (!fbi->pseudo_palette)
1549 return -ENOMEM;
1550
1551 ret = fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0);
1552 if (ret < 0) {
1553 print_err("Fail to allocate colormap (%d entries)",
1554 AU1200_LCD_NBR_PALETTE_ENTRIES);
1555 return ret;
1556 }
1557
1558 strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
1559 fbi->fix.smem_start = fbdev->fb_phys;
1560 fbi->fix.smem_len = fbdev->fb_len;
1561 fbi->fix.type = FB_TYPE_PACKED_PIXELS;
1562 fbi->fix.xpanstep = 0;
1563 fbi->fix.ypanstep = 0;
1564 fbi->fix.mmio_start = 0;
1565 fbi->fix.mmio_len = 0;
1566 fbi->fix.accel = FB_ACCEL_NONE;
1567
1568 fbi->screen_base = (char __iomem *) fbdev->fb_mem;
1569
1570 au1200fb_update_fbinfo(fbi);
1571
1572 return 0;
1573 }
1574
1575
1576
1577
1578 static int au1200fb_setup(struct au1200fb_platdata *pd)
1579 {
1580 char *options = NULL;
1581 char *this_opt, *endptr;
1582 int num_panels = ARRAY_SIZE(known_lcd_panels);
1583 int panel_idx = -1;
1584
1585 fb_get_options(DRIVER_NAME, &options);
1586
1587 if (!options)
1588 goto out;
1589
1590 while ((this_opt = strsep(&options, ",")) != NULL) {
1591
1592
1593 if (!strncmp(this_opt, "panel:", 6)) {
1594 int i;
1595 long int li;
1596 char *endptr;
1597 this_opt += 6;
1598
1599
1600 li = simple_strtol(this_opt, &endptr, 0);
1601 if (*endptr == '\0')
1602 panel_idx = (int)li;
1603 else if (strcmp(this_opt, "bs") == 0)
1604 panel_idx = pd->panel_index();
1605 else {
1606 for (i = 0; i < num_panels; i++) {
1607 if (!strcmp(this_opt,
1608 known_lcd_panels[i].name)) {
1609 panel_idx = i;
1610 break;
1611 }
1612 }
1613 }
1614 if ((panel_idx < 0) || (panel_idx >= num_panels))
1615 print_warn("Panel %s not supported!", this_opt);
1616 else
1617 panel_index = panel_idx;
1618
1619 } else if (strncmp(this_opt, "nohwcursor", 10) == 0)
1620 nohwcursor = 1;
1621 else if (strncmp(this_opt, "devices:", 8) == 0) {
1622 this_opt += 8;
1623 device_count = simple_strtol(this_opt, &endptr, 0);
1624 if ((device_count < 0) ||
1625 (device_count > MAX_DEVICE_COUNT))
1626 device_count = MAX_DEVICE_COUNT;
1627 } else if (strncmp(this_opt, "wincfg:", 7) == 0) {
1628 this_opt += 7;
1629 window_index = simple_strtol(this_opt, &endptr, 0);
1630 if ((window_index < 0) ||
1631 (window_index >= ARRAY_SIZE(windows)))
1632 window_index = DEFAULT_WINDOW_INDEX;
1633 } else if (strncmp(this_opt, "off", 3) == 0)
1634 return 1;
1635 else
1636 print_warn("Unsupported option \"%s\"", this_opt);
1637 }
1638
1639 out:
1640 return 0;
1641 }
1642
1643
1644 static int au1200fb_drv_probe(struct platform_device *dev)
1645 {
1646 struct au1200fb_device *fbdev;
1647 struct au1200fb_platdata *pd;
1648 struct fb_info *fbi = NULL;
1649 int bpp, plane, ret, irq;
1650
1651 print_info("" DRIVER_DESC "");
1652
1653 pd = dev->dev.platform_data;
1654 if (!pd)
1655 return -ENODEV;
1656
1657
1658 if (au1200fb_setup(pd))
1659 return -ENODEV;
1660
1661
1662 panel = &known_lcd_panels[panel_index];
1663 win = &windows[window_index];
1664
1665 printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
1666 printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
1667
1668 for (plane = 0; plane < device_count; ++plane) {
1669 bpp = winbpp(win->w[plane].mode_winctrl1);
1670 if (win->w[plane].xres == 0)
1671 win->w[plane].xres = panel->Xres;
1672 if (win->w[plane].yres == 0)
1673 win->w[plane].yres = panel->Yres;
1674
1675 fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
1676 &dev->dev);
1677 if (!fbi) {
1678 ret = -ENOMEM;
1679 goto failed;
1680 }
1681
1682 _au1200fb_infos[plane] = fbi;
1683 fbdev = fbi->par;
1684 fbdev->fb_info = fbi;
1685 fbdev->pd = pd;
1686 fbdev->dev = &dev->dev;
1687
1688 fbdev->plane = plane;
1689
1690
1691 fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
1692
1693 fbdev->fb_mem = dmam_alloc_attrs(&dev->dev,
1694 PAGE_ALIGN(fbdev->fb_len),
1695 &fbdev->fb_phys, GFP_KERNEL, 0);
1696 if (!fbdev->fb_mem) {
1697 print_err("fail to allocate framebuffer (size: %dK))",
1698 fbdev->fb_len / 1024);
1699 ret = -ENOMEM;
1700 goto failed;
1701 }
1702
1703 print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
1704 print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
1705
1706
1707 ret = au1200fb_init_fbinfo(fbdev);
1708 if (ret < 0)
1709 goto failed;
1710
1711
1712 ret = register_framebuffer(fbi);
1713 if (ret < 0) {
1714 print_err("cannot register new framebuffer");
1715 goto failed;
1716 }
1717
1718 au1200fb_fb_set_par(fbi);
1719
1720 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
1721 if (plane == 0)
1722 if (fb_prepare_logo(fbi, FB_ROTATE_UR)) {
1723
1724 fb_set_cmap(&fbi->cmap, fbi);
1725 fb_show_logo(fbi, FB_ROTATE_UR);
1726 }
1727 #endif
1728 }
1729
1730
1731 irq = platform_get_irq(dev, 0);
1732 ret = request_irq(irq, au1200fb_handle_irq,
1733 IRQF_SHARED, "lcd", (void *)dev);
1734 if (ret) {
1735 print_err("fail to request interrupt line %d (err: %d)",
1736 irq, ret);
1737 goto failed;
1738 }
1739
1740 platform_set_drvdata(dev, pd);
1741
1742
1743 au1200_setpanel(panel, pd);
1744
1745 return 0;
1746
1747 failed:
1748 for (plane = 0; plane < device_count; ++plane) {
1749 fbi = _au1200fb_infos[plane];
1750 if (!fbi)
1751 break;
1752
1753
1754 unregister_framebuffer(fbi);
1755 if (fbi->cmap.len != 0)
1756 fb_dealloc_cmap(&fbi->cmap);
1757 kfree(fbi->pseudo_palette);
1758
1759 framebuffer_release(fbi);
1760 _au1200fb_infos[plane] = NULL;
1761 }
1762 return ret;
1763 }
1764
1765 static int au1200fb_drv_remove(struct platform_device *dev)
1766 {
1767 struct au1200fb_platdata *pd = platform_get_drvdata(dev);
1768 struct fb_info *fbi;
1769 int plane;
1770
1771
1772 au1200_setpanel(NULL, pd);
1773
1774 for (plane = 0; plane < device_count; ++plane) {
1775 fbi = _au1200fb_infos[plane];
1776
1777
1778 unregister_framebuffer(fbi);
1779 if (fbi->cmap.len != 0)
1780 fb_dealloc_cmap(&fbi->cmap);
1781 kfree(fbi->pseudo_palette);
1782
1783 framebuffer_release(fbi);
1784 _au1200fb_infos[plane] = NULL;
1785 }
1786
1787 free_irq(platform_get_irq(dev, 0), (void *)dev);
1788
1789 return 0;
1790 }
1791
1792 #ifdef CONFIG_PM
1793 static int au1200fb_drv_suspend(struct device *dev)
1794 {
1795 struct au1200fb_platdata *pd = dev_get_drvdata(dev);
1796 au1200_setpanel(NULL, pd);
1797
1798 lcd->outmask = 0;
1799 wmb();
1800
1801 return 0;
1802 }
1803
1804 static int au1200fb_drv_resume(struct device *dev)
1805 {
1806 struct au1200fb_platdata *pd = dev_get_drvdata(dev);
1807 struct fb_info *fbi;
1808 int i;
1809
1810
1811 au1200_setpanel(panel, pd);
1812
1813 for (i = 0; i < device_count; i++) {
1814 fbi = _au1200fb_infos[i];
1815 au1200fb_fb_set_par(fbi);
1816 }
1817
1818 return 0;
1819 }
1820
1821 static const struct dev_pm_ops au1200fb_pmops = {
1822 .suspend = au1200fb_drv_suspend,
1823 .resume = au1200fb_drv_resume,
1824 .freeze = au1200fb_drv_suspend,
1825 .thaw = au1200fb_drv_resume,
1826 };
1827
1828 #define AU1200FB_PMOPS (&au1200fb_pmops)
1829
1830 #else
1831 #define AU1200FB_PMOPS NULL
1832 #endif
1833
1834 static struct platform_driver au1200fb_driver = {
1835 .driver = {
1836 .name = "au1200-lcd",
1837 .pm = AU1200FB_PMOPS,
1838 },
1839 .probe = au1200fb_drv_probe,
1840 .remove = au1200fb_drv_remove,
1841 };
1842 module_platform_driver(au1200fb_driver);
1843
1844 MODULE_DESCRIPTION(DRIVER_DESC);
1845 MODULE_LICENSE("GPL");