linux/drivers/video/mbx/mbxfb.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/video/mbx/mbxfb.c
   3 *
   4 *  Copyright (C) 2006-2007 8D Technologies inc
   5 *  Raphael Assenat <raph@8d.com>
   6 *      - Added video overlay support
   7 *      - Various improvements
   8 *
   9 *  Copyright (C) 2006 Compulab, Ltd.
  10 *  Mike Rapoport <mike@compulab.co.il>
  11 *      - Creation of driver
  12 *
  13 *   Based on pxafb.c
  14 *
  15 * This file is subject to the terms and conditions of the GNU General Public
  16 * License.  See the file COPYING in the main directory of this archive for
  17 * more details.
  18 *
  19 *   Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
  20 *
  21 */
  22
  23#include <linux/delay.h>
  24#include <linux/fb.h>
  25#include <linux/init.h>
  26#include <linux/module.h>
  27#include <linux/platform_device.h>
  28#include <linux/uaccess.h>
  29
  30#include <asm/io.h>
  31
  32#include <video/mbxfb.h>
  33
  34#include "regs.h"
  35#include "reg_bits.h"
  36
  37static unsigned long virt_base_2700;
  38
  39#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
  40
  41/* Without this delay, the graphics appears somehow scaled and
  42 * there is a lot of jitter in scanlines. This delay is probably
  43 * needed only after setting some specific register(s) somewhere,
  44 * not all over the place... */
  45#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
  46
  47#define MIN_XRES        16
  48#define MIN_YRES        16
  49#define MAX_XRES        2048
  50#define MAX_YRES        2048
  51
  52#define MAX_PALETTES    16
  53
  54/* FIXME: take care of different chip revisions with different sizes
  55   of ODFB */
  56#define MEMORY_OFFSET   0x60000
  57
  58struct mbxfb_info {
  59        struct device *dev;
  60
  61        struct resource *fb_res;
  62        struct resource *fb_req;
  63
  64        struct resource *reg_res;
  65        struct resource *reg_req;
  66
  67        void __iomem *fb_virt_addr;
  68        unsigned long fb_phys_addr;
  69
  70        void __iomem *reg_virt_addr;
  71        unsigned long reg_phys_addr;
  72
  73        int (*platform_probe) (struct fb_info * fb);
  74        int (*platform_remove) (struct fb_info * fb);
  75
  76        u32 pseudo_palette[MAX_PALETTES];
  77#ifdef CONFIG_FB_MBX_DEBUG
  78        void *debugfs_data;
  79#endif
  80
  81};
  82
  83static struct fb_var_screeninfo mbxfb_default __devinitdata = {
  84        .xres = 640,
  85        .yres = 480,
  86        .xres_virtual = 640,
  87        .yres_virtual = 480,
  88        .bits_per_pixel = 16,
  89        .red = {11, 5, 0},
  90        .green = {5, 6, 0},
  91        .blue = {0, 5, 0},
  92        .activate = FB_ACTIVATE_TEST,
  93        .height = -1,
  94        .width = -1,
  95        .pixclock = 40000,
  96        .left_margin = 48,
  97        .right_margin = 16,
  98        .upper_margin = 33,
  99        .lower_margin = 10,
 100        .hsync_len = 96,
 101        .vsync_len = 2,
 102        .vmode = FB_VMODE_NONINTERLACED,
 103        .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 104};
 105
 106static struct fb_fix_screeninfo mbxfb_fix  __devinitdata = {
 107        .id = "MBX",
 108        .type = FB_TYPE_PACKED_PIXELS,
 109        .visual = FB_VISUAL_TRUECOLOR,
 110        .xpanstep = 0,
 111        .ypanstep = 0,
 112        .ywrapstep = 0,
 113        .accel = FB_ACCEL_NONE,
 114};
 115
 116struct pixclock_div {
 117        u8 m;
 118        u8 n;
 119        u8 p;
 120};
 121
 122static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
 123                                       struct pixclock_div *div)
 124{
 125        u8 m, n, p;
 126        unsigned int err = 0;
 127        unsigned int min_err = ~0x0;
 128        unsigned int clk;
 129        unsigned int best_clk = 0;
 130        unsigned int ref_clk = 13000;   /* FIXME: take from platform data */
 131        unsigned int pixclock;
 132
 133        /* convert pixclock to KHz */
 134        pixclock = PICOS2KHZ(pixclock_ps);
 135
 136        /* PLL output freq = (ref_clk * M) / (N * 2^P)
 137         *
 138         * M: 1 to 63
 139         * N: 1 to 7
 140         * P: 0 to 7
 141         */
 142
 143        /* RAPH: When N==1, the resulting pixel clock appears to
 144         * get divided by 2. Preventing N=1 by starting the following
 145         * loop at 2 prevents this. Is this a bug with my chip
 146         * revision or something I dont understand? */
 147        for (m = 1; m < 64; m++) {
 148                for (n = 2; n < 8; n++) {
 149                        for (p = 0; p < 8; p++) {
 150                                clk = (ref_clk * m) / (n * (1 << p));
 151                                err = (clk > pixclock) ? (clk - pixclock) :
 152                                        (pixclock - clk);
 153                                if (err < min_err) {
 154                                        min_err = err;
 155                                        best_clk = clk;
 156                                        div->m = m;
 157                                        div->n = n;
 158                                        div->p = p;
 159                                }
 160                        }
 161                }
 162        }
 163        return KHZ2PICOS(best_clk);
 164}
 165
 166static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 167                           u_int trans, struct fb_info *info)
 168{
 169        u32 val, ret = 1;
 170
 171        if (regno < MAX_PALETTES) {
 172                u32 *pal = info->pseudo_palette;
 173
 174                val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
 175                        ((blue & 0xf800) >> 11);
 176                pal[regno] = val;
 177                ret = 0;
 178        }
 179
 180        return ret;
 181}
 182
 183static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 184{
 185        struct pixclock_div div;
 186
 187        var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
 188
 189        if (var->xres < MIN_XRES)
 190                var->xres = MIN_XRES;
 191        if (var->yres < MIN_YRES)
 192                var->yres = MIN_YRES;
 193        if (var->xres > MAX_XRES)
 194                return -EINVAL;
 195        if (var->yres > MAX_YRES)
 196                return -EINVAL;
 197        var->xres_virtual = max(var->xres_virtual, var->xres);
 198        var->yres_virtual = max(var->yres_virtual, var->yres);
 199
 200        switch (var->bits_per_pixel) {
 201                /* 8 bits-per-pixel is not supported yet */
 202        case 8:
 203                return -EINVAL;
 204        case 16:
 205                var->green.length = (var->green.length == 5) ? 5 : 6;
 206                var->red.length = 5;
 207                var->blue.length = 5;
 208                var->transp.length = 6 - var->green.length;
 209                var->blue.offset = 0;
 210                var->green.offset = 5;
 211                var->red.offset = 5 + var->green.length;
 212                var->transp.offset = (5 + var->red.offset) & 15;
 213                break;
 214        case 24:                /* RGB 888   */
 215        case 32:                /* RGBA 8888 */
 216                var->red.offset = 16;
 217                var->red.length = 8;
 218                var->green.offset = 8;
 219                var->green.length = 8;
 220                var->blue.offset = 0;
 221                var->blue.length = 8;
 222                var->transp.length = var->bits_per_pixel - 24;
 223                var->transp.offset = (var->transp.length) ? 24 : 0;
 224                break;
 225        }
 226        var->red.msb_right = 0;
 227        var->green.msb_right = 0;
 228        var->blue.msb_right = 0;
 229        var->transp.msb_right = 0;
 230
 231        return 0;
 232}
 233
 234static int mbxfb_set_par(struct fb_info *info)
 235{
 236        struct fb_var_screeninfo *var = &info->var;
 237        struct pixclock_div div;
 238        ushort hbps, ht, hfps, has;
 239        ushort vbps, vt, vfps, vas;
 240        u32 gsctrl = readl(GSCTRL);
 241        u32 gsadr = readl(GSADR);
 242
 243        info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
 244
 245        /* setup color mode */
 246        gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
 247        /* FIXME: add *WORKING* support for 8-bits per color */
 248        if (info->var.bits_per_pixel == 8) {
 249                return -EINVAL;
 250        } else {
 251                fb_dealloc_cmap(&info->cmap);
 252                gsctrl &= ~GSCTRL_LUT_EN;
 253
 254                info->fix.visual = FB_VISUAL_TRUECOLOR;
 255                switch (info->var.bits_per_pixel) {
 256                case 16:
 257                        if (info->var.green.length == 5)
 258                                gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
 259                        else
 260                                gsctrl |= GSCTRL_GPIXFMT_RGB565;
 261                        break;
 262                case 24:
 263                        gsctrl |= GSCTRL_GPIXFMT_RGB888;
 264                        break;
 265                case 32:
 266                        gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
 267                        break;
 268                }
 269        }
 270
 271        /* setup resolution */
 272        gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
 273        gsctrl |= Gsctrl_Width(info->var.xres) |
 274                Gsctrl_Height(info->var.yres);
 275        write_reg_dly(gsctrl, GSCTRL);
 276
 277        gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
 278        gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
 279                                 (8 * 16) - 1);
 280        write_reg_dly(gsadr, GSADR);
 281
 282        /* setup timings */
 283        var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
 284
 285        write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
 286                Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
 287
 288        hbps = var->hsync_len;
 289        has = hbps + var->left_margin;
 290        hfps = has + var->xres;
 291        ht = hfps + var->right_margin;
 292
 293        vbps = var->vsync_len;
 294        vas = vbps + var->upper_margin;
 295        vfps = vas + var->yres;
 296        vt = vfps + var->lower_margin;
 297
 298        write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
 299        write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
 300        write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
 301        write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
 302
 303        write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
 304        write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
 305        write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
 306        write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
 307        write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
 308
 309        write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 310
 311        write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
 312
 313        return 0;
 314}
 315
 316static int mbxfb_blank(int blank, struct fb_info *info)
 317{
 318        switch (blank) {
 319        case FB_BLANK_POWERDOWN:
 320        case FB_BLANK_VSYNC_SUSPEND:
 321        case FB_BLANK_HSYNC_SUSPEND:
 322        case FB_BLANK_NORMAL:
 323                write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
 324                write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
 325                write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
 326                break;
 327        case FB_BLANK_UNBLANK:
 328                write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 329                write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
 330                break;
 331        }
 332        return 0;
 333}
 334
 335static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
 336{
 337        u32 vsctrl, vscadr, vsadr;
 338        u32 sssize, spoctrl, shctrl;
 339        u32 vubase, vvbase;
 340        u32 vovrclk;
 341
 342        if (set->scaled_width==0 || set->scaled_height==0)
 343                return -EINVAL;
 344
 345        /* read registers which have reserved bits
 346         * so we can write them back as-is. */
 347        vovrclk = readl(VOVRCLK);
 348        vsctrl = readl(VSCTRL);
 349        vscadr = readl(VSCADR);
 350        vubase = readl(VUBASE);
 351        vvbase = readl(VVBASE);
 352        shctrl = readl(SHCTRL);
 353
 354        spoctrl = readl(SPOCTRL);
 355        sssize = readl(SSSIZE);
 356
 357        vsctrl &= ~(    FMsk(VSCTRL_VSWIDTH) |
 358                                        FMsk(VSCTRL_VSHEIGHT) |
 359                                        FMsk(VSCTRL_VPIXFMT) |
 360                                        VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
 361                                        VSCTRL_COSITED );
 362        vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
 363                                VSCTRL_CSC_EN;
 364
 365        vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) );
 366        vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
 367        vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
 368
 369        switch (set->fmt) {
 370        case MBXFB_FMT_YUV16:
 371                vsctrl |= VSCTRL_VPIXFMT_YUV12;
 372
 373                set->Y_stride = ((set->width) + 0xf ) & ~0xf;
 374                break;
 375        case MBXFB_FMT_YUV12:
 376                vsctrl |= VSCTRL_VPIXFMT_YUV12;
 377
 378                set->Y_stride = ((set->width) + 0xf ) & ~0xf;
 379                vubase |= VUBASE_UVHALFSTR;
 380
 381                break;
 382        case MBXFB_FMT_UY0VY1:
 383                vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
 384                set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 385                break;
 386        case MBXFB_FMT_VY0UY1:
 387                vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
 388                set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 389                break;
 390        case MBXFB_FMT_Y0UY1V:
 391                vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
 392                set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 393                break;
 394        case MBXFB_FMT_Y0VY1U:
 395                vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
 396                set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 397                        break;
 398        default:
 399                return -EINVAL;
 400        }
 401
 402        /* VSCTRL has the bits which sets the Video Pixel Format.
 403         * When passing from a packed to planar format,
 404         * if we write VSCTRL first, VVBASE and VUBASE would
 405         * be zero if we would not set them here. (And then,
 406         * the chips hangs and only a reset seems to fix it).
 407         *
 408         * If course, the values calculated here have no meaning
 409         * for packed formats.
 410         */
 411        set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
 412                set->U_offset = set->height * set->Y_stride;
 413                set->V_offset = set->U_offset +
 414                                                set->height * set->UV_stride;
 415        vubase |= Vubase_Ubase_Adr(
 416                        (0x60000 + set->mem_offset + set->U_offset)>>3);
 417        vvbase |= Vvbase_Vbase_Adr(
 418                        (0x60000 + set->mem_offset + set->V_offset)>>3);
 419
 420
 421        vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
 422
 423        if (set->enable)
 424                vscadr |= VSCADR_STR_EN;
 425
 426
 427        vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
 428                Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
 429
 430        sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
 431        sssize = Sssize_Sc_Width(set->scaled_width-1) |
 432                        Sssize_Sc_Height(set->scaled_height-1);
 433
 434        spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
 435                        SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
 436                        FMsk(SPOCTRL_VPITCH));
 437        spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height);
 438
 439        /* Bypass horiz/vert scaler when same size */
 440        if (set->scaled_width == set->width)
 441                spoctrl |= SPOCTRL_H_SC_BP;
 442        if (set->scaled_height == set->height)
 443                spoctrl |= SPOCTRL_V_SC_BP;
 444
 445        shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM);
 446        shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width);
 447
 448        /* Video plane registers */
 449        write_reg(vsctrl, VSCTRL);
 450        write_reg(vscadr, VSCADR);
 451        write_reg(vubase, VUBASE);
 452        write_reg(vvbase, VVBASE);
 453        write_reg(vsadr, VSADR);
 454
 455        /* Video scaler registers */
 456        write_reg(sssize, SSSIZE);
 457        write_reg(spoctrl, SPOCTRL);
 458        write_reg(shctrl, SHCTRL);
 459
 460        /* Clock */
 461        if (set->enable)
 462                vovrclk |= 1;
 463        else
 464                vovrclk &= ~1;
 465
 466        write_reg(vovrclk, VOVRCLK);
 467
 468        return 0;
 469}
 470
 471static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder)
 472{
 473        unsigned long gscadr, vscadr;
 474
 475        if (porder->bottom == porder->top)
 476                return -EINVAL;
 477
 478        gscadr = readl(GSCADR);
 479        vscadr = readl(VSCADR);
 480
 481        gscadr &= ~(FMsk(GSCADR_BLEND_POS));
 482        vscadr &= ~(FMsk(VSCADR_BLEND_POS));
 483
 484        switch (porder->bottom) {
 485        case MBXFB_PLANE_GRAPHICS:
 486                gscadr |= GSCADR_BLEND_GFX;
 487                break;
 488        case MBXFB_PLANE_VIDEO:
 489                vscadr |= VSCADR_BLEND_GFX;
 490                break;
 491        default:
 492                return -EINVAL;
 493        }
 494
 495        switch (porder->top) {
 496        case MBXFB_PLANE_GRAPHICS:
 497                gscadr |= GSCADR_BLEND_VID;
 498                break;
 499        case MBXFB_PLANE_VIDEO:
 500                vscadr |= GSCADR_BLEND_VID;
 501                break;
 502        default:
 503                return -EINVAL;
 504        }
 505
 506        write_reg_dly(vscadr, VSCADR);
 507        write_reg_dly(gscadr, GSCADR);
 508
 509        return 0;
 510
 511}
 512
 513static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha)
 514{
 515        unsigned long vscadr, vbbase, vcmsk;
 516        unsigned long gscadr, gbbase, gdrctrl;
 517
 518        vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) |
 519                                Vbbase_Colkey(alpha->overlay_colorkey);
 520
 521        gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) |
 522                                Gbbase_Colkey(alpha->graphics_colorkey);
 523
 524        vcmsk = readl(VCMSK);
 525        vcmsk &= ~(FMsk(VCMSK_COLKEY_M));
 526        vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask);
 527
 528        gdrctrl = readl(GDRCTRL);
 529        gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM));
 530        gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask);
 531
 532        vscadr = readl(VSCADR);
 533        vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN);
 534
 535        gscadr = readl(GSCADR);
 536        gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC);
 537
 538        switch (alpha->overlay_colorkey_mode) {
 539        case MBXFB_COLORKEY_DISABLED:
 540                break;
 541        case MBXFB_COLORKEY_PREVIOUS:
 542                vscadr |= VSCADR_COLKEY_EN;
 543                break;
 544        case MBXFB_COLORKEY_CURRENT:
 545                vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC;
 546                break;
 547        default:
 548                return -EINVAL;
 549        }
 550
 551        switch (alpha->overlay_blend_mode) {
 552        case MBXFB_ALPHABLEND_NONE:
 553                vscadr |= VSCADR_BLEND_NONE;
 554                break;
 555        case MBXFB_ALPHABLEND_GLOBAL:
 556                vscadr |= VSCADR_BLEND_GLOB;
 557                break;
 558        case MBXFB_ALPHABLEND_PIXEL:
 559                vscadr |= VSCADR_BLEND_PIX;
 560                break;
 561        default:
 562                return -EINVAL;
 563        }
 564
 565        switch (alpha->graphics_colorkey_mode) {
 566        case MBXFB_COLORKEY_DISABLED:
 567                break;
 568        case MBXFB_COLORKEY_PREVIOUS:
 569                gscadr |= GSCADR_COLKEY_EN;
 570                break;
 571        case MBXFB_COLORKEY_CURRENT:
 572                gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC;
 573                break;
 574        default:
 575                return -EINVAL;
 576        }
 577
 578        switch (alpha->graphics_blend_mode) {
 579        case MBXFB_ALPHABLEND_NONE:
 580                gscadr |= GSCADR_BLEND_NONE;
 581                break;
 582        case MBXFB_ALPHABLEND_GLOBAL:
 583                gscadr |= GSCADR_BLEND_GLOB;
 584                break;
 585        case MBXFB_ALPHABLEND_PIXEL:
 586                gscadr |= GSCADR_BLEND_PIX;
 587                break;
 588        default:
 589                return -EINVAL;
 590        }
 591
 592        write_reg_dly(vbbase, VBBASE);
 593        write_reg_dly(gbbase, GBBASE);
 594        write_reg_dly(vcmsk, VCMSK);
 595        write_reg_dly(gdrctrl, GDRCTRL);
 596        write_reg_dly(gscadr, GSCADR);
 597        write_reg_dly(vscadr, VSCADR);
 598
 599        return 0;
 600}
 601
 602static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
 603                                unsigned long arg)
 604{
 605        struct mbxfb_overlaySetup       setup;
 606        struct mbxfb_planeorder         porder;
 607        struct mbxfb_alphaCtl           alpha;
 608        struct mbxfb_reg                        reg;
 609        int res;
 610        __u32 tmp;
 611
 612        switch (cmd)
 613        {
 614                case MBXFB_IOCX_OVERLAY:
 615                        if (copy_from_user(&setup, (void __user*)arg,
 616                                                sizeof(struct mbxfb_overlaySetup)))
 617                                return -EFAULT;
 618
 619                        res = mbxfb_setupOverlay(&setup);
 620                        if (res)
 621                                return res;
 622
 623                        if (copy_to_user((void __user*)arg, &setup,
 624                                                sizeof(struct mbxfb_overlaySetup)))
 625                                return -EFAULT;
 626
 627                        return 0;
 628
 629                case MBXFB_IOCS_PLANEORDER:
 630                        if (copy_from_user(&porder, (void __user*)arg,
 631                                        sizeof(struct mbxfb_planeorder)))
 632                        return -EFAULT;
 633
 634                        return mbxfb_ioctl_planeorder(&porder);
 635
 636                case MBXFB_IOCS_ALPHA:
 637                        if (copy_from_user(&alpha, (void __user*)arg,
 638                                        sizeof(struct mbxfb_alphaCtl)))
 639                        return -EFAULT;
 640
 641                        return mbxfb_ioctl_alphactl(&alpha);
 642
 643                case MBXFB_IOCS_REG:
 644                        if (copy_from_user(&reg, (void __user*)arg,
 645                                                sizeof(struct mbxfb_reg)))
 646                                return -EFAULT;
 647
 648                        if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
 649                                return -EINVAL;
 650
 651                        tmp = readl(virt_base_2700 + reg.addr);
 652                        tmp &= ~reg.mask;
 653                        tmp |= reg.val & reg.mask;
 654                        writel(tmp, virt_base_2700 + reg.addr);
 655
 656                        return 0;
 657                case MBXFB_IOCX_REG:
 658                        if (copy_from_user(&reg, (void __user*)arg,
 659                                                sizeof(struct mbxfb_reg)))
 660                                return -EFAULT;
 661
 662                        if (reg.addr >= 0x10000)        /* regs are from 0x3fe0000 to 0x3feffff */
 663                                return -EINVAL;
 664                        reg.val = readl(virt_base_2700 + reg.addr);
 665
 666                        if (copy_to_user((void __user*)arg, &reg,
 667                                                sizeof(struct mbxfb_reg)))
 668                                return -EFAULT;
 669
 670                        return 0;
 671        }
 672        return -EINVAL;
 673}
 674
 675static struct fb_ops mbxfb_ops = {
 676        .owner = THIS_MODULE,
 677        .fb_check_var = mbxfb_check_var,
 678        .fb_set_par = mbxfb_set_par,
 679        .fb_setcolreg = mbxfb_setcolreg,
 680        .fb_fillrect = cfb_fillrect,
 681        .fb_copyarea = cfb_copyarea,
 682        .fb_imageblit = cfb_imageblit,
 683        .fb_blank = mbxfb_blank,
 684        .fb_ioctl = mbxfb_ioctl,
 685};
 686
 687/*
 688  Enable external SDRAM controller. Assume that all clocks are active
 689  by now.
 690*/
 691static void __devinit setup_memc(struct fb_info *fbi)
 692{
 693        unsigned long tmp;
 694        int i;
 695
 696        /* FIXME: use platfrom specific parameters */
 697        /* setup SDRAM controller */
 698        write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
 699                LMCFG_LMA_TS),
 700               LMCFG);
 701
 702        write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
 703
 704        /* setup SDRAM timings */
 705        write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
 706                Lmtim_Trc(9) | Lmtim_Tdpl(2)),
 707               LMTIM);
 708        /* setup SDRAM refresh rate */
 709        write_reg_dly(0xc2b, LMREFRESH);
 710        /* setup SDRAM type parameters */
 711        write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
 712                LMTYPE_COLSZ_8),
 713               LMTYPE);
 714        /* enable memory controller */
 715        write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
 716        /* perform dummy reads */
 717        for ( i = 0; i < 16; i++ ) {
 718                tmp = readl(fbi->screen_base);
 719        }
 720}
 721
 722static void enable_clocks(struct fb_info *fbi)
 723{
 724        /* enable clocks */
 725        write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
 726        write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
 727        write_reg_dly(0x00000000, CLKSLEEP);
 728
 729        /* PLL output = (Frefclk * M) / (N * 2^P )
 730         *
 731         * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
 732         * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
 733         * */
 734        write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
 735                CORE_PLL_EN),
 736               COREPLL);
 737
 738        write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
 739                DISP_PLL_EN),
 740               DISPPLL);
 741
 742        write_reg_dly(0x00000000, VOVRCLK);
 743        write_reg_dly(PIXCLK_EN, PIXCLK);
 744        write_reg_dly(MEMCLK_EN, MEMCLK);
 745        write_reg_dly(0x00000001, M24CLK);
 746        write_reg_dly(0x00000001, MBXCLK);
 747        write_reg_dly(SDCLK_EN, SDCLK);
 748        write_reg_dly(0x00000001, PIXCLKDIV);
 749}
 750
 751static void __devinit setup_graphics(struct fb_info *fbi)
 752{
 753        unsigned long gsctrl;
 754        unsigned long vscadr;
 755
 756        gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
 757                Gsctrl_Height(fbi->var.yres);
 758        switch (fbi->var.bits_per_pixel) {
 759        case 16:
 760                if (fbi->var.green.length == 5)
 761                        gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
 762                else
 763                        gsctrl |= GSCTRL_GPIXFMT_RGB565;
 764                break;
 765        case 24:
 766                gsctrl |= GSCTRL_GPIXFMT_RGB888;
 767                break;
 768        case 32:
 769                gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
 770                break;
 771        }
 772
 773        write_reg_dly(gsctrl, GSCTRL);
 774        write_reg_dly(0x00000000, GBBASE);
 775        write_reg_dly(0x00ffffff, GDRCTRL);
 776        write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
 777        write_reg_dly(0x00000000, GPLUT);
 778
 779        vscadr = readl(VSCADR);
 780        vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M));
 781        vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE;
 782        write_reg_dly(vscadr, VSCADR);
 783}
 784
 785static void __devinit setup_display(struct fb_info *fbi)
 786{
 787        unsigned long dsctrl = 0;
 788
 789        dsctrl = DSCTRL_BLNK_POL;
 790        if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
 791                dsctrl |= DSCTRL_HS_POL;
 792        if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
 793                dsctrl |= DSCTRL_VS_POL;
 794        write_reg_dly(dsctrl, DSCTRL);
 795        write_reg_dly(0xd0303010, DMCTRL);
 796        write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 797}
 798
 799static void __devinit enable_controller(struct fb_info *fbi)
 800{
 801        u32 svctrl, shctrl;
 802
 803        write_reg_dly(SYSRST_RST, SYSRST);
 804
 805        /* setup a timeout, raise drive strength */
 806        write_reg_dly(0xffffff0c, SYSCFG);
 807
 808        enable_clocks(fbi);
 809        setup_memc(fbi);
 810        setup_graphics(fbi);
 811        setup_display(fbi);
 812
 813        shctrl = readl(SHCTRL);
 814        shctrl &= ~(FMsk(SHCTRL_HINITIAL));
 815        shctrl |= Shctrl_Hinitial(4<<11);
 816        writel(shctrl, SHCTRL);
 817
 818        svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
 819        writel(svctrl, SVCTRL);
 820
 821        writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP
 822                        , SPOCTRL);
 823
 824        /* Those coefficients are good for scaling up. For scaling
 825         * down, the application has to calculate them. */
 826        write_reg(0xff000100, VSCOEFF0);
 827        write_reg(0xfdfcfdfe, VSCOEFF1);
 828        write_reg(0x170d0500, VSCOEFF2);
 829        write_reg(0x3d372d22, VSCOEFF3);
 830        write_reg(0x00000040, VSCOEFF4);
 831
 832        write_reg(0xff010100, HSCOEFF0);
 833        write_reg(0x00000000, HSCOEFF1);
 834        write_reg(0x02010000, HSCOEFF2);
 835        write_reg(0x01020302, HSCOEFF3);
 836        write_reg(0xf9fbfe00, HSCOEFF4);
 837        write_reg(0xfbf7f6f7, HSCOEFF5);
 838        write_reg(0x1c110700, HSCOEFF6);
 839        write_reg(0x3e393127, HSCOEFF7);
 840        write_reg(0x00000040, HSCOEFF8);
 841
 842}
 843
 844#ifdef CONFIG_PM
 845/*
 846 * Power management hooks.  Note that we won't be called from IRQ context,
 847 * unlike the blank functions above, so we may sleep.
 848 */
 849static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
 850{
 851        /* make frame buffer memory enter self-refresh mode */
 852        write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
 853        while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
 854                ; /* empty statement */
 855
 856        /* reset the device, since it's initial state is 'mostly sleeping' */
 857        write_reg_dly(SYSRST_RST, SYSRST);
 858        return 0;
 859}
 860
 861static int mbxfb_resume(struct platform_device *dev)
 862{
 863        struct fb_info *fbi = platform_get_drvdata(dev);
 864
 865        enable_clocks(fbi);
 866/*      setup_graphics(fbi); */
 867/*      setup_display(fbi); */
 868
 869        write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 870        return 0;
 871}
 872#else
 873#define mbxfb_suspend   NULL
 874#define mbxfb_resume    NULL
 875#endif
 876
 877/* debugfs entries */
 878#ifndef CONFIG_FB_MBX_DEBUG
 879#define mbxfb_debugfs_init(x)   do {} while(0)
 880#define mbxfb_debugfs_remove(x) do {} while(0)
 881#endif
 882
 883#define res_size(_r) (((_r)->end - (_r)->start) + 1)
 884
 885static int __devinit mbxfb_probe(struct platform_device *dev)
 886{
 887        int ret;
 888        struct fb_info *fbi;
 889        struct mbxfb_info *mfbi;
 890        struct mbxfb_platform_data *pdata;
 891
 892        dev_dbg(&dev->dev, "mbxfb_probe\n");
 893
 894        pdata = dev->dev.platform_data;
 895        if (!pdata) {
 896                dev_err(&dev->dev, "platform data is required\n");
 897                return -EINVAL;
 898        }
 899
 900        fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
 901        if (fbi == NULL) {
 902                dev_err(&dev->dev, "framebuffer_alloc failed\n");
 903                return -ENOMEM;
 904        }
 905
 906        mfbi = fbi->par;
 907        fbi->pseudo_palette = mfbi->pseudo_palette;
 908
 909
 910        if (pdata->probe)
 911                mfbi->platform_probe = pdata->probe;
 912        if (pdata->remove)
 913                mfbi->platform_remove = pdata->remove;
 914
 915        mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 916        mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
 917
 918        if (!mfbi->fb_res || !mfbi->reg_res) {
 919                dev_err(&dev->dev, "no resources found\n");
 920                ret = -ENODEV;
 921                goto err1;
 922        }
 923
 924        mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
 925                                          res_size(mfbi->fb_res), dev->name);
 926        if (mfbi->fb_req == NULL) {
 927                dev_err(&dev->dev, "failed to claim framebuffer memory\n");
 928                ret = -EINVAL;
 929                goto err1;
 930        }
 931        mfbi->fb_phys_addr = mfbi->fb_res->start;
 932
 933        mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
 934                                           res_size(mfbi->reg_res), dev->name);
 935        if (mfbi->reg_req == NULL) {
 936                dev_err(&dev->dev, "failed to claim Marathon registers\n");
 937                ret = -EINVAL;
 938                goto err2;
 939        }
 940        mfbi->reg_phys_addr = mfbi->reg_res->start;
 941
 942        mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
 943                                              res_size(mfbi->reg_req));
 944        if (!mfbi->reg_virt_addr) {
 945                dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
 946                ret = -EINVAL;
 947                goto err3;
 948        }
 949        virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
 950
 951        mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
 952                                             res_size(mfbi->fb_req));
 953        if (!mfbi->reg_virt_addr) {
 954                dev_err(&dev->dev, "failed to ioremap frame buffer\n");
 955                ret = -EINVAL;
 956                goto err4;
 957        }
 958
 959        fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
 960        fbi->screen_size = pdata->memsize;
 961        fbi->fbops = &mbxfb_ops;
 962
 963        fbi->var = mbxfb_default;
 964        fbi->fix = mbxfb_fix;
 965        fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
 966        fbi->fix.smem_len = pdata->memsize;
 967        fbi->fix.line_length = mbxfb_default.xres_virtual *
 968                                        mbxfb_default.bits_per_pixel / 8;
 969
 970        ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 971        if (ret < 0) {
 972                dev_err(&dev->dev, "fb_alloc_cmap failed\n");
 973                ret = -EINVAL;
 974                goto err5;
 975        }
 976
 977        platform_set_drvdata(dev, fbi);
 978
 979        printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
 980
 981        if (mfbi->platform_probe)
 982                mfbi->platform_probe(fbi);
 983
 984        enable_controller(fbi);
 985
 986        mbxfb_debugfs_init(fbi);
 987
 988        ret = register_framebuffer(fbi);
 989        if (ret < 0) {
 990                dev_err(&dev->dev, "register_framebuffer failed\n");
 991                ret = -EINVAL;
 992                goto err6;
 993        }
 994
 995        return 0;
 996
 997err6:
 998        fb_dealloc_cmap(&fbi->cmap);
 999err5:
1000        iounmap(mfbi->fb_virt_addr);
1001err4:
1002        iounmap(mfbi->reg_virt_addr);
1003err3:
1004        release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
1005err2:
1006        release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
1007err1:
1008        framebuffer_release(fbi);
1009
1010        return ret;
1011}
1012
1013static int __devexit mbxfb_remove(struct platform_device *dev)
1014{
1015        struct fb_info *fbi = platform_get_drvdata(dev);
1016
1017        write_reg_dly(SYSRST_RST, SYSRST);
1018
1019        mbxfb_debugfs_remove(fbi);
1020
1021        if (fbi) {
1022                struct mbxfb_info *mfbi = fbi->par;
1023
1024                unregister_framebuffer(fbi);
1025                if (mfbi) {
1026                        if (mfbi->platform_remove)
1027                                mfbi->platform_remove(fbi);
1028
1029                        if (mfbi->fb_virt_addr)
1030                                iounmap(mfbi->fb_virt_addr);
1031                        if (mfbi->reg_virt_addr)
1032                                iounmap(mfbi->reg_virt_addr);
1033                        if (mfbi->reg_req)
1034                                release_mem_region(mfbi->reg_req->start,
1035                                                   res_size(mfbi->reg_req));
1036                        if (mfbi->fb_req)
1037                                release_mem_region(mfbi->fb_req->start,
1038                                                   res_size(mfbi->fb_req));
1039                }
1040                framebuffer_release(fbi);
1041        }
1042
1043        return 0;
1044}
1045
1046static struct platform_driver mbxfb_driver = {
1047        .probe = mbxfb_probe,
1048        .remove = mbxfb_remove,
1049        .suspend = mbxfb_suspend,
1050        .resume = mbxfb_resume,
1051        .driver = {
1052                .name = "mbx-fb",
1053        },
1054};
1055
1056int __devinit mbxfb_init(void)
1057{
1058        return platform_driver_register(&mbxfb_driver);
1059}
1060
1061static void __devexit mbxfb_exit(void)
1062{
1063        platform_driver_unregister(&mbxfb_driver);
1064}
1065
1066module_init(mbxfb_init);
1067module_exit(mbxfb_exit);
1068
1069MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
1070MODULE_AUTHOR("Mike Rapoport, Compulab");
1071MODULE_LICENSE("GPL");
1072