0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/fb.h>
0011 #include <linux/delay.h>
0012 #include <asm/io.h>
0013 #include <asm/delay.h>
0014 #include <asm/msr.h>
0015 #include <linux/cs5535.h>
0016
0017 #include "gxfb.h"
0018
0019
0020
0021
0022
0023 struct gx_pll_entry {
0024 long pixclock;
0025 u32 sys_rstpll_bits;
0026 u32 dotpll_value;
0027 };
0028
0029 #define POSTDIV3 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
0030 #define PREMULT2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPREMULT2)
0031 #define PREDIV2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
0032
0033 static const struct gx_pll_entry gx_pll_table_48MHz[] = {
0034 { 40123, POSTDIV3, 0x00000BF2 },
0035 { 39721, 0, 0x00000037 },
0036 { 35308, POSTDIV3|PREMULT2, 0x00000B1A },
0037 { 31746, POSTDIV3, 0x000002D2 },
0038 { 27777, POSTDIV3|PREMULT2, 0x00000FE2 },
0039 { 26666, POSTDIV3, 0x0000057A },
0040 { 25000, POSTDIV3, 0x0000030A },
0041 { 22271, 0, 0x00000063 },
0042 { 20202, 0, 0x0000054B },
0043 { 20000, 0, 0x0000026E },
0044 { 19860, PREMULT2, 0x00000037 },
0045 { 18518, POSTDIV3|PREMULT2, 0x00000B0D },
0046 { 17777, 0, 0x00000577 },
0047 { 17733, 0, 0x000007F7 },
0048 { 17653, 0, 0x0000057B },
0049 { 16949, PREMULT2, 0x00000707 },
0050 { 15873, POSTDIV3|PREMULT2, 0x00000B39 },
0051 { 15384, POSTDIV3|PREMULT2, 0x00000B45 },
0052 { 14814, POSTDIV3|PREMULT2, 0x00000FC1 },
0053 { 14124, POSTDIV3, 0x00000561 },
0054 { 13888, POSTDIV3, 0x000007E1 },
0055 { 13426, PREMULT2, 0x00000F4A },
0056 { 13333, 0, 0x00000052 },
0057 { 12698, 0, 0x00000056 },
0058 { 12500, POSTDIV3|PREMULT2, 0x00000709 },
0059 { 11135, PREMULT2, 0x00000262 },
0060 { 10582, 0, 0x000002D2 },
0061 { 10101, PREMULT2, 0x00000B4A },
0062 { 10000, PREMULT2, 0x00000036 },
0063 { 9259, 0, 0x000007E2 },
0064 { 8888, 0, 0x000007F6 },
0065 { 7692, POSTDIV3|PREMULT2, 0x00000FB0 },
0066 { 7407, POSTDIV3|PREMULT2, 0x00000B50 },
0067 { 6349, 0, 0x00000055 },
0068 { 6172, 0, 0x000009C1 },
0069 { 5787, PREMULT2, 0x0000002D },
0070 { 5698, 0, 0x000002C1 },
0071 { 5291, 0, 0x000002D1 },
0072 { 4938, 0, 0x00000551 },
0073 { 4357, 0, 0x0000057D },
0074 };
0075
0076 static const struct gx_pll_entry gx_pll_table_14MHz[] = {
0077 { 39721, 0, 0x00000037 },
0078 { 35308, 0, 0x00000B7B },
0079 { 31746, 0, 0x000004D3 },
0080 { 27777, 0, 0x00000BE3 },
0081 { 26666, 0, 0x0000074F },
0082 { 25000, 0, 0x0000050B },
0083 { 22271, 0, 0x00000063 },
0084 { 20202, 0, 0x0000054B },
0085 { 20000, 0, 0x0000026E },
0086 { 19860, 0, 0x000007C3 },
0087 { 18518, 0, 0x000007E3 },
0088 { 17777, 0, 0x00000577 },
0089 { 17733, 0, 0x000002FB },
0090 { 17653, 0, 0x0000057B },
0091 { 16949, 0, 0x0000058B },
0092 { 15873, 0, 0x0000095E },
0093 { 15384, 0, 0x0000096A },
0094 { 14814, 0, 0x00000BC2 },
0095 { 14124, 0, 0x0000098A },
0096 { 13888, 0, 0x00000BE2 },
0097 { 13333, 0, 0x00000052 },
0098 { 12698, 0, 0x00000056 },
0099 { 12500, 0, 0x0000050A },
0100 { 11135, 0, 0x0000078E },
0101 { 10582, 0, 0x000002D2 },
0102 { 10101, 0, 0x000011F6 },
0103 { 10000, 0, 0x0000054E },
0104 { 9259, 0, 0x000007E2 },
0105 { 8888, 0, 0x000002FA },
0106 { 7692, 0, 0x00000BB1 },
0107 { 7407, 0, 0x00000975 },
0108 { 6349, 0, 0x00000055 },
0109 { 6172, 0, 0x000009C1 },
0110 { 5698, 0, 0x000002C1 },
0111 { 5291, 0, 0x00000539 },
0112 { 4938, 0, 0x00000551 },
0113 { 4357, 0, 0x0000057D },
0114 };
0115
0116 void gx_set_dclk_frequency(struct fb_info *info)
0117 {
0118 const struct gx_pll_entry *pll_table;
0119 int pll_table_len;
0120 int i, best_i;
0121 long min, diff;
0122 u64 dotpll, sys_rstpll;
0123 int timeout = 1000;
0124
0125
0126 if (cpu_data(0).x86_stepping == 1) {
0127 pll_table = gx_pll_table_14MHz;
0128 pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
0129 } else {
0130 pll_table = gx_pll_table_48MHz;
0131 pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
0132 }
0133
0134
0135 best_i = 0;
0136 min = abs(pll_table[0].pixclock - info->var.pixclock);
0137 for (i = 1; i < pll_table_len; i++) {
0138 diff = abs(pll_table[i].pixclock - info->var.pixclock);
0139 if (diff < min) {
0140 min = diff;
0141 best_i = i;
0142 }
0143 }
0144
0145 rdmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
0146 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
0147
0148
0149 dotpll &= 0x00000000ffffffffull;
0150 dotpll |= (u64)pll_table[best_i].dotpll_value << 32;
0151 dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
0152 dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
0153
0154 wrmsrl(MSR_GLCP_DOTPLL, dotpll);
0155
0156
0157 sys_rstpll &= ~( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2
0158 | MSR_GLCP_SYS_RSTPLL_DOTPREMULT2
0159 | MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 );
0160 sys_rstpll |= pll_table[best_i].sys_rstpll_bits;
0161
0162 wrmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
0163
0164
0165 dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
0166 wrmsrl(MSR_GLCP_DOTPLL, dotpll);
0167
0168
0169 do {
0170 rdmsrl(MSR_GLCP_DOTPLL, dotpll);
0171 } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
0172 }
0173
0174 static void
0175 gx_configure_tft(struct fb_info *info)
0176 {
0177 struct gxfb_par *par = info->par;
0178 unsigned long val;
0179 unsigned long fp;
0180
0181
0182
0183 rdmsrl(MSR_GX_MSR_PADSEL, val);
0184 val &= ~MSR_GX_MSR_PADSEL_MASK;
0185 val |= MSR_GX_MSR_PADSEL_TFT;
0186 wrmsrl(MSR_GX_MSR_PADSEL, val);
0187
0188
0189
0190 fp = read_fp(par, FP_PM);
0191 fp &= ~FP_PM_P;
0192 write_fp(par, FP_PM, fp);
0193
0194
0195
0196 fp = read_fp(par, FP_PT1);
0197 fp &= FP_PT1_VSIZE_MASK;
0198 fp |= info->var.yres << FP_PT1_VSIZE_SHIFT;
0199 write_fp(par, FP_PT1, fp);
0200
0201
0202
0203
0204 fp = 0x0F100000;
0205
0206
0207
0208 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
0209 fp |= FP_PT2_VSP;
0210
0211 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
0212 fp |= FP_PT2_HSP;
0213
0214 write_fp(par, FP_PT2, fp);
0215
0216
0217 write_fp(par, FP_DFC, FP_DFC_NFI);
0218
0219
0220
0221 fp = read_vp(par, VP_DCFG);
0222 fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN;
0223 write_vp(par, VP_DCFG, fp);
0224
0225
0226
0227 fp = read_fp(par, FP_PM);
0228 fp |= FP_PM_P;
0229 write_fp(par, FP_PM, fp);
0230 }
0231
0232 void gx_configure_display(struct fb_info *info)
0233 {
0234 struct gxfb_par *par = info->par;
0235 u32 dcfg, misc;
0236
0237
0238 dcfg = read_vp(par, VP_DCFG);
0239
0240
0241 dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
0242 write_vp(par, VP_DCFG, dcfg);
0243
0244
0245 dcfg &= ~(VP_DCFG_CRT_SYNC_SKW
0246 | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL
0247 | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
0248
0249
0250 dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT;
0251
0252
0253 dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN;
0254
0255 misc = read_vp(par, VP_MISC);
0256
0257
0258 misc |= VP_MISC_GAM_EN;
0259
0260 if (par->enable_crt) {
0261
0262
0263 misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN);
0264 write_vp(par, VP_MISC, misc);
0265
0266
0267
0268
0269 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
0270 dcfg |= VP_DCFG_CRT_HSYNC_POL;
0271 if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
0272 dcfg |= VP_DCFG_CRT_VSYNC_POL;
0273 } else {
0274
0275 misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN);
0276 write_vp(par, VP_MISC, misc);
0277 }
0278
0279
0280
0281
0282 dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN;
0283
0284
0285
0286 write_vp(par, VP_DCFG, dcfg);
0287
0288
0289
0290 if (par->enable_crt == 0)
0291 gx_configure_tft(info);
0292 }
0293
0294 int gx_blank_display(struct fb_info *info, int blank_mode)
0295 {
0296 struct gxfb_par *par = info->par;
0297 u32 dcfg, fp_pm;
0298 int blank, hsync, vsync, crt;
0299
0300
0301 switch (blank_mode) {
0302 case FB_BLANK_UNBLANK:
0303 blank = 0; hsync = 1; vsync = 1; crt = 1;
0304 break;
0305 case FB_BLANK_NORMAL:
0306 blank = 1; hsync = 1; vsync = 1; crt = 1;
0307 break;
0308 case FB_BLANK_VSYNC_SUSPEND:
0309 blank = 1; hsync = 1; vsync = 0; crt = 1;
0310 break;
0311 case FB_BLANK_HSYNC_SUSPEND:
0312 blank = 1; hsync = 0; vsync = 1; crt = 1;
0313 break;
0314 case FB_BLANK_POWERDOWN:
0315 blank = 1; hsync = 0; vsync = 0; crt = 0;
0316 break;
0317 default:
0318 return -EINVAL;
0319 }
0320 dcfg = read_vp(par, VP_DCFG);
0321 dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
0322 VP_DCFG_CRT_EN);
0323 if (!blank)
0324 dcfg |= VP_DCFG_DAC_BL_EN;
0325 if (hsync)
0326 dcfg |= VP_DCFG_HSYNC_EN;
0327 if (vsync)
0328 dcfg |= VP_DCFG_VSYNC_EN;
0329 if (crt)
0330 dcfg |= VP_DCFG_CRT_EN;
0331 write_vp(par, VP_DCFG, dcfg);
0332
0333
0334
0335 if (par->enable_crt == 0) {
0336 fp_pm = read_fp(par, FP_PM);
0337 if (blank_mode == FB_BLANK_POWERDOWN)
0338 fp_pm &= ~FP_PM_P;
0339 else
0340 fp_pm |= FP_PM_P;
0341 write_fp(par, FP_PM, fp_pm);
0342 }
0343
0344 return 0;
0345 }