diff options
author | Zhao Yakui <yakui.zhao@intel.com> | 2012-08-08 09:53:48 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-08-23 19:28:58 -0400 |
commit | d66760962d75af12697d5197b3e97d51fe64169c (patch) | |
tree | 8fe91ce6d5592b3ecf9e1327d5d442d5b6a37224 /drivers/gpu/drm/gma500 | |
parent | 25e9dc69709afad2be8de4ac2ecd6015356936ca (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.c | 82 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_intel_drv.h | 5 |
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 { | |||
57 | struct cdv_intel_limit_t { | 57 | struct 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 | ||
64 | static 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 | */ |
217 | static int | 227 | static int |
218 | cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, | 228 | cdv_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 | ||
441 | static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target, | 454 | static 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 |