On Wed, Oct 25, 2023 at 06:39:57PM +0800, Keith Zhao wrote:
+static int starfive_hdmi_setup(struct starfive_hdmi *hdmi,
struct drm_display_mode *mode)
+{
- hdmi_modb(hdmi, STARFIVE_BIAS_CONTROL, STARFIVE_BIAS_ENABLE, STARFIVE_BIAS_ENABLE);
- hdmi_writeb(hdmi, STARFIVE_RX_CONTROL, STARFIVE_RX_ENABLE);
- hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
You're never using that variable.
- hdmi->tmds_rate = mode->clock * 1000;
- starfive_hdmi_phy_clk_set_rate(hdmi);
- while (!(hdmi_readb(hdmi, STARFIVE_PRE_PLL_LOCK_STATUS) & 0x1))
continue;
- while (!(hdmi_readb(hdmi, STARFIVE_POST_PLL_LOCK_STATUS) & 0x1))
continue;
- /*turn on LDO*/
- hdmi_writeb(hdmi, STARFIVE_LDO_CONTROL, STARFIVE_LDO_ENABLE);
- /*turn on serializer*/
- hdmi_writeb(hdmi, STARFIVE_SERIALIER_CONTROL, STARFIVE_SERIALIER_ENABLE);
- starfive_hdmi_tx_phy_power_down(hdmi);
- starfive_hdmi_config_video_timing(hdmi, mode);
- starfive_hdmi_tx_phy_power_on(hdmi);
- starfive_hdmi_tmds_driver_on(hdmi);
- starfive_hdmi_sync_tmds(hdmi);
- return 0;
+}
+static void starfive_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
+{
- struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
- drm_mode_copy(&hdmi->previous_mode, adj_mode);
+}
You're never using that field, and it's not the previous mode, but the current mode.
+static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder) +{
- struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
- int ret, idx;
- struct drm_device *drm = hdmi->connector.dev;
- if (drm && !drm_dev_enter(drm, &idx))
return;
- ret = pm_runtime_get_sync(hdmi->dev);
- if (ret < 0)
return;
pm_runtime_resume_and_get is what you want here
- mdelay(10);
???
Sprinkling delays here and there isn't great. What is the issue this is trying to workaround?
- starfive_hdmi_setup(hdmi, mode);
- if (drm)
drm_dev_exit(idx);
+}
+static void starfive_hdmi_encoder_disable(struct drm_encoder *encoder) +{
- struct starfive_hdmi *hdmi = encoder_to_hdmi(encoder);
- int idx;
- struct drm_device *drm = hdmi->connector.dev;
- if (drm && !drm_dev_enter(drm, &idx))
return;
- pm_runtime_put(hdmi->dev);
pm_runtime calls should be safe anytime. If you need to protect them through a drm_dev_enter call, that call should be in the pm_runtime hook itself.
- if (drm)
drm_dev_exit(idx);
+}
+static int +starfive_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
+{
- bool valid = false;
- struct drm_display_mode *mode = &crtc_state->adjusted_mode;
- struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
- vs_crtc_state->encoder_type = encoder->encoder_type;
- vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
Ok, so those two will always be ENCODER_TMDS and RGB888. Drop them from your CRTC state and use the proper defines there.
- const struct pre_pll_config *cfg = pre_pll_cfg_table;
- int pclk = mode->clock * 1000;
- for (; cfg->pixclock != 0; cfg++) {
if (pclk == cfg->pixclock) {
if (pclk > 297000000)
continue;
valid = true;
break;
}
- }
- return (valid) ? 0 : -EINVAL;
+}
+static const struct drm_encoder_helper_funcs starfive_hdmi_encoder_helper_funcs = {
- .enable = starfive_hdmi_encoder_enable,
- .disable = starfive_hdmi_encoder_disable,
- .mode_set = starfive_hdmi_encoder_mode_set,
- .atomic_check = starfive_hdmi_encoder_atomic_check,
+};
+static enum drm_connector_status +starfive_hdmi_connector_detect(struct drm_connector *connector, bool force) +{
- struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
- struct drm_device *drm = hdmi->connector.dev;
- int ret;
- int idx;
- if (drm && !drm_dev_enter(drm, &idx))
return connector_status_disconnected;
- ret = pm_runtime_get_sync(hdmi->dev);
- if (ret < 0)
return ret;
- ret = (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
connector_status_connected : connector_status_disconnected;
- pm_runtime_put(hdmi->dev);
- if (drm)
drm_dev_exit(idx);
- return ret;
+}
+static int starfive_hdmi_connector_get_modes(struct drm_connector *connector) +{
- struct starfive_hdmi *hdmi = connector_to_hdmi(connector);
- struct edid *edid;
- int ret = 0;
- if (!hdmi->ddc)
return 0;
- ret = pm_runtime_get_sync(hdmi->dev);
- if (ret < 0)
return ret;
- edid = drm_get_edid(connector, hdmi->ddc);
- if (edid) {
hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
You're not using that field anywhere, and it's available in drm_display_info already.
hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
Ditto
+struct hdmi_data_info {
- int vic;
- bool sink_is_hdmi;
- bool sink_has_audio;
- unsigned int enc_in_format;
You're not using it
- unsigned int enc_out_format;
Ditto
- unsigned int colorimetry;
Ditto
Which means that as things stands, you can get rid of that entire structure.
+};
+struct starfive_hdmi {
- struct device *dev;
- struct drm_device *drm_dev;
- struct drm_encoder encoder;
- struct drm_connector connector;
- struct starfive_hdmi_i2c *i2c;
- int irq;
- struct clk *sys_clk;
- struct clk *mclk;
- struct clk *bclk;
- struct reset_control *tx_rst;
- void __iomem *regs;
- struct i2c_adapter *ddc;
- unsigned long tmds_rate;
You're not using that either.
Maxime