mxsfb.c revision 396fa99e0e58198f400110f2b6432b5b6522476b
1/* 2 * Copyright (C) 2010 Juergen Beisert, Pengutronix 3 * 4 * This code is based on: 5 * Author: Vitaly Wool <vital@embeddedalley.com> 6 * 7 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. 8 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#define DRIVER_NAME "mxsfb" 21 22/** 23 * @file 24 * @brief LCDIF driver for i.MX23 and i.MX28 25 * 26 * The LCDIF support four modes of operation 27 * - MPU interface (to drive smart displays) -> not supported yet 28 * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet 29 * - Dotclock interface (to drive LC displays with RGB data and sync signals) 30 * - DVI (to drive ITU-R BT656) -> not supported yet 31 * 32 * This driver depends on a correct setup of the pins used for this purpose 33 * (platform specific). 34 * 35 * For the developer: Don't forget to set the data bus width to the display 36 * in the imx_fb_videomode structure. You will else end up with ugly colours. 37 * If you fight against jitter you can vary the clock delay. This is a feature 38 * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give 39 * the required value in the imx_fb_videomode structure. 40 */ 41 42#include <linux/module.h> 43#include <linux/kernel.h> 44#include <linux/platform_device.h> 45#include <linux/clk.h> 46#include <linux/dma-mapping.h> 47#include <linux/io.h> 48#include <mach/mxsfb.h> 49 50#define REG_SET 4 51#define REG_CLR 8 52 53#define LCDC_CTRL 0x00 54#define LCDC_CTRL1 0x10 55#define LCDC_V4_CTRL2 0x20 56#define LCDC_V3_TRANSFER_COUNT 0x20 57#define LCDC_V4_TRANSFER_COUNT 0x30 58#define LCDC_V4_CUR_BUF 0x40 59#define LCDC_V4_NEXT_BUF 0x50 60#define LCDC_V3_CUR_BUF 0x30 61#define LCDC_V3_NEXT_BUF 0x40 62#define LCDC_TIMING 0x60 63#define LCDC_VDCTRL0 0x70 64#define LCDC_VDCTRL1 0x80 65#define LCDC_VDCTRL2 0x90 66#define LCDC_VDCTRL3 0xa0 67#define LCDC_VDCTRL4 0xb0 68#define LCDC_DVICTRL0 0xc0 69#define LCDC_DVICTRL1 0xd0 70#define LCDC_DVICTRL2 0xe0 71#define LCDC_DVICTRL3 0xf0 72#define LCDC_DVICTRL4 0x100 73#define LCDC_V4_DATA 0x180 74#define LCDC_V3_DATA 0x1b0 75#define LCDC_V4_DEBUG0 0x1d0 76#define LCDC_V3_DEBUG0 0x1f0 77 78#define CTRL_SFTRST (1 << 31) 79#define CTRL_CLKGATE (1 << 30) 80#define CTRL_BYPASS_COUNT (1 << 19) 81#define CTRL_VSYNC_MODE (1 << 18) 82#define CTRL_DOTCLK_MODE (1 << 17) 83#define CTRL_DATA_SELECT (1 << 16) 84#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) 85#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) 86#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) 87#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) 88#define CTRL_MASTER (1 << 5) 89#define CTRL_DF16 (1 << 3) 90#define CTRL_DF18 (1 << 2) 91#define CTRL_DF24 (1 << 1) 92#define CTRL_RUN (1 << 0) 93 94#define CTRL1_FIFO_CLEAR (1 << 21) 95#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) 96#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) 97 98#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) 99#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) 100#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) 101#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) 102 103 104#define VDCTRL0_ENABLE_PRESENT (1 << 28) 105#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) 106#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) 107#define VDCTRL0_DOTCLK_ACT_FAILING (1 << 25) 108#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) 109#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) 110#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) 111#define VDCTRL0_HALF_LINE (1 << 19) 112#define VDCTRL0_HALF_LINE_MODE (1 << 18) 113#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) 114#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) 115 116#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) 117#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) 118 119#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) 120#define VDCTRL3_VSYNC_ONLY (1 << 28) 121#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) 122#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) 123#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) 124#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff) 125 126#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ 127#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ 128#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18) 129#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) 130 131#define DEBUG0_HSYNC (1 < 26) 132#define DEBUG0_VSYNC (1 < 25) 133 134#define MIN_XRES 120 135#define MIN_YRES 120 136 137#define RED 0 138#define GREEN 1 139#define BLUE 2 140#define TRANSP 3 141 142enum mxsfb_devtype { 143 MXSFB_V3, 144 MXSFB_V4, 145}; 146 147/* CPU dependent register offsets */ 148struct mxsfb_devdata { 149 unsigned transfer_count; 150 unsigned cur_buf; 151 unsigned next_buf; 152 unsigned debug0; 153 unsigned hs_wdth_mask; 154 unsigned hs_wdth_shift; 155 unsigned ipversion; 156}; 157 158struct mxsfb_info { 159 struct fb_info fb_info; 160 struct platform_device *pdev; 161 struct clk *clk; 162 void __iomem *base; /* registers */ 163 unsigned allocated_size; 164 int enabled; 165 unsigned ld_intf_width; 166 unsigned dotclk_delay; 167 const struct mxsfb_devdata *devdata; 168 int mapped; 169}; 170 171#define mxsfb_is_v3(host) (host->devdata->ipversion == 3) 172#define mxsfb_is_v4(host) (host->devdata->ipversion == 4) 173 174static const struct mxsfb_devdata mxsfb_devdata[] = { 175 [MXSFB_V3] = { 176 .transfer_count = LCDC_V3_TRANSFER_COUNT, 177 .cur_buf = LCDC_V3_CUR_BUF, 178 .next_buf = LCDC_V3_NEXT_BUF, 179 .debug0 = LCDC_V3_DEBUG0, 180 .hs_wdth_mask = 0xff, 181 .hs_wdth_shift = 24, 182 .ipversion = 3, 183 }, 184 [MXSFB_V4] = { 185 .transfer_count = LCDC_V4_TRANSFER_COUNT, 186 .cur_buf = LCDC_V4_CUR_BUF, 187 .next_buf = LCDC_V4_NEXT_BUF, 188 .debug0 = LCDC_V4_DEBUG0, 189 .hs_wdth_mask = 0x3fff, 190 .hs_wdth_shift = 18, 191 .ipversion = 4, 192 }, 193}; 194 195#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info)) 196 197/* mask and shift depends on architecture */ 198static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) 199{ 200 return (val & host->devdata->hs_wdth_mask) << 201 host->devdata->hs_wdth_shift; 202} 203 204static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val) 205{ 206 return (val >> host->devdata->hs_wdth_shift) & 207 host->devdata->hs_wdth_mask; 208} 209 210static const struct fb_bitfield def_rgb565[] = { 211 [RED] = { 212 .offset = 11, 213 .length = 5, 214 }, 215 [GREEN] = { 216 .offset = 5, 217 .length = 6, 218 }, 219 [BLUE] = { 220 .offset = 0, 221 .length = 5, 222 }, 223 [TRANSP] = { /* no support for transparency */ 224 .length = 0, 225 } 226}; 227 228static const struct fb_bitfield def_rgb666[] = { 229 [RED] = { 230 .offset = 16, 231 .length = 6, 232 }, 233 [GREEN] = { 234 .offset = 8, 235 .length = 6, 236 }, 237 [BLUE] = { 238 .offset = 0, 239 .length = 6, 240 }, 241 [TRANSP] = { /* no support for transparency */ 242 .length = 0, 243 } 244}; 245 246static const struct fb_bitfield def_rgb888[] = { 247 [RED] = { 248 .offset = 16, 249 .length = 8, 250 }, 251 [GREEN] = { 252 .offset = 8, 253 .length = 8, 254 }, 255 [BLUE] = { 256 .offset = 0, 257 .length = 8, 258 }, 259 [TRANSP] = { /* no support for transparency */ 260 .length = 0, 261 } 262}; 263 264static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf) 265{ 266 chan &= 0xffff; 267 chan >>= 16 - bf->length; 268 return chan << bf->offset; 269} 270 271static int mxsfb_check_var(struct fb_var_screeninfo *var, 272 struct fb_info *fb_info) 273{ 274 struct mxsfb_info *host = to_imxfb_host(fb_info); 275 const struct fb_bitfield *rgb = NULL; 276 277 if (var->xres < MIN_XRES) 278 var->xres = MIN_XRES; 279 if (var->yres < MIN_YRES) 280 var->yres = MIN_YRES; 281 282 var->xres_virtual = var->xres; 283 284 var->yres_virtual = var->yres; 285 286 switch (var->bits_per_pixel) { 287 case 16: 288 /* always expect RGB 565 */ 289 rgb = def_rgb565; 290 break; 291 case 32: 292 switch (host->ld_intf_width) { 293 case STMLCDIF_8BIT: 294 pr_debug("Unsupported LCD bus width mapping\n"); 295 break; 296 case STMLCDIF_16BIT: 297 case STMLCDIF_18BIT: 298 /* 24 bit to 18 bit mapping */ 299 rgb = def_rgb666; 300 break; 301 case STMLCDIF_24BIT: 302 /* real 24 bit */ 303 rgb = def_rgb888; 304 break; 305 } 306 break; 307 default: 308 pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel); 309 return -EINVAL; 310 } 311 312 /* 313 * Copy the RGB parameters for this display 314 * from the machine specific parameters. 315 */ 316 var->red = rgb[RED]; 317 var->green = rgb[GREEN]; 318 var->blue = rgb[BLUE]; 319 var->transp = rgb[TRANSP]; 320 321 return 0; 322} 323 324static void mxsfb_enable_controller(struct fb_info *fb_info) 325{ 326 struct mxsfb_info *host = to_imxfb_host(fb_info); 327 u32 reg; 328 329 dev_dbg(&host->pdev->dev, "%s\n", __func__); 330 331 clk_enable(host->clk); 332 clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); 333 334 /* if it was disabled, re-enable the mode again */ 335 writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); 336 337 /* enable the SYNC signals first, then the DMA engine */ 338 reg = readl(host->base + LCDC_VDCTRL4); 339 reg |= VDCTRL4_SYNC_SIGNALS_ON; 340 writel(reg, host->base + LCDC_VDCTRL4); 341 342 writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET); 343 344 host->enabled = 1; 345} 346 347static void mxsfb_disable_controller(struct fb_info *fb_info) 348{ 349 struct mxsfb_info *host = to_imxfb_host(fb_info); 350 unsigned loop; 351 u32 reg; 352 353 dev_dbg(&host->pdev->dev, "%s\n", __func__); 354 355 /* 356 * Even if we disable the controller here, it will still continue 357 * until its FIFOs are running out of data 358 */ 359 writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_CLR); 360 361 loop = 1000; 362 while (loop) { 363 reg = readl(host->base + LCDC_CTRL); 364 if (!(reg & CTRL_RUN)) 365 break; 366 loop--; 367 } 368 369 writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR); 370 371 clk_disable(host->clk); 372 373 host->enabled = 0; 374} 375 376static int mxsfb_set_par(struct fb_info *fb_info) 377{ 378 struct mxsfb_info *host = to_imxfb_host(fb_info); 379 u32 ctrl, vdctrl0, vdctrl4; 380 int line_size, fb_size; 381 int reenable = 0; 382 383 line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); 384 fb_size = fb_info->var.yres_virtual * line_size; 385 386 if (fb_size > fb_info->fix.smem_len) 387 return -ENOMEM; 388 389 fb_info->fix.line_length = line_size; 390 391 /* 392 * It seems, you can't re-program the controller if it is still running. 393 * This may lead into shifted pictures (FIFO issue?). 394 * So, first stop the controller and drain its FIFOs 395 */ 396 if (host->enabled) { 397 reenable = 1; 398 mxsfb_disable_controller(fb_info); 399 } 400 401 /* clear the FIFOs */ 402 writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); 403 404 ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER | 405 CTRL_SET_BUS_WIDTH(host->ld_intf_width); 406 407 switch (fb_info->var.bits_per_pixel) { 408 case 16: 409 dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n"); 410 ctrl |= CTRL_SET_WORD_LENGTH(0); 411 writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + LCDC_CTRL1); 412 break; 413 case 32: 414 dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n"); 415 ctrl |= CTRL_SET_WORD_LENGTH(3); 416 switch (host->ld_intf_width) { 417 case STMLCDIF_8BIT: 418 dev_dbg(&host->pdev->dev, 419 "Unsupported LCD bus width mapping\n"); 420 return -EINVAL; 421 case STMLCDIF_16BIT: 422 case STMLCDIF_18BIT: 423 /* 24 bit to 18 bit mapping */ 424 ctrl |= CTRL_DF24; /* ignore the upper 2 bits in 425 * each colour component 426 */ 427 break; 428 case STMLCDIF_24BIT: 429 /* real 24 bit */ 430 break; 431 } 432 /* do not use packed pixels = one pixel per word instead */ 433 writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); 434 break; 435 default: 436 dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n", 437 fb_info->var.bits_per_pixel); 438 return -EINVAL; 439 } 440 441 writel(ctrl, host->base + LCDC_CTRL); 442 443 writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) | 444 TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres), 445 host->base + host->devdata->transfer_count); 446 447 vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */ 448 VDCTRL0_VSYNC_PERIOD_UNIT | 449 VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | 450 VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len); 451 if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT) 452 vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; 453 if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT) 454 vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; 455 if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT) 456 vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; 457 if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT) 458 vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING; 459 460 writel(vdctrl0, host->base + LCDC_VDCTRL0); 461 462 /* frame length in lines */ 463 writel(fb_info->var.upper_margin + fb_info->var.vsync_len + 464 fb_info->var.lower_margin + fb_info->var.yres, 465 host->base + LCDC_VDCTRL1); 466 467 /* line length in units of clocks or pixels */ 468 writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) | 469 VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin + 470 fb_info->var.hsync_len + fb_info->var.right_margin + 471 fb_info->var.xres), 472 host->base + LCDC_VDCTRL2); 473 474 writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin + 475 fb_info->var.hsync_len) | 476 SET_VERT_WAIT_CNT(fb_info->var.upper_margin + 477 fb_info->var.vsync_len), 478 host->base + LCDC_VDCTRL3); 479 480 vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres); 481 if (mxsfb_is_v4(host)) 482 vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay); 483 writel(vdctrl4, host->base + LCDC_VDCTRL4); 484 485 writel(fb_info->fix.smem_start + 486 fb_info->fix.line_length * fb_info->var.yoffset, 487 host->base + host->devdata->next_buf); 488 489 if (reenable) 490 mxsfb_enable_controller(fb_info); 491 492 return 0; 493} 494 495static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 496 u_int transp, struct fb_info *fb_info) 497{ 498 unsigned int val; 499 int ret = -EINVAL; 500 501 /* 502 * If greyscale is true, then we convert the RGB value 503 * to greyscale no matter what visual we are using. 504 */ 505 if (fb_info->var.grayscale) 506 red = green = blue = (19595 * red + 38470 * green + 507 7471 * blue) >> 16; 508 509 switch (fb_info->fix.visual) { 510 case FB_VISUAL_TRUECOLOR: 511 /* 512 * 12 or 16-bit True Colour. We encode the RGB value 513 * according to the RGB bitfield information. 514 */ 515 if (regno < 16) { 516 u32 *pal = fb_info->pseudo_palette; 517 518 val = chan_to_field(red, &fb_info->var.red); 519 val |= chan_to_field(green, &fb_info->var.green); 520 val |= chan_to_field(blue, &fb_info->var.blue); 521 522 pal[regno] = val; 523 ret = 0; 524 } 525 break; 526 527 case FB_VISUAL_STATIC_PSEUDOCOLOR: 528 case FB_VISUAL_PSEUDOCOLOR: 529 break; 530 } 531 532 return ret; 533} 534 535static int mxsfb_blank(int blank, struct fb_info *fb_info) 536{ 537 struct mxsfb_info *host = to_imxfb_host(fb_info); 538 539 switch (blank) { 540 case FB_BLANK_POWERDOWN: 541 case FB_BLANK_VSYNC_SUSPEND: 542 case FB_BLANK_HSYNC_SUSPEND: 543 case FB_BLANK_NORMAL: 544 if (host->enabled) 545 mxsfb_disable_controller(fb_info); 546 break; 547 548 case FB_BLANK_UNBLANK: 549 if (!host->enabled) 550 mxsfb_enable_controller(fb_info); 551 break; 552 } 553 return 0; 554} 555 556static int mxsfb_pan_display(struct fb_var_screeninfo *var, 557 struct fb_info *fb_info) 558{ 559 struct mxsfb_info *host = to_imxfb_host(fb_info); 560 unsigned offset; 561 562 if (var->xoffset != 0) 563 return -EINVAL; 564 565 offset = fb_info->fix.line_length * var->yoffset; 566 567 /* update on next VSYNC */ 568 writel(fb_info->fix.smem_start + offset, 569 host->base + host->devdata->next_buf); 570 571 return 0; 572} 573 574static struct fb_ops mxsfb_ops = { 575 .owner = THIS_MODULE, 576 .fb_check_var = mxsfb_check_var, 577 .fb_set_par = mxsfb_set_par, 578 .fb_setcolreg = mxsfb_setcolreg, 579 .fb_blank = mxsfb_blank, 580 .fb_pan_display = mxsfb_pan_display, 581 .fb_fillrect = cfb_fillrect, 582 .fb_copyarea = cfb_copyarea, 583 .fb_imageblit = cfb_imageblit, 584}; 585 586static int __devinit mxsfb_restore_mode(struct mxsfb_info *host) 587{ 588 struct fb_info *fb_info = &host->fb_info; 589 unsigned line_count; 590 unsigned period; 591 unsigned long pa, fbsize; 592 int bits_per_pixel, ofs; 593 u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; 594 struct fb_videomode vmode; 595 596 /* Only restore the mode when the controller is running */ 597 ctrl = readl(host->base + LCDC_CTRL); 598 if (!(ctrl & CTRL_RUN)) 599 return -EINVAL; 600 601 vdctrl0 = readl(host->base + LCDC_VDCTRL0); 602 vdctrl2 = readl(host->base + LCDC_VDCTRL2); 603 vdctrl3 = readl(host->base + LCDC_VDCTRL3); 604 vdctrl4 = readl(host->base + LCDC_VDCTRL4); 605 606 transfer_count = readl(host->base + host->devdata->transfer_count); 607 608 vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count); 609 vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count); 610 611 switch (CTRL_GET_WORD_LENGTH(ctrl)) { 612 case 0: 613 bits_per_pixel = 16; 614 break; 615 case 3: 616 bits_per_pixel = 32; 617 case 1: 618 default: 619 return -EINVAL; 620 } 621 622 fb_info->var.bits_per_pixel = bits_per_pixel; 623 624 vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); 625 vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2); 626 vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len; 627 vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len - 628 vmode.left_margin - vmode.xres; 629 vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0); 630 period = readl(host->base + LCDC_VDCTRL1); 631 vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len; 632 vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres; 633 634 vmode.vmode = FB_VMODE_NONINTERLACED; 635 636 vmode.sync = 0; 637 if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH) 638 vmode.sync |= FB_SYNC_HOR_HIGH_ACT; 639 if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH) 640 vmode.sync |= FB_SYNC_VERT_HIGH_ACT; 641 642 pr_debug("Reconstructed video mode:\n"); 643 pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n", 644 vmode.xres, vmode.yres, 645 vmode.hsync_len, vmode.left_margin, vmode.right_margin, 646 vmode.vsync_len, vmode.upper_margin, vmode.lower_margin); 647 pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock)); 648 649 fb_add_videomode(&vmode, &fb_info->modelist); 650 651 host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl); 652 host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4); 653 654 fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3); 655 656 pa = readl(host->base + host->devdata->cur_buf); 657 fbsize = fb_info->fix.line_length * vmode.yres; 658 if (pa < fb_info->fix.smem_start) 659 return -EINVAL; 660 if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) 661 return -EINVAL; 662 ofs = pa - fb_info->fix.smem_start; 663 if (ofs) { 664 memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); 665 writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf); 666 } 667 668 line_count = fb_info->fix.smem_len / fb_info->fix.line_length; 669 fb_info->fix.ypanstep = 1; 670 671 clk_enable(host->clk); 672 host->enabled = 1; 673 674 return 0; 675} 676 677static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host) 678{ 679 struct fb_info *fb_info = &host->fb_info; 680 struct fb_var_screeninfo *var = &fb_info->var; 681 struct mxsfb_platform_data *pdata = host->pdev->dev.platform_data; 682 dma_addr_t fb_phys; 683 void *fb_virt; 684 unsigned fb_size = pdata->fb_size; 685 686 fb_info->fbops = &mxsfb_ops; 687 fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; 688 strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id)); 689 fb_info->fix.type = FB_TYPE_PACKED_PIXELS; 690 fb_info->fix.ypanstep = 1; 691 fb_info->fix.visual = FB_VISUAL_TRUECOLOR, 692 fb_info->fix.accel = FB_ACCEL_NONE; 693 694 var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16; 695 var->nonstd = 0; 696 var->activate = FB_ACTIVATE_NOW; 697 var->accel_flags = 0; 698 var->vmode = FB_VMODE_NONINTERLACED; 699 700 host->dotclk_delay = pdata->dotclk_delay; 701 host->ld_intf_width = pdata->ld_intf_width; 702 703 /* Memory allocation for framebuffer */ 704 if (pdata->fb_phys) { 705 if (!fb_size) 706 return -EINVAL; 707 708 fb_phys = pdata->fb_phys; 709 710 if (!request_mem_region(fb_phys, fb_size, host->pdev->name)) 711 return -ENOMEM; 712 713 fb_virt = ioremap(fb_phys, fb_size); 714 if (!fb_virt) { 715 release_mem_region(fb_phys, fb_size); 716 return -ENOMEM; 717 } 718 host->mapped = 1; 719 } else { 720 if (!fb_size) 721 fb_size = SZ_2M; /* default */ 722 fb_virt = alloc_pages_exact(fb_size, GFP_DMA); 723 if (!fb_virt) 724 return -ENOMEM; 725 726 fb_phys = virt_to_phys(fb_virt); 727 } 728 729 fb_info->fix.smem_start = fb_phys; 730 fb_info->screen_base = fb_virt; 731 fb_info->screen_size = fb_info->fix.smem_len = fb_size; 732 733 if (mxsfb_restore_mode(host)) 734 memset(fb_virt, 0, fb_size); 735 736 return 0; 737} 738 739static void __devexit mxsfb_free_videomem(struct mxsfb_info *host) 740{ 741 struct fb_info *fb_info = &host->fb_info; 742 743 if (host->mapped) { 744 iounmap(fb_info->screen_base); 745 release_mem_region(fb_info->fix.smem_start, 746 fb_info->screen_size); 747 } else { 748 free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len); 749 } 750} 751 752static int __devinit mxsfb_probe(struct platform_device *pdev) 753{ 754 struct mxsfb_platform_data *pdata = pdev->dev.platform_data; 755 struct resource *res; 756 struct mxsfb_info *host; 757 struct fb_info *fb_info; 758 struct fb_modelist *modelist; 759 int i, ret; 760 761 if (!pdata) { 762 dev_err(&pdev->dev, "No platformdata. Giving up\n"); 763 return -ENODEV; 764 } 765 766 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 767 if (!res) { 768 dev_err(&pdev->dev, "Cannot get memory IO resource\n"); 769 return -ENODEV; 770 } 771 772 if (!request_mem_region(res->start, resource_size(res), pdev->name)) 773 return -EBUSY; 774 775 fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev); 776 if (!fb_info) { 777 dev_err(&pdev->dev, "Failed to allocate fbdev\n"); 778 ret = -ENOMEM; 779 goto error_alloc_info; 780 } 781 782 host = to_imxfb_host(fb_info); 783 784 host->base = ioremap(res->start, resource_size(res)); 785 if (!host->base) { 786 dev_err(&pdev->dev, "ioremap failed\n"); 787 ret = -ENOMEM; 788 goto error_ioremap; 789 } 790 791 host->pdev = pdev; 792 platform_set_drvdata(pdev, host); 793 794 host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; 795 796 host->clk = clk_get(&host->pdev->dev, NULL); 797 if (IS_ERR(host->clk)) { 798 ret = PTR_ERR(host->clk); 799 goto error_getclock; 800 } 801 802 fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); 803 if (!fb_info->pseudo_palette) { 804 ret = -ENOMEM; 805 goto error_pseudo_pallette; 806 } 807 808 INIT_LIST_HEAD(&fb_info->modelist); 809 810 ret = mxsfb_init_fbinfo(host); 811 if (ret != 0) 812 goto error_init_fb; 813 814 for (i = 0; i < pdata->mode_count; i++) 815 fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist); 816 817 modelist = list_first_entry(&fb_info->modelist, 818 struct fb_modelist, list); 819 fb_videomode_to_var(&fb_info->var, &modelist->mode); 820 821 /* init the color fields */ 822 mxsfb_check_var(&fb_info->var, fb_info); 823 824 platform_set_drvdata(pdev, fb_info); 825 826 ret = register_framebuffer(fb_info); 827 if (ret != 0) { 828 dev_err(&pdev->dev,"Failed to register framebuffer\n"); 829 goto error_register; 830 } 831 832 if (!host->enabled) { 833 writel(0, host->base + LCDC_CTRL); 834 mxsfb_set_par(fb_info); 835 mxsfb_enable_controller(fb_info); 836 } 837 838 dev_info(&pdev->dev, "initialized\n"); 839 840 return 0; 841 842error_register: 843 if (host->enabled) 844 clk_disable(host->clk); 845 fb_destroy_modelist(&fb_info->modelist); 846error_init_fb: 847 kfree(fb_info->pseudo_palette); 848error_pseudo_pallette: 849 clk_put(host->clk); 850error_getclock: 851 iounmap(host->base); 852error_ioremap: 853 framebuffer_release(fb_info); 854error_alloc_info: 855 release_mem_region(res->start, resource_size(res)); 856 857 return ret; 858} 859 860static int __devexit mxsfb_remove(struct platform_device *pdev) 861{ 862 struct fb_info *fb_info = platform_get_drvdata(pdev); 863 struct mxsfb_info *host = to_imxfb_host(fb_info); 864 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 865 866 if (host->enabled) 867 mxsfb_disable_controller(fb_info); 868 869 unregister_framebuffer(fb_info); 870 kfree(fb_info->pseudo_palette); 871 mxsfb_free_videomem(host); 872 iounmap(host->base); 873 clk_put(host->clk); 874 875 framebuffer_release(fb_info); 876 release_mem_region(res->start, resource_size(res)); 877 878 platform_set_drvdata(pdev, NULL); 879 880 return 0; 881} 882 883static struct platform_device_id mxsfb_devtype[] = { 884 { 885 .name = "imx23-fb", 886 .driver_data = MXSFB_V3, 887 }, { 888 .name = "imx28-fb", 889 .driver_data = MXSFB_V4, 890 }, { 891 /* sentinel */ 892 } 893}; 894MODULE_DEVICE_TABLE(platform, mxsfb_devtype); 895 896static struct platform_driver mxsfb_driver = { 897 .probe = mxsfb_probe, 898 .remove = __devexit_p(mxsfb_remove), 899 .id_table = mxsfb_devtype, 900 .driver = { 901 .name = DRIVER_NAME, 902 }, 903}; 904 905module_platform_driver(mxsfb_driver); 906 907MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); 908MODULE_AUTHOR("Sascha Hauer, Pengutronix"); 909MODULE_LICENSE("GPL"); 910