linux-old/drivers/video/epson1356fb.c
<<
>>
Prefs
   1/*
   2 *      epson1356fb.c  --  Epson SED1356 Framebuffer Driver
   3 *
   4 *      Copyright 2001, 2002, 2003 MontaVista Software Inc.
   5 *      Author: MontaVista Software, Inc.
   6 *              stevel@mvista.com or source@mvista.com
   7 *
   8 *      This program is free software; you can redistribute  it and/or modify it
   9 *      under  the terms of  the GNU General  Public License as published by the
  10 *      Free Software Foundation;  either version 2 of the  License, or (at your
  11 *      option) any later version.
  12 *
  13 *      THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  14 *      WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  15 *      MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  16 *      NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  17 *      INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  18 *      NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  19 *      USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  20 *      ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  21 *      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  22 *      THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23 *
  24 *      You should have received a copy of the  GNU General Public License along
  25 *      with this program; if not, write  to the Free Software Foundation, Inc.,
  26 *      675 Mass Ave, Cambridge, MA 02139, USA.
  27 *
  28 * 
  29 *      TODO:
  30 *
  31 *      Revision history
  32 *      03.12.2001  0.1   Initial release
  33 *
  34 */
  35
  36#include <linux/config.h>
  37#include <linux/version.h>
  38#include <linux/module.h>
  39
  40#include <linux/kernel.h>
  41#include <linux/errno.h>
  42#include <linux/string.h>
  43#include <linux/mm.h>
  44#include <linux/tty.h>
  45#include <linux/slab.h>
  46#include <linux/vmalloc.h>
  47#include <linux/delay.h>
  48#include <linux/interrupt.h>
  49#include <linux/fb.h>
  50#include <linux/selection.h>
  51#include <linux/console.h>
  52#include <linux/init.h>
  53#include <linux/pci.h>
  54#include <linux/nvram.h>
  55#include <linux/kd.h>
  56#include <linux/vt_kern.h>
  57#include <asm/io.h>
  58#include <asm/uaccess.h>
  59#include <linux/timer.h>
  60#include <linux/pagemap.h>
  61
  62#include <asm/pgalloc.h>
  63#include <asm/uaccess.h>
  64#include <asm/tlb.h>
  65
  66#ifdef CONFIG_MTRR
  67#include <asm/mtrr.h>
  68#endif
  69
  70#include <video/fbcon.h>
  71#include <video/fbcon-cfb8.h>
  72#include <video/fbcon-cfb16.h>
  73#include <video/fbcon-cfb24.h>
  74#include <video/fbcon-cfb32.h>
  75
  76#include <linux/spinlock.h>
  77
  78#include <video/e1356fb.h>
  79
  80#ifdef CONFIG_SOC_AU1X00
  81#include <asm/au1000.h>
  82#endif
  83
  84#define E1356FB_DEBUG 1
  85#undef E1356FB_VERBOSE_DEBUG
  86#undef SHADOW_FRAME_BUFFER
  87#include "epson1356fb.h"
  88
  89static char *options;
  90MODULE_PARM(options, "s");
  91
  92/*
  93 *  Frame buffer device API
  94 */
  95static int e1356fb_open(struct fb_info *fb, int user);
  96static int e1356fb_release(struct fb_info *fb, int user);
  97static int e1356fb_get_fix(struct fb_fix_screeninfo* fix, 
  98                           int con,
  99                           struct fb_info* fb);
 100static int e1356fb_get_var(struct fb_var_screeninfo* var, 
 101                           int con,
 102                           struct fb_info* fb);
 103static int e1356fb_set_var(struct fb_var_screeninfo* var,
 104                           int con,
 105                           struct fb_info* fb);
 106static int e1356fb_pan_display(struct fb_var_screeninfo* var, 
 107                               int con,
 108                               struct fb_info* fb);
 109static int e1356fb_get_cmap(struct fb_cmap *cmap, 
 110                            int kspc, 
 111                            int con,
 112                            struct fb_info* info);
 113static int e1356fb_set_cmap(struct fb_cmap* cmap, 
 114                            int kspc, 
 115                            int con,
 116                            struct fb_info* info);
 117static int e1356fb_ioctl(struct inode* inode, 
 118                         struct file* file, 
 119                         u_int cmd,
 120                         u_long arg, 
 121                         int con, 
 122                         struct fb_info* info);
 123static int e1356fb_mmap(struct fb_info *info,
 124                        struct file *file,
 125                        struct vm_area_struct *vma);
 126
 127/*
 128 *  Interface to the low level console driver
 129 */
 130static int  e1356fb_switch_con(int con, 
 131                               struct fb_info* fb);
 132static int  e1356fb_updatevar(int con, 
 133                              struct fb_info* fb);
 134static void e1356fb_blank(int blank, 
 135                          struct fb_info* fb);
 136
 137/*
 138 *  Internal routines
 139 */
 140static void e1356fb_set_par(const struct e1356fb_par* par,
 141                            struct fb_info_e1356* 
 142                            info);
 143static int  e1356fb_var_to_par(const struct fb_var_screeninfo *var,
 144                               struct e1356fb_par* par,
 145                               const struct fb_info_e1356* info);
 146static int  e1356fb_par_to_var(struct fb_var_screeninfo* var,
 147                               struct e1356fb_par* par,
 148                               const struct fb_info_e1356* info);
 149static int  e1356fb_encode_fix(struct fb_fix_screeninfo* fix,
 150                               const struct e1356fb_par* par,
 151                               const struct fb_info_e1356* info);
 152static void e1356fb_set_dispsw(struct display* disp, 
 153                               struct fb_info_e1356* info,
 154                               int bpp, 
 155                               int accel);
 156static int  e1356fb_getcolreg(u_int regno,
 157                              u_int* red, 
 158                              u_int* green, 
 159                              u_int* blue,
 160                              u_int* transp, 
 161                              struct fb_info* fb);
 162static int  e1356fb_setcolreg(u_int regno, 
 163                              u_int red, 
 164                              u_int green, 
 165                              u_int blue,
 166                              u_int transp, 
 167                              struct fb_info* fb);
 168static void  e1356fb_install_cmap(struct display *d, 
 169                                  struct fb_info *info);
 170
 171static void e1356fb_hwcursor_init(struct fb_info_e1356* info);
 172static void e1356fb_createcursorshape(struct display* p);
 173static void e1356fb_createcursor(struct display * p);  
 174
 175/*
 176 * do_xxx: Hardware-specific functions
 177 */
 178static void  do_pan_var(struct fb_var_screeninfo* var,
 179                        struct fb_info_e1356* i);
 180static void  do_flashcursor(unsigned long ptr);
 181static void  doBlt_Move(const struct e1356fb_par* par,
 182                        struct fb_info_e1356* i,
 183                        blt_info_t* blt);
 184static void  doBlt_SolidFill(const struct e1356fb_par* par,
 185                             struct fb_info_e1356* i,
 186                             blt_info_t* blt);
 187
 188/*
 189 *  Interface used by the world
 190 */
 191int e1356fb_init(void);
 192void e1356fb_setup(char *options, int *ints);
 193
 194static int currcon = 0;
 195
 196static struct fb_ops e1356fb_ops = {
 197        owner:  THIS_MODULE,
 198        fb_open:        e1356fb_open,
 199        fb_release:     e1356fb_release,
 200        fb_get_fix:     e1356fb_get_fix,
 201        fb_get_var:     e1356fb_get_var,
 202        fb_set_var:     e1356fb_set_var,
 203        fb_get_cmap:    e1356fb_get_cmap,
 204        fb_set_cmap:    e1356fb_set_cmap,
 205        fb_pan_display: e1356fb_pan_display,
 206        fb_ioctl:       e1356fb_ioctl,
 207        fb_mmap:        e1356fb_mmap,
 208};
 209
 210#define PCI_VENDOR_ID_EPSON         0x10f4
 211#define PCI_DEVICE_ID_EPSON_SDU1356 0x1300
 212
 213
 214static struct fb_info_e1356 fb_info;
 215static struct e1356fb_fix boot_fix; // boot options
 216static struct e1356fb_par boot_par; // boot options
 217
 218/* ------------------------------------------------------------------------- 
 219 *                      Hardware-specific funcions
 220 * ------------------------------------------------------------------------- */
 221
 222/*
 223 * The SED1356 has only a 16-bit wide data bus, so some embedded
 224 * implementations with 32-bit CPU's (Alchemy Pb1000) may not
 225 * correctly emulate a 32-bit write to the framebuffer by splitting
 226 * the write into two seperate 16-bit writes. So it is safest to
 227 * only do byte or half-word writes to the fb. This routine assumes
 228 * fbaddr is atleast aligned on a half-word boundary.
 229 */
 230static inline void
 231fbfill(u16* fbaddr, u8 val, int size)
 232{
 233        u16 valw = (u16)val | ((u16)val << 8);
 234        for ( ; size >= 2; size -= 2)
 235                writew(valw, fbaddr++);
 236        if (size)
 237                writeb(val, (u8*)fbaddr);
 238}
 239
 240static inline int
 241e1356_wait_bitclr(u8* reg, u8 bit, int timeout)
 242{
 243        while (readb(reg) & bit) {
 244                udelay(10);
 245                if (!--timeout)
 246                        break;
 247        }
 248        return timeout;
 249}
 250
 251static inline int
 252e1356_wait_bitset(u8* reg, u8 bit, int timeout)
 253{
 254        while (!(readb(reg) & bit)) {
 255                udelay(10);
 256                if (!--timeout)
 257                        break;
 258        }
 259        return timeout;
 260}
 261
 262
 263static struct fb_videomode panel_modedb[] = {
 264        {
 265                /* 320x240 @ 109 Hz, 33.3 kHz hsync */
 266                NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),
 267                16, 16, 32, 24, 48, 8,
 268                0, FB_VMODE_NONINTERLACED
 269        }, {
 270                /* 640x480 @ 84 Hz, 48.1 kHz hsync */
 271                NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),
 272                96, 32, 32, 48, 64, 8,
 273                0, FB_VMODE_NONINTERLACED
 274        }, {
 275                /* 800x600 @ 76 Hz, 46.3 kHz hsync */
 276                NULL, 76, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),
 277                32, 10, 1, 1, 22, 1,
 278                0, FB_VMODE_NONINTERLACED
 279        }
 280};
 281static struct fb_videomode crt_modedb[] = {
 282        {
 283                /* 320x240 @ 84 Hz, 31.25 kHz hsync */
 284                NULL, 84, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/2),
 285                128, 128, 60, 60, 64, 8,
 286                0, FB_VMODE_NONINTERLACED
 287        }, {
 288                /* 320x240 @ 109 Hz, 33.3 kHz hsync */
 289                NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),
 290                16, 16, 32, 24, 48, 8,
 291                0, FB_VMODE_NONINTERLACED
 292        }, {
 293                /* 512x384 @ 77 Hz, 31.25 kHz hsync */
 294                NULL, 77, 512, 384, KHZ2PICOS(MAX_PIXCLOCK/2),
 295                48, 16, 16, 1, 64, 3,
 296                0, FB_VMODE_NONINTERLACED
 297        }, {
 298                /* 640x400 @ 88 Hz, 43.1 kHz hsync */
 299                NULL, 88, 640, 400, KHZ2PICOS(MAX_PIXCLOCK/1),
 300                128, 96, 32, 48, 64, 8,
 301                0, FB_VMODE_NONINTERLACED
 302        }, {
 303                /* 640x480 @ 84 Hz, 48.1 kHz hsync */
 304                NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),
 305                96, 32, 32, 48, 64, 8,
 306                0, FB_VMODE_NONINTERLACED
 307        }, {
 308                /* 768x576 @ 62 Hz, 38.5 kHz hsync */
 309                NULL, 62, 768, 576, KHZ2PICOS(MAX_PIXCLOCK/1),
 310                144, 16, 28, 6, 112, 4,
 311                0, FB_VMODE_NONINTERLACED
 312        }, {
 313                /* 800x600 @ 60 Hz, 37.9 kHz hsync */
 314                NULL, 60, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),
 315                88, 40, 23, 1, 128, 4,
 316                FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
 317                FB_VMODE_NONINTERLACED
 318        }
 319};
 320
 321static struct fb_videomode ntsc_modedb[] = {
 322        {
 323                /* 640x480 @ 62 Hz, requires flicker filter */
 324                //NULL, 62, 640, 480, 34921, 213, 57, 20, 2, 0, 0,
 325                NULL, 62, 640, 480, KHZ2PICOS(2*NTSC_PIXCLOCK),
 326                200, 70, 15, 7, 0, 0,
 327                FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
 328        }
 329};
 330static struct fb_videomode pal_modedb[] = {
 331        {
 332                /* 640x480 @ 56 Hz, requires flicker filter */
 333                NULL, 56, 640, 480, KHZ2PICOS(2*PAL_PIXCLOCK),
 334                350, 145, 49, 23, 0, 0,
 335                FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
 336        }
 337};
 338
 339
 340static inline void
 341fb_videomode_to_var(struct fb_videomode* mode,
 342                    struct fb_var_screeninfo*var)
 343{
 344        var->xres = mode->xres;
 345        var->yres = mode->yres;
 346        var->pixclock = mode->pixclock;
 347        var->left_margin = mode->left_margin;
 348        var->right_margin = mode->right_margin;
 349        var->upper_margin = mode->upper_margin;
 350        var->lower_margin = mode->lower_margin;
 351        var->hsync_len = mode->hsync_len;
 352        var->vsync_len = mode->vsync_len;
 353        var->sync = mode->sync;
 354        var->vmode = mode->vmode;
 355}
 356
 357
 358static int
 359e1356fb_get_mode(const struct fb_info_e1356 *info,
 360                 int xres,
 361                 int yres,
 362                 struct fb_videomode ** modedb,
 363                 struct fb_videomode ** mode)
 364{
 365        struct fb_videomode * ret;
 366        int i, dbsize;
 367
 368        if (IS_PANEL(info->fix.disp_type)) {
 369                ret = panel_modedb;
 370                dbsize = sizeof(panel_modedb)/sizeof(struct fb_videomode);
 371        } else if (info->fix.disp_type == DISP_TYPE_CRT) {
 372                ret = crt_modedb;
 373                dbsize = sizeof(crt_modedb)/sizeof(struct fb_videomode);
 374        } else if (info->fix.disp_type == DISP_TYPE_NTSC) {
 375                ret = ntsc_modedb;
 376                dbsize = sizeof(ntsc_modedb)/sizeof(struct fb_videomode);
 377        } else {
 378                ret = pal_modedb;
 379                dbsize = sizeof(pal_modedb)/sizeof(struct fb_videomode);
 380        }
 381        
 382        if (modedb)
 383                *modedb = ret;
 384        for (i=0; i<dbsize; i++) {
 385                if (xres == ret[i].xres && yres == ret[i].yres) {
 386                        *mode = &ret[i];
 387                        break;
 388                }
 389        }
 390        if (i == dbsize)
 391                return -EINVAL;
 392        return dbsize;
 393}
 394
 395
 396
 397#ifdef E1356FB_VERBOSE_DEBUG
 398static void
 399dump_par(const struct e1356fb_par* par)
 400{
 401        DPRINTK("width:       %d\n", par->width);
 402        DPRINTK("height:      %d\n", par->height);
 403        DPRINTK("width_virt:  %d\n", par->width_virt);
 404        DPRINTK("height_virt: %d\n", par->height_virt);
 405        DPRINTK("bpp:         %d\n", par->bpp);
 406        DPRINTK("pixclock:    %d\n", par->ipclk.pixclk);
 407        DPRINTK("horiz_ndp:   %d\n", par->horiz_ndp);
 408        DPRINTK("vert_ndp:    %d\n", par->vert_ndp);
 409        DPRINTK("hsync_pol:   %d\n", par->hsync_pol);
 410        DPRINTK("hsync_start: %d\n", par->hsync_start);
 411        DPRINTK("hsync_width: %d\n", par->hsync_width);
 412        DPRINTK("vsync_pol:   %d\n", par->vsync_pol);
 413        DPRINTK("vsync_start: %d\n", par->vsync_start);
 414        DPRINTK("vsync_width: %d\n", par->vsync_width);
 415        DPRINTK("cmap_len:    %d\n", par->cmap_len);
 416}
 417
 418static void
 419dump_display_regs(reg_dispcfg_t* dispcfg, reg_dispmode_t* dispmode)
 420{
 421        DPRINTK("hdw:            0x%02x\n", readb(&dispcfg->hdw));
 422        DPRINTK("hndp:           0x%02x\n", readb(&dispcfg->hndp));
 423        DPRINTK("hsync_start:    0x%02x\n", readb(&dispcfg->hsync_start));
 424        DPRINTK("hsync_pulse:    0x%02x\n", readb(&dispcfg->hsync_pulse));
 425        DPRINTK("vdh0:           0x%02x\n", readb(&dispcfg->vdh0));
 426        DPRINTK("vdh1:           0x%02x\n", readb(&dispcfg->vdh1));
 427        DPRINTK("vndp:           0x%02x\n", readb(&dispcfg->vndp));
 428        DPRINTK("vsync_start:    0x%02x\n", readb(&dispcfg->vsync_start));
 429        DPRINTK("vsync_pulse:    0x%02x\n", readb(&dispcfg->vsync_pulse));
 430        DPRINTK("tv_output_ctrl: 0x%02x\n\n", readb(&dispcfg->tv_output_ctrl));
 431
 432        DPRINTK("disp_mode:        0x%02x\n", readb(&dispmode->disp_mode));
 433        DPRINTK("lcd_misc:         0x%02x\n", readb(&dispmode->lcd_misc));
 434        DPRINTK("start_addr0:      0x%02x\n", readb(&dispmode->start_addr0));
 435        DPRINTK("start_addr1:      0x%02x\n", readb(&dispmode->start_addr1));
 436        DPRINTK("start_addr2:      0x%02x\n", readb(&dispmode->start_addr2));
 437        DPRINTK("mem_addr_offset0: 0x%02x\n", readb(&dispmode->mem_addr_offset0));
 438        DPRINTK("mem_addr_offset1: 0x%02x\n", readb(&dispmode->mem_addr_offset1));
 439        DPRINTK("pixel_panning:    0x%02x\n", readb(&dispmode->pixel_panning));
 440        DPRINTK("fifo_high_thresh: 0x%02x\n", readb(&dispmode->fifo_high_thresh));
 441        DPRINTK("fifo_low_thresh:  0x%02x\n", readb(&dispmode->fifo_low_thresh));
 442}
 443
 444static void
 445dump_fb(u8* base, int len)
 446{
 447        int i;
 448        DPRINTK("FB memory dump, start 0x%p, len %d", base, len);
 449        for (i=0; i<len; i++) {
 450                if (!(i%16))
 451                        printk("\n%p: %02x ", &base[i], readb(&base[i]));
 452                else
 453                        printk("%02x ", readb(&base[i]));
 454        }
 455        printk("\n");
 456}
 457
 458#endif // E1356FB_VERBOSE_DEBUG
 459
 460
 461
 462// Input:  ipclk->clksrc, ipclk->pixclk_d
 463// Output: ipclk->pixclk, ipclk->error, and ipclk->divisor
 464static int
 465get_nearest_pixclk_div(pixclock_info_t* ipclk, int x2)
 466{
 467        int pixclk_d = ipclk->pixclk_d;
 468        int clksrc = ipclk->clksrc;
 469
 470        if (x2) clksrc *= 2;
 471
 472        if (clksrc < (3*pixclk_d+1)/2)
 473                ipclk->divisor = 1;
 474        else if (clksrc < (5*pixclk_d+1)/2)
 475                ipclk->divisor = 2;
 476        else if (clksrc < (7*pixclk_d+1)/2)
 477                ipclk->divisor = 3;
 478        else if (clksrc < (9*pixclk_d+1)/2)
 479                ipclk->divisor = 4;
 480        else
 481                return -ENXIO;
 482
 483        ipclk->pixclk = clksrc / ipclk->divisor;
 484        ipclk->error = (100*(pixclk_d - ipclk->pixclk)) / pixclk_d;
 485        return 0;
 486}
 487
 488static int
 489e1356_calc_pixclock(const struct fb_info_e1356 *info,
 490                    pixclock_info_t* ipclk)
 491{
 492        int src_sel=-1, flicker_mult=0;
 493        pixclock_info_t test, ret;
 494    
 495        if (ipclk->pixclk > info->max_pixclock)
 496                return -ENXIO;
 497
 498        test.pixclk_d = ipclk->pixclk_d;
 499        ret.error = 100;
 500        
 501        if (IS_TV(info->fix.disp_type) &&
 502            (info->fix.tv_filt & TV_FILT_FLICKER))
 503                flicker_mult = 0x80;
 504        
 505        test.clksrc = info->fix.busclk;
 506        if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
 507            abs(test.error) < abs(ret.error)) {
 508                ret = test;
 509                src_sel = 0x01;
 510        }
 511
 512        test.clksrc = info->fix.mclk;
 513        if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
 514            abs(test.error) < abs(ret.error)) {
 515                ret = test;
 516                src_sel = 0x03;
 517        }
 518
 519        test.clksrc = info->fix.clki;
 520        if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
 521            abs(test.error) < abs(ret.error)) {
 522                ret = test;
 523                src_sel = 0x00;
 524        }
 525
 526        test.clksrc = info->fix.clki2;
 527        if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 &&
 528            abs(test.error) < abs(ret.error)) {
 529                ret = test;
 530                src_sel = 0x02;
 531        }
 532
 533        if (ret.error > MAX_PCLK_ERROR_LOWER ||
 534            ret.error < MAX_PCLK_ERROR_HIGHER)
 535                return -ENXIO;
 536    
 537        ret.pixclk_bits = flicker_mult | ((ret.divisor-1)<<4) | src_sel;
 538        *ipclk = ret;
 539        return 0;
 540}
 541
 542static inline int
 543e1356_engine_wait_complete(reg_bitblt_t* bltreg)
 544{
 545        return e1356_wait_bitclr(&bltreg->ctrl0, 0x80, 5000);
 546}
 547static inline int
 548e1356_engine_wait_busy(reg_bitblt_t* bltreg)
 549{
 550        return e1356_wait_bitset(&bltreg->ctrl0, 0x80, 5000);
 551}
 552
 553static void
 554e1356fb_engine_init(const struct e1356fb_par* par,
 555                    struct fb_info_e1356* info)
 556{
 557        reg_bitblt_t* bltreg = info->reg.bitblt;
 558    
 559        e1356_engine_wait_complete(bltreg);
 560
 561        writeb(0, &bltreg->ctrl0);
 562        writeb(0, &bltreg->ctrl1);
 563        writeb(0, &bltreg->rop_code);
 564        writeb(0, &bltreg->operation);
 565        writeb(0, &bltreg->src_start_addr0);
 566        writeb(0, &bltreg->src_start_addr1);
 567        writeb(0, &bltreg->src_start_addr2);
 568        writeb(0, &bltreg->dest_start_addr0);
 569        writeb(0, &bltreg->dest_start_addr1);
 570        writeb(0, &bltreg->dest_start_addr2);
 571        writew(0, &bltreg->mem_addr_offset0);
 572        writew(0, &bltreg->width0);
 573        writew(0, &bltreg->height0);
 574        writew(0, &bltreg->bg_color0);
 575        writew(0, &bltreg->fg_color0);
 576}
 577
 578
 579static void doBlt_Write(const struct e1356fb_par* par,
 580                        struct fb_info_e1356* info,
 581                        blt_info_t* blt)
 582{
 583        reg_bitblt_t* bltreg = info->reg.bitblt;
 584        int nWords, nTotalWords;
 585        u32 srcphase, dstAddr;
 586        u16* w16;
 587        u32 stride = par->width_virt * par->Bpp;
 588
 589        dstAddr = blt->dst_x * par->Bpp + blt->dst_y * stride;
 590        srcphase = (u32)blt->src & 1;
 591    
 592        if (blt->attribute & BLT_ATTR_TRANSPARENT)
 593                writew(blt->bg_color, &bltreg->bg_color0);
 594        else
 595                writeb(blt->rop, &bltreg->rop_code);
 596    
 597        writeb(blt->operation, &bltreg->operation);
 598        writeb((u8)srcphase, &bltreg->src_start_addr0);
 599        writew(stride/2, &bltreg->mem_addr_offset0);
 600
 601        writeb(dstAddr, &bltreg->dest_start_addr0);
 602        writeb(dstAddr>>8, &bltreg->dest_start_addr1);
 603        writeb(dstAddr>>16, &bltreg->dest_start_addr2);
 604
 605        writew(blt->dst_width-1, &bltreg->width0);
 606        writew(blt->dst_height-1, &bltreg->height0);
 607
 608        // program color format operation
 609        writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
 610
 611        // start it up
 612        writeb(0x80, &bltreg->ctrl0);
 613
 614        // wait for it to actually start
 615        e1356_engine_wait_busy(bltreg);
 616
 617        // calculate the number of 16 bit words per one blt line
 618
 619        nWords = srcphase + ((blt->dst_width - srcphase)*par->Bpp + 1) / 2;
 620        nTotalWords = nWords*blt->dst_height;
 621        w16 = (u16*)((u32)blt->src & 0xfffffffe);   // Word aligned
 622
 623        while (nTotalWords > 0) {
 624                int j, nFIFO;
 625                u8 ctrl0;
 626
 627                // read the FIFO status
 628                ctrl0 = readb(&bltreg->ctrl0);
 629
 630                if ((ctrl0 & 0x30) == 0x20)
 631                        // FIFO is at least half full, but not full
 632                        nFIFO = 1;
 633                else if ((ctrl0 & 0x40) == 0)
 634                        // FIFO is empty
 635                        nFIFO = 16;
 636                else
 637                        // FIFO is full
 638                        continue;
 639
 640                for (j = 0; j < nFIFO && nTotalWords > 0; j++,nTotalWords--)
 641                        writew(*w16++, info->reg.bitblt_data);
 642        }
 643
 644        e1356_engine_wait_complete(bltreg);
 645}
 646
 647
 648static void
 649doBlt_SolidFill(const struct e1356fb_par* par,
 650                struct fb_info_e1356* info,
 651                blt_info_t* blt)
 652{
 653        reg_bitblt_t* bltreg = info->reg.bitblt;
 654        u32 width = blt->dst_width, height = blt->dst_height;
 655        u32 stride = par->width_virt * par->Bpp;
 656        u32 dest_addr = (blt->dst_y * stride) + (blt->dst_x * par->Bpp);
 657
 658        if (width == 0 || height == 0)
 659                return;
 660
 661        // program dest address
 662        writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0);
 663        writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1);
 664        writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2);
 665
 666        // program width and height of solid-fill blit
 667        writew(width-1, &bltreg->width0);
 668        writew(height-1, &bltreg->height0);
 669
 670        // program color of fill
 671        writew(blt->fg_color, &bltreg->fg_color0);
 672        // select solid-fill BLIT
 673        writeb(BLT_SOLID_FILL, &bltreg->operation);
 674        // program color format operation
 675        writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
 676        // program BLIT memory offset
 677        writew(stride/2, &bltreg->mem_addr_offset0);
 678
 679        // start it up (self completes)
 680        writeb(0x80, &bltreg->ctrl0);
 681
 682        e1356_engine_wait_complete(bltreg);
 683}
 684
 685
 686static void
 687doBlt_Move(const struct e1356fb_par* par,
 688           struct fb_info_e1356* info,
 689           blt_info_t* blt)
 690{
 691        reg_bitblt_t* bltreg = info->reg.bitblt;
 692        int neg_dir=0;
 693        u32 dest_addr, src_addr;
 694        u32 bpp = par->bpp;
 695        u32 stride = par->width_virt * par->Bpp; // virt line length in bytes
 696        u32 srcx = blt->src_x, srcy = blt->src_y;
 697        u32 dstx = blt->dst_x, dsty = blt->dst_y;
 698        u32 width = blt->dst_width, height = blt->dst_height;
 699    
 700        if (width == 0 || height == 0)
 701                return;
 702   
 703        src_addr = srcx*par->Bpp + srcy*stride;
 704        dest_addr = dstx*par->Bpp + dsty*stride;
 705
 706        /*
 707         * See if regions overlap and dest region is beyond source region.
 708         * If so, we need to do a move BLT in negative direction. Only applies
 709         * if the BLT is not transparent.
 710         */
 711        if (!(blt->attribute & BLT_ATTR_TRANSPARENT)) {
 712                if ((srcx + width  > dstx) && (srcx < dstx + width) &&
 713                    (srcy + height > dsty) && (srcy < dsty + height) &&
 714                    (dest_addr > src_addr)) {
 715                        neg_dir = 1;
 716                        // negative direction : get the coords of lower right corner
 717                        src_addr += stride * (height-1) + par->Bpp * (width-1);
 718                        dest_addr += stride * (height-1) + par->Bpp * (width-1);
 719                }
 720        }
 721    
 722        // program BLIT memory offset
 723        writew(stride/2, &bltreg->mem_addr_offset0);
 724
 725        // program src and dest addresses
 726        writeb(src_addr & 0x00ff, &bltreg->src_start_addr0);
 727        writeb((src_addr>>8) & 0x00ff, &bltreg->src_start_addr1);
 728        writeb((src_addr>>16) & 0x00ff, &bltreg->src_start_addr2);
 729        writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0);
 730        writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1);
 731        writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2);
 732
 733        // program width and height of blit
 734        writew(width-1, &bltreg->width0);
 735        writew(height-1, &bltreg->height0);
 736
 737        // program color format operation
 738        writeb(bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
 739
 740        // set the blt type
 741        if (blt->attribute & BLT_ATTR_TRANSPARENT) {
 742                writew(blt->bg_color, &bltreg->bg_color0);
 743                writeb(BLT_MOVE_POS_TRANSP, &bltreg->operation); 
 744        } else {
 745                writeb(blt->rop, &bltreg->rop_code);
 746                // select pos/neg move BLIT
 747                writeb(neg_dir ? BLT_MOVE_NEG_ROP : BLT_MOVE_POS_ROP,
 748                       &bltreg->operation); 
 749        }
 750
 751        // start it up (self completes)
 752        writeb(0x80, &bltreg->ctrl0);
 753
 754        e1356_engine_wait_complete(bltreg);
 755}
 756
 757
 758static void doBlt_ColorExpand(const struct e1356fb_par* par,
 759                              struct fb_info_e1356* info,
 760                              blt_info_t* blt)
 761{
 762        reg_bitblt_t* bltreg = info->reg.bitblt;
 763        int i, j, nWords, Sx, Sy;
 764        u32 dstAddr;
 765        u16* wpt, *wpt1;
 766        u32 stride = par->width_virt * par->Bpp;
 767
 768        if (blt->dst_width == 0 || blt->dst_height == 0)
 769                return;
 770
 771        Sx = blt->src_x;
 772        Sy = blt->src_y;
 773
 774        writeb((7 - Sx%8), &bltreg->rop_code);
 775
 776        writeb(blt->operation, &bltreg->operation);
 777
 778        writeb((u8)(Sx & 1), &bltreg->src_start_addr0);
 779
 780        dstAddr = blt->dst_x*par->Bpp + blt->dst_y * stride;
 781        writeb(dstAddr, &bltreg->dest_start_addr0);
 782        writeb(dstAddr>>8, &bltreg->dest_start_addr1);
 783        writeb(dstAddr>>16, &bltreg->dest_start_addr2);
 784
 785        // program color format operation
 786        writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1);
 787        writew(stride/2, &bltreg->mem_addr_offset0);
 788        writew(blt->dst_width-1, &bltreg->width0);
 789        writew(blt->dst_height-1, &bltreg->height0);
 790        writew(blt->bg_color, &bltreg->bg_color0);
 791        writew(blt->fg_color, &bltreg->fg_color0);
 792
 793        // start it up
 794        writeb(0x80, &bltreg->ctrl0);
 795
 796        // wait for it to actually start
 797        e1356_engine_wait_busy(bltreg);
 798
 799        // calculate the number of 16 bit words per one blt line
 800
 801        nWords = (Sx%16 + blt->dst_width + 15)/16;
 802
 803        wpt = blt->src + (Sy*blt->srcstride + Sx/16)/2;
 804
 805        for (i = 0; i < blt->dst_height; i++) {
 806                wpt1 = wpt;
 807
 808                for (j = 0; j < nWords; j++) {
 809                        // loop until FIFO becomes empty...
 810                        e1356_wait_bitclr(&bltreg->ctrl0, 0x40, 10000);
 811                        writew(*wpt1++, info->reg.bitblt_data);
 812                }
 813        
 814                wpt += blt->srcstride/2;
 815        }
 816
 817        e1356_engine_wait_complete(bltreg);
 818}
 819
 820
 821/*
 822 * The BitBLT operation dispatcher
 823 */
 824static int
 825doBlt(const struct e1356fb_par* par,
 826      struct fb_info_e1356* info,
 827      blt_info_t* blt)
 828{
 829        /*
 830         * Make sure we're not reentering in the middle of an
 831         * active BitBLT operation. ALWAYS call this dispatcher
 832         * and not one of the above BLT routines directly, or you
 833         * run the risk of overlapping BLT operations, which can
 834         * cause complete system hangs.
 835     */
 836        if (readb(&info->reg.bitblt->ctrl0) & 0x80)
 837                return -ENXIO;
 838    
 839        switch (blt->operation) {
 840        case BLT_MOVE_POS_ROP:
 841        case BLT_MOVE_NEG_ROP:
 842        case BLT_MOVE_POS_TRANSP:
 843                doBlt_Move(par, info, blt);
 844                break;
 845        case BLT_COLOR_EXP:
 846        case BLT_COLOR_EXP_TRANSP:
 847                doBlt_ColorExpand(par, info, blt);
 848                break;
 849        case BLT_SOLID_FILL:
 850                doBlt_SolidFill(par, info, blt);
 851                break;
 852        case BLT_WRITE_ROP:
 853        case BLT_WRITE_TRANSP:
 854                doBlt_Write(par, info, blt);
 855                break;
 856        case BLT_READ:
 857        case BLT_PAT_FILL_ROP:
 858        case BLT_PAT_FILL_TRANSP:
 859        case BLT_MOVE_COLOR_EXP:
 860        case BLT_MOVE_COLOR_EXP_TRANSP:
 861                DPRINTK("BitBLT operation 0x%02x not implemented yet\n",
 862                        blt->operation);
 863                return -ENXIO;
 864        default:
 865                DPRINTK("Unknown BitBLT operation 0x%02x\n", blt->operation);
 866                return -ENXIO;
 867        }
 868    
 869        return 0;
 870}
 871
 872
 873// Initializes blt->src and blt->srcstride
 874static void fill_putcs_buffer(struct display *p,
 875                              blt_info_t* blt,
 876                              const unsigned short* str,
 877                              int count)
 878{   
 879        int row, i, j;
 880        u8* b1, *b2;
 881        u32 fw = fontwidth(p);
 882        u32 fwb = (fw + 7) >> 3;
 883        u32 fh = fontheight(p);
 884        int bytesPerChar = fwb * fh;
 885
 886        if (count*bytesPerChar > PAGE_SIZE) {
 887                // Truncate the string if it overflows putcs_buffer, which is
 888                // one page in size.
 889                count = PAGE_SIZE/bytesPerChar - 1;
 890        }
 891
 892        blt->srcstride = (fwb*count + 1) & ~1; //round up to be even
 893        
 894        b1 = (u8*)blt->src;
 895
 896        for (row = 0; row < fh; row++) {
 897                b2 = b1;
 898                for (i = 0; i < count; i++) {
 899                        for (j=0; j<fwb; j++)
 900                                *b2++ = p->fontdata[(str[i] & p->charmask) *
 901                                                   bytesPerChar +
 902                                                   row*fwb + j];
 903                }
 904                b1 += blt->srcstride;
 905        }
 906}
 907
 908
 909/*
 910 * Set the color of a palette entry in 8bpp mode 
 911 */
 912static inline void
 913do_setpalentry(reg_lut_t* lut, unsigned regno,
 914               u8 r, u8 g, u8 b)
 915{
 916        writeb(0x00, &lut->mode);
 917        writeb((u8)regno, &lut->addr);
 918        writeb(r&0xf0, &lut->data);
 919        writeb(g&0xf0, &lut->data);
 920        writeb(b&0xf0, &lut->data);
 921}
 922
 923   
 924static void
 925do_pan_var(struct fb_var_screeninfo* var, struct fb_info_e1356* info)
 926{
 927        u32 pixel_start, start_addr;
 928        u8 pixel_pan;
 929        struct e1356fb_par* par = &info->current_par;
 930        reg_misc_t* misc = info->reg.misc;
 931        reg_dispmode_t* dispmode = (IS_PANEL(info->fix.disp_type)) ?
 932                info->reg.lcd_mode : info->reg.crttv_mode;
 933        
 934        pixel_start = var->yoffset * par->width_virt + var->xoffset;
 935        start_addr = (pixel_start * par->Bpp) / 2;
 936        pixel_pan = (par->bpp == 8) ? (u8)(pixel_start & 1) : 0;
 937    
 938        if (readb(&misc->disp_mode) != 0) {
 939                reg_dispcfg_t* dispcfg = (IS_PANEL(info->fix.disp_type)) ?
 940                        info->reg.lcd_cfg : info->reg.crttv_cfg;
 941
 942                // wait for the end of the current VNDP
 943                e1356_wait_bitclr(&dispcfg->vndp, 0x80, 5000);
 944                // now wait for the start of a new VNDP
 945                e1356_wait_bitset(&dispcfg->vndp, 0x80, 5000);
 946        }
 947    
 948        writeb((u8)(start_addr & 0xff), &dispmode->start_addr0);
 949        writeb((u8)((start_addr>>8) & 0xff), &dispmode->start_addr1);
 950        writeb((u8)((start_addr>>16) & 0xff), &dispmode->start_addr2);
 951        writeb(pixel_pan, &dispmode->pixel_panning);
 952}
 953
 954
 955/*
 956 * Invert the hardware cursor image (timerfunc)  
 957 */
 958static void
 959do_flashcursor(unsigned long ptr)
 960{
 961        u8 curs_ctrl;
 962        struct fb_info_e1356* info = (struct fb_info_e1356 *)ptr;
 963        reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
 964                info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
 965
 966        spin_lock(&info->cursor.lock);
 967        // toggle cursor enable bit
 968        curs_ctrl = readb(&inkcurs->ctrl);
 969        writeb((curs_ctrl ^ 0x01) & 0x01, &inkcurs->ctrl);
 970        info->cursor.timer.expires = jiffies+HZ/2;
 971        add_timer(&info->cursor.timer);
 972        spin_unlock(&info->cursor.lock);
 973}
 974
 975#ifdef SHADOW_FRAME_BUFFER
 976/*
 977 * Write BLT the shadow frame buffer to the real fb (timerfunc)  
 978 */
 979static void
 980do_write_shadow_fb(unsigned long ptr)
 981{
 982        blt_info_t blt;
 983        struct fb_info_e1356 *info = (struct fb_info_e1356*)ptr;
 984        struct fb_info* fb = &info->fb_info;
 985        struct e1356fb_par* par = &info->current_par;
 986        u32 stride = par->width_virt * par->Bpp;
 987
 988        unsigned long j_start = jiffies;
 989    
 990        blt.src_x = blt.src_y = 0;
 991        blt.attribute = 0;
 992        blt.dst_width = par->width;
 993        blt.dst_height = par->height;
 994        blt.dst_y = fb->var.yoffset;
 995        blt.dst_x = fb->var.xoffset;
 996        blt.operation = BLT_WRITE_ROP;
 997        blt.rop = 0x0c; // ROP: destination = source
 998        blt.src = (u16*)(info->shadow.fb + blt.dst_x * par->Bpp +
 999                         blt.dst_y * stride);
1000
1001        doBlt(par, info, &blt);
1002    
1003        info->shadow.timer.expires = jiffies+HZ/2;
1004        add_timer(&info->shadow.timer);
1005
1006        //DPRINTK("delta jiffies = %ld\n", jiffies - j_start);
1007}
1008#endif
1009
1010
1011/* ------------------------------------------------------------------------- 
1012 *              Hardware independent part, interface to the world
1013 * ------------------------------------------------------------------------- */
1014
1015static void
1016e1356_cfbX_clear_margins(struct vc_data* conp, struct display* p,
1017                         int bottom_only)
1018{
1019        blt_info_t blt;
1020        unsigned int cw=fontwidth(p);
1021        unsigned int ch=fontheight(p);
1022        unsigned int rw=p->var.xres % cw;
1023        unsigned int bh=p->var.yres % ch;
1024        unsigned int rs=p->var.xres - rw;
1025        unsigned int bs=p->var.yres - bh;
1026
1027        //DPRINTK("\n");
1028
1029        if (!bottom_only && rw) { 
1030                blt.dst_x = p->var.xoffset+rs;
1031                blt.dst_y = p->var.yoffset;
1032                blt.dst_height = p->var.yres;
1033                blt.dst_width = rw;
1034                blt.attribute = 0;
1035                blt.fg_color = 0;
1036                blt.operation = BLT_SOLID_FILL;
1037                doBlt (&fb_info.current_par, &fb_info, &blt);
1038        }
1039    
1040        if (bh) { 
1041                blt.dst_x = p->var.xoffset;
1042                blt.dst_y = p->var.yoffset+bs;
1043                blt.dst_height = bh;
1044                blt.dst_width = rs;
1045                blt.attribute = 0;
1046                blt.fg_color = 0;
1047                blt.operation = BLT_SOLID_FILL;
1048                doBlt (&fb_info.current_par, &fb_info, &blt);
1049        }
1050}
1051
1052static void
1053e1356_cfbX_bmove(struct display* p, 
1054                 int sy, 
1055                 int sx, 
1056                 int dy,
1057                 int dx, 
1058                 int height, 
1059                 int width)
1060{
1061        blt_info_t blt;
1062    
1063        //DPRINTK("(%d,%d) to (%d,%d) size (%d,%d)\n", sx,sy,dx,dy,width,height);
1064
1065        blt.src_x = fontwidth_x8(p)*sx;
1066        blt.src_y = fontheight(p)*sy;
1067        blt.dst_x = fontwidth_x8(p)*dx;
1068        blt.dst_y = fontheight(p)*dy;
1069        blt.src_height = blt.dst_height = fontheight(p)*height;
1070        blt.src_width = blt.dst_width = fontwidth_x8(p)*width;
1071        blt.attribute = 0;
1072        blt.rop = 0x0c;
1073        /*
1074         * The move BLT routine will actually decide between a pos/neg
1075         * move BLT. This is just so that the BLT dispatcher knows to
1076         * call the move BLT routine.
1077         */
1078        blt.operation = BLT_MOVE_POS_ROP;
1079
1080        doBlt (&fb_info.current_par, &fb_info, &blt);
1081}
1082
1083static void
1084e1356_cfb8_putc(struct vc_data* conp,
1085                struct display* p,
1086                int c, int yy,int xx)
1087{   
1088        blt_info_t blt;
1089        u32 fgx,bgx;
1090        u32 fw = fontwidth_x8(p);
1091        u32 fh = fontheight(p);
1092        u16 cs = (u16)c;
1093
1094        fgx = attr_fgcol(p, c);
1095        bgx = attr_bgcol(p, c);
1096
1097        blt.src_x = blt.src_y = 0;
1098        blt.attribute = 0;
1099        blt.dst_width = fw;
1100        blt.dst_height = fh;
1101        blt.dst_y = yy * fh;
1102        blt.dst_x = xx * fw;
1103        blt.bg_color = bgx;
1104        blt.fg_color = fgx;
1105        blt.operation = BLT_COLOR_EXP;
1106        blt.src = fb_info.putcs_buffer;
1107        fill_putcs_buffer(p, &blt, &cs, 1);
1108
1109        doBlt(&fb_info.current_par, &fb_info, &blt);
1110
1111}
1112
1113static void
1114e1356_cfb16_putc(struct vc_data* conp,
1115                 struct display* p,
1116                 int c, int yy,int xx)
1117{   
1118        blt_info_t blt;
1119        u32 fgx,bgx;
1120        u32 fw = fontwidth_x8(p);
1121        u32 fh = fontheight(p);
1122        u16 cs = (u16)c;
1123    
1124        fgx = ((u16*)p->dispsw_data)[attr_fgcol(p,c)];
1125        bgx = ((u16*)p->dispsw_data)[attr_bgcol(p,c)];
1126
1127        blt.src_x = blt.src_y = 0;
1128        blt.attribute = 0;
1129        blt.dst_width = fw;
1130        blt.dst_height = fh;
1131        blt.dst_y = yy * fh;
1132        blt.dst_x = xx * fw;
1133        blt.bg_color = bgx;
1134        blt.fg_color = fgx;
1135        blt.operation = BLT_COLOR_EXP;
1136        blt.src = fb_info.putcs_buffer;
1137        fill_putcs_buffer(p, &blt, &cs, 1);
1138
1139        doBlt(&fb_info.current_par, &fb_info, &blt);
1140}
1141
1142
1143static void
1144e1356_cfb8_putcs(struct vc_data* conp,
1145                 struct display* p,
1146                 const unsigned short *s,int count,int yy,int xx)
1147{
1148        blt_info_t blt;
1149        u32 fgx,bgx;
1150        u32 fw = fontwidth_x8(p);
1151        u32 fh = fontheight(p);
1152
1153        //DPRINTK("\n");
1154
1155        fgx=attr_fgcol(p, *s);
1156        bgx=attr_bgcol(p, *s);
1157
1158        blt.src_x = blt.src_y = 0;
1159        blt.attribute = 0;
1160        blt.dst_width = count * fw;
1161        blt.dst_height = fh;
1162        blt.dst_y = yy * fh;
1163        blt.dst_x = xx * fw;
1164        blt.bg_color = bgx;
1165        blt.fg_color = fgx;
1166        blt.operation = BLT_COLOR_EXP;
1167        blt.src = fb_info.putcs_buffer;
1168        fill_putcs_buffer(p, &blt, s, count);
1169
1170        doBlt(&fb_info.current_par, &fb_info, &blt);
1171}
1172
1173static void
1174e1356_cfb16_putcs(struct vc_data* conp,
1175                  struct display* p,
1176                  const unsigned short *s,int count,int yy,int xx)
1177{
1178        blt_info_t blt;
1179        u32 fgx,bgx;
1180        u32 fw = fontwidth_x8(p);
1181        u32 fh = fontheight(p);
1182
1183        //DPRINTK("\n");
1184
1185        fgx=((u16*)p->dispsw_data)[attr_fgcol(p,*s)];
1186        bgx=((u16*)p->dispsw_data)[attr_bgcol(p,*s)];
1187
1188        blt.src_x = blt.src_y = 0;
1189        blt.attribute = 0;
1190        blt.dst_width = count * fw;
1191        blt.dst_height = fh;
1192        blt.dst_y = yy * fh;
1193        blt.dst_x = xx * fw;
1194        blt.bg_color = bgx;
1195        blt.fg_color = fgx;
1196        blt.operation = BLT_COLOR_EXP;
1197        blt.src = fb_info.putcs_buffer;
1198        fill_putcs_buffer(p, &blt, s, count);
1199
1200        doBlt(&fb_info.current_par, &fb_info, &blt);
1201}
1202
1203
1204static void
1205e1356_cfb8_clear(struct vc_data* conp, 
1206                 struct display* p, 
1207                 int sy,
1208                 int sx, 
1209                 int height, 
1210                 int width)
1211{
1212        blt_info_t blt;
1213        u32 bg = attr_bgcol_ec(p,conp);
1214
1215        //DPRINTK("(%d,%d) size (%d,%d)\n", sx,sy,width,height);
1216
1217        blt.dst_x = fontwidth_x8(p)*sx;
1218        blt.dst_y = fontheight(p)*sy;
1219        blt.dst_height = fontheight(p)*height;
1220        blt.dst_width = fontwidth_x8(p)*width;
1221        blt.attribute = 0;
1222        blt.fg_color = bg;
1223        blt.operation = BLT_SOLID_FILL;
1224
1225        doBlt (&fb_info.current_par, &fb_info, &blt);
1226}
1227
1228static void
1229e1356_cfb16_clear(struct vc_data* conp, 
1230                  struct display* p, 
1231                  int sy,
1232                  int sx, 
1233                  int height, 
1234                  int width)
1235{
1236        blt_info_t blt;
1237        u32 bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
1238
1239        //DPRINTK("(%d,%d) size (%d,%d)\n", sx,sy,width,height);
1240
1241        blt.dst_x = fontwidth_x8(p)*sx;
1242        blt.dst_y = fontheight(p)*sy;
1243        blt.dst_height = fontheight(p)*height;
1244        blt.dst_width = fontwidth_x8(p)*width;
1245        blt.attribute = 0;
1246        blt.fg_color = bg;
1247        blt.operation = BLT_SOLID_FILL;
1248
1249        doBlt (&fb_info.current_par, &fb_info, &blt);
1250}
1251
1252
1253static void
1254e1356_cfbX_revc(struct display *p, int xx, int yy)
1255{
1256        // not used if h/w cursor
1257        //DPRINTK("\n");
1258}
1259
1260static void
1261e1356_cfbX_cursor(struct display *p, int mode, int x, int y) 
1262{
1263        unsigned long flags;
1264        struct fb_info_e1356 *info=(struct fb_info_e1356 *)p->fb_info;
1265        reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
1266                info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
1267    
1268        //DPRINTK("\n");
1269
1270        if (mode == CM_ERASE) {
1271                if (info->cursor.state != CM_ERASE) {
1272                        spin_lock_irqsave(&info->cursor.lock,flags);
1273                        info->cursor.state = CM_ERASE;
1274                        del_timer(&(info->cursor.timer));
1275                        writeb(0x00, &inkcurs->ctrl);
1276                        spin_unlock_irqrestore(&info->cursor.lock,flags);
1277                }
1278                return;
1279        }
1280    
1281        if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
1282                e1356fb_createcursor(p);
1283    
1284        x *= fontwidth_x8(p);
1285        y *= fontheight(p);
1286        x -= p->var.xoffset;
1287        y -= p->var.yoffset;
1288    
1289        spin_lock_irqsave(&info->cursor.lock,flags);
1290        if ((x != info->cursor.x) || (y != info->cursor.y) ||
1291            (info->cursor.redraw)) {
1292                info->cursor.x = x;
1293                info->cursor.y = y;
1294                info->cursor.redraw = 0;
1295                writeb(0x01, &inkcurs->ctrl);
1296                writew(x, &inkcurs->x_pos0);
1297                writew(y, &inkcurs->y_pos0);
1298                /* fix cursor color - XFree86 forgets to restore it properly */
1299                writeb(0x00, &inkcurs->blue0);
1300                writeb(0x00, &inkcurs->green0);
1301                writeb(0x00, &inkcurs->red0);
1302                writeb(0x1f, &inkcurs->blue1);
1303                writeb(0x3f, &inkcurs->green1);
1304                writeb(0x1f, &inkcurs->red1);
1305        }
1306
1307        info->cursor.state = CM_DRAW;
1308        mod_timer(&info->cursor.timer, jiffies+HZ/2);
1309        spin_unlock_irqrestore(&info->cursor.lock,flags);
1310}
1311
1312#ifdef FBCON_HAS_CFB8
1313static struct display_switch fbcon_e1356_8 = {
1314        setup:          fbcon_cfb8_setup, 
1315        bmove:          e1356_cfbX_bmove, 
1316        clear:          e1356_cfb8_clear, 
1317        putc:           e1356_cfb8_putc,
1318        putcs:          e1356_cfb8_putcs, 
1319        revc:           e1356_cfbX_revc,   
1320        cursor:         e1356_cfbX_cursor, 
1321        clear_margins:  e1356_cfbX_clear_margins,
1322        fontwidthmask:  FONTWIDTHRANGE(6,16)
1323};
1324#endif
1325
1326#ifdef FBCON_HAS_CFB16
1327static struct display_switch fbcon_e1356_16 = {
1328        setup:          fbcon_cfb16_setup, 
1329        bmove:          e1356_cfbX_bmove, 
1330        clear:          e1356_cfb16_clear, 
1331        putc:           e1356_cfb16_putc,
1332        putcs:          e1356_cfb16_putcs, 
1333        revc:           e1356_cfbX_revc, 
1334        cursor:         e1356_cfbX_cursor, 
1335        clear_margins:  e1356_cfbX_clear_margins,
1336        fontwidthmask:  FONTWIDTHRANGE(6,16)
1337};
1338#endif
1339
1340/* ------------------------------------------------------------------------- */
1341
1342static void
1343e1356fb_set_par(const struct e1356fb_par* par,
1344                struct fb_info_e1356* info)
1345{
1346        reg_dispcfg_t* dispcfg=NULL;
1347        reg_dispmode_t* dispmode=NULL;
1348        u8* pclk_cfg=NULL;
1349        u8 width, hndp=0, hsync_start=0, hsync_width=0;
1350        u8 vndp, vsync_start, vsync_width=0, display_mode;
1351        u8 main_display_mode=0;
1352        u16 height, addr_offset;
1353        int disp_type = info->fix.disp_type;
1354
1355        DPRINTK("%dx%d-%dbpp @ %d Hz, %d kHz hsync\n",
1356                par->width, par->height, par->bpp,
1357                par->vsync_freq, (((2*par->hsync_freq)/1000)+1)/2);
1358#ifdef E1356FB_VERBOSE_DEBUG
1359        dump_par(par);
1360#endif
1361    
1362        info->current_par = *par;
1363
1364        width = (par->width >> 3) - 1;
1365        display_mode = (par->bpp == 8) ? 0x03 : 0x05;
1366        addr_offset = (par->width_virt * par->Bpp) / 2;
1367        vsync_start = (disp_type == DISP_TYPE_LCD) ? 0 : par->vsync_start - 1;
1368        height = par->height - 1;
1369        vndp = par->vert_ndp - 1;
1370
1371        switch (disp_type) {
1372        case DISP_TYPE_LCD:
1373                dispcfg = info->reg.lcd_cfg;
1374                dispmode = info->reg.lcd_mode;
1375                pclk_cfg = &info->reg.clk_cfg->lcd_pclk_cfg;
1376                hndp = (par->horiz_ndp >> 3) - 1;
1377                hsync_start = 0;
1378                hsync_width = par->hsync_pol ? 0x00 : 0x80;
1379                vsync_width = par->vsync_pol ? 0x00 : 0x80;
1380                main_display_mode = 0x01;
1381                break;
1382        case DISP_TYPE_TFT:
1383                dispcfg = info->reg.lcd_cfg;
1384                dispmode = info->reg.lcd_mode;
1385                pclk_cfg = &info->reg.clk_cfg->lcd_pclk_cfg;
1386                hndp = (par->horiz_ndp >> 3) - 1;
1387                hsync_start = (par->bpp == 8) ?
1388                        (par->hsync_start - 4) >> 3 :
1389                                (par->hsync_start - 6) >> 3;
1390                hsync_width =
1391                        (par->hsync_pol ? 0x80 : 0x00) |
1392                        ((par->hsync_width >> 3) - 1);
1393                vsync_width =
1394                        (par->vsync_pol ? 0x80 : 0x00) |
1395                        (par->vsync_width - 1);
1396                main_display_mode = 0x01;
1397                break;
1398        case DISP_TYPE_CRT:
1399                dispcfg = info->reg.crttv_cfg;
1400                dispmode = info->reg.crttv_mode;
1401                pclk_cfg = &info->reg.clk_cfg->crttv_pclk_cfg;
1402                hndp = (par->horiz_ndp >> 3) - 1;
1403                hsync_start = (par->bpp == 8) ?
1404                        (par->hsync_start - 3) >> 3 :
1405                                (par->hsync_start - 5) >> 3;
1406                hsync_width =
1407                        (par->hsync_pol ? 0x80 : 0x00) |
1408                        ((par->hsync_width >> 3) - 1);
1409                vsync_width =
1410                        (par->vsync_pol ? 0x80 : 0x00) |
1411                        (par->vsync_width - 1);
1412                main_display_mode = 0x02;
1413                break;
1414        case DISP_TYPE_NTSC:
1415        case DISP_TYPE_PAL:
1416                dispcfg = info->reg.crttv_cfg;
1417                dispmode = info->reg.crttv_mode;
1418                pclk_cfg = &info->reg.clk_cfg->crttv_pclk_cfg;
1419                hndp = (disp_type == DISP_TYPE_PAL) ?
1420                        (par->horiz_ndp - 7) >> 3 :
1421                                (par->horiz_ndp - 6) >> 3;
1422                hsync_start = (par->bpp == 8) ?
1423                        (par->hsync_start + 7) >> 3 :
1424                                (par->hsync_start + 5) >> 3;
1425                hsync_width = 0;
1426                vsync_width = 0;
1427                main_display_mode = (info->fix.tv_filt & TV_FILT_FLICKER) ?
1428                        0x06 : 0x04;
1429                break;
1430        }
1431
1432        // Blast the regs!
1433        // note: reset panning/scrolling (set start-addr and
1434        // pixel pan regs to 0). Panning is handled by pan_display.
1435
1436        e1356_engine_wait_complete(info->reg.bitblt);
1437
1438        // disable display while initializing
1439        writeb(0, &info->reg.misc->disp_mode);
1440
1441        writeb(par->ipclk.pixclk_bits, pclk_cfg);
1442
1443        writeb(width, &dispcfg->hdw);
1444        writeb(hndp, &dispcfg->hndp);
1445        writeb(hsync_start, &dispcfg->hsync_start);
1446        writeb(hsync_width, &dispcfg->hsync_pulse);
1447        writew(height, &dispcfg->vdh0);
1448        writeb(vndp, &dispcfg->vndp);
1449        writeb(vsync_start, &dispcfg->vsync_start);
1450        writeb(vsync_width, &dispcfg->vsync_pulse);
1451
1452        writeb(display_mode, &dispmode->disp_mode);
1453        if (info->fix.mmunalign && info->mmaped)
1454                writeb(1, &dispmode->start_addr0);
1455        else
1456                writeb(0, &dispmode->start_addr0);
1457        writeb(0, &dispmode->start_addr1);
1458        writeb(0, &dispmode->start_addr2);
1459        writew(addr_offset, &dispmode->mem_addr_offset0);
1460        writeb(0, &dispmode->pixel_panning);
1461
1462        // reset BitBlt engine
1463        e1356fb_engine_init(par, info);
1464
1465#ifdef E1356FB_VERBOSE_DEBUG
1466        dump_display_regs(dispcfg, dispmode);
1467#endif
1468
1469        /* clear out framebuffer memory */
1470        fbfill(fb_info.membase_virt, 0, fb_info.fb_size);
1471        // finally, enable display!
1472        writeb(main_display_mode, &info->reg.misc->disp_mode); 
1473}
1474
1475
1476static int
1477e1356fb_verify_timing(struct e1356fb_par* par,
1478                      const struct fb_info_e1356* info)
1479{
1480        int disp_type = info->fix.disp_type;
1481
1482        // timing boundary checks
1483        if (par->horiz_ndp > max_hndp[disp_type]) {
1484                DPRINTK("horiz_ndp too big: %d\n", par->horiz_ndp);
1485                return -EINVAL;
1486        }
1487        if (par->vert_ndp > max_vndp[disp_type]) {
1488                DPRINTK("vert_ndp too big: %d\n", par->vert_ndp);
1489                return -EINVAL;
1490        }
1491
1492        if (disp_type != DISP_TYPE_LCD) {
1493                if (par->hsync_start >
1494                    max_hsync_start[(par->bpp==16)][disp_type]) {
1495                        DPRINTK("hsync_start too big: %d\n",
1496                                par->hsync_start);
1497                        return -EINVAL;
1498                }
1499                if (par->vsync_start > max_vsync_start[disp_type]) {
1500                        DPRINTK("vsync_start too big: %d\n",
1501                                par->vsync_start);
1502                        return -EINVAL;
1503                }
1504                if (!IS_TV(disp_type)) {
1505                        if (par->hsync_width > max_hsync_width[disp_type]) {
1506                                DPRINTK("hsync_width too big: %d\n",
1507                                        par->hsync_width);
1508                                return -EINVAL;
1509                        }
1510                        if (par->vsync_width > max_vsync_width[disp_type]) {
1511                                DPRINTK("vsync_width too big: %d\n",
1512                                        par->vsync_width);
1513                                return -EINVAL;
1514                        }
1515                }
1516        }
1517
1518        if (IS_TV(disp_type)) {
1519                int tv_pixclk = (disp_type == DISP_TYPE_NTSC) ?
1520                        NTSC_PIXCLOCK : PAL_PIXCLOCK;
1521                if (info->fix.tv_filt & TV_FILT_FLICKER)
1522                        tv_pixclk *= 2;
1523                
1524                if (par->ipclk.pixclk_d != tv_pixclk) {
1525                        DPRINTK("invalid TV pixel clock %u kHz\n",
1526                                par->ipclk.pixclk_d);
1527                        return -EINVAL;
1528                }
1529        }
1530        
1531        if (e1356_calc_pixclock(info, &par->ipclk) < 0) {
1532                DPRINTK("can't set pixel clock %u kHz\n",
1533                        par->ipclk.pixclk_d);
1534                return -EINVAL;
1535        }
1536 
1537#ifdef E1356FB_VERBOSE_DEBUG
1538        DPRINTK("desired pixclock = %d kHz, actual = %d kHz, error = %d%%\n",
1539                par->ipclk.pixclk_d, par->ipclk.pixclk, par->ipclk.error);
1540#endif
1541    
1542        if (disp_type != DISP_TYPE_LCD) {
1543                if (par->horiz_ndp < par->hsync_start + par->hsync_width) {
1544                        DPRINTK("invalid horiz. timing\n");
1545                        return -EINVAL;
1546                }
1547                if (par->vert_ndp < par->vsync_start + par->vsync_width) {
1548                        DPRINTK("invalid vert. timing\n");
1549                        return -EINVAL;
1550                }
1551
1552                // SED1356 Hardware Functional Spec, section 13.5
1553                if (disp_type == DISP_TYPE_NTSC &&
1554                    ((par->width + par->horiz_ndp != 910) ||
1555                     (par->height + 2*par->vert_ndp+1 != 525))) {
1556                        DPRINTK("invalid NTSC timing\n");
1557                        return -EINVAL;
1558                } else if (disp_type == DISP_TYPE_PAL &&
1559                           ((par->width + par->horiz_ndp != 1135) ||
1560                            (par->height + 2*par->vert_ndp+1 != 625))) {
1561                        DPRINTK("invalid PAL timing\n");
1562                        return -EINVAL;
1563                }
1564        }
1565    
1566        par->hsync_freq = (1000 * par->ipclk.pixclk) /
1567                (par->width + par->horiz_ndp);
1568        par->vsync_freq = par->hsync_freq / (par->height + par->vert_ndp);
1569        
1570        if (par->hsync_freq < 30000 || par->hsync_freq > 90000) {
1571                DPRINTK("hsync freq too %s: %u Hz\n",
1572                        par->hsync_freq < 30000 ? "low" : "high",
1573                        par->hsync_freq);
1574                return -EINVAL;
1575        }
1576        if (par->vsync_freq < 50 || par->vsync_freq > 110) {
1577                DPRINTK("vsync freq too %s: %u Hz\n",
1578                        par->vsync_freq < 50 ? "low" : "high",
1579                        par->vsync_freq);
1580                return -EINVAL;
1581        }
1582
1583        return 0;
1584}
1585
1586static int
1587e1356fb_verify_par(struct e1356fb_par* par,
1588                   const struct fb_info_e1356* info)
1589{
1590        int disp_type = info->fix.disp_type;
1591    
1592        if (par->bpp != 8 && par->bpp != 16) {
1593                DPRINTK("depth not supported: %u bpp\n", par->bpp);
1594                return -EINVAL;
1595        }
1596
1597        if (par->width > par->width_virt) {
1598                DPRINTK("virtual x resolution < physical x resolution not possible\n");
1599                return -EINVAL;
1600        }
1601
1602        if (par->height > par->height_virt) {
1603                DPRINTK("virtual y resolution < physical y resolution not possible\n");
1604                return -EINVAL;
1605        }
1606
1607        if (par->width < 320 || par->width > 1024) {
1608                DPRINTK("width not supported: %u\n", par->width);
1609                return -EINVAL;
1610        }
1611
1612        if ((disp_type == DISP_TYPE_LCD && (par->width % 16)) ||
1613            (disp_type == DISP_TYPE_TFT && (par->width % 8))) {
1614                DPRINTK("invalid width for panel type: %u\n", par->width);
1615                return -EINVAL;
1616        }
1617
1618        if (par->height < 200 || par->height > 1024) {
1619                DPRINTK("height not supported: %u\n", par->height);
1620                return -EINVAL;
1621        }
1622
1623        if (par->width_virt * par->height_virt * par->Bpp >
1624            info->fb_size) {
1625                DPRINTK("not enough memory for virtual screen (%ux%ux%u)\n",
1626                        par->width_virt, par->height_virt, par->bpp);
1627                return -EINVAL;
1628        }
1629
1630        return e1356fb_verify_timing(par, info);
1631}
1632
1633
1634static int
1635e1356fb_var_to_par(const struct fb_var_screeninfo* var,
1636                   struct e1356fb_par* par,
1637                   const struct fb_info_e1356* info)
1638{
1639        if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1640                DPRINTK("interlace not supported\n");
1641                return -EINVAL;
1642        }
1643
1644        memset(par, 0, sizeof(struct e1356fb_par));
1645
1646        par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
1647        par->width_virt  = var->xres_virtual;
1648        par->height      = var->yres;
1649        par->height_virt = var->yres_virtual;
1650        par->bpp         = var->bits_per_pixel;
1651        par->Bpp         = (par->bpp + 7) >> 3;
1652
1653        par->ipclk.pixclk_d = PICOS2KHZ(var->pixclock);
1654
1655        par->hsync_start = var->right_margin;
1656        par->hsync_width = var->hsync_len;
1657
1658        par->vsync_start = var->lower_margin;
1659        par->vsync_width = var->vsync_len;
1660
1661        par->horiz_ndp = var->left_margin + var->right_margin + var->hsync_len;
1662        par->vert_ndp = var->upper_margin + var->lower_margin + var->vsync_len;
1663
1664        par->hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0;
1665        par->vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0;
1666
1667        par->cmap_len  = (par->bpp == 8) ? 256 : 16;
1668
1669        return e1356fb_verify_par(par, info);
1670}
1671
1672static int
1673e1356fb_par_to_var(struct fb_var_screeninfo* var,
1674                   struct e1356fb_par* par,
1675                   const struct fb_info_e1356* info)
1676{
1677        struct fb_var_screeninfo v;
1678        int ret;
1679    
1680        // First, make sure par is valid.
1681        if ((ret = e1356fb_verify_par(par, info)))
1682                return ret;
1683
1684        memset(&v, 0, sizeof(struct fb_var_screeninfo));
1685        v.xres_virtual   = par->width_virt;
1686        v.yres_virtual   = par->height_virt;
1687        v.xres           = par->width;
1688        v.yres           = par->height;
1689        v.right_margin   = par->hsync_start;
1690        v.hsync_len      = par->hsync_width;
1691        v.left_margin    = par->horiz_ndp - par->hsync_start - par->hsync_width;
1692        v.lower_margin   = par->vsync_start;
1693        v.vsync_len      = par->vsync_width;
1694        v.upper_margin   = par->vert_ndp - par->vsync_start - par->vsync_width;
1695        v.bits_per_pixel = par->bpp;
1696
1697        switch(par->bpp) {
1698        case 8:
1699                v.red.offset = v.green.offset = v.blue.offset = 0;
1700                v.red.length = v.green.length = v.blue.length = 4;
1701                break;
1702        case 16:
1703                v.red.offset   = 11;
1704                v.red.length   = 5;
1705                v.green.offset = 5;
1706                v.green.length = 6;
1707                v.blue.offset  = 0;
1708                v.blue.length  = 5;
1709                break;
1710        }
1711
1712        v.height = v.width = -1;
1713        v.pixclock = KHZ2PICOS(par->ipclk.pixclk);
1714
1715        if (par->hsync_pol)
1716                v.sync |= FB_SYNC_HOR_HIGH_ACT;
1717        if (par->vsync_pol)
1718                v.sync |= FB_SYNC_VERT_HIGH_ACT;
1719
1720        *var = v;
1721        return 0;
1722}
1723
1724static int
1725e1356fb_encode_fix(struct fb_fix_screeninfo*  fix,
1726                   const struct e1356fb_par*   par,
1727                   const struct fb_info_e1356* info)
1728{
1729        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1730    
1731        strcpy(fix->id, "Epson SED1356");
1732        fix->smem_start  = info->fix.membase_phys;
1733        fix->smem_len    = info->fb_size;
1734        fix->mmio_start  = info->fix.regbase_phys;
1735        fix->mmio_len    = info->regbase_size;
1736        fix->accel       = FB_ACCEL_EPSON_SED1356;
1737        fix->type        = FB_TYPE_PACKED_PIXELS;
1738        fix->type_aux    = 0;
1739        fix->line_length = par->width_virt * par->Bpp;
1740        fix->visual      =
1741                (par->bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1742    
1743        fix->xpanstep    = info->fix.nopan ? 0 : 1;
1744        fix->ypanstep    = info->fix.nopan ? 0 : 1;
1745        fix->ywrapstep   = 0;
1746    
1747        return 0;
1748}
1749
1750static int e1356fb_open(struct fb_info *fb, int user)
1751{
1752        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
1753        if (user) {
1754                info->open++;
1755        }
1756        MOD_INC_USE_COUNT;
1757        return 0;
1758}
1759
1760static int e1356fb_release(struct fb_info *fb, int user)
1761{
1762        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
1763        if (user && info->open) {
1764                info->open--;
1765                if (info->open == 0)
1766                        info->mmaped = 0;
1767        }
1768        MOD_DEC_USE_COUNT;
1769        return 0;
1770}
1771
1772static int
1773e1356fb_get_fix(struct fb_fix_screeninfo *fix, 
1774                int con,
1775                struct fb_info *fb)
1776{
1777        const struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
1778        struct e1356fb_par par;
1779
1780        //DPRINTK("\n");
1781
1782        if (con == -1)
1783                par = info->current_par;
1784        else
1785                e1356fb_var_to_par(&fb_display[con].var, &par, info);
1786        e1356fb_encode_fix(fix, &par, info);
1787        return 0;
1788}
1789
1790static int
1791e1356fb_get_var(struct fb_var_screeninfo *var, 
1792                int con,
1793                struct fb_info *fb)
1794{
1795        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
1796
1797        //DPRINTK("\n");
1798
1799        if (con == -1)
1800                e1356fb_par_to_var(var, &info->current_par, info);
1801        else
1802                *var = fb_display[con].var;
1803        return 0;
1804}
1805 
1806static void
1807e1356fb_set_dispsw(struct display *disp, 
1808                   struct fb_info_e1356 *info,
1809                   int bpp, 
1810                   int accel)
1811{
1812        struct e1356fb_fix* fix = &info->fix;
1813        //DPRINTK("\n");
1814
1815        if (disp->dispsw && disp->conp) 
1816                fb_con.con_cursor(disp->conp, CM_ERASE);
1817        switch (bpp) {
1818#ifdef FBCON_HAS_CFB8
1819        case 8:
1820                disp->dispsw = fix->noaccel ? &fbcon_cfb8 : &fbcon_e1356_8;
1821                if (fix->nohwcursor)
1822                        fbcon_e1356_8.cursor = NULL;
1823                break;
1824#endif
1825#ifdef FBCON_HAS_CFB16
1826        case 16:
1827                disp->dispsw = fix->noaccel ? &fbcon_cfb16 : &fbcon_e1356_16;
1828                disp->dispsw_data = info->fbcon_cmap16;
1829                if (fix->nohwcursor)
1830                        fbcon_e1356_16.cursor = NULL;
1831                break;
1832#endif
1833        default:
1834                disp->dispsw = &fbcon_dummy;
1835        }
1836   
1837}
1838
1839static int
1840e1356fb_set_var(struct fb_var_screeninfo *var, 
1841                int con,
1842                struct fb_info *fb)
1843{
1844        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
1845        struct e1356fb_par par;
1846        struct display *display;
1847        int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
1848        int activate = var->activate;
1849        int j,k;
1850    
1851        DPRINTK("\n");
1852        
1853        if (con >= 0)
1854                display = &fb_display[con];
1855        else
1856                display = fb->disp;     /* used during initialization */
1857   
1858        if ((err = e1356fb_var_to_par(var, &par, info))) {
1859                struct fb_videomode *dm;
1860                /*
1861                 * this mode didn't pass the tests. Try the
1862                 * corresponding mode from our own modedb.
1863                 */
1864                DPRINTK("req mode failed, trying SED1356 %dx%d mode\n",
1865                        var->xres, var->yres);
1866                if (e1356fb_get_mode(info, var->xres,
1867                                     var->yres, NULL, &dm) < 0) {
1868                        DPRINTK("no SED1356 %dx%d mode found, failed\n",
1869                                var->xres, var->yres);
1870                        return err;
1871                }
1872                fb_videomode_to_var(dm, var);
1873                if ((err = e1356fb_var_to_par(var, &par, info))) {
1874                        DPRINTK("SED1356 %dx%d mode failed\n",
1875                                var->xres, var->yres);
1876                        return err;
1877                }
1878        }
1879        
1880        if (info->fix.tv_filt & TV_FILT_FLICKER)
1881                printk("e1356fb: TV flicker filter enabled\n");
1882    
1883        e1356fb_par_to_var(var, &par, info);
1884   
1885        if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1886                oldxres  = display->var.xres;
1887                oldyres  = display->var.yres;
1888                oldvxres = display->var.xres_virtual;
1889                oldvyres = display->var.yres_virtual;
1890                oldbpp   = display->var.bits_per_pixel;
1891                oldaccel = display->var.accel_flags;
1892                display->var = *var;
1893                if (con < 0                         ||
1894                    oldxres  != var->xres           || 
1895                    oldyres  != var->yres           ||
1896                    oldvxres != var->xres_virtual   || 
1897                    oldvyres != var->yres_virtual   ||
1898                    oldbpp   != var->bits_per_pixel || 
1899                    oldaccel != var->accel_flags) {
1900                        struct fb_fix_screeninfo fix;
1901            
1902                        e1356fb_encode_fix(&fix, &par, info);
1903                        display->screen_base    = info->membase_virt;
1904                        display->visual         = fix.visual;
1905                        display->type           = fix.type;
1906                        display->type_aux       = fix.type_aux;
1907                        display->ypanstep       = fix.ypanstep;
1908                        display->ywrapstep      = fix.ywrapstep;
1909                        display->line_length    = fix.line_length;
1910                        display->next_line      = fix.line_length;
1911                        display->can_soft_blank = 1;
1912                        display->inverse        = 0;
1913                        accel = var->accel_flags & FB_ACCELF_TEXT;
1914                        e1356fb_set_dispsw(display, info, par.bpp, accel);
1915         
1916                        if (info->fix.nopan)
1917                                display->scrollmode = SCROLL_YREDRAW;
1918        
1919                        if (info->fb_info.changevar)
1920                                (*info->fb_info.changevar)(con);
1921                }
1922                if (var->bits_per_pixel==8)
1923                        for(j = 0; j < 16; j++) {
1924                                k = color_table[j];
1925                                fb_info.palette[j].red   = default_red[k];
1926                                fb_info.palette[j].green = default_grn[k];
1927                                fb_info.palette[j].blue  = default_blu[k];
1928                        }
1929      
1930                del_timer(&(info->cursor.timer)); 
1931                fb_info.cursor.state=CM_ERASE;
1932        
1933                if (!info->fb_info.display_fg ||
1934                    info->fb_info.display_fg->vc_num == con || con < 0)
1935                        e1356fb_set_par(&par, info);
1936
1937                if (!info->fix.nohwcursor) 
1938                        if (display && display->conp)
1939                                e1356fb_createcursor( display );
1940                info->cursor.redraw = 1;
1941
1942                if (oldbpp != var->bits_per_pixel || con < 0) {
1943                        if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1944                                return err;
1945                        e1356fb_install_cmap(display, &(info->fb_info));
1946                }
1947        }
1948  
1949        return 0;
1950}
1951
1952static int
1953e1356fb_pan_display(struct fb_var_screeninfo* var, 
1954                    int con,
1955                    struct fb_info* fb)
1956{
1957        struct fb_info_e1356* info = (struct fb_info_e1356*)fb;
1958        struct e1356fb_par* par = &info->current_par;
1959    
1960        //DPRINTK("\n");
1961
1962        if (info->fix.nopan)
1963                return -EINVAL;
1964
1965        if ((int)var->xoffset < 0 ||
1966            var->xoffset + par->width > par->width_virt ||
1967            (int)var->yoffset < 0 ||
1968            var->yoffset + par->height > par->height_virt)
1969                return -EINVAL;
1970    
1971        if (con == currcon)
1972                do_pan_var(var, info);
1973    
1974        fb_display[con].var.xoffset = var->xoffset;
1975        fb_display[con].var.yoffset = var->yoffset; 
1976
1977        return 0;
1978}
1979
1980static int
1981e1356fb_get_cmap(struct fb_cmap *cmap, 
1982                 int kspc, 
1983                 int con,
1984                 struct fb_info *fb)
1985{
1986        struct fb_info_e1356* info = (struct fb_info_e1356*)fb;
1987        struct display *d = (con<0) ? fb->disp : fb_display + con;
1988   
1989        //DPRINTK("\n");
1990
1991        if (con == currcon) {
1992                /* current console? */
1993                return fb_get_cmap(cmap, kspc, e1356fb_getcolreg, fb);
1994        } else if (d->cmap.len) {
1995                /* non default colormap? */
1996                fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
1997        } else {
1998                fb_copy_cmap(fb_default_cmap(info->current_par.cmap_len),
1999                             cmap, kspc ? 0 : 2);
2000        }
2001        return 0;
2002}
2003
2004static int
2005e1356fb_set_cmap(struct fb_cmap *cmap, 
2006                 int kspc, 
2007                 int con,
2008                 struct fb_info *fb)
2009{
2010        struct display *d = (con<0) ? fb->disp : fb_display + con;
2011        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
2012        int cmap_len = (info->current_par.bpp == 8) ? 256 : 16;
2013
2014        //DPRINTK("\n");
2015
2016        if (d->cmap.len!=cmap_len) {
2017                int err;
2018                if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
2019                        return err;
2020        }
2021    
2022        if (con == currcon) {
2023                /* current console? */
2024                return fb_set_cmap(cmap, kspc, e1356fb_setcolreg, fb);
2025        } else {
2026                fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
2027        }
2028        return 0;
2029}
2030
2031static int
2032e1356fb_ioctl(struct inode *inode, 
2033              struct file *file, 
2034              u_int cmd,
2035              u_long arg, 
2036              int con, 
2037              struct fb_info *fb)
2038{
2039        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
2040        blt_info_t blt;
2041        u16* src = NULL;
2042        int ret=0;
2043    
2044        switch (cmd) {
2045        case FBIO_SED1356_BITBLT:
2046                if (copy_from_user(&blt, (void *)arg, sizeof(blt_info_t)))
2047                        return -EFAULT;
2048                if (blt.src) {
2049                        if ((ret = verify_area(VERIFY_READ,
2050                                               (void*)blt.src, blt.srcsize)))
2051                                return ret;
2052                        if ((src = (u16*)kmalloc(blt.srcsize,
2053                                                 GFP_KERNEL)) == NULL)
2054                                return -ENOMEM;
2055                        if (copy_from_user(src, (void *)blt.src, blt.srcsize))
2056                                return -EFAULT;
2057                        blt.src = src;
2058                }
2059                ret = doBlt(&info->current_par, info, &blt);
2060                if (src)
2061                        kfree(src);
2062                break;
2063        default:
2064                return -EINVAL;
2065        }
2066
2067        return ret;
2068}
2069
2070
2071static int
2072e1356fb_mmap(struct fb_info *fb,
2073             struct file *file,
2074             struct vm_area_struct *vma)
2075{
2076        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
2077        unsigned int len;
2078        phys_t start=0, off;
2079
2080        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
2081                DPRINTK("invalid vma->vm_pgoff\n");
2082                return -EINVAL;
2083        }
2084    
2085#ifdef SHADOW_FRAME_BUFFER
2086        if (!info->shadow.fb) {
2087                int order = 0;
2088                while (info->fb_size > (PAGE_SIZE * (1 << order)))
2089                        order++;
2090                info->shadow.fb = (void*)__get_free_pages(GFP_KERNEL, order);
2091                if (!info->shadow.fb) {
2092                        DPRINTK("shadow fb alloc failed\n");
2093                        return -ENXIO;
2094                }
2095                memset(info->shadow.fb, 0, info->fb_size);
2096                init_timer(&info->shadow.timer);
2097                info->shadow.timer.function = do_write_shadow_fb;
2098                info->shadow.timer.data = (unsigned long)info;
2099        }
2100        mod_timer(&info->shadow.timer, jiffies+HZ/2);
2101        start = virt_to_phys(info->shadow.fb) & PAGE_MASK;
2102#else
2103        start = info->fix.membase_phys & PAGE_MASK;
2104#endif
2105
2106        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fb_size);
2107
2108        off = vma->vm_pgoff << PAGE_SHIFT;
2109    
2110        if ((vma->vm_end - vma->vm_start + off) > len) {
2111                DPRINTK("invalid vma\n");
2112                return -EINVAL;
2113        }
2114
2115        off += start;
2116        vma->vm_pgoff = off >> PAGE_SHIFT;
2117
2118        pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
2119#ifdef SHADOW_FRAME_BUFFER
2120        vma->vm_flags |= VM_RESERVED;
2121        pgprot_val(vma->vm_page_prot) &= ~_CACHE_UNCACHED;
2122#else
2123        pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
2124#endif
2125
2126        /* This is an IO map - tell maydump to skip this VMA */
2127        vma->vm_flags |= VM_IO;
2128        // FIXME: shouldn't have to do this. If the pages are marked writeable,
2129        // the TLB fault handlers should set these.
2130        pgprot_val(vma->vm_page_prot) |= (_PAGE_DIRTY | _PAGE_VALID);
2131    
2132        /*
2133         * The SED1356 has only a 16-bit wide data bus, and some
2134         * embedded platforms, such as the Pb1000, do not automatically
2135         * split 32-bit word accesses to the framebuffer into
2136         * seperate half-word accesses. Hence the upper half-word
2137         * never gets to the framebuffer. The following solution is
2138         * to intentionally return a non-32-bit-aligned VA. As long
2139         * as the user app assumes (and doesn't check) that the returned
2140         * VA is 32-bit aligned, all (assumed aligned) 32-bit accesses
2141         * will actually be unaligned and will get trapped by the MIPS
2142         * unaligned exception handler. This handler will emulate the
2143         * load/store instructions by splitting up the load/store
2144         * into two 16-bit load/stores. (This emulation is currently
2145         * enabled by default, but may be disabled in the future, when
2146         * alignment problems in user-level programs get fixed. When
2147         * that happens, this solution won't work anymore, unless the
2148         * process that mmap's the fb also calls sysmips(MIPS_FIXADE, 1),
2149         * which turns address-error emulation back on).
2150         *
2151         * Furthermore, this solution only seems to work for TinyX
2152         * (Xfbdev). Others, like Qt/E, do snoop the returned VA
2153         * and compensate, or do originally unaligned 32-bit accesses
2154         * which then become aligned, hence breaking this solution.
2155         */
2156        if (info->fix.mmunalign)
2157                vma->vm_start += 2;
2158        
2159        if (io_remap_page_range(vma->vm_start, off,
2160                                vma->vm_end - vma->vm_start,
2161                                vma->vm_page_prot))
2162                return -EAGAIN;
2163
2164        info->mmaped = 1;
2165        return 0;
2166}
2167
2168
2169int __init
2170e1356fb_init(void)
2171{
2172        struct fb_var_screeninfo var;
2173        struct e1356fb_fix * epfix = &fb_info.fix;
2174        e1356_reg_t* reg;
2175        void* regbase;
2176        char* name = "SED1356";
2177        int periodMCLK, periodBCLK;
2178        int dram_timing, rr_div, mclk_src;
2179        u8 rev_code, btmp, mclk_cfg;
2180
2181        if (options) {
2182                e1356fb_setup(options, 0);
2183        }
2184
2185        // clear out fb_info
2186        memset(&fb_info, 0, sizeof(struct fb_info_e1356));
2187
2188        // copy boot options
2189        fb_info.fix = boot_fix;
2190        fb_info.default_par = boot_par;
2191
2192        fb_info.regbase_size = E1356_REG_SIZE;
2193
2194        if (!epfix->system) {
2195                printk(KERN_ERR "e1356/86fb: no valid system found\n");
2196                return -ENODEV;
2197        }
2198
2199        if (epfix->system == SYS_SDU1356) {
2200                // it's the SDU1356B0C PCI eval card.
2201                struct pci_dev *pdev = NULL;
2202                if (!pci_present())   /* No PCI bus in this machine! */
2203                        return -ENODEV;
2204                if (!(pdev = pci_find_device(PCI_VENDOR_ID_EPSON,
2205                                             PCI_DEVICE_ID_EPSON_SDU1356, pdev)))
2206                        return -ENODEV;
2207                if (pci_enable_device(pdev))
2208                        return -ENODEV;
2209                epfix->regbase_phys = pci_resource_start(pdev, 0);
2210                epfix->membase_phys = epfix->regbase_phys + E1356_REG_SIZE;
2211        }
2212        
2213        fb_info.regbase_virt = ioremap_nocache(epfix->regbase_phys,
2214                                               E1356_REG_SIZE);
2215
2216        if (!fb_info.regbase_virt) {
2217                printk("e1356fb: Can't remap %s register area.\n", name);
2218                return -ENXIO;
2219        }
2220
2221        regbase = fb_info.regbase_virt;
2222        reg = &fb_info.reg;
2223    
2224        // Initialize the register pointers
2225        reg->basic =         (reg_basic_t*)   (regbase + REG_BASE_BASIC);
2226        reg->genio =         (reg_genio_t*)   (regbase + REG_BASE_GENIO);
2227        reg->md_cfg =        (reg_mdcfg_t*)   (regbase + REG_BASE_MDCFG);
2228        reg->clk_cfg =       (reg_clkcfg_t*)  (regbase + REG_BASE_CLKCFG);
2229        reg->mem_cfg =       (reg_memcfg_t*)  (regbase + REG_BASE_MEMCFG);
2230        reg->panel_cfg =     (reg_panelcfg_t*)(regbase + REG_BASE_PANELCFG);
2231        reg->lcd_cfg =       (reg_dispcfg_t*) (regbase + REG_BASE_LCD_DISPCFG);
2232        reg->crttv_cfg =     (reg_dispcfg_t*) (regbase + REG_BASE_CRTTV_DISPCFG);
2233        reg->lcd_mode =      (reg_dispmode_t*)(regbase + REG_BASE_LCD_DISPMODE);
2234        reg->crttv_mode =    (reg_dispmode_t*)(regbase + REG_BASE_CRTTV_DISPMODE);
2235        reg->lcd_inkcurs =   (reg_inkcurs_t*) (regbase + REG_BASE_LCD_INKCURS);
2236        reg->crttv_inkcurs = (reg_inkcurs_t*) (regbase + REG_BASE_CRTTV_INKCURS);
2237        reg->bitblt =        (reg_bitblt_t*)  (regbase + REG_BASE_BITBLT);
2238        reg->lut =           (reg_lut_t*)     (regbase + REG_BASE_LUT);
2239        reg->pwr_save =      (reg_pwrsave_t*) (regbase + REG_BASE_PWRSAVE);
2240        reg->misc =          (reg_misc_t*)    (regbase + REG_BASE_MISC);
2241        reg->mediaplug =     (reg_mediaplug_t*)(regbase + REG_BASE_MEDIAPLUG);
2242        reg->bitblt_data =   (u16*)           (regbase + REG_BASE_BITBLT_DATA);
2243    
2244        // Enable all register access
2245        writeb(0, &reg->basic->misc);
2246
2247        rev_code = readb(&reg->basic->rev_code);
2248        if ((rev_code >> 2) == 0x04) {
2249                printk("Found EPSON1356 Display Controller\n");
2250        }
2251        else if ((rev_code >> 2) == 0x07) {
2252                printk("Found EPSON13806 Display Controller\n");
2253        }
2254        else {
2255                iounmap(fb_info.regbase_virt);
2256                printk("e1356/806fb: %s not found, rev_code=0x%02x.\n",
2257                       name, rev_code);
2258                return -ENODEV;
2259        }
2260
2261        fb_info.chip_rev = rev_code & 0x03;
2262
2263        // Determine frame-buffer size
2264        switch (readb(&reg->md_cfg->md_cfg_stat0) >> 6) {
2265        case 0:
2266        case 2:
2267                fb_info.fb_size = 0x80000;   /* 512K bytes */
2268                break;
2269        case 1:
2270                if ((rev_code >> 2) == 7) /* 806 */
2271                        fb_info.fb_size = 0x140000;  /* 1.2M bytes */
2272                else
2273                        fb_info.fb_size = 0x200000;  /* 2M bytes */
2274                break;
2275        default:
2276                fb_info.fb_size = 0x200000;  /* 2M bytes */
2277                break;
2278        }
2279
2280        fb_info.membase_virt = ioremap_nocache(epfix->membase_phys,
2281                                               fb_info.fb_size);
2282    
2283        if (!fb_info.membase_virt) {
2284                printk("e1356fb: Can't remap %s framebuffer.\n", name);
2285                iounmap(fb_info.regbase_virt);
2286                return -ENXIO;
2287        }
2288    
2289        printk("e1356/806fb: Detected  %dKB framebuffer\n", 
2290                        (unsigned)fb_info.fb_size/1000);
2291
2292#ifdef CONFIG_MTRR
2293        if (!epfix->nomtrr) {
2294                fb_info.mtrr_idx = mtrr_add(epfix->membase_phys, fb_info.fb_size,
2295                                            MTRR_TYPE_WRCOMB, 1);
2296                printk("e1356fb: MTRR's turned on\n");
2297        }
2298#endif
2299    
2300        if (!boot_fix.noaccel) {
2301                /*
2302                  Allocate a page for string BLTs. A 4K page is
2303                  enough for a 256 character string at an 8x16 font.
2304                */
2305                fb_info.putcs_buffer = (void*)__get_free_pages(GFP_KERNEL, 0);
2306                if (fb_info.putcs_buffer == NULL) {
2307                        printk("e1356fb: Can't allocate putcs buffer\n");
2308                        goto unmap_ret_enxio;
2309                }
2310        }
2311
2312        // Begin SED1356 initialization
2313
2314        // disable display while initializing
2315        writeb(0, &reg->misc->disp_mode);
2316        // Set the GPIO1 and 2 to inputs
2317        writeb(0, &reg->genio->gpio_cfg);
2318        writeb(0, &reg->genio->gpio_ctrl);
2319        if (fb_info.chip_rev == 7) /* 806 */
2320                writeb(0, &reg->genio->gpio_ctrl2);
2321
2322        /*
2323         * Program the clocks
2324         */
2325
2326#ifdef CONFIG_SOC_AU1X00
2327        if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500))
2328                epfix->busclk = get_au1x00_lcd_clock();
2329#endif
2330        
2331        if (epfix->busclk > 80000) {
2332                printk("e1356fb: specified busclk too high\n");
2333                goto ret_enxio;
2334        }
2335
2336        epfix->mclk = mclk_cfg = 0;
2337        if (epfix->system == SYS_PB1500) {
2338                epfix->mclk = epfix->busclk;
2339                mclk_cfg = 0x01;
2340        }
2341        else {
2342                // Find the highest allowable MCLK
2343                if (epfix->busclk <= MAX_PIXCLOCK && 
2344                                epfix->busclk > epfix->mclk) {
2345                        epfix->mclk = epfix->busclk;
2346                        mclk_cfg = 0x01;
2347                }
2348                if (epfix->clki <= MAX_PIXCLOCK && epfix->clki > epfix->mclk) {
2349                        epfix->mclk = epfix->clki;
2350                        mclk_cfg = 0x00;
2351                }
2352                if (epfix->busclk/2 <= MAX_PIXCLOCK && 
2353                                epfix->busclk/2 > epfix->mclk) {
2354                        epfix->mclk = epfix->busclk/2;
2355                        mclk_cfg = 0x11;
2356                }
2357                if (epfix->clki/2 <= MAX_PIXCLOCK && 
2358                                epfix->clki/2 > epfix->mclk) {
2359                        epfix->mclk = epfix->clki/2;
2360                        mclk_cfg = 0x10;
2361                }
2362        }
2363        
2364        if (!epfix->mclk) {
2365                printk("e1356fb: couldn't find an allowable MCLK!\n");
2366                goto ret_enxio;
2367        }
2368
2369        // When changing mclk src, you must first set bit 4 to 1.
2370        writeb(readb(&reg->clk_cfg->mem_clk_cfg) | 0x10,
2371               &reg->clk_cfg->mem_clk_cfg);
2372        writeb(mclk_cfg, &reg->clk_cfg->mem_clk_cfg);
2373
2374        printk("e1356fb: clocks (kHz): busclk=%d mclk=%d clki=%d clki2=%d\n",
2375               epfix->busclk, epfix->mclk, epfix->clki, epfix->clki2);
2376
2377        // Set max pixel clock
2378        switch (epfix->disp_type) {
2379        case DISP_TYPE_LCD:
2380        case DISP_TYPE_TFT:
2381        case DISP_TYPE_CRT:
2382                fb_info.max_pixclock = epfix->mclk;
2383                break;
2384        case DISP_TYPE_NTSC:
2385        case DISP_TYPE_PAL:
2386                fb_info.max_pixclock = (epfix->disp_type == DISP_TYPE_NTSC) ?
2387                        NTSC_PIXCLOCK : PAL_PIXCLOCK;
2388                if (epfix->tv_filt & TV_FILT_FLICKER)
2389                        fb_info.max_pixclock *= 2;
2390                break;
2391        default:
2392                printk("e1356fb: invalid specified display type\n");
2393                goto ret_enxio;
2394        }
2395
2396        periodMCLK = 1000000L / epfix->mclk;   // in nano-seconds
2397        periodBCLK = 1000000L / epfix->busclk; // in nano-seconds
2398        if (readb(&reg->md_cfg->md_cfg_stat1) & (1<<4))
2399                periodBCLK *= 2;
2400    
2401        if ((epfix->system == SYS_PB1000) || (epfix->system == SYS_PB1500))
2402                writeb(0x00, &reg->clk_cfg->cpu2mem_wait_sel);
2403        else if (periodMCLK - 4 > periodBCLK)
2404                writeb(0x02, &reg->clk_cfg->cpu2mem_wait_sel);
2405        else if (2*periodMCLK - 4 > periodBCLK)
2406                writeb(0x01, &reg->clk_cfg->cpu2mem_wait_sel);
2407        else
2408                writeb(0x00, &reg->clk_cfg->cpu2mem_wait_sel);
2409
2410        // Program memory config
2411        if (epfix->mem_type < MEM_TYPE_EDO_2CAS ||
2412            epfix->mem_type > MEM_TYPE_EMBEDDED_SDRAM) {
2413                printk("e1356fb: bad memory type specified\n");
2414                goto ret_enxio;
2415        }
2416        writeb((u8)epfix->mem_type, &reg->mem_cfg->mem_cfg);
2417
2418        // calc closest refresh rate
2419        rr_div = 7;
2420        mclk_src = (mclk_cfg & 1) ? epfix->busclk : epfix->clki;
2421        while ((mclk_src >> (6 + rr_div)) < epfix->mem_refresh)
2422                if (--rr_div < 0) {
2423                        printk("e1356fb: can't set specified refresh rate\n");
2424                        goto ret_enxio;
2425                }
2426    
2427        DPRINTK("refresh rate = %d kHz\n", (mclk_src >> (6 + rr_div)));
2428
2429        // add Suspend-Mode Refresh bits
2430        if (epfix->mem_smr < MEM_SMR_CBR || epfix->mem_smr > MEM_SMR_NONE) {
2431                printk("e1356fb: invalid specified suspend-mode refresh type\n");
2432                goto ret_enxio;
2433        }
2434        writeb(rr_div | (epfix->mem_smr << 6), &reg->mem_cfg->dram_refresh);
2435
2436        // set DRAM speed
2437        switch (epfix->mem_speed) {
2438        case 50:
2439                dram_timing = epfix->mclk >= 33000 ? 0x0101 : 0x0212;
2440                break;
2441        case 60:
2442                if (epfix->mclk >= 30000)
2443                        dram_timing = 0x0101;
2444                else if (epfix->mclk >= 25000)
2445                        dram_timing =
2446                                (epfix->mem_type == MEM_TYPE_EDO_2CAS ||
2447                                 epfix->mem_type == MEM_TYPE_EDO_2WE) ?
2448                                0x0212 : 0x0101;
2449                else
2450                        dram_timing = 0x0212;
2451                break;
2452        case 70:
2453                if (epfix->mclk >= 30000)
2454                        dram_timing = 0x0000;
2455                else if (epfix->mclk >= 25000)
2456                        dram_timing = 0x0101;
2457                else
2458                        dram_timing =
2459                                (epfix->mem_type == MEM_TYPE_EDO_2CAS ||
2460                                 epfix->mem_type == MEM_TYPE_EDO_2WE) ?
2461                                0x0212 : 0x0211;
2462                break;
2463        case 80:
2464                if (epfix->mclk >= 25000)
2465                        dram_timing = 0x0100;
2466                else
2467                        dram_timing = 0x0101;
2468                break;
2469        default:
2470                printk("e1356fb: invalid specified memory speed\n");
2471                goto ret_enxio;
2472        }
2473
2474        writew(dram_timing, &reg->mem_cfg->dram_timings_ctrl0);
2475    
2476        currcon = -1;
2477        if (!epfix->nohwcursor)
2478                e1356fb_hwcursor_init(&fb_info);
2479    
2480        init_timer(&fb_info.cursor.timer);
2481        fb_info.cursor.timer.function = do_flashcursor; 
2482        fb_info.cursor.timer.data = (unsigned long)(&fb_info);
2483        fb_info.cursor.state = CM_ERASE;
2484        spin_lock_init(&fb_info.cursor.lock);
2485    
2486        strcpy(fb_info.fb_info.modename, "Epson "); 
2487        strcat(fb_info.fb_info.modename, name);
2488        fb_info.fb_info.changevar  = NULL;
2489        fb_info.fb_info.node       = -1;
2490
2491        fb_info.fb_info.fbops      = &e1356fb_ops;
2492        fb_info.fb_info.disp       = &fb_info.disp;
2493        strcpy(fb_info.fb_info.fontname, epfix->fontname);
2494        fb_info.fb_info.switch_con = &e1356fb_switch_con;
2495        fb_info.fb_info.updatevar  = &e1356fb_updatevar;
2496        fb_info.fb_info.blank      = &e1356fb_blank;
2497        fb_info.fb_info.flags      = FBINFO_FLAG_DEFAULT;
2498    
2499        // Set-up display
2500        // clear out unused stuff
2501        writeb(0, &reg->panel_cfg->mod_rate);
2502        writeb(0x01, &reg->lcd_mode->lcd_misc);
2503        writeb(0, &reg->lcd_mode->fifo_high_thresh);
2504        writeb(0, &reg->lcd_mode->fifo_low_thresh);
2505        writeb(0, &reg->crttv_mode->fifo_high_thresh);
2506        writeb(0, &reg->crttv_mode->fifo_low_thresh);
2507    
2508        switch (epfix->disp_type) {
2509        case DISP_TYPE_LCD:
2510                switch (epfix->panel_width) {
2511                case 4: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x04); break;
2512                case 8: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x14); break;
2513                case 16: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x24); break;
2514                default:
2515                        printk("e1356fb: invalid specified LCD panel data width\n");
2516                        goto ret_enxio;
2517                }
2518                writeb(btmp, &reg->panel_cfg->panel_type);
2519                break;
2520        case DISP_TYPE_TFT:
2521                switch (epfix->panel_width) {
2522                case 9: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x05); break;
2523                case 12: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x15); break;
2524                case 18: btmp = (u8)(((epfix->panel_el & 1)<<7) | 0x25); break;
2525                default:
2526                        printk("e1356fb: invalid specified TFT panel data width\n");
2527                        goto ret_enxio;
2528                }
2529                writeb(btmp, &reg->panel_cfg->panel_type);
2530                break;
2531        case DISP_TYPE_CRT:
2532                writeb(0x00, &reg->crttv_cfg->tv_output_ctrl);
2533                break;
2534        case DISP_TYPE_NTSC:
2535        case DISP_TYPE_PAL:
2536                if (epfix->tv_fmt < TV_FMT_COMPOSITE ||
2537                    epfix->tv_fmt > TV_FMT_S_VIDEO) {
2538                        printk("e1356fb: invalid specified TV output format\n");
2539                        goto ret_enxio;
2540                }
2541                btmp = epfix->disp_type == DISP_TYPE_PAL ? 0x01 : 0x00;
2542                btmp |= (epfix->tv_fmt == TV_FMT_S_VIDEO ? 0x02 : 0x00);
2543                btmp |= ((epfix->tv_filt & TV_FILT_LUM) ? 0x10 : 0x00);
2544                btmp |= ((epfix->tv_filt & TV_FILT_CHROM) ? 0x20 : 0x00);
2545                writeb(btmp, &reg->crttv_cfg->tv_output_ctrl);
2546                break;
2547        }
2548
2549        memset(&var, 0, sizeof(var));
2550        /*
2551         * If mode_option wasn't given at boot, assume all the boot
2552         * option timing parameters were specified individually, in
2553         * which case we convert par_to_var instead of calling
2554         * fb_find_mode.
2555         */
2556        if (epfix->mode_option) {
2557                struct fb_videomode* modedb, *dm;
2558                int dbsize = e1356fb_get_mode(&fb_info, 640, 480, &modedb, &dm);
2559
2560                // first try the generic modedb
2561                if (!fb_find_mode(&var, &fb_info.fb_info, epfix->mode_option,
2562                                  NULL, 0, NULL, boot_par.bpp)) {
2563                        printk("e1356fb: mode %s failed, trying e1356 modedb\n",
2564                               epfix->mode_option);
2565                        // didn't work in generic modedb, try ours
2566                        if (!fb_find_mode(&var, &fb_info.fb_info,
2567                                          epfix->mode_option,
2568                                          modedb, dbsize, dm, boot_par.bpp)) {
2569                                printk("e1356fb: mode %s failed e1356 modedb too, sorry\n",
2570                                       epfix->mode_option);
2571                                
2572                                goto ret_enxio;
2573                        }
2574                }
2575
2576                var.xres_virtual = boot_par.width_virt ?
2577                        boot_par.width_virt : boot_par.width;
2578                var.yres_virtual = boot_par.height_virt ?
2579                        boot_par.height_virt : boot_par.height;
2580        } else {
2581                if (e1356fb_par_to_var(&var, &fb_info.default_par, &fb_info)) {
2582                        printk("e1356fb: boot option mode failed\n");
2583                        goto ret_enxio;
2584                }
2585        }
2586    
2587        if (boot_fix.noaccel)
2588                var.accel_flags &= ~FB_ACCELF_TEXT;
2589        else
2590                var.accel_flags |= FB_ACCELF_TEXT;
2591    
2592        if (e1356fb_var_to_par(&var, &fb_info.default_par, &fb_info)) {
2593                /*
2594                 * Can't use the mode from the mode db or the default
2595                 * mode or the boot options - give up
2596                 */
2597                printk("e1356fb: mode failed var_to_par\n");
2598                goto ret_enxio;
2599        }
2600    
2601        fb_info.disp.screen_base    = fb_info.membase_virt;
2602        fb_info.disp.var            = var; // struct copy
2603    
2604        // here's where the screen is actually initialized and enabled
2605        if (e1356fb_set_var(&var, -1, &fb_info.fb_info)) {
2606                printk("e1356fb: can't set video mode\n");
2607                goto ret_enxio;
2608        }
2609    
2610        writeb(0, &reg->pwr_save->cfg);     // disable power-save mode
2611        writeb(0, &reg->misc->cpu2mem_watchdog); // disable watchdog timer
2612
2613#ifdef E1356FB_VERBOSE_DEBUG
2614        dump_fb(fb_info.membase_virt + 0x100000, 512);
2615#endif
2616
2617        if (register_framebuffer(&fb_info.fb_info) < 0) {
2618                writeb(0, &reg->misc->disp_mode); 
2619                printk("e1356fb: can't register framebuffer\n");
2620                goto ret_enxio;
2621        }
2622    
2623        printk("fb%d: %s frame buffer device\n", 
2624               GET_FB_IDX(fb_info.fb_info.node),
2625               fb_info.fb_info.modename);
2626    
2627    
2628        return 0;
2629
2630 ret_enxio:
2631        free_pages((unsigned long)fb_info.putcs_buffer, 0);
2632 unmap_ret_enxio:
2633        iounmap(fb_info.regbase_virt);
2634        iounmap(fb_info.membase_virt);
2635        return -ENXIO;
2636}
2637
2638/**
2639 *      e1356fb_exit - Driver cleanup
2640 *
2641 *      Releases all resources allocated during the
2642 *      course of the driver's lifetime.
2643 *
2644 *      FIXME - do results of fb_alloc_cmap need disposal?
2645 */
2646static void __exit
2647e1356fb_exit (void)
2648{
2649        unregister_framebuffer(&fb_info.fb_info);
2650        del_timer_sync(&fb_info.cursor.timer);
2651
2652#ifdef CONFIG_MTRR
2653        if (!fb_info.fix.nomtrr) {
2654                mtrr_del(fb_info.mtrr_idx, fb_info.fix.membase_phys,
2655                         fb_info.fb_size);
2656                printk("fb: MTRR's  turned off\n");
2657        }
2658#endif
2659
2660        free_pages((unsigned long)fb_info.putcs_buffer, 0);
2661        iounmap(fb_info.regbase_virt);
2662        iounmap(fb_info.membase_virt);
2663}
2664
2665MODULE_AUTHOR("Steve Longerbeam <stevel@mvista.com>");
2666MODULE_DESCRIPTION("SED1356 framebuffer device driver");
2667
2668#ifdef MODULE
2669module_init(e1356fb_init);
2670#endif
2671module_exit(e1356fb_exit);
2672
2673
2674void
2675e1356fb_setup(char *options, int *ints)
2676{
2677        char* this_opt;
2678    
2679        memset(&boot_fix, 0, sizeof(struct e1356fb_fix));
2680        memset(&boot_par, 0, sizeof(struct e1356fb_par));
2681        boot_fix.system = -1;
2682    
2683        if (!options || !*options)
2684                return;
2685    
2686        for(this_opt=strtok(options, ","); this_opt;
2687            this_opt=strtok(NULL, ",")) {
2688                if (!strncmp(this_opt, "noaccel", 7)) {
2689                        boot_fix.noaccel = 1;
2690                } else if (!strncmp(this_opt, "nopan", 5)) {
2691                        boot_fix.nopan = 1;
2692                } else if (!strncmp(this_opt, "nohwcursor", 10)) {
2693                        boot_fix.nohwcursor = 1;
2694                } else if (!strncmp(this_opt, "mmunalign:", 10)) {
2695                        boot_fix.mmunalign = simple_strtoul(this_opt+10,
2696                                                            NULL, 0);
2697#ifdef CONFIG_MTRR
2698                } else if (!strncmp(this_opt, "nomtrr", 6)) {
2699                        boot_fix.nomtrr = 1;
2700#endif
2701                } else if (!strncmp(this_opt, "font:", 5)) {
2702                        strncpy(boot_fix.fontname, this_opt+5,
2703                                sizeof(boot_fix.fontname)-1);
2704                } else if (!strncmp(this_opt, "regbase:", 8)) {
2705                        boot_fix.regbase_phys = simple_strtoul(this_opt+8,
2706                                                               NULL, 0);
2707                } else if (!strncmp(this_opt, "membase:", 8)) {
2708                        boot_fix.membase_phys = simple_strtoul(this_opt+8,
2709                                                               NULL, 0);
2710                } else if (!strncmp(this_opt, "memsp:", 6)) {
2711                        boot_fix.mem_speed = simple_strtoul(this_opt+6,
2712                                                            NULL, 0);
2713                } else if (!strncmp(this_opt, "memtyp:", 7)) {
2714                        boot_fix.mem_type = simple_strtoul(this_opt+7,
2715                                                           NULL, 0);
2716                } else if (!strncmp(this_opt, "memref:", 7)) {
2717                        boot_fix.mem_refresh = simple_strtoul(this_opt+7,
2718                                                              NULL, 0);
2719                } else if (!strncmp(this_opt, "memsmr:", 7)) {
2720                        boot_fix.mem_smr = simple_strtoul(this_opt+7, NULL, 0);
2721                } else if (!strncmp(this_opt, "busclk:", 7)) {
2722                        boot_fix.busclk = simple_strtoul(this_opt+7, NULL, 0);
2723                } else if (!strncmp(this_opt, "clki:", 5)) {
2724                        boot_fix.clki = simple_strtoul(this_opt+5, NULL, 0);
2725                } else if (!strncmp(this_opt, "clki2:", 6)) {
2726                        boot_fix.clki2 = simple_strtoul(this_opt+6, NULL, 0);
2727                } else if (!strncmp(this_opt, "display:", 8)) {
2728                        if (!strncmp(this_opt+8, "lcd", 3))
2729                                boot_fix.disp_type = DISP_TYPE_LCD;
2730                        else if (!strncmp(this_opt+8, "tft", 3))
2731                                boot_fix.disp_type = DISP_TYPE_TFT;
2732                        else if (!strncmp(this_opt+8, "crt", 3))
2733                                boot_fix.disp_type = DISP_TYPE_CRT;
2734                        else if (!strncmp(this_opt+8, "pal", 3))
2735                                boot_fix.disp_type = DISP_TYPE_PAL;
2736                        else if (!strncmp(this_opt+8, "ntsc", 4))
2737                                boot_fix.disp_type = DISP_TYPE_NTSC;
2738                } else if (!strncmp(this_opt, "width:", 6)) {
2739                        boot_par.width = simple_strtoul(this_opt+6, NULL, 0);
2740                } else if (!strncmp(this_opt, "height:", 7)) {
2741                        boot_par.height = simple_strtoul(this_opt+7, NULL, 0);
2742                } else if (!strncmp(this_opt, "bpp:", 4)) {
2743                        boot_par.bpp = simple_strtoul(this_opt+4, NULL, 0);
2744                        boot_par.cmap_len = (boot_par.bpp == 8) ? 256 : 16;
2745                } else if (!strncmp(this_opt, "elpanel:", 8)) {
2746                        boot_fix.panel_el = simple_strtoul(this_opt+8,
2747                                                           NULL, 0);
2748                } else if (!strncmp(this_opt, "pdataw:", 7)) {
2749                        boot_fix.panel_width = simple_strtoul(this_opt+7,
2750                                                              NULL, 0);
2751                } else if (!strncmp(this_opt, "hndp:", 5)) {
2752                        boot_par.horiz_ndp = simple_strtoul(this_opt+5,
2753                                                            NULL, 0);
2754                } else if (!strncmp(this_opt, "vndp:", 5)) {
2755                        boot_par.vert_ndp = simple_strtoul(this_opt+5,
2756                                                           NULL, 0);
2757                } else if (!strncmp(this_opt, "hspol:", 6)) {
2758                        boot_par.hsync_pol = simple_strtoul(this_opt+6,
2759                                                            NULL, 0);
2760                } else if (!strncmp(this_opt, "vspol:", 6)) {
2761                        boot_par.vsync_pol = simple_strtoul(this_opt+6,
2762                                                            NULL, 0);
2763                } else if (!strncmp(this_opt, "hsstart:", 8)) {
2764                        boot_par.hsync_start = simple_strtoul(this_opt+8,
2765                                                              NULL, 0);
2766                } else if (!strncmp(this_opt, "hswidth:", 8)) {
2767                        boot_par.hsync_width = simple_strtoul(this_opt+8,
2768                                                              NULL, 0);
2769                } else if (!strncmp(this_opt, "vsstart:", 8)) {
2770                        boot_par.vsync_start = simple_strtoul(this_opt+8,
2771                                                              NULL, 0);
2772                } else if (!strncmp(this_opt, "vswidth:", 8)) {
2773                        boot_par.vsync_width = simple_strtoul(this_opt+8,
2774                                                              NULL, 0);
2775                } else if (!strncmp(this_opt, "tvfilt:", 7)) {
2776                        boot_fix.tv_filt = simple_strtoul(this_opt+7, NULL, 0);
2777                } else if (!strncmp(this_opt, "tvfmt:", 6)) {
2778                        boot_fix.tv_fmt = simple_strtoul(this_opt+6, NULL, 0);
2779                } else if (!strncmp(this_opt, "system:", 7)) {
2780                        if (!strncmp(this_opt+7, "pb1000", 10)) {
2781                                boot_fix = systems[SYS_PB1000].fix;
2782                                boot_par = systems[SYS_PB1000].par;
2783                        } else if (!strncmp(this_opt+7, "pb1500", 7)) {
2784                                boot_fix = systems[SYS_PB1500].fix;
2785                                boot_par = systems[SYS_PB1500].par;
2786                        } else if (!strncmp(this_opt+7, "sdu1356", 7)) {
2787                                boot_fix = systems[SYS_SDU1356].fix;
2788                                boot_par = systems[SYS_SDU1356].par;
2789                        } else if (!strncmp(this_opt+7, "clio1050", 7)) {
2790                                boot_fix = systems[SYS_CLIO1050].fix;
2791                                boot_par = systems[SYS_CLIO1050].par;
2792                        }
2793                } else {
2794                        boot_fix.mode_option = this_opt;
2795                }
2796        } 
2797}
2798
2799
2800/*
2801 * FIXME: switching consoles could be dangerous. What if switching
2802 * from a panel to a CRT/TV, or vice versa? More needs to be
2803 * done here.
2804 */
2805static int
2806e1356fb_switch_con(int con, struct fb_info *fb)
2807{
2808        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
2809        struct e1356fb_par par;
2810        int old_con = currcon;
2811        int set_par = 1;
2812
2813        //DPRINTK("\n");
2814
2815        /* Do we have to save the colormap? */
2816        if (currcon>=0)
2817                if (fb_display[currcon].cmap.len)
2818                        fb_get_cmap(&fb_display[currcon].cmap, 1,
2819                                    e1356fb_getcolreg, fb);
2820   
2821        currcon = con;
2822        fb_display[currcon].var.activate = FB_ACTIVATE_NOW; 
2823        e1356fb_var_to_par(&fb_display[con].var, &par, info);
2824        if (old_con>=0 && vt_cons[old_con]->vc_mode!=KD_GRAPHICS) {
2825                /* check if we have to change video registers */
2826                struct e1356fb_par old_par;
2827                e1356fb_var_to_par(&fb_display[old_con].var, &old_par, info);
2828                if (!memcmp(&par,&old_par,sizeof(par)))
2829                        set_par = 0;    /* avoid flicker */
2830        }
2831        if (set_par)
2832                e1356fb_set_par(&par, info);
2833    
2834        if (fb_display[con].dispsw && fb_display[con].conp)
2835                fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
2836   
2837        del_timer(&(info->cursor.timer));
2838        fb_info.cursor.state=CM_ERASE; 
2839   
2840        if (!info->fix.nohwcursor) 
2841                if (fb_display[con].conp)
2842                        e1356fb_createcursor( &fb_display[con] );
2843   
2844        info->cursor.redraw=1;
2845   
2846        e1356fb_set_dispsw(&fb_display[con], 
2847                           info, 
2848                           par.bpp,
2849                           fb_display[con].var.accel_flags & FB_ACCELF_TEXT);
2850   
2851        e1356fb_install_cmap(&fb_display[con], fb);
2852        e1356fb_updatevar(con, fb);
2853   
2854        return 1;
2855}
2856
2857/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2858static void
2859e1356fb_blank(int blank, struct fb_info *fb)
2860{
2861        struct fb_info_e1356 *info = (struct fb_info_e1356*)fb;
2862        reg_dispmode_t* dispmode = (IS_PANEL(info->fix.disp_type)) ?
2863                info->reg.lcd_mode : info->reg.crttv_mode;
2864        reg_pwrsave_t* pwrsave = info->reg.pwr_save;
2865
2866        //DPRINTK("\n");
2867
2868        switch (blank) {
2869        case 0:
2870                // Get out of power save mode
2871                writeb(0x00, &pwrsave->cfg);
2872                writeb(readb(&dispmode->disp_mode) & ~0x80,
2873                       &dispmode->disp_mode);
2874                break;
2875        case 1:
2876                // Get out of power save mode
2877                writeb(0x00, &pwrsave->cfg);
2878                writeb(readb(&dispmode->disp_mode) | 0x80,
2879                       &dispmode->disp_mode);
2880                break;
2881                // No support for turning off horiz or vert sync, so just treat
2882                // it as a power off.
2883        case 2:
2884        case 3:
2885        case 4:
2886                writeb(0x01, &pwrsave->cfg);
2887                break;
2888        }
2889}
2890
2891
2892static int
2893e1356fb_updatevar(int con, struct fb_info* fb)
2894{
2895        struct fb_info_e1356* i = (struct fb_info_e1356*)fb;
2896
2897        //DPRINTK("\n");
2898
2899        if ((con==currcon) && (!i->fix.nopan)) 
2900                do_pan_var(&fb_display[con].var,i);
2901        return 0;
2902}
2903
2904static int
2905e1356fb_getcolreg(unsigned        regno, 
2906                  unsigned*       red, 
2907                  unsigned*       green,
2908                  unsigned*       blue, 
2909                  unsigned*       transp,
2910                  struct fb_info* fb)
2911{
2912        struct fb_info_e1356* i = (struct fb_info_e1356*)fb;
2913
2914        if (regno > i->current_par.cmap_len)
2915                return 1;
2916   
2917        *red    = i->palette[regno].red; 
2918        *green  = i->palette[regno].green; 
2919        *blue   = i->palette[regno].blue; 
2920        *transp = 0;
2921   
2922        return 0;
2923}
2924
2925static int
2926e1356fb_setcolreg(unsigned        regno, 
2927                  unsigned        red, 
2928                  unsigned        green,
2929                  unsigned        blue, 
2930                  unsigned        transp,
2931                  struct fb_info* info)
2932{
2933        struct fb_info_e1356* i = (struct fb_info_e1356*)info;
2934
2935        if (regno > 255)
2936                return 1;
2937
2938        i->palette[regno].red    = red;
2939        i->palette[regno].green  = green;
2940        i->palette[regno].blue   = blue;
2941   
2942        switch(i->current_par.bpp) {
2943#ifdef FBCON_HAS_CFB8
2944        case 8:
2945                do_setpalentry(i->reg.lut, regno,
2946                               (u8)(red>>8), (u8)(green>>8), (u8)(blue>>8));
2947                break;
2948#endif
2949#ifdef FBCON_HAS_CFB16
2950        case 16:
2951                i->fbcon_cmap16[regno] = (regno << 10) | (regno << 5) | regno;
2952                break;
2953#endif
2954        default:
2955                DPRINTK("bad depth %u\n", i->current_par.bpp);
2956                break;
2957        }
2958        return 0;
2959}
2960
2961static void
2962e1356fb_install_cmap(struct display *d, struct fb_info *info) 
2963{
2964        struct fb_info_e1356* i = (struct fb_info_e1356*)info;
2965
2966        //DPRINTK("\n");
2967
2968        if (d->cmap.len) {
2969                fb_set_cmap(&(d->cmap), 1, e1356fb_setcolreg, info);
2970        } else {
2971                fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1,
2972                            e1356fb_setcolreg, info);
2973        }
2974}
2975
2976static void
2977e1356fb_createcursorshape(struct display* p) 
2978{
2979        int h,u;
2980   
2981        h = fontheight(p);
2982
2983        fb_info.cursor.type = p->conp->vc_cursor_type & CUR_HWMASK;
2984
2985        switch (fb_info.cursor.type) {
2986        case CUR_NONE: 
2987                u = h; 
2988                break;
2989        case CUR_UNDERLINE: 
2990                u = h - 2; 
2991                break;
2992        case CUR_LOWER_THIRD: 
2993                u = (h * 2) / 3; 
2994                break;
2995        case CUR_LOWER_HALF: 
2996                u = h / 2; 
2997                break;
2998        case CUR_TWO_THIRDS: 
2999                u = h / 3; 
3000                break;
3001        case CUR_BLOCK:
3002        default:
3003                u = 0;
3004                break;
3005        }
3006    
3007        fb_info.cursor.w = fontwidth_x8(p);
3008        fb_info.cursor.u = u;
3009        fb_info.cursor.h = h;
3010}
3011   
3012static void
3013e1356fb_createcursor(struct display *p)
3014{
3015        void* memcursor;
3016        int y, w, h, u;
3017    
3018        e1356fb_createcursorshape(p);
3019
3020        h = fb_info.cursor.h;
3021        w = fb_info.cursor.w;
3022        u = fb_info.cursor.u;
3023        memcursor = fb_info.membase_virt + fb_info.fb_size;
3024
3025        // write cursor to display memory
3026        for (y=0; y<64; y++) {
3027                if (y >= h || y < u) {
3028                        fbfill((u16*)memcursor, 0xaa, 16); // b/g
3029                } else {
3030                        fbfill((u16*)memcursor, 0xff, w/4); // inverted b/g
3031                        fbfill((u16*)memcursor + w/4, 0xaa, (64 - w)/4); // b/g
3032                }
3033                memcursor += 16;
3034        }
3035}
3036   
3037static void
3038e1356fb_hwcursor_init(struct fb_info_e1356* info)
3039{
3040        reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ?
3041                info->reg.lcd_inkcurs : info->reg.crttv_inkcurs;
3042
3043        fb_info.fb_size -= 1024;
3044        // program cursor base address
3045        writeb(0x00, &inkcurs->start_addr);
3046        printk("e1356fb: reserving 1024 bytes for the hwcursor at %p\n",
3047               fb_info.membase_virt + fb_info.fb_size);
3048}
3049
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.