linux/drivers/video/fbdev/via/lcd.c
<<
>>
Prefs
   1/*
   2 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
   3 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
   4
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public
   7 * License as published by the Free Software Foundation;
   8 * either version 2, or (at your option) any later version.
   9
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
  12 * the implied warranty of MERCHANTABILITY or FITNESS FOR
  13 * A PARTICULAR PURPOSE.See the GNU General Public License
  14 * for more details.
  15
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc.,
  19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20 */
  21#include <linux/via-core.h>
  22#include <linux/via_i2c.h>
  23#include "global.h"
  24
  25#define viafb_compact_res(x, y) (((x)<<16)|(y))
  26
  27/* CLE266 Software Power Sequence */
  28/* {Mask}, {Data}, {Delay} */
  29static const int PowerSequenceOn[3][3] = {
  30        {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01}
  31};
  32static const int PowerSequenceOff[3][3] = {
  33        {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01}
  34};
  35
  36static struct _lcd_scaling_factor lcd_scaling_factor = {
  37        /* LCD Horizontal Scaling Factor Register */
  38        {LCD_HOR_SCALING_FACTOR_REG_NUM,
  39         {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } },
  40        /* LCD Vertical Scaling Factor Register */
  41        {LCD_VER_SCALING_FACTOR_REG_NUM,
  42         {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } }
  43};
  44static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
  45        /* LCD Horizontal Scaling Factor Register */
  46        {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } },
  47        /* LCD Vertical Scaling Factor Register */
  48        {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } }
  49};
  50
  51static bool lvds_identify_integratedlvds(void);
  52static void fp_id_to_vindex(int panel_id);
  53static int lvds_register_read(int index);
  54static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
  55                      int panel_vres);
  56static void lcd_patch_skew_dvp0(struct lvds_setting_information
  57                         *plvds_setting_info,
  58                         struct lvds_chip_information *plvds_chip_info);
  59static void lcd_patch_skew_dvp1(struct lvds_setting_information
  60                         *plvds_setting_info,
  61                         struct lvds_chip_information *plvds_chip_info);
  62static void lcd_patch_skew(struct lvds_setting_information
  63        *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
  64
  65static void integrated_lvds_disable(struct lvds_setting_information
  66                             *plvds_setting_info,
  67                             struct lvds_chip_information *plvds_chip_info);
  68static void integrated_lvds_enable(struct lvds_setting_information
  69                            *plvds_setting_info,
  70                            struct lvds_chip_information *plvds_chip_info);
  71static void lcd_powersequence_off(void);
  72static void lcd_powersequence_on(void);
  73static void fill_lcd_format(void);
  74static void check_diport_of_integrated_lvds(
  75        struct lvds_chip_information *plvds_chip_info,
  76                                     struct lvds_setting_information
  77                                     *plvds_setting_info);
  78
  79static inline bool check_lvds_chip(int device_id_subaddr, int device_id)
  80{
  81        return lvds_register_read(device_id_subaddr) == device_id;
  82}
  83
  84void viafb_init_lcd_size(void)
  85{
  86        DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
  87
  88        fp_id_to_vindex(viafb_lcd_panel_id);
  89        viaparinfo->lvds_setting_info2->lcd_panel_hres =
  90                viaparinfo->lvds_setting_info->lcd_panel_hres;
  91        viaparinfo->lvds_setting_info2->lcd_panel_vres =
  92                viaparinfo->lvds_setting_info->lcd_panel_vres;
  93        viaparinfo->lvds_setting_info2->device_lcd_dualedge =
  94            viaparinfo->lvds_setting_info->device_lcd_dualedge;
  95        viaparinfo->lvds_setting_info2->LCDDithering =
  96                viaparinfo->lvds_setting_info->LCDDithering;
  97}
  98
  99static bool lvds_identify_integratedlvds(void)
 100{
 101        if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) {
 102                /* Two dual channel LCD (Internal LVDS + External LVDS): */
 103                /* If we have an external LVDS, such as VT1636, we should
 104                   have its chip ID already. */
 105                if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
 106                        viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
 107                            INTEGRATED_LVDS;
 108                        DEBUG_MSG(KERN_INFO "Support two dual channel LVDS! "
 109                                  "(Internal LVDS + External LVDS)\n");
 110                } else {
 111                        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
 112                            INTEGRATED_LVDS;
 113                        DEBUG_MSG(KERN_INFO "Not found external LVDS, "
 114                                  "so can't support two dual channel LVDS!\n");
 115                }
 116        } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
 117                /* Two single channel LCD (Internal LVDS + Internal LVDS): */
 118                viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
 119                INTEGRATED_LVDS;
 120                viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
 121                        INTEGRATED_LVDS;
 122                DEBUG_MSG(KERN_INFO "Support two single channel LVDS! "
 123                          "(Internal LVDS + Internal LVDS)\n");
 124        } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
 125                /* If we have found external LVDS, just use it,
 126                   otherwise, we will use internal LVDS as default. */
 127                if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
 128                        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
 129                            INTEGRATED_LVDS;
 130                        DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n");
 131                }
 132        } else {
 133                viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
 134                        NON_LVDS_TRANSMITTER;
 135                DEBUG_MSG(KERN_INFO "Do not support LVDS!\n");
 136                return false;
 137        }
 138
 139        return true;
 140}
 141
 142bool viafb_lvds_trasmitter_identify(void)
 143{
 144        if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
 145                viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
 146                DEBUG_MSG(KERN_INFO
 147                          "Found VIA VT1636 LVDS on port i2c 0x31\n");
 148        } else {
 149                if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
 150                        viaparinfo->chip_info->lvds_chip_info.i2c_port =
 151                                VIA_PORT_2C;
 152                        DEBUG_MSG(KERN_INFO
 153                                  "Found VIA VT1636 LVDS on port gpio 0x2c\n");
 154                }
 155        }
 156
 157        if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
 158                lvds_identify_integratedlvds();
 159
 160        if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
 161                return true;
 162        /* Check for VT1631: */
 163        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS;
 164        viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
 165                VT1631_LVDS_I2C_ADDR;
 166
 167        if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID)) {
 168                DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n");
 169                DEBUG_MSG(KERN_INFO "\n %2d",
 170                          viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
 171                DEBUG_MSG(KERN_INFO "\n %2d",
 172                          viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
 173                return true;
 174        }
 175
 176        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
 177                NON_LVDS_TRANSMITTER;
 178        viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
 179                VT1631_LVDS_I2C_ADDR;
 180        return false;
 181}
 182
 183static void fp_id_to_vindex(int panel_id)
 184{
 185        DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
 186
 187        if (panel_id > LCD_PANEL_ID_MAXIMUM)
 188                viafb_lcd_panel_id = panel_id =
 189                viafb_read_reg(VIACR, CR3F) & 0x0F;
 190
 191        switch (panel_id) {
 192        case 0x0:
 193                viaparinfo->lvds_setting_info->lcd_panel_hres = 640;
 194                viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
 195                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 196                viaparinfo->lvds_setting_info->LCDDithering = 1;
 197                break;
 198        case 0x1:
 199                viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
 200                viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
 201                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 202                viaparinfo->lvds_setting_info->LCDDithering = 1;
 203                break;
 204        case 0x2:
 205                viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
 206                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 207                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 208                viaparinfo->lvds_setting_info->LCDDithering = 1;
 209                break;
 210        case 0x3:
 211                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 212                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 213                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 214                viaparinfo->lvds_setting_info->LCDDithering = 1;
 215                break;
 216        case 0x4:
 217                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 218                viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
 219                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 220                viaparinfo->lvds_setting_info->LCDDithering = 1;
 221                break;
 222        case 0x5:
 223                viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
 224                viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
 225                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 226                viaparinfo->lvds_setting_info->LCDDithering = 1;
 227                break;
 228        case 0x6:
 229                viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
 230                viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
 231                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 232                viaparinfo->lvds_setting_info->LCDDithering = 1;
 233                break;
 234        case 0x8:
 235                viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
 236                viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
 237                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 238                viaparinfo->lvds_setting_info->LCDDithering = 1;
 239                break;
 240        case 0x9:
 241                viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
 242                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 243                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 244                viaparinfo->lvds_setting_info->LCDDithering = 1;
 245                break;
 246        case 0xA:
 247                viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
 248                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 249                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 250                viaparinfo->lvds_setting_info->LCDDithering = 0;
 251                break;
 252        case 0xB:
 253                viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
 254                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 255                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 256                viaparinfo->lvds_setting_info->LCDDithering = 0;
 257                break;
 258        case 0xC:
 259                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 260                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 261                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 262                viaparinfo->lvds_setting_info->LCDDithering = 0;
 263                break;
 264        case 0xD:
 265                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 266                viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
 267                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 268                viaparinfo->lvds_setting_info->LCDDithering = 0;
 269                break;
 270        case 0xE:
 271                viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
 272                viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
 273                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 274                viaparinfo->lvds_setting_info->LCDDithering = 0;
 275                break;
 276        case 0xF:
 277                viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
 278                viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
 279                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 280                viaparinfo->lvds_setting_info->LCDDithering = 0;
 281                break;
 282        case 0x10:
 283                viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
 284                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 285                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 286                viaparinfo->lvds_setting_info->LCDDithering = 0;
 287                break;
 288        case 0x11:
 289                viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
 290                viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
 291                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 292                viaparinfo->lvds_setting_info->LCDDithering = 1;
 293                break;
 294        case 0x12:
 295                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 296                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 297                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 298                viaparinfo->lvds_setting_info->LCDDithering = 1;
 299                break;
 300        case 0x13:
 301                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 302                viaparinfo->lvds_setting_info->lcd_panel_vres = 800;
 303                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 304                viaparinfo->lvds_setting_info->LCDDithering = 1;
 305                break;
 306        case 0x14:
 307                viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
 308                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 309                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 310                viaparinfo->lvds_setting_info->LCDDithering = 0;
 311                break;
 312        case 0x15:
 313                viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
 314                viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
 315                viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
 316                viaparinfo->lvds_setting_info->LCDDithering = 0;
 317                break;
 318        case 0x16:
 319                viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
 320                viaparinfo->lvds_setting_info->lcd_panel_vres = 640;
 321                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 322                viaparinfo->lvds_setting_info->LCDDithering = 1;
 323                break;
 324        case 0x17:
 325                /* OLPC XO-1.5 panel */
 326                viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
 327                viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
 328                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 329                viaparinfo->lvds_setting_info->LCDDithering = 0;
 330                break;
 331        default:
 332                viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
 333                viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
 334                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
 335                viaparinfo->lvds_setting_info->LCDDithering = 1;
 336        }
 337}
 338
 339static int lvds_register_read(int index)
 340{
 341        u8 data;
 342
 343        viafb_i2c_readbyte(VIA_PORT_2C,
 344                        (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
 345                        (u8) index, &data);
 346        return data;
 347}
 348
 349static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
 350                      int panel_vres)
 351{
 352        int reg_value = 0;
 353        int viafb_load_reg_num;
 354        struct io_register *reg = NULL;
 355
 356        DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n");
 357
 358        /* LCD Scaling Enable */
 359        viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
 360
 361        /* Check if expansion for horizontal */
 362        if (set_hres < panel_hres) {
 363                /* Load Horizontal Scaling Factor */
 364                switch (viaparinfo->chip_info->gfx_chip_name) {
 365                case UNICHROME_CLE266:
 366                case UNICHROME_K400:
 367                        reg_value =
 368                            CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
 369                        viafb_load_reg_num =
 370                            lcd_scaling_factor_CLE.lcd_hor_scaling_factor.
 371                            reg_num;
 372                        reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg;
 373                        viafb_load_reg(reg_value,
 374                                viafb_load_reg_num, reg, VIACR);
 375                        break;
 376                case UNICHROME_K800:
 377                case UNICHROME_PM800:
 378                case UNICHROME_CN700:
 379                case UNICHROME_CX700:
 380                case UNICHROME_K8M890:
 381                case UNICHROME_P4M890:
 382                case UNICHROME_P4M900:
 383                case UNICHROME_CN750:
 384                case UNICHROME_VX800:
 385                case UNICHROME_VX855:
 386                case UNICHROME_VX900:
 387                        reg_value =
 388                            K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
 389                        /* Horizontal scaling enabled */
 390                        viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6);
 391                        viafb_load_reg_num =
 392                            lcd_scaling_factor.lcd_hor_scaling_factor.reg_num;
 393                        reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg;
 394                        viafb_load_reg(reg_value,
 395                                viafb_load_reg_num, reg, VIACR);
 396                        break;
 397                }
 398
 399                DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value);
 400        } else {
 401                /* Horizontal scaling disabled */
 402                viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7);
 403        }
 404
 405        /* Check if expansion for vertical */
 406        if (set_vres < panel_vres) {
 407                /* Load Vertical Scaling Factor */
 408                switch (viaparinfo->chip_info->gfx_chip_name) {
 409                case UNICHROME_CLE266:
 410                case UNICHROME_K400:
 411                        reg_value =
 412                            CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
 413                        viafb_load_reg_num =
 414                            lcd_scaling_factor_CLE.lcd_ver_scaling_factor.
 415                            reg_num;
 416                        reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg;
 417                        viafb_load_reg(reg_value,
 418                                viafb_load_reg_num, reg, VIACR);
 419                        break;
 420                case UNICHROME_K800:
 421                case UNICHROME_PM800:
 422                case UNICHROME_CN700:
 423                case UNICHROME_CX700:
 424                case UNICHROME_K8M890:
 425                case UNICHROME_P4M890:
 426                case UNICHROME_P4M900:
 427                case UNICHROME_CN750:
 428                case UNICHROME_VX800:
 429                case UNICHROME_VX855:
 430                case UNICHROME_VX900:
 431                        reg_value =
 432                            K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
 433                        /* Vertical scaling enabled */
 434                        viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3);
 435                        viafb_load_reg_num =
 436                            lcd_scaling_factor.lcd_ver_scaling_factor.reg_num;
 437                        reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg;
 438                        viafb_load_reg(reg_value,
 439                                viafb_load_reg_num, reg, VIACR);
 440                        break;
 441                }
 442
 443                DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value);
 444        } else {
 445                /* Vertical scaling disabled */
 446                viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3);
 447        }
 448}
 449
 450static void via_pitch_alignment_patch_lcd(int iga_path, int hres, int bpp)
 451{
 452        unsigned char cr13, cr35, cr65, cr66, cr67;
 453        unsigned long dwScreenPitch = 0;
 454        unsigned long dwPitch;
 455
 456        dwPitch = hres * (bpp >> 3);
 457        if (dwPitch & 0x1F) {
 458                dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
 459                if (iga_path == IGA2) {
 460                        if (bpp > 8) {
 461                                cr66 = (unsigned char)(dwScreenPitch & 0xFF);
 462                                viafb_write_reg(CR66, VIACR, cr66);
 463                                cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
 464                                cr67 |=
 465                                    (unsigned
 466                                     char)((dwScreenPitch & 0x300) >> 8);
 467                                viafb_write_reg(CR67, VIACR, cr67);
 468                        }
 469
 470                        /* Fetch Count */
 471                        cr67 = viafb_read_reg(VIACR, CR67) & 0xF3;
 472                        cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7);
 473                        viafb_write_reg(CR67, VIACR, cr67);
 474                        cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF);
 475                        cr65 += 2;
 476                        viafb_write_reg(CR65, VIACR, cr65);
 477                } else {
 478                        if (bpp > 8) {
 479                                cr13 = (unsigned char)(dwScreenPitch & 0xFF);
 480                                viafb_write_reg(CR13, VIACR, cr13);
 481                                cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
 482                                cr35 |=
 483                                    (unsigned
 484                                     char)((dwScreenPitch & 0x700) >> 3);
 485                                viafb_write_reg(CR35, VIACR, cr35);
 486                        }
 487                }
 488        }
 489}
 490static void lcd_patch_skew_dvp0(struct lvds_setting_information
 491                         *plvds_setting_info,
 492                         struct lvds_chip_information *plvds_chip_info)
 493{
 494        if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
 495                switch (viaparinfo->chip_info->gfx_chip_name) {
 496                case UNICHROME_P4M900:
 497                        viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info,
 498                                                    plvds_chip_info);
 499                        break;
 500                case UNICHROME_P4M890:
 501                        viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info,
 502                                                    plvds_chip_info);
 503                        break;
 504                }
 505        }
 506}
 507static void lcd_patch_skew_dvp1(struct lvds_setting_information
 508                         *plvds_setting_info,
 509                         struct lvds_chip_information *plvds_chip_info)
 510{
 511        if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
 512                switch (viaparinfo->chip_info->gfx_chip_name) {
 513                case UNICHROME_CX700:
 514                        viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info,
 515                                                    plvds_chip_info);
 516                        break;
 517                }
 518        }
 519}
 520static void lcd_patch_skew(struct lvds_setting_information
 521        *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
 522{
 523        DEBUG_MSG(KERN_INFO "lcd_patch_skew\n");
 524        switch (plvds_chip_info->output_interface) {
 525        case INTERFACE_DVP0:
 526                lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info);
 527                break;
 528        case INTERFACE_DVP1:
 529                lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info);
 530                break;
 531        case INTERFACE_DFP_LOW:
 532                if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
 533                        viafb_write_reg_mask(CR99, VIACR, 0x08,
 534                                       BIT0 + BIT1 + BIT2 + BIT3);
 535                }
 536                break;
 537        }
 538}
 539
 540/* LCD Set Mode */
 541void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
 542        u16 cyres, struct lvds_setting_information *plvds_setting_info,
 543        struct lvds_chip_information *plvds_chip_info)
 544{
 545        int set_iga = plvds_setting_info->iga_path;
 546        int mode_bpp = var->bits_per_pixel;
 547        int set_hres = cxres ? cxres : var->xres;
 548        int set_vres = cyres ? cyres : var->yres;
 549        int panel_hres = plvds_setting_info->lcd_panel_hres;
 550        int panel_vres = plvds_setting_info->lcd_panel_vres;
 551        u32 clock;
 552        struct via_display_timing timing;
 553        struct fb_var_screeninfo panel_var;
 554        const struct fb_videomode *mode_crt_table, *panel_crt_table;
 555
 556        DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
 557        /* Get mode table */
 558        mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60);
 559        /* Get panel table Pointer */
 560        panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
 561        viafb_fill_var_timing_info(&panel_var, panel_crt_table);
 562        DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
 563        if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
 564                viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
 565        clock = PICOS2KHZ(panel_crt_table->pixclock) * 1000;
 566        plvds_setting_info->vclk = clock;
 567
 568        if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
 569                && plvds_setting_info->display_method == LCD_EXPANDSION) {
 570                timing = var_to_timing(&panel_var, panel_hres, panel_vres);
 571                load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
 572        } else {
 573                timing = var_to_timing(&panel_var, set_hres, set_vres);
 574                if (set_iga == IGA2)
 575                        /* disable scaling */
 576                        via_write_reg_mask(VIACR, 0x79, 0x00,
 577                                BIT0 + BIT1 + BIT2);
 578        }
 579
 580        if (set_iga == IGA1)
 581                via_set_primary_timing(&timing);
 582        else if (set_iga == IGA2)
 583                via_set_secondary_timing(&timing);
 584
 585        /* Fetch count for IGA2 only */
 586        viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
 587
 588        if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
 589                && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
 590                viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
 591
 592        fill_lcd_format();
 593        viafb_set_vclock(clock, set_iga);
 594        lcd_patch_skew(plvds_setting_info, plvds_chip_info);
 595
 596        /* If K8M800, enable LCD Prefetch Mode. */
 597        if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
 598            || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
 599                viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
 600
 601        /* Patch for non 32bit alignment mode */
 602        via_pitch_alignment_patch_lcd(plvds_setting_info->iga_path, set_hres,
 603                var->bits_per_pixel);
 604}
 605
 606static void integrated_lvds_disable(struct lvds_setting_information
 607                             *plvds_setting_info,
 608                             struct lvds_chip_information *plvds_chip_info)
 609{
 610        bool turn_off_first_powersequence = false;
 611        bool turn_off_second_powersequence = false;
 612        if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
 613                turn_off_first_powersequence = true;
 614        if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
 615                turn_off_first_powersequence = true;
 616        if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
 617                turn_off_second_powersequence = true;
 618        if (turn_off_second_powersequence) {
 619                /* Use second power sequence control: */
 620
 621                /* Turn off power sequence. */
 622                viafb_write_reg_mask(CRD4, VIACR, 0, BIT1);
 623
 624                /* Turn off back light. */
 625                viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7);
 626        }
 627        if (turn_off_first_powersequence) {
 628                /* Use first power sequence control: */
 629
 630                /* Turn off power sequence. */
 631                viafb_write_reg_mask(CR6A, VIACR, 0, BIT3);
 632
 633                /* Turn off back light. */
 634                viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
 635        }
 636
 637        /* Power off LVDS channel. */
 638        switch (plvds_chip_info->output_interface) {
 639        case INTERFACE_LVDS0:
 640                {
 641                        viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7);
 642                        break;
 643                }
 644
 645        case INTERFACE_LVDS1:
 646                {
 647                        viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6);
 648                        break;
 649                }
 650
 651        case INTERFACE_LVDS0LVDS1:
 652                {
 653                        viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7);
 654                        break;
 655                }
 656        }
 657}
 658
 659static void integrated_lvds_enable(struct lvds_setting_information
 660                            *plvds_setting_info,
 661                            struct lvds_chip_information *plvds_chip_info)
 662{
 663        DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
 664                  plvds_chip_info->output_interface);
 665        if (plvds_setting_info->lcd_mode == LCD_SPWG)
 666                viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
 667        else
 668                viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
 669
 670        switch (plvds_chip_info->output_interface) {
 671        case INTERFACE_LVDS0LVDS1:
 672        case INTERFACE_LVDS0:
 673                /* Use first power sequence control: */
 674                /* Use hardware control power sequence. */
 675                viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
 676                /* Turn on back light. */
 677                viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
 678                /* Turn on hardware power sequence. */
 679                viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
 680                break;
 681        case INTERFACE_LVDS1:
 682                /* Use second power sequence control: */
 683                /* Use hardware control power sequence. */
 684                viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
 685                /* Turn on back light. */
 686                viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
 687                /* Turn on hardware power sequence. */
 688                viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
 689                break;
 690        }
 691
 692        /* Power on LVDS channel. */
 693        switch (plvds_chip_info->output_interface) {
 694        case INTERFACE_LVDS0:
 695                {
 696                        viafb_write_reg_mask(CRD2, VIACR, 0, BIT7);
 697                        break;
 698                }
 699
 700        case INTERFACE_LVDS1:
 701                {
 702                        viafb_write_reg_mask(CRD2, VIACR, 0, BIT6);
 703                        break;
 704                }
 705
 706        case INTERFACE_LVDS0LVDS1:
 707                {
 708                        viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7);
 709                        break;
 710                }
 711        }
 712}
 713
 714void viafb_lcd_disable(void)
 715{
 716
 717        if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
 718                lcd_powersequence_off();
 719                /* DI1 pad off */
 720                viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
 721        } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
 722                if (viafb_LCD2_ON
 723                    && (INTEGRATED_LVDS ==
 724                        viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
 725                        integrated_lvds_disable(viaparinfo->lvds_setting_info,
 726                                &viaparinfo->chip_info->lvds_chip_info2);
 727                if (INTEGRATED_LVDS ==
 728                        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
 729                        integrated_lvds_disable(viaparinfo->lvds_setting_info,
 730                                &viaparinfo->chip_info->lvds_chip_info);
 731                if (VT1636_LVDS == viaparinfo->chip_info->
 732                        lvds_chip_info.lvds_chip_name)
 733                        viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
 734                                &viaparinfo->chip_info->lvds_chip_info);
 735        } else if (VT1636_LVDS ==
 736        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
 737                viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
 738                                    &viaparinfo->chip_info->lvds_chip_info);
 739        } else {
 740                /* Backlight off           */
 741                viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
 742                /* 24 bit DI data paht off */
 743                viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
 744        }
 745
 746        /* Disable expansion bit   */
 747        viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
 748        /* Simultaneout disabled   */
 749        viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
 750}
 751
 752static void set_lcd_output_path(int set_iga, int output_interface)
 753{
 754        switch (output_interface) {
 755        case INTERFACE_DFP:
 756                if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
 757                    || (UNICHROME_P4M890 ==
 758                    viaparinfo->chip_info->gfx_chip_name))
 759                        viafb_write_reg_mask(CR97, VIACR, 0x84,
 760                                       BIT7 + BIT2 + BIT1 + BIT0);
 761        case INTERFACE_DVP0:
 762        case INTERFACE_DVP1:
 763        case INTERFACE_DFP_HIGH:
 764        case INTERFACE_DFP_LOW:
 765                if (set_iga == IGA2)
 766                        viafb_write_reg(CR91, VIACR, 0x00);
 767                break;
 768        }
 769}
 770
 771void viafb_lcd_enable(void)
 772{
 773        viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
 774        viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
 775        set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path,
 776                viaparinfo->chip_info->lvds_chip_info.output_interface);
 777        if (viafb_LCD2_ON)
 778                set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path,
 779                        viaparinfo->chip_info->
 780                        lvds_chip_info2.output_interface);
 781
 782        if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
 783                /* DI1 pad on */
 784                viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
 785                lcd_powersequence_on();
 786        } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
 787                if (viafb_LCD2_ON && (INTEGRATED_LVDS ==
 788                        viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
 789                        integrated_lvds_enable(viaparinfo->lvds_setting_info2, \
 790                                &viaparinfo->chip_info->lvds_chip_info2);
 791                if (INTEGRATED_LVDS ==
 792                        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
 793                        integrated_lvds_enable(viaparinfo->lvds_setting_info,
 794                                &viaparinfo->chip_info->lvds_chip_info);
 795                if (VT1636_LVDS == viaparinfo->chip_info->
 796                        lvds_chip_info.lvds_chip_name)
 797                        viafb_enable_lvds_vt1636(viaparinfo->
 798                        lvds_setting_info, &viaparinfo->chip_info->
 799                        lvds_chip_info);
 800        } else if (VT1636_LVDS ==
 801        viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
 802                viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
 803                                   &viaparinfo->chip_info->lvds_chip_info);
 804        } else {
 805                /* Backlight on            */
 806                viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
 807                /* 24 bit DI data paht on  */
 808                viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
 809                /* LCD enabled             */
 810                viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
 811        }
 812}
 813
 814static void lcd_powersequence_off(void)
 815{
 816        int i, mask, data;
 817
 818        /* Software control power sequence */
 819        viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
 820
 821        for (i = 0; i < 3; i++) {
 822                mask = PowerSequenceOff[0][i];
 823                data = PowerSequenceOff[1][i] & mask;
 824                viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
 825                udelay(PowerSequenceOff[2][i]);
 826        }
 827
 828        /* Disable LCD */
 829        viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08);
 830}
 831
 832static void lcd_powersequence_on(void)
 833{
 834        int i, mask, data;
 835
 836        /* Software control power sequence */
 837        viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
 838
 839        /* Enable LCD */
 840        viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08);
 841
 842        for (i = 0; i < 3; i++) {
 843                mask = PowerSequenceOn[0][i];
 844                data = PowerSequenceOn[1][i] & mask;
 845                viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
 846                udelay(PowerSequenceOn[2][i]);
 847        }
 848
 849        udelay(1);
 850}
 851
 852static void fill_lcd_format(void)
 853{
 854        u8 bdithering = 0, bdual = 0;
 855
 856        if (viaparinfo->lvds_setting_info->device_lcd_dualedge)
 857                bdual = BIT4;
 858        if (viaparinfo->lvds_setting_info->LCDDithering)
 859                bdithering = BIT0;
 860        /* Dual & Dithering */
 861        viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0);
 862}
 863
 864static void check_diport_of_integrated_lvds(
 865        struct lvds_chip_information *plvds_chip_info,
 866                                     struct lvds_setting_information
 867                                     *plvds_setting_info)
 868{
 869        /* Determine LCD DI Port by hardware layout. */
 870        switch (viafb_display_hardware_layout) {
 871        case HW_LAYOUT_LCD_ONLY:
 872                {
 873                        if (plvds_setting_info->device_lcd_dualedge) {
 874                                plvds_chip_info->output_interface =
 875                                    INTERFACE_LVDS0LVDS1;
 876                        } else {
 877                                plvds_chip_info->output_interface =
 878                                    INTERFACE_LVDS0;
 879                        }
 880
 881                        break;
 882                }
 883
 884        case HW_LAYOUT_DVI_ONLY:
 885                {
 886                        plvds_chip_info->output_interface = INTERFACE_NONE;
 887                        break;
 888                }
 889
 890        case HW_LAYOUT_LCD1_LCD2:
 891        case HW_LAYOUT_LCD_EXTERNAL_LCD2:
 892                {
 893                        plvds_chip_info->output_interface =
 894                            INTERFACE_LVDS0LVDS1;
 895                        break;
 896                }
 897
 898        case HW_LAYOUT_LCD_DVI:
 899                {
 900                        plvds_chip_info->output_interface = INTERFACE_LVDS1;
 901                        break;
 902                }
 903
 904        default:
 905                {
 906                        plvds_chip_info->output_interface = INTERFACE_LVDS1;
 907                        break;
 908                }
 909        }
 910
 911        DEBUG_MSG(KERN_INFO
 912                  "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n",
 913                  viafb_display_hardware_layout,
 914                  plvds_chip_info->output_interface);
 915}
 916
 917void viafb_init_lvds_output_interface(struct lvds_chip_information
 918                                *plvds_chip_info,
 919                                struct lvds_setting_information
 920                                *plvds_setting_info)
 921{
 922        if (INTERFACE_NONE != plvds_chip_info->output_interface) {
 923                /*Do nothing, lcd port is specified by module parameter */
 924                return;
 925        }
 926
 927        switch (plvds_chip_info->lvds_chip_name) {
 928
 929        case VT1636_LVDS:
 930                switch (viaparinfo->chip_info->gfx_chip_name) {
 931                case UNICHROME_CX700:
 932                        plvds_chip_info->output_interface = INTERFACE_DVP1;
 933                        break;
 934                case UNICHROME_CN700:
 935                        plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
 936                        break;
 937                default:
 938                        plvds_chip_info->output_interface = INTERFACE_DVP0;
 939                        break;
 940                }
 941                break;
 942
 943        case INTEGRATED_LVDS:
 944                check_diport_of_integrated_lvds(plvds_chip_info,
 945                                                plvds_setting_info);
 946                break;
 947
 948        default:
 949                switch (viaparinfo->chip_info->gfx_chip_name) {
 950                case UNICHROME_K8M890:
 951                case UNICHROME_P4M900:
 952                case UNICHROME_P4M890:
 953                        plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
 954                        break;
 955                default:
 956                        plvds_chip_info->output_interface = INTERFACE_DFP;
 957                        break;
 958                }
 959                break;
 960        }
 961}
 962
 963bool viafb_lcd_get_mobile_state(bool *mobile)
 964{
 965        unsigned char __iomem *romptr, *tableptr, *biosptr;
 966        u8 core_base;
 967        /* Rom address */
 968        const u32 romaddr = 0x000C0000;
 969        u16 start_pattern;
 970
 971        biosptr = ioremap(romaddr, 0x10000);
 972        start_pattern = readw(biosptr);
 973
 974        /* Compare pattern */
 975        if (start_pattern == 0xAA55) {
 976                /* Get the start of Table */
 977                /* 0x1B means BIOS offset position */
 978                romptr = biosptr + 0x1B;
 979                tableptr = biosptr + readw(romptr);
 980
 981                /* Get the start of biosver structure */
 982                /* 18 means BIOS version position. */
 983                romptr = tableptr + 18;
 984                romptr = biosptr + readw(romptr);
 985
 986                /* The offset should be 44, but the
 987                   actual image is less three char. */
 988                /* pRom += 44; */
 989                romptr += 41;
 990
 991                core_base = readb(romptr);
 992
 993                if (core_base & 0x8)
 994                        *mobile = false;
 995                else
 996                        *mobile = true;
 997                /* release memory */
 998                iounmap(biosptr);
 999
1000                return true;
1001        } else {
1002                iounmap(biosptr);
1003                return false;
1004        }
1005}
1006