Skip to content

Commit

Permalink
gma500: Program the DPLL lane based on the selected digitial port
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Zhao Yakui authored and Dave Airlie committed Aug 23, 2012
1 parent 25e9dc6 commit d667609
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 31 deletions.
82 changes: 51 additions & 31 deletions drivers/gpu/drm/gma500/cdv_intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,14 @@ struct cdv_intel_clock_t {
struct cdv_intel_limit_t {
struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1;
struct cdv_intel_p2_t p2;
bool (*find_pll)(const struct cdv_intel_limit_t *, struct drm_crtc *,
int, int, struct cdv_intel_clock_t *);
};

static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
struct drm_crtc *crtc, int target, int refclk,
struct cdv_intel_clock_t *best_clock);

#define CDV_LIMIT_SINGLE_LVDS_96 0
#define CDV_LIMIT_SINGLE_LVDS_100 1
#define CDV_LIMIT_DAC_HDMI_27 2
Expand All @@ -76,6 +82,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p1 = {.min = 2, .max = 10},
.p2 = {.dot_limit = 200000,
.p2_slow = 14, .p2_fast = 14},
.find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_SINGLE_LVDS_100MHz */
.dot = {.min = 20000, .max = 115500},
Expand All @@ -90,6 +97,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
* is 80-224Mhz. Prefer single channel as much as possible.
*/
.p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14},
.find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_DAC_HDMI_27MHz */
.dot = {.min = 20000, .max = 400000},
Expand All @@ -101,6 +109,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p = {.min = 5, .max = 90},
.p1 = {.min = 1, .max = 9},
.p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
.find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_DAC_HDMI_96MHz */
.dot = {.min = 20000, .max = 400000},
Expand All @@ -112,6 +121,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p = {.min = 5, .max = 100},
.p1 = {.min = 1, .max = 10},
.p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
.find_pll = cdv_intel_find_best_PLL,
},
};

Expand Down Expand Up @@ -216,7 +226,7 @@ static void cdv_sb_reset(struct drm_device *dev)
*/
static int
cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
struct cdv_intel_clock_t *clock, bool is_lvds)
struct cdv_intel_clock_t *clock, bool is_lvds, u32 ddi_select)
{
struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_crtc->pipe;
Expand Down Expand Up @@ -336,30 +346,33 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
if (ret)
return ret;

lane_reg = PSB_LANE0;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

lane_reg = PSB_LANE1;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

lane_reg = PSB_LANE2;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

lane_reg = PSB_LANE3;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

if (ddi_select) {
if ((ddi_select & DDI_MASK) == DDI0_SELECT) {
lane_reg = PSB_LANE0;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

lane_reg = PSB_LANE1;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);
} else {
lane_reg = PSB_LANE2;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);

lane_reg = PSB_LANE3;
cdv_sb_read(dev, lane_reg, &lane_value);
lane_value &= ~(LANE_PLL_MASK);
lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
cdv_sb_write(dev, lane_reg, lane_value);
}
}
return 0;
}

Expand Down Expand Up @@ -438,13 +451,12 @@ static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc,
return true;
}

static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target,
int refclk,
struct cdv_intel_clock_t *best_clock)
static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
struct drm_crtc *crtc, int target, int refclk,
struct cdv_intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct cdv_intel_clock_t clock;
const struct cdv_intel_limit_t *limit = cdv_intel_limit(crtc, refclk);
int err = target;


Expand Down Expand Up @@ -954,6 +966,8 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
bool is_hdmi = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
const struct cdv_intel_limit_t *limit;
u32 ddi_select = 0;

list_for_each_entry(connector, &mode_config->connector_list, head) {
struct psb_intel_encoder *psb_intel_encoder =
Expand All @@ -963,6 +977,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
|| connector->encoder->crtc != crtc)
continue;

ddi_select = psb_intel_encoder->ddi_select;
switch (psb_intel_encoder->type) {
case INTEL_OUTPUT_LVDS:
is_lvds = true;
Expand All @@ -976,6 +991,9 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_HDMI:
is_hdmi = true;
break;
default:
DRM_ERROR("invalid output type.\n");
return 0;
}
}

Expand All @@ -992,8 +1010,10 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}

drm_mode_debug_printmodeline(adjusted_mode);

limit = cdv_intel_limit(crtc, refclk);

ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk,
&clock);
if (!ok) {
dev_err(dev->dev, "Couldn't find PLL settings for mode!\n");
Expand Down Expand Up @@ -1032,7 +1052,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
REG_WRITE(map->dpll, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
REG_READ(map->dpll);

cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds);
cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds, ddi_select);

udelay(150);

Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/gma500/cdv_intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,11 @@ void cdv_hdmi_init(struct drm_device *dev,
switch (reg) {
case SDVOB:
ddc_bus = GPIOE;
psb_intel_encoder->ddi_select = DDI0_SELECT;
break;
case SDVOC:
ddc_bus = GPIOD;
psb_intel_encoder->ddi_select = DDI1_SELECT;
break;
default:
DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/gma500/psb_intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ struct psb_intel_encoder {
void (*hot_plug)(struct psb_intel_encoder *);
int crtc_mask;
int clone_mask;
u32 ddi_select; /* Channel info */
#define DDI0_SELECT 0x01
#define DDI1_SELECT 0x02
#define DP_MASK 0x8000;
#define DDI_MASK 0x03
void *dev_priv; /* For sdvo_priv, lvds_priv, etc... */

/* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's
Expand Down

0 comments on commit d667609

Please sign in to comment.