diff options
| author | Dave Airlie <airlied@linux.ie> | 2006-03-22 20:30:05 -0500 |
|---|---|---|
| committer | Dave Airlie <airlied@linux.ie> | 2006-04-02 21:43:28 -0400 |
| commit | 7679f4d69296de97a7f62458cc4d1c6c884dfcfb (patch) | |
| tree | 118ec34ee36be93d95abeb2628a16cd0d386c927 /drivers/video | |
| parent | 9639d5ec07a490134f05ac890506a367aaf8663b (diff) | |
intelfb: make i915 modeset
This takes the modeset and pll code from my X driver.
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/video')
| -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); |
