aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/intelfb/intelfbhw.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@linux.ie>2006-03-22 20:30:05 -0500
committerDave Airlie <airlied@linux.ie>2006-04-02 21:43:28 -0400
commit7679f4d69296de97a7f62458cc4d1c6c884dfcfb (patch)
tree118ec34ee36be93d95abeb2628a16cd0d386c927 /drivers/video/intelfb/intelfbhw.c
parent9639d5ec07a490134f05ac890506a367aaf8663b (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/intelfb/intelfbhw.c')
-rw-r--r--drivers/video/intelfb/intelfbhw.c136
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
563static int calc_vclock3(int index, int m, int n, int p) 563static 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
813calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, 829calc_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);