aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/gma500
diff options
context:
space:
mode:
authorZhao Yakui <yakui.zhao@intel.com>2012-08-08 09:53:48 -0400
committerDave Airlie <airlied@redhat.com>2012-08-23 19:28:58 -0400
commitd66760962d75af12697d5197b3e97d51fe64169c (patch)
tree8fe91ce6d5592b3ecf9e1327d5d442d5b6a37224 /drivers/gpu/drm/gma500
parent25e9dc69709afad2be8de4ac2ecd6015356936ca (diff)
gma500: Program the DPLL lane based on the selected digitial port
Based on the spec, the CRT output doesn't use the lane. And the HDMI B output uses the Lane0/1 while the HDMI C output uses the Lane 2/3. But currently it will program all the four lanes for the CRT/HDMI. Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> [Ported to the in-kernel driver] Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/gma500')
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c82
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c2
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h5
3 files changed, 58 insertions, 31 deletions
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 5c3a3121ad1..f16169c95de 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -57,8 +57,14 @@ struct cdv_intel_clock_t {
57struct cdv_intel_limit_t { 57struct cdv_intel_limit_t {
58 struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1; 58 struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1;
59 struct cdv_intel_p2_t p2; 59 struct cdv_intel_p2_t p2;
60 bool (*find_pll)(const struct cdv_intel_limit_t *, struct drm_crtc *,
61 int, int, struct cdv_intel_clock_t *);
60}; 62};
61 63
64static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
65 struct drm_crtc *crtc, int target, int refclk,
66 struct cdv_intel_clock_t *best_clock);
67
62#define CDV_LIMIT_SINGLE_LVDS_96 0 68#define CDV_LIMIT_SINGLE_LVDS_96 0
63#define CDV_LIMIT_SINGLE_LVDS_100 1 69#define CDV_LIMIT_SINGLE_LVDS_100 1
64#define CDV_LIMIT_DAC_HDMI_27 2 70#define CDV_LIMIT_DAC_HDMI_27 2
@@ -76,6 +82,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
76 .p1 = {.min = 2, .max = 10}, 82 .p1 = {.min = 2, .max = 10},
77 .p2 = {.dot_limit = 200000, 83 .p2 = {.dot_limit = 200000,
78 .p2_slow = 14, .p2_fast = 14}, 84 .p2_slow = 14, .p2_fast = 14},
85 .find_pll = cdv_intel_find_best_PLL,
79 }, 86 },
80 { /* CDV_SINGLE_LVDS_100MHz */ 87 { /* CDV_SINGLE_LVDS_100MHz */
81 .dot = {.min = 20000, .max = 115500}, 88 .dot = {.min = 20000, .max = 115500},
@@ -90,6 +97,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
90 * is 80-224Mhz. Prefer single channel as much as possible. 97 * is 80-224Mhz. Prefer single channel as much as possible.
91 */ 98 */
92 .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, 99 .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14},
100 .find_pll = cdv_intel_find_best_PLL,
93 }, 101 },
94 { /* CDV_DAC_HDMI_27MHz */ 102 { /* CDV_DAC_HDMI_27MHz */
95 .dot = {.min = 20000, .max = 400000}, 103 .dot = {.min = 20000, .max = 400000},
@@ -101,6 +109,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
101 .p = {.min = 5, .max = 90}, 109 .p = {.min = 5, .max = 90},
102 .p1 = {.min = 1, .max = 9}, 110 .p1 = {.min = 1, .max = 9},
103 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, 111 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
112 .find_pll = cdv_intel_find_best_PLL,
104 }, 113 },
105 { /* CDV_DAC_HDMI_96MHz */ 114 { /* CDV_DAC_HDMI_96MHz */
106 .dot = {.min = 20000, .max = 400000}, 115 .dot = {.min = 20000, .max = 400000},
@@ -112,6 +121,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
112 .p = {.min = 5, .max = 100}, 121 .p = {.min = 5, .max = 100},
113 .p1 = {.min = 1, .max = 10}, 122 .p1 = {.min = 1, .max = 10},
114 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, 123 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
124 .find_pll = cdv_intel_find_best_PLL,
115 }, 125 },
116}; 126};
117 127
@@ -216,7 +226,7 @@ static void cdv_sb_reset(struct drm_device *dev)
216 */ 226 */
217static int 227static int
218cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, 228cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
219 struct cdv_intel_clock_t *clock, bool is_lvds) 229 struct cdv_intel_clock_t *clock, bool is_lvds, u32 ddi_select)
220{ 230{
221 struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc); 231 struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc);
222 int pipe = psb_crtc->pipe; 232 int pipe = psb_crtc->pipe;
@@ -336,30 +346,33 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
336 if (ret) 346 if (ret)
337 return ret; 347 return ret;
338 348
339 lane_reg = PSB_LANE0; 349 if (ddi_select) {
340 cdv_sb_read(dev, lane_reg, &lane_value); 350 if ((ddi_select & DDI_MASK) == DDI0_SELECT) {
341 lane_value &= ~(LANE_PLL_MASK); 351 lane_reg = PSB_LANE0;
342 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe); 352 cdv_sb_read(dev, lane_reg, &lane_value);
343 cdv_sb_write(dev, lane_reg, lane_value); 353 lane_value &= ~(LANE_PLL_MASK);
344 354 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
345 lane_reg = PSB_LANE1; 355 cdv_sb_write(dev, lane_reg, lane_value);
346 cdv_sb_read(dev, lane_reg, &lane_value); 356
347 lane_value &= ~(LANE_PLL_MASK); 357 lane_reg = PSB_LANE1;
348 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe); 358 cdv_sb_read(dev, lane_reg, &lane_value);
349 cdv_sb_write(dev, lane_reg, lane_value); 359 lane_value &= ~(LANE_PLL_MASK);
350 360 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
351 lane_reg = PSB_LANE2; 361 cdv_sb_write(dev, lane_reg, lane_value);
352 cdv_sb_read(dev, lane_reg, &lane_value); 362 } else {
353 lane_value &= ~(LANE_PLL_MASK); 363 lane_reg = PSB_LANE2;
354 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe); 364 cdv_sb_read(dev, lane_reg, &lane_value);
355 cdv_sb_write(dev, lane_reg, lane_value); 365 lane_value &= ~(LANE_PLL_MASK);
356 366 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
357 lane_reg = PSB_LANE3; 367 cdv_sb_write(dev, lane_reg, lane_value);
358 cdv_sb_read(dev, lane_reg, &lane_value); 368
359 lane_value &= ~(LANE_PLL_MASK); 369 lane_reg = PSB_LANE3;
360 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe); 370 cdv_sb_read(dev, lane_reg, &lane_value);
361 cdv_sb_write(dev, lane_reg, lane_value); 371 lane_value &= ~(LANE_PLL_MASK);
362 372 lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
373 cdv_sb_write(dev, lane_reg, lane_value);
374 }
375 }
363 return 0; 376 return 0;
364} 377}
365 378
@@ -438,13 +451,12 @@ static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc,
438 return true; 451 return true;
439} 452}
440 453
441static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target, 454static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
442 int refclk, 455 struct drm_crtc *crtc, int target, int refclk,
443 struct cdv_intel_clock_t *best_clock) 456 struct cdv_intel_clock_t *best_clock)
444{ 457{
445 struct drm_device *dev = crtc->dev; 458 struct drm_device *dev = crtc->dev;
446 struct cdv_intel_clock_t clock; 459 struct cdv_intel_clock_t clock;
447 const struct cdv_intel_limit_t *limit = cdv_intel_limit(crtc, refclk);
448 int err = target; 460 int err = target;
449 461
450 462
@@ -954,6 +966,8 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
954 bool is_hdmi = false; 966 bool is_hdmi = false;
955 struct drm_mode_config *mode_config = &dev->mode_config; 967 struct drm_mode_config *mode_config = &dev->mode_config;
956 struct drm_connector *connector; 968 struct drm_connector *connector;
969 const struct cdv_intel_limit_t *limit;
970 u32 ddi_select = 0;
957 971
958 list_for_each_entry(connector, &mode_config->connector_list, head) { 972 list_for_each_entry(connector, &mode_config->connector_list, head) {
959 struct psb_intel_encoder *psb_intel_encoder = 973 struct psb_intel_encoder *psb_intel_encoder =
@@ -963,6 +977,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
963 || connector->encoder->crtc != crtc) 977 || connector->encoder->crtc != crtc)
964 continue; 978 continue;
965 979
980 ddi_select = psb_intel_encoder->ddi_select;
966 switch (psb_intel_encoder->type) { 981 switch (psb_intel_encoder->type) {
967 case INTEL_OUTPUT_LVDS: 982 case INTEL_OUTPUT_LVDS:
968 is_lvds = true; 983 is_lvds = true;
@@ -976,6 +991,9 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
976 case INTEL_OUTPUT_HDMI: 991 case INTEL_OUTPUT_HDMI:
977 is_hdmi = true; 992 is_hdmi = true;
978 break; 993 break;
994 default:
995 DRM_ERROR("invalid output type.\n");
996 return 0;
979 } 997 }
980 } 998 }
981 999
@@ -992,8 +1010,10 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
992 } 1010 }
993 1011
994 drm_mode_debug_printmodeline(adjusted_mode); 1012 drm_mode_debug_printmodeline(adjusted_mode);
1013
1014 limit = cdv_intel_limit(crtc, refclk);
995 1015
996 ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, 1016 ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk,
997 &clock); 1017 &clock);
998 if (!ok) { 1018 if (!ok) {
999 dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); 1019 dev_err(dev->dev, "Couldn't find PLL settings for mode!\n");
@@ -1032,7 +1052,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
1032 REG_WRITE(map->dpll, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE); 1052 REG_WRITE(map->dpll, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
1033 REG_READ(map->dpll); 1053 REG_READ(map->dpll);
1034 1054
1035 cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds); 1055 cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds, ddi_select);
1036 1056
1037 udelay(150); 1057 udelay(150);
1038 1058
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index a86f87b9ddd..0c90f0316db 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -352,9 +352,11 @@ void cdv_hdmi_init(struct drm_device *dev,
352 switch (reg) { 352 switch (reg) {
353 case SDVOB: 353 case SDVOB:
354 ddc_bus = GPIOE; 354 ddc_bus = GPIOE;
355 psb_intel_encoder->ddi_select = DDI0_SELECT;
355 break; 356 break;
356 case SDVOC: 357 case SDVOC:
357 ddc_bus = GPIOD; 358 ddc_bus = GPIOD;
359 psb_intel_encoder->ddi_select = DDI1_SELECT;
358 break; 360 break;
359 default: 361 default:
360 DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); 362 DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index ebe1a28f60e..7b357b04d4e 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -133,6 +133,11 @@ struct psb_intel_encoder {
133 void (*hot_plug)(struct psb_intel_encoder *); 133 void (*hot_plug)(struct psb_intel_encoder *);
134 int crtc_mask; 134 int crtc_mask;
135 int clone_mask; 135 int clone_mask;
136 u32 ddi_select; /* Channel info */
137#define DDI0_SELECT 0x01
138#define DDI1_SELECT 0x02
139#define DP_MASK 0x8000;
140#define DDI_MASK 0x03
136 void *dev_priv; /* For sdvo_priv, lvds_priv, etc... */ 141 void *dev_priv; /* For sdvo_priv, lvds_priv, etc... */
137 142
138 /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's 143 /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's