summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h17
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c233
2 files changed, 198 insertions, 52 deletions
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 5302d6566d7c..b5d9c0ca757b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -126,6 +126,23 @@
#define MGAG200_MAX_FB_HEIGHT 4096
#define MGAG200_MAX_FB_WIDTH 4096
+/*
+ * Stores parameters for programming the PLLs
+ *
+ * Fref: reference frequency (A: 25.175 Mhz, B: 28.361, C: XX Mhz)
+ * Fo: output frequency
+ * Fvco = Fref * (N / M)
+ * Fo = Fvco / P
+ *
+ * S = [0..3]
+ */
+struct mgag200_pll_values {
+ unsigned int m;
+ unsigned int n;
+ unsigned int p;
+ unsigned int s;
+};
+
#define to_mga_connector(x) container_of(x, struct mga_connector, base)
struct mga_i2c_chan {
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 549595b1daba..c9eb044bcb7d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -114,7 +114,8 @@ static inline void mga_wait_busy(struct mga_device *mdev)
* PLL setup
*/
-static int mgag200_g200_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
struct drm_device *dev = &mdev->base;
const int post_div_max = 7;
@@ -174,16 +175,32 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock)
drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
clock, f_vco, m, n, p, s);
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG_DAC(MGA1064_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3)));
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
return 0;
}
-static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
+static void mgag200_set_pixpll_g200(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+}
+
+static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
@@ -290,32 +307,45 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
return -EINVAL;
}
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = 0;
+
+ return 0;
+}
+
+static void mgag200_set_pixpll_g200se(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
- WREG_DAC(MGA1064_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_PIX_PLLC_P, p);
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
if (unique_rev_id >= 0x04) {
WREG_DAC(0x1a, 0x09);
msleep(20);
WREG_DAC(0x1a, 0x01);
-
}
-
- return 0;
}
-static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
unsigned int vcomax, vcomin, pllreffreq;
unsigned int delta, tmpdelta;
unsigned int testp, testm, testn, testp2;
unsigned int p, m, n;
unsigned int computed;
- int i, j, tmpcount, vcount;
- bool pll_locked = false;
- u8 tmp;
m = n = p = 0;
@@ -388,6 +418,25 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
}
}
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = 0;
+
+ return 0;
+}
+
+static void mgag200_set_pixpll_g200wb(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+ int i, j, tmpcount, vcount;
+ bool pll_locked = false;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
for (i = 0; i <= 32 && pll_locked == false; i++) {
@@ -430,9 +479,9 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
udelay(50);
/* program pixel pll register */
- WREG_DAC(MGA1064_WB_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_WB_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_WB_PIX_PLLC_P, p);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
udelay(50);
@@ -480,21 +529,21 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
udelay(5);
}
}
+
WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
WREG_DAC(MGA1064_REMHEADCTL, tmp);
- return 0;
}
-static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
unsigned int vcomax, vcomin, pllreffreq;
unsigned int delta, tmpdelta;
unsigned int testp, testm, testn;
unsigned int p, m, n;
unsigned int computed;
- u8 tmp;
m = n = p = 0;
vcomax = 550000;
@@ -527,6 +576,23 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
}
}
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = 0;
+
+ return 0;
+}
+
+static void mgag200_set_pixpll_g200ev(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
@@ -547,9 +613,9 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
WREG8(DAC_DATA, tmp);
- WREG_DAC(MGA1064_EV_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_EV_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_EV_PIX_PLLC_P, p);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
udelay(50);
@@ -578,20 +644,16 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
WREG8(DAC_DATA, tmp);
-
- return 0;
}
-static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
unsigned int vcomax, vcomin, pllreffreq;
unsigned int delta, tmpdelta;
unsigned int testp, testm, testn;
unsigned int p, m, n;
unsigned int computed;
- int i, j, tmpcount, vcount;
- u8 tmp;
- bool pll_locked = false;
m = n = p = 0;
@@ -662,6 +724,25 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
}
}
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = 0;
+
+ return 0;
+}
+
+static void mgag200_set_pixpll_g200eh(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+ int i, j, tmpcount, vcount;
+ bool pll_locked = false;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
for (i = 0; i <= 32 && pll_locked == false; i++) {
@@ -681,9 +762,9 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
udelay(500);
- WREG_DAC(MGA1064_EH_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_EH_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_EH_PIX_PLLC_P, p);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
udelay(500);
@@ -711,11 +792,10 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
udelay(5);
}
}
-
- return 0;
}
-static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long clock,
+ struct mgag200_pll_values *pixpllc)
{
static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
unsigned int vcomax, vcomin, pllreffreq;
@@ -723,7 +803,6 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
int testr, testn, testm, testo;
unsigned int p, m, n;
unsigned int computed, vco;
- int tmp;
m = n = p = 0;
vcomax = 1488000;
@@ -764,6 +843,23 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
}
}
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = 0;
+
+ return 0;
+}
+
+static void mgag200_set_pixpll_g200er(struct mga_device *mdev,
+ const struct mgag200_pll_values *pixpllc)
+{
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+ xpixpllcm = pixpllc->m;
+ xpixpllcn = pixpllc->n;
+ xpixpllcp = pixpllc->p | (pixpllc->s << 3);
+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
@@ -788,37 +884,70 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
udelay(500);
- WREG_DAC(MGA1064_ER_PIX_PLLC_N, n);
- WREG_DAC(MGA1064_ER_PIX_PLLC_M, m);
- WREG_DAC(MGA1064_ER_PIX_PLLC_P, p);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
udelay(50);
-
- return 0;
}
-static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock)
+static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock)
{
+ struct mgag200_pll_values pixpll;
+ int ret;
+
switch(mdev->type) {
case G200_PCI:
case G200_AGP:
- return mgag200_g200_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200(mdev, clock, &pixpll);
+ break;
case G200_SE_A:
case G200_SE_B:
- return mga_g200se_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200se(mdev, clock, &pixpll);
+ break;
case G200_WB:
case G200_EW3:
- return mga_g200wb_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200wb(mdev, clock, &pixpll);
+ break;
case G200_EV:
- return mga_g200ev_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200ev(mdev, clock, &pixpll);
+ break;
case G200_EH:
case G200_EH3:
- return mga_g200eh_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200eh(mdev, clock, &pixpll);
+ break;
case G200_ER:
- return mga_g200er_set_plls(mdev, clock);
+ ret = mgag200_compute_pixpll_values_g200er(mdev, clock, &pixpll);
+ break;
}
- return 0;
+ if (ret)
+ return;
+
+ switch (mdev->type) {
+ case G200_PCI:
+ case G200_AGP:
+ mgag200_set_pixpll_g200(mdev, &pixpll);
+ break;
+ case G200_SE_A:
+ case G200_SE_B:
+ mgag200_set_pixpll_g200se(mdev, &pixpll);
+ break;
+ case G200_WB:
+ case G200_EW3:
+ mgag200_set_pixpll_g200wb(mdev, &pixpll);
+ break;
+ case G200_EV:
+ mgag200_set_pixpll_g200ev(mdev, &pixpll);
+ break;
+ case G200_EH:
+ case G200_EH3:
+ mgag200_set_pixpll_g200eh(mdev, &pixpll);
+ break;
+ case G200_ER:
+ mgag200_set_pixpll_g200er(mdev, &pixpll);
+ break;
+ }
}
static void mgag200_g200wb_hold_bmc(struct mga_device *mdev)