Commit 45e88f99 authored by Maxime Ripard's avatar Maxime Ripard

drm/sun4i: tcon: Don't rely on encoders to enable the TCON

So far, we've required all the TCON-connected encoders to call the TCON
enable and disable functions.

This was made this way because in the RGB/LVDS case, the TCON is the CRTC
and the encoder. However, in all the other cases (HDMI, TV, DSI, etc.), we
have another encoder down the road that needs to be programmed.

We also needed to know which channel the encoder is connected to, which is
encoder-specific.

The CRTC's enable and disable callbacks can work just fine for our use
case, and we can get the channel to use just by looking at the type of
encoder, since that is fixed. Implement those callbacks, which will
remove some of the encoder boilerplate.
Reviewed-by: default avatarChen-Yu Tsai <wens@csie.org>
Signed-off-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Link: https://patchwork.freedesktop.org/patch/msgid/90b4396e19b3eca61b2ebfdae0672074b88ad74d.1508231063.git-series.maxime.ripard@free-electrons.com
parent 961c645c
...@@ -30,6 +30,22 @@ ...@@ -30,6 +30,22 @@
#include "sunxi_engine.h" #include "sunxi_engine.h"
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
/*
* While this isn't really working in the DRM theory, in practice we
* can only ever have one encoder per TCON since we have a mux in our
* TCON.
*/
static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
{
struct drm_encoder *encoder;
drm_for_each_encoder(encoder, crtc->dev)
if (encoder->crtc == crtc)
return encoder;
return NULL;
}
static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_state) struct drm_crtc_state *old_state)
{ {
...@@ -72,11 +88,12 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -72,11 +88,12 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state) struct drm_crtc_state *old_state)
{ {
struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
DRM_DEBUG_DRIVER("Disabling the CRTC\n"); DRM_DEBUG_DRIVER("Disabling the CRTC\n");
sun4i_tcon_disable(scrtc->tcon); sun4i_tcon_set_status(scrtc->tcon, encoder, false);
if (crtc->state->event && !crtc->state->active) { if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock); spin_lock_irq(&crtc->dev->event_lock);
...@@ -90,11 +107,12 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, ...@@ -90,11 +107,12 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state) struct drm_crtc_state *old_state)
{ {
struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
DRM_DEBUG_DRIVER("Enabling the CRTC\n"); DRM_DEBUG_DRIVER("Enabling the CRTC\n");
sun4i_tcon_enable(scrtc->tcon); sun4i_tcon_set_status(scrtc->tcon, encoder, true);
} }
static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
......
...@@ -86,8 +86,6 @@ static int sun4i_hdmi_atomic_check(struct drm_encoder *encoder, ...@@ -86,8 +86,6 @@ static int sun4i_hdmi_atomic_check(struct drm_encoder *encoder,
static void sun4i_hdmi_disable(struct drm_encoder *encoder) static void sun4i_hdmi_disable(struct drm_encoder *encoder)
{ {
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = crtc->tcon;
u32 val; u32 val;
DRM_DEBUG_DRIVER("Disabling the HDMI Output\n"); DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
...@@ -95,22 +93,16 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder) ...@@ -95,22 +93,16 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder)
val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG); val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
val &= ~SUN4I_HDMI_VID_CTRL_ENABLE; val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;
writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
sun4i_tcon_channel_disable(tcon, 1);
} }
static void sun4i_hdmi_enable(struct drm_encoder *encoder) static void sun4i_hdmi_enable(struct drm_encoder *encoder)
{ {
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = crtc->tcon;
u32 val = 0; u32 val = 0;
DRM_DEBUG_DRIVER("Enabling the HDMI Output\n"); DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
sun4i_tcon_channel_enable(tcon, 1);
sun4i_hdmi_setup_avi_infoframes(hdmi, mode); sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI); val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END); val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
......
...@@ -134,13 +134,10 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder) ...@@ -134,13 +134,10 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling RGB output\n"); DRM_DEBUG_DRIVER("Enabling RGB output\n");
if (!IS_ERR(tcon->panel)) if (!IS_ERR(tcon->panel)) {
drm_panel_prepare(tcon->panel); drm_panel_prepare(tcon->panel);
sun4i_tcon_channel_enable(tcon, 0);
if (!IS_ERR(tcon->panel))
drm_panel_enable(tcon->panel); drm_panel_enable(tcon->panel);
}
} }
static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
...@@ -150,13 +147,10 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) ...@@ -150,13 +147,10 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Disabling RGB output\n"); DRM_DEBUG_DRIVER("Disabling RGB output\n");
if (!IS_ERR(tcon->panel)) if (!IS_ERR(tcon->panel)) {
drm_panel_disable(tcon->panel); drm_panel_disable(tcon->panel);
sun4i_tcon_channel_disable(tcon, 0);
if (!IS_ERR(tcon->panel))
drm_panel_unprepare(tcon->panel); drm_panel_unprepare(tcon->panel);
}
} }
static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder, static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
......
...@@ -35,66 +35,61 @@ ...@@ -35,66 +35,61 @@
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
#include "sunxi_engine.h" #include "sunxi_engine.h"
void sun4i_tcon_disable(struct sun4i_tcon *tcon) static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
bool enabled)
{ {
DRM_DEBUG_DRIVER("Disabling TCON\n"); struct clk *clk;
/* Disable the TCON */ switch (channel) {
regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, case 0:
SUN4I_TCON_GCTL_TCON_ENABLE, 0);
}
EXPORT_SYMBOL(sun4i_tcon_disable);
void sun4i_tcon_enable(struct sun4i_tcon *tcon)
{
DRM_DEBUG_DRIVER("Enabling TCON\n");
/* Enable the TCON */
regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
SUN4I_TCON_GCTL_TCON_ENABLE,
SUN4I_TCON_GCTL_TCON_ENABLE);
}
EXPORT_SYMBOL(sun4i_tcon_enable);
void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
{
DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
/* Disable the TCON's channel */
if (channel == 0) {
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
SUN4I_TCON0_CTL_TCON_ENABLE, 0); SUN4I_TCON0_CTL_TCON_ENABLE,
clk_disable_unprepare(tcon->dclk); enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
clk = tcon->dclk;
break;
case 1:
WARN_ON(!tcon->quirks->has_channel_1);
regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
SUN4I_TCON1_CTL_TCON_ENABLE,
enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
clk = tcon->sclk1;
break;
default:
DRM_WARN("Unknown channel... doing nothing\n");
return; return;
} }
WARN_ON(!tcon->quirks->has_channel_1); if (enabled)
regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, clk_prepare_enable(clk);
SUN4I_TCON1_CTL_TCON_ENABLE, 0); else
clk_disable_unprepare(tcon->sclk1); clk_disable_unprepare(clk);
} }
EXPORT_SYMBOL(sun4i_tcon_channel_disable);
void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel) void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
const struct drm_encoder *encoder,
bool enabled)
{ {
DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel); int channel;
/* Enable the TCON's channel */ switch (encoder->encoder_type) {
if (channel == 0) { case DRM_MODE_ENCODER_NONE:
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, channel = 0;
SUN4I_TCON0_CTL_TCON_ENABLE, break;
SUN4I_TCON0_CTL_TCON_ENABLE); case DRM_MODE_ENCODER_TMDS:
clk_prepare_enable(tcon->dclk); case DRM_MODE_ENCODER_TVDAC:
channel = 1;
break;
default:
DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
return; return;
} }
WARN_ON(!tcon->quirks->has_channel_1); regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON_GCTL_TCON_ENABLE,
SUN4I_TCON1_CTL_TCON_ENABLE, enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
SUN4I_TCON1_CTL_TCON_ENABLE);
clk_prepare_enable(tcon->sclk1); sun4i_tcon_channel_set_status(tcon, channel, enabled);
} }
EXPORT_SYMBOL(sun4i_tcon_channel_enable);
void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable) void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
{ {
......
...@@ -190,15 +190,9 @@ struct sun4i_tcon { ...@@ -190,15 +190,9 @@ struct sun4i_tcon {
struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
struct drm_panel *sun4i_tcon_find_panel(struct device_node *node); struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
/* Global Control */
void sun4i_tcon_disable(struct sun4i_tcon *tcon);
void sun4i_tcon_enable(struct sun4i_tcon *tcon);
/* Channel Control */
void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable); void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
void sun4i_tcon_set_status(struct sun4i_tcon *crtc,
const struct drm_encoder *encoder, bool enable);
/* Mode Related Controls */ /* Mode Related Controls */
void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel, void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
......
...@@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder) ...@@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
{ {
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc); struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = crtc->tcon;
DRM_DEBUG_DRIVER("Disabling the TV Output\n"); DRM_DEBUG_DRIVER("Disabling the TV Output\n");
sun4i_tcon_channel_disable(tcon, 1);
regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG, regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE, SUN4I_TVE_EN_ENABLE,
0); 0);
...@@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder) ...@@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
{ {
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc); struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = crtc->tcon;
DRM_DEBUG_DRIVER("Enabling the TV Output\n"); DRM_DEBUG_DRIVER("Enabling the TV Output\n");
...@@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder) ...@@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG, regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE, SUN4I_TVE_EN_ENABLE,
SUN4I_TVE_EN_ENABLE); SUN4I_TVE_EN_ENABLE);
sun4i_tcon_channel_enable(tcon, 1);
} }
static void sun4i_tv_mode_set(struct drm_encoder *encoder, static void sun4i_tv_mode_set(struct drm_encoder *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