diff options
Diffstat (limited to 'drivers/video/intelfb/intelfbhw.c')
-rw-r--r-- | drivers/video/intelfb/intelfbhw.c | 136 |
1 files changed, 96 insertions, 40 deletions
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index f8c8c0a3f565..0bfa668bec21 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c | |||
@@ -562,6 +562,8 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | |||
562 | 562 | ||
563 | static int calc_vclock3(int index, int m, int n, int p) | 563 | static int calc_vclock3(int index, int m, int n, int p) |
564 | { | 564 | { |
565 | if (p == 0 || n == 0) | ||
566 | return 0; | ||
565 | return PLL_REFCLK * m / n / p; | 567 | return PLL_REFCLK * m / n / p; |
566 | } | 568 | } |
567 | 569 | ||
@@ -570,6 +572,8 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2) | |||
570 | switch(index) | 572 | switch(index) |
571 | { | 573 | { |
572 | case PLLS_I9xx: | 574 | case PLLS_I9xx: |
575 | if (p1 == 0) | ||
576 | return 0; | ||
573 | return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / | 577 | return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / |
574 | ((p1)) * (p2 ? 10 : 5))); | 578 | ((p1)) * (p2 ? 10 : 5))); |
575 | case PLLS_I8xx: | 579 | case PLLS_I8xx: |
@@ -779,8 +783,20 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2) | |||
779 | 783 | ||
780 | if (index == PLLS_I9xx) | 784 | if (index == PLLS_I9xx) |
781 | { | 785 | { |
782 | p1 = (p / 10) + 1; | 786 | switch (p) { |
783 | p2 = 0; | 787 | case 10: |
788 | p1 = 2; | ||
789 | p2 = 0; | ||
790 | break; | ||
791 | case 20: | ||
792 | p1 = 1; | ||
793 | p2 = 0; | ||
794 | break; | ||
795 | default: | ||
796 | p1 = (p / 10) + 1; | ||
797 | p2 = 0; | ||
798 | break; | ||
799 | } | ||
784 | 800 | ||
785 | *retp1 = (unsigned int)p1; | 801 | *retp1 = (unsigned int)p1; |
786 | *retp2 = (unsigned int)p2; | 802 | *retp2 = (unsigned int)p2; |
@@ -813,8 +829,8 @@ static int | |||
813 | calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, | 829 | calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, |
814 | u32 *retp2, u32 *retclock) | 830 | u32 *retp2, u32 *retclock) |
815 | { | 831 | { |
816 | u32 m1, m2, n, p1, p2, n1; | 832 | u32 m1, m2, n, p1, p2, n1, testm; |
817 | u32 f_vco, p, p_best = 0, m, f_out; | 833 | u32 f_vco, p, p_best = 0, m, f_out = 0; |
818 | u32 err_max, err_target, err_best = 10000000; | 834 | u32 err_max, err_target, err_best = 10000000; |
819 | u32 n_best = 0, m_best = 0, f_best, f_err; | 835 | u32 n_best = 0, m_best = 0, f_best, f_err; |
820 | u32 p_min, p_max, p_inc, div_min, div_max; | 836 | u32 p_min, p_max, p_inc, div_min, div_max; |
@@ -826,7 +842,10 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re | |||
826 | DBG_MSG("Clock is %d\n", clock); | 842 | DBG_MSG("Clock is %d\n", clock); |
827 | 843 | ||
828 | div_max = plls[index].max_vco_freq / clock; | 844 | div_max = plls[index].max_vco_freq / clock; |
829 | div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock; | 845 | if (index == PLLS_I9xx) |
846 | div_min = 5; | ||
847 | else | ||
848 | div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock; | ||
830 | 849 | ||
831 | if (clock <= plls[index].p_transition_clock) | 850 | if (clock <= plls[index].p_transition_clock) |
832 | p_inc = plls[index].p_inc_lo; | 851 | p_inc = plls[index].p_inc_lo; |
@@ -839,6 +858,16 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re | |||
839 | if (p_max > plls[index].max_p) | 858 | if (p_max > plls[index].max_p) |
840 | p_max = plls[index].max_p; | 859 | p_max = plls[index].max_p; |
841 | 860 | ||
861 | if (clock < PLL_REFCLK && index==PLLS_I9xx) | ||
862 | { | ||
863 | p_min = 10; | ||
864 | p_max = 20; | ||
865 | /* this makes 640x480 work it really shouldn't | ||
866 | - SOMEONE WITHOUT DOCS WOZ HERE */ | ||
867 | if (clock < 30000) | ||
868 | clock *= 4; | ||
869 | } | ||
870 | |||
842 | DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); | 871 | DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); |
843 | 872 | ||
844 | p = p_min; | 873 | p = p_min; |
@@ -854,26 +883,28 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re | |||
854 | do { | 883 | do { |
855 | m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; | 884 | m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; |
856 | if (m < plls[index].min_m) | 885 | if (m < plls[index].min_m) |
857 | m = plls[index].min_m; | 886 | m = plls[index].min_m + 1; |
858 | if (m > plls[index].max_m) | 887 | if (m > plls[index].max_m) |
859 | m = plls[index].max_m; | 888 | m = plls[index].max_m - 1; |
860 | f_out = calc_vclock3(index, m, n, p); | 889 | for (testm = m - 1; testm <= m; testm++) { |
861 | if (splitm(index, m, &m1, &m2)) { | 890 | f_out = calc_vclock3(index, m, n, p); |
862 | WRN_MSG("cannot split m = %d\n", m); | 891 | if (splitm(index, m, &m1, &m2)) { |
863 | n++; | 892 | WRN_MSG("cannot split m = %d\n", m); |
864 | continue; | 893 | n++; |
865 | } | 894 | continue; |
866 | if (clock > f_out) | 895 | } |
867 | f_err = clock - f_out; | 896 | if (clock > f_out) |
868 | else | 897 | f_err = clock - f_out; |
869 | f_err = f_out - clock; | 898 | else/* slightly bias the error for bigger clocks */ |
870 | 899 | f_err = f_out - clock + 1; | |
871 | if (f_err < err_best) { | 900 | |
872 | m_best = m; | 901 | if (f_err < err_best) { |
873 | n_best = n; | 902 | m_best = m; |
874 | p_best = p; | 903 | n_best = n; |
875 | f_best = f_out; | 904 | p_best = p; |
876 | err_best = f_err; | 905 | f_best = f_out; |
906 | err_best = f_err; | ||
907 | } | ||
877 | } | 908 | } |
878 | n++; | 909 | n++; |
879 | } while ((n <= plls[index].max_n) && (f_out >= clock)); | 910 | } while ((n <= plls[index].max_n) && (f_out >= clock)); |
@@ -1157,6 +1188,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1157 | u32 hsync_reg, htotal_reg, hblank_reg; | 1188 | u32 hsync_reg, htotal_reg, hblank_reg; |
1158 | u32 vsync_reg, vtotal_reg, vblank_reg; | 1189 | u32 vsync_reg, vtotal_reg, vblank_reg; |
1159 | u32 src_size_reg; | 1190 | u32 src_size_reg; |
1191 | u32 count, tmp_val[3]; | ||
1160 | 1192 | ||
1161 | /* Assume single pipe, display plane A, analog CRT. */ | 1193 | /* Assume single pipe, display plane A, analog CRT. */ |
1162 | 1194 | ||
@@ -1225,6 +1257,28 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1225 | src_size_reg = SRC_SIZE_A; | 1257 | src_size_reg = SRC_SIZE_A; |
1226 | } | 1258 | } |
1227 | 1259 | ||
1260 | /* turn off pipe */ | ||
1261 | tmp = INREG(pipe_conf_reg); | ||
1262 | tmp &= ~PIPECONF_ENABLE; | ||
1263 | OUTREG(pipe_conf_reg, tmp); | ||
1264 | |||
1265 | count = 0; | ||
1266 | do{ | ||
1267 | tmp_val[count%3] = INREG(0x70000); | ||
1268 | if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2])) | ||
1269 | break; | ||
1270 | count++; | ||
1271 | udelay(1); | ||
1272 | if (count % 200 == 0) | ||
1273 | { | ||
1274 | tmp = INREG(pipe_conf_reg); | ||
1275 | tmp &= ~PIPECONF_ENABLE; | ||
1276 | OUTREG(pipe_conf_reg, tmp); | ||
1277 | } | ||
1278 | } while(count < 2000); | ||
1279 | |||
1280 | OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE); | ||
1281 | |||
1228 | /* Disable planes A and B. */ | 1282 | /* Disable planes A and B. */ |
1229 | tmp = INREG(DSPACNTR); | 1283 | tmp = INREG(DSPACNTR); |
1230 | tmp &= ~DISPPLANE_PLANE_ENABLE; | 1284 | tmp &= ~DISPPLANE_PLANE_ENABLE; |
@@ -1242,10 +1296,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1242 | tmp |= ADPA_DPMS_D3; | 1296 | tmp |= ADPA_DPMS_D3; |
1243 | OUTREG(ADPA, tmp); | 1297 | OUTREG(ADPA, tmp); |
1244 | 1298 | ||
1245 | /* turn off pipe */ | 1299 | /* do some funky magic - xyzzy */ |
1246 | tmp = INREG(pipe_conf_reg); | 1300 | OUTREG(0x61204, 0xabcd0000); |
1247 | tmp &= ~PIPECONF_ENABLE; | ||
1248 | OUTREG(pipe_conf_reg, tmp); | ||
1249 | 1301 | ||
1250 | /* turn off PLL */ | 1302 | /* turn off PLL */ |
1251 | tmp = INREG(dpll_reg); | 1303 | tmp = INREG(dpll_reg); |
@@ -1257,26 +1309,30 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1257 | OUTREG(fp0_reg, *fp0); | 1309 | OUTREG(fp0_reg, *fp0); |
1258 | OUTREG(fp1_reg, *fp1); | 1310 | OUTREG(fp1_reg, *fp1); |
1259 | 1311 | ||
1260 | /* Set pipe parameters */ | 1312 | /* Enable PLL */ |
1261 | OUTREG(hsync_reg, *hs); | 1313 | tmp = INREG(dpll_reg); |
1262 | OUTREG(hblank_reg, *hb); | 1314 | tmp |= DPLL_VCO_ENABLE; |
1263 | OUTREG(htotal_reg, *ht); | 1315 | OUTREG(dpll_reg, tmp); |
1264 | OUTREG(vsync_reg, *vs); | ||
1265 | OUTREG(vblank_reg, *vb); | ||
1266 | OUTREG(vtotal_reg, *vt); | ||
1267 | OUTREG(src_size_reg, *ss); | ||
1268 | 1316 | ||
1269 | /* Set DVOs B/C */ | 1317 | /* Set DVOs B/C */ |
1270 | OUTREG(DVOB, hw->dvob); | 1318 | OUTREG(DVOB, hw->dvob); |
1271 | OUTREG(DVOC, hw->dvoc); | 1319 | OUTREG(DVOC, hw->dvoc); |
1272 | 1320 | ||
1321 | /* undo funky magic */ | ||
1322 | OUTREG(0x61204, 0x00000000); | ||
1323 | |||
1273 | /* Set ADPA */ | 1324 | /* Set ADPA */ |
1325 | OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE); | ||
1274 | OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); | 1326 | OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); |
1275 | 1327 | ||
1276 | /* Enable PLL */ | 1328 | /* Set pipe parameters */ |
1277 | tmp = INREG(dpll_reg); | 1329 | OUTREG(hsync_reg, *hs); |
1278 | tmp |= DPLL_VCO_ENABLE; | 1330 | OUTREG(hblank_reg, *hb); |
1279 | OUTREG(dpll_reg, tmp); | 1331 | OUTREG(htotal_reg, *ht); |
1332 | OUTREG(vsync_reg, *vs); | ||
1333 | OUTREG(vblank_reg, *vb); | ||
1334 | OUTREG(vtotal_reg, *vt); | ||
1335 | OUTREG(src_size_reg, *ss); | ||
1280 | 1336 | ||
1281 | /* Enable pipe */ | 1337 | /* Enable pipe */ |
1282 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); | 1338 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); |