forked from Minki/linux
- core: Make atomic_enable and disable optional for CRTC
- dw-hdmi: Lower max frequency for the Allwinner H6, SCDC configuration improvements for older controller versions - omap: a fix for the CEC clock management policy -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCXK9aTQAKCRDj7w1vZxhR xXKwAP9vwrBuyG0j7nK/uVPEHZYUgb41i9t+dC38wAWDcbb4swEAzGs+VEkqKvSt T9dJNxd1lbdYTRTOKkiRT40tuoiR2Q0= =NuDF -----END PGP SIGNATURE----- Merge tag 'drm-misc-fixes-2019-04-11' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes - core: Make atomic_enable and disable optional for CRTC - dw-hdmi: Lower max frequency for the Allwinner H6, SCDC configuration improvements for older controller versions - omap: a fix for the CEC clock management policy Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190411151658.orm46ccd5zmrw27l@flea
This commit is contained in:
commit
ffb5d6fe14
@ -1037,6 +1037,31 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
|
EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
|
||||||
|
|
||||||
|
/* Filter out invalid setups to avoid configuring SCDC and scrambling */
|
||||||
|
static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi)
|
||||||
|
{
|
||||||
|
struct drm_display_info *display = &hdmi->connector.display_info;
|
||||||
|
|
||||||
|
/* Completely disable SCDC support for older controllers */
|
||||||
|
if (hdmi->version < 0x200a)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Disable if SCDC is not supported, or if an HF-VSDB block is absent */
|
||||||
|
if (!display->hdmi.scdc.supported ||
|
||||||
|
!display->hdmi.scdc.scrambling.supported)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable if display only support low TMDS rates and scrambling
|
||||||
|
* for low rates is not supported either
|
||||||
|
*/
|
||||||
|
if (!display->hdmi.scdc.scrambling.low_rates &&
|
||||||
|
display->max_tmds_clock <= 340000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
|
* HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
|
||||||
* - The Source shall suspend transmission of the TMDS clock and data
|
* - The Source shall suspend transmission of the TMDS clock and data
|
||||||
@ -1055,7 +1080,7 @@ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
|
|||||||
unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
|
unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
|
||||||
|
|
||||||
/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
|
/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
|
||||||
if (hdmi->connector.display_info.hdmi.scdc.supported) {
|
if (dw_hdmi_support_scdc(hdmi)) {
|
||||||
if (mtmdsclock > HDMI14_MAX_TMDSCLK)
|
if (mtmdsclock > HDMI14_MAX_TMDSCLK)
|
||||||
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
|
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
|
||||||
else
|
else
|
||||||
@ -1579,8 +1604,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
|||||||
|
|
||||||
/* Set up HDMI_FC_INVIDCONF */
|
/* Set up HDMI_FC_INVIDCONF */
|
||||||
inv_val = (hdmi->hdmi_data.hdcp_enable ||
|
inv_val = (hdmi->hdmi_data.hdcp_enable ||
|
||||||
vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
|
(dw_hdmi_support_scdc(hdmi) &&
|
||||||
hdmi_info->scdc.scrambling.low_rates ?
|
(vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
|
||||||
|
hdmi_info->scdc.scrambling.low_rates)) ?
|
||||||
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
|
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
|
||||||
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
|
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
|
||||||
|
|
||||||
@ -1646,7 +1672,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Scrambling Control */
|
/* Scrambling Control */
|
||||||
if (hdmi_info->scdc.supported) {
|
if (dw_hdmi_support_scdc(hdmi)) {
|
||||||
if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
|
if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
|
||||||
hdmi_info->scdc.scrambling.low_rates) {
|
hdmi_info->scdc.scrambling.low_rates) {
|
||||||
/*
|
/*
|
||||||
|
@ -1034,7 +1034,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
|
|||||||
funcs->atomic_disable(crtc, old_crtc_state);
|
funcs->atomic_disable(crtc, old_crtc_state);
|
||||||
else if (funcs->disable)
|
else if (funcs->disable)
|
||||||
funcs->disable(crtc);
|
funcs->disable(crtc);
|
||||||
else
|
else if (funcs->dpms)
|
||||||
funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
|
funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||||
|
|
||||||
if (!(dev->irq_enabled && dev->num_crtcs))
|
if (!(dev->irq_enabled && dev->num_crtcs))
|
||||||
@ -1277,10 +1277,9 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
|
|||||||
if (new_crtc_state->enable) {
|
if (new_crtc_state->enable) {
|
||||||
DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
|
DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
|
||||||
crtc->base.id, crtc->name);
|
crtc->base.id, crtc->name);
|
||||||
|
|
||||||
if (funcs->atomic_enable)
|
if (funcs->atomic_enable)
|
||||||
funcs->atomic_enable(crtc, old_crtc_state);
|
funcs->atomic_enable(crtc, old_crtc_state);
|
||||||
else
|
else if (funcs->commit)
|
||||||
funcs->commit(crtc);
|
funcs->commit(crtc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,7 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||||||
REG_FLD_MOD(core->base, HDMI_CORE_SYS_INTR_UNMASK4, 0, 3, 3);
|
REG_FLD_MOD(core->base, HDMI_CORE_SYS_INTR_UNMASK4, 0, 3, 3);
|
||||||
hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE);
|
hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE);
|
||||||
hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE);
|
hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE);
|
||||||
|
REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0);
|
||||||
hdmi4_core_disable(core);
|
hdmi4_core_disable(core);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -182,16 +183,24 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize CEC clock divider: CEC needs 2MHz clock hence
|
||||||
|
* set the divider to 24 to get 48/24=2MHz clock
|
||||||
|
*/
|
||||||
|
REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0x18, 5, 0);
|
||||||
|
|
||||||
/* Clear TX FIFO */
|
/* Clear TX FIFO */
|
||||||
if (!hdmi_cec_clear_tx_fifo(adap)) {
|
if (!hdmi_cec_clear_tx_fifo(adap)) {
|
||||||
pr_err("cec-%s: could not clear TX FIFO\n", adap->name);
|
pr_err("cec-%s: could not clear TX FIFO\n", adap->name);
|
||||||
return -EIO;
|
err = -EIO;
|
||||||
|
goto err_disable_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear RX FIFO */
|
/* Clear RX FIFO */
|
||||||
if (!hdmi_cec_clear_rx_fifo(adap)) {
|
if (!hdmi_cec_clear_rx_fifo(adap)) {
|
||||||
pr_err("cec-%s: could not clear RX FIFO\n", adap->name);
|
pr_err("cec-%s: could not clear RX FIFO\n", adap->name);
|
||||||
return -EIO;
|
err = -EIO;
|
||||||
|
goto err_disable_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear CEC interrupts */
|
/* Clear CEC interrupts */
|
||||||
@ -236,6 +245,12 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||||||
hdmi_write_reg(core->base, HDMI_CEC_INT_STATUS_1, temp);
|
hdmi_write_reg(core->base, HDMI_CEC_INT_STATUS_1, temp);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_disable_clk:
|
||||||
|
REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0);
|
||||||
|
hdmi4_core_disable(core);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
static int hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||||
@ -333,11 +348,8 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
|
|||||||
return ret;
|
return ret;
|
||||||
core->wp = wp;
|
core->wp = wp;
|
||||||
|
|
||||||
/*
|
/* Disable clock initially, hdmi_cec_adap_enable() manages it */
|
||||||
* Initialize CEC clock divider: CEC needs 2MHz clock hence
|
REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0, 5, 0);
|
||||||
* set the devider to 24 to get 48/24=2MHz clock
|
|
||||||
*/
|
|
||||||
REG_FLD_MOD(core->wp->base, HDMI_WP_CLK, 0x18, 5, 0);
|
|
||||||
|
|
||||||
ret = cec_register_adapter(core->adap, &pdev->dev);
|
ret = cec_register_adapter(core->adap, &pdev->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -708,7 +708,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
|
|||||||
else
|
else
|
||||||
acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
|
||||||
/*
|
/*
|
||||||
* The I2S input word length is twice the lenght given in the IEC-60958
|
* The I2S input word length is twice the length given in the IEC-60958
|
||||||
* status word. If the word size is greater than
|
* status word. If the word size is greater than
|
||||||
* 20 bits, increment by one.
|
* 20 bits, increment by one.
|
||||||
*/
|
*/
|
||||||
|
@ -48,8 +48,13 @@ static enum drm_mode_status
|
|||||||
sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector,
|
sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector,
|
||||||
const struct drm_display_mode *mode)
|
const struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
/* This is max for HDMI 2.0b (4K@60Hz) */
|
/*
|
||||||
if (mode->clock > 594000)
|
* Controller support maximum of 594 MHz, which correlates to
|
||||||
|
* 4K@60Hz 4:4:4 or RGB. However, for frequencies greater than
|
||||||
|
* 340 MHz scrambling has to be enabled. Because scrambling is
|
||||||
|
* not yet implemented, just limit to 340 MHz for now.
|
||||||
|
*/
|
||||||
|
if (mode->clock > 340000)
|
||||||
return MODE_CLOCK_HIGH;
|
return MODE_CLOCK_HIGH;
|
||||||
|
|
||||||
return MODE_OK;
|
return MODE_OK;
|
||||||
|
@ -227,7 +227,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
|
|||||||
|
|
||||||
err_unregister_gates:
|
err_unregister_gates:
|
||||||
for (i = 0; i < CLK_NUM; i++)
|
for (i = 0; i < CLK_NUM; i++)
|
||||||
if (clk_data->hws[i])
|
if (!IS_ERR_OR_NULL(clk_data->hws[i]))
|
||||||
clk_hw_unregister_gate(clk_data->hws[i]);
|
clk_hw_unregister_gate(clk_data->hws[i]);
|
||||||
clk_disable_unprepare(tcon_top->bus);
|
clk_disable_unprepare(tcon_top->bus);
|
||||||
err_assert_reset:
|
err_assert_reset:
|
||||||
@ -245,7 +245,8 @@ static void sun8i_tcon_top_unbind(struct device *dev, struct device *master,
|
|||||||
|
|
||||||
of_clk_del_provider(dev->of_node);
|
of_clk_del_provider(dev->of_node);
|
||||||
for (i = 0; i < CLK_NUM; i++)
|
for (i = 0; i < CLK_NUM; i++)
|
||||||
clk_hw_unregister_gate(clk_data->hws[i]);
|
if (clk_data->hws[i])
|
||||||
|
clk_hw_unregister_gate(clk_data->hws[i]);
|
||||||
|
|
||||||
clk_disable_unprepare(tcon_top->bus);
|
clk_disable_unprepare(tcon_top->bus);
|
||||||
reset_control_assert(tcon_top->rst);
|
reset_control_assert(tcon_top->rst);
|
||||||
|
@ -418,6 +418,8 @@ struct drm_crtc_helper_funcs {
|
|||||||
* Drivers can use the @old_crtc_state input parameter if the operations
|
* Drivers can use the @old_crtc_state input parameter if the operations
|
||||||
* needed to enable the CRTC don't depend solely on the new state but
|
* needed to enable the CRTC don't depend solely on the new state but
|
||||||
* also on the transition between the old state and the new state.
|
* also on the transition between the old state and the new state.
|
||||||
|
*
|
||||||
|
* This function is optional.
|
||||||
*/
|
*/
|
||||||
void (*atomic_enable)(struct drm_crtc *crtc,
|
void (*atomic_enable)(struct drm_crtc *crtc,
|
||||||
struct drm_crtc_state *old_crtc_state);
|
struct drm_crtc_state *old_crtc_state);
|
||||||
@ -441,6 +443,8 @@ struct drm_crtc_helper_funcs {
|
|||||||
* parameter @old_crtc_state which could be used to access the old
|
* parameter @old_crtc_state which could be used to access the old
|
||||||
* state. Atomic drivers should consider to use this one instead
|
* state. Atomic drivers should consider to use this one instead
|
||||||
* of @disable.
|
* of @disable.
|
||||||
|
*
|
||||||
|
* This function is optional.
|
||||||
*/
|
*/
|
||||||
void (*atomic_disable)(struct drm_crtc *crtc,
|
void (*atomic_disable)(struct drm_crtc *crtc,
|
||||||
struct drm_crtc_state *old_crtc_state);
|
struct drm_crtc_state *old_crtc_state);
|
||||||
|
Loading…
Reference in New Issue
Block a user