1/* Smedia Glamo 336x/337x driver 2 * 3 * (C) 2007-2008 by Openmoko, Inc. 4 * Author: Harald Welte <laforge@openmoko.org> 5 * All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 */ 22 23#include <linux/module.h> 24#include <linux/kernel.h> 25#include <linux/string.h> 26#include <linux/mm.h> 27#include <linux/delay.h> 28#include <linux/fb.h> 29#include <linux/init.h> 30#include <linux/platform_device.h> 31#include <linux/spinlock.h> 32#include <linux/io.h> 33#include <linux/mfd/glamo.h> 34 35#include <asm/div64.h> 36 37#ifdef CONFIG_PM 38#include <linux/pm.h> 39#endif 40 41#include <linux/glamofb.h> 42 43#include "glamo-regs.h" 44#include "glamo-core.h" 45 46static void glamofb_program_mode(struct glamofb_handle* glamo); 47 48struct glamofb_handle { 49 struct glamo_core *core; 50 struct fb_info *fb; 51 struct device *dev; 52 struct resource *reg; 53 struct resource *fb_res; 54 char __iomem *base; 55 struct glamo_fb_platform_data *mach_info; 56 char __iomem *cursor_addr; 57 int cursor_on; 58 u_int32_t pseudo_pal[16]; 59 spinlock_t lock_cmd; 60 int blank_mode; 61 int mode_set; /* 0 if the current display mode hasn't been set on the glamo */ 62 int output_enabled; /* 0 if the video output is disabled */ 63}; 64 65static void glamo_output_enable(struct glamofb_handle *gfb) { 66 struct glamo_core *gcore = gfb->core; 67 68 if (gfb->output_enabled) 69 return; 70 71 /* enable the pixel clock if off */ 72 glamo_engine_clkreg_set(gcore, 73 GLAMO_ENGINE_LCD, 74 GLAMO_CLOCK_LCD_EN_DCLK, 75 GLAMO_CLOCK_LCD_EN_DCLK); 76 77 gfb->output_enabled = 1; 78 if (!gfb->mode_set) 79 glamofb_program_mode(gfb); 80} 81 82static void glamo_output_disable(struct glamofb_handle *gfb) { 83 struct glamo_core *gcore = gfb->core; 84 85 if (!gfb->output_enabled) 86 return; 87 88 /* enable the pixel clock if off */ 89 glamo_engine_clkreg_set(gcore, 90 GLAMO_ENGINE_LCD, 91 GLAMO_CLOCK_LCD_EN_DCLK, 92 0); 93 94 gfb->output_enabled = 0; 95} 96 97 98static int reg_read(struct glamofb_handle *glamo, 99 u_int16_t reg) 100{ 101 int i = 0; 102 103 for (i = 0; i != 2; i++) 104 nop(); 105 106 return readw(glamo->base + reg); 107} 108 109static void reg_write(struct glamofb_handle *glamo, 110 u_int16_t reg, u_int16_t val) 111{ 112 int i = 0; 113 114 for (i = 0; i != 2; i++) 115 nop(); 116 117 writew(val, glamo->base + reg); 118} 119 120static struct glamo_script glamo_regs[] = { 121 { GLAMO_REG_LCD_MODE1, 0x0020 }, 122 /* no display rotation, no hardware cursor, no dither, no gamma, 123 * no retrace flip, vsync low-active, hsync low active, 124 * no TVCLK, no partial display, hw dest color from fb, 125 * no partial display mode, LCD1, software flip, */ 126 { GLAMO_REG_LCD_MODE2, 0x9020 }, 127 /* video flip, no ptr, no ptr, dhclk off, 128 * normal mode, no cpuif, 129 * res, serial msb first, single fb, no fr ctrl, 130 * cpu if bits all zero, no crc 131 * 0000 0000 0010 0000 */ 132 { GLAMO_REG_LCD_MODE3, 0x0b40 }, 133 /* src data rgb565, res, 18bit rgb666 134 * 000 01 011 0100 0000 */ 135 { GLAMO_REG_LCD_POLARITY, 0x440c }, 136 /* DE high active, no cpu/lcd if, cs0 force low, a0 low active, 137 * np cpu if, 9bit serial data, sclk rising edge latch data 138 * 01 00 0 100 0 000 01 0 0 */ 139 /* The following values assume 640*480@16bpp */ 140 { GLAMO_REG_LCD_A_BASE1, 0x0000 }, /* display A base address 15:0 */ 141 { GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */ 142 { GLAMO_REG_LCD_CURSOR_BASE1, 0xC000 }, /* cursor base address 15:0 */ 143 { GLAMO_REG_LCD_CURSOR_BASE2, 0x0012 }, /* cursor base address 22:16 */ 144 { GLAMO_REG_LCD_COMMAND2, 0x0000 }, /* display page A */ 145}; 146 147static int glamofb_run_script(struct glamofb_handle *glamo, 148 struct glamo_script *script, int len) 149{ 150 int i; 151 152 if (glamo->core->suspending) { 153 dev_err(&glamo->core->pdev->dev, 154 "IGNORING glamofb_run_script while " 155 "suspended\n"); 156 return -EBUSY; 157 } 158 159 for (i = 0; i < len; i++) { 160 struct glamo_script *line = &script[i]; 161 162 if (line->reg == 0xffff) 163 return 0; 164 else if (line->reg == 0xfffe) 165 msleep(line->val); 166 else 167 reg_write(glamo, script[i].reg, script[i].val); 168 } 169 170 return 0; 171} 172 173static int glamofb_check_var(struct fb_var_screeninfo *var, 174 struct fb_info *info) 175{ 176 struct glamofb_handle *glamo = info->par; 177 178 if (glamo->core->suspending) { 179 dev_err(&glamo->core->pdev->dev, 180 "IGNORING glamofb_check_var while " 181 "suspended\n"); 182 return -EBUSY; 183 } 184 185 if (var->bits_per_pixel != 16) 186 var->bits_per_pixel = 16; 187 188 var->height = glamo->mach_info->height; 189 var->width = glamo->mach_info->width; 190 191 /* FIXME: set rgb positions */ 192 switch (var->bits_per_pixel) { 193 case 16: 194 switch (reg_read(glamo, GLAMO_REG_LCD_MODE3) & 0xc000) { 195 case GLAMO_LCD_SRC_RGB565: 196 var->red.offset = 11; 197 var->green.offset = 5; 198 var->blue.offset = 0; 199 var->red.length = 5; 200 var->green.length = 6; 201 var->blue.length = 5; 202 var->transp.length = 0; 203 break; 204 case GLAMO_LCD_SRC_ARGB1555: 205 var->transp.offset = 15; 206 var->red.offset = 10; 207 var->green.offset = 5; 208 var->blue.offset = 0; 209 var->transp.length = 1; 210 var->red.length = 5; 211 var->green.length = 5; 212 var->blue.length = 5; 213 break; 214 case GLAMO_LCD_SRC_ARGB4444: 215 var->transp.offset = 12; 216 var->red.offset = 8; 217 var->green.offset = 4; 218 var->blue.offset = 0; 219 var->transp.length = 4; 220 var->red.length = 4; 221 var->green.length = 4; 222 var->blue.length = 4; 223 break; 224 } 225 break; 226 case 24: 227 case 32: 228 default: 229 /* The Smedia Glamo doesn't support anything but 16bit color */ 230 printk(KERN_ERR 231 "Smedia driver does not [yet?] support 24/32bpp\n"); 232 return -EINVAL; 233 } 234 235 return 0; 236} 237 238static void reg_set_bit_mask(struct glamofb_handle *glamo, 239 u_int16_t reg, u_int16_t mask, 240 u_int16_t val) 241{ 242 u_int16_t tmp; 243 244 val &= mask; 245 246 tmp = reg_read(glamo, reg); 247 tmp &= ~mask; 248 tmp |= val; 249 reg_write(glamo, reg, tmp); 250} 251 252#define GLAMO_LCD_WIDTH_MASK 0x03FF 253#define GLAMO_LCD_HEIGHT_MASK 0x03FF 254#define GLAMO_LCD_PITCH_MASK 0x07FE 255#define GLAMO_LCD_HV_TOTAL_MASK 0x03FF 256#define GLAMO_LCD_HV_RETR_START_MASK 0x03FF 257#define GLAMO_LCD_HV_RETR_END_MASK 0x03FF 258#define GLAMO_LCD_HV_RETR_DISP_START_MASK 0x03FF 259#define GLAMO_LCD_HV_RETR_DISP_END_MASK 0x03FF 260 261/* the caller has to enxure lock_cmd is held and we are in cmd mode */ 262static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation) 263{ 264 int glamo_rot; 265 266 if (glamo->core->suspending) { 267 dev_err(&glamo->core->pdev->dev, 268 "IGNORING rotate_lcd while " 269 "suspended\n"); 270 return; 271 } 272 273 switch (rotation) { 274 case FB_ROTATE_CW: 275 glamo_rot = GLAMO_LCD_ROT_MODE_90; 276 break; 277 case FB_ROTATE_UD: 278 glamo_rot = GLAMO_LCD_ROT_MODE_180; 279 break; 280 case FB_ROTATE_CCW: 281 glamo_rot = GLAMO_LCD_ROT_MODE_270; 282 break; 283 default: 284 glamo_rot = GLAMO_LCD_ROT_MODE_0; 285 break; 286 } 287 288 reg_set_bit_mask(glamo, 289 GLAMO_REG_LCD_WIDTH, 290 GLAMO_LCD_ROT_MODE_MASK, 291 glamo_rot); 292 reg_set_bit_mask(glamo, 293 GLAMO_REG_LCD_MODE1, 294 GLAMO_LCD_MODE1_ROTATE_EN, 295 (glamo_rot != GLAMO_LCD_ROT_MODE_0) ? 296 GLAMO_LCD_MODE1_ROTATE_EN : 0); 297} 298 299static void glamofb_program_mode(struct glamofb_handle* gfb) { 300 int sync, bp, disp, fp, total; 301 unsigned long flags; 302 struct glamo_core *gcore = gfb->core; 303 struct fb_var_screeninfo *var = &gfb->fb->var; 304 305 dev_dbg(&gcore->pdev->dev, 306 "glamofb_program_mode spin_lock_irqsave\n"); 307 spin_lock_irqsave(&gfb->lock_cmd, flags); 308 309 if (glamofb_cmd_mode(gfb, 1)) 310 goto out_unlock; 311 312 if (var->pixclock) 313 glamo_engine_reclock(gcore, 314 GLAMO_ENGINE_LCD, 315 (1000000000UL / gfb->fb->var.pixclock) * 1000); 316 317 reg_set_bit_mask(gfb, 318 GLAMO_REG_LCD_WIDTH, 319 GLAMO_LCD_WIDTH_MASK, 320 var->xres); 321 reg_set_bit_mask(gfb, 322 GLAMO_REG_LCD_HEIGHT, 323 GLAMO_LCD_HEIGHT_MASK, 324 var->yres); 325 reg_set_bit_mask(gfb, 326 GLAMO_REG_LCD_PITCH, 327 GLAMO_LCD_PITCH_MASK, 328 gfb->fb->fix.line_length); 329 330 /* honour the rotation request */ 331 __rotate_lcd(gfb, var->rotate); 332 333 /* update scannout timings */ 334 sync = 0; 335 bp = sync + var->hsync_len; 336 disp = bp + var->left_margin; 337 fp = disp + var->xres; 338 total = fp + var->right_margin; 339 340 reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_TOTAL, 341 GLAMO_LCD_HV_TOTAL_MASK, total); 342 reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_RETR_START, 343 GLAMO_LCD_HV_RETR_START_MASK, sync); 344 reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_RETR_END, 345 GLAMO_LCD_HV_RETR_END_MASK, bp); 346 reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_DISP_START, 347 GLAMO_LCD_HV_RETR_DISP_START_MASK, disp); 348 reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_DISP_END, 349 GLAMO_LCD_HV_RETR_DISP_END_MASK, fp); 350 351 sync = 0; 352 bp = sync + var->vsync_len; 353 disp = bp + var->upper_margin; 354 fp = disp + var->yres; 355 total = fp + var->lower_margin; 356 357 reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_TOTAL, 358 GLAMO_LCD_HV_TOTAL_MASK, total); 359 reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_RETR_START, 360 GLAMO_LCD_HV_RETR_START_MASK, sync); 361 reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_RETR_END, 362 GLAMO_LCD_HV_RETR_END_MASK, bp); 363 reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_DISP_START, 364 GLAMO_LCD_HV_RETR_DISP_START_MASK, disp); 365 reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_DISP_END, 366 GLAMO_LCD_HV_RETR_DISP_END_MASK, fp); 367 368 glamofb_cmd_mode(gfb, 0); 369 370 gfb->mode_set = 1; 371 372out_unlock: 373 dev_dbg(&gcore->pdev->dev, 374 "glamofb_program_mode spin_unlock_irqrestore\n"); 375 spin_unlock_irqrestore(&gfb->lock_cmd, flags); 376} 377 378 379static int glamofb_pan_display(struct fb_var_screeninfo *var, 380 struct fb_info *info) 381{ 382 return 0; 383} 384 385static struct fb_videomode *glamofb_find_mode(struct fb_info *info, 386 struct fb_var_screeninfo *var) { 387 struct glamofb_handle *glamo = info->par; 388 struct glamo_fb_platform_data *mach_info = glamo->mach_info; 389 struct fb_videomode *mode; 390 int i; 391 392 for(i = mach_info->num_modes, mode = mach_info->modes; i > 0; --i, ++mode) { 393 if (mode->xres == var->xres && 394 mode->yres == var->yres) 395 return mode; 396 } 397 398 return NULL; 399} 400 401static int glamofb_set_par(struct fb_info *info) 402{ 403 struct glamofb_handle *glamo = info->par; 404 struct fb_var_screeninfo *var = &info->var; 405 struct fb_videomode *mode; 406 407 if (glamo->core->suspending) { 408 dev_err(&glamo->core->pdev->dev, 409 "IGNORING glamofb_set_par while " 410 "suspended\n"); 411 return -EBUSY; 412 } 413 414 mode = glamofb_find_mode(info, var); 415 if (!mode) 416 return -EINVAL; 417 418 fb_videomode_to_var(var, mode); 419 420 info->mode = mode; 421 422 glamo->mode_set = 0; 423 424 switch(var->rotate) { 425 case FB_ROTATE_CW: 426 case FB_ROTATE_CCW: 427 info->fix.line_length = (var->yres * var->bits_per_pixel) / 8; 428 /* FIXME: Limit pixelclock */ 429 var->pixclock *= 2; 430 break; 431 default: 432 info->fix.line_length = (var->xres * var->bits_per_pixel) / 8; 433 break; 434 } 435 436 if(glamo->output_enabled) 437 glamofb_program_mode(glamo); 438 439 return 0; 440} 441 442static int glamofb_blank(int blank_mode, struct fb_info *info) 443{ 444 struct glamofb_handle *gfb = info->par; 445 446 dev_dbg(gfb->dev, "glamofb_blank(%u)\n", blank_mode); 447 448 switch (blank_mode) { 449 case FB_BLANK_VSYNC_SUSPEND: 450 case FB_BLANK_HSYNC_SUSPEND: 451 /* FIXME: add pdata hook/flag to indicate whether 452 * we should already switch off pixel clock here */ 453 break; 454 case FB_BLANK_POWERDOWN: 455 /* disable the pixel clock */ 456 glamo_output_disable(gfb); 457 gfb->blank_mode = blank_mode; 458 break; 459 case FB_BLANK_UNBLANK: 460 case FB_BLANK_NORMAL: 461 glamo_output_enable(gfb); 462 gfb->blank_mode = blank_mode; 463 break; 464 } 465 466 /* FIXME: once we have proper clock management in glamo-core, 467 * we can determine if other units need MCLK1 or the PLL, and 468 * disable it if not used. */ 469 return 0; 470} 471 472static inline unsigned int chan_to_field(unsigned int chan, 473 struct fb_bitfield *bf) 474{ 475 chan &= 0xffff; 476 chan >>= 16 - bf->length; 477 return chan << bf->offset; 478} 479 480static int glamofb_setcolreg(unsigned regno, 481 unsigned red, unsigned green, unsigned blue, 482 unsigned transp, struct fb_info *info) 483{ 484 struct glamofb_handle *glamo = info->par; 485 unsigned int val; 486 487 if (glamo->core->suspending) { 488 dev_err(&glamo->core->pdev->dev, 489 "IGNORING glamofb_set_par while " 490 "suspended\n"); 491 return -EBUSY; 492 } 493 494 switch (glamo->fb->fix.visual) { 495 case FB_VISUAL_TRUECOLOR: 496 case FB_VISUAL_DIRECTCOLOR: 497 /* true-colour, use pseuo-palette */ 498 499 if (regno < 16) { 500 u32 *pal = glamo->fb->pseudo_palette; 501 502 val = chan_to_field(red, &glamo->fb->var.red); 503 val |= chan_to_field(green, &glamo->fb->var.green); 504 val |= chan_to_field(blue, &glamo->fb->var.blue); 505 506 pal[regno] = val; 507 }; 508 break; 509 default: 510 return 1; /* unknown type */ 511 } 512 513 return 0; 514} 515 516static int glamofb_ioctl(struct fb_info *info, unsigned int cmd, 517 unsigned long arg) { 518 struct glamofb_handle *gfb = (struct glamofb_handle*)info->par; 519 struct glamo_core *gcore = gfb->core; 520 int retval = -ENOTTY; 521 522 switch (cmd) { 523 case GLAMOFB_ENGINE_ENABLE: 524 retval = glamo_engine_enable(gcore, arg); 525 break; 526 case GLAMOFB_ENGINE_DISABLE: 527 retval = glamo_engine_disable(gcore, arg); 528 break; 529 case GLAMOFB_ENGINE_RESET: 530 glamo_engine_reset(gcore, arg); 531 retval = 0; 532 break; 533 default: 534 break; 535 } 536 537 return retval; 538} 539 540 541#ifdef CONFIG_MFD_GLAMO_HWACCEL 542static inline void glamofb_vsync_wait(struct glamofb_handle *glamo, 543 int line, int size, int range) 544{ 545 int count[2]; 546 547 do { 548 count[0] = reg_read(glamo, GLAMO_REG_LCD_STATUS2) & 0x3ff; 549 count[1] = reg_read(glamo, GLAMO_REG_LCD_STATUS2) & 0x3ff; 550 } while (count[0] != count[1] || 551 (line < count[0] + range && 552 size > count[0] - range) || 553 count[0] < range * 2); 554} 555 556/* 557 * Enable/disable the hardware cursor mode altogether 558 * (for blinking and such, use glamofb_cursor()). 559 */ 560static void glamofb_cursor_onoff(struct glamofb_handle *glamo, int on) 561{ 562 int y, size; 563 564 if (glamo->cursor_on) { 565 y = reg_read(glamo, GLAMO_REG_LCD_CURSOR_Y_POS); 566 size = reg_read(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE); 567 568 glamofb_vsync_wait(glamo, y, size, 30); 569 } 570 571 reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1, 572 GLAMO_LCD_MODE1_CURSOR_EN, 573 on ? GLAMO_LCD_MODE1_CURSOR_EN : 0); 574 glamo->cursor_on = on; 575 576 /* Hide the cursor by default */ 577 reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE, 0); 578} 579 580static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor) 581{ 582 struct glamofb_handle *glamo = info->par; 583 unsigned long flags; 584 585 spin_lock_irqsave(&glamo->lock_cmd, flags); 586 587 reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE, 588 cursor->enable ? cursor->image.width : 0); 589 590 if (cursor->set & FB_CUR_SETPOS) { 591 reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_POS, 592 cursor->image.dx); 593 reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_POS, 594 cursor->image.dy); 595 } 596 597 if (cursor->set & FB_CUR_SETCMAP) { 598 uint16_t fg = glamo->pseudo_pal[cursor->image.fg_color]; 599 uint16_t bg = glamo->pseudo_pal[cursor->image.bg_color]; 600 601 reg_write(glamo, GLAMO_REG_LCD_CURSOR_FG_COLOR, fg); 602 reg_write(glamo, GLAMO_REG_LCD_CURSOR_BG_COLOR, bg); 603 reg_write(glamo, GLAMO_REG_LCD_CURSOR_DST_COLOR, fg); 604 } 605 606 if (cursor->set & FB_CUR_SETHOT) 607 reg_write(glamo, GLAMO_REG_LCD_CURSOR_PRESET, 608 (cursor->hot.x << 8) | cursor->hot.y); 609 610 if ((cursor->set & FB_CUR_SETSIZE) || 611 (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE))) { 612 int x, y, pitch, op; 613 const uint8_t *pcol = cursor->image.data; 614 const uint8_t *pmsk = cursor->mask; 615 uint8_t __iomem *dst = glamo->cursor_addr; 616 uint8_t dcol = 0; 617 uint8_t dmsk = 0; 618 uint8_t byte = 0; 619 620 if (cursor->image.depth > 1) { 621 spin_unlock_irqrestore(&glamo->lock_cmd, flags); 622 return -EINVAL; 623 } 624 625 pitch = ((cursor->image.width + 7) >> 2) & ~1; 626 reg_write(glamo, GLAMO_REG_LCD_CURSOR_PITCH, 627 pitch); 628 reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE, 629 cursor->image.height); 630 631 for (y = 0; y < cursor->image.height; y++) { 632 byte = 0; 633 for (x = 0; x < cursor->image.width; x++) { 634 if ((x % 8) == 0) { 635 dcol = *pcol++; 636 dmsk = *pmsk++; 637 } else { 638 dcol >>= 1; 639 dmsk >>= 1; 640 } 641 642 if (cursor->rop == ROP_COPY) 643 op = (dmsk & 1) ? 644 (dcol & 1) ? 1 : 3 : 0; 645 else 646 op = ((dmsk & 1) << 1) | 647 ((dcol & 1) << 0); 648 byte |= op << ((x & 3) << 1); 649 650 if (x % 4 == 3) { 651 writeb(byte, dst + x / 4); 652 byte = 0; 653 } 654 } 655 if (x % 4) { 656 writeb(byte, dst + x / 4); 657 byte = 0; 658 } 659 660 dst += pitch; 661 } 662 } 663 664 spin_unlock_irqrestore(&glamo->lock_cmd, flags); 665 666 return 0; 667} 668#endif 669 670static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb) 671{ 672 /* DGCMdQempty -- 1 == command queue is empty */ 673 return reg_read(gfb, GLAMO_REG_LCD_STATUS1) & (1 << 15); 674} 675 676/* call holding gfb->lock_cmd when locking, until you unlock */ 677int glamofb_cmd_mode(struct glamofb_handle *gfb, int on) 678{ 679 int timeout = 2000000; 680 681 if (gfb->core->suspending) { 682 dev_err(&gfb->core->pdev->dev, 683 "IGNORING glamofb_cmd_mode while " 684 "suspended\n"); 685 return -EBUSY; 686 } 687 688 dev_dbg(gfb->dev, "glamofb_cmd_mode(gfb=%p, on=%d)\n", gfb, on); 689 if (on) { 690 dev_dbg(gfb->dev, "%s: waiting for cmdq empty: ", 691 __func__); 692 while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) 693 cpu_relax(); 694 if (timeout < 0) { 695 printk(KERN_ERR"*************" 696 "glamofb cmd_queue never got empty" 697 "*************\n"); 698 return -EIO; 699 } 700 dev_dbg(gfb->dev, "empty!\n"); 701 702 /* display the entire frame then switch to command */ 703 reg_write(gfb, GLAMO_REG_LCD_COMMAND1, 704 GLAMO_LCD_CMD_TYPE_DISP | 705 GLAMO_LCD_CMD_DATA_FIRE_VSYNC); 706 707 /* wait until lcd idle */ 708 dev_dbg(gfb->dev, "waiting for lcd idle: "); 709 timeout = 2000000; 710 while ((!reg_read(gfb, GLAMO_REG_LCD_STATUS2) & (1 << 12)) && 711 (timeout--)) 712 cpu_relax(); 713 if (timeout < 0) { 714 printk(KERN_ERR"*************" 715 "glamofb lcd never idle" 716 "*************\n"); 717 return -EIO; 718 } 719 720 mdelay(100); 721 722 dev_dbg(gfb->dev, "cmd mode entered\n"); 723 724 } else { 725 /* RGB interface needs vsync/hsync */ 726 if (reg_read(gfb, GLAMO_REG_LCD_MODE3) & GLAMO_LCD_MODE3_RGB) 727 reg_write(gfb, GLAMO_REG_LCD_COMMAND1, 728 GLAMO_LCD_CMD_TYPE_DISP | 729 GLAMO_LCD_CMD_DATA_DISP_SYNC); 730 731 reg_write(gfb, GLAMO_REG_LCD_COMMAND1, 732 GLAMO_LCD_CMD_TYPE_DISP | 733 GLAMO_LCD_CMD_DATA_DISP_FIRE); 734 } 735 736 return 0; 737} 738EXPORT_SYMBOL_GPL(glamofb_cmd_mode); 739 740 741int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val) 742{ 743 int timeout = 200000; 744 745 if (gfb->core->suspending) { 746 dev_err(&gfb->core->pdev->dev, 747 "IGNORING glamofb_cmd_write while " 748 "suspended\n"); 749 return -EBUSY; 750 } 751 752 dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __func__); 753 while ((!glamofb_cmdq_empty(gfb)) && (timeout--)) 754 yield(); 755 if (timeout < 0) { 756 printk(KERN_ERR"*************" 757 "glamofb cmd_queue never got empty" 758 "*************\n"); 759 return 1; 760 } 761 dev_dbg(gfb->dev, "idle, writing 0x%04x\n", val); 762 763 reg_write(gfb, GLAMO_REG_LCD_COMMAND1, val); 764 765 return 0; 766} 767EXPORT_SYMBOL_GPL(glamofb_cmd_write); 768 769static struct fb_ops glamofb_ops = { 770 .owner = THIS_MODULE, 771 .fb_check_var = glamofb_check_var, 772 .fb_pan_display = glamofb_pan_display, 773 .fb_set_par = glamofb_set_par, 774 .fb_blank = glamofb_blank, 775 .fb_setcolreg = glamofb_setcolreg, 776 .fb_ioctl = glamofb_ioctl, 777#ifdef CONFIG_MFD_GLAMO_HWACCEL 778 .fb_cursor = glamofb_cursor, 779#endif 780 .fb_fillrect = cfb_fillrect, 781 .fb_copyarea = cfb_copyarea, 782 .fb_imageblit = cfb_imageblit, 783}; 784 785static int glamofb_init_regs(struct glamofb_handle *glamo) 786{ 787 struct fb_info *info = glamo->fb; 788 789 glamofb_check_var(&info->var, info); 790 glamofb_run_script(glamo, glamo_regs, ARRAY_SIZE(glamo_regs)); 791 glamofb_set_par(info); 792 793 return 0; 794} 795 796static int __init glamofb_probe(struct platform_device *pdev) 797{ 798 int rc = -EIO; 799 struct fb_info *fbinfo; 800 struct glamofb_handle *glamofb; 801 struct glamo_core *core = dev_get_drvdata(pdev->dev.parent); 802 struct glamo_fb_platform_data *mach_info; 803 804 printk(KERN_INFO "SMEDIA Glamo frame buffer driver (C) 2007 " 805 "Openmoko, Inc.\n"); 806 807 if (!core->pdata || !core->pdata->fb_data) 808 return -ENOENT; 809 810 811 fbinfo = framebuffer_alloc(sizeof(struct glamofb_handle), &pdev->dev); 812 if (!fbinfo) 813 return -ENOMEM; 814 815 816 glamofb = fbinfo->par; 817 glamofb->fb = fbinfo; 818 glamofb->dev = &pdev->dev; 819 820 glamofb->blank_mode = FB_BLANK_POWERDOWN; 821 822 strcpy(fbinfo->fix.id, "SMedia Glamo"); 823 824 glamofb->reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, 825 "glamo-fb-regs"); 826 if (!glamofb->reg) { 827 dev_err(&pdev->dev, "platform device with no registers?\n"); 828 rc = -ENOENT; 829 goto out_free; 830 } 831 832 glamofb->fb_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 833 "glamo-fb-mem"); 834 if (!glamofb->fb_res) { 835 dev_err(&pdev->dev, "platform device with no memory ?\n"); 836 rc = -ENOENT; 837 goto out_free; 838 } 839 840 glamofb->reg = request_mem_region(glamofb->reg->start, 841 resource_size(glamofb->reg), pdev->name); 842 if (!glamofb->reg) { 843 dev_err(&pdev->dev, "failed to request mmio region\n"); 844 goto out_free; 845 } 846 847 glamofb->fb_res = request_mem_region(glamofb->fb_res->start, 848 resource_size(glamofb->fb_res), 849 pdev->name); 850 if (!glamofb->fb_res) { 851 dev_err(&pdev->dev, "failed to request vram region\n"); 852 goto out_release_reg; 853 } 854 855 /* we want to remap only the registers required for this core 856 * driver. */ 857 glamofb->base = ioremap_nocache(glamofb->reg->start, resource_size(glamofb->reg)); 858 if (!glamofb->base) { 859 dev_err(&pdev->dev, "failed to ioremap() mmio memory\n"); 860 goto out_release_fb; 861 } 862 863 fbinfo->fix.smem_start = (unsigned long) glamofb->fb_res->start; 864 fbinfo->fix.smem_len = (__u32) resource_size(glamofb->fb_res); 865 866 fbinfo->screen_base = ioremap(glamofb->fb_res->start, 867 resource_size(glamofb->fb_res)); 868 if (!fbinfo->screen_base) { 869 dev_err(&pdev->dev, "failed to ioremap() vram memory\n"); 870 goto out_release_fb; 871 } 872 glamofb->cursor_addr = fbinfo->screen_base + 0x12C000; 873 874 platform_set_drvdata(pdev, glamofb); 875 876 mach_info = core->pdata->fb_data; 877 glamofb->core = core; 878 glamofb->mach_info = mach_info; 879 880 fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; 881 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; 882 fbinfo->fix.type_aux = 0; 883 fbinfo->fix.xpanstep = 0; 884 fbinfo->fix.ypanstep = 0; 885 fbinfo->fix.ywrapstep = 0; 886 fbinfo->fix.accel = FB_ACCEL_GLAMO; 887 888 889 fbinfo->fbops = &glamofb_ops; 890 fbinfo->flags = FBINFO_FLAG_DEFAULT; 891 fbinfo->pseudo_palette = &glamofb->pseudo_pal; 892 893 fbinfo->mode = mach_info->modes; 894 fb_videomode_to_var(&fbinfo->var, fbinfo->mode); 895 fbinfo->var.bits_per_pixel = 16; 896 fbinfo->var.nonstd = 0; 897 fbinfo->var.activate = FB_ACTIVATE_NOW; 898 fbinfo->var.height = mach_info->height; 899 fbinfo->var.width = mach_info->width; 900 fbinfo->var.accel_flags = 0; 901 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; 902 903 glamo_engine_enable(core, GLAMO_ENGINE_LCD); 904 glamo_engine_reset(core, GLAMO_ENGINE_LCD); 905 glamofb->output_enabled = 1; 906 glamofb->mode_set = 1; 907 908 dev_info(&pdev->dev, "spin_lock_init\n"); 909 spin_lock_init(&glamofb->lock_cmd); 910 glamofb_init_regs(glamofb); 911#ifdef CONFIG_MFD_GLAMO_HWACCEL 912 glamofb_cursor_onoff(glamofb, 1); 913#endif 914 915 fb_videomode_to_modelist(mach_info->modes, mach_info->num_modes, 916 &fbinfo->modelist); 917 918 rc = register_framebuffer(fbinfo); 919 if (rc < 0) { 920 dev_err(&pdev->dev, "failed to register framebuffer\n"); 921 goto out_unmap_fb; 922 } 923 924 printk(KERN_INFO "fb%d: %s frame buffer device\n", 925 fbinfo->node, fbinfo->fix.id); 926 927 return 0; 928 929out_unmap_fb: 930 iounmap(fbinfo->screen_base); 931 iounmap(glamofb->base); 932out_release_fb: 933 release_mem_region(glamofb->fb_res->start, resource_size(glamofb->fb_res)); 934out_release_reg: 935 release_mem_region(glamofb->reg->start, resource_size(glamofb->reg)); 936out_free: 937 framebuffer_release(fbinfo); 938 return rc; 939} 940 941static int glamofb_remove(struct platform_device *pdev) 942{ 943 struct glamofb_handle *glamofb = platform_get_drvdata(pdev); 944 945 platform_set_drvdata(pdev, NULL); 946 iounmap(glamofb->base); 947 release_mem_region(glamofb->reg->start, resource_size(glamofb->reg)); 948 kfree(glamofb); 949 950 return 0; 951} 952 953#ifdef CONFIG_PM 954 955static int glamofb_suspend(struct device *dev) 956{ 957 struct glamofb_handle *gfb = dev_get_drvdata(dev); 958 959 /* we need to stop anything touching our framebuffer */ 960 fb_set_suspend(gfb->fb, 1); 961 962 /* seriously -- nobody is allowed to touch glamo memory when we 963 * are suspended or we lock on nWAIT 964 */ 965 /* iounmap(gfb->fb->screen_base); */ 966 967 return 0; 968} 969 970static int glamofb_resume(struct device *dev) 971{ 972 struct glamofb_handle *gfb = dev_get_drvdata(dev); 973 974 /* OK let's allow framebuffer ops again */ 975 /* gfb->fb->screen_base = ioremap(gfb->fb_res->start, 976 resource_size(gfb->fb_res)); */ 977 glamo_engine_enable(gfb->core, GLAMO_ENGINE_LCD); 978 glamo_engine_reset(gfb->core, GLAMO_ENGINE_LCD); 979 980 glamofb_init_regs(gfb); 981#ifdef CONFIG_MFD_GLAMO_HWACCEL 982 glamofb_cursor_onoff(gfb, 1); 983#endif 984 985 fb_set_suspend(gfb->fb, 0); 986 987 return 0; 988} 989 990static struct dev_pm_ops glamofb_pm_ops = { 991 .suspend = glamofb_suspend, 992 .resume = glamofb_resume, 993}; 994 995#define GLAMOFB_PM_OPS (&glamofb_pm_ops) 996 997#else 998#define GLAMOFB_PM_OPS NULL 999#endif 1000 1001static struct platform_driver glamofb_driver = { 1002 .probe = glamofb_probe, 1003 .remove = glamofb_remove, 1004 .driver = { 1005 .name = "glamo-fb", 1006 .owner = THIS_MODULE, 1007 .pm = GLAMOFB_PM_OPS 1008 }, 1009}; 1010 1011static int __devinit glamofb_init(void) 1012{ 1013 return platform_driver_register(&glamofb_driver); 1014} 1015 1016static void __exit glamofb_cleanup(void) 1017{ 1018 platform_driver_unregister(&glamofb_driver); 1019} 1020 1021module_init(glamofb_init); 1022module_exit(glamofb_cleanup); 1023 1024MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); 1025MODULE_DESCRIPTION("Smedia Glamo 336x/337x framebuffer driver"); 1026MODULE_LICENSE("GPL"); 1027