linux/drivers/video/da8xx-fb.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 MontaVista Software Inc.
   3 * Copyright (C) 2008-2009 Texas Instruments Inc
   4 *
   5 * Based on the LCD driver for TI Avalanche processors written by
   6 * Ajay Singh and Shalom Hai.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option)any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21 */
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/fb.h>
  25#include <linux/dma-mapping.h>
  26#include <linux/device.h>
  27#include <linux/platform_device.h>
  28#include <linux/uaccess.h>
  29#include <linux/interrupt.h>
  30#include <linux/clk.h>
  31#include <linux/cpufreq.h>
  32#include <linux/console.h>
  33#include <linux/slab.h>
  34#include <video/da8xx-fb.h>
  35
  36#define DRIVER_NAME "da8xx_lcdc"
  37
  38/* LCD Status Register */
  39#define LCD_END_OF_FRAME0               BIT(8)
  40#define LCD_FIFO_UNDERFLOW              BIT(5)
  41#define LCD_SYNC_LOST                   BIT(2)
  42
  43/* LCD DMA Control Register */
  44#define LCD_DMA_BURST_SIZE(x)           ((x) << 4)
  45#define LCD_DMA_BURST_1                 0x0
  46#define LCD_DMA_BURST_2                 0x1
  47#define LCD_DMA_BURST_4                 0x2
  48#define LCD_DMA_BURST_8                 0x3
  49#define LCD_DMA_BURST_16                0x4
  50#define LCD_END_OF_FRAME_INT_ENA        BIT(2)
  51#define LCD_DUAL_FRAME_BUFFER_ENABLE    BIT(0)
  52
  53/* LCD Control Register */
  54#define LCD_CLK_DIVISOR(x)              ((x) << 8)
  55#define LCD_RASTER_MODE                 0x01
  56
  57/* LCD Raster Control Register */
  58#define LCD_PALETTE_LOAD_MODE(x)        ((x) << 20)
  59#define PALETTE_AND_DATA                0x00
  60#define PALETTE_ONLY                    0x01
  61
  62#define LCD_MONO_8BIT_MODE              BIT(9)
  63#define LCD_RASTER_ORDER                BIT(8)
  64#define LCD_TFT_MODE                    BIT(7)
  65#define LCD_UNDERFLOW_INT_ENA           BIT(6)
  66#define LCD_MONOCHROME_MODE             BIT(1)
  67#define LCD_RASTER_ENABLE               BIT(0)
  68#define LCD_TFT_ALT_ENABLE              BIT(23)
  69#define LCD_STN_565_ENABLE              BIT(24)
  70
  71/* LCD Raster Timing 2 Register */
  72#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x)      ((x) << 16)
  73#define LCD_AC_BIAS_FREQUENCY(x)                ((x) << 8)
  74#define LCD_SYNC_CTRL                           BIT(25)
  75#define LCD_SYNC_EDGE                           BIT(24)
  76#define LCD_INVERT_PIXEL_CLOCK                  BIT(22)
  77#define LCD_INVERT_LINE_CLOCK                   BIT(21)
  78#define LCD_INVERT_FRAME_CLOCK                  BIT(20)
  79
  80/* LCD Block */
  81#define  LCD_CTRL_REG                           0x4
  82#define  LCD_STAT_REG                           0x8
  83#define  LCD_RASTER_CTRL_REG                    0x28
  84#define  LCD_RASTER_TIMING_0_REG                0x2C
  85#define  LCD_RASTER_TIMING_1_REG                0x30
  86#define  LCD_RASTER_TIMING_2_REG                0x34
  87#define  LCD_DMA_CTRL_REG                       0x40
  88#define  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG        0x44
  89#define  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG     0x48
  90
  91#define WSI_TIMEOUT     50
  92#define PALETTE_SIZE    256
  93#define LEFT_MARGIN     64
  94#define RIGHT_MARGIN    64
  95#define UPPER_MARGIN    32
  96#define LOWER_MARGIN    32
  97
  98static resource_size_t da8xx_fb_reg_base;
  99static struct resource *lcdc_regs;
 100
 101static inline unsigned int lcdc_read(unsigned int addr)
 102{
 103        return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr));
 104}
 105
 106static inline void lcdc_write(unsigned int val, unsigned int addr)
 107{
 108        __raw_writel(val, da8xx_fb_reg_base + (addr));
 109}
 110
 111struct da8xx_fb_par {
 112        resource_size_t p_palette_base;
 113        unsigned char *v_palette_base;
 114        struct clk *lcdc_clk;
 115        int irq;
 116        unsigned short pseudo_palette[16];
 117        unsigned int databuf_sz;
 118        unsigned int palette_sz;
 119        unsigned int pxl_clk;
 120        int blank;
 121#ifdef CONFIG_CPU_FREQ
 122        struct notifier_block   freq_transition;
 123#endif
 124        void (*panel_power_ctrl)(int);
 125};
 126
 127/* Variable Screen Information */
 128static struct fb_var_screeninfo da8xx_fb_var __devinitdata = {
 129        .xoffset = 0,
 130        .yoffset = 0,
 131        .transp = {0, 0, 0},
 132        .nonstd = 0,
 133        .activate = 0,
 134        .height = -1,
 135        .width = -1,
 136        .pixclock = 46666,      /* 46us - AUO display */
 137        .accel_flags = 0,
 138        .left_margin = LEFT_MARGIN,
 139        .right_margin = RIGHT_MARGIN,
 140        .upper_margin = UPPER_MARGIN,
 141        .lower_margin = LOWER_MARGIN,
 142        .sync = 0,
 143        .vmode = FB_VMODE_NONINTERLACED
 144};
 145
 146static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
 147        .id = "DA8xx FB Drv",
 148        .type = FB_TYPE_PACKED_PIXELS,
 149        .type_aux = 0,
 150        .visual = FB_VISUAL_PSEUDOCOLOR,
 151        .xpanstep = 1,
 152        .ypanstep = 1,
 153        .ywrapstep = 1,
 154        .accel = FB_ACCEL_NONE
 155};
 156
 157struct da8xx_panel {
 158        const char      name[25];       /* Full name <vendor>_<model> */
 159        unsigned short  width;
 160        unsigned short  height;
 161        int             hfp;            /* Horizontal front porch */
 162        int             hbp;            /* Horizontal back porch */
 163        int             hsw;            /* Horizontal Sync Pulse Width */
 164        int             vfp;            /* Vertical front porch */
 165        int             vbp;            /* Vertical back porch */
 166        int             vsw;            /* Vertical Sync Pulse Width */
 167        unsigned int    pxl_clk;        /* Pixel clock */
 168        unsigned char   invert_pxl_clk; /* Invert Pixel clock */
 169};
 170
 171static struct da8xx_panel known_lcd_panels[] = {
 172        /* Sharp LCD035Q3DG01 */
 173        [0] = {
 174                .name = "Sharp_LCD035Q3DG01",
 175                .width = 320,
 176                .height = 240,
 177                .hfp = 8,
 178                .hbp = 6,
 179                .hsw = 0,
 180                .vfp = 2,
 181                .vbp = 2,
 182                .vsw = 0,
 183                .pxl_clk = 4608000,
 184                .invert_pxl_clk = 1,
 185        },
 186        /* Sharp LK043T1DG01 */
 187        [1] = {
 188                .name = "Sharp_LK043T1DG01",
 189                .width = 480,
 190                .height = 272,
 191                .hfp = 2,
 192                .hbp = 2,
 193                .hsw = 41,
 194                .vfp = 2,
 195                .vbp = 2,
 196                .vsw = 10,
 197                .pxl_clk = 7833600,
 198                .invert_pxl_clk = 0,
 199        },
 200};
 201
 202/* Enable the Raster Engine of the LCD Controller */
 203static inline void lcd_enable_raster(void)
 204{
 205        u32 reg;
 206
 207        reg = lcdc_read(LCD_RASTER_CTRL_REG);
 208        if (!(reg & LCD_RASTER_ENABLE))
 209                lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
 210}
 211
 212/* Disable the Raster Engine of the LCD Controller */
 213static inline void lcd_disable_raster(void)
 214{
 215        u32 reg;
 216
 217        reg = lcdc_read(LCD_RASTER_CTRL_REG);
 218        if (reg & LCD_RASTER_ENABLE)
 219                lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
 220}
 221
 222static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
 223{
 224        u32 tmp = par->p_palette_base + par->databuf_sz - 4;
 225        u32 reg;
 226
 227        /* Update the databuf in the hw. */
 228        lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
 229        lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
 230
 231        /* Start the DMA. */
 232        reg = lcdc_read(LCD_RASTER_CTRL_REG);
 233        reg &= ~(3 << 20);
 234        if (load_mode == LOAD_DATA)
 235                reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA);
 236        else if (load_mode == LOAD_PALETTE)
 237                reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
 238
 239        lcdc_write(reg, LCD_RASTER_CTRL_REG);
 240}
 241
 242/* Configure the Burst Size of DMA */
 243static int lcd_cfg_dma(int burst_size)
 244{
 245        u32 reg;
 246
 247        reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001;
 248        switch (burst_size) {
 249        case 1:
 250                reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
 251                break;
 252        case 2:
 253                reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
 254                break;
 255        case 4:
 256                reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
 257                break;
 258        case 8:
 259                reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
 260                break;
 261        case 16:
 262                reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
 263                break;
 264        default:
 265                return -EINVAL;
 266        }
 267        lcdc_write(reg, LCD_DMA_CTRL_REG);
 268
 269        return 0;
 270}
 271
 272static void lcd_cfg_ac_bias(int period, int transitions_per_int)
 273{
 274        u32 reg;
 275
 276        /* Set the AC Bias Period and Number of Transisitons per Interrupt */
 277        reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000;
 278        reg |= LCD_AC_BIAS_FREQUENCY(period) |
 279                LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
 280        lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
 281}
 282
 283static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
 284                int front_porch)
 285{
 286        u32 reg;
 287
 288        reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf;
 289        reg |= ((back_porch & 0xff) << 24)
 290            | ((front_porch & 0xff) << 16)
 291            | ((pulse_width & 0x3f) << 10);
 292        lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
 293}
 294
 295static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
 296                int front_porch)
 297{
 298        u32 reg;
 299
 300        reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff;
 301        reg |= ((back_porch & 0xff) << 24)
 302            | ((front_porch & 0xff) << 16)
 303            | ((pulse_width & 0x3f) << 10);
 304        lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
 305}
 306
 307static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
 308{
 309        u32 reg;
 310
 311        reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
 312                                                LCD_MONO_8BIT_MODE |
 313                                                LCD_MONOCHROME_MODE);
 314
 315        switch (cfg->p_disp_panel->panel_shade) {
 316        case MONOCHROME:
 317                reg |= LCD_MONOCHROME_MODE;
 318                if (cfg->mono_8bit_mode)
 319                        reg |= LCD_MONO_8BIT_MODE;
 320                break;
 321        case COLOR_ACTIVE:
 322                reg |= LCD_TFT_MODE;
 323                if (cfg->tft_alt_mode)
 324                        reg |= LCD_TFT_ALT_ENABLE;
 325                break;
 326
 327        case COLOR_PASSIVE:
 328                if (cfg->stn_565_mode)
 329                        reg |= LCD_STN_565_ENABLE;
 330                break;
 331
 332        default:
 333                return -EINVAL;
 334        }
 335
 336        /* enable additional interrupts here */
 337        reg |= LCD_UNDERFLOW_INT_ENA;
 338
 339        lcdc_write(reg, LCD_RASTER_CTRL_REG);
 340
 341        reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
 342
 343        if (cfg->sync_ctrl)
 344                reg |= LCD_SYNC_CTRL;
 345        else
 346                reg &= ~LCD_SYNC_CTRL;
 347
 348        if (cfg->sync_edge)
 349                reg |= LCD_SYNC_EDGE;
 350        else
 351                reg &= ~LCD_SYNC_EDGE;
 352
 353        if (cfg->invert_line_clock)
 354                reg |= LCD_INVERT_LINE_CLOCK;
 355        else
 356                reg &= ~LCD_INVERT_LINE_CLOCK;
 357
 358        if (cfg->invert_frm_clock)
 359                reg |= LCD_INVERT_FRAME_CLOCK;
 360        else
 361                reg &= ~LCD_INVERT_FRAME_CLOCK;
 362
 363        lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
 364
 365        return 0;
 366}
 367
 368static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
 369                u32 bpp, u32 raster_order)
 370{
 371        u32 bpl, reg;
 372
 373        /* Disable Dual Frame Buffer. */
 374        reg = lcdc_read(LCD_DMA_CTRL_REG);
 375        lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE,
 376                                                LCD_DMA_CTRL_REG);
 377        /* Set the Panel Width */
 378        /* Pixels per line = (PPL + 1)*16 */
 379        /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
 380        width &= 0x3f0;
 381        reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
 382        reg &= 0xfffffc00;
 383        reg |= ((width >> 4) - 1) << 4;
 384        lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
 385
 386        /* Set the Panel Height */
 387        reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
 388        reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
 389        lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
 390
 391        /* Set the Raster Order of the Frame Buffer */
 392        reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
 393        if (raster_order)
 394                reg |= LCD_RASTER_ORDER;
 395        lcdc_write(reg, LCD_RASTER_CTRL_REG);
 396
 397        switch (bpp) {
 398        case 1:
 399        case 2:
 400        case 4:
 401        case 16:
 402                par->palette_sz = 16 * 2;
 403                break;
 404
 405        case 8:
 406                par->palette_sz = 256 * 2;
 407                break;
 408
 409        default:
 410                return -EINVAL;
 411        }
 412
 413        bpl = width * bpp / 8;
 414        par->databuf_sz = height * bpl + par->palette_sz;
 415
 416        return 0;
 417}
 418
 419static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 420                              unsigned blue, unsigned transp,
 421                              struct fb_info *info)
 422{
 423        struct da8xx_fb_par *par = info->par;
 424        unsigned short *palette = (unsigned short *)par->v_palette_base;
 425        u_short pal;
 426
 427        if (regno > 255)
 428                return 1;
 429
 430        if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
 431                return 1;
 432
 433        if (info->var.bits_per_pixel == 8) {
 434                red >>= 4;
 435                green >>= 8;
 436                blue >>= 12;
 437
 438                pal = (red & 0x0f00);
 439                pal |= (green & 0x00f0);
 440                pal |= (blue & 0x000f);
 441
 442                palette[regno] = pal;
 443
 444        } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
 445                red >>= (16 - info->var.red.length);
 446                red <<= info->var.red.offset;
 447
 448                green >>= (16 - info->var.green.length);
 449                green <<= info->var.green.offset;
 450
 451                blue >>= (16 - info->var.blue.length);
 452                blue <<= info->var.blue.offset;
 453
 454                par->pseudo_palette[regno] = red | green | blue;
 455
 456                palette[0] = 0x4000;
 457        }
 458
 459        return 0;
 460}
 461
 462static void lcd_reset(struct da8xx_fb_par *par)
 463{
 464        /* Disable the Raster if previously Enabled */
 465        lcd_disable_raster();
 466
 467        /* DMA has to be disabled */
 468        lcdc_write(0, LCD_DMA_CTRL_REG);
 469        lcdc_write(0, LCD_RASTER_CTRL_REG);
 470}
 471
 472static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
 473{
 474        unsigned int lcd_clk, div;
 475
 476        lcd_clk = clk_get_rate(par->lcdc_clk);
 477        div = lcd_clk / par->pxl_clk;
 478
 479        /* Configure the LCD clock divisor. */
 480        lcdc_write(LCD_CLK_DIVISOR(div) |
 481                        (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
 482}
 483
 484static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
 485                struct da8xx_panel *panel)
 486{
 487        u32 bpp;
 488        int ret = 0;
 489
 490        lcd_reset(par);
 491
 492        /* Calculate the divider */
 493        lcd_calc_clk_divider(par);
 494
 495        if (panel->invert_pxl_clk)
 496                lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |
 497                        LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
 498        else
 499                lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) &
 500                        ~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
 501
 502        /* Configure the DMA burst size. */
 503        ret = lcd_cfg_dma(cfg->dma_burst_sz);
 504        if (ret < 0)
 505                return ret;
 506
 507        /* Configure the AC bias properties. */
 508        lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
 509
 510        /* Configure the vertical and horizontal sync properties. */
 511        lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp);
 512        lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp);
 513
 514        /* Configure for disply */
 515        ret = lcd_cfg_display(cfg);
 516        if (ret < 0)
 517                return ret;
 518
 519        if (QVGA != cfg->p_disp_panel->panel_type)
 520                return -EINVAL;
 521
 522        if (cfg->bpp <= cfg->p_disp_panel->max_bpp &&
 523            cfg->bpp >= cfg->p_disp_panel->min_bpp)
 524                bpp = cfg->bpp;
 525        else
 526                bpp = cfg->p_disp_panel->max_bpp;
 527        if (bpp == 12)
 528                bpp = 16;
 529        ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width,
 530                                (unsigned int)panel->height, bpp,
 531                                cfg->raster_order);
 532        if (ret < 0)
 533                return ret;
 534
 535        /* Configure FDD */
 536        lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) |
 537                       (cfg->fdd << 12), LCD_RASTER_CTRL_REG);
 538
 539        return 0;
 540}
 541
 542static irqreturn_t lcdc_irq_handler(int irq, void *arg)
 543{
 544        u32 stat = lcdc_read(LCD_STAT_REG);
 545
 546        if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
 547                lcd_disable_raster();
 548                lcdc_write(stat, LCD_STAT_REG);
 549                lcd_enable_raster();
 550        } else
 551                lcdc_write(stat, LCD_STAT_REG);
 552
 553        return IRQ_HANDLED;
 554}
 555
 556static int fb_check_var(struct fb_var_screeninfo *var,
 557                        struct fb_info *info)
 558{
 559        int err = 0;
 560
 561        switch (var->bits_per_pixel) {
 562        case 1:
 563        case 8:
 564                var->red.offset = 0;
 565                var->red.length = 8;
 566                var->green.offset = 0;
 567                var->green.length = 8;
 568                var->blue.offset = 0;
 569                var->blue.length = 8;
 570                var->transp.offset = 0;
 571                var->transp.length = 0;
 572                break;
 573        case 4:
 574                var->red.offset = 0;
 575                var->red.length = 4;
 576                var->green.offset = 0;
 577                var->green.length = 4;
 578                var->blue.offset = 0;
 579                var->blue.length = 4;
 580                var->transp.offset = 0;
 581                var->transp.length = 0;
 582                break;
 583        case 16:                /* RGB 565 */
 584                var->red.offset = 11;
 585                var->red.length = 5;
 586                var->green.offset = 5;
 587                var->green.length = 6;
 588                var->blue.offset = 0;
 589                var->blue.length = 5;
 590                var->transp.offset = 0;
 591                var->transp.length = 0;
 592                break;
 593        default:
 594                err = -EINVAL;
 595        }
 596
 597        var->red.msb_right = 0;
 598        var->green.msb_right = 0;
 599        var->blue.msb_right = 0;
 600        var->transp.msb_right = 0;
 601        return err;
 602}
 603
 604#ifdef CONFIG_CPU_FREQ
 605static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
 606                                     unsigned long val, void *data)
 607{
 608        struct da8xx_fb_par *par;
 609
 610        par = container_of(nb, struct da8xx_fb_par, freq_transition);
 611        if (val == CPUFREQ_PRECHANGE) {
 612                lcd_disable_raster();
 613        } else if (val == CPUFREQ_POSTCHANGE) {
 614                lcd_calc_clk_divider(par);
 615                lcd_enable_raster();
 616        }
 617
 618        return 0;
 619}
 620
 621static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par)
 622{
 623        par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition;
 624
 625        return cpufreq_register_notifier(&par->freq_transition,
 626                                         CPUFREQ_TRANSITION_NOTIFIER);
 627}
 628
 629static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
 630{
 631        cpufreq_unregister_notifier(&par->freq_transition,
 632                                    CPUFREQ_TRANSITION_NOTIFIER);
 633}
 634#endif
 635
 636static int __devexit fb_remove(struct platform_device *dev)
 637{
 638        struct fb_info *info = dev_get_drvdata(&dev->dev);
 639
 640        if (info) {
 641                struct da8xx_fb_par *par = info->par;
 642
 643#ifdef CONFIG_CPU_FREQ
 644                lcd_da8xx_cpufreq_deregister(par);
 645#endif
 646                if (par->panel_power_ctrl)
 647                        par->panel_power_ctrl(0);
 648
 649                lcd_disable_raster();
 650                lcdc_write(0, LCD_RASTER_CTRL_REG);
 651
 652                /* disable DMA  */
 653                lcdc_write(0, LCD_DMA_CTRL_REG);
 654
 655                unregister_framebuffer(info);
 656                fb_dealloc_cmap(&info->cmap);
 657                dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
 658                                        info->screen_base - PAGE_SIZE,
 659                                        info->fix.smem_start);
 660                free_irq(par->irq, par);
 661                clk_disable(par->lcdc_clk);
 662                clk_put(par->lcdc_clk);
 663                framebuffer_release(info);
 664                iounmap((void __iomem *)da8xx_fb_reg_base);
 665                release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
 666
 667        }
 668        return 0;
 669}
 670
 671static int fb_ioctl(struct fb_info *info, unsigned int cmd,
 672                          unsigned long arg)
 673{
 674        struct lcd_sync_arg sync_arg;
 675
 676        switch (cmd) {
 677        case FBIOGET_CONTRAST:
 678        case FBIOPUT_CONTRAST:
 679        case FBIGET_BRIGHTNESS:
 680        case FBIPUT_BRIGHTNESS:
 681        case FBIGET_COLOR:
 682        case FBIPUT_COLOR:
 683                return -ENOTTY;
 684        case FBIPUT_HSYNC:
 685                if (copy_from_user(&sync_arg, (char *)arg,
 686                                sizeof(struct lcd_sync_arg)))
 687                        return -EFAULT;
 688                lcd_cfg_horizontal_sync(sync_arg.back_porch,
 689                                        sync_arg.pulse_width,
 690                                        sync_arg.front_porch);
 691                break;
 692        case FBIPUT_VSYNC:
 693                if (copy_from_user(&sync_arg, (char *)arg,
 694                                sizeof(struct lcd_sync_arg)))
 695                        return -EFAULT;
 696                lcd_cfg_vertical_sync(sync_arg.back_porch,
 697                                        sync_arg.pulse_width,
 698                                        sync_arg.front_porch);
 699                break;
 700        default:
 701                return -EINVAL;
 702        }
 703        return 0;
 704}
 705
 706static int cfb_blank(int blank, struct fb_info *info)
 707{
 708        struct da8xx_fb_par *par = info->par;
 709        int ret = 0;
 710
 711        if (par->blank == blank)
 712                return 0;
 713
 714        par->blank = blank;
 715        switch (blank) {
 716        case FB_BLANK_UNBLANK:
 717                if (par->panel_power_ctrl)
 718                        par->panel_power_ctrl(1);
 719
 720                lcd_enable_raster();
 721                break;
 722        case FB_BLANK_POWERDOWN:
 723                if (par->panel_power_ctrl)
 724                        par->panel_power_ctrl(0);
 725
 726                lcd_disable_raster();
 727                break;
 728        default:
 729                ret = -EINVAL;
 730        }
 731
 732        return ret;
 733}
 734
 735static struct fb_ops da8xx_fb_ops = {
 736        .owner = THIS_MODULE,
 737        .fb_check_var = fb_check_var,
 738        .fb_setcolreg = fb_setcolreg,
 739        .fb_ioctl = fb_ioctl,
 740        .fb_fillrect = cfb_fillrect,
 741        .fb_copyarea = cfb_copyarea,
 742        .fb_imageblit = cfb_imageblit,
 743        .fb_blank = cfb_blank,
 744};
 745
 746static int __init fb_probe(struct platform_device *device)
 747{
 748        struct da8xx_lcdc_platform_data *fb_pdata =
 749                                                device->dev.platform_data;
 750        struct lcd_ctrl_config *lcd_cfg;
 751        struct da8xx_panel *lcdc_info;
 752        struct fb_info *da8xx_fb_info;
 753        struct clk *fb_clk = NULL;
 754        struct da8xx_fb_par *par;
 755        resource_size_t len;
 756        int ret, i;
 757
 758        if (fb_pdata == NULL) {
 759                dev_err(&device->dev, "Can not get platform data\n");
 760                return -ENOENT;
 761        }
 762
 763        lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);
 764        if (!lcdc_regs) {
 765                dev_err(&device->dev,
 766                        "Can not get memory resource for LCD controller\n");
 767                return -ENOENT;
 768        }
 769
 770        len = resource_size(lcdc_regs);
 771
 772        lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name);
 773        if (!lcdc_regs)
 774                return -EBUSY;
 775
 776        da8xx_fb_reg_base = (resource_size_t)ioremap(lcdc_regs->start, len);
 777        if (!da8xx_fb_reg_base) {
 778                ret = -EBUSY;
 779                goto err_request_mem;
 780        }
 781
 782        fb_clk = clk_get(&device->dev, NULL);
 783        if (IS_ERR(fb_clk)) {
 784                dev_err(&device->dev, "Can not get device clock\n");
 785                ret = -ENODEV;
 786                goto err_ioremap;
 787        }
 788        ret = clk_enable(fb_clk);
 789        if (ret)
 790                goto err_clk_put;
 791
 792        for (i = 0, lcdc_info = known_lcd_panels;
 793                i < ARRAY_SIZE(known_lcd_panels);
 794                i++, lcdc_info++) {
 795                if (strcmp(fb_pdata->type, lcdc_info->name) == 0)
 796                        break;
 797        }
 798
 799        if (i == ARRAY_SIZE(known_lcd_panels)) {
 800                dev_err(&device->dev, "GLCD: No valid panel found\n");
 801                ret = -ENODEV;
 802                goto err_clk_disable;
 803        } else
 804                dev_info(&device->dev, "GLCD: Found %s panel\n",
 805                                        fb_pdata->type);
 806
 807        lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data;
 808
 809        da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
 810                                        &device->dev);
 811        if (!da8xx_fb_info) {
 812                dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
 813                ret = -ENOMEM;
 814                goto err_clk_disable;
 815        }
 816
 817        par = da8xx_fb_info->par;
 818        par->lcdc_clk = fb_clk;
 819        par->pxl_clk = lcdc_info->pxl_clk;
 820        if (fb_pdata->panel_power_ctrl) {
 821                par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
 822                par->panel_power_ctrl(1);
 823        }
 824
 825        if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {
 826                dev_err(&device->dev, "lcd_init failed\n");
 827                ret = -EFAULT;
 828                goto err_release_fb;
 829        }
 830
 831        /* allocate frame buffer */
 832        da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,
 833                                        par->databuf_sz + PAGE_SIZE,
 834                                        (resource_size_t *)
 835                                        &da8xx_fb_info->fix.smem_start,
 836                                        GFP_KERNEL | GFP_DMA);
 837
 838        if (!da8xx_fb_info->screen_base) {
 839                dev_err(&device->dev,
 840                        "GLCD: kmalloc for frame buffer failed\n");
 841                ret = -EINVAL;
 842                goto err_release_fb;
 843        }
 844
 845        /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */
 846        par->v_palette_base = da8xx_fb_info->screen_base +
 847                                (PAGE_SIZE - par->palette_sz);
 848        par->p_palette_base = da8xx_fb_info->fix.smem_start +
 849                                (PAGE_SIZE - par->palette_sz);
 850
 851        /* the rest of the frame buffer is pixel data */
 852        da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;
 853        da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
 854        da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
 855        da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
 856
 857        par->irq = platform_get_irq(device, 0);
 858        if (par->irq < 0) {
 859                ret = -ENOENT;
 860                goto err_release_fb_mem;
 861        }
 862
 863        ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
 864        if (ret)
 865                goto err_release_fb_mem;
 866
 867        /* Initialize par */
 868        da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
 869
 870        da8xx_fb_var.xres = lcdc_info->width;
 871        da8xx_fb_var.xres_virtual = lcdc_info->width;
 872
 873        da8xx_fb_var.yres = lcdc_info->height;
 874        da8xx_fb_var.yres_virtual = lcdc_info->height;
 875
 876        da8xx_fb_var.grayscale =
 877            lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
 878        da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;
 879
 880        da8xx_fb_var.hsync_len = lcdc_info->hsw;
 881        da8xx_fb_var.vsync_len = lcdc_info->vsw;
 882
 883        /* Initialize fbinfo */
 884        da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
 885        da8xx_fb_info->fix = da8xx_fb_fix;
 886        da8xx_fb_info->var = da8xx_fb_var;
 887        da8xx_fb_info->fbops = &da8xx_fb_ops;
 888        da8xx_fb_info->pseudo_palette = par->pseudo_palette;
 889        da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
 890                                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 891
 892        ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
 893        if (ret)
 894                goto err_free_irq;
 895
 896        /* First palette_sz byte of the frame buffer is the palette */
 897        da8xx_fb_info->cmap.len = par->palette_sz;
 898
 899        /* Flush the buffer to the screen. */
 900        lcd_blit(LOAD_DATA, par);
 901
 902        /* initialize var_screeninfo */
 903        da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
 904        fb_set_var(da8xx_fb_info, &da8xx_fb_var);
 905
 906        dev_set_drvdata(&device->dev, da8xx_fb_info);
 907        /* Register the Frame Buffer  */
 908        if (register_framebuffer(da8xx_fb_info) < 0) {
 909                dev_err(&device->dev,
 910                        "GLCD: Frame Buffer Registration Failed!\n");
 911                ret = -EINVAL;
 912                goto err_dealloc_cmap;
 913        }
 914
 915#ifdef CONFIG_CPU_FREQ
 916        ret = lcd_da8xx_cpufreq_register(par);
 917        if (ret) {
 918                dev_err(&device->dev, "failed to register cpufreq\n");
 919                goto err_cpu_freq;
 920        }
 921#endif
 922
 923        /* enable raster engine */
 924        lcd_enable_raster();
 925
 926        return 0;
 927
 928#ifdef CONFIG_CPU_FREQ
 929err_cpu_freq:
 930        unregister_framebuffer(da8xx_fb_info);
 931#endif
 932
 933err_dealloc_cmap:
 934        fb_dealloc_cmap(&da8xx_fb_info->cmap);
 935
 936err_free_irq:
 937        free_irq(par->irq, par);
 938
 939err_release_fb_mem:
 940        dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
 941                                da8xx_fb_info->screen_base - PAGE_SIZE,
 942                                da8xx_fb_info->fix.smem_start);
 943
 944err_release_fb:
 945        framebuffer_release(da8xx_fb_info);
 946
 947err_clk_disable:
 948        clk_disable(fb_clk);
 949
 950err_clk_put:
 951        clk_put(fb_clk);
 952
 953err_ioremap:
 954        iounmap((void __iomem *)da8xx_fb_reg_base);
 955
 956err_request_mem:
 957        release_mem_region(lcdc_regs->start, len);
 958
 959        return ret;
 960}
 961
 962#ifdef CONFIG_PM
 963static int fb_suspend(struct platform_device *dev, pm_message_t state)
 964{
 965        struct fb_info *info = platform_get_drvdata(dev);
 966        struct da8xx_fb_par *par = info->par;
 967
 968        acquire_console_sem();
 969        if (par->panel_power_ctrl)
 970                par->panel_power_ctrl(0);
 971
 972        fb_set_suspend(info, 1);
 973        lcd_disable_raster();
 974        clk_disable(par->lcdc_clk);
 975        release_console_sem();
 976
 977        return 0;
 978}
 979static int fb_resume(struct platform_device *dev)
 980{
 981        struct fb_info *info = platform_get_drvdata(dev);
 982        struct da8xx_fb_par *par = info->par;
 983
 984        acquire_console_sem();
 985        if (par->panel_power_ctrl)
 986                par->panel_power_ctrl(1);
 987
 988        clk_enable(par->lcdc_clk);
 989        lcd_enable_raster();
 990        fb_set_suspend(info, 0);
 991        release_console_sem();
 992
 993        return 0;
 994}
 995#else
 996#define fb_suspend NULL
 997#define fb_resume NULL
 998#endif
 999
1000static struct platform_driver da8xx_fb_driver = {
1001        .probe = fb_probe,
1002        .remove = fb_remove,
1003        .suspend = fb_suspend,
1004        .resume = fb_resume,
1005        .driver = {
1006                   .name = DRIVER_NAME,
1007                   .owner = THIS_MODULE,
1008                   },
1009};
1010
1011static int __init da8xx_fb_init(void)
1012{
1013        return platform_driver_register(&da8xx_fb_driver);
1014}
1015
1016static void __exit da8xx_fb_cleanup(void)
1017{
1018        platform_driver_unregister(&da8xx_fb_driver);
1019}
1020
1021module_init(da8xx_fb_init);
1022module_exit(da8xx_fb_cleanup);
1023
1024MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx");
1025MODULE_AUTHOR("Texas Instruments");
1026MODULE_LICENSE("GPL");
1027
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.