linux/drivers/video/fb-puv3.c
<<
>>
Prefs
   1/*
   2 * Frame Buffer Driver for PKUnity-v3 Unigfx
   3 * Code specific to PKUnity SoC and UniCore ISA
   4 *
   5 *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
   6 *      Copyright (C) 2001-2010 Guan Xuetao
   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 version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/errno.h>
  16#include <linux/platform_device.h>
  17#include <linux/clk.h>
  18#include <linux/fb.h>
  19#include <linux/init.h>
  20#include <linux/console.h>
  21
  22#include <asm/sizes.h>
  23#include <mach/hardware.h>
  24
  25/* Platform_data reserved for unifb registers. */
  26#define UNIFB_REGS_NUM          10
  27/* RAM reserved for the frame buffer. */
  28#define UNIFB_MEMSIZE           (SZ_4M)         /* 4 MB for 1024*768*32b */
  29
  30/*
  31 * cause UNIGFX don not have EDID
  32 * all the modes are organized as follow
  33 */
  34static const struct fb_videomode unifb_modes[] = {
  35        /* 0 640x480-60 VESA */
  36        { "640x480@60",  60,  640, 480,  25175000,  48, 16, 34, 10,  96, 1,
  37          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  38        /* 1 640x480-75 VESA */
  39        { "640x480@75",  75,  640, 480,  31500000, 120, 16, 18,  1,  64, 1,
  40          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  41        /* 2 800x600-60 VESA */
  42        { "800x600@60",  60,  800, 600,  40000000,  88, 40, 26,  1, 128, 1,
  43          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  44        /* 3 800x600-75 VESA */
  45        { "800x600@75",  75,  800, 600,  49500000, 160, 16, 23,  1,  80, 1,
  46          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  47        /* 4 1024x768-60 VESA */
  48        { "1024x768@60", 60, 1024, 768,  65000000, 160, 24, 34,  3, 136, 1,
  49          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  50        /* 5 1024x768-75 VESA */
  51        { "1024x768@75", 75, 1024, 768,  78750000, 176, 16, 30,  1,  96, 1,
  52          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  53        /* 6 1280x960-60 VESA */
  54        { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38,  1, 112, 1,
  55          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  56        /* 7 1440x900-60 VESA */
  57        { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30,  3, 152, 1,
  58          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  59        /* 8 FIXME 9 1024x600-60 VESA UNTESTED */
  60        { "1024x600@60", 60, 1024, 600,  50650000, 160, 24, 26,  1, 136, 1,
  61          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  62        /* 9 FIXME 10 1024x600-75 VESA UNTESTED */
  63        { "1024x600@75", 75, 1024, 600,  61500000, 176, 16, 23,  1,  96, 1,
  64          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  65        /* 10 FIXME 11 1366x768-60 VESA UNTESTED */
  66        { "1366x768@60", 60, 1366, 768,  85500000, 256, 58, 18,  1,  112, 3,
  67          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
  68};
  69
  70static struct fb_var_screeninfo unifb_default = {
  71        .xres =         640,
  72        .yres =         480,
  73        .xres_virtual = 640,
  74        .yres_virtual = 480,
  75        .bits_per_pixel = 16,
  76        .red =          { 11, 5, 0 },
  77        .green =        { 5,  6, 0 },
  78        .blue =         { 0,  5, 0 },
  79        .activate =     FB_ACTIVATE_NOW,
  80        .height =       -1,
  81        .width =        -1,
  82        .pixclock =     25175000,
  83        .left_margin =  48,
  84        .right_margin = 16,
  85        .upper_margin = 33,
  86        .lower_margin = 10,
  87        .hsync_len =    96,
  88        .vsync_len =    2,
  89        .vmode =        FB_VMODE_NONINTERLACED,
  90};
  91
  92static struct fb_fix_screeninfo unifb_fix = {
  93        .id =           "UNIGFX FB",
  94        .type =         FB_TYPE_PACKED_PIXELS,
  95        .visual =       FB_VISUAL_TRUECOLOR,
  96        .xpanstep =     1,
  97        .ypanstep =     1,
  98        .ywrapstep =    1,
  99        .accel =        FB_ACCEL_NONE,
 100};
 101
 102static void unifb_sync(struct fb_info *info)
 103{
 104        /* TODO: may, this can be replaced by interrupt */
 105        int cnt;
 106
 107        for (cnt = 0; cnt < 0x10000000; cnt++) {
 108                if (readl(UGE_COMMAND) & 0x1000000)
 109                        return;
 110        }
 111
 112        if (cnt > 0x8000000)
 113                dev_warn(info->device, "Warning: UniGFX GE time out ...\n");
 114}
 115
 116static void unifb_prim_fillrect(struct fb_info *info,
 117                                const struct fb_fillrect *region)
 118{
 119        int awidth = region->width;
 120        int aheight = region->height;
 121        int m_iBpp = info->var.bits_per_pixel;
 122        int screen_width = info->var.xres;
 123        int src_sel = 1;        /* from fg_color */
 124        int pat_sel = 1;
 125        int src_x0 = 0;
 126        int dst_x0 = region->dx;
 127        int src_y0 = 0;
 128        int dst_y0 = region->dy;
 129        int rop_alpha_sel = 0;
 130        int rop_alpha_code = 0xCC;
 131        int x_dir = 1;
 132        int y_dir = 1;
 133        int alpha_r = 0;
 134        int alpha_sel = 0;
 135        int dst_pitch = screen_width * (m_iBpp / 8);
 136        int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
 137        int src_pitch = screen_width * (m_iBpp / 8);
 138        int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
 139        unsigned int command = 0;
 140        int clip_region = 0;
 141        int clip_en = 0;
 142        int tp_en = 0;
 143        int fg_color = 0;
 144        int bottom = info->var.yres - 1;
 145        int right = info->var.xres - 1;
 146        int top = 0;
 147
 148        bottom = (bottom << 16) | right;
 149        command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16)
 150                | (x_dir << 20) | (y_dir << 21) | (command << 24)
 151                | (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
 152        src_pitch = (dst_pitch << 16) | src_pitch;
 153        awidth = awidth | (aheight << 16);
 154        alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff)
 155                | (alpha_sel << 16);
 156        src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
 157        dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
 158        fg_color = region->color;
 159
 160        unifb_sync(info);
 161
 162        writel(((u32 *)(info->pseudo_palette))[fg_color], UGE_FCOLOR);
 163        writel(0, UGE_BCOLOR);
 164        writel(src_pitch, UGE_PITCH);
 165        writel(src_offset, UGE_SRCSTART);
 166        writel(dst_offset, UGE_DSTSTART);
 167        writel(awidth, UGE_WIDHEIGHT);
 168        writel(top, UGE_CLIP0);
 169        writel(bottom, UGE_CLIP1);
 170        writel(alpha_r, UGE_ROPALPHA);
 171        writel(src_x0, UGE_SRCXY);
 172        writel(dst_x0, UGE_DSTXY);
 173        writel(command, UGE_COMMAND);
 174}
 175
 176static void unifb_fillrect(struct fb_info *info,
 177                const struct fb_fillrect *region)
 178{
 179        struct fb_fillrect modded;
 180        int vxres, vyres;
 181
 182        if (info->flags & FBINFO_HWACCEL_DISABLED) {
 183                sys_fillrect(info, region);
 184                return;
 185        }
 186
 187        vxres = info->var.xres_virtual;
 188        vyres = info->var.yres_virtual;
 189
 190        memcpy(&modded, region, sizeof(struct fb_fillrect));
 191
 192        if (!modded.width || !modded.height ||
 193            modded.dx >= vxres || modded.dy >= vyres)
 194                return;
 195
 196        if (modded.dx + modded.width > vxres)
 197                modded.width = vxres - modded.dx;
 198        if (modded.dy + modded.height > vyres)
 199                modded.height = vyres - modded.dy;
 200
 201        unifb_prim_fillrect(info, &modded);
 202}
 203
 204static void unifb_prim_copyarea(struct fb_info *info,
 205                                const struct fb_copyarea *area)
 206{
 207        int awidth = area->width;
 208        int aheight = area->height;
 209        int m_iBpp = info->var.bits_per_pixel;
 210        int screen_width = info->var.xres;
 211        int src_sel = 2;        /* from mem */
 212        int pat_sel = 0;
 213        int src_x0 = area->sx;
 214        int dst_x0 = area->dx;
 215        int src_y0 = area->sy;
 216        int dst_y0 = area->dy;
 217
 218        int rop_alpha_sel = 0;
 219        int rop_alpha_code = 0xCC;
 220        int x_dir = 1;
 221        int y_dir = 1;
 222
 223        int alpha_r = 0;
 224        int alpha_sel = 0;
 225        int dst_pitch = screen_width * (m_iBpp / 8);
 226        int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
 227        int src_pitch = screen_width * (m_iBpp / 8);
 228        int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
 229        unsigned int command = 0;
 230        int clip_region = 0;
 231        int clip_en = 1;
 232        int tp_en = 0;
 233        int top = 0;
 234        int bottom = info->var.yres;
 235        int right = info->var.xres;
 236        int fg_color = 0;
 237        int bg_color = 0;
 238
 239        if (src_x0 < 0)
 240                src_x0 = 0;
 241        if (src_y0 < 0)
 242                src_y0 = 0;
 243
 244        if (src_y0 - dst_y0 > 0) {
 245                y_dir = 1;
 246        } else {
 247                y_dir = 0;
 248                src_offset = (src_y0 + aheight) * src_pitch +
 249                                src_x0 * (m_iBpp / 8);
 250                dst_offset = (dst_y0 + aheight) * dst_pitch +
 251                                dst_x0 * (m_iBpp / 8);
 252                src_y0 += aheight;
 253                dst_y0 += aheight;
 254        }
 255
 256        command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16) |
 257                (x_dir << 20) | (y_dir << 21) | (command << 24) |
 258                (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
 259        src_pitch = (dst_pitch << 16) | src_pitch;
 260        awidth = awidth | (aheight << 16);
 261        alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff) |
 262                (alpha_sel << 16);
 263        src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
 264        dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
 265        bottom = (bottom << 16) | right;
 266
 267        unifb_sync(info);
 268
 269        writel(src_pitch, UGE_PITCH);
 270        writel(src_offset, UGE_SRCSTART);
 271        writel(dst_offset, UGE_DSTSTART);
 272        writel(awidth, UGE_WIDHEIGHT);
 273        writel(top, UGE_CLIP0);
 274        writel(bottom, UGE_CLIP1);
 275        writel(bg_color, UGE_BCOLOR);
 276        writel(fg_color, UGE_FCOLOR);
 277        writel(alpha_r, UGE_ROPALPHA);
 278        writel(src_x0, UGE_SRCXY);
 279        writel(dst_x0, UGE_DSTXY);
 280        writel(command, UGE_COMMAND);
 281}
 282
 283static void unifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 284{
 285        struct fb_copyarea modded;
 286        u32 vxres, vyres;
 287        modded.sx = area->sx;
 288        modded.sy = area->sy;
 289        modded.dx = area->dx;
 290        modded.dy = area->dy;
 291        modded.width = area->width;
 292        modded.height = area->height;
 293
 294        if (info->flags & FBINFO_HWACCEL_DISABLED) {
 295                sys_copyarea(info, area);
 296                return;
 297        }
 298
 299        vxres = info->var.xres_virtual;
 300        vyres = info->var.yres_virtual;
 301
 302        if (!modded.width || !modded.height ||
 303            modded.sx >= vxres || modded.sy >= vyres ||
 304            modded.dx >= vxres || modded.dy >= vyres)
 305                return;
 306
 307        if (modded.sx + modded.width > vxres)
 308                modded.width = vxres - modded.sx;
 309        if (modded.dx + modded.width > vxres)
 310                modded.width = vxres - modded.dx;
 311        if (modded.sy + modded.height > vyres)
 312                modded.height = vyres - modded.sy;
 313        if (modded.dy + modded.height > vyres)
 314                modded.height = vyres - modded.dy;
 315
 316        unifb_prim_copyarea(info, &modded);
 317}
 318
 319static void unifb_imageblit(struct fb_info *info, const struct fb_image *image)
 320{
 321        sys_imageblit(info, image);
 322}
 323
 324static u_long get_line_length(int xres_virtual, int bpp)
 325{
 326        u_long length;
 327
 328        length = xres_virtual * bpp;
 329        length = (length + 31) & ~31;
 330        length >>= 3;
 331        return length;
 332}
 333
 334/*
 335 *  Setting the video mode has been split into two parts.
 336 *  First part, xxxfb_check_var, must not write anything
 337 *  to hardware, it should only verify and adjust var.
 338 *  This means it doesn't alter par but it does use hardware
 339 *  data from it to check this var.
 340 */
 341static int unifb_check_var(struct fb_var_screeninfo *var,
 342                         struct fb_info *info)
 343{
 344        u_long line_length;
 345
 346        /*
 347         *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
 348         *  as FB_VMODE_SMOOTH_XPAN is only used internally
 349         */
 350
 351        if (var->vmode & FB_VMODE_CONUPDATE) {
 352                var->vmode |= FB_VMODE_YWRAP;
 353                var->xoffset = info->var.xoffset;
 354                var->yoffset = info->var.yoffset;
 355        }
 356
 357        /*
 358         *  Some very basic checks
 359         */
 360        if (!var->xres)
 361                var->xres = 1;
 362        if (!var->yres)
 363                var->yres = 1;
 364        if (var->xres > var->xres_virtual)
 365                var->xres_virtual = var->xres;
 366        if (var->yres > var->yres_virtual)
 367                var->yres_virtual = var->yres;
 368        if (var->bits_per_pixel <= 1)
 369                var->bits_per_pixel = 1;
 370        else if (var->bits_per_pixel <= 8)
 371                var->bits_per_pixel = 8;
 372        else if (var->bits_per_pixel <= 16)
 373                var->bits_per_pixel = 16;
 374        else if (var->bits_per_pixel <= 24)
 375                var->bits_per_pixel = 24;
 376        else if (var->bits_per_pixel <= 32)
 377                var->bits_per_pixel = 32;
 378        else
 379                return -EINVAL;
 380
 381        if (var->xres_virtual < var->xoffset + var->xres)
 382                var->xres_virtual = var->xoffset + var->xres;
 383        if (var->yres_virtual < var->yoffset + var->yres)
 384                var->yres_virtual = var->yoffset + var->yres;
 385
 386        /*
 387         *  Memory limit
 388         */
 389        line_length =
 390            get_line_length(var->xres_virtual, var->bits_per_pixel);
 391        if (line_length * var->yres_virtual > UNIFB_MEMSIZE)
 392                return -ENOMEM;
 393
 394        /*
 395         * Now that we checked it we alter var. The reason being is that the
 396         * video mode passed in might not work but slight changes to it might
 397         * make it work. This way we let the user know what is acceptable.
 398         */
 399        switch (var->bits_per_pixel) {
 400        case 1:
 401        case 8:
 402                var->red.offset = 0;
 403                var->red.length = 8;
 404                var->green.offset = 0;
 405                var->green.length = 8;
 406                var->blue.offset = 0;
 407                var->blue.length = 8;
 408                var->transp.offset = 0;
 409                var->transp.length = 0;
 410                break;
 411        case 16:                /* RGBA 5551 */
 412                if (var->transp.length) {
 413                        var->red.offset = 0;
 414                        var->red.length = 5;
 415                        var->green.offset = 5;
 416                        var->green.length = 5;
 417                        var->blue.offset = 10;
 418                        var->blue.length = 5;
 419                        var->transp.offset = 15;
 420                        var->transp.length = 1;
 421                } else {        /* RGB 565 */
 422                        var->red.offset = 11;
 423                        var->red.length = 5;
 424                        var->green.offset = 5;
 425                        var->green.length = 6;
 426                        var->blue.offset = 0;
 427                        var->blue.length = 5;
 428                        var->transp.offset = 0;
 429                        var->transp.length = 0;
 430                }
 431                break;
 432        case 24:                /* RGB 888 */
 433                var->red.offset = 0;
 434                var->red.length = 8;
 435                var->green.offset = 8;
 436                var->green.length = 8;
 437                var->blue.offset = 16;
 438                var->blue.length = 8;
 439                var->transp.offset = 0;
 440                var->transp.length = 0;
 441                break;
 442        case 32:                /* RGBA 8888 */
 443                var->red.offset = 16;
 444                var->red.length = 8;
 445                var->green.offset = 8;
 446                var->green.length = 8;
 447                var->blue.offset = 0;
 448                var->blue.length = 8;
 449                var->transp.offset = 24;
 450                var->transp.length = 8;
 451                break;
 452        }
 453        var->red.msb_right = 0;
 454        var->green.msb_right = 0;
 455        var->blue.msb_right = 0;
 456        var->transp.msb_right = 0;
 457
 458        return 0;
 459}
 460
 461/*
 462 * This routine actually sets the video mode. It's in here where we
 463 * the hardware state info->par and fix which can be affected by the
 464 * change in par. For this driver it doesn't do much.
 465 */
 466static int unifb_set_par(struct fb_info *info)
 467{
 468        int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd;
 469        int format;
 470
 471#ifdef CONFIG_PUV3_PM
 472        struct clk *clk_vga;
 473        u32 pixclk = 0;
 474        int i;
 475
 476        for (i = 0; i <= 10; i++) {
 477                if    (info->var.xres         == unifb_modes[i].xres
 478                    && info->var.yres         == unifb_modes[i].yres
 479                    && info->var.upper_margin == unifb_modes[i].upper_margin
 480                    && info->var.lower_margin == unifb_modes[i].lower_margin
 481                    && info->var.left_margin  == unifb_modes[i].left_margin
 482                    && info->var.right_margin == unifb_modes[i].right_margin
 483                    && info->var.hsync_len    == unifb_modes[i].hsync_len
 484                    && info->var.vsync_len    == unifb_modes[i].vsync_len) {
 485                        pixclk = unifb_modes[i].pixclock;
 486                        break;
 487                }
 488        }
 489
 490        /* set clock rate */
 491        clk_vga = clk_get(info->device, "VGA_CLK");
 492        if (clk_vga == ERR_PTR(-ENOENT))
 493                return -ENOENT;
 494
 495        if (pixclk != 0) {
 496                if (clk_set_rate(clk_vga, pixclk)) { /* set clock failed */
 497                        info->fix = unifb_fix;
 498                        info->var = unifb_default;
 499                        if (clk_set_rate(clk_vga, unifb_default.pixclock))
 500                                return -EINVAL;
 501                }
 502        }
 503#endif
 504
 505        info->fix.line_length = get_line_length(info->var.xres_virtual,
 506                                                info->var.bits_per_pixel);
 507
 508        hSyncStart = info->var.xres + info->var.right_margin;
 509        hSyncEnd = hSyncStart + info->var.hsync_len;
 510        hTotal = hSyncEnd + info->var.left_margin;
 511
 512        vSyncStart = info->var.yres + info->var.lower_margin;
 513        vSyncEnd = vSyncStart + info->var.vsync_len;
 514        vTotal = vSyncEnd + info->var.upper_margin;
 515
 516        switch (info->var.bits_per_pixel) {
 517        case 8:
 518                format = UDE_CFG_DST8;
 519                break;
 520        case 16:
 521                format = UDE_CFG_DST16;
 522                break;
 523        case 24:
 524                format = UDE_CFG_DST24;
 525                break;
 526        case 32:
 527                format = UDE_CFG_DST32;
 528                break;
 529        default:
 530                return -EINVAL;
 531        }
 532
 533        writel(info->fix.smem_start, UDE_FSA);
 534        writel(info->var.yres, UDE_LS);
 535        writel(get_line_length(info->var.xres,
 536                        info->var.bits_per_pixel) >> 3, UDE_PS);
 537                        /* >> 3 for hardware required. */
 538        writel((hTotal << 16) | (info->var.xres), UDE_HAT);
 539        writel(((hTotal - 1) << 16) | (info->var.xres - 1), UDE_HBT);
 540        writel(((hSyncEnd - 1) << 16) | (hSyncStart - 1), UDE_HST);
 541        writel((vTotal << 16) | (info->var.yres), UDE_VAT);
 542        writel(((vTotal - 1) << 16) | (info->var.yres - 1), UDE_VBT);
 543        writel(((vSyncEnd - 1) << 16) | (vSyncStart - 1), UDE_VST);
 544        writel(UDE_CFG_GDEN_ENABLE | UDE_CFG_TIMEUP_ENABLE
 545                        | format | 0xC0000001, UDE_CFG);
 546
 547        return 0;
 548}
 549
 550/*
 551 *  Set a single color register. The values supplied are already
 552 *  rounded down to the hardware's capabilities (according to the
 553 *  entries in the var structure). Return != 0 for invalid regno.
 554 */
 555static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 556                         u_int transp, struct fb_info *info)
 557{
 558        if (regno >= 256)       /* no. of hw registers */
 559                return 1;
 560
 561        /* grayscale works only partially under directcolor */
 562        if (info->var.grayscale) {
 563                /* grayscale = 0.30*R + 0.59*G + 0.11*B */
 564                red = green = blue =
 565                    (red * 77 + green * 151 + blue * 28) >> 8;
 566        }
 567
 568#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
 569        switch (info->fix.visual) {
 570        case FB_VISUAL_TRUECOLOR:
 571        case FB_VISUAL_PSEUDOCOLOR:
 572                red = CNVT_TOHW(red, info->var.red.length);
 573                green = CNVT_TOHW(green, info->var.green.length);
 574                blue = CNVT_TOHW(blue, info->var.blue.length);
 575                transp = CNVT_TOHW(transp, info->var.transp.length);
 576                break;
 577        case FB_VISUAL_DIRECTCOLOR:
 578                red = CNVT_TOHW(red, 8);        /* expect 8 bit DAC */
 579                green = CNVT_TOHW(green, 8);
 580                blue = CNVT_TOHW(blue, 8);
 581                /* hey, there is bug in transp handling... */
 582                transp = CNVT_TOHW(transp, 8);
 583                break;
 584        }
 585#undef CNVT_TOHW
 586        /* Truecolor has hardware independent palette */
 587        if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
 588                u32 v;
 589
 590                if (regno >= 16)
 591                        return 1;
 592
 593                v = (red << info->var.red.offset) |
 594                    (green << info->var.green.offset) |
 595                    (blue << info->var.blue.offset) |
 596                    (transp << info->var.transp.offset);
 597                switch (info->var.bits_per_pixel) {
 598                case 8:
 599                        break;
 600                case 16:
 601                case 24:
 602                case 32:
 603                        ((u32 *) (info->pseudo_palette))[regno] = v;
 604                        break;
 605                default:
 606                        return 1;
 607                }
 608                return 0;
 609        }
 610        return 0;
 611}
 612
 613/*
 614 *  Pan or Wrap the Display
 615 *
 616 *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 617 */
 618static int unifb_pan_display(struct fb_var_screeninfo *var,
 619                           struct fb_info *info)
 620{
 621        if (var->vmode & FB_VMODE_YWRAP) {
 622                if (var->yoffset < 0
 623                    || var->yoffset >= info->var.yres_virtual
 624                    || var->xoffset)
 625                        return -EINVAL;
 626        } else {
 627                if (var->xoffset + info->var.xres > info->var.xres_virtual ||
 628                    var->yoffset + info->var.yres > info->var.yres_virtual)
 629                        return -EINVAL;
 630        }
 631        info->var.xoffset = var->xoffset;
 632        info->var.yoffset = var->yoffset;
 633        if (var->vmode & FB_VMODE_YWRAP)
 634                info->var.vmode |= FB_VMODE_YWRAP;
 635        else
 636                info->var.vmode &= ~FB_VMODE_YWRAP;
 637        return 0;
 638}
 639
 640int unifb_mmap(struct fb_info *info,
 641                    struct vm_area_struct *vma)
 642{
 643        unsigned long size = vma->vm_end - vma->vm_start;
 644        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 645        unsigned long pos = info->fix.smem_start + offset;
 646
 647        if (offset + size > info->fix.smem_len)
 648                return -EINVAL;
 649
 650        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 651
 652        if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size,
 653                                vma->vm_page_prot))
 654                return -EAGAIN;
 655
 656        /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
 657        return 0;
 658}
 659
 660static struct fb_ops unifb_ops = {
 661        .fb_read        = fb_sys_read,
 662        .fb_write       = fb_sys_write,
 663        .fb_check_var   = unifb_check_var,
 664        .fb_set_par     = unifb_set_par,
 665        .fb_setcolreg   = unifb_setcolreg,
 666        .fb_pan_display = unifb_pan_display,
 667        .fb_fillrect    = unifb_fillrect,
 668        .fb_copyarea    = unifb_copyarea,
 669        .fb_imageblit   = unifb_imageblit,
 670        .fb_mmap        = unifb_mmap,
 671};
 672
 673/*
 674 *  Initialisation
 675 */
 676static int unifb_probe(struct platform_device *dev)
 677{
 678        struct fb_info *info;
 679        u32 unifb_regs[UNIFB_REGS_NUM];
 680        int retval = -ENOMEM;
 681        struct resource *iomem;
 682        void *videomemory;
 683
 684        videomemory = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP,
 685                                get_order(UNIFB_MEMSIZE));
 686        if (!videomemory)
 687                goto err;
 688
 689        memset(videomemory, 0, UNIFB_MEMSIZE);
 690
 691        unifb_fix.smem_start = virt_to_phys(videomemory);
 692        unifb_fix.smem_len = UNIFB_MEMSIZE;
 693
 694        iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 695        unifb_fix.mmio_start = iomem->start;
 696
 697        info = framebuffer_alloc(sizeof(u32)*256, &dev->dev);
 698        if (!info)
 699                goto err;
 700
 701        info->screen_base = (char __iomem *)videomemory;
 702        info->fbops = &unifb_ops;
 703
 704        retval = fb_find_mode(&info->var, info, NULL,
 705                              unifb_modes, 10, &unifb_modes[0], 16);
 706
 707        if (!retval || (retval == 4))
 708                info->var = unifb_default;
 709
 710        info->fix = unifb_fix;
 711        info->pseudo_palette = info->par;
 712        info->par = NULL;
 713        info->flags = FBINFO_FLAG_DEFAULT;
 714#ifdef FB_ACCEL_PUV3_UNIGFX
 715        info->fix.accel = FB_ACCEL_PUV3_UNIGFX;
 716#endif
 717
 718        retval = fb_alloc_cmap(&info->cmap, 256, 0);
 719        if (retval < 0)
 720                goto err1;
 721
 722        retval = register_framebuffer(info);
 723        if (retval < 0)
 724                goto err2;
 725        platform_set_drvdata(dev, info);
 726        platform_device_add_data(dev, unifb_regs, sizeof(u32) * UNIFB_REGS_NUM);
 727
 728        printk(KERN_INFO
 729               "fb%d: Virtual frame buffer device, using %dM of video memory\n",
 730               info->node, UNIFB_MEMSIZE >> 20);
 731        return 0;
 732err2:
 733        fb_dealloc_cmap(&info->cmap);
 734err1:
 735        framebuffer_release(info);
 736err:
 737        return retval;
 738}
 739
 740static int unifb_remove(struct platform_device *dev)
 741{
 742        struct fb_info *info = platform_get_drvdata(dev);
 743
 744        if (info) {
 745                unregister_framebuffer(info);
 746                fb_dealloc_cmap(&info->cmap);
 747                framebuffer_release(info);
 748        }
 749        return 0;
 750}
 751
 752#ifdef CONFIG_PM
 753static int unifb_resume(struct platform_device *dev)
 754{
 755        int rc = 0;
 756        u32 *unifb_regs = dev->dev.platform_data;
 757
 758        if (dev->dev.power.power_state.event == PM_EVENT_ON)
 759                return 0;
 760
 761        console_lock();
 762
 763        if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
 764                writel(unifb_regs[0], UDE_FSA);
 765                writel(unifb_regs[1], UDE_LS);
 766                writel(unifb_regs[2], UDE_PS);
 767                writel(unifb_regs[3], UDE_HAT);
 768                writel(unifb_regs[4], UDE_HBT);
 769                writel(unifb_regs[5], UDE_HST);
 770                writel(unifb_regs[6], UDE_VAT);
 771                writel(unifb_regs[7], UDE_VBT);
 772                writel(unifb_regs[8], UDE_VST);
 773                writel(unifb_regs[9], UDE_CFG);
 774        }
 775        dev->dev.power.power_state = PMSG_ON;
 776
 777        console_unlock();
 778
 779        return rc;
 780}
 781
 782static int unifb_suspend(struct platform_device *dev, pm_message_t mesg)
 783{
 784        u32 *unifb_regs = dev->dev.platform_data;
 785
 786        unifb_regs[0] = readl(UDE_FSA);
 787        unifb_regs[1] = readl(UDE_LS);
 788        unifb_regs[2] = readl(UDE_PS);
 789        unifb_regs[3] = readl(UDE_HAT);
 790        unifb_regs[4] = readl(UDE_HBT);
 791        unifb_regs[5] = readl(UDE_HST);
 792        unifb_regs[6] = readl(UDE_VAT);
 793        unifb_regs[7] = readl(UDE_VBT);
 794        unifb_regs[8] = readl(UDE_VST);
 795        unifb_regs[9] = readl(UDE_CFG);
 796
 797        if (mesg.event == dev->dev.power.power_state.event)
 798                return 0;
 799
 800        switch (mesg.event) {
 801        case PM_EVENT_FREEZE:           /* about to take snapshot */
 802        case PM_EVENT_PRETHAW:          /* before restoring snapshot */
 803                goto done;
 804        }
 805
 806        console_lock();
 807
 808        /* do nothing... */
 809
 810        console_unlock();
 811
 812done:
 813        dev->dev.power.power_state = mesg;
 814
 815        return 0;
 816}
 817#else
 818#define unifb_resume    NULL
 819#define unifb_suspend   NULL
 820#endif
 821
 822static struct platform_driver unifb_driver = {
 823        .probe   = unifb_probe,
 824        .remove  = unifb_remove,
 825        .resume  = unifb_resume,
 826        .suspend = unifb_suspend,
 827        .driver  = {
 828                .name   = "PKUnity-v3-UNIGFX",
 829        },
 830};
 831
 832static int __init unifb_init(void)
 833{
 834#ifndef MODULE
 835        if (fb_get_options("unifb", NULL))
 836                return -ENODEV;
 837#endif
 838
 839        return platform_driver_register(&unifb_driver);
 840}
 841
 842module_init(unifb_init);
 843
 844static void __exit unifb_exit(void)
 845{
 846        platform_driver_unregister(&unifb_driver);
 847}
 848
 849module_exit(unifb_exit);
 850
 851MODULE_LICENSE("GPL v2");
 852
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.