Commit f5732e66 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2018-03-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes

sun4i fixes on clk, division by zero and LVDS.

* tag 'drm-misc-fixes-2018-03-07' of git://anongit.freedesktop.org/drm/drm-misc:
  drm/sun4i: crtc: Call drm_crtc_vblank_on / drm_crtc_vblank_off
  drm/sun4i: rgb: Fix potential division by zero
  drm/sun4i: tcon: Reduce the scope of the LVDS error a bit
  drm/sun4i: Release exclusive clock lock when disabling TCON
  drm/sun4i: Fix dclk_set_phase
parents aa87d62f fd00c4ee
...@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, ...@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
DRM_DEBUG_DRIVER("Disabling the CRTC\n"); DRM_DEBUG_DRIVER("Disabling the CRTC\n");
drm_crtc_vblank_off(crtc);
sun4i_tcon_set_status(scrtc->tcon, encoder, false); sun4i_tcon_set_status(scrtc->tcon, encoder, false);
if (crtc->state->event && !crtc->state->active) { if (crtc->state->event && !crtc->state->active) {
...@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, ...@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
DRM_DEBUG_DRIVER("Enabling the CRTC\n"); DRM_DEBUG_DRIVER("Enabling the CRTC\n");
sun4i_tcon_set_status(scrtc->tcon, encoder, true); sun4i_tcon_set_status(scrtc->tcon, encoder, true);
drm_crtc_vblank_on(crtc);
} }
static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
......
...@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) ...@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw)
static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees)
{ {
struct sun4i_dclk *dclk = hw_to_dclk(hw); struct sun4i_dclk *dclk = hw_to_dclk(hw);
u32 val = degrees / 120;
val <<= 28;
regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG,
GENMASK(29, 28), GENMASK(29, 28),
degrees / 120); val);
return 0; return 0;
} }
......
...@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, ...@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
DRM_DEBUG_DRIVER("Vertical parameters OK\n"); DRM_DEBUG_DRIVER("Vertical parameters OK\n");
tcon->dclk_min_div = 6;
tcon->dclk_max_div = 127;
rounded_rate = clk_round_rate(tcon->dclk, rate); rounded_rate = clk_round_rate(tcon->dclk, rate);
if (rounded_rate < rate) if (rounded_rate < rate)
return MODE_CLOCK_LOW; return MODE_CLOCK_LOW;
......
...@@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, ...@@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
return; return;
} }
if (enabled) if (enabled) {
clk_prepare_enable(clk); clk_prepare_enable(clk);
else } else {
clk_rate_exclusive_put(clk);
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
}
} }
static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
...@@ -873,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, ...@@ -873,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
return ret; return ret;
} }
/* if (tcon->quirks->supports_lvds) {
* This can only be made optional since we've had DT nodes /*
* without the LVDS reset properties. * This can only be made optional since we've had DT
* * nodes without the LVDS reset properties.
* If the property is missing, just disable LVDS, and print a *
* warning. * If the property is missing, just disable LVDS, and
*/ * print a warning.
tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); */
if (IS_ERR(tcon->lvds_rst)) { tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
dev_err(dev, "Couldn't get our reset line\n"); if (IS_ERR(tcon->lvds_rst)) {
return PTR_ERR(tcon->lvds_rst); dev_err(dev, "Couldn't get our reset line\n");
} else if (tcon->lvds_rst) { return PTR_ERR(tcon->lvds_rst);
has_lvds_rst = true; } else if (tcon->lvds_rst) {
reset_control_reset(tcon->lvds_rst); has_lvds_rst = true;
} else { reset_control_reset(tcon->lvds_rst);
has_lvds_rst = false; } else {
} has_lvds_rst = false;
}
/* /*
* This can only be made optional since we've had DT nodes * This can only be made optional since we've had DT
* without the LVDS reset properties. * nodes without the LVDS reset properties.
* *
* If the property is missing, just disable LVDS, and print a * If the property is missing, just disable LVDS, and
* warning. * print a warning.
*/ */
if (tcon->quirks->has_lvds_alt) { if (tcon->quirks->has_lvds_alt) {
tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
if (IS_ERR(tcon->lvds_pll)) { if (IS_ERR(tcon->lvds_pll)) {
if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
has_lvds_alt = false; has_lvds_alt = false;
} else {
dev_err(dev, "Couldn't get the LVDS PLL\n");
return PTR_ERR(tcon->lvds_pll);
}
} else { } else {
dev_err(dev, "Couldn't get the LVDS PLL\n"); has_lvds_alt = true;
return PTR_ERR(tcon->lvds_pll);
} }
} else {
has_lvds_alt = true;
} }
}
if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { if (!has_lvds_rst ||
dev_warn(dev, (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
"Missing LVDS properties, Please upgrade your DT\n"); dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");
dev_warn(dev, "LVDS output disabled\n"); dev_warn(dev, "LVDS output disabled\n");
can_lvds = false; can_lvds = false;
} else {
can_lvds = true;
}
} else { } else {
can_lvds = true; can_lvds = false;
} }
ret = sun4i_tcon_init_clocks(dev, tcon); ret = sun4i_tcon_init_clocks(dev, tcon);
...@@ -1137,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { ...@@ -1137,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
}; };
static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
/* nothing is supported */ .supports_lvds = true,
}; };
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
......
...@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { ...@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks {
bool has_channel_1; /* a33 does not have channel 1 */ bool has_channel_1; /* a33 does not have channel 1 */
bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */
bool needs_de_be_mux; /* sun6i needs mux to select backend */ bool needs_de_be_mux; /* sun6i needs mux to select backend */
bool supports_lvds; /* Does the TCON support an LVDS output? */
/* callback to handle tcon muxing options */ /* callback to handle tcon muxing options */
int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment