Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc9 1914 lines 49 kB view raw
1/* linux/drivers/video/s3c-fb.c 2 * 3 * Copyright 2008 Openmoko Inc. 4 * Copyright 2008-2010 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk> 6 * http://armlinux.simtec.co.uk/ 7 * 8 * Samsung SoC Framebuffer driver 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software FoundatIon. 13*/ 14 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/platform_device.h> 18#include <linux/dma-mapping.h> 19#include <linux/slab.h> 20#include <linux/init.h> 21#include <linux/clk.h> 22#include <linux/fb.h> 23#include <linux/io.h> 24#include <linux/uaccess.h> 25#include <linux/interrupt.h> 26#include <linux/pm_runtime.h> 27 28#include <mach/map.h> 29#include <plat/regs-fb-v4.h> 30#include <plat/fb.h> 31 32/* This driver will export a number of framebuffer interfaces depending 33 * on the configuration passed in via the platform data. Each fb instance 34 * maps to a hardware window. Currently there is no support for runtime 35 * setting of the alpha-blending functions that each window has, so only 36 * window 0 is actually useful. 37 * 38 * Window 0 is treated specially, it is used for the basis of the LCD 39 * output timings and as the control for the output power-down state. 40*/ 41 42/* note, the previous use of <mach/regs-fb.h> to get platform specific data 43 * has been replaced by using the platform device name to pick the correct 44 * configuration data for the system. 45*/ 46 47#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE 48#undef writel 49#define writel(v, r) do { \ 50 printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ 51 __raw_writel(v, r); } while (0) 52#endif /* FB_S3C_DEBUG_REGWRITE */ 53 54/* irq_flags bits */ 55#define S3C_FB_VSYNC_IRQ_EN 0 56 57#define VSYNC_TIMEOUT_MSEC 50 58 59struct s3c_fb; 60 61#define VALID_BPP(x) (1 << ((x) - 1)) 62 63#define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride)) 64#define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00) 65#define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04) 66#define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08) 67#define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C) 68 69/** 70 * struct s3c_fb_variant - fb variant information 71 * @is_2443: Set if S3C2443/S3C2416 style hardware. 72 * @nr_windows: The number of windows. 73 * @vidtcon: The base for the VIDTCONx registers 74 * @wincon: The base for the WINxCON registers. 75 * @winmap: The base for the WINxMAP registers. 76 * @keycon: The abse for the WxKEYCON registers. 77 * @buf_start: Offset of buffer start registers. 78 * @buf_size: Offset of buffer size registers. 79 * @buf_end: Offset of buffer end registers. 80 * @osd: The base for the OSD registers. 81 * @palette: Address of palette memory, or 0 if none. 82 * @has_prtcon: Set if has PRTCON register. 83 * @has_shadowcon: Set if has SHADOWCON register. 84 */ 85struct s3c_fb_variant { 86 unsigned int is_2443:1; 87 unsigned short nr_windows; 88 unsigned short vidtcon; 89 unsigned short wincon; 90 unsigned short winmap; 91 unsigned short keycon; 92 unsigned short buf_start; 93 unsigned short buf_end; 94 unsigned short buf_size; 95 unsigned short osd; 96 unsigned short osd_stride; 97 unsigned short palette[S3C_FB_MAX_WIN]; 98 99 unsigned int has_prtcon:1; 100 unsigned int has_shadowcon:1; 101}; 102 103/** 104 * struct s3c_fb_win_variant 105 * @has_osd_c: Set if has OSD C register. 106 * @has_osd_d: Set if has OSD D register. 107 * @has_osd_alpha: Set if can change alpha transparency for a window. 108 * @palette_sz: Size of palette in entries. 109 * @palette_16bpp: Set if palette is 16bits wide. 110 * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate 111 * register is located at the given offset from OSD_BASE. 112 * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel. 113 * 114 * valid_bpp bit x is set if (x+1)BPP is supported. 115 */ 116struct s3c_fb_win_variant { 117 unsigned int has_osd_c:1; 118 unsigned int has_osd_d:1; 119 unsigned int has_osd_alpha:1; 120 unsigned int palette_16bpp:1; 121 unsigned short osd_size_off; 122 unsigned short palette_sz; 123 u32 valid_bpp; 124}; 125 126/** 127 * struct s3c_fb_driverdata - per-device type driver data for init time. 128 * @variant: The variant information for this driver. 129 * @win: The window information for each window. 130 */ 131struct s3c_fb_driverdata { 132 struct s3c_fb_variant variant; 133 struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN]; 134}; 135 136/** 137 * struct s3c_fb_palette - palette information 138 * @r: Red bitfield. 139 * @g: Green bitfield. 140 * @b: Blue bitfield. 141 * @a: Alpha bitfield. 142 */ 143struct s3c_fb_palette { 144 struct fb_bitfield r; 145 struct fb_bitfield g; 146 struct fb_bitfield b; 147 struct fb_bitfield a; 148}; 149 150/** 151 * struct s3c_fb_win - per window private data for each framebuffer. 152 * @windata: The platform data supplied for the window configuration. 153 * @parent: The hardware that this window is part of. 154 * @fbinfo: Pointer pack to the framebuffer info for this window. 155 * @varint: The variant information for this window. 156 * @palette_buffer: Buffer/cache to hold palette entries. 157 * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/ 158 * @index: The window number of this window. 159 * @palette: The bitfields for changing r/g/b into a hardware palette entry. 160 */ 161struct s3c_fb_win { 162 struct s3c_fb_pd_win *windata; 163 struct s3c_fb *parent; 164 struct fb_info *fbinfo; 165 struct s3c_fb_palette palette; 166 struct s3c_fb_win_variant variant; 167 168 u32 *palette_buffer; 169 u32 pseudo_palette[16]; 170 unsigned int index; 171}; 172 173/** 174 * struct s3c_fb_vsync - vsync information 175 * @wait: a queue for processes waiting for vsync 176 * @count: vsync interrupt count 177 */ 178struct s3c_fb_vsync { 179 wait_queue_head_t wait; 180 unsigned int count; 181}; 182 183/** 184 * struct s3c_fb - overall hardware state of the hardware 185 * @slock: The spinlock protection for this data sturcture. 186 * @dev: The device that we bound to, for printing, etc. 187 * @regs_res: The resource we claimed for the IO registers. 188 * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. 189 * @regs: The mapped hardware registers. 190 * @variant: Variant information for this hardware. 191 * @enabled: A bitmask of enabled hardware windows. 192 * @pdata: The platform configuration data passed with the device. 193 * @windows: The hardware windows that have been claimed. 194 * @irq_no: IRQ line number 195 * @irq_flags: irq flags 196 * @vsync_info: VSYNC-related information (count, queues...) 197 */ 198struct s3c_fb { 199 spinlock_t slock; 200 struct device *dev; 201 struct resource *regs_res; 202 struct clk *bus_clk; 203 void __iomem *regs; 204 struct s3c_fb_variant variant; 205 206 unsigned char enabled; 207 208 struct s3c_fb_platdata *pdata; 209 struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; 210 211 int irq_no; 212 unsigned long irq_flags; 213 struct s3c_fb_vsync vsync_info; 214}; 215 216/** 217 * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode. 218 * @win: The device window. 219 * @bpp: The bit depth. 220 */ 221static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp) 222{ 223 return win->variant.valid_bpp & VALID_BPP(bpp); 224} 225 226/** 227 * s3c_fb_check_var() - framebuffer layer request to verify a given mode. 228 * @var: The screen information to verify. 229 * @info: The framebuffer device. 230 * 231 * Framebuffer layer call to verify the given information and allow us to 232 * update various information depending on the hardware capabilities. 233 */ 234static int s3c_fb_check_var(struct fb_var_screeninfo *var, 235 struct fb_info *info) 236{ 237 struct s3c_fb_win *win = info->par; 238 struct s3c_fb *sfb = win->parent; 239 240 dev_dbg(sfb->dev, "checking parameters\n"); 241 242 var->xres_virtual = max(var->xres_virtual, var->xres); 243 var->yres_virtual = max(var->yres_virtual, var->yres); 244 245 if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { 246 dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", 247 win->index, var->bits_per_pixel); 248 return -EINVAL; 249 } 250 251 /* always ensure these are zero, for drop through cases below */ 252 var->transp.offset = 0; 253 var->transp.length = 0; 254 255 switch (var->bits_per_pixel) { 256 case 1: 257 case 2: 258 case 4: 259 case 8: 260 if (sfb->variant.palette[win->index] != 0) { 261 /* non palletised, A:1,R:2,G:3,B:2 mode */ 262 var->red.offset = 4; 263 var->green.offset = 2; 264 var->blue.offset = 0; 265 var->red.length = 5; 266 var->green.length = 3; 267 var->blue.length = 2; 268 var->transp.offset = 7; 269 var->transp.length = 1; 270 } else { 271 var->red.offset = 0; 272 var->red.length = var->bits_per_pixel; 273 var->green = var->red; 274 var->blue = var->red; 275 } 276 break; 277 278 case 19: 279 /* 666 with one bit alpha/transparency */ 280 var->transp.offset = 18; 281 var->transp.length = 1; 282 case 18: 283 var->bits_per_pixel = 32; 284 285 /* 666 format */ 286 var->red.offset = 12; 287 var->green.offset = 6; 288 var->blue.offset = 0; 289 var->red.length = 6; 290 var->green.length = 6; 291 var->blue.length = 6; 292 break; 293 294 case 16: 295 /* 16 bpp, 565 format */ 296 var->red.offset = 11; 297 var->green.offset = 5; 298 var->blue.offset = 0; 299 var->red.length = 5; 300 var->green.length = 6; 301 var->blue.length = 5; 302 break; 303 304 case 32: 305 case 28: 306 case 25: 307 var->transp.length = var->bits_per_pixel - 24; 308 var->transp.offset = 24; 309 /* drop through */ 310 case 24: 311 /* our 24bpp is unpacked, so 32bpp */ 312 var->bits_per_pixel = 32; 313 var->red.offset = 16; 314 var->red.length = 8; 315 var->green.offset = 8; 316 var->green.length = 8; 317 var->blue.offset = 0; 318 var->blue.length = 8; 319 break; 320 321 default: 322 dev_err(sfb->dev, "invalid bpp\n"); 323 } 324 325 dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); 326 return 0; 327} 328 329/** 330 * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. 331 * @sfb: The hardware state. 332 * @pixclock: The pixel clock wanted, in picoseconds. 333 * 334 * Given the specified pixel clock, work out the necessary divider to get 335 * close to the output frequency. 336 */ 337static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) 338{ 339 unsigned long clk = clk_get_rate(sfb->bus_clk); 340 unsigned long long tmp; 341 unsigned int result; 342 343 tmp = (unsigned long long)clk; 344 tmp *= pixclk; 345 346 do_div(tmp, 1000000000UL); 347 result = (unsigned int)tmp / 1000; 348 349 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", 350 pixclk, clk, result, clk / result); 351 352 return result; 353} 354 355/** 356 * s3c_fb_align_word() - align pixel count to word boundary 357 * @bpp: The number of bits per pixel 358 * @pix: The value to be aligned. 359 * 360 * Align the given pixel count so that it will start on an 32bit word 361 * boundary. 362 */ 363static int s3c_fb_align_word(unsigned int bpp, unsigned int pix) 364{ 365 int pix_per_word; 366 367 if (bpp > 16) 368 return pix; 369 370 pix_per_word = (8 * 32) / bpp; 371 return ALIGN(pix, pix_per_word); 372} 373 374/** 375 * vidosd_set_size() - set OSD size for a window 376 * 377 * @win: the window to set OSD size for 378 * @size: OSD size register value 379 */ 380static void vidosd_set_size(struct s3c_fb_win *win, u32 size) 381{ 382 struct s3c_fb *sfb = win->parent; 383 384 /* OSD can be set up if osd_size_off != 0 for this window */ 385 if (win->variant.osd_size_off) 386 writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant) 387 + win->variant.osd_size_off); 388} 389 390/** 391 * vidosd_set_alpha() - set alpha transparency for a window 392 * 393 * @win: the window to set OSD size for 394 * @alpha: alpha register value 395 */ 396static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha) 397{ 398 struct s3c_fb *sfb = win->parent; 399 400 if (win->variant.has_osd_alpha) 401 writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant)); 402} 403 404/** 405 * shadow_protect_win() - disable updating values from shadow registers at vsync 406 * 407 * @win: window to protect registers for 408 * @protect: 1 to protect (disable updates) 409 */ 410static void shadow_protect_win(struct s3c_fb_win *win, bool protect) 411{ 412 struct s3c_fb *sfb = win->parent; 413 u32 reg; 414 415 if (protect) { 416 if (sfb->variant.has_prtcon) { 417 writel(PRTCON_PROTECT, sfb->regs + PRTCON); 418 } else if (sfb->variant.has_shadowcon) { 419 reg = readl(sfb->regs + SHADOWCON); 420 writel(reg | SHADOWCON_WINx_PROTECT(win->index), 421 sfb->regs + SHADOWCON); 422 } 423 } else { 424 if (sfb->variant.has_prtcon) { 425 writel(0, sfb->regs + PRTCON); 426 } else if (sfb->variant.has_shadowcon) { 427 reg = readl(sfb->regs + SHADOWCON); 428 writel(reg & ~SHADOWCON_WINx_PROTECT(win->index), 429 sfb->regs + SHADOWCON); 430 } 431 } 432} 433 434/** 435 * s3c_fb_set_par() - framebuffer request to set new framebuffer state. 436 * @info: The framebuffer to change. 437 * 438 * Framebuffer layer request to set a new mode for the specified framebuffer 439 */ 440static int s3c_fb_set_par(struct fb_info *info) 441{ 442 struct fb_var_screeninfo *var = &info->var; 443 struct s3c_fb_win *win = info->par; 444 struct s3c_fb *sfb = win->parent; 445 void __iomem *regs = sfb->regs; 446 void __iomem *buf = regs; 447 int win_no = win->index; 448 u32 alpha = 0; 449 u32 data; 450 u32 pagewidth; 451 int clkdiv; 452 453 dev_dbg(sfb->dev, "setting framebuffer parameters\n"); 454 455 shadow_protect_win(win, 1); 456 457 switch (var->bits_per_pixel) { 458 case 32: 459 case 24: 460 case 16: 461 case 12: 462 info->fix.visual = FB_VISUAL_TRUECOLOR; 463 break; 464 case 8: 465 if (win->variant.palette_sz >= 256) 466 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 467 else 468 info->fix.visual = FB_VISUAL_TRUECOLOR; 469 break; 470 case 1: 471 info->fix.visual = FB_VISUAL_MONO01; 472 break; 473 default: 474 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 475 break; 476 } 477 478 info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; 479 480 info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; 481 info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; 482 483 /* disable the window whilst we update it */ 484 writel(0, regs + WINCON(win_no)); 485 486 /* use platform specified window as the basis for the lcd timings */ 487 488 if (win_no == sfb->pdata->default_win) { 489 clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); 490 491 data = sfb->pdata->vidcon0; 492 data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); 493 494 if (clkdiv > 1) 495 data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; 496 else 497 data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ 498 499 /* write the timing data to the panel */ 500 501 if (sfb->variant.is_2443) 502 data |= (1 << 5); 503 504 data |= VIDCON0_ENVID | VIDCON0_ENVID_F; 505 writel(data, regs + VIDCON0); 506 507 data = VIDTCON0_VBPD(var->upper_margin - 1) | 508 VIDTCON0_VFPD(var->lower_margin - 1) | 509 VIDTCON0_VSPW(var->vsync_len - 1); 510 511 writel(data, regs + sfb->variant.vidtcon); 512 513 data = VIDTCON1_HBPD(var->left_margin - 1) | 514 VIDTCON1_HFPD(var->right_margin - 1) | 515 VIDTCON1_HSPW(var->hsync_len - 1); 516 517 /* VIDTCON1 */ 518 writel(data, regs + sfb->variant.vidtcon + 4); 519 520 data = VIDTCON2_LINEVAL(var->yres - 1) | 521 VIDTCON2_HOZVAL(var->xres - 1); 522 writel(data, regs + sfb->variant.vidtcon + 8); 523 } 524 525 /* write the buffer address */ 526 527 /* start and end registers stride is 8 */ 528 buf = regs + win_no * 8; 529 530 writel(info->fix.smem_start, buf + sfb->variant.buf_start); 531 532 data = info->fix.smem_start + info->fix.line_length * var->yres; 533 writel(data, buf + sfb->variant.buf_end); 534 535 pagewidth = (var->xres * var->bits_per_pixel) >> 3; 536 data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | 537 VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); 538 writel(data, regs + sfb->variant.buf_size + (win_no * 4)); 539 540 /* write 'OSD' registers to control position of framebuffer */ 541 542 data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); 543 writel(data, regs + VIDOSD_A(win_no, sfb->variant)); 544 545 data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, 546 var->xres - 1)) | 547 VIDOSDxB_BOTRIGHT_Y(var->yres - 1); 548 549 writel(data, regs + VIDOSD_B(win_no, sfb->variant)); 550 551 data = var->xres * var->yres; 552 553 alpha = VIDISD14C_ALPHA1_R(0xf) | 554 VIDISD14C_ALPHA1_G(0xf) | 555 VIDISD14C_ALPHA1_B(0xf); 556 557 vidosd_set_alpha(win, alpha); 558 vidosd_set_size(win, data); 559 560 /* Enable DMA channel for this window */ 561 if (sfb->variant.has_shadowcon) { 562 data = readl(sfb->regs + SHADOWCON); 563 data |= SHADOWCON_CHx_ENABLE(win_no); 564 writel(data, sfb->regs + SHADOWCON); 565 } 566 567 data = WINCONx_ENWIN; 568 569 /* note, since we have to round up the bits-per-pixel, we end up 570 * relying on the bitfield information for r/g/b/a to work out 571 * exactly which mode of operation is intended. */ 572 573 switch (var->bits_per_pixel) { 574 case 1: 575 data |= WINCON0_BPPMODE_1BPP; 576 data |= WINCONx_BITSWP; 577 data |= WINCONx_BURSTLEN_4WORD; 578 break; 579 case 2: 580 data |= WINCON0_BPPMODE_2BPP; 581 data |= WINCONx_BITSWP; 582 data |= WINCONx_BURSTLEN_8WORD; 583 break; 584 case 4: 585 data |= WINCON0_BPPMODE_4BPP; 586 data |= WINCONx_BITSWP; 587 data |= WINCONx_BURSTLEN_8WORD; 588 break; 589 case 8: 590 if (var->transp.length != 0) 591 data |= WINCON1_BPPMODE_8BPP_1232; 592 else 593 data |= WINCON0_BPPMODE_8BPP_PALETTE; 594 data |= WINCONx_BURSTLEN_8WORD; 595 data |= WINCONx_BYTSWP; 596 break; 597 case 16: 598 if (var->transp.length != 0) 599 data |= WINCON1_BPPMODE_16BPP_A1555; 600 else 601 data |= WINCON0_BPPMODE_16BPP_565; 602 data |= WINCONx_HAWSWP; 603 data |= WINCONx_BURSTLEN_16WORD; 604 break; 605 case 24: 606 case 32: 607 if (var->red.length == 6) { 608 if (var->transp.length != 0) 609 data |= WINCON1_BPPMODE_19BPP_A1666; 610 else 611 data |= WINCON1_BPPMODE_18BPP_666; 612 } else if (var->transp.length == 1) 613 data |= WINCON1_BPPMODE_25BPP_A1888 614 | WINCON1_BLD_PIX; 615 else if (var->transp.length == 4) 616 data |= WINCON1_BPPMODE_28BPP_A4888 617 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; 618 else 619 data |= WINCON0_BPPMODE_24BPP_888; 620 621 data |= WINCONx_WSWP; 622 data |= WINCONx_BURSTLEN_16WORD; 623 break; 624 } 625 626 /* Enable the colour keying for the window below this one */ 627 if (win_no > 0) { 628 u32 keycon0_data = 0, keycon1_data = 0; 629 void __iomem *keycon = regs + sfb->variant.keycon; 630 631 keycon0_data = ~(WxKEYCON0_KEYBL_EN | 632 WxKEYCON0_KEYEN_F | 633 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); 634 635 keycon1_data = WxKEYCON1_COLVAL(0xffffff); 636 637 keycon += (win_no - 1) * 8; 638 639 writel(keycon0_data, keycon + WKEYCON0); 640 writel(keycon1_data, keycon + WKEYCON1); 641 } 642 643 writel(data, regs + sfb->variant.wincon + (win_no * 4)); 644 writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); 645 646 shadow_protect_win(win, 0); 647 648 return 0; 649} 650 651/** 652 * s3c_fb_update_palette() - set or schedule a palette update. 653 * @sfb: The hardware information. 654 * @win: The window being updated. 655 * @reg: The palette index being changed. 656 * @value: The computed palette value. 657 * 658 * Change the value of a palette register, either by directly writing to 659 * the palette (this requires the palette RAM to be disconnected from the 660 * hardware whilst this is in progress) or schedule the update for later. 661 * 662 * At the moment, since we have no VSYNC interrupt support, we simply set 663 * the palette entry directly. 664 */ 665static void s3c_fb_update_palette(struct s3c_fb *sfb, 666 struct s3c_fb_win *win, 667 unsigned int reg, 668 u32 value) 669{ 670 void __iomem *palreg; 671 u32 palcon; 672 673 palreg = sfb->regs + sfb->variant.palette[win->index]; 674 675 dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n", 676 __func__, win->index, reg, palreg, value); 677 678 win->palette_buffer[reg] = value; 679 680 palcon = readl(sfb->regs + WPALCON); 681 writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON); 682 683 if (win->variant.palette_16bpp) 684 writew(value, palreg + (reg * 2)); 685 else 686 writel(value, palreg + (reg * 4)); 687 688 writel(palcon, sfb->regs + WPALCON); 689} 690 691static inline unsigned int chan_to_field(unsigned int chan, 692 struct fb_bitfield *bf) 693{ 694 chan &= 0xffff; 695 chan >>= 16 - bf->length; 696 return chan << bf->offset; 697} 698 699/** 700 * s3c_fb_setcolreg() - framebuffer layer request to change palette. 701 * @regno: The palette index to change. 702 * @red: The red field for the palette data. 703 * @green: The green field for the palette data. 704 * @blue: The blue field for the palette data. 705 * @trans: The transparency (alpha) field for the palette data. 706 * @info: The framebuffer being changed. 707 */ 708static int s3c_fb_setcolreg(unsigned regno, 709 unsigned red, unsigned green, unsigned blue, 710 unsigned transp, struct fb_info *info) 711{ 712 struct s3c_fb_win *win = info->par; 713 struct s3c_fb *sfb = win->parent; 714 unsigned int val; 715 716 dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", 717 __func__, win->index, regno, red, green, blue); 718 719 switch (info->fix.visual) { 720 case FB_VISUAL_TRUECOLOR: 721 /* true-colour, use pseudo-palette */ 722 723 if (regno < 16) { 724 u32 *pal = info->pseudo_palette; 725 726 val = chan_to_field(red, &info->var.red); 727 val |= chan_to_field(green, &info->var.green); 728 val |= chan_to_field(blue, &info->var.blue); 729 730 pal[regno] = val; 731 } 732 break; 733 734 case FB_VISUAL_PSEUDOCOLOR: 735 if (regno < win->variant.palette_sz) { 736 val = chan_to_field(red, &win->palette.r); 737 val |= chan_to_field(green, &win->palette.g); 738 val |= chan_to_field(blue, &win->palette.b); 739 740 s3c_fb_update_palette(sfb, win, regno, val); 741 } 742 743 break; 744 745 default: 746 return 1; /* unknown type */ 747 } 748 749 return 0; 750} 751 752/** 753 * s3c_fb_enable() - Set the state of the main LCD output 754 * @sfb: The main framebuffer state. 755 * @enable: The state to set. 756 */ 757static void s3c_fb_enable(struct s3c_fb *sfb, int enable) 758{ 759 u32 vidcon0 = readl(sfb->regs + VIDCON0); 760 761 if (enable) 762 vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; 763 else { 764 /* see the note in the framebuffer datasheet about 765 * why you cannot take both of these bits down at the 766 * same time. */ 767 768 if (!(vidcon0 & VIDCON0_ENVID)) 769 return; 770 771 vidcon0 |= VIDCON0_ENVID; 772 vidcon0 &= ~VIDCON0_ENVID_F; 773 } 774 775 writel(vidcon0, sfb->regs + VIDCON0); 776} 777 778/** 779 * s3c_fb_blank() - blank or unblank the given window 780 * @blank_mode: The blank state from FB_BLANK_* 781 * @info: The framebuffer to blank. 782 * 783 * Framebuffer layer request to change the power state. 784 */ 785static int s3c_fb_blank(int blank_mode, struct fb_info *info) 786{ 787 struct s3c_fb_win *win = info->par; 788 struct s3c_fb *sfb = win->parent; 789 unsigned int index = win->index; 790 u32 wincon; 791 792 dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); 793 794 wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); 795 796 switch (blank_mode) { 797 case FB_BLANK_POWERDOWN: 798 wincon &= ~WINCONx_ENWIN; 799 sfb->enabled &= ~(1 << index); 800 /* fall through to FB_BLANK_NORMAL */ 801 802 case FB_BLANK_NORMAL: 803 /* disable the DMA and display 0x0 (black) */ 804 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), 805 sfb->regs + sfb->variant.winmap + (index * 4)); 806 break; 807 808 case FB_BLANK_UNBLANK: 809 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); 810 wincon |= WINCONx_ENWIN; 811 sfb->enabled |= (1 << index); 812 break; 813 814 case FB_BLANK_VSYNC_SUSPEND: 815 case FB_BLANK_HSYNC_SUSPEND: 816 default: 817 return 1; 818 } 819 820 writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); 821 822 /* Check the enabled state to see if we need to be running the 823 * main LCD interface, as if there are no active windows then 824 * it is highly likely that we also do not need to output 825 * anything. 826 */ 827 828 /* We could do something like the following code, but the current 829 * system of using framebuffer events means that we cannot make 830 * the distinction between just window 0 being inactive and all 831 * the windows being down. 832 * 833 * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); 834 */ 835 836 /* we're stuck with this until we can do something about overriding 837 * the power control using the blanking event for a single fb. 838 */ 839 if (index == sfb->pdata->default_win) 840 s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); 841 842 return 0; 843} 844 845/** 846 * s3c_fb_pan_display() - Pan the display. 847 * 848 * Note that the offsets can be written to the device at any time, as their 849 * values are latched at each vsync automatically. This also means that only 850 * the last call to this function will have any effect on next vsync, but 851 * there is no need to sleep waiting for it to prevent tearing. 852 * 853 * @var: The screen information to verify. 854 * @info: The framebuffer device. 855 */ 856static int s3c_fb_pan_display(struct fb_var_screeninfo *var, 857 struct fb_info *info) 858{ 859 struct s3c_fb_win *win = info->par; 860 struct s3c_fb *sfb = win->parent; 861 void __iomem *buf = sfb->regs + win->index * 8; 862 unsigned int start_boff, end_boff; 863 864 /* Offset in bytes to the start of the displayed area */ 865 start_boff = var->yoffset * info->fix.line_length; 866 /* X offset depends on the current bpp */ 867 if (info->var.bits_per_pixel >= 8) { 868 start_boff += var->xoffset * (info->var.bits_per_pixel >> 3); 869 } else { 870 switch (info->var.bits_per_pixel) { 871 case 4: 872 start_boff += var->xoffset >> 1; 873 break; 874 case 2: 875 start_boff += var->xoffset >> 2; 876 break; 877 case 1: 878 start_boff += var->xoffset >> 3; 879 break; 880 default: 881 dev_err(sfb->dev, "invalid bpp\n"); 882 return -EINVAL; 883 } 884 } 885 /* Offset in bytes to the end of the displayed area */ 886 end_boff = start_boff + var->yres * info->fix.line_length; 887 888 /* Temporarily turn off per-vsync update from shadow registers until 889 * both start and end addresses are updated to prevent corruption */ 890 shadow_protect_win(win, 1); 891 892 writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start); 893 writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end); 894 895 shadow_protect_win(win, 0); 896 897 return 0; 898} 899 900/** 901 * s3c_fb_enable_irq() - enable framebuffer interrupts 902 * @sfb: main hardware state 903 */ 904static void s3c_fb_enable_irq(struct s3c_fb *sfb) 905{ 906 void __iomem *regs = sfb->regs; 907 u32 irq_ctrl_reg; 908 909 if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) { 910 /* IRQ disabled, enable it */ 911 irq_ctrl_reg = readl(regs + VIDINTCON0); 912 913 irq_ctrl_reg |= VIDINTCON0_INT_ENABLE; 914 irq_ctrl_reg |= VIDINTCON0_INT_FRAME; 915 916 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK; 917 irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC; 918 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK; 919 irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE; 920 921 writel(irq_ctrl_reg, regs + VIDINTCON0); 922 } 923} 924 925/** 926 * s3c_fb_disable_irq() - disable framebuffer interrupts 927 * @sfb: main hardware state 928 */ 929static void s3c_fb_disable_irq(struct s3c_fb *sfb) 930{ 931 void __iomem *regs = sfb->regs; 932 u32 irq_ctrl_reg; 933 934 if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) { 935 /* IRQ enabled, disable it */ 936 irq_ctrl_reg = readl(regs + VIDINTCON0); 937 938 irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME; 939 irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE; 940 941 writel(irq_ctrl_reg, regs + VIDINTCON0); 942 } 943} 944 945static irqreturn_t s3c_fb_irq(int irq, void *dev_id) 946{ 947 struct s3c_fb *sfb = dev_id; 948 void __iomem *regs = sfb->regs; 949 u32 irq_sts_reg; 950 951 spin_lock(&sfb->slock); 952 953 irq_sts_reg = readl(regs + VIDINTCON1); 954 955 if (irq_sts_reg & VIDINTCON1_INT_FRAME) { 956 957 /* VSYNC interrupt, accept it */ 958 writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1); 959 960 sfb->vsync_info.count++; 961 wake_up_interruptible(&sfb->vsync_info.wait); 962 } 963 964 /* We only support waiting for VSYNC for now, so it's safe 965 * to always disable irqs here. 966 */ 967 s3c_fb_disable_irq(sfb); 968 969 spin_unlock(&sfb->slock); 970 return IRQ_HANDLED; 971} 972 973/** 974 * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout 975 * @sfb: main hardware state 976 * @crtc: head index. 977 */ 978static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc) 979{ 980 unsigned long count; 981 int ret; 982 983 if (crtc != 0) 984 return -ENODEV; 985 986 count = sfb->vsync_info.count; 987 s3c_fb_enable_irq(sfb); 988 ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, 989 count != sfb->vsync_info.count, 990 msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); 991 if (ret == 0) 992 return -ETIMEDOUT; 993 994 return 0; 995} 996 997static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, 998 unsigned long arg) 999{ 1000 struct s3c_fb_win *win = info->par; 1001 struct s3c_fb *sfb = win->parent; 1002 int ret; 1003 u32 crtc; 1004 1005 switch (cmd) { 1006 case FBIO_WAITFORVSYNC: 1007 if (get_user(crtc, (u32 __user *)arg)) { 1008 ret = -EFAULT; 1009 break; 1010 } 1011 1012 ret = s3c_fb_wait_for_vsync(sfb, crtc); 1013 break; 1014 default: 1015 ret = -ENOTTY; 1016 } 1017 1018 return ret; 1019} 1020 1021static int s3c_fb_open(struct fb_info *info, int user) 1022{ 1023 struct s3c_fb_win *win = info->par; 1024 struct s3c_fb *sfb = win->parent; 1025 1026 pm_runtime_get_sync(sfb->dev); 1027 1028 return 0; 1029} 1030 1031static int s3c_fb_release(struct fb_info *info, int user) 1032{ 1033 struct s3c_fb_win *win = info->par; 1034 struct s3c_fb *sfb = win->parent; 1035 1036 pm_runtime_put_sync(sfb->dev); 1037 1038 return 0; 1039} 1040 1041static struct fb_ops s3c_fb_ops = { 1042 .owner = THIS_MODULE, 1043 .fb_open = s3c_fb_open, 1044 .fb_release = s3c_fb_release, 1045 .fb_check_var = s3c_fb_check_var, 1046 .fb_set_par = s3c_fb_set_par, 1047 .fb_blank = s3c_fb_blank, 1048 .fb_setcolreg = s3c_fb_setcolreg, 1049 .fb_fillrect = cfb_fillrect, 1050 .fb_copyarea = cfb_copyarea, 1051 .fb_imageblit = cfb_imageblit, 1052 .fb_pan_display = s3c_fb_pan_display, 1053 .fb_ioctl = s3c_fb_ioctl, 1054}; 1055 1056/** 1057 * s3c_fb_missing_pixclock() - calculates pixel clock 1058 * @mode: The video mode to change. 1059 * 1060 * Calculate the pixel clock when none has been given through platform data. 1061 */ 1062static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode) 1063{ 1064 u64 pixclk = 1000000000000ULL; 1065 u32 div; 1066 1067 div = mode->left_margin + mode->hsync_len + mode->right_margin + 1068 mode->xres; 1069 div *= mode->upper_margin + mode->vsync_len + mode->lower_margin + 1070 mode->yres; 1071 div *= mode->refresh ? : 60; 1072 1073 do_div(pixclk, div); 1074 1075 mode->pixclock = pixclk; 1076} 1077 1078/** 1079 * s3c_fb_alloc_memory() - allocate display memory for framebuffer window 1080 * @sfb: The base resources for the hardware. 1081 * @win: The window to initialise memory for. 1082 * 1083 * Allocate memory for the given framebuffer. 1084 */ 1085static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb, 1086 struct s3c_fb_win *win) 1087{ 1088 struct s3c_fb_pd_win *windata = win->windata; 1089 unsigned int real_size, virt_size, size; 1090 struct fb_info *fbi = win->fbinfo; 1091 dma_addr_t map_dma; 1092 1093 dev_dbg(sfb->dev, "allocating memory for display\n"); 1094 1095 real_size = windata->win_mode.xres * windata->win_mode.yres; 1096 virt_size = windata->virtual_x * windata->virtual_y; 1097 1098 dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", 1099 real_size, windata->win_mode.xres, windata->win_mode.yres, 1100 virt_size, windata->virtual_x, windata->virtual_y); 1101 1102 size = (real_size > virt_size) ? real_size : virt_size; 1103 size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp; 1104 size /= 8; 1105 1106 fbi->fix.smem_len = size; 1107 size = PAGE_ALIGN(size); 1108 1109 dev_dbg(sfb->dev, "want %u bytes for window\n", size); 1110 1111 fbi->screen_base = dma_alloc_writecombine(sfb->dev, size, 1112 &map_dma, GFP_KERNEL); 1113 if (!fbi->screen_base) 1114 return -ENOMEM; 1115 1116 dev_dbg(sfb->dev, "mapped %x to %p\n", 1117 (unsigned int)map_dma, fbi->screen_base); 1118 1119 memset(fbi->screen_base, 0x0, size); 1120 fbi->fix.smem_start = map_dma; 1121 1122 return 0; 1123} 1124 1125/** 1126 * s3c_fb_free_memory() - free the display memory for the given window 1127 * @sfb: The base resources for the hardware. 1128 * @win: The window to free the display memory for. 1129 * 1130 * Free the display memory allocated by s3c_fb_alloc_memory(). 1131 */ 1132static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) 1133{ 1134 struct fb_info *fbi = win->fbinfo; 1135 1136 if (fbi->screen_base) 1137 dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len), 1138 fbi->screen_base, fbi->fix.smem_start); 1139} 1140 1141/** 1142 * s3c_fb_release_win() - release resources for a framebuffer window. 1143 * @win: The window to cleanup the resources for. 1144 * 1145 * Release the resources that where claimed for the hardware window, 1146 * such as the framebuffer instance and any memory claimed for it. 1147 */ 1148static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) 1149{ 1150 u32 data; 1151 1152 if (win->fbinfo) { 1153 if (sfb->variant.has_shadowcon) { 1154 data = readl(sfb->regs + SHADOWCON); 1155 data &= ~SHADOWCON_CHx_ENABLE(win->index); 1156 data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index); 1157 writel(data, sfb->regs + SHADOWCON); 1158 } 1159 unregister_framebuffer(win->fbinfo); 1160 if (win->fbinfo->cmap.len) 1161 fb_dealloc_cmap(&win->fbinfo->cmap); 1162 s3c_fb_free_memory(sfb, win); 1163 framebuffer_release(win->fbinfo); 1164 } 1165} 1166 1167/** 1168 * s3c_fb_probe_win() - register an hardware window 1169 * @sfb: The base resources for the hardware 1170 * @variant: The variant information for this window. 1171 * @res: Pointer to where to place the resultant window. 1172 * 1173 * Allocate and do the basic initialisation for one of the hardware's graphics 1174 * windows. 1175 */ 1176static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, 1177 struct s3c_fb_win_variant *variant, 1178 struct s3c_fb_win **res) 1179{ 1180 struct fb_var_screeninfo *var; 1181 struct fb_videomode *initmode; 1182 struct s3c_fb_pd_win *windata; 1183 struct s3c_fb_win *win; 1184 struct fb_info *fbinfo; 1185 int palette_size; 1186 int ret; 1187 1188 dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant); 1189 1190 init_waitqueue_head(&sfb->vsync_info.wait); 1191 1192 palette_size = variant->palette_sz * 4; 1193 1194 fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) + 1195 palette_size * sizeof(u32), sfb->dev); 1196 if (!fbinfo) { 1197 dev_err(sfb->dev, "failed to allocate framebuffer\n"); 1198 return -ENOENT; 1199 } 1200 1201 windata = sfb->pdata->win[win_no]; 1202 initmode = &windata->win_mode; 1203 1204 WARN_ON(windata->max_bpp == 0); 1205 WARN_ON(windata->win_mode.xres == 0); 1206 WARN_ON(windata->win_mode.yres == 0); 1207 1208 win = fbinfo->par; 1209 *res = win; 1210 var = &fbinfo->var; 1211 win->variant = *variant; 1212 win->fbinfo = fbinfo; 1213 win->parent = sfb; 1214 win->windata = windata; 1215 win->index = win_no; 1216 win->palette_buffer = (u32 *)(win + 1); 1217 1218 ret = s3c_fb_alloc_memory(sfb, win); 1219 if (ret) { 1220 dev_err(sfb->dev, "failed to allocate display memory\n"); 1221 return ret; 1222 } 1223 1224 /* setup the r/b/g positions for the window's palette */ 1225 if (win->variant.palette_16bpp) { 1226 /* Set RGB 5:6:5 as default */ 1227 win->palette.r.offset = 11; 1228 win->palette.r.length = 5; 1229 win->palette.g.offset = 5; 1230 win->palette.g.length = 6; 1231 win->palette.b.offset = 0; 1232 win->palette.b.length = 5; 1233 1234 } else { 1235 /* Set 8bpp or 8bpp and 1bit alpha */ 1236 win->palette.r.offset = 16; 1237 win->palette.r.length = 8; 1238 win->palette.g.offset = 8; 1239 win->palette.g.length = 8; 1240 win->palette.b.offset = 0; 1241 win->palette.b.length = 8; 1242 } 1243 1244 /* setup the initial video mode from the window */ 1245 fb_videomode_to_var(&fbinfo->var, initmode); 1246 1247 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; 1248 fbinfo->fix.accel = FB_ACCEL_NONE; 1249 fbinfo->var.activate = FB_ACTIVATE_NOW; 1250 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; 1251 fbinfo->var.bits_per_pixel = windata->default_bpp; 1252 fbinfo->fbops = &s3c_fb_ops; 1253 fbinfo->flags = FBINFO_FLAG_DEFAULT; 1254 fbinfo->pseudo_palette = &win->pseudo_palette; 1255 1256 /* prepare to actually start the framebuffer */ 1257 1258 ret = s3c_fb_check_var(&fbinfo->var, fbinfo); 1259 if (ret < 0) { 1260 dev_err(sfb->dev, "check_var failed on initial video params\n"); 1261 return ret; 1262 } 1263 1264 /* create initial colour map */ 1265 1266 ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1); 1267 if (ret == 0) 1268 fb_set_cmap(&fbinfo->cmap, fbinfo); 1269 else 1270 dev_err(sfb->dev, "failed to allocate fb cmap\n"); 1271 1272 s3c_fb_set_par(fbinfo); 1273 1274 dev_dbg(sfb->dev, "about to register framebuffer\n"); 1275 1276 /* run the check_var and set_par on our configuration. */ 1277 1278 ret = register_framebuffer(fbinfo); 1279 if (ret < 0) { 1280 dev_err(sfb->dev, "failed to register framebuffer\n"); 1281 return ret; 1282 } 1283 1284 dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id); 1285 1286 return 0; 1287} 1288 1289/** 1290 * s3c_fb_clear_win() - clear hardware window registers. 1291 * @sfb: The base resources for the hardware. 1292 * @win: The window to process. 1293 * 1294 * Reset the specific window registers to a known state. 1295 */ 1296static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) 1297{ 1298 void __iomem *regs = sfb->regs; 1299 u32 reg; 1300 1301 writel(0, regs + sfb->variant.wincon + (win * 4)); 1302 writel(0, regs + VIDOSD_A(win, sfb->variant)); 1303 writel(0, regs + VIDOSD_B(win, sfb->variant)); 1304 writel(0, regs + VIDOSD_C(win, sfb->variant)); 1305 reg = readl(regs + SHADOWCON); 1306 writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON); 1307} 1308 1309static int __devinit s3c_fb_probe(struct platform_device *pdev) 1310{ 1311 const struct platform_device_id *platid; 1312 struct s3c_fb_driverdata *fbdrv; 1313 struct device *dev = &pdev->dev; 1314 struct s3c_fb_platdata *pd; 1315 struct s3c_fb *sfb; 1316 struct resource *res; 1317 int win; 1318 int ret = 0; 1319 1320 platid = platform_get_device_id(pdev); 1321 fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; 1322 1323 if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) { 1324 dev_err(dev, "too many windows, cannot attach\n"); 1325 return -EINVAL; 1326 } 1327 1328 pd = pdev->dev.platform_data; 1329 if (!pd) { 1330 dev_err(dev, "no platform data specified\n"); 1331 return -EINVAL; 1332 } 1333 1334 sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL); 1335 if (!sfb) { 1336 dev_err(dev, "no memory for framebuffers\n"); 1337 return -ENOMEM; 1338 } 1339 1340 dev_dbg(dev, "allocate new framebuffer %p\n", sfb); 1341 1342 sfb->dev = dev; 1343 sfb->pdata = pd; 1344 sfb->variant = fbdrv->variant; 1345 1346 spin_lock_init(&sfb->slock); 1347 1348 sfb->bus_clk = clk_get(dev, "lcd"); 1349 if (IS_ERR(sfb->bus_clk)) { 1350 dev_err(dev, "failed to get bus clock\n"); 1351 ret = PTR_ERR(sfb->bus_clk); 1352 goto err_sfb; 1353 } 1354 1355 clk_enable(sfb->bus_clk); 1356 1357 pm_runtime_enable(sfb->dev); 1358 1359 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1360 if (!res) { 1361 dev_err(dev, "failed to find registers\n"); 1362 ret = -ENOENT; 1363 goto err_clk; 1364 } 1365 1366 sfb->regs_res = request_mem_region(res->start, resource_size(res), 1367 dev_name(dev)); 1368 if (!sfb->regs_res) { 1369 dev_err(dev, "failed to claim register region\n"); 1370 ret = -ENOENT; 1371 goto err_clk; 1372 } 1373 1374 sfb->regs = ioremap(res->start, resource_size(res)); 1375 if (!sfb->regs) { 1376 dev_err(dev, "failed to map registers\n"); 1377 ret = -ENXIO; 1378 goto err_req_region; 1379 } 1380 1381 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1382 if (!res) { 1383 dev_err(dev, "failed to acquire irq resource\n"); 1384 ret = -ENOENT; 1385 goto err_ioremap; 1386 } 1387 sfb->irq_no = res->start; 1388 ret = request_irq(sfb->irq_no, s3c_fb_irq, 1389 0, "s3c_fb", sfb); 1390 if (ret) { 1391 dev_err(dev, "irq request failed\n"); 1392 goto err_ioremap; 1393 } 1394 1395 dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); 1396 1397 platform_set_drvdata(pdev, sfb); 1398 pm_runtime_get_sync(sfb->dev); 1399 1400 /* setup gpio and output polarity controls */ 1401 1402 pd->setup_gpio(); 1403 1404 writel(pd->vidcon1, sfb->regs + VIDCON1); 1405 1406 /* zero all windows before we do anything */ 1407 1408 for (win = 0; win < fbdrv->variant.nr_windows; win++) 1409 s3c_fb_clear_win(sfb, win); 1410 1411 /* initialise colour key controls */ 1412 for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) { 1413 void __iomem *regs = sfb->regs + sfb->variant.keycon; 1414 1415 regs += (win * 8); 1416 writel(0xffffff, regs + WKEYCON0); 1417 writel(0xffffff, regs + WKEYCON1); 1418 } 1419 1420 /* we have the register setup, start allocating framebuffers */ 1421 1422 for (win = 0; win < fbdrv->variant.nr_windows; win++) { 1423 if (!pd->win[win]) 1424 continue; 1425 1426 if (!pd->win[win]->win_mode.pixclock) 1427 s3c_fb_missing_pixclock(&pd->win[win]->win_mode); 1428 1429 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], 1430 &sfb->windows[win]); 1431 if (ret < 0) { 1432 dev_err(dev, "failed to create window %d\n", win); 1433 for (; win >= 0; win--) 1434 s3c_fb_release_win(sfb, sfb->windows[win]); 1435 goto err_irq; 1436 } 1437 } 1438 1439 platform_set_drvdata(pdev, sfb); 1440 pm_runtime_put_sync(sfb->dev); 1441 1442 return 0; 1443 1444err_irq: 1445 free_irq(sfb->irq_no, sfb); 1446 1447err_ioremap: 1448 iounmap(sfb->regs); 1449 1450err_req_region: 1451 release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); 1452 1453err_clk: 1454 clk_disable(sfb->bus_clk); 1455 clk_put(sfb->bus_clk); 1456 1457err_sfb: 1458 kfree(sfb); 1459 return ret; 1460} 1461 1462/** 1463 * s3c_fb_remove() - Cleanup on module finalisation 1464 * @pdev: The platform device we are bound to. 1465 * 1466 * Shutdown and then release all the resources that the driver allocated 1467 * on initialisation. 1468 */ 1469static int __devexit s3c_fb_remove(struct platform_device *pdev) 1470{ 1471 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1472 int win; 1473 1474 pm_runtime_get_sync(sfb->dev); 1475 1476 for (win = 0; win < S3C_FB_MAX_WIN; win++) 1477 if (sfb->windows[win]) 1478 s3c_fb_release_win(sfb, sfb->windows[win]); 1479 1480 free_irq(sfb->irq_no, sfb); 1481 1482 iounmap(sfb->regs); 1483 1484 clk_disable(sfb->bus_clk); 1485 clk_put(sfb->bus_clk); 1486 1487 release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); 1488 1489 pm_runtime_put_sync(sfb->dev); 1490 pm_runtime_disable(sfb->dev); 1491 1492 kfree(sfb); 1493 return 0; 1494} 1495 1496#ifdef CONFIG_PM 1497static int s3c_fb_suspend(struct device *dev) 1498{ 1499 struct platform_device *pdev = to_platform_device(dev); 1500 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1501 struct s3c_fb_win *win; 1502 int win_no; 1503 1504 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { 1505 win = sfb->windows[win_no]; 1506 if (!win) 1507 continue; 1508 1509 /* use the blank function to push into power-down */ 1510 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); 1511 } 1512 1513 clk_disable(sfb->bus_clk); 1514 return 0; 1515} 1516 1517static int s3c_fb_resume(struct device *dev) 1518{ 1519 struct platform_device *pdev = to_platform_device(dev); 1520 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1521 struct s3c_fb_platdata *pd = sfb->pdata; 1522 struct s3c_fb_win *win; 1523 int win_no; 1524 1525 clk_enable(sfb->bus_clk); 1526 1527 /* setup gpio and output polarity controls */ 1528 pd->setup_gpio(); 1529 writel(pd->vidcon1, sfb->regs + VIDCON1); 1530 1531 /* zero all windows before we do anything */ 1532 for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) 1533 s3c_fb_clear_win(sfb, win_no); 1534 1535 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { 1536 void __iomem *regs = sfb->regs + sfb->variant.keycon; 1537 1538 regs += (win_no * 8); 1539 writel(0xffffff, regs + WKEYCON0); 1540 writel(0xffffff, regs + WKEYCON1); 1541 } 1542 1543 /* restore framebuffers */ 1544 for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { 1545 win = sfb->windows[win_no]; 1546 if (!win) 1547 continue; 1548 1549 dev_dbg(&pdev->dev, "resuming window %d\n", win_no); 1550 s3c_fb_set_par(win->fbinfo); 1551 } 1552 1553 return 0; 1554} 1555 1556static int s3c_fb_runtime_suspend(struct device *dev) 1557{ 1558 struct platform_device *pdev = to_platform_device(dev); 1559 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1560 struct s3c_fb_win *win; 1561 int win_no; 1562 1563 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { 1564 win = sfb->windows[win_no]; 1565 if (!win) 1566 continue; 1567 1568 /* use the blank function to push into power-down */ 1569 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); 1570 } 1571 1572 clk_disable(sfb->bus_clk); 1573 return 0; 1574} 1575 1576static int s3c_fb_runtime_resume(struct device *dev) 1577{ 1578 struct platform_device *pdev = to_platform_device(dev); 1579 struct s3c_fb *sfb = platform_get_drvdata(pdev); 1580 struct s3c_fb_platdata *pd = sfb->pdata; 1581 struct s3c_fb_win *win; 1582 int win_no; 1583 1584 clk_enable(sfb->bus_clk); 1585 1586 /* setup gpio and output polarity controls */ 1587 pd->setup_gpio(); 1588 writel(pd->vidcon1, sfb->regs + VIDCON1); 1589 1590 /* zero all windows before we do anything */ 1591 for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) 1592 s3c_fb_clear_win(sfb, win_no); 1593 1594 for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { 1595 void __iomem *regs = sfb->regs + sfb->variant.keycon; 1596 1597 regs += (win_no * 8); 1598 writel(0xffffff, regs + WKEYCON0); 1599 writel(0xffffff, regs + WKEYCON1); 1600 } 1601 1602 /* restore framebuffers */ 1603 for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { 1604 win = sfb->windows[win_no]; 1605 if (!win) 1606 continue; 1607 1608 dev_dbg(&pdev->dev, "resuming window %d\n", win_no); 1609 s3c_fb_set_par(win->fbinfo); 1610 } 1611 1612 return 0; 1613} 1614 1615#else 1616#define s3c_fb_suspend NULL 1617#define s3c_fb_resume NULL 1618#define s3c_fb_runtime_suspend NULL 1619#define s3c_fb_runtime_resume NULL 1620#endif 1621 1622 1623#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) 1624#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) 1625 1626static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = { 1627 [0] = { 1628 .has_osd_c = 1, 1629 .osd_size_off = 0x8, 1630 .palette_sz = 256, 1631 .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | 1632 VALID_BPP(18) | VALID_BPP(24)), 1633 }, 1634 [1] = { 1635 .has_osd_c = 1, 1636 .has_osd_d = 1, 1637 .osd_size_off = 0xc, 1638 .has_osd_alpha = 1, 1639 .palette_sz = 256, 1640 .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | 1641 VALID_BPP(18) | VALID_BPP(19) | 1642 VALID_BPP(24) | VALID_BPP(25) | 1643 VALID_BPP(28)), 1644 }, 1645 [2] = { 1646 .has_osd_c = 1, 1647 .has_osd_d = 1, 1648 .osd_size_off = 0xc, 1649 .has_osd_alpha = 1, 1650 .palette_sz = 16, 1651 .palette_16bpp = 1, 1652 .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | 1653 VALID_BPP(18) | VALID_BPP(19) | 1654 VALID_BPP(24) | VALID_BPP(25) | 1655 VALID_BPP(28)), 1656 }, 1657 [3] = { 1658 .has_osd_c = 1, 1659 .has_osd_alpha = 1, 1660 .palette_sz = 16, 1661 .palette_16bpp = 1, 1662 .valid_bpp = (VALID_BPP124 | VALID_BPP(16) | 1663 VALID_BPP(18) | VALID_BPP(19) | 1664 VALID_BPP(24) | VALID_BPP(25) | 1665 VALID_BPP(28)), 1666 }, 1667 [4] = { 1668 .has_osd_c = 1, 1669 .has_osd_alpha = 1, 1670 .palette_sz = 4, 1671 .palette_16bpp = 1, 1672 .valid_bpp = (VALID_BPP(1) | VALID_BPP(2) | 1673 VALID_BPP(16) | VALID_BPP(18) | 1674 VALID_BPP(19) | VALID_BPP(24) | 1675 VALID_BPP(25) | VALID_BPP(28)), 1676 }, 1677}; 1678 1679static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = { 1680 [0] = { 1681 .has_osd_c = 1, 1682 .osd_size_off = 0x8, 1683 .palette_sz = 256, 1684 .valid_bpp = (VALID_BPP1248 | VALID_BPP(13) | 1685 VALID_BPP(15) | VALID_BPP(16) | 1686 VALID_BPP(18) | VALID_BPP(19) | 1687 VALID_BPP(24) | VALID_BPP(25) | 1688 VALID_BPP(32)), 1689 }, 1690 [1] = { 1691 .has_osd_c = 1, 1692 .has_osd_d = 1, 1693 .osd_size_off = 0xc, 1694 .has_osd_alpha = 1, 1695 .palette_sz = 256, 1696 .valid_bpp = (VALID_BPP1248 | VALID_BPP(13) | 1697 VALID_BPP(15) | VALID_BPP(16) | 1698 VALID_BPP(18) | VALID_BPP(19) | 1699 VALID_BPP(24) | VALID_BPP(25) | 1700 VALID_BPP(32)), 1701 }, 1702 [2] = { 1703 .has_osd_c = 1, 1704 .has_osd_d = 1, 1705 .osd_size_off = 0xc, 1706 .has_osd_alpha = 1, 1707 .palette_sz = 256, 1708 .valid_bpp = (VALID_BPP1248 | VALID_BPP(13) | 1709 VALID_BPP(15) | VALID_BPP(16) | 1710 VALID_BPP(18) | VALID_BPP(19) | 1711 VALID_BPP(24) | VALID_BPP(25) | 1712 VALID_BPP(32)), 1713 }, 1714 [3] = { 1715 .has_osd_c = 1, 1716 .has_osd_alpha = 1, 1717 .palette_sz = 256, 1718 .valid_bpp = (VALID_BPP1248 | VALID_BPP(13) | 1719 VALID_BPP(15) | VALID_BPP(16) | 1720 VALID_BPP(18) | VALID_BPP(19) | 1721 VALID_BPP(24) | VALID_BPP(25) | 1722 VALID_BPP(32)), 1723 }, 1724 [4] = { 1725 .has_osd_c = 1, 1726 .has_osd_alpha = 1, 1727 .palette_sz = 256, 1728 .valid_bpp = (VALID_BPP1248 | VALID_BPP(13) | 1729 VALID_BPP(15) | VALID_BPP(16) | 1730 VALID_BPP(18) | VALID_BPP(19) | 1731 VALID_BPP(24) | VALID_BPP(25) | 1732 VALID_BPP(32)), 1733 }, 1734}; 1735 1736static struct s3c_fb_driverdata s3c_fb_data_64xx = { 1737 .variant = { 1738 .nr_windows = 5, 1739 .vidtcon = VIDTCON0, 1740 .wincon = WINCON(0), 1741 .winmap = WINxMAP(0), 1742 .keycon = WKEYCON, 1743 .osd = VIDOSD_BASE, 1744 .osd_stride = 16, 1745 .buf_start = VIDW_BUF_START(0), 1746 .buf_size = VIDW_BUF_SIZE(0), 1747 .buf_end = VIDW_BUF_END(0), 1748 1749 .palette = { 1750 [0] = 0x400, 1751 [1] = 0x800, 1752 [2] = 0x300, 1753 [3] = 0x320, 1754 [4] = 0x340, 1755 }, 1756 1757 .has_prtcon = 1, 1758 }, 1759 .win[0] = &s3c_fb_data_64xx_wins[0], 1760 .win[1] = &s3c_fb_data_64xx_wins[1], 1761 .win[2] = &s3c_fb_data_64xx_wins[2], 1762 .win[3] = &s3c_fb_data_64xx_wins[3], 1763 .win[4] = &s3c_fb_data_64xx_wins[4], 1764}; 1765 1766static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = { 1767 .variant = { 1768 .nr_windows = 5, 1769 .vidtcon = VIDTCON0, 1770 .wincon = WINCON(0), 1771 .winmap = WINxMAP(0), 1772 .keycon = WKEYCON, 1773 .osd = VIDOSD_BASE, 1774 .osd_stride = 16, 1775 .buf_start = VIDW_BUF_START(0), 1776 .buf_size = VIDW_BUF_SIZE(0), 1777 .buf_end = VIDW_BUF_END(0), 1778 1779 .palette = { 1780 [0] = 0x2400, 1781 [1] = 0x2800, 1782 [2] = 0x2c00, 1783 [3] = 0x3000, 1784 [4] = 0x3400, 1785 }, 1786 1787 .has_prtcon = 1, 1788 }, 1789 .win[0] = &s3c_fb_data_s5p_wins[0], 1790 .win[1] = &s3c_fb_data_s5p_wins[1], 1791 .win[2] = &s3c_fb_data_s5p_wins[2], 1792 .win[3] = &s3c_fb_data_s5p_wins[3], 1793 .win[4] = &s3c_fb_data_s5p_wins[4], 1794}; 1795 1796static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = { 1797 .variant = { 1798 .nr_windows = 5, 1799 .vidtcon = VIDTCON0, 1800 .wincon = WINCON(0), 1801 .winmap = WINxMAP(0), 1802 .keycon = WKEYCON, 1803 .osd = VIDOSD_BASE, 1804 .osd_stride = 16, 1805 .buf_start = VIDW_BUF_START(0), 1806 .buf_size = VIDW_BUF_SIZE(0), 1807 .buf_end = VIDW_BUF_END(0), 1808 1809 .palette = { 1810 [0] = 0x2400, 1811 [1] = 0x2800, 1812 [2] = 0x2c00, 1813 [3] = 0x3000, 1814 [4] = 0x3400, 1815 }, 1816 1817 .has_shadowcon = 1, 1818 }, 1819 .win[0] = &s3c_fb_data_s5p_wins[0], 1820 .win[1] = &s3c_fb_data_s5p_wins[1], 1821 .win[2] = &s3c_fb_data_s5p_wins[2], 1822 .win[3] = &s3c_fb_data_s5p_wins[3], 1823 .win[4] = &s3c_fb_data_s5p_wins[4], 1824}; 1825 1826/* S3C2443/S3C2416 style hardware */ 1827static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = { 1828 .variant = { 1829 .nr_windows = 2, 1830 .is_2443 = 1, 1831 1832 .vidtcon = 0x08, 1833 .wincon = 0x14, 1834 .winmap = 0xd0, 1835 .keycon = 0xb0, 1836 .osd = 0x28, 1837 .osd_stride = 12, 1838 .buf_start = 0x64, 1839 .buf_size = 0x94, 1840 .buf_end = 0x7c, 1841 1842 .palette = { 1843 [0] = 0x400, 1844 [1] = 0x800, 1845 }, 1846 }, 1847 .win[0] = &(struct s3c_fb_win_variant) { 1848 .palette_sz = 256, 1849 .valid_bpp = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24), 1850 }, 1851 .win[1] = &(struct s3c_fb_win_variant) { 1852 .has_osd_c = 1, 1853 .has_osd_alpha = 1, 1854 .palette_sz = 256, 1855 .valid_bpp = (VALID_BPP1248 | VALID_BPP(16) | 1856 VALID_BPP(18) | VALID_BPP(19) | 1857 VALID_BPP(24) | VALID_BPP(25) | 1858 VALID_BPP(28)), 1859 }, 1860}; 1861 1862static struct platform_device_id s3c_fb_driver_ids[] = { 1863 { 1864 .name = "s3c-fb", 1865 .driver_data = (unsigned long)&s3c_fb_data_64xx, 1866 }, { 1867 .name = "s5pc100-fb", 1868 .driver_data = (unsigned long)&s3c_fb_data_s5pc100, 1869 }, { 1870 .name = "s5pv210-fb", 1871 .driver_data = (unsigned long)&s3c_fb_data_s5pv210, 1872 }, { 1873 .name = "s3c2443-fb", 1874 .driver_data = (unsigned long)&s3c_fb_data_s3c2443, 1875 }, 1876 {}, 1877}; 1878MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); 1879 1880static const struct dev_pm_ops s3cfb_pm_ops = { 1881 .suspend = s3c_fb_suspend, 1882 .resume = s3c_fb_resume, 1883 .runtime_suspend = s3c_fb_runtime_suspend, 1884 .runtime_resume = s3c_fb_runtime_resume, 1885}; 1886 1887static struct platform_driver s3c_fb_driver = { 1888 .probe = s3c_fb_probe, 1889 .remove = __devexit_p(s3c_fb_remove), 1890 .id_table = s3c_fb_driver_ids, 1891 .driver = { 1892 .name = "s3c-fb", 1893 .owner = THIS_MODULE, 1894 .pm = &s3cfb_pm_ops, 1895 }, 1896}; 1897 1898static int __init s3c_fb_init(void) 1899{ 1900 return platform_driver_register(&s3c_fb_driver); 1901} 1902 1903static void __exit s3c_fb_cleanup(void) 1904{ 1905 platform_driver_unregister(&s3c_fb_driver); 1906} 1907 1908module_init(s3c_fb_init); 1909module_exit(s3c_fb_cleanup); 1910 1911MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 1912MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); 1913MODULE_LICENSE("GPL"); 1914MODULE_ALIAS("platform:s3c-fb");