summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am3
-rw-r--r--src/i810_reg.h13
-rw-r--r--src/i830.h4
-rw-r--r--src/i830_driver.c13
-rw-r--r--src/i830_raw.c175
5 files changed, 193 insertions, 15 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d6bdc460..48b2ca8b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,7 +56,8 @@ i810_drv_la_SOURCES = \
i830_rotate.c \
i830_randr.c \
i830_raw.c \
- i830_i2c.c
+ i830_i2c.c \
+ i830_sdvo.c
if DRI
i810_drv_la_SOURCES += \
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 05791dc2..600bd13b 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -678,6 +678,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DPLL_2X_CLOCK_ENABLE (1 << 30)
#define DPLL_SYNCLOCK_ENABLE (1 << 29)
#define DPLL_VGA_MODE_DISABLE (1 << 28)
+#define DPLL_DIVISOR_SELECT (1 << 24)
#define DPLL_P2_MASK 1
#define DPLL_P2_SHIFT 23
#define DPLL_P1_FORCE_DIV2 (1 << 21)
@@ -712,16 +713,26 @@ struct pll_min_max {
/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
/* Clock values are in units of kHz */
#define PLL_REFCLK 48000
+
#define MIN_VCO_FREQ 930000
#define MAX_VCO_FREQ 1400000
#define MIN_CLOCK 25000
#define MAX_CLOCK 350000
#define P_TRANSITION_CLOCK 165000
-#define CALC_VCLOCK(m1, m2, n, p1, p2) \
+
+#define I9XX_MIN_VCO_FREQ 1400000
+#define I9XX_MAX_VCO_FREQ 2800000
+#define I9XX_P_TRANSITION_CLOCK 200000
+
+#define CALC_VCLOCK_i8xx(m1, m2, n, p1, p2) \
((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
(((p1) + 2) * (1 << (p2 + 1))))
+#define CALC_VCLOCK_i9xx(m1, m2, n, p1, p2) \
+ ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
+ (((1<<p1)) * (p2 ? 10 : 5)))
+
#define CALC_VCLOCK3(m, n, p) ((PLL_REFCLK * (m) / (n)) / (p))
diff --git a/src/i830.h b/src/i830.h
index 1fe5ae9b..6aa6fd64 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -250,6 +250,10 @@ struct _I830DVORec {
struct _I830RegI2CDriver *i2c_drv;
};
+typedef struct _I830SDVORec {
+ I2CDevRec d;
+ unsigned char sdvo_regs[20];
+} I830SDVORec, *I830SDVOPtr;
typedef struct _I830Rec {
unsigned char *MMIOBase;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 2946e72e..84ce65d7 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -345,7 +345,9 @@ I830DumpModeDebugInfo(ScrnInfoPtr pScrn)
temp = INREG(DPLL_A);
p2 = (temp >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
p1 = (temp >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
- p = (p1+2) * ( 1<< (p2 + 1));
+
+ p = ((1 << p1) * (p2 ? 10 : 5));
+ // p = (p1+2) * ( 1<< (p2 + 1));
ErrorF("DPLL A is %08X: p1 is %d p2 is %d\n", temp, p1, p2);
temp = INREG(FPA0);
n = (temp >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -353,7 +355,7 @@ I830DumpModeDebugInfo(ScrnInfoPtr pScrn)
m2 = (temp >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m = (5 * ((m1) + 2) + ((m2) + 2));
n += 2;
- clock = ((PLL_REFCLK * m / n) / p);
+ clock = (((PLL_REFCLK * m) / n) / p);
ErrorF("FPA0 is %08X N is %d m1 is %d m2 is %d\n", temp, n, m1, m2);
ErrorF("m %d n %d p %d clock %d\n", m, n, p, clock);
@@ -2209,12 +2211,19 @@ I830PreInitDDC(ScrnInfoPtr pScrn)
return;
}
else {
+ pointer ret_p;
pI830->num_dvos = 2;
pI830->dvos[1].bus_type = I830_I2C_BUS_SDVO;
/* i915 has sDVO */
pI830->ddc2 = I830I2CInit(pScrn, &pI830->dvos[1].pI2CBus, GPIOE, "SDVOCTRL");
if (pI830->ddc2 = FALSE)
return;
+
+ ret_p=I830SDVOInit(pI830->dvos[1].pI2CBus);
+
+
+ I830SDVOGetStatus(ret_p);
+
}
pI830->ddc2 = TRUE;
diff --git a/src/i830_raw.c b/src/i830_raw.c
index c8f284d0..860ce440 100644
--- a/src/i830_raw.c
+++ b/src/i830_raw.c
@@ -69,7 +69,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
struct pll_min_max plls[PLLS_MAX] = {
{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31 }, //I8xx
- { 70, 125, 10, 22, 5, 9, 4, 7, 6, 79, 2, 16 } //I9xx
+ { 70, 120, 10, 20, 4, 12, 3, 8, 6, 79, 0, 31 } //I9xx
};
/* Split the M parameter into M1 and M2. */
@@ -95,6 +95,26 @@ splitm(int index, unsigned int m, CARD32 *retm1, CARD32 *retm2)
/* Split the P parameter into P1 and P2. */
static int
+splitp_i9xx(int index, unsigned int p, CARD32 *retp1, CARD32 *retp2)
+{
+ int p1_bit, p2, p1;
+ int p2_vals[4] = { 5 , 10, 7, 14 };
+
+// if ((p % 10) == 0)
+ p2 = 0;
+// else
+// p2 = 0;
+
+ p1_bit = (p / (p2_vals[p2]));
+ p1 = ffs(p1_bit) - 1;
+
+ *retp1 = (unsigned int)p1;
+ *retp2 = (unsigned int)p2;
+ return 0;
+}
+
+/* Split the P parameter into P1 and P2. */
+static int
splitp(int index, unsigned int p, CARD32 *retp1, CARD32 *retp2)
{
int p1, p2;
@@ -117,6 +137,107 @@ splitp(int index, unsigned int p, CARD32 *retp1, CARD32 *retp2)
}
}
+int
+i9xx_calc_pll_params(int index, int clock,
+ CARD32 *retm1, CARD32 *retm2,
+ CARD32 *retn, CARD32 *retp1, CARD32 *retp2,
+ CARD32 *retclock, CARD32 *use_x2)
+{
+ volatile CARD32 m1, m2, n, p1, p2, n1;
+ CARD32 f_vco, p, p_best = 0, m, f_out;
+ CARD32 err_max, err_target, err_best = 10000000;
+ volatile CARD32 n_best = 0, m_best = 0, f_best, f_err;
+ volatile CARD32 p_min, p_max, p_inc, div_min, div_max;
+ int ret;
+
+ /* Accept 0.5% difference, but aim for 0.1% */
+ err_max = 5 * clock / 1000;
+ err_target = clock / 1000;
+
+ DPRINTF(PFX, "Clock is %d\n", clock);
+
+ div_max = I9XX_MAX_VCO_FREQ / clock;
+ div_min = ROUND_UP_TO(I9XX_MIN_VCO_FREQ, clock) / clock;
+
+ if (clock <= I9XX_P_TRANSITION_CLOCK)
+ p_inc = 10;
+ else
+ p_inc = 5;
+ p_min = ROUND_UP_TO(div_min, p_inc);
+ p_max = ROUND_DOWN_TO(div_max, p_inc);
+ if (p_min < plls[index].min_p)
+ p_min = plls[index].min_p;
+ if (p_max > plls[index].max_p)
+ p_max = plls[index].max_p;
+
+ DPRINTF(PFX, "p range is %d-%d (%d)\n", p_min, p_max, p_inc);
+ clock /= 2;
+ p = p_min;
+ do {
+ ret = splitp_i9xx(index, p, &p1, &p2);
+ fprintf(stderr,"trying p %d p1 %d p2 %d\n", p , p1, p2);
+ if (ret) {
+ DPRINTF(PFX, "cannot split p = %d\n", p);
+ p += p_inc;
+ continue;
+ }
+ n = plls[index].min_n;
+ f_vco = clock * p;
+ do {
+ m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
+ if (m < plls[index].min_m)
+ m = plls[index].min_m;
+ if (m > plls[index].max_m)
+ m = plls[index].max_m;
+ f_out = CALC_VCLOCK3(m, n, p);
+ if (splitm(index, m, &m1, &m2)) {
+ DPRINTF(PFX, "cannot split m = %d\n", m);
+ n++;
+ continue;
+ }
+ if (clock > f_out)
+ f_err = clock - f_out;
+ else
+ f_err = f_out - clock;
+
+ if (f_err < err_best) {
+ m_best = m;
+ n_best = n;
+ p_best = p;
+ f_best = f_out;
+ err_best = f_err;
+ }
+ n++;
+ } while ((n <= plls[index].max_n) && (f_out >= clock));
+ p += p_inc;
+ } while ((p <= p_max));
+
+ if (!m_best) {
+ DPRINTF(PFX,"cannot find parameters for clock %d\n", clock);
+ return 1;
+ }
+ m = m_best;
+ n = n_best;
+ p = p_best;
+ splitm(index, m, &m1, &m2);
+ splitp_i9xx(index, p, &p1, &p2);
+ n1 = n - 2;
+
+ DPRINTF(PFX, "m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
+ "f: %d (%d), VCO: %d\n",
+ m, m1, m2, n, n1, p, p1, p2,
+ CALC_VCLOCK3(m, n, p), CALC_VCLOCK_i9xx(m1, m2, n1, p1, p2),
+ CALC_VCLOCK3(m, n, p) * p);
+ *retm1 = m1;
+ *retm2 = m2;
+ *retn = n1;
+ *retp1 = p1;
+ *retp2 = p2;
+ *retclock = CALC_VCLOCK_i9xx(m1, m2, n1, p1, p2);
+
+ return 0;
+}
+
static int
calc_pll_params(int index, int clock, CARD32 *retm1, CARD32 *retm2, CARD32 *retn, CARD32 *retp1,
CARD32 *retp2, CARD32 *retclock)
@@ -126,6 +247,7 @@ calc_pll_params(int index, int clock, CARD32 *retm1, CARD32 *retm2, CARD32 *retn
CARD32 err_max, err_target, err_best = 10000000;
CARD32 n_best = 0, m_best = 0, f_best, f_err;
CARD32 p_min, p_max, p_inc, div_min, div_max;
+ int ret;
/* Accept 0.5% difference, but aim for 0.1% */
err_max = 5 * clock / 1000;
@@ -151,7 +273,8 @@ calc_pll_params(int index, int clock, CARD32 *retm1, CARD32 *retm2, CARD32 *retn
p = p_min;
do {
- if (splitp(index, p, &p1, &p2)) {
+ ret = splitp(index, p, &p1, &p2);
+ if (ret) {
DPRINTF(PFX, "cannot split p = %d\n", p);
p += p_inc;
continue;
@@ -202,14 +325,14 @@ calc_pll_params(int index, int clock, CARD32 *retm1, CARD32 *retm2, CARD32 *retn
DPRINTF(PFX, "m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
"f: %d (%d), VCO: %d\n",
m, m1, m2, n, n1, p, p1, p2,
- CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
+ CALC_VCLOCK3(m, n, p), CALC_VCLOCK_i8xx(m1, m2, n1, p1, p2),
CALC_VCLOCK3(m, n, p) * p);
*retm1 = m1;
*retm2 = m2;
*retn = n1;
*retp1 = p1;
*retp2 = p2;
- *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+ *retclock = CALC_VCLOCK_i8xx(m1, m2, n1, p1, p2);
return 0;
}
@@ -242,9 +365,11 @@ I830RawSetHw(ScrnInfoPtr pScrn, DisplayModePtr pMode)
CARD32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
int index;
int displays = pI830->operatingDevices;
-
+ int use_x2=0;
+ int ret;
+
index = IS_I9XX(pI830) ? PLLS_I9xx : PLLS_I8xx;
-
+
/* Disable VGA */
hw->vgacntrl |= VGA_CNTRL_DISABLE;
@@ -306,11 +431,32 @@ I830RawSetHw(ScrnInfoPtr pScrn, DisplayModePtr pMode)
/* Desired clock in kHz */
// clock_target = 1000000000 / var->pixclock;
clock_target = pMode->Clock;
-
- if (calc_pll_params(index, clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
- WRN_MSG("calc_pll_params failed\n");
- return FALSE;
+
+ if (IS_I9XX(pI830))
+ ret=i9xx_calc_pll_params(index, clock_target, &m1, &m2, &n, &p1, &p2, &clock, &use_x2);
+ else
+ ret=calc_pll_params(index, clock_target, &m1, &m2, &n, &p1, &p2, &clock);
+ if (ret) {
+ ErrorF("calc_pll_params failed\n");
+ return FALSE;
}
+#if 0
+// use_x2 = 0;
+ if (0) //clock != clock_target && IS_I9XX(pI830))
+ {
+ /* try again with a divisor */
+ clock_target /= 2;
+ if (IS_I9XX(pI830))
+ ret=i9xx_calc_pll_params(index, clock_target, &m1, &m2, &n, &p1, &p2, &clock);
+ else
+ ret=calc_pll_params(index, clock_target, &m1, &m2, &n, &p1, &p2, &clock);
+ if (ret) {
+ ErrorF("calc_pll_params failed\n");
+ return FALSE;
+ }
+ use_x2 = 1;
+ }
+#endif
/* Check for overflow. */
if (check_overflow(pScrn, p1, DPLL_P1_MASK, "PLL P1 parameter"))
@@ -330,7 +476,14 @@ I830RawSetHw(ScrnInfoPtr pScrn, DisplayModePtr pMode)
*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
if (IS_I9XX(pI830))
- *dpll |= 0x3 | 0x4000000;
+ {
+ *dpll |= 0x4000000;
+
+ if (use_x2)
+ *dpll |= DPLL_2X_CLOCK_ENABLE;
+ else
+ *dpll &= ~DPLL_2X_CLOCK_ENABLE;
+ }
*fp0 = (n << FP_N_DIVISOR_SHIFT) |
(m1 << FP_M1_DIVISOR_SHIFT) |