162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SiS 300/540/630[S]/730[S]
462306a36Sopenharmony_ci * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX]
562306a36Sopenharmony_ci * XGI V3XT/V5/V8, Z7
662306a36Sopenharmony_ci * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Linux kernel specific extensions to init.c/init301.c
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Author:	Thomas Winischhofer <thomas@winischhofer.net>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "initdef.h"
1662306a36Sopenharmony_ci#include "vgatypes.h"
1762306a36Sopenharmony_ci#include "vstruct.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/types.h>
2062306a36Sopenharmony_ci#include <linux/fb.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciint		sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
2362306a36Sopenharmony_ci			unsigned char modeno, unsigned char rateindex);
2462306a36Sopenharmony_ciint		sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
2562306a36Sopenharmony_ci			unsigned char rateindex, struct fb_var_screeninfo *var);
2662306a36Sopenharmony_cibool		sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
2762306a36Sopenharmony_ci			int *htotal, int *vtotal, unsigned char rateindex);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciextern bool	SiSInitPtr(struct SiS_Private *SiS_Pr);
3062306a36Sopenharmony_ciextern bool	SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
3162306a36Sopenharmony_ci			unsigned short *ModeIdIndex);
3262306a36Sopenharmony_ciextern void	SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
3362306a36Sopenharmony_ci			int xres, int yres, struct fb_var_screeninfo *var, bool writeres);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint
3662306a36Sopenharmony_cisisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
3762306a36Sopenharmony_ci			unsigned char rateindex)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci    unsigned short ModeNo = modeno;
4062306a36Sopenharmony_ci    unsigned short ModeIdIndex = 0, ClockIndex = 0;
4162306a36Sopenharmony_ci    unsigned short RRTI = 0;
4262306a36Sopenharmony_ci    int Clock;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci    if(!SiSInitPtr(SiS_Pr)) return 65000;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci    if(rateindex > 0) rateindex--;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
4962306a36Sopenharmony_ci    switch(ModeNo) {
5062306a36Sopenharmony_ci    case 0x5a: ModeNo = 0x50; break;
5162306a36Sopenharmony_ci    case 0x5b: ModeNo = 0x56;
5262306a36Sopenharmony_ci    }
5362306a36Sopenharmony_ci#endif
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {
5662306a36Sopenharmony_ci       printk(KERN_ERR "Could not find mode %x\n", ModeNo);
5762306a36Sopenharmony_ci       return 65000;
5862306a36Sopenharmony_ci    }
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci    RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
6362306a36Sopenharmony_ci       if(SiS_Pr->SiS_UseWide == 1) {
6462306a36Sopenharmony_ci	  /* Wide screen: Ignore rateindex */
6562306a36Sopenharmony_ci	  ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE;
6662306a36Sopenharmony_ci       } else {
6762306a36Sopenharmony_ci	  RRTI += rateindex;
6862306a36Sopenharmony_ci	  ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM;
6962306a36Sopenharmony_ci       }
7062306a36Sopenharmony_ci    } else {
7162306a36Sopenharmony_ci       RRTI += rateindex;
7262306a36Sopenharmony_ci       ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK;
7362306a36Sopenharmony_ci    }
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci    Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci    return Clock;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciint
8162306a36Sopenharmony_cisisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
8262306a36Sopenharmony_ci			unsigned char rateindex, struct fb_var_screeninfo *var)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci    unsigned short ModeNo = modeno;
8562306a36Sopenharmony_ci    unsigned short ModeIdIndex = 0, index = 0, RRTI = 0;
8662306a36Sopenharmony_ci    int            j;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci    if(!SiSInitPtr(SiS_Pr)) return 0;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci    if(rateindex > 0) rateindex--;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
9362306a36Sopenharmony_ci    switch(ModeNo) {
9462306a36Sopenharmony_ci       case 0x5a: ModeNo = 0x50; break;
9562306a36Sopenharmony_ci       case 0x5b: ModeNo = 0x56;
9662306a36Sopenharmony_ci    }
9762306a36Sopenharmony_ci#endif
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci    RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
10262306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
10362306a36Sopenharmony_ci       if(SiS_Pr->SiS_UseWide == 1) {
10462306a36Sopenharmony_ci	  /* Wide screen: Ignore rateindex */
10562306a36Sopenharmony_ci	  index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE;
10662306a36Sopenharmony_ci       } else {
10762306a36Sopenharmony_ci	  RRTI += rateindex;
10862306a36Sopenharmony_ci	  index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM;
10962306a36Sopenharmony_ci       }
11062306a36Sopenharmony_ci    } else {
11162306a36Sopenharmony_ci       RRTI += rateindex;
11262306a36Sopenharmony_ci       index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC;
11362306a36Sopenharmony_ci    }
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci    SiS_Generic_ConvertCRData(SiS_Pr,
11662306a36Sopenharmony_ci			(unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0],
11762306a36Sopenharmony_ci			SiS_Pr->SiS_RefIndex[RRTI].XRes,
11862306a36Sopenharmony_ci			SiS_Pr->SiS_RefIndex[RRTI].YRes,
11962306a36Sopenharmony_ci			var, false);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000)
12262306a36Sopenharmony_ci       var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
12362306a36Sopenharmony_ci    else
12462306a36Sopenharmony_ci       var->sync |= FB_SYNC_VERT_HIGH_ACT;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000)
12762306a36Sopenharmony_ci       var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
12862306a36Sopenharmony_ci    else
12962306a36Sopenharmony_ci       var->sync |= FB_SYNC_HOR_HIGH_ACT;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci    var->vmode = FB_VMODE_NONINTERLACED;
13262306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080)
13362306a36Sopenharmony_ci       var->vmode = FB_VMODE_INTERLACED;
13462306a36Sopenharmony_ci    else {
13562306a36Sopenharmony_ci       j = 0;
13662306a36Sopenharmony_ci       while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
13762306a36Sopenharmony_ci	  if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
13862306a36Sopenharmony_ci	                  SiS_Pr->SiS_RefIndex[RRTI].ModeID) {
13962306a36Sopenharmony_ci	      if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
14062306a36Sopenharmony_ci	      	  var->vmode = FB_VMODE_DOUBLE;
14162306a36Sopenharmony_ci	      }
14262306a36Sopenharmony_ci	      break;
14362306a36Sopenharmony_ci	  }
14462306a36Sopenharmony_ci	  j++;
14562306a36Sopenharmony_ci       }
14662306a36Sopenharmony_ci    }
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
14962306a36Sopenharmony_ci#if 0  /* Do this? */
15062306a36Sopenharmony_ci       var->upper_margin <<= 1;
15162306a36Sopenharmony_ci       var->lower_margin <<= 1;
15262306a36Sopenharmony_ci       var->vsync_len <<= 1;
15362306a36Sopenharmony_ci#endif
15462306a36Sopenharmony_ci    } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
15562306a36Sopenharmony_ci       var->upper_margin >>= 1;
15662306a36Sopenharmony_ci       var->lower_margin >>= 1;
15762306a36Sopenharmony_ci       var->vsync_len >>= 1;
15862306a36Sopenharmony_ci    }
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci    return 1;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cibool
16462306a36Sopenharmony_cisisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
16562306a36Sopenharmony_ci			int *vtotal, unsigned char rateindex)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci    unsigned short ModeNo = modeno;
16862306a36Sopenharmony_ci    unsigned short ModeIdIndex = 0, CRT1Index = 0;
16962306a36Sopenharmony_ci    unsigned short RRTI = 0;
17062306a36Sopenharmony_ci    unsigned char  sr_data, cr_data, cr_data2;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci    if(!SiSInitPtr(SiS_Pr)) return false;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci    if(rateindex > 0) rateindex--;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
17762306a36Sopenharmony_ci    switch(ModeNo) {
17862306a36Sopenharmony_ci       case 0x5a: ModeNo = 0x50; break;
17962306a36Sopenharmony_ci       case 0x5b: ModeNo = 0x56;
18062306a36Sopenharmony_ci    }
18162306a36Sopenharmony_ci#endif
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci    RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
18662306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
18762306a36Sopenharmony_ci       if(SiS_Pr->SiS_UseWide == 1) {
18862306a36Sopenharmony_ci	  /* Wide screen: Ignore rateindex */
18962306a36Sopenharmony_ci	  CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE;
19062306a36Sopenharmony_ci       } else {
19162306a36Sopenharmony_ci	  RRTI += rateindex;
19262306a36Sopenharmony_ci	  CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM;
19362306a36Sopenharmony_ci       }
19462306a36Sopenharmony_ci    } else {
19562306a36Sopenharmony_ci       RRTI += rateindex;
19662306a36Sopenharmony_ci       CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC;
19762306a36Sopenharmony_ci    }
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci    sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
20062306a36Sopenharmony_ci    cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
20162306a36Sopenharmony_ci    *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci    sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
20462306a36Sopenharmony_ci    cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
20562306a36Sopenharmony_ci    cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
20662306a36Sopenharmony_ci    *vtotal = ((cr_data & 0xFF) |
20762306a36Sopenharmony_ci	       ((unsigned short)(cr_data2 & 0x01) <<  8) |
20862306a36Sopenharmony_ci	       ((unsigned short)(cr_data2 & 0x20) <<  4) |
20962306a36Sopenharmony_ci	       ((unsigned short)(sr_data  & 0x01) << 10)) + 2;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci    if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode)
21262306a36Sopenharmony_ci       *vtotal *= 2;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci    return true;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci
219