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 v2.6.29-rc7 885 lines 22 kB view raw
1/* 2 * SuperH Mobile LCDC Framebuffer 3 * 4 * Copyright (c) 2008 Magnus Damm 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/delay.h> 14#include <linux/mm.h> 15#include <linux/fb.h> 16#include <linux/clk.h> 17#include <linux/platform_device.h> 18#include <linux/dma-mapping.h> 19#include <linux/interrupt.h> 20#include <video/sh_mobile_lcdc.h> 21#include <asm/atomic.h> 22 23#define PALETTE_NR 16 24 25struct sh_mobile_lcdc_priv; 26struct sh_mobile_lcdc_chan { 27 struct sh_mobile_lcdc_priv *lcdc; 28 unsigned long *reg_offs; 29 unsigned long ldmt1r_value; 30 unsigned long enabled; /* ME and SE in LDCNT2R */ 31 struct sh_mobile_lcdc_chan_cfg cfg; 32 u32 pseudo_palette[PALETTE_NR]; 33 struct fb_info info; 34 dma_addr_t dma_handle; 35 struct fb_deferred_io defio; 36}; 37 38struct sh_mobile_lcdc_priv { 39 void __iomem *base; 40 int irq; 41#ifdef CONFIG_HAVE_CLK 42 atomic_t clk_usecnt; 43 struct clk *dot_clk; 44 struct clk *clk; 45#endif 46 unsigned long lddckr; 47 struct sh_mobile_lcdc_chan ch[2]; 48}; 49 50/* shared registers */ 51#define _LDDCKR 0x410 52#define _LDDCKSTPR 0x414 53#define _LDINTR 0x468 54#define _LDSR 0x46c 55#define _LDCNT1R 0x470 56#define _LDCNT2R 0x474 57#define _LDDDSR 0x47c 58#define _LDDWD0R 0x800 59#define _LDDRDR 0x840 60#define _LDDWAR 0x900 61#define _LDDRAR 0x904 62 63/* per-channel registers */ 64enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, 65 LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR }; 66 67static unsigned long lcdc_offs_mainlcd[] = { 68 [LDDCKPAT1R] = 0x400, 69 [LDDCKPAT2R] = 0x404, 70 [LDMT1R] = 0x418, 71 [LDMT2R] = 0x41c, 72 [LDMT3R] = 0x420, 73 [LDDFR] = 0x424, 74 [LDSM1R] = 0x428, 75 [LDSM2R] = 0x42c, 76 [LDSA1R] = 0x430, 77 [LDMLSR] = 0x438, 78 [LDHCNR] = 0x448, 79 [LDHSYNR] = 0x44c, 80 [LDVLNR] = 0x450, 81 [LDVSYNR] = 0x454, 82 [LDPMR] = 0x460, 83}; 84 85static unsigned long lcdc_offs_sublcd[] = { 86 [LDDCKPAT1R] = 0x408, 87 [LDDCKPAT2R] = 0x40c, 88 [LDMT1R] = 0x600, 89 [LDMT2R] = 0x604, 90 [LDMT3R] = 0x608, 91 [LDDFR] = 0x60c, 92 [LDSM1R] = 0x610, 93 [LDSM2R] = 0x614, 94 [LDSA1R] = 0x618, 95 [LDMLSR] = 0x620, 96 [LDHCNR] = 0x624, 97 [LDHSYNR] = 0x628, 98 [LDVLNR] = 0x62c, 99 [LDVSYNR] = 0x630, 100 [LDPMR] = 0x63c, 101}; 102 103#define START_LCDC 0x00000001 104#define LCDC_RESET 0x00000100 105#define DISPLAY_BEU 0x00000008 106#define LCDC_ENABLE 0x00000001 107#define LDINTR_FE 0x00000400 108#define LDINTR_FS 0x00000004 109 110static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 111 int reg_nr, unsigned long data) 112{ 113 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); 114} 115 116static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, 117 int reg_nr) 118{ 119 return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]); 120} 121 122static void lcdc_write(struct sh_mobile_lcdc_priv *priv, 123 unsigned long reg_offs, unsigned long data) 124{ 125 iowrite32(data, priv->base + reg_offs); 126} 127 128static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv, 129 unsigned long reg_offs) 130{ 131 return ioread32(priv->base + reg_offs); 132} 133 134static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, 135 unsigned long reg_offs, 136 unsigned long mask, unsigned long until) 137{ 138 while ((lcdc_read(priv, reg_offs) & mask) != until) 139 cpu_relax(); 140} 141 142static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 143{ 144 return chan->cfg.chan == LCDC_CHAN_SUBLCD; 145} 146 147static void lcdc_sys_write_index(void *handle, unsigned long data) 148{ 149 struct sh_mobile_lcdc_chan *ch = handle; 150 151 lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); 152 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 153 lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 154} 155 156static void lcdc_sys_write_data(void *handle, unsigned long data) 157{ 158 struct sh_mobile_lcdc_chan *ch = handle; 159 160 lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); 161 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 162 lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 163} 164 165static unsigned long lcdc_sys_read_data(void *handle) 166{ 167 struct sh_mobile_lcdc_chan *ch = handle; 168 169 lcdc_write(ch->lcdc, _LDDRDR, 0x01000000); 170 lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 171 lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 172 udelay(1); 173 174 return lcdc_read(ch->lcdc, _LDDRDR) & 0xffff; 175} 176 177struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { 178 lcdc_sys_write_index, 179 lcdc_sys_write_data, 180 lcdc_sys_read_data, 181}; 182 183#ifdef CONFIG_HAVE_CLK 184static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 185{ 186 if (atomic_inc_and_test(&priv->clk_usecnt)) { 187 clk_enable(priv->clk); 188 if (priv->dot_clk) 189 clk_enable(priv->dot_clk); 190 } 191} 192 193static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) 194{ 195 if (atomic_sub_return(1, &priv->clk_usecnt) == -1) { 196 if (priv->dot_clk) 197 clk_disable(priv->dot_clk); 198 clk_disable(priv->clk); 199 } 200} 201#else 202static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {} 203static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {} 204#endif 205 206static void sh_mobile_lcdc_deferred_io(struct fb_info *info, 207 struct list_head *pagelist) 208{ 209 struct sh_mobile_lcdc_chan *ch = info->par; 210 211 /* enable clocks before accessing hardware */ 212 sh_mobile_lcdc_clk_on(ch->lcdc); 213 214 /* trigger panel update */ 215 lcdc_write_chan(ch, LDSM2R, 1); 216} 217 218static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 219{ 220 struct fb_deferred_io *fbdefio = info->fbdefio; 221 222 if (fbdefio) 223 schedule_delayed_work(&info->deferred_work, fbdefio->delay); 224} 225 226static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 227{ 228 struct sh_mobile_lcdc_priv *priv = data; 229 unsigned long tmp; 230 231 /* acknowledge interrupt */ 232 tmp = lcdc_read(priv, _LDINTR); 233 tmp &= 0xffffff00; /* mask in high 24 bits */ 234 tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */ 235 lcdc_write(priv, _LDINTR, tmp); 236 237 /* disable clocks */ 238 sh_mobile_lcdc_clk_off(priv); 239 return IRQ_HANDLED; 240} 241 242static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 243 int start) 244{ 245 unsigned long tmp = lcdc_read(priv, _LDCNT2R); 246 int k; 247 248 /* start or stop the lcdc */ 249 if (start) 250 lcdc_write(priv, _LDCNT2R, tmp | START_LCDC); 251 else 252 lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC); 253 254 /* wait until power is applied/stopped on all channels */ 255 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 256 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 257 while (1) { 258 tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3; 259 if (start && tmp == 3) 260 break; 261 if (!start && tmp == 0) 262 break; 263 cpu_relax(); 264 } 265 266 if (!start) 267 lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 268} 269 270static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 271{ 272 struct sh_mobile_lcdc_chan *ch; 273 struct fb_videomode *lcd_cfg; 274 struct sh_mobile_lcdc_board_cfg *board_cfg; 275 unsigned long tmp; 276 int k, m; 277 int ret = 0; 278 279 /* enable clocks before accessing the hardware */ 280 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 281 if (priv->ch[k].enabled) 282 sh_mobile_lcdc_clk_on(priv); 283 284 /* reset */ 285 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); 286 lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); 287 288 /* enable LCDC channels */ 289 tmp = lcdc_read(priv, _LDCNT2R); 290 tmp |= priv->ch[0].enabled; 291 tmp |= priv->ch[1].enabled; 292 lcdc_write(priv, _LDCNT2R, tmp); 293 294 /* read data from external memory, avoid using the BEU for now */ 295 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); 296 297 /* stop the lcdc first */ 298 sh_mobile_lcdc_start_stop(priv, 0); 299 300 /* configure clocks */ 301 tmp = priv->lddckr; 302 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 303 ch = &priv->ch[k]; 304 305 if (!priv->ch[k].enabled) 306 continue; 307 308 m = ch->cfg.clock_divider; 309 if (!m) 310 continue; 311 312 if (m == 1) 313 m = 1 << 6; 314 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 315 316 lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); 317 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 318 } 319 320 lcdc_write(priv, _LDDCKR, tmp); 321 322 /* start dotclock again */ 323 lcdc_write(priv, _LDDCKSTPR, 0); 324 lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 325 326 /* interrupts are disabled to begin with */ 327 lcdc_write(priv, _LDINTR, 0); 328 329 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 330 ch = &priv->ch[k]; 331 lcd_cfg = &ch->cfg.lcd_cfg; 332 333 if (!ch->enabled) 334 continue; 335 336 tmp = ch->ldmt1r_value; 337 tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; 338 tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; 339 tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; 340 tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; 341 tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; 342 tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; 343 tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; 344 lcdc_write_chan(ch, LDMT1R, tmp); 345 346 /* setup SYS bus */ 347 lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); 348 lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); 349 350 /* horizontal configuration */ 351 tmp = lcd_cfg->xres + lcd_cfg->hsync_len; 352 tmp += lcd_cfg->left_margin; 353 tmp += lcd_cfg->right_margin; 354 tmp /= 8; /* HTCN */ 355 tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */ 356 lcdc_write_chan(ch, LDHCNR, tmp); 357 358 tmp = lcd_cfg->xres; 359 tmp += lcd_cfg->right_margin; 360 tmp /= 8; /* HSYNP */ 361 tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */ 362 lcdc_write_chan(ch, LDHSYNR, tmp); 363 364 /* power supply */ 365 lcdc_write_chan(ch, LDPMR, 0); 366 367 /* vertical configuration */ 368 tmp = lcd_cfg->yres + lcd_cfg->vsync_len; 369 tmp += lcd_cfg->upper_margin; 370 tmp += lcd_cfg->lower_margin; /* VTLN */ 371 tmp |= lcd_cfg->yres << 16; /* VDLN */ 372 lcdc_write_chan(ch, LDVLNR, tmp); 373 374 tmp = lcd_cfg->yres; 375 tmp += lcd_cfg->lower_margin; /* VSYNP */ 376 tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */ 377 lcdc_write_chan(ch, LDVSYNR, tmp); 378 379 board_cfg = &ch->cfg.board_cfg; 380 if (board_cfg->setup_sys) 381 ret = board_cfg->setup_sys(board_cfg->board_data, ch, 382 &sh_mobile_lcdc_sys_bus_ops); 383 if (ret) 384 return ret; 385 } 386 387 /* word and long word swap */ 388 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); 389 390 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 391 ch = &priv->ch[k]; 392 393 if (!priv->ch[k].enabled) 394 continue; 395 396 /* set bpp format in PKF[4:0] */ 397 tmp = lcdc_read_chan(ch, LDDFR); 398 tmp &= ~(0x0001001f); 399 tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0; 400 lcdc_write_chan(ch, LDDFR, tmp); 401 402 /* point out our frame buffer */ 403 lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start); 404 405 /* set line size */ 406 lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length); 407 408 /* setup deferred io if SYS bus */ 409 tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 410 if (ch->ldmt1r_value & (1 << 12) && tmp) { 411 ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 412 ch->defio.delay = msecs_to_jiffies(tmp); 413 ch->info.fbdefio = &ch->defio; 414 fb_deferred_io_init(&ch->info); 415 416 /* one-shot mode */ 417 lcdc_write_chan(ch, LDSM1R, 1); 418 419 /* enable "Frame End Interrupt Enable" bit */ 420 lcdc_write(priv, _LDINTR, LDINTR_FE); 421 422 } else { 423 /* continuous read mode */ 424 lcdc_write_chan(ch, LDSM1R, 0); 425 } 426 } 427 428 /* display output */ 429 lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); 430 431 /* start the lcdc */ 432 sh_mobile_lcdc_start_stop(priv, 1); 433 434 /* tell the board code to enable the panel */ 435 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 436 ch = &priv->ch[k]; 437 board_cfg = &ch->cfg.board_cfg; 438 if (board_cfg->display_on) 439 board_cfg->display_on(board_cfg->board_data); 440 } 441 442 return 0; 443} 444 445static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) 446{ 447 struct sh_mobile_lcdc_chan *ch; 448 struct sh_mobile_lcdc_board_cfg *board_cfg; 449 unsigned long tmp; 450 int k; 451 452 /* tell the board code to disable the panel */ 453 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 454 ch = &priv->ch[k]; 455 board_cfg = &ch->cfg.board_cfg; 456 if (board_cfg->display_off) 457 board_cfg->display_off(board_cfg->board_data); 458 459 /* cleanup deferred io if SYS bus */ 460 tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 461 if (ch->ldmt1r_value & (1 << 12) && tmp) { 462 fb_deferred_io_cleanup(&ch->info); 463 ch->info.fbdefio = NULL; 464 } 465 } 466 467 /* stop the lcdc */ 468 sh_mobile_lcdc_start_stop(priv, 0); 469 470 /* stop clocks */ 471 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 472 if (priv->ch[k].enabled) 473 sh_mobile_lcdc_clk_off(priv); 474} 475 476static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 477{ 478 int ifm, miftyp; 479 480 switch (ch->cfg.interface_type) { 481 case RGB8: ifm = 0; miftyp = 0; break; 482 case RGB9: ifm = 0; miftyp = 4; break; 483 case RGB12A: ifm = 0; miftyp = 5; break; 484 case RGB12B: ifm = 0; miftyp = 6; break; 485 case RGB16: ifm = 0; miftyp = 7; break; 486 case RGB18: ifm = 0; miftyp = 10; break; 487 case RGB24: ifm = 0; miftyp = 11; break; 488 case SYS8A: ifm = 1; miftyp = 0; break; 489 case SYS8B: ifm = 1; miftyp = 1; break; 490 case SYS8C: ifm = 1; miftyp = 2; break; 491 case SYS8D: ifm = 1; miftyp = 3; break; 492 case SYS9: ifm = 1; miftyp = 4; break; 493 case SYS12: ifm = 1; miftyp = 5; break; 494 case SYS16A: ifm = 1; miftyp = 7; break; 495 case SYS16B: ifm = 1; miftyp = 8; break; 496 case SYS16C: ifm = 1; miftyp = 9; break; 497 case SYS18: ifm = 1; miftyp = 10; break; 498 case SYS24: ifm = 1; miftyp = 11; break; 499 default: goto bad; 500 } 501 502 /* SUBLCD only supports SYS interface */ 503 if (lcdc_chan_is_sublcd(ch)) { 504 if (ifm == 0) 505 goto bad; 506 else 507 ifm = 0; 508 } 509 510 ch->ldmt1r_value = (ifm << 12) | miftyp; 511 return 0; 512 bad: 513 return -EINVAL; 514} 515 516static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, 517 int clock_source, 518 struct sh_mobile_lcdc_priv *priv) 519{ 520#ifdef CONFIG_HAVE_CLK 521 char clk_name[8]; 522#endif 523 char *str; 524 int icksel; 525 526 switch (clock_source) { 527 case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break; 528 case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break; 529 case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break; 530 default: 531 return -EINVAL; 532 } 533 534 priv->lddckr = icksel << 16; 535 536#ifdef CONFIG_HAVE_CLK 537 atomic_set(&priv->clk_usecnt, -1); 538 snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id); 539 priv->clk = clk_get(&pdev->dev, clk_name); 540 if (IS_ERR(priv->clk)) { 541 dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); 542 return PTR_ERR(priv->clk); 543 } 544 545 if (str) { 546 priv->dot_clk = clk_get(&pdev->dev, str); 547 if (IS_ERR(priv->dot_clk)) { 548 dev_err(&pdev->dev, "cannot get dot clock %s\n", str); 549 clk_put(priv->clk); 550 return PTR_ERR(priv->dot_clk); 551 } 552 } 553#endif 554 555 return 0; 556} 557 558static int sh_mobile_lcdc_setcolreg(u_int regno, 559 u_int red, u_int green, u_int blue, 560 u_int transp, struct fb_info *info) 561{ 562 u32 *palette = info->pseudo_palette; 563 564 if (regno >= PALETTE_NR) 565 return -EINVAL; 566 567 /* only FB_VISUAL_TRUECOLOR supported */ 568 569 red >>= 16 - info->var.red.length; 570 green >>= 16 - info->var.green.length; 571 blue >>= 16 - info->var.blue.length; 572 transp >>= 16 - info->var.transp.length; 573 574 palette[regno] = (red << info->var.red.offset) | 575 (green << info->var.green.offset) | 576 (blue << info->var.blue.offset) | 577 (transp << info->var.transp.offset); 578 579 return 0; 580} 581 582static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 583 .id = "SH Mobile LCDC", 584 .type = FB_TYPE_PACKED_PIXELS, 585 .visual = FB_VISUAL_TRUECOLOR, 586 .accel = FB_ACCEL_NONE, 587}; 588 589static void sh_mobile_lcdc_fillrect(struct fb_info *info, 590 const struct fb_fillrect *rect) 591{ 592 sys_fillrect(info, rect); 593 sh_mobile_lcdc_deferred_io_touch(info); 594} 595 596static void sh_mobile_lcdc_copyarea(struct fb_info *info, 597 const struct fb_copyarea *area) 598{ 599 sys_copyarea(info, area); 600 sh_mobile_lcdc_deferred_io_touch(info); 601} 602 603static void sh_mobile_lcdc_imageblit(struct fb_info *info, 604 const struct fb_image *image) 605{ 606 sys_imageblit(info, image); 607 sh_mobile_lcdc_deferred_io_touch(info); 608} 609 610static struct fb_ops sh_mobile_lcdc_ops = { 611 .fb_setcolreg = sh_mobile_lcdc_setcolreg, 612 .fb_read = fb_sys_read, 613 .fb_write = fb_sys_write, 614 .fb_fillrect = sh_mobile_lcdc_fillrect, 615 .fb_copyarea = sh_mobile_lcdc_copyarea, 616 .fb_imageblit = sh_mobile_lcdc_imageblit, 617}; 618 619static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) 620{ 621 switch (bpp) { 622 case 16: /* PKF[4:0] = 00011 - RGB 565 */ 623 var->red.offset = 11; 624 var->red.length = 5; 625 var->green.offset = 5; 626 var->green.length = 6; 627 var->blue.offset = 0; 628 var->blue.length = 5; 629 var->transp.offset = 0; 630 var->transp.length = 0; 631 break; 632 633 case 32: /* PKF[4:0] = 00000 - RGB 888 634 * sh7722 pdf says 00RRGGBB but reality is GGBB00RR 635 * this may be because LDDDSR has word swap enabled.. 636 */ 637 var->red.offset = 0; 638 var->red.length = 8; 639 var->green.offset = 24; 640 var->green.length = 8; 641 var->blue.offset = 16; 642 var->blue.length = 8; 643 var->transp.offset = 0; 644 var->transp.length = 0; 645 break; 646 default: 647 return -EINVAL; 648 } 649 var->bits_per_pixel = bpp; 650 var->red.msb_right = 0; 651 var->green.msb_right = 0; 652 var->blue.msb_right = 0; 653 var->transp.msb_right = 0; 654 return 0; 655} 656 657static int sh_mobile_lcdc_remove(struct platform_device *pdev); 658 659static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) 660{ 661 struct fb_info *info; 662 struct sh_mobile_lcdc_priv *priv; 663 struct sh_mobile_lcdc_info *pdata; 664 struct sh_mobile_lcdc_chan_cfg *cfg; 665 struct resource *res; 666 int error; 667 void *buf; 668 int i, j; 669 670 if (!pdev->dev.platform_data) { 671 dev_err(&pdev->dev, "no platform data defined\n"); 672 error = -EINVAL; 673 goto err0; 674 } 675 676 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 677 i = platform_get_irq(pdev, 0); 678 if (!res || i < 0) { 679 dev_err(&pdev->dev, "cannot get platform resources\n"); 680 error = -ENOENT; 681 goto err0; 682 } 683 684 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 685 if (!priv) { 686 dev_err(&pdev->dev, "cannot allocate device data\n"); 687 error = -ENOMEM; 688 goto err0; 689 } 690 691 error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, 692 pdev->dev.bus_id, priv); 693 if (error) { 694 dev_err(&pdev->dev, "unable to request irq\n"); 695 goto err1; 696 } 697 698 priv->irq = i; 699 platform_set_drvdata(pdev, priv); 700 pdata = pdev->dev.platform_data; 701 702 j = 0; 703 for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 704 priv->ch[j].lcdc = priv; 705 memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 706 707 error = sh_mobile_lcdc_check_interface(&priv->ch[i]); 708 if (error) { 709 dev_err(&pdev->dev, "unsupported interface type\n"); 710 goto err1; 711 } 712 713 switch (pdata->ch[i].chan) { 714 case LCDC_CHAN_MAINLCD: 715 priv->ch[j].enabled = 1 << 1; 716 priv->ch[j].reg_offs = lcdc_offs_mainlcd; 717 j++; 718 break; 719 case LCDC_CHAN_SUBLCD: 720 priv->ch[j].enabled = 1 << 2; 721 priv->ch[j].reg_offs = lcdc_offs_sublcd; 722 j++; 723 break; 724 } 725 } 726 727 if (!j) { 728 dev_err(&pdev->dev, "no channels defined\n"); 729 error = -EINVAL; 730 goto err1; 731 } 732 733 error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); 734 if (error) { 735 dev_err(&pdev->dev, "unable to setup clocks\n"); 736 goto err1; 737 } 738 739 priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1); 740 741 for (i = 0; i < j; i++) { 742 info = &priv->ch[i].info; 743 cfg = &priv->ch[i].cfg; 744 745 info->fbops = &sh_mobile_lcdc_ops; 746 info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; 747 info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres; 748 info->var.width = cfg->lcd_size_cfg.width; 749 info->var.height = cfg->lcd_size_cfg.height; 750 info->var.activate = FB_ACTIVATE_NOW; 751 error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp); 752 if (error) 753 break; 754 755 info->fix = sh_mobile_lcdc_fix; 756 info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8); 757 info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres; 758 759 buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, 760 &priv->ch[i].dma_handle, GFP_KERNEL); 761 if (!buf) { 762 dev_err(&pdev->dev, "unable to allocate buffer\n"); 763 error = -ENOMEM; 764 break; 765 } 766 767 info->pseudo_palette = &priv->ch[i].pseudo_palette; 768 info->flags = FBINFO_FLAG_DEFAULT; 769 770 error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 771 if (error < 0) { 772 dev_err(&pdev->dev, "unable to allocate cmap\n"); 773 dma_free_coherent(&pdev->dev, info->fix.smem_len, 774 buf, priv->ch[i].dma_handle); 775 break; 776 } 777 778 memset(buf, 0, info->fix.smem_len); 779 info->fix.smem_start = priv->ch[i].dma_handle; 780 info->screen_base = buf; 781 info->device = &pdev->dev; 782 info->par = &priv->ch[i]; 783 } 784 785 if (error) 786 goto err1; 787 788 error = sh_mobile_lcdc_start(priv); 789 if (error) { 790 dev_err(&pdev->dev, "unable to start hardware\n"); 791 goto err1; 792 } 793 794 for (i = 0; i < j; i++) { 795 error = register_framebuffer(&priv->ch[i].info); 796 if (error < 0) 797 goto err1; 798 } 799 800 for (i = 0; i < j; i++) { 801 info = &priv->ch[i].info; 802 dev_info(info->dev, 803 "registered %s/%s as %dx%d %dbpp.\n", 804 pdev->name, 805 (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ? 806 "mainlcd" : "sublcd", 807 (int) priv->ch[i].cfg.lcd_cfg.xres, 808 (int) priv->ch[i].cfg.lcd_cfg.yres, 809 priv->ch[i].cfg.bpp); 810 811 /* deferred io mode: disable clock to save power */ 812 if (info->fbdefio) 813 sh_mobile_lcdc_clk_off(priv); 814 } 815 816 return 0; 817 err1: 818 sh_mobile_lcdc_remove(pdev); 819 err0: 820 return error; 821} 822 823static int sh_mobile_lcdc_remove(struct platform_device *pdev) 824{ 825 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 826 struct fb_info *info; 827 int i; 828 829 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 830 if (priv->ch[i].info.dev) 831 unregister_framebuffer(&priv->ch[i].info); 832 833 sh_mobile_lcdc_stop(priv); 834 835 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 836 info = &priv->ch[i].info; 837 838 if (!info->device) 839 continue; 840 841 dma_free_coherent(&pdev->dev, info->fix.smem_len, 842 info->screen_base, priv->ch[i].dma_handle); 843 fb_dealloc_cmap(&info->cmap); 844 } 845 846#ifdef CONFIG_HAVE_CLK 847 if (priv->dot_clk) 848 clk_put(priv->dot_clk); 849 clk_put(priv->clk); 850#endif 851 852 if (priv->base) 853 iounmap(priv->base); 854 855 if (priv->irq) 856 free_irq(priv->irq, priv); 857 kfree(priv); 858 return 0; 859} 860 861static struct platform_driver sh_mobile_lcdc_driver = { 862 .driver = { 863 .name = "sh_mobile_lcdc_fb", 864 .owner = THIS_MODULE, 865 }, 866 .probe = sh_mobile_lcdc_probe, 867 .remove = sh_mobile_lcdc_remove, 868}; 869 870static int __init sh_mobile_lcdc_init(void) 871{ 872 return platform_driver_register(&sh_mobile_lcdc_driver); 873} 874 875static void __exit sh_mobile_lcdc_exit(void) 876{ 877 platform_driver_unregister(&sh_mobile_lcdc_driver); 878} 879 880module_init(sh_mobile_lcdc_init); 881module_exit(sh_mobile_lcdc_exit); 882 883MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 884MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 885MODULE_LICENSE("GPL v2");