From 7a5cd45fab0a2671aa4ea6d8fb80cea268387176 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 14 Dec 2024 15:37:05 +0200 Subject: drm/encoder_slave: make mode_valid accept const struct drm_display_mode The mode_valid() callbacks of drm_encoder, drm_crtc and drm_bridge accept const struct drm_display_mode argument. Change the mode_valid callback of drm_encoder_slave to also accept const argument. Reviewed-by: Laurent Pinchart Reviewed-by: Lyude Paul Reviewed-by: Maxime Ripard Reviewed-by: Thomas Zimmermann Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20241214-drm-connector-mode-valid-const-v2-1-4f9498a4c822@linaro.org Signed-off-by: Dmitry Baryshkov --- include/drm/drm_encoder_slave.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_encoder_slave.h b/include/drm/drm_encoder_slave.h index 49172166a164..b526643833dc 100644 --- a/include/drm/drm_encoder_slave.h +++ b/include/drm/drm_encoder_slave.h @@ -85,7 +85,7 @@ struct drm_encoder_slave_funcs { * @mode_valid: Analogous to &drm_encoder_helper_funcs @mode_valid. */ int (*mode_valid)(struct drm_encoder *encoder, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); /** * @mode_set: Analogous to &drm_encoder_helper_funcs @mode_set * callback. Wrapped by drm_i2c_encoder_mode_set(). -- cgit v1.2.3 From 66df9debcb29d14802912ed79a9cf9ba721b51a4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 14 Dec 2024 15:37:08 +0200 Subject: drm/connector: make mode_valid_ctx take a const struct drm_display_mode The mode_valid() callbacks of drm_encoder, drm_crtc and drm_bridge take a const struct drm_display_mode argument. Change the mode_valid_ctx callback of drm_connector to also take a const argument. Acked-by: Jani Nikula Reviewed-by: Laurent Pinchart Reviewed-by: Maxime Ripard Reviewed-by: Thomas Zimmermann Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20241214-drm-connector-mode-valid-const-v2-4-4f9498a4c822@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 6 +++--- include/drm/drm_modeset_helper_vtables.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 56ca571e534c..0812a3fd8b37 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1432,9 +1432,9 @@ static int intel_dp_mst_get_modes(struct drm_connector *connector) static int intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, - struct drm_display_mode *mode, - struct drm_modeset_acquire_ctx *ctx, - enum drm_mode_status *status) + const struct drm_display_mode *mode, + struct drm_modeset_acquire_ctx *ctx, + enum drm_mode_status *status) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index ec59015aec3c..fa9ee6a128be 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -1006,7 +1006,7 @@ struct drm_connector_helper_funcs { * */ int (*mode_valid_ctx)(struct drm_connector *connector, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_modeset_acquire_ctx *ctx, enum drm_mode_status *status); -- cgit v1.2.3 From 26d6fd81916e62d2b0568d9756e5f9c33f0f9b7a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 14 Dec 2024 15:37:09 +0200 Subject: drm/connector: make mode_valid take a const struct drm_display_mode The mode_valid() callbacks of drm_encoder, drm_crtc and drm_bridge take a const struct drm_display_mode argument. Change the mode_valid callback of drm_connector to also take a const argument. Acked-by: Jani Nikula Reviewed-by: Liviu Dudau Reviewed-by: Raphael Gallais-Pou Reviewed-by: Laurent Pinchart Reviewed-by: Lyude Paul Reviewed-by: Maxime Ripard Reviewed-by: Thomas Zimmermann Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20241214-drm-connector-mode-valid-const-v2-5-4f9498a4c822@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/atombios_dp.c | 2 +- drivers/gpu/drm/amd/amdgpu/atombios_dp.h | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +- drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c | 2 +- drivers/gpu/drm/arm/malidp_mw.c | 2 +- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 +- drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 2 +- drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 7 ------- drivers/gpu/drm/display/drm_bridge_connector.c | 2 +- drivers/gpu/drm/display/drm_hdmi_state_helper.c | 2 +- drivers/gpu/drm/drm_crtc_helper_internal.h | 2 +- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_crt.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_dp.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 2 +- drivers/gpu/drm/gma500/oaktrail_hdmi.c | 2 +- drivers/gpu/drm/gma500/psb_intel_drv.h | 2 +- drivers/gpu/drm/gma500/psb_intel_lvds.c | 2 +- drivers/gpu/drm/gma500/psb_intel_sdvo.c | 2 +- drivers/gpu/drm/i915/display/dvo_ch7017.c | 2 +- drivers/gpu/drm/i915/display/dvo_ch7xxx.c | 2 +- drivers/gpu/drm/i915/display/dvo_ivch.c | 2 +- drivers/gpu/drm/i915/display/dvo_ns2501.c | 2 +- drivers/gpu/drm/i915/display/dvo_sil164.c | 2 +- drivers/gpu/drm/i915/display/dvo_tfp410.c | 2 +- drivers/gpu/drm/i915/display/icl_dsi.c | 2 +- drivers/gpu/drm/i915/display/intel_crt.c | 2 +- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_dsi.c | 2 +- drivers/gpu/drm/i915/display/intel_dsi.h | 2 +- drivers/gpu/drm/i915/display/intel_dvo.c | 2 +- drivers/gpu/drm/i915/display/intel_dvo_dev.h | 2 +- drivers/gpu/drm/i915/display/intel_hdmi.c | 2 +- drivers/gpu/drm/i915/display/intel_lvds.c | 2 +- drivers/gpu/drm/i915/display/intel_sdvo.c | 2 +- drivers/gpu/drm/i915/display/intel_tv.c | 2 +- drivers/gpu/drm/i915/display/vlv_dsi.c | 2 +- drivers/gpu/drm/imx/ipuv3/imx-tve.c | 2 +- drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +- drivers/gpu/drm/qxl/qxl_display.c | 2 +- drivers/gpu/drm/radeon/atombios_dp.c | 2 +- drivers/gpu/drm/radeon/radeon_connectors.c | 10 +++++----- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +- drivers/gpu/drm/rockchip/inno_hdmi.c | 4 ++-- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 +- drivers/gpu/drm/sti/sti_dvo.c | 2 +- drivers/gpu/drm/sti/sti_hda.c | 2 +- drivers/gpu/drm/sti/sti_hdmi.c | 2 +- drivers/gpu/drm/tegra/dsi.c | 2 +- drivers/gpu/drm/tegra/hdmi.c | 2 +- drivers/gpu/drm/tegra/sor.c | 2 +- drivers/gpu/drm/vc4/vc4_txp.c | 2 +- drivers/gpu/drm/virtio/virtgpu_display.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 +- include/drm/display/drm_hdmi_state_helper.h | 2 +- include/drm/drm_modeset_helper_vtables.h | 2 +- 66 files changed, 73 insertions(+), 80 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 344e0a9ee08a..5e375e9c4f5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -674,7 +674,7 @@ static int amdgpu_connector_lvds_get_modes(struct drm_connector *connector) } static enum drm_mode_status amdgpu_connector_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); @@ -839,7 +839,7 @@ static int amdgpu_connector_vga_get_modes(struct drm_connector *connector) } static enum drm_mode_status amdgpu_connector_vga_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); @@ -1196,7 +1196,7 @@ static void amdgpu_connector_dvi_force(struct drm_connector *connector) } static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); @@ -1464,7 +1464,7 @@ out: } static enum drm_mode_status amdgpu_connector_dp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 622634c08c7b..521b9faab180 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -430,7 +430,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector, } int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector_atom_dig *dig_connector; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.h b/drivers/gpu/drm/amd/amdgpu/atombios_dp.h index f59d85eaddf0..3e24acf8133f 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.h +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.h @@ -32,7 +32,7 @@ int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder, void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector, const struct drm_display_mode *mode); int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); bool amdgpu_atombios_dp_needs_link_train(struct amdgpu_connector *amdgpu_connector); void amdgpu_atombios_dp_set_rx_power_state(struct drm_connector *connector, u8 power_state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f92ad3b77c19..35c486ca74f6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7416,7 +7416,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, } enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { int result = MODE_ERROR; struct dc_sink *dc_sink; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 6464a8378387..2cf9f6ca20bc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -945,7 +945,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, int link_index); enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c index ebccb74306a7..e075a6b317cc 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c @@ -88,7 +88,7 @@ komeda_wb_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status komeda_wb_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct drm_mode_config *mode_config = &dev->mode_config; diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index 2577f0cef8fc..600af5ad81b1 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -43,7 +43,7 @@ static int malidp_mw_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status malidp_mw_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct drm_mode_config *mode_config = &dev->mode_config; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index eb5919b38263..fda66e7876b8 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -847,7 +847,7 @@ static int adv7511_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status adv7511_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct adv7511 *adv = connector_to_adv7511(connector); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index d081850e3c03..25345c3274e3 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -1619,7 +1619,7 @@ bool cdns_mhdp_bandwidth_ok(struct cdns_mhdp_device *mhdp, static enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn); diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index a3dcee62e7a5..a47aabf134fd 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -115,16 +115,9 @@ static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) return num_modes; } -static enum drm_mode_status ge_b850v3_lvds_mode_valid( - struct drm_connector *connector, struct drm_display_mode *mode) -{ - return MODE_OK; -} - static const struct drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = { .get_modes = ge_b850v3_lvds_get_modes, - .mode_valid = ge_b850v3_lvds_mode_valid, }; static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 32108307de66..0397e62f9cbc 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -327,7 +327,7 @@ static int drm_bridge_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status drm_bridge_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector); diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index cfc2aaee1da0..2691e8b3e480 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -539,7 +539,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check); */ enum drm_mode_status drm_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { unsigned long long clock; diff --git a/drivers/gpu/drm/drm_crtc_helper_internal.h b/drivers/gpu/drm/drm_crtc_helper_internal.h index 8059f65c5d6c..bae73936acf9 100644 --- a/drivers/gpu/drm/drm_crtc_helper_internal.h +++ b/drivers/gpu/drm/drm_crtc_helper_internal.h @@ -43,7 +43,7 @@ enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder, const struct drm_display_mode *mode); int drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_modeset_acquire_ctx *ctx, enum drm_mode_status *status); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 96b266b37ba4..080b55200614 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -202,7 +202,7 @@ enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder, int drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_modeset_acquire_ctx *ctx, enum drm_mode_status *status) { diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 176fd8871759..01813e11e6c6 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -931,7 +931,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) } static enum drm_mode_status hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct hdmi_context *hdata = connector_to_hdmi(connector); int ret; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index c418e8496bdf..84eff7519e32 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -63,7 +63,7 @@ static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->hdisplay & 0xf) return MODE_ERROR; diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 5a0acd914f76..06fe7480e7af 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -69,7 +69,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) } static enum drm_mode_status cdv_intel_crt_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index cc2ed9b3fd2d..53990d27c39f 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -505,7 +505,7 @@ static void cdv_intel_edp_backlight_off (struct gma_encoder *intel_encoder) static enum drm_mode_status cdv_intel_dp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 2d95e0471291..f2a3e37ef632 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -222,7 +222,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) } static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index f3a4517bdf27..9276e3676ba0 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -153,7 +153,7 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector) } static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index ed8626c73541..1cf394369127 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -514,7 +514,7 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode) } static enum drm_mode_status oaktrail_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 2499fd6a80c9..9dc9dcd1b09f 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -212,7 +212,7 @@ extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value); diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 138f153d38ba..9ad611b5956e 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -331,7 +331,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); struct gma_encoder *gma_encoder = gma_attached_encoder(connector); diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 8dafff963ca8..afda40fc4494 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1159,7 +1159,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) } static enum drm_mode_status psb_intel_sdvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); diff --git a/drivers/gpu/drm/i915/display/dvo_ch7017.c b/drivers/gpu/drm/i915/display/dvo_ch7017.c index 493e730c685b..206818f9ad49 100644 --- a/drivers/gpu/drm/i915/display/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/display/dvo_ch7017.c @@ -247,7 +247,7 @@ static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 160000) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c index 534b8544e0a4..10ab3cc73e58 100644 --- a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c @@ -276,7 +276,7 @@ static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/i915/display/dvo_ivch.c b/drivers/gpu/drm/i915/display/dvo_ivch.c index 0d5cce6051b1..d9c3152d4338 100644 --- a/drivers/gpu/drm/i915/display/dvo_ivch.c +++ b/drivers/gpu/drm/i915/display/dvo_ivch.c @@ -314,7 +314,7 @@ static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 112000) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/i915/display/dvo_ns2501.c b/drivers/gpu/drm/i915/display/dvo_ns2501.c index 9d47f8a93e94..cb619ffc974f 100644 --- a/drivers/gpu/drm/i915/display/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/display/dvo_ns2501.c @@ -524,7 +524,7 @@ static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { DRM_DEBUG_KMS ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", diff --git a/drivers/gpu/drm/i915/display/dvo_sil164.c b/drivers/gpu/drm/i915/display/dvo_sil164.c index a8dd40c00997..b42c717085f3 100644 --- a/drivers/gpu/drm/i915/display/dvo_sil164.c +++ b/drivers/gpu/drm/i915/display/dvo_sil164.c @@ -189,7 +189,7 @@ static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { return MODE_OK; } diff --git a/drivers/gpu/drm/i915/display/dvo_tfp410.c b/drivers/gpu/drm/i915/display/dvo_tfp410.c index d9a0cd753a87..280699438526 100644 --- a/drivers/gpu/drm/i915/display/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/display/dvo_tfp410.c @@ -217,7 +217,7 @@ static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo) } static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { return MODE_OK; } diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 8a49f499e3fb..afe90cf0842a 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1459,7 +1459,7 @@ static void gen11_dsi_post_disable(struct intel_atomic_state *state, } static enum drm_mode_status gen11_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_i915_private *i915 = to_i915(connector->dev); enum drm_mode_status status; diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 74c1983fe07e..69667cd49ec8 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -352,7 +352,7 @@ static void intel_enable_crt(struct intel_atomic_state *state, static enum drm_mode_status intel_crt_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_display *display = to_intel_display(connector->dev); struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ff5ba7b3035f..ea4f775b12a1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1371,7 +1371,7 @@ bool intel_dp_has_dsc(const struct intel_connector *connector) static enum drm_mode_status intel_dp_mode_valid(struct drm_connector *_connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_connector *connector = to_intel_connector(_connector); struct intel_dp *intel_dp = intel_attached_dp(connector); diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c index 0be46c6c9611..c93a3cf75c52 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.c +++ b/drivers/gpu/drm/i915/display/intel_dsi.c @@ -58,7 +58,7 @@ int intel_dsi_get_modes(struct drm_connector *connector) } enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h index e8ba4ccd99d3..89c7166a3860 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.h +++ b/drivers/gpu/drm/i915/display/intel_dsi.h @@ -165,7 +165,7 @@ enum drm_panel_orientation intel_dsi_get_panel_orientation(struct intel_connector *connector); int intel_dsi_get_modes(struct drm_connector *connector); enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, const struct mipi_dsi_host_ops *funcs, enum port port); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 2d5ffb37eac9..f425bea748c4 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -217,7 +217,7 @@ static void intel_enable_dvo(struct intel_atomic_state *state, static enum drm_mode_status intel_dvo_mode_valid(struct drm_connector *_connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_connector *connector = to_intel_connector(_connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h index 4bf476656b8c..d20667870e50 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo_dev.h +++ b/drivers/gpu/drm/i915/display/intel_dvo_dev.h @@ -71,7 +71,7 @@ struct intel_dvo_dev_ops { * \return MODE_OK if the mode is valid, or another MODE_* otherwise. */ enum drm_mode_status (*mode_valid)(struct intel_dvo_device *dvo, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); /* * Callback for setting up a video mode after fixups have been made. diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index c6ce6bb88d7c..ae7600ea4a19 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2025,7 +2025,7 @@ intel_hdmi_mode_clock_valid(struct drm_connector *connector, int clock, static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_display *display = to_intel_display(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 6d7637ad980a..ef2f5c8948a7 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -389,7 +389,7 @@ static void intel_lvds_shutdown(struct intel_encoder *encoder) static enum drm_mode_status intel_lvds_mode_valid(struct drm_connector *_connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_connector *connector = to_intel_connector(_connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 7a28104f68ad..3dcb48879e81 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1938,7 +1938,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, static enum drm_mode_status intel_sdvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_i915_private *i915 = to_i915(connector->dev); struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 27c530218ee6..fa2634aa574a 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -957,7 +957,7 @@ static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct intel_display *display = to_intel_display(connector->dev); struct drm_i915_private *i915 = to_i915(connector->dev); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 9383eedee2d4..e7d9f5897d87 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1542,7 +1542,7 @@ static const struct drm_encoder_funcs intel_dsi_funcs = { }; static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_i915_private *i915 = to_i915(connector->dev); diff --git a/drivers/gpu/drm/imx/ipuv3/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c index 3a3c8a195119..c5629e155d25 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-tve.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c @@ -217,7 +217,7 @@ static int imx_tve_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status imx_tve_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct imx_tve *tve = con_to_tve(connector); unsigned long rate; diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index 7444b75c4215..52e728181b52 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -58,7 +58,7 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status mdp4_lvds_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct mdp4_lvds_connector *mdp4_lvds_connector = to_mdp4_lvds_connector(connector); diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 8097249612bc..2e09b5a6d155 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1142,7 +1142,7 @@ nv50_mstc_atomic_best_encoder(struct drm_connector *connector, static enum drm_mode_status nv50_mstc_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct nv50_mstc *mstc = nv50_mstc(connector); struct nouveau_encoder *outp = mstc->mstm->outp; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 8d5c9c74cbb9..2d26784bde74 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1074,7 +1074,7 @@ get_tmds_link_bandwidth(struct drm_connector *connector) static enum drm_mode_status nouveau_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index bc24af08dfcd..70aff64ced87 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -1044,7 +1044,7 @@ static int qxl_conn_get_modes(struct drm_connector *connector) } static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *ddev = connector->dev; struct qxl_device *qdev = to_qxl(ddev); diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 6328627b7c34..fa78824931cc 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -467,7 +467,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector, } int radeon_dp_mode_valid_helper(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index f9996304d943..9f6a3df951ba 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -806,7 +806,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) } static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -968,7 +968,7 @@ static int radeon_vga_get_modes(struct drm_connector *connector) } static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; @@ -1116,7 +1116,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector) } static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) return MODE_CLOCK_RANGE; @@ -1447,7 +1447,7 @@ static void radeon_dvi_force(struct drm_connector *connector) } static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; @@ -1723,7 +1723,7 @@ out: } static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 4063d3801e81..3102f6c2d055 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -706,7 +706,7 @@ extern int radeon_get_monitor_bpc(struct drm_connector *connector); extern void radeon_connector_hotplug(struct drm_connector *connector); extern int radeon_dp_mode_valid_helper(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); extern void radeon_dp_set_link_config(struct drm_connector *connector, const struct drm_display_mode *mode); extern void radeon_dp_link_train(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index b17de83b988b..292c31de18f1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -275,7 +275,7 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status cdn_dp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct cdn_dp_device *dp = connector_to_dp(connector); struct drm_display_info *display_info = &dp->connector.display_info; diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 898d90155057..483ecfeaebb0 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -471,7 +471,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, } static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { unsigned long mpixelclk, max_tolerance; long rounded_refclk; @@ -577,7 +577,7 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status inno_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 403336397214..f7a460190313 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -482,7 +482,7 @@ static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status rk3066_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u32 vic = drm_match_cea_mode(mode); diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index c6c2abaa1891..4dcddd02629b 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -349,7 +349,7 @@ static int sti_dvo_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status sti_dvo_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { int target = mode->clock * 1000; int target_min = target - CLK_TOLERANCE_HZ; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 57aa260d1e46..14fdc00d2ba0 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -603,7 +603,7 @@ static int sti_hda_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status sti_hda_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { int target = mode->clock * 1000; int target_min = target - CLK_TOLERANCE_HZ; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index ca2fe17de4a5..164a34d793d8 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1011,7 +1011,7 @@ fail: static enum drm_mode_status sti_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { int target = mode->clock * 1000; int target_min = target - CLK_TOLERANCE_HZ; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 4a8cd9ed0a94..9bb077558167 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -812,7 +812,7 @@ static const struct drm_connector_funcs tegra_dsi_connector_funcs = { static enum drm_mode_status tegra_dsi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { return MODE_OK; } diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e705f8590c13..8cd2969e7d4b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1137,7 +1137,7 @@ static const struct drm_connector_funcs tegra_hdmi_connector_funcs = { static enum drm_mode_status tegra_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct tegra_output *output = connector_to_output(connector); struct tegra_hdmi *hdmi = to_hdmi(output); diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 802d2db7007a..f98f70eda906 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1789,7 +1789,7 @@ static int tegra_sor_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status tegra_sor_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { return MODE_OK; } diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 4eab069cda75..42acac05fe47 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -196,7 +196,7 @@ static int vc4_txp_connector_get_modes(struct drm_connector *connector) static enum drm_mode_status vc4_txp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; struct drm_mode_config *mode_config = &dev->mode_config; diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 64baf2f22d9f..59a45e74a641 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -189,7 +189,7 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector) } static enum drm_mode_status virtio_gpu_conn_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct virtio_gpu_output *output = drm_connector_to_virtio_gpu_output(connector); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8db38927729b..c896de07f7b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2660,7 +2660,7 @@ out_unref: * Returns MODE_OK on success, or a drm_mode_status error code. */ enum drm_mode_status vmw_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { enum drm_mode_status ret; struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 2a6c6d6581e0..4eab581883e2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -435,7 +435,7 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, int increment, struct vmw_kms_dirty *dirty); enum drm_mode_status vmw_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); int vmw_connector_get_modes(struct drm_connector *connector); void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 114a75069e1c..f5d2ed1b0a72 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -839,7 +839,7 @@ static void vmw_stdu_connector_destroy(struct drm_connector *connector) static enum drm_mode_status vmw_stdu_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { enum drm_mode_status ret; struct drm_device *dev = connector->dev; diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h index 9ae19f3caf72..dc2d1c48cc5b 100644 --- a/include/drm/display/drm_hdmi_state_helper.h +++ b/include/drm/display/drm_hdmi_state_helper.h @@ -27,6 +27,6 @@ void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector); enum drm_mode_status drm_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); #endif // DRM_HDMI_STATE_HELPER_H_ diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index fa9ee6a128be..b62f41f48962 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -967,7 +967,7 @@ struct drm_connector_helper_funcs { * drm_mode_status. */ enum drm_mode_status (*mode_valid)(struct drm_connector *connector, - struct drm_display_mode *mode); + const struct drm_display_mode *mode); /** * @mode_valid_ctx: -- cgit v1.2.3 From 9a0dfe9bacef9c3bf6aaa92b5913945364ef805f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 6 Jan 2025 01:00:13 +0200 Subject: drm/nouveau: incorporate I2C TV encoder drivers Chrontel CH7006 and Silicon Image sil164 drivers use drm_encoder_slave interface which is being used only by the nouveau driver. It doesn't make sense to keep this interface inside the DRM subsystem. In preparation to moving this set of helpers to the nouveau driver, move the only two I2C driver that use that interface to the nouveau driver too. Suggested-by: Laurent Pinchart Signed-off-by: Dmitry Baryshkov Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20250106-nouveau-encoder-slave-v3-1-1d37d2f2c67f@linaro.org --- arch/arm/configs/multi_v7_defconfig | 4 +- arch/parisc/configs/generic-32bit_defconfig | 4 +- arch/parisc/configs/generic-64bit_defconfig | 4 +- drivers/gpu/drm/i2c/Kconfig | 18 - drivers/gpu/drm/i2c/Makefile | 6 - drivers/gpu/drm/i2c/ch7006_drv.c | 549 --------------------- drivers/gpu/drm/i2c/ch7006_mode.c | 470 ------------------ drivers/gpu/drm/i2c/ch7006_priv.h | 344 ------------- drivers/gpu/drm/i2c/sil164_drv.c | 451 ----------------- drivers/gpu/drm/nouveau/Kconfig | 18 + drivers/gpu/drm/nouveau/dispnv04/Kbuild | 2 + drivers/gpu/drm/nouveau/dispnv04/dfp.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/i2c/Kbuild | 5 + drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c | 549 +++++++++++++++++++++ drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c | 470 ++++++++++++++++++ drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h | 345 +++++++++++++ drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c | 452 +++++++++++++++++ drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | 2 +- .../gpu/drm/nouveau/include/dispnv04/i2c/ch7006.h | 87 ++++ .../gpu/drm/nouveau/include/dispnv04/i2c/sil164.h | 64 +++ include/drm/i2c/ch7006.h | 87 ---- include/drm/i2c/sil164.h | 64 --- 22 files changed, 2000 insertions(+), 1997 deletions(-) delete mode 100644 drivers/gpu/drm/i2c/ch7006_drv.c delete mode 100644 drivers/gpu/drm/i2c/ch7006_mode.c delete mode 100644 drivers/gpu/drm/i2c/ch7006_priv.h delete mode 100644 drivers/gpu/drm/i2c/sil164_drv.c create mode 100644 drivers/gpu/drm/nouveau/dispnv04/i2c/Kbuild create mode 100644 drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c create mode 100644 drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c create mode 100644 drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h create mode 100644 drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c create mode 100644 drivers/gpu/drm/nouveau/include/dispnv04/i2c/ch7006.h create mode 100644 drivers/gpu/drm/nouveau/include/dispnv04/i2c/sil164.h delete mode 100644 include/drm/i2c/ch7006.h delete mode 100644 include/drm/i2c/sil164.h (limited to 'include') diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 758276027dbc..4b100ddb0c54 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -713,10 +713,10 @@ CONFIG_VIDEO_ADV7604_CEC=y CONFIG_VIDEO_ML86V7667=m CONFIG_IMX_IPUV3_CORE=m CONFIG_DRM=y -# CONFIG_DRM_I2C_CH7006 is not set -# CONFIG_DRM_I2C_SIL164 is not set CONFIG_DRM_I2C_NXP_TDA998X=m CONFIG_DRM_NOUVEAU=m +# CONFIG_DRM_NOUVEAU_CH7006 is not set +# CONFIG_DRM_NOUVEAU_SIL164 is not set CONFIG_DRM_EXYNOS=m CONFIG_DRM_EXYNOS_FIMD=y CONFIG_DRM_EXYNOS_MIXER=y diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig index 5ce258f3fffa..f5fffc24c3bc 100644 --- a/arch/parisc/configs/generic-32bit_defconfig +++ b/arch/parisc/configs/generic-32bit_defconfig @@ -132,11 +132,11 @@ CONFIG_I2C=y CONFIG_HWMON=m CONFIG_DRM=m CONFIG_DRM_DISPLAY_DP_AUX_CEC=y -# CONFIG_DRM_I2C_CH7006 is not set -# CONFIG_DRM_I2C_SIL164 is not set CONFIG_DRM_RADEON=m CONFIG_DRM_NOUVEAU=m # CONFIG_DRM_NOUVEAU_BACKLIGHT is not set +# CONFIG_DRM_NOUVEAU_CH7006 is not set +# CONFIG_DRM_NOUVEAU_SIL164 is not set CONFIG_DRM_VGEM=m CONFIG_DRM_UDL=m CONFIG_DRM_MGAG200=m diff --git a/arch/parisc/configs/generic-64bit_defconfig b/arch/parisc/configs/generic-64bit_defconfig index 19a804860ed5..704f68fbf960 100644 --- a/arch/parisc/configs/generic-64bit_defconfig +++ b/arch/parisc/configs/generic-64bit_defconfig @@ -193,11 +193,11 @@ CONFIG_MEDIA_SUPPORT=m CONFIG_AGP=y CONFIG_AGP_PARISC=y CONFIG_DRM=y -# CONFIG_DRM_I2C_CH7006 is not set -# CONFIG_DRM_I2C_SIL164 is not set CONFIG_DRM_RADEON=y CONFIG_DRM_NOUVEAU=m # CONFIG_DRM_NOUVEAU_BACKLIGHT is not set +# CONFIG_DRM_NOUVEAU_CH7006 is not set +# CONFIG_DRM_NOUVEAU_SIL164 is not set CONFIG_DRM_MGAG200=m CONFIG_FB=y CONFIG_FB_PM2=m diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 6f19e1c35e30..d5200f67958e 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -2,24 +2,6 @@ menu "I2C encoder or helper chips" depends on DRM && DRM_KMS_HELPER && I2C -config DRM_I2C_CH7006 - tristate "Chrontel ch7006 TV encoder" - default m if DRM_NOUVEAU - help - Support for Chrontel ch7006 and similar TV encoders, found - on some nVidia video cards. - - This driver is currently only useful if you're also using - the nouveau driver. - -config DRM_I2C_SIL164 - tristate "Silicon Image sil164 TMDS transmitter" - default m if DRM_NOUVEAU - help - Support for sil164 and similar single-link (or dual-link - when used in pairs) TMDS transmitters, used in some nVidia - video cards. - config DRM_I2C_NXP_TDA998X tristate "NXP Semiconductors TDA998X HDMI encoder" default m if DRM_TILCDC diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index a962f6f08568..31fd35527d99 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -1,10 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -ch7006-y := ch7006_drv.o ch7006_mode.o -obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o - -sil164-y := sil164_drv.o -obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o - tda998x-y := tda998x_drv.o obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o obj-$(CONFIG_DRM_I2C_NXP_TDA9950) += tda9950.o diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c deleted file mode 100644 index db4f95020fae..000000000000 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include - -#include - -#include "ch7006_priv.h" - -/* DRM encoder functions */ - -static void ch7006_encoder_set_config(struct drm_encoder *encoder, - void *params) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - - priv->params = *(struct ch7006_encoder_params *)params; -} - -static void ch7006_encoder_destroy(struct drm_encoder *encoder) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - - drm_property_destroy(encoder->dev, priv->scale_property); - - kfree(priv); - to_encoder_slave(encoder)->slave_priv = NULL; - - drm_i2c_encoder_destroy(encoder); -} - -static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_state *state = &priv->state; - - ch7006_dbg(client, "\n"); - - if (mode == priv->last_dpms) - return; - priv->last_dpms = mode; - - ch7006_setup_power_state(encoder); - - ch7006_load_reg(client, state, CH7006_POWER); -} - -static void ch7006_encoder_save(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - - ch7006_dbg(client, "\n"); - - ch7006_state_save(client, &priv->saved_state); -} - -static void ch7006_encoder_restore(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - - ch7006_dbg(client, "\n"); - - ch7006_state_load(client, &priv->saved_state); -} - -static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - - /* The ch7006 is painfully picky with the input timings so no - * custom modes for now... */ - - priv->mode = ch7006_lookup_mode(encoder, mode); - - return !!priv->mode; -} - -static int ch7006_encoder_mode_valid(struct drm_encoder *encoder, - const struct drm_display_mode *mode) -{ - if (ch7006_lookup_mode(encoder, mode)) - return MODE_OK; - else - return MODE_BAD; -} - -static void ch7006_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *drm_mode, - struct drm_display_mode *adjusted_mode) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_encoder_params *params = &priv->params; - struct ch7006_state *state = &priv->state; - uint8_t *regs = state->regs; - const struct ch7006_mode *mode = priv->mode; - const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; - int start_active; - - ch7006_dbg(client, "\n"); - - regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode; - regs[CH7006_BWIDTH] = 0; - regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT, - params->input_format); - - regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK - | bitf(CH7006_CLKMODE_XCM, params->xcm) - | bitf(CH7006_CLKMODE_PCM, params->pcm); - if (params->clock_mode) - regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER; - if (params->clock_edge) - regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE; - - start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7); - regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active); - regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active); - - regs[CH7006_INPUT_SYNC] = 0; - if (params->sync_direction) - regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT; - if (params->sync_encoding) - regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED; - if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC) - regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC; - if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC) - regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC; - - regs[CH7006_DETECT] = 0; - regs[CH7006_BCLKOUT] = 0; - - regs[CH7006_SUBC_INC3] = 0; - if (params->pout_level) - regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V; - - regs[CH7006_SUBC_INC4] = 0; - if (params->active_detect) - regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT; - - regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL]; - - ch7006_setup_levels(encoder); - ch7006_setup_subcarrier(encoder); - ch7006_setup_pll(encoder); - ch7006_setup_power_state(encoder); - ch7006_setup_properties(encoder); - - ch7006_state_load(client, state); -} - -static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_state *state = &priv->state; - int det; - - ch7006_dbg(client, "\n"); - - ch7006_save_reg(client, state, CH7006_DETECT); - ch7006_save_reg(client, state, CH7006_POWER); - ch7006_save_reg(client, state, CH7006_CLKMODE); - - ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET | - bitfs(CH7006_POWER_LEVEL, NORMAL)); - ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER); - - ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE); - - ch7006_write(client, CH7006_DETECT, 0); - - det = ch7006_read(client, CH7006_DETECT); - - ch7006_load_reg(client, state, CH7006_CLKMODE); - ch7006_load_reg(client, state, CH7006_POWER); - ch7006_load_reg(client, state, CH7006_DETECT); - - if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| - CH7006_DETECT_SVIDEO_C_TEST| - CH7006_DETECT_CVBS_TEST)) == 0) - priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART; - else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| - CH7006_DETECT_SVIDEO_C_TEST)) == 0) - priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; - else if ((det & CH7006_DETECT_CVBS_TEST) == 0) - priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite; - else - priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; - - drm_object_property_set_value(&connector->base, - encoder->dev->mode_config.tv_subconnector_property, - priv->subconnector); - - return priv->subconnector ? connector_status_connected : - connector_status_disconnected; -} - -static int ch7006_encoder_get_modes(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - const struct ch7006_mode *mode; - int n = 0; - - for (mode = ch7006_modes; mode->mode.clock; mode++) { - if (~mode->valid_scales & 1<scale || - ~mode->valid_norms & 1<norm) - continue; - - drm_mode_probed_add(connector, - drm_mode_duplicate(encoder->dev, &mode->mode)); - - n++; - } - - return n; -} - -static int ch7006_encoder_create_resources(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct drm_device *dev = encoder->dev; - struct drm_mode_config *conf = &dev->mode_config; - - drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names); - - priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2); - if (!priv->scale_property) - return -ENOMEM; - - drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property, - priv->select_subconnector); - drm_object_attach_property(&connector->base, conf->tv_subconnector_property, - priv->subconnector); - drm_object_attach_property(&connector->base, conf->tv_left_margin_property, - priv->hmargin); - drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property, - priv->vmargin); - drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property, - priv->norm); - drm_object_attach_property(&connector->base, conf->tv_brightness_property, - priv->brightness); - drm_object_attach_property(&connector->base, conf->tv_contrast_property, - priv->contrast); - drm_object_attach_property(&connector->base, conf->tv_flicker_reduction_property, - priv->flicker); - drm_object_attach_property(&connector->base, priv->scale_property, - priv->scale); - - return 0; -} - -static int ch7006_encoder_set_property(struct drm_encoder *encoder, - struct drm_connector *connector, - struct drm_property *property, - uint64_t val) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_state *state = &priv->state; - struct drm_mode_config *conf = &encoder->dev->mode_config; - struct drm_crtc *crtc = encoder->crtc; - bool modes_changed = false; - - ch7006_dbg(client, "\n"); - - if (property == conf->tv_select_subconnector_property) { - priv->select_subconnector = val; - - ch7006_setup_power_state(encoder); - - ch7006_load_reg(client, state, CH7006_POWER); - - } else if (property == conf->tv_left_margin_property) { - priv->hmargin = val; - - ch7006_setup_properties(encoder); - - ch7006_load_reg(client, state, CH7006_POV); - ch7006_load_reg(client, state, CH7006_HPOS); - - } else if (property == conf->tv_bottom_margin_property) { - priv->vmargin = val; - - ch7006_setup_properties(encoder); - - ch7006_load_reg(client, state, CH7006_POV); - ch7006_load_reg(client, state, CH7006_VPOS); - - } else if (property == conf->legacy_tv_mode_property) { - if (connector->dpms != DRM_MODE_DPMS_OFF) - return -EINVAL; - - priv->norm = val; - - modes_changed = true; - - } else if (property == conf->tv_brightness_property) { - priv->brightness = val; - - ch7006_setup_levels(encoder); - - ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); - - } else if (property == conf->tv_contrast_property) { - priv->contrast = val; - - ch7006_setup_properties(encoder); - - ch7006_load_reg(client, state, CH7006_CONTRAST); - - } else if (property == conf->tv_flicker_reduction_property) { - priv->flicker = val; - - ch7006_setup_properties(encoder); - - ch7006_load_reg(client, state, CH7006_FFILTER); - - } else if (property == priv->scale_property) { - if (connector->dpms != DRM_MODE_DPMS_OFF) - return -EINVAL; - - priv->scale = val; - - modes_changed = true; - - } else { - return -EINVAL; - } - - if (modes_changed) { - drm_helper_probe_single_connector_modes(connector, 0, 0); - - if (crtc) - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->primary->fb); - } - - return 0; -} - -static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = { - .set_config = ch7006_encoder_set_config, - .destroy = ch7006_encoder_destroy, - .dpms = ch7006_encoder_dpms, - .save = ch7006_encoder_save, - .restore = ch7006_encoder_restore, - .mode_fixup = ch7006_encoder_mode_fixup, - .mode_valid = ch7006_encoder_mode_valid, - .mode_set = ch7006_encoder_mode_set, - .detect = ch7006_encoder_detect, - .get_modes = ch7006_encoder_get_modes, - .create_resources = ch7006_encoder_create_resources, - .set_property = ch7006_encoder_set_property, -}; - - -/* I2C driver functions */ - -static int ch7006_probe(struct i2c_client *client) -{ - uint8_t addr = CH7006_VERSION_ID; - uint8_t val; - int ret; - - ch7006_dbg(client, "\n"); - - ret = i2c_master_send(client, &addr, sizeof(addr)); - if (ret < 0) - goto fail; - - ret = i2c_master_recv(client, &val, sizeof(val)); - if (ret < 0) - goto fail; - - ch7006_info(client, "Detected version ID: %x\n", val); - - /* I don't know what this is for, but otherwise I get no - * signal. - */ - ch7006_write(client, 0x3d, 0x0); - - return 0; - -fail: - ch7006_err(client, "Error %d reading version ID\n", ret); - - return -ENODEV; -} - -static void ch7006_remove(struct i2c_client *client) -{ - ch7006_dbg(client, "\n"); -} - -static int ch7006_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - ch7006_dbg(client, "\n"); - - ch7006_write(client, 0x3d, 0x0); - - return 0; -} - -static int ch7006_encoder_init(struct i2c_client *client, - struct drm_device *dev, - struct drm_encoder_slave *encoder) -{ - struct ch7006_priv *priv; - int i; - - ch7006_dbg(client, "\n"); - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - encoder->slave_priv = priv; - encoder->slave_funcs = &ch7006_encoder_funcs; - - priv->norm = TV_NORM_PAL; - priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic; - priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; - priv->scale = 1; - priv->contrast = 50; - priv->brightness = 50; - priv->flicker = 50; - priv->hmargin = 50; - priv->vmargin = 50; - priv->last_dpms = -1; - priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); - - if (ch7006_tv_norm) { - for (i = 0; i < NUM_TV_NORMS; i++) { - if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) { - priv->norm = i; - break; - } - } - - if (i == NUM_TV_NORMS) - ch7006_err(client, "Invalid TV norm setting \"%s\".\n", - ch7006_tv_norm); - } - - if (ch7006_scale >= 0 && ch7006_scale <= 2) - priv->scale = ch7006_scale; - else - ch7006_err(client, "Invalid scale setting \"%d\".\n", - ch7006_scale); - - return 0; -} - -static const struct i2c_device_id ch7006_ids[] = { - { "ch7006" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ch7006_ids); - -static const struct dev_pm_ops ch7006_pm_ops = { - .resume = ch7006_resume, -}; - -static struct drm_i2c_encoder_driver ch7006_driver = { - .i2c_driver = { - .probe = ch7006_probe, - .remove = ch7006_remove, - - .driver = { - .name = "ch7006", - .pm = &ch7006_pm_ops, - }, - - .id_table = ch7006_ids, - }, - - .encoder_init = ch7006_encoder_init, -}; - - -/* Module initialization */ - -static int __init ch7006_init(void) -{ - return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver); -} - -static void __exit ch7006_exit(void) -{ - drm_i2c_encoder_unregister(&ch7006_driver); -} - -int ch7006_debug; -module_param_named(debug, ch7006_debug, int, 0600); -MODULE_PARM_DESC(debug, "Enable debug output."); - -char *ch7006_tv_norm; -module_param_named(tv_norm, ch7006_tv_norm, charp, 0600); -MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" - "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n" - "\t\tDefault: PAL"); - -int ch7006_scale = 1; -module_param_named(scale, ch7006_scale, int, 0600); -MODULE_PARM_DESC(scale, "Default scale.\n" - "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n" - "\t\t\t1 -> Select default video modes.\n" - "\t\t\t2 -> Select video modes with a lower blanking ratio."); - -MODULE_AUTHOR("Francisco Jerez "); -MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver"); -MODULE_LICENSE("GPL and additional rights"); - -module_init(ch7006_init); -module_exit(ch7006_exit); diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c deleted file mode 100644 index 6afe6d0ee630..000000000000 --- a/drivers/gpu/drm/i2c/ch7006_mode.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "ch7006_priv.h" - -const char * const ch7006_tv_norm_names[] = { - [TV_NORM_PAL] = "PAL", - [TV_NORM_PAL_M] = "PAL-M", - [TV_NORM_PAL_N] = "PAL-N", - [TV_NORM_PAL_NC] = "PAL-Nc", - [TV_NORM_PAL_60] = "PAL-60", - [TV_NORM_NTSC_M] = "NTSC-M", - [TV_NORM_NTSC_J] = "NTSC-J", -}; - -#define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001, \ - .vdisplay = 480, \ - .vtotal = 525, \ - .hvirtual = 660 - -#define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1, \ - .vdisplay = 576, \ - .vtotal = 625, \ - .hvirtual = 810 - -const struct ch7006_tv_norm_info ch7006_tv_norms[] = { - [TV_NORM_NTSC_M] = { - NTSC_LIKE_TIMINGS, - .black_level = 0.339 * fixed1, - .subc_freq = 3579545 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC), - .voffset = 0, - }, - [TV_NORM_NTSC_J] = { - NTSC_LIKE_TIMINGS, - .black_level = 0.286 * fixed1, - .subc_freq = 3579545 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J), - .voffset = 0, - }, - [TV_NORM_PAL] = { - PAL_LIKE_TIMINGS, - .black_level = 0.3 * fixed1, - .subc_freq = 4433618.75 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), - .voffset = 0, - }, - [TV_NORM_PAL_M] = { - NTSC_LIKE_TIMINGS, - .black_level = 0.339 * fixed1, - .subc_freq = 3575611.433 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), - .voffset = 16, - }, - - /* The following modes seem to work right but they're - * undocumented */ - - [TV_NORM_PAL_N] = { - PAL_LIKE_TIMINGS, - .black_level = 0.339 * fixed1, - .subc_freq = 4433618.75 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), - .voffset = 0, - }, - [TV_NORM_PAL_NC] = { - PAL_LIKE_TIMINGS, - .black_level = 0.3 * fixed1, - .subc_freq = 3582056.25 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), - .voffset = 0, - }, - [TV_NORM_PAL_60] = { - NTSC_LIKE_TIMINGS, - .black_level = 0.3 * fixed1, - .subc_freq = 4433618.75 * fixed1, - .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), - .voffset = 16, - }, -}; - -#define __MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ - subc, scale, scale_mask, norm_mask, e_hd, e_vd) { \ - .mode = { \ - .name = #hd "x" #vd, \ - .status = 0, \ - .type = DRM_MODE_TYPE_DRIVER, \ - .clock = f, \ - .hdisplay = hd, \ - .hsync_start = e_hd + 16, \ - .hsync_end = e_hd + 80, \ - .htotal = ht, \ - .hskew = 0, \ - .vdisplay = vd, \ - .vsync_start = vd + 10, \ - .vsync_end = vd + 26, \ - .vtotal = vt, \ - .vscan = 0, \ - .flags = DRM_MODE_FLAG_##hsynp##HSYNC | \ - DRM_MODE_FLAG_##vsynp##VSYNC, \ - }, \ - .enc_hdisp = e_hd, \ - .enc_vdisp = e_vd, \ - .subc_coeff = subc * fixed1, \ - .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \ - bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \ - .valid_scales = scale_mask, \ - .valid_norms = norm_mask \ - } - -#define MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ - subc, scale, scale_mask, norm_mask) \ - __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale, \ - scale_mask, norm_mask, hd, vd) - -#define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J | \ - 1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60) - -#define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) - -const struct ch7006_mode ch7006_modes[] = { - MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), - MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), - MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), - MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE), - MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE), - MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE), - MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE), - MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE), - MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE), - MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE), - MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE), - MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE), - MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE), - MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE), - MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE), - MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE), - MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE), - MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE), - MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE), - __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600), - MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE), - MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE), - MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE), - MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE), - MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE), - {} -}; - -const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, - const struct drm_display_mode *drm_mode) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - const struct ch7006_mode *mode; - - for (mode = ch7006_modes; mode->mode.clock; mode++) { - - if (~mode->valid_norms & 1<norm) - continue; - - if (mode->mode.hdisplay != drm_mode->hdisplay || - mode->mode.vdisplay != drm_mode->vdisplay || - mode->mode.vtotal != drm_mode->vtotal || - mode->mode.htotal != drm_mode->htotal || - mode->mode.clock != drm_mode->clock) - continue; - - return mode; - } - - return NULL; -} - -/* Some common HW state calculation code */ - -void ch7006_setup_levels(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - uint8_t *regs = priv->state.regs; - const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; - int gain; - int black_level; - - /* Set DAC_GAIN if the voltage drop between white and black is - * high enough. */ - if (norm->black_level < 339*fixed1/1000) { - gain = 76; - - regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN; - } else { - gain = 71; - - regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN; - } - - black_level = round_fixed(norm->black_level*26625)/gain; - - /* Correct it with the specified brightness. */ - black_level = interpolate(90, black_level, 208, priv->brightness); - - regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level); - - ch7006_dbg(client, "black level: %d\n", black_level); -} - -void ch7006_setup_subcarrier(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_state *state = &priv->state; - const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; - const struct ch7006_mode *mode = priv->mode; - uint32_t subc_inc; - - subc_inc = round_fixed((mode->subc_coeff >> 8) - * (norm->subc_freq >> 24)); - - setbitf(state, CH7006_SUBC_INC0, 28, subc_inc); - setbitf(state, CH7006_SUBC_INC1, 24, subc_inc); - setbitf(state, CH7006_SUBC_INC2, 20, subc_inc); - setbitf(state, CH7006_SUBC_INC3, 16, subc_inc); - setbitf(state, CH7006_SUBC_INC4, 12, subc_inc); - setbitf(state, CH7006_SUBC_INC5, 8, subc_inc); - setbitf(state, CH7006_SUBC_INC6, 4, subc_inc); - setbitf(state, CH7006_SUBC_INC7, 0, subc_inc); - - ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc); -} - -void ch7006_setup_pll(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - uint8_t *regs = priv->state.regs; - const struct ch7006_mode *mode = priv->mode; - int n, best_n = 0; - int m, best_m = 0; - int freq, best_freq = 0; - - for (n = 0; n < CH7006_MAXN; n++) { - for (m = 0; m < CH7006_MAXM; m++) { - freq = CH7006_FREQ0*(n+2)/(m+2); - - if (abs(freq - mode->mode.clock) < - abs(best_freq - mode->mode.clock)) { - best_freq = freq; - best_n = n; - best_m = m; - } - } - } - - regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) | - bitf(CH7006_PLLOV_M_8, best_m); - - regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m); - regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n); - - if (best_n < 108) - regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR; - else - regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR; - - ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n", - best_n, best_m, best_freq, best_n < 108); -} - -void ch7006_setup_power_state(struct drm_encoder *encoder) -{ - struct ch7006_priv *priv = to_ch7006_priv(encoder); - uint8_t *power = &priv->state.regs[CH7006_POWER]; - int subconnector; - - subconnector = priv->select_subconnector ? priv->select_subconnector : - priv->subconnector; - - *power = CH7006_POWER_RESET; - - if (priv->last_dpms == DRM_MODE_DPMS_ON) { - switch (subconnector) { - case DRM_MODE_SUBCONNECTOR_SVIDEO: - *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF); - break; - case DRM_MODE_SUBCONNECTOR_Composite: - *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF); - break; - case DRM_MODE_SUBCONNECTOR_SCART: - *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) | - CH7006_POWER_SCART; - break; - } - - } else { - if (priv->chip_version >= 0x20) - *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); - else - *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); - } -} - -void ch7006_setup_properties(struct drm_encoder *encoder) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_state *state = &priv->state; - const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; - const struct ch7006_mode *ch_mode = priv->mode; - const struct drm_display_mode *mode = &ch_mode->mode; - uint8_t *regs = state->regs; - int flicker, contrast, hpos, vpos; - uint64_t scale, aspect; - - flicker = interpolate(0, 2, 3, priv->flicker); - regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) | - bitf(CH7006_FFILTER_LUMA, flicker) | - bitf(CH7006_FFILTER_CHROMA, 1); - - contrast = interpolate(0, 5, 7, priv->contrast); - regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast); - - scale = norm->vtotal*fixed1; - do_div(scale, mode->vtotal); - - aspect = ch_mode->enc_hdisp*fixed1; - do_div(aspect, ch_mode->enc_vdisp); - - hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale) - * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4; - - setbitf(state, CH7006_POV, HPOS_8, hpos); - setbitf(state, CH7006_HPOS, 0, hpos); - - vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale) - + norm->voffset) * priv->vmargin / 100 / 2; - - setbitf(state, CH7006_POV, VPOS_8, vpos); - setbitf(state, CH7006_VPOS, 0, vpos); - - ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos); -} - -/* HW access functions */ - -void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val) -{ - uint8_t buf[] = {addr, val}; - int ret; - - ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); - if (ret < 0) - ch7006_err(client, "Error %d writing to subaddress 0x%x\n", - ret, addr); -} - -uint8_t ch7006_read(struct i2c_client *client, uint8_t addr) -{ - uint8_t val; - int ret; - - ret = i2c_master_send(client, &addr, sizeof(addr)); - if (ret < 0) - goto fail; - - ret = i2c_master_recv(client, &val, sizeof(val)); - if (ret < 0) - goto fail; - - return val; - -fail: - ch7006_err(client, "Error %d reading from subaddress 0x%x\n", - ret, addr); - return 0; -} - -void ch7006_state_load(struct i2c_client *client, - struct ch7006_state *state) -{ - ch7006_load_reg(client, state, CH7006_POWER); - - ch7006_load_reg(client, state, CH7006_DISPMODE); - ch7006_load_reg(client, state, CH7006_FFILTER); - ch7006_load_reg(client, state, CH7006_BWIDTH); - ch7006_load_reg(client, state, CH7006_INPUT_FORMAT); - ch7006_load_reg(client, state, CH7006_CLKMODE); - ch7006_load_reg(client, state, CH7006_START_ACTIVE); - ch7006_load_reg(client, state, CH7006_POV); - ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); - ch7006_load_reg(client, state, CH7006_HPOS); - ch7006_load_reg(client, state, CH7006_VPOS); - ch7006_load_reg(client, state, CH7006_INPUT_SYNC); - ch7006_load_reg(client, state, CH7006_DETECT); - ch7006_load_reg(client, state, CH7006_CONTRAST); - ch7006_load_reg(client, state, CH7006_PLLOV); - ch7006_load_reg(client, state, CH7006_PLLM); - ch7006_load_reg(client, state, CH7006_PLLN); - ch7006_load_reg(client, state, CH7006_BCLKOUT); - ch7006_load_reg(client, state, CH7006_SUBC_INC0); - ch7006_load_reg(client, state, CH7006_SUBC_INC1); - ch7006_load_reg(client, state, CH7006_SUBC_INC2); - ch7006_load_reg(client, state, CH7006_SUBC_INC3); - ch7006_load_reg(client, state, CH7006_SUBC_INC4); - ch7006_load_reg(client, state, CH7006_SUBC_INC5); - ch7006_load_reg(client, state, CH7006_SUBC_INC6); - ch7006_load_reg(client, state, CH7006_SUBC_INC7); - ch7006_load_reg(client, state, CH7006_PLL_CONTROL); - ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0); -} - -void ch7006_state_save(struct i2c_client *client, - struct ch7006_state *state) -{ - ch7006_save_reg(client, state, CH7006_POWER); - - ch7006_save_reg(client, state, CH7006_DISPMODE); - ch7006_save_reg(client, state, CH7006_FFILTER); - ch7006_save_reg(client, state, CH7006_BWIDTH); - ch7006_save_reg(client, state, CH7006_INPUT_FORMAT); - ch7006_save_reg(client, state, CH7006_CLKMODE); - ch7006_save_reg(client, state, CH7006_START_ACTIVE); - ch7006_save_reg(client, state, CH7006_POV); - ch7006_save_reg(client, state, CH7006_BLACK_LEVEL); - ch7006_save_reg(client, state, CH7006_HPOS); - ch7006_save_reg(client, state, CH7006_VPOS); - ch7006_save_reg(client, state, CH7006_INPUT_SYNC); - ch7006_save_reg(client, state, CH7006_DETECT); - ch7006_save_reg(client, state, CH7006_CONTRAST); - ch7006_save_reg(client, state, CH7006_PLLOV); - ch7006_save_reg(client, state, CH7006_PLLM); - ch7006_save_reg(client, state, CH7006_PLLN); - ch7006_save_reg(client, state, CH7006_BCLKOUT); - ch7006_save_reg(client, state, CH7006_SUBC_INC0); - ch7006_save_reg(client, state, CH7006_SUBC_INC1); - ch7006_save_reg(client, state, CH7006_SUBC_INC2); - ch7006_save_reg(client, state, CH7006_SUBC_INC3); - ch7006_save_reg(client, state, CH7006_SUBC_INC4); - ch7006_save_reg(client, state, CH7006_SUBC_INC5); - ch7006_save_reg(client, state, CH7006_SUBC_INC6); - ch7006_save_reg(client, state, CH7006_SUBC_INC7); - ch7006_save_reg(client, state, CH7006_PLL_CONTROL); - ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0); - - state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) | - (state->regs[CH7006_FFILTER] & 0x0c) >> 2 | - (state->regs[CH7006_FFILTER] & 0x03) << 2; -} diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h deleted file mode 100644 index 052bdc48a339..000000000000 --- a/drivers/gpu/drm/i2c/ch7006_priv.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __DRM_I2C_CH7006_PRIV_H__ -#define __DRM_I2C_CH7006_PRIV_H__ - -#include -#include -#include - -typedef int64_t fixed; -#define fixed1 (1LL << 32) - -enum ch7006_tv_norm { - TV_NORM_PAL, - TV_NORM_PAL_M, - TV_NORM_PAL_N, - TV_NORM_PAL_NC, - TV_NORM_PAL_60, - TV_NORM_NTSC_M, - TV_NORM_NTSC_J, - NUM_TV_NORMS -}; - -struct ch7006_tv_norm_info { - fixed vrefresh; - int vdisplay; - int vtotal; - int hvirtual; - - fixed subc_freq; - fixed black_level; - - uint32_t dispmode; - int voffset; -}; - -struct ch7006_mode { - struct drm_display_mode mode; - - int enc_hdisp; - int enc_vdisp; - - fixed subc_coeff; - uint32_t dispmode; - - uint32_t valid_scales; - uint32_t valid_norms; -}; - -struct ch7006_state { - uint8_t regs[0x26]; -}; - -struct ch7006_priv { - struct ch7006_encoder_params params; - const struct ch7006_mode *mode; - - struct ch7006_state state; - struct ch7006_state saved_state; - - struct drm_property *scale_property; - - int select_subconnector; - int subconnector; - int hmargin; - int vmargin; - enum ch7006_tv_norm norm; - int brightness; - int contrast; - int flicker; - int scale; - - int chip_version; - int last_dpms; -}; - -#define to_ch7006_priv(x) \ - ((struct ch7006_priv *)to_encoder_slave(x)->slave_priv) - -extern int ch7006_debug; -extern char *ch7006_tv_norm; -extern int ch7006_scale; - -extern const char * const ch7006_tv_norm_names[]; -extern const struct ch7006_tv_norm_info ch7006_tv_norms[]; -extern const struct ch7006_mode ch7006_modes[]; - -const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, - const struct drm_display_mode *drm_mode); - -void ch7006_setup_levels(struct drm_encoder *encoder); -void ch7006_setup_subcarrier(struct drm_encoder *encoder); -void ch7006_setup_pll(struct drm_encoder *encoder); -void ch7006_setup_power_state(struct drm_encoder *encoder); -void ch7006_setup_properties(struct drm_encoder *encoder); - -void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val); -uint8_t ch7006_read(struct i2c_client *client, uint8_t addr); - -void ch7006_state_load(struct i2c_client *client, - struct ch7006_state *state); -void ch7006_state_save(struct i2c_client *client, - struct ch7006_state *state); - -/* Some helper macros */ - -#define ch7006_dbg(client, format, ...) do { \ - if (ch7006_debug) \ - dev_printk(KERN_DEBUG, &client->dev, \ - "%s: " format, __func__, ## __VA_ARGS__); \ - } while (0) -#define ch7006_info(client, format, ...) \ - dev_info(&client->dev, format, __VA_ARGS__) -#define ch7006_err(client, format, ...) \ - dev_err(&client->dev, format, __VA_ARGS__) - -#define __mask(src, bitfield) \ - (((2 << (1 ? bitfield)) - 1) & ~((1 << (0 ? bitfield)) - 1)) -#define mask(bitfield) __mask(bitfield) - -#define __bitf(src, bitfield, x) \ - (((x) >> (src) << (0 ? bitfield)) & __mask(src, bitfield)) -#define bitf(bitfield, x) __bitf(bitfield, x) -#define bitfs(bitfield, s) __bitf(bitfield, bitfield##_##s) -#define setbitf(state, reg, bitfield, x) \ - state->regs[reg] = (state->regs[reg] & ~mask(reg##_##bitfield)) \ - | bitf(reg##_##bitfield, x) - -#define __unbitf(src, bitfield, x) \ - ((x & __mask(src, bitfield)) >> (0 ? bitfield) << (src)) -#define unbitf(bitfield, x) __unbitf(bitfield, x) - -static inline int interpolate(int y0, int y1, int y2, int x) -{ - return y1 + (x < 50 ? y1 - y0 : y2 - y1) * (x - 50) / 50; -} - -static inline int32_t round_fixed(fixed x) -{ - return (x + fixed1/2) >> 32; -} - -#define ch7006_load_reg(client, state, reg) ch7006_write(client, reg, state->regs[reg]) -#define ch7006_save_reg(client, state, reg) state->regs[reg] = ch7006_read(client, reg) - -/* Fixed hardware specs */ - -#define CH7006_FREQ0 14318 -#define CH7006_MAXN 650 -#define CH7006_MAXM 315 - -/* Register definitions */ - -#define CH7006_DISPMODE 0x00 -#define CH7006_DISPMODE_INPUT_RES 0, 7:5 -#define CH7006_DISPMODE_INPUT_RES_512x384 0x0 -#define CH7006_DISPMODE_INPUT_RES_720x400 0x1 -#define CH7006_DISPMODE_INPUT_RES_640x400 0x2 -#define CH7006_DISPMODE_INPUT_RES_640x480 0x3 -#define CH7006_DISPMODE_INPUT_RES_800x600 0x4 -#define CH7006_DISPMODE_INPUT_RES_NATIVE 0x5 -#define CH7006_DISPMODE_OUTPUT_STD 0, 4:3 -#define CH7006_DISPMODE_OUTPUT_STD_PAL 0x0 -#define CH7006_DISPMODE_OUTPUT_STD_NTSC 0x1 -#define CH7006_DISPMODE_OUTPUT_STD_PAL_M 0x2 -#define CH7006_DISPMODE_OUTPUT_STD_NTSC_J 0x3 -#define CH7006_DISPMODE_SCALING_RATIO 0, 2:0 -#define CH7006_DISPMODE_SCALING_RATIO_5_4 0x0 -#define CH7006_DISPMODE_SCALING_RATIO_1_1 0x1 -#define CH7006_DISPMODE_SCALING_RATIO_7_8 0x2 -#define CH7006_DISPMODE_SCALING_RATIO_5_6 0x3 -#define CH7006_DISPMODE_SCALING_RATIO_3_4 0x4 -#define CH7006_DISPMODE_SCALING_RATIO_7_10 0x5 - -#define CH7006_FFILTER 0x01 -#define CH7006_FFILTER_TEXT 0, 5:4 -#define CH7006_FFILTER_LUMA 0, 3:2 -#define CH7006_FFILTER_CHROMA 0, 1:0 -#define CH7006_FFILTER_CHROMA_NO_DCRAWL 0x3 - -#define CH7006_BWIDTH 0x03 -#define CH7006_BWIDTH_5L_FFILER (1 << 7) -#define CH7006_BWIDTH_CVBS_NO_CHROMA (1 << 6) -#define CH7006_BWIDTH_CHROMA 0, 5:4 -#define CH7006_BWIDTH_SVIDEO_YPEAK (1 << 3) -#define CH7006_BWIDTH_SVIDEO_LUMA 0, 2:1 -#define CH7006_BWIDTH_CVBS_LUMA 0, 0:0 - -#define CH7006_INPUT_FORMAT 0x04 -#define CH7006_INPUT_FORMAT_DAC_GAIN (1 << 6) -#define CH7006_INPUT_FORMAT_RGB_PASS_THROUGH (1 << 5) -#define CH7006_INPUT_FORMAT_FORMAT 0, 3:0 -#define CH7006_INPUT_FORMAT_FORMAT_RGB16 0x0 -#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m16 0x1 -#define CH7006_INPUT_FORMAT_FORMAT_RGB24m16 0x2 -#define CH7006_INPUT_FORMAT_FORMAT_RGB15 0x3 -#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12C 0x4 -#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12I 0x5 -#define CH7006_INPUT_FORMAT_FORMAT_RGB24m8 0x6 -#define CH7006_INPUT_FORMAT_FORMAT_RGB16m8 0x7 -#define CH7006_INPUT_FORMAT_FORMAT_RGB15m8 0x8 -#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m8 0x9 - -#define CH7006_CLKMODE 0x06 -#define CH7006_CLKMODE_SUBC_LOCK (1 << 7) -#define CH7006_CLKMODE_MASTER (1 << 6) -#define CH7006_CLKMODE_POS_EDGE (1 << 4) -#define CH7006_CLKMODE_XCM 0, 3:2 -#define CH7006_CLKMODE_PCM 0, 1:0 - -#define CH7006_START_ACTIVE 0x07 -#define CH7006_START_ACTIVE_0 0, 7:0 - -#define CH7006_POV 0x08 -#define CH7006_POV_START_ACTIVE_8 8, 2:2 -#define CH7006_POV_HPOS_8 8, 1:1 -#define CH7006_POV_VPOS_8 8, 0:0 - -#define CH7006_BLACK_LEVEL 0x09 -#define CH7006_BLACK_LEVEL_0 0, 7:0 - -#define CH7006_HPOS 0x0a -#define CH7006_HPOS_0 0, 7:0 - -#define CH7006_VPOS 0x0b -#define CH7006_VPOS_0 0, 7:0 - -#define CH7006_INPUT_SYNC 0x0d -#define CH7006_INPUT_SYNC_EMBEDDED (1 << 3) -#define CH7006_INPUT_SYNC_OUTPUT (1 << 2) -#define CH7006_INPUT_SYNC_PVSYNC (1 << 1) -#define CH7006_INPUT_SYNC_PHSYNC (1 << 0) - -#define CH7006_POWER 0x0e -#define CH7006_POWER_SCART (1 << 4) -#define CH7006_POWER_RESET (1 << 3) -#define CH7006_POWER_LEVEL 0, 2:0 -#define CH7006_POWER_LEVEL_CVBS_OFF 0x0 -#define CH7006_POWER_LEVEL_POWER_OFF 0x1 -#define CH7006_POWER_LEVEL_SVIDEO_OFF 0x2 -#define CH7006_POWER_LEVEL_NORMAL 0x3 -#define CH7006_POWER_LEVEL_FULL_POWER_OFF 0x4 - -#define CH7006_DETECT 0x10 -#define CH7006_DETECT_SVIDEO_Y_TEST (1 << 3) -#define CH7006_DETECT_SVIDEO_C_TEST (1 << 2) -#define CH7006_DETECT_CVBS_TEST (1 << 1) -#define CH7006_DETECT_SENSE (1 << 0) - -#define CH7006_CONTRAST 0x11 -#define CH7006_CONTRAST_0 0, 2:0 - -#define CH7006_PLLOV 0x13 -#define CH7006_PLLOV_N_8 8, 2:1 -#define CH7006_PLLOV_M_8 8, 0:0 - -#define CH7006_PLLM 0x14 -#define CH7006_PLLM_0 0, 7:0 - -#define CH7006_PLLN 0x15 -#define CH7006_PLLN_0 0, 7:0 - -#define CH7006_BCLKOUT 0x17 - -#define CH7006_SUBC_INC0 0x18 -#define CH7006_SUBC_INC0_28 28, 3:0 - -#define CH7006_SUBC_INC1 0x19 -#define CH7006_SUBC_INC1_24 24, 3:0 - -#define CH7006_SUBC_INC2 0x1a -#define CH7006_SUBC_INC2_20 20, 3:0 - -#define CH7006_SUBC_INC3 0x1b -#define CH7006_SUBC_INC3_GPIO1_VAL (1 << 7) -#define CH7006_SUBC_INC3_GPIO0_VAL (1 << 6) -#define CH7006_SUBC_INC3_POUT_3_3V (1 << 5) -#define CH7006_SUBC_INC3_POUT_INV (1 << 4) -#define CH7006_SUBC_INC3_16 16, 3:0 - -#define CH7006_SUBC_INC4 0x1c -#define CH7006_SUBC_INC4_GPIO1_IN (1 << 7) -#define CH7006_SUBC_INC4_GPIO0_IN (1 << 6) -#define CH7006_SUBC_INC4_DS_INPUT (1 << 4) -#define CH7006_SUBC_INC4_12 12, 3:0 - -#define CH7006_SUBC_INC5 0x1d -#define CH7006_SUBC_INC5_8 8, 3:0 - -#define CH7006_SUBC_INC6 0x1e -#define CH7006_SUBC_INC6_4 4, 3:0 - -#define CH7006_SUBC_INC7 0x1f -#define CH7006_SUBC_INC7_0 0, 3:0 - -#define CH7006_PLL_CONTROL 0x20 -#define CH7006_PLL_CONTROL_CPI (1 << 5) -#define CH7006_PLL_CONTROL_CAPACITOR (1 << 4) -#define CH7006_PLL_CONTROL_7STAGES (1 << 3) -#define CH7006_PLL_CONTROL_DIGITAL_5V (1 << 2) -#define CH7006_PLL_CONTROL_ANALOG_5V (1 << 1) -#define CH7006_PLL_CONTROL_MEMORY_5V (1 << 0) - -#define CH7006_CALC_SUBC_INC0 0x21 -#define CH7006_CALC_SUBC_INC0_24 24, 4:3 -#define CH7006_CALC_SUBC_INC0_HYST 0, 2:1 -#define CH7006_CALC_SUBC_INC0_AUTO (1 << 0) - -#define CH7006_CALC_SUBC_INC1 0x22 -#define CH7006_CALC_SUBC_INC1_16 16, 7:0 - -#define CH7006_CALC_SUBC_INC2 0x23 -#define CH7006_CALC_SUBC_INC2_8 8, 7:0 - -#define CH7006_CALC_SUBC_INC3 0x24 -#define CH7006_CALC_SUBC_INC3_0 0, 7:0 - -#define CH7006_VERSION_ID 0x25 - -#endif diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c deleted file mode 100644 index 6e5da2c5762f..000000000000 --- a/drivers/gpu/drm/i2c/sil164_drv.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2010 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include - -#include -#include -#include -#include -#include - -struct sil164_priv { - struct sil164_encoder_params config; - struct i2c_client *duallink_slave; - - uint8_t saved_state[0x10]; - uint8_t saved_slave_state[0x10]; -}; - -#define to_sil164_priv(x) \ - ((struct sil164_priv *)to_encoder_slave(x)->slave_priv) - -#define sil164_dbg(client, format, ...) do { \ - if (drm_debug_enabled(DRM_UT_KMS)) \ - dev_printk(KERN_DEBUG, &client->dev, \ - "%s: " format, __func__, ## __VA_ARGS__); \ - } while (0) -#define sil164_info(client, format, ...) \ - dev_info(&client->dev, format, __VA_ARGS__) -#define sil164_err(client, format, ...) \ - dev_err(&client->dev, format, __VA_ARGS__) - -#define SIL164_I2C_ADDR_MASTER 0x38 -#define SIL164_I2C_ADDR_SLAVE 0x39 - -/* HW register definitions */ - -#define SIL164_VENDOR_LO 0x0 -#define SIL164_VENDOR_HI 0x1 -#define SIL164_DEVICE_LO 0x2 -#define SIL164_DEVICE_HI 0x3 -#define SIL164_REVISION 0x4 -#define SIL164_FREQ_MIN 0x6 -#define SIL164_FREQ_MAX 0x7 -#define SIL164_CONTROL0 0x8 -# define SIL164_CONTROL0_POWER_ON 0x01 -# define SIL164_CONTROL0_EDGE_RISING 0x02 -# define SIL164_CONTROL0_INPUT_24BIT 0x04 -# define SIL164_CONTROL0_DUAL_EDGE 0x08 -# define SIL164_CONTROL0_HSYNC_ON 0x10 -# define SIL164_CONTROL0_VSYNC_ON 0x20 -#define SIL164_DETECT 0x9 -# define SIL164_DETECT_INTR_STAT 0x01 -# define SIL164_DETECT_HOTPLUG_STAT 0x02 -# define SIL164_DETECT_RECEIVER_STAT 0x04 -# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00 -# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08 -# define SIL164_DETECT_OUT_MODE_HIGH 0x00 -# define SIL164_DETECT_OUT_MODE_INTR 0x10 -# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20 -# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30 -# define SIL164_DETECT_VSWING_STAT 0x80 -#define SIL164_CONTROL1 0xa -# define SIL164_CONTROL1_DESKEW_ENABLE 0x10 -# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5 -#define SIL164_GPIO 0xb -#define SIL164_CONTROL2 0xc -# define SIL164_CONTROL2_FILTER_ENABLE 0x01 -# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1 -# define SIL164_CONTROL2_DUALLINK_MASTER 0x40 -# define SIL164_CONTROL2_SYNC_CONT 0x80 -#define SIL164_DUALLINK 0xd -# define SIL164_DUALLINK_ENABLE 0x10 -# define SIL164_DUALLINK_SKEW_SHIFT 5 -#define SIL164_PLLZONE 0xe -# define SIL164_PLLZONE_STAT 0x08 -# define SIL164_PLLZONE_FORCE_ON 0x10 -# define SIL164_PLLZONE_FORCE_HIGH 0x20 - -/* HW access functions */ - -static void -sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val) -{ - uint8_t buf[] = {addr, val}; - int ret; - - ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); - if (ret < 0) - sil164_err(client, "Error %d writing to subaddress 0x%x\n", - ret, addr); -} - -static uint8_t -sil164_read(struct i2c_client *client, uint8_t addr) -{ - uint8_t val; - int ret; - - ret = i2c_master_send(client, &addr, sizeof(addr)); - if (ret < 0) - goto fail; - - ret = i2c_master_recv(client, &val, sizeof(val)); - if (ret < 0) - goto fail; - - return val; - -fail: - sil164_err(client, "Error %d reading from subaddress 0x%x\n", - ret, addr); - return 0; -} - -static void -sil164_save_state(struct i2c_client *client, uint8_t *state) -{ - int i; - - for (i = 0x8; i <= 0xe; i++) - state[i] = sil164_read(client, i); -} - -static void -sil164_restore_state(struct i2c_client *client, uint8_t *state) -{ - int i; - - for (i = 0x8; i <= 0xe; i++) - sil164_write(client, i, state[i]); -} - -static void -sil164_set_power_state(struct i2c_client *client, bool on) -{ - uint8_t control0 = sil164_read(client, SIL164_CONTROL0); - - if (on) - control0 |= SIL164_CONTROL0_POWER_ON; - else - control0 &= ~SIL164_CONTROL0_POWER_ON; - - sil164_write(client, SIL164_CONTROL0, control0); -} - -static void -sil164_init_state(struct i2c_client *client, - struct sil164_encoder_params *config, - bool duallink) -{ - sil164_write(client, SIL164_CONTROL0, - SIL164_CONTROL0_HSYNC_ON | - SIL164_CONTROL0_VSYNC_ON | - (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) | - (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) | - (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0)); - - sil164_write(client, SIL164_DETECT, - SIL164_DETECT_INTR_STAT | - SIL164_DETECT_OUT_MODE_RECEIVER); - - sil164_write(client, SIL164_CONTROL1, - (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) | - (((config->input_skew + 4) & 0x7) - << SIL164_CONTROL1_DESKEW_INCR_SHIFT)); - - sil164_write(client, SIL164_CONTROL2, - SIL164_CONTROL2_SYNC_CONT | - (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) | - (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT)); - - sil164_write(client, SIL164_PLLZONE, 0); - - if (duallink) - sil164_write(client, SIL164_DUALLINK, - SIL164_DUALLINK_ENABLE | - (((config->duallink_skew + 4) & 0x7) - << SIL164_DUALLINK_SKEW_SHIFT)); - else - sil164_write(client, SIL164_DUALLINK, 0); -} - -/* DRM encoder functions */ - -static void -sil164_encoder_set_config(struct drm_encoder *encoder, void *params) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - - priv->config = *(struct sil164_encoder_params *)params; -} - -static void -sil164_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - bool on = (mode == DRM_MODE_DPMS_ON); - bool duallink = (on && encoder->crtc->mode.clock > 165000); - - sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on); - - if (priv->duallink_slave) - sil164_set_power_state(priv->duallink_slave, duallink); -} - -static void -sil164_encoder_save(struct drm_encoder *encoder) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - - sil164_save_state(drm_i2c_encoder_get_client(encoder), - priv->saved_state); - - if (priv->duallink_slave) - sil164_save_state(priv->duallink_slave, - priv->saved_slave_state); -} - -static void -sil164_encoder_restore(struct drm_encoder *encoder) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - - sil164_restore_state(drm_i2c_encoder_get_client(encoder), - priv->saved_state); - - if (priv->duallink_slave) - sil164_restore_state(priv->duallink_slave, - priv->saved_slave_state); -} - -static int -sil164_encoder_mode_valid(struct drm_encoder *encoder, - const struct drm_display_mode *mode) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - - if (mode->clock < 32000) - return MODE_CLOCK_LOW; - - if (mode->clock > 330000 || - (mode->clock > 165000 && !priv->duallink_slave)) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -static void -sil164_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - bool duallink = adjusted_mode->clock > 165000; - - sil164_init_state(drm_i2c_encoder_get_client(encoder), - &priv->config, duallink); - - if (priv->duallink_slave) - sil164_init_state(priv->duallink_slave, - &priv->config, duallink); - - sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON); -} - -static enum drm_connector_status -sil164_encoder_detect(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); - - if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT) - return connector_status_connected; - else - return connector_status_disconnected; -} - -static int -sil164_encoder_get_modes(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - return 0; -} - -static int -sil164_encoder_create_resources(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - return 0; -} - -static int -sil164_encoder_set_property(struct drm_encoder *encoder, - struct drm_connector *connector, - struct drm_property *property, - uint64_t val) -{ - return 0; -} - -static void -sil164_encoder_destroy(struct drm_encoder *encoder) -{ - struct sil164_priv *priv = to_sil164_priv(encoder); - - i2c_unregister_device(priv->duallink_slave); - - kfree(priv); - drm_i2c_encoder_destroy(encoder); -} - -static const struct drm_encoder_slave_funcs sil164_encoder_funcs = { - .set_config = sil164_encoder_set_config, - .destroy = sil164_encoder_destroy, - .dpms = sil164_encoder_dpms, - .save = sil164_encoder_save, - .restore = sil164_encoder_restore, - .mode_valid = sil164_encoder_mode_valid, - .mode_set = sil164_encoder_mode_set, - .detect = sil164_encoder_detect, - .get_modes = sil164_encoder_get_modes, - .create_resources = sil164_encoder_create_resources, - .set_property = sil164_encoder_set_property, -}; - -/* I2C driver functions */ - -static int -sil164_probe(struct i2c_client *client) -{ - int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 | - sil164_read(client, SIL164_VENDOR_LO); - int device = sil164_read(client, SIL164_DEVICE_HI) << 8 | - sil164_read(client, SIL164_DEVICE_LO); - int rev = sil164_read(client, SIL164_REVISION); - - if (vendor != 0x1 || device != 0x6) { - sil164_dbg(client, "Unknown device %x:%x.%x\n", - vendor, device, rev); - return -ENODEV; - } - - sil164_info(client, "Detected device %x:%x.%x\n", - vendor, device, rev); - - return 0; -} - -static struct i2c_client * -sil164_detect_slave(struct i2c_client *client) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg = { - .addr = SIL164_I2C_ADDR_SLAVE, - .len = 0, - }; - const struct i2c_board_info info = { - I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE) - }; - - if (i2c_transfer(adap, &msg, 1) != 1) { - sil164_dbg(adap, "No dual-link slave found."); - return NULL; - } - - return i2c_new_client_device(adap, &info); -} - -static int -sil164_encoder_init(struct i2c_client *client, - struct drm_device *dev, - struct drm_encoder_slave *encoder) -{ - struct sil164_priv *priv; - struct i2c_client *slave_client; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - encoder->slave_priv = priv; - encoder->slave_funcs = &sil164_encoder_funcs; - - slave_client = sil164_detect_slave(client); - if (!IS_ERR(slave_client)) - priv->duallink_slave = slave_client; - - return 0; -} - -static const struct i2c_device_id sil164_ids[] = { - { "sil164" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sil164_ids); - -static struct drm_i2c_encoder_driver sil164_driver = { - .i2c_driver = { - .probe = sil164_probe, - .driver = { - .name = "sil164", - }, - .id_table = sil164_ids, - }, - .encoder_init = sil164_encoder_init, -}; - -/* Module initialization */ - -static int __init -sil164_init(void) -{ - return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver); -} - -static void __exit -sil164_exit(void) -{ - drm_i2c_encoder_unregister(&sil164_driver); -} - -MODULE_AUTHOR("Francisco Jerez "); -MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver"); -MODULE_LICENSE("GPL and additional rights"); - -module_init(sil164_init); -module_exit(sil164_exit); diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index ce840300578d..ac76c0787010 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -109,3 +109,21 @@ config DRM_NOUVEAU_GSP_DEFAULT help Say Y here if you want to use the GSP codepaths by default on Turing and Ampere GPUs. + +config DRM_NOUVEAU_CH7006 + tristate "Chrontel ch7006 TV encoder" + depends on DRM_NOUVEAU + default m + help + Support for Chrontel ch7006 and similar TV encoders. + + This driver is currently only useful if you're also using + the nouveau driver. + +config DRM_NOUVEAU_SIL164 + tristate "Silicon Image sil164 TMDS transmitter" + depends on DRM_NOUVEAU + default m + help + Support for sil164 and similar single-link (or dual-link + when used in pairs) TMDS transmitters. diff --git a/drivers/gpu/drm/nouveau/dispnv04/Kbuild b/drivers/gpu/drm/nouveau/dispnv04/Kbuild index 975c4e226936..949802882ebd 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/Kbuild +++ b/drivers/gpu/drm/nouveau/dispnv04/Kbuild @@ -10,3 +10,5 @@ nouveau-y += dispnv04/overlay.o nouveau-y += dispnv04/tvmodesnv17.o nouveau-y += dispnv04/tvnv04.o nouveau-y += dispnv04/tvnv17.o + +include $(src)/dispnv04/i2c/Kbuild diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 504c421aa176..25fa41edcb3c 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -35,7 +35,7 @@ #include "hw.h" #include "nvreg.h" -#include +#include #include diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/Kbuild b/drivers/gpu/drm/nouveau/dispnv04/i2c/Kbuild new file mode 100644 index 000000000000..3fddfc97bcb3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/Kbuild @@ -0,0 +1,5 @@ +ch7006-y := dispnv04/i2c/ch7006_drv.o dispnv04/i2c/ch7006_mode.o +obj-$(CONFIG_DRM_NOUVEAU_CH7006) += ch7006.o + +sil164-y := dispnv04/i2c/sil164_drv.o +obj-$(CONFIG_DRM_NOUVEAU_SIL164) += sil164.o diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c new file mode 100644 index 000000000000..db4f95020fae --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +#include + +#include "ch7006_priv.h" + +/* DRM encoder functions */ + +static void ch7006_encoder_set_config(struct drm_encoder *encoder, + void *params) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + + priv->params = *(struct ch7006_encoder_params *)params; +} + +static void ch7006_encoder_destroy(struct drm_encoder *encoder) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + + drm_property_destroy(encoder->dev, priv->scale_property); + + kfree(priv); + to_encoder_slave(encoder)->slave_priv = NULL; + + drm_i2c_encoder_destroy(encoder); +} + +static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_state *state = &priv->state; + + ch7006_dbg(client, "\n"); + + if (mode == priv->last_dpms) + return; + priv->last_dpms = mode; + + ch7006_setup_power_state(encoder); + + ch7006_load_reg(client, state, CH7006_POWER); +} + +static void ch7006_encoder_save(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + + ch7006_dbg(client, "\n"); + + ch7006_state_save(client, &priv->saved_state); +} + +static void ch7006_encoder_restore(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + + ch7006_dbg(client, "\n"); + + ch7006_state_load(client, &priv->saved_state); +} + +static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + + /* The ch7006 is painfully picky with the input timings so no + * custom modes for now... */ + + priv->mode = ch7006_lookup_mode(encoder, mode); + + return !!priv->mode; +} + +static int ch7006_encoder_mode_valid(struct drm_encoder *encoder, + const struct drm_display_mode *mode) +{ + if (ch7006_lookup_mode(encoder, mode)) + return MODE_OK; + else + return MODE_BAD; +} + +static void ch7006_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *drm_mode, + struct drm_display_mode *adjusted_mode) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_encoder_params *params = &priv->params; + struct ch7006_state *state = &priv->state; + uint8_t *regs = state->regs; + const struct ch7006_mode *mode = priv->mode; + const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; + int start_active; + + ch7006_dbg(client, "\n"); + + regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode; + regs[CH7006_BWIDTH] = 0; + regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT, + params->input_format); + + regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK + | bitf(CH7006_CLKMODE_XCM, params->xcm) + | bitf(CH7006_CLKMODE_PCM, params->pcm); + if (params->clock_mode) + regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER; + if (params->clock_edge) + regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE; + + start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7); + regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active); + regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active); + + regs[CH7006_INPUT_SYNC] = 0; + if (params->sync_direction) + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT; + if (params->sync_encoding) + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED; + if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC) + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC; + if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC) + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC; + + regs[CH7006_DETECT] = 0; + regs[CH7006_BCLKOUT] = 0; + + regs[CH7006_SUBC_INC3] = 0; + if (params->pout_level) + regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V; + + regs[CH7006_SUBC_INC4] = 0; + if (params->active_detect) + regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT; + + regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL]; + + ch7006_setup_levels(encoder); + ch7006_setup_subcarrier(encoder); + ch7006_setup_pll(encoder); + ch7006_setup_power_state(encoder); + ch7006_setup_properties(encoder); + + ch7006_state_load(client, state); +} + +static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_state *state = &priv->state; + int det; + + ch7006_dbg(client, "\n"); + + ch7006_save_reg(client, state, CH7006_DETECT); + ch7006_save_reg(client, state, CH7006_POWER); + ch7006_save_reg(client, state, CH7006_CLKMODE); + + ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET | + bitfs(CH7006_POWER_LEVEL, NORMAL)); + ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER); + + ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE); + + ch7006_write(client, CH7006_DETECT, 0); + + det = ch7006_read(client, CH7006_DETECT); + + ch7006_load_reg(client, state, CH7006_CLKMODE); + ch7006_load_reg(client, state, CH7006_POWER); + ch7006_load_reg(client, state, CH7006_DETECT); + + if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| + CH7006_DETECT_SVIDEO_C_TEST| + CH7006_DETECT_CVBS_TEST)) == 0) + priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART; + else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| + CH7006_DETECT_SVIDEO_C_TEST)) == 0) + priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; + else if ((det & CH7006_DETECT_CVBS_TEST) == 0) + priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite; + else + priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + + drm_object_property_set_value(&connector->base, + encoder->dev->mode_config.tv_subconnector_property, + priv->subconnector); + + return priv->subconnector ? connector_status_connected : + connector_status_disconnected; +} + +static int ch7006_encoder_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + const struct ch7006_mode *mode; + int n = 0; + + for (mode = ch7006_modes; mode->mode.clock; mode++) { + if (~mode->valid_scales & 1<scale || + ~mode->valid_norms & 1<norm) + continue; + + drm_mode_probed_add(connector, + drm_mode_duplicate(encoder->dev, &mode->mode)); + + n++; + } + + return n; +} + +static int ch7006_encoder_create_resources(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct drm_device *dev = encoder->dev; + struct drm_mode_config *conf = &dev->mode_config; + + drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names); + + priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2); + if (!priv->scale_property) + return -ENOMEM; + + drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property, + priv->select_subconnector); + drm_object_attach_property(&connector->base, conf->tv_subconnector_property, + priv->subconnector); + drm_object_attach_property(&connector->base, conf->tv_left_margin_property, + priv->hmargin); + drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property, + priv->vmargin); + drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property, + priv->norm); + drm_object_attach_property(&connector->base, conf->tv_brightness_property, + priv->brightness); + drm_object_attach_property(&connector->base, conf->tv_contrast_property, + priv->contrast); + drm_object_attach_property(&connector->base, conf->tv_flicker_reduction_property, + priv->flicker); + drm_object_attach_property(&connector->base, priv->scale_property, + priv->scale); + + return 0; +} + +static int ch7006_encoder_set_property(struct drm_encoder *encoder, + struct drm_connector *connector, + struct drm_property *property, + uint64_t val) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_state *state = &priv->state; + struct drm_mode_config *conf = &encoder->dev->mode_config; + struct drm_crtc *crtc = encoder->crtc; + bool modes_changed = false; + + ch7006_dbg(client, "\n"); + + if (property == conf->tv_select_subconnector_property) { + priv->select_subconnector = val; + + ch7006_setup_power_state(encoder); + + ch7006_load_reg(client, state, CH7006_POWER); + + } else if (property == conf->tv_left_margin_property) { + priv->hmargin = val; + + ch7006_setup_properties(encoder); + + ch7006_load_reg(client, state, CH7006_POV); + ch7006_load_reg(client, state, CH7006_HPOS); + + } else if (property == conf->tv_bottom_margin_property) { + priv->vmargin = val; + + ch7006_setup_properties(encoder); + + ch7006_load_reg(client, state, CH7006_POV); + ch7006_load_reg(client, state, CH7006_VPOS); + + } else if (property == conf->legacy_tv_mode_property) { + if (connector->dpms != DRM_MODE_DPMS_OFF) + return -EINVAL; + + priv->norm = val; + + modes_changed = true; + + } else if (property == conf->tv_brightness_property) { + priv->brightness = val; + + ch7006_setup_levels(encoder); + + ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); + + } else if (property == conf->tv_contrast_property) { + priv->contrast = val; + + ch7006_setup_properties(encoder); + + ch7006_load_reg(client, state, CH7006_CONTRAST); + + } else if (property == conf->tv_flicker_reduction_property) { + priv->flicker = val; + + ch7006_setup_properties(encoder); + + ch7006_load_reg(client, state, CH7006_FFILTER); + + } else if (property == priv->scale_property) { + if (connector->dpms != DRM_MODE_DPMS_OFF) + return -EINVAL; + + priv->scale = val; + + modes_changed = true; + + } else { + return -EINVAL; + } + + if (modes_changed) { + drm_helper_probe_single_connector_modes(connector, 0, 0); + + if (crtc) + drm_crtc_helper_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, + crtc->primary->fb); + } + + return 0; +} + +static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = { + .set_config = ch7006_encoder_set_config, + .destroy = ch7006_encoder_destroy, + .dpms = ch7006_encoder_dpms, + .save = ch7006_encoder_save, + .restore = ch7006_encoder_restore, + .mode_fixup = ch7006_encoder_mode_fixup, + .mode_valid = ch7006_encoder_mode_valid, + .mode_set = ch7006_encoder_mode_set, + .detect = ch7006_encoder_detect, + .get_modes = ch7006_encoder_get_modes, + .create_resources = ch7006_encoder_create_resources, + .set_property = ch7006_encoder_set_property, +}; + + +/* I2C driver functions */ + +static int ch7006_probe(struct i2c_client *client) +{ + uint8_t addr = CH7006_VERSION_ID; + uint8_t val; + int ret; + + ch7006_dbg(client, "\n"); + + ret = i2c_master_send(client, &addr, sizeof(addr)); + if (ret < 0) + goto fail; + + ret = i2c_master_recv(client, &val, sizeof(val)); + if (ret < 0) + goto fail; + + ch7006_info(client, "Detected version ID: %x\n", val); + + /* I don't know what this is for, but otherwise I get no + * signal. + */ + ch7006_write(client, 0x3d, 0x0); + + return 0; + +fail: + ch7006_err(client, "Error %d reading version ID\n", ret); + + return -ENODEV; +} + +static void ch7006_remove(struct i2c_client *client) +{ + ch7006_dbg(client, "\n"); +} + +static int ch7006_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + ch7006_dbg(client, "\n"); + + ch7006_write(client, 0x3d, 0x0); + + return 0; +} + +static int ch7006_encoder_init(struct i2c_client *client, + struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + struct ch7006_priv *priv; + int i; + + ch7006_dbg(client, "\n"); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + encoder->slave_priv = priv; + encoder->slave_funcs = &ch7006_encoder_funcs; + + priv->norm = TV_NORM_PAL; + priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic; + priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + priv->scale = 1; + priv->contrast = 50; + priv->brightness = 50; + priv->flicker = 50; + priv->hmargin = 50; + priv->vmargin = 50; + priv->last_dpms = -1; + priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); + + if (ch7006_tv_norm) { + for (i = 0; i < NUM_TV_NORMS; i++) { + if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) { + priv->norm = i; + break; + } + } + + if (i == NUM_TV_NORMS) + ch7006_err(client, "Invalid TV norm setting \"%s\".\n", + ch7006_tv_norm); + } + + if (ch7006_scale >= 0 && ch7006_scale <= 2) + priv->scale = ch7006_scale; + else + ch7006_err(client, "Invalid scale setting \"%d\".\n", + ch7006_scale); + + return 0; +} + +static const struct i2c_device_id ch7006_ids[] = { + { "ch7006" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ch7006_ids); + +static const struct dev_pm_ops ch7006_pm_ops = { + .resume = ch7006_resume, +}; + +static struct drm_i2c_encoder_driver ch7006_driver = { + .i2c_driver = { + .probe = ch7006_probe, + .remove = ch7006_remove, + + .driver = { + .name = "ch7006", + .pm = &ch7006_pm_ops, + }, + + .id_table = ch7006_ids, + }, + + .encoder_init = ch7006_encoder_init, +}; + + +/* Module initialization */ + +static int __init ch7006_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver); +} + +static void __exit ch7006_exit(void) +{ + drm_i2c_encoder_unregister(&ch7006_driver); +} + +int ch7006_debug; +module_param_named(debug, ch7006_debug, int, 0600); +MODULE_PARM_DESC(debug, "Enable debug output."); + +char *ch7006_tv_norm; +module_param_named(tv_norm, ch7006_tv_norm, charp, 0600); +MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" + "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n" + "\t\tDefault: PAL"); + +int ch7006_scale = 1; +module_param_named(scale, ch7006_scale, int, 0600); +MODULE_PARM_DESC(scale, "Default scale.\n" + "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n" + "\t\t\t1 -> Select default video modes.\n" + "\t\t\t2 -> Select video modes with a lower blanking ratio."); + +MODULE_AUTHOR("Francisco Jerez "); +MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver"); +MODULE_LICENSE("GPL and additional rights"); + +module_init(ch7006_init); +module_exit(ch7006_exit); diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c new file mode 100644 index 000000000000..6afe6d0ee630 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ch7006_priv.h" + +const char * const ch7006_tv_norm_names[] = { + [TV_NORM_PAL] = "PAL", + [TV_NORM_PAL_M] = "PAL-M", + [TV_NORM_PAL_N] = "PAL-N", + [TV_NORM_PAL_NC] = "PAL-Nc", + [TV_NORM_PAL_60] = "PAL-60", + [TV_NORM_NTSC_M] = "NTSC-M", + [TV_NORM_NTSC_J] = "NTSC-J", +}; + +#define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001, \ + .vdisplay = 480, \ + .vtotal = 525, \ + .hvirtual = 660 + +#define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1, \ + .vdisplay = 576, \ + .vtotal = 625, \ + .hvirtual = 810 + +const struct ch7006_tv_norm_info ch7006_tv_norms[] = { + [TV_NORM_NTSC_M] = { + NTSC_LIKE_TIMINGS, + .black_level = 0.339 * fixed1, + .subc_freq = 3579545 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC), + .voffset = 0, + }, + [TV_NORM_NTSC_J] = { + NTSC_LIKE_TIMINGS, + .black_level = 0.286 * fixed1, + .subc_freq = 3579545 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J), + .voffset = 0, + }, + [TV_NORM_PAL] = { + PAL_LIKE_TIMINGS, + .black_level = 0.3 * fixed1, + .subc_freq = 4433618.75 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), + .voffset = 0, + }, + [TV_NORM_PAL_M] = { + NTSC_LIKE_TIMINGS, + .black_level = 0.339 * fixed1, + .subc_freq = 3575611.433 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), + .voffset = 16, + }, + + /* The following modes seem to work right but they're + * undocumented */ + + [TV_NORM_PAL_N] = { + PAL_LIKE_TIMINGS, + .black_level = 0.339 * fixed1, + .subc_freq = 4433618.75 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), + .voffset = 0, + }, + [TV_NORM_PAL_NC] = { + PAL_LIKE_TIMINGS, + .black_level = 0.3 * fixed1, + .subc_freq = 3582056.25 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), + .voffset = 0, + }, + [TV_NORM_PAL_60] = { + NTSC_LIKE_TIMINGS, + .black_level = 0.3 * fixed1, + .subc_freq = 4433618.75 * fixed1, + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), + .voffset = 16, + }, +}; + +#define __MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ + subc, scale, scale_mask, norm_mask, e_hd, e_vd) { \ + .mode = { \ + .name = #hd "x" #vd, \ + .status = 0, \ + .type = DRM_MODE_TYPE_DRIVER, \ + .clock = f, \ + .hdisplay = hd, \ + .hsync_start = e_hd + 16, \ + .hsync_end = e_hd + 80, \ + .htotal = ht, \ + .hskew = 0, \ + .vdisplay = vd, \ + .vsync_start = vd + 10, \ + .vsync_end = vd + 26, \ + .vtotal = vt, \ + .vscan = 0, \ + .flags = DRM_MODE_FLAG_##hsynp##HSYNC | \ + DRM_MODE_FLAG_##vsynp##VSYNC, \ + }, \ + .enc_hdisp = e_hd, \ + .enc_vdisp = e_vd, \ + .subc_coeff = subc * fixed1, \ + .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \ + bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \ + .valid_scales = scale_mask, \ + .valid_norms = norm_mask \ + } + +#define MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ + subc, scale, scale_mask, norm_mask) \ + __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale, \ + scale_mask, norm_mask, hd, vd) + +#define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J | \ + 1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60) + +#define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) + +const struct ch7006_mode ch7006_modes[] = { + MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), + MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), + MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), + MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE), + MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE), + MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE), + MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE), + MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE), + MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE), + MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE), + MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE), + MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE), + MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE), + MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE), + MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE), + MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE), + MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE), + MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE), + MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE), + __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600), + MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE), + MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE), + MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE), + MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE), + MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE), + {} +}; + +const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, + const struct drm_display_mode *drm_mode) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + const struct ch7006_mode *mode; + + for (mode = ch7006_modes; mode->mode.clock; mode++) { + + if (~mode->valid_norms & 1<norm) + continue; + + if (mode->mode.hdisplay != drm_mode->hdisplay || + mode->mode.vdisplay != drm_mode->vdisplay || + mode->mode.vtotal != drm_mode->vtotal || + mode->mode.htotal != drm_mode->htotal || + mode->mode.clock != drm_mode->clock) + continue; + + return mode; + } + + return NULL; +} + +/* Some common HW state calculation code */ + +void ch7006_setup_levels(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + uint8_t *regs = priv->state.regs; + const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; + int gain; + int black_level; + + /* Set DAC_GAIN if the voltage drop between white and black is + * high enough. */ + if (norm->black_level < 339*fixed1/1000) { + gain = 76; + + regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN; + } else { + gain = 71; + + regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN; + } + + black_level = round_fixed(norm->black_level*26625)/gain; + + /* Correct it with the specified brightness. */ + black_level = interpolate(90, black_level, 208, priv->brightness); + + regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level); + + ch7006_dbg(client, "black level: %d\n", black_level); +} + +void ch7006_setup_subcarrier(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_state *state = &priv->state; + const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; + const struct ch7006_mode *mode = priv->mode; + uint32_t subc_inc; + + subc_inc = round_fixed((mode->subc_coeff >> 8) + * (norm->subc_freq >> 24)); + + setbitf(state, CH7006_SUBC_INC0, 28, subc_inc); + setbitf(state, CH7006_SUBC_INC1, 24, subc_inc); + setbitf(state, CH7006_SUBC_INC2, 20, subc_inc); + setbitf(state, CH7006_SUBC_INC3, 16, subc_inc); + setbitf(state, CH7006_SUBC_INC4, 12, subc_inc); + setbitf(state, CH7006_SUBC_INC5, 8, subc_inc); + setbitf(state, CH7006_SUBC_INC6, 4, subc_inc); + setbitf(state, CH7006_SUBC_INC7, 0, subc_inc); + + ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc); +} + +void ch7006_setup_pll(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + uint8_t *regs = priv->state.regs; + const struct ch7006_mode *mode = priv->mode; + int n, best_n = 0; + int m, best_m = 0; + int freq, best_freq = 0; + + for (n = 0; n < CH7006_MAXN; n++) { + for (m = 0; m < CH7006_MAXM; m++) { + freq = CH7006_FREQ0*(n+2)/(m+2); + + if (abs(freq - mode->mode.clock) < + abs(best_freq - mode->mode.clock)) { + best_freq = freq; + best_n = n; + best_m = m; + } + } + } + + regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) | + bitf(CH7006_PLLOV_M_8, best_m); + + regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m); + regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n); + + if (best_n < 108) + regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR; + else + regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR; + + ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n", + best_n, best_m, best_freq, best_n < 108); +} + +void ch7006_setup_power_state(struct drm_encoder *encoder) +{ + struct ch7006_priv *priv = to_ch7006_priv(encoder); + uint8_t *power = &priv->state.regs[CH7006_POWER]; + int subconnector; + + subconnector = priv->select_subconnector ? priv->select_subconnector : + priv->subconnector; + + *power = CH7006_POWER_RESET; + + if (priv->last_dpms == DRM_MODE_DPMS_ON) { + switch (subconnector) { + case DRM_MODE_SUBCONNECTOR_SVIDEO: + *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF); + break; + case DRM_MODE_SUBCONNECTOR_Composite: + *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF); + break; + case DRM_MODE_SUBCONNECTOR_SCART: + *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) | + CH7006_POWER_SCART; + break; + } + + } else { + if (priv->chip_version >= 0x20) + *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); + else + *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); + } +} + +void ch7006_setup_properties(struct drm_encoder *encoder) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); + struct ch7006_state *state = &priv->state; + const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; + const struct ch7006_mode *ch_mode = priv->mode; + const struct drm_display_mode *mode = &ch_mode->mode; + uint8_t *regs = state->regs; + int flicker, contrast, hpos, vpos; + uint64_t scale, aspect; + + flicker = interpolate(0, 2, 3, priv->flicker); + regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) | + bitf(CH7006_FFILTER_LUMA, flicker) | + bitf(CH7006_FFILTER_CHROMA, 1); + + contrast = interpolate(0, 5, 7, priv->contrast); + regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast); + + scale = norm->vtotal*fixed1; + do_div(scale, mode->vtotal); + + aspect = ch_mode->enc_hdisp*fixed1; + do_div(aspect, ch_mode->enc_vdisp); + + hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale) + * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4; + + setbitf(state, CH7006_POV, HPOS_8, hpos); + setbitf(state, CH7006_HPOS, 0, hpos); + + vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale) + + norm->voffset) * priv->vmargin / 100 / 2; + + setbitf(state, CH7006_POV, VPOS_8, vpos); + setbitf(state, CH7006_VPOS, 0, vpos); + + ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos); +} + +/* HW access functions */ + +void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val) +{ + uint8_t buf[] = {addr, val}; + int ret; + + ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); + if (ret < 0) + ch7006_err(client, "Error %d writing to subaddress 0x%x\n", + ret, addr); +} + +uint8_t ch7006_read(struct i2c_client *client, uint8_t addr) +{ + uint8_t val; + int ret; + + ret = i2c_master_send(client, &addr, sizeof(addr)); + if (ret < 0) + goto fail; + + ret = i2c_master_recv(client, &val, sizeof(val)); + if (ret < 0) + goto fail; + + return val; + +fail: + ch7006_err(client, "Error %d reading from subaddress 0x%x\n", + ret, addr); + return 0; +} + +void ch7006_state_load(struct i2c_client *client, + struct ch7006_state *state) +{ + ch7006_load_reg(client, state, CH7006_POWER); + + ch7006_load_reg(client, state, CH7006_DISPMODE); + ch7006_load_reg(client, state, CH7006_FFILTER); + ch7006_load_reg(client, state, CH7006_BWIDTH); + ch7006_load_reg(client, state, CH7006_INPUT_FORMAT); + ch7006_load_reg(client, state, CH7006_CLKMODE); + ch7006_load_reg(client, state, CH7006_START_ACTIVE); + ch7006_load_reg(client, state, CH7006_POV); + ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); + ch7006_load_reg(client, state, CH7006_HPOS); + ch7006_load_reg(client, state, CH7006_VPOS); + ch7006_load_reg(client, state, CH7006_INPUT_SYNC); + ch7006_load_reg(client, state, CH7006_DETECT); + ch7006_load_reg(client, state, CH7006_CONTRAST); + ch7006_load_reg(client, state, CH7006_PLLOV); + ch7006_load_reg(client, state, CH7006_PLLM); + ch7006_load_reg(client, state, CH7006_PLLN); + ch7006_load_reg(client, state, CH7006_BCLKOUT); + ch7006_load_reg(client, state, CH7006_SUBC_INC0); + ch7006_load_reg(client, state, CH7006_SUBC_INC1); + ch7006_load_reg(client, state, CH7006_SUBC_INC2); + ch7006_load_reg(client, state, CH7006_SUBC_INC3); + ch7006_load_reg(client, state, CH7006_SUBC_INC4); + ch7006_load_reg(client, state, CH7006_SUBC_INC5); + ch7006_load_reg(client, state, CH7006_SUBC_INC6); + ch7006_load_reg(client, state, CH7006_SUBC_INC7); + ch7006_load_reg(client, state, CH7006_PLL_CONTROL); + ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0); +} + +void ch7006_state_save(struct i2c_client *client, + struct ch7006_state *state) +{ + ch7006_save_reg(client, state, CH7006_POWER); + + ch7006_save_reg(client, state, CH7006_DISPMODE); + ch7006_save_reg(client, state, CH7006_FFILTER); + ch7006_save_reg(client, state, CH7006_BWIDTH); + ch7006_save_reg(client, state, CH7006_INPUT_FORMAT); + ch7006_save_reg(client, state, CH7006_CLKMODE); + ch7006_save_reg(client, state, CH7006_START_ACTIVE); + ch7006_save_reg(client, state, CH7006_POV); + ch7006_save_reg(client, state, CH7006_BLACK_LEVEL); + ch7006_save_reg(client, state, CH7006_HPOS); + ch7006_save_reg(client, state, CH7006_VPOS); + ch7006_save_reg(client, state, CH7006_INPUT_SYNC); + ch7006_save_reg(client, state, CH7006_DETECT); + ch7006_save_reg(client, state, CH7006_CONTRAST); + ch7006_save_reg(client, state, CH7006_PLLOV); + ch7006_save_reg(client, state, CH7006_PLLM); + ch7006_save_reg(client, state, CH7006_PLLN); + ch7006_save_reg(client, state, CH7006_BCLKOUT); + ch7006_save_reg(client, state, CH7006_SUBC_INC0); + ch7006_save_reg(client, state, CH7006_SUBC_INC1); + ch7006_save_reg(client, state, CH7006_SUBC_INC2); + ch7006_save_reg(client, state, CH7006_SUBC_INC3); + ch7006_save_reg(client, state, CH7006_SUBC_INC4); + ch7006_save_reg(client, state, CH7006_SUBC_INC5); + ch7006_save_reg(client, state, CH7006_SUBC_INC6); + ch7006_save_reg(client, state, CH7006_SUBC_INC7); + ch7006_save_reg(client, state, CH7006_PLL_CONTROL); + ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0); + + state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) | + (state->regs[CH7006_FFILTER] & 0x0c) >> 2 | + (state->regs[CH7006_FFILTER] & 0x03) << 2; +} diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h new file mode 100644 index 000000000000..d7a91e17510f --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __NOUVEAU_I2C_CH7006_PRIV_H__ +#define __NOUVEAU_I2C_CH7006_PRIV_H__ + +#include +#include + +#include + +typedef int64_t fixed; +#define fixed1 (1LL << 32) + +enum ch7006_tv_norm { + TV_NORM_PAL, + TV_NORM_PAL_M, + TV_NORM_PAL_N, + TV_NORM_PAL_NC, + TV_NORM_PAL_60, + TV_NORM_NTSC_M, + TV_NORM_NTSC_J, + NUM_TV_NORMS +}; + +struct ch7006_tv_norm_info { + fixed vrefresh; + int vdisplay; + int vtotal; + int hvirtual; + + fixed subc_freq; + fixed black_level; + + uint32_t dispmode; + int voffset; +}; + +struct ch7006_mode { + struct drm_display_mode mode; + + int enc_hdisp; + int enc_vdisp; + + fixed subc_coeff; + uint32_t dispmode; + + uint32_t valid_scales; + uint32_t valid_norms; +}; + +struct ch7006_state { + uint8_t regs[0x26]; +}; + +struct ch7006_priv { + struct ch7006_encoder_params params; + const struct ch7006_mode *mode; + + struct ch7006_state state; + struct ch7006_state saved_state; + + struct drm_property *scale_property; + + int select_subconnector; + int subconnector; + int hmargin; + int vmargin; + enum ch7006_tv_norm norm; + int brightness; + int contrast; + int flicker; + int scale; + + int chip_version; + int last_dpms; +}; + +#define to_ch7006_priv(x) \ + ((struct ch7006_priv *)to_encoder_slave(x)->slave_priv) + +extern int ch7006_debug; +extern char *ch7006_tv_norm; +extern int ch7006_scale; + +extern const char * const ch7006_tv_norm_names[]; +extern const struct ch7006_tv_norm_info ch7006_tv_norms[]; +extern const struct ch7006_mode ch7006_modes[]; + +const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, + const struct drm_display_mode *drm_mode); + +void ch7006_setup_levels(struct drm_encoder *encoder); +void ch7006_setup_subcarrier(struct drm_encoder *encoder); +void ch7006_setup_pll(struct drm_encoder *encoder); +void ch7006_setup_power_state(struct drm_encoder *encoder); +void ch7006_setup_properties(struct drm_encoder *encoder); + +void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val); +uint8_t ch7006_read(struct i2c_client *client, uint8_t addr); + +void ch7006_state_load(struct i2c_client *client, + struct ch7006_state *state); +void ch7006_state_save(struct i2c_client *client, + struct ch7006_state *state); + +/* Some helper macros */ + +#define ch7006_dbg(client, format, ...) do { \ + if (ch7006_debug) \ + dev_printk(KERN_DEBUG, &client->dev, \ + "%s: " format, __func__, ## __VA_ARGS__); \ + } while (0) +#define ch7006_info(client, format, ...) \ + dev_info(&client->dev, format, __VA_ARGS__) +#define ch7006_err(client, format, ...) \ + dev_err(&client->dev, format, __VA_ARGS__) + +#define __mask(src, bitfield) \ + (((2 << (1 ? bitfield)) - 1) & ~((1 << (0 ? bitfield)) - 1)) +#define mask(bitfield) __mask(bitfield) + +#define __bitf(src, bitfield, x) \ + (((x) >> (src) << (0 ? bitfield)) & __mask(src, bitfield)) +#define bitf(bitfield, x) __bitf(bitfield, x) +#define bitfs(bitfield, s) __bitf(bitfield, bitfield##_##s) +#define setbitf(state, reg, bitfield, x) \ + state->regs[reg] = (state->regs[reg] & ~mask(reg##_##bitfield)) \ + | bitf(reg##_##bitfield, x) + +#define __unbitf(src, bitfield, x) \ + ((x & __mask(src, bitfield)) >> (0 ? bitfield) << (src)) +#define unbitf(bitfield, x) __unbitf(bitfield, x) + +static inline int interpolate(int y0, int y1, int y2, int x) +{ + return y1 + (x < 50 ? y1 - y0 : y2 - y1) * (x - 50) / 50; +} + +static inline int32_t round_fixed(fixed x) +{ + return (x + fixed1/2) >> 32; +} + +#define ch7006_load_reg(client, state, reg) ch7006_write(client, reg, state->regs[reg]) +#define ch7006_save_reg(client, state, reg) state->regs[reg] = ch7006_read(client, reg) + +/* Fixed hardware specs */ + +#define CH7006_FREQ0 14318 +#define CH7006_MAXN 650 +#define CH7006_MAXM 315 + +/* Register definitions */ + +#define CH7006_DISPMODE 0x00 +#define CH7006_DISPMODE_INPUT_RES 0, 7:5 +#define CH7006_DISPMODE_INPUT_RES_512x384 0x0 +#define CH7006_DISPMODE_INPUT_RES_720x400 0x1 +#define CH7006_DISPMODE_INPUT_RES_640x400 0x2 +#define CH7006_DISPMODE_INPUT_RES_640x480 0x3 +#define CH7006_DISPMODE_INPUT_RES_800x600 0x4 +#define CH7006_DISPMODE_INPUT_RES_NATIVE 0x5 +#define CH7006_DISPMODE_OUTPUT_STD 0, 4:3 +#define CH7006_DISPMODE_OUTPUT_STD_PAL 0x0 +#define CH7006_DISPMODE_OUTPUT_STD_NTSC 0x1 +#define CH7006_DISPMODE_OUTPUT_STD_PAL_M 0x2 +#define CH7006_DISPMODE_OUTPUT_STD_NTSC_J 0x3 +#define CH7006_DISPMODE_SCALING_RATIO 0, 2:0 +#define CH7006_DISPMODE_SCALING_RATIO_5_4 0x0 +#define CH7006_DISPMODE_SCALING_RATIO_1_1 0x1 +#define CH7006_DISPMODE_SCALING_RATIO_7_8 0x2 +#define CH7006_DISPMODE_SCALING_RATIO_5_6 0x3 +#define CH7006_DISPMODE_SCALING_RATIO_3_4 0x4 +#define CH7006_DISPMODE_SCALING_RATIO_7_10 0x5 + +#define CH7006_FFILTER 0x01 +#define CH7006_FFILTER_TEXT 0, 5:4 +#define CH7006_FFILTER_LUMA 0, 3:2 +#define CH7006_FFILTER_CHROMA 0, 1:0 +#define CH7006_FFILTER_CHROMA_NO_DCRAWL 0x3 + +#define CH7006_BWIDTH 0x03 +#define CH7006_BWIDTH_5L_FFILER (1 << 7) +#define CH7006_BWIDTH_CVBS_NO_CHROMA (1 << 6) +#define CH7006_BWIDTH_CHROMA 0, 5:4 +#define CH7006_BWIDTH_SVIDEO_YPEAK (1 << 3) +#define CH7006_BWIDTH_SVIDEO_LUMA 0, 2:1 +#define CH7006_BWIDTH_CVBS_LUMA 0, 0:0 + +#define CH7006_INPUT_FORMAT 0x04 +#define CH7006_INPUT_FORMAT_DAC_GAIN (1 << 6) +#define CH7006_INPUT_FORMAT_RGB_PASS_THROUGH (1 << 5) +#define CH7006_INPUT_FORMAT_FORMAT 0, 3:0 +#define CH7006_INPUT_FORMAT_FORMAT_RGB16 0x0 +#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m16 0x1 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m16 0x2 +#define CH7006_INPUT_FORMAT_FORMAT_RGB15 0x3 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12C 0x4 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12I 0x5 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m8 0x6 +#define CH7006_INPUT_FORMAT_FORMAT_RGB16m8 0x7 +#define CH7006_INPUT_FORMAT_FORMAT_RGB15m8 0x8 +#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m8 0x9 + +#define CH7006_CLKMODE 0x06 +#define CH7006_CLKMODE_SUBC_LOCK (1 << 7) +#define CH7006_CLKMODE_MASTER (1 << 6) +#define CH7006_CLKMODE_POS_EDGE (1 << 4) +#define CH7006_CLKMODE_XCM 0, 3:2 +#define CH7006_CLKMODE_PCM 0, 1:0 + +#define CH7006_START_ACTIVE 0x07 +#define CH7006_START_ACTIVE_0 0, 7:0 + +#define CH7006_POV 0x08 +#define CH7006_POV_START_ACTIVE_8 8, 2:2 +#define CH7006_POV_HPOS_8 8, 1:1 +#define CH7006_POV_VPOS_8 8, 0:0 + +#define CH7006_BLACK_LEVEL 0x09 +#define CH7006_BLACK_LEVEL_0 0, 7:0 + +#define CH7006_HPOS 0x0a +#define CH7006_HPOS_0 0, 7:0 + +#define CH7006_VPOS 0x0b +#define CH7006_VPOS_0 0, 7:0 + +#define CH7006_INPUT_SYNC 0x0d +#define CH7006_INPUT_SYNC_EMBEDDED (1 << 3) +#define CH7006_INPUT_SYNC_OUTPUT (1 << 2) +#define CH7006_INPUT_SYNC_PVSYNC (1 << 1) +#define CH7006_INPUT_SYNC_PHSYNC (1 << 0) + +#define CH7006_POWER 0x0e +#define CH7006_POWER_SCART (1 << 4) +#define CH7006_POWER_RESET (1 << 3) +#define CH7006_POWER_LEVEL 0, 2:0 +#define CH7006_POWER_LEVEL_CVBS_OFF 0x0 +#define CH7006_POWER_LEVEL_POWER_OFF 0x1 +#define CH7006_POWER_LEVEL_SVIDEO_OFF 0x2 +#define CH7006_POWER_LEVEL_NORMAL 0x3 +#define CH7006_POWER_LEVEL_FULL_POWER_OFF 0x4 + +#define CH7006_DETECT 0x10 +#define CH7006_DETECT_SVIDEO_Y_TEST (1 << 3) +#define CH7006_DETECT_SVIDEO_C_TEST (1 << 2) +#define CH7006_DETECT_CVBS_TEST (1 << 1) +#define CH7006_DETECT_SENSE (1 << 0) + +#define CH7006_CONTRAST 0x11 +#define CH7006_CONTRAST_0 0, 2:0 + +#define CH7006_PLLOV 0x13 +#define CH7006_PLLOV_N_8 8, 2:1 +#define CH7006_PLLOV_M_8 8, 0:0 + +#define CH7006_PLLM 0x14 +#define CH7006_PLLM_0 0, 7:0 + +#define CH7006_PLLN 0x15 +#define CH7006_PLLN_0 0, 7:0 + +#define CH7006_BCLKOUT 0x17 + +#define CH7006_SUBC_INC0 0x18 +#define CH7006_SUBC_INC0_28 28, 3:0 + +#define CH7006_SUBC_INC1 0x19 +#define CH7006_SUBC_INC1_24 24, 3:0 + +#define CH7006_SUBC_INC2 0x1a +#define CH7006_SUBC_INC2_20 20, 3:0 + +#define CH7006_SUBC_INC3 0x1b +#define CH7006_SUBC_INC3_GPIO1_VAL (1 << 7) +#define CH7006_SUBC_INC3_GPIO0_VAL (1 << 6) +#define CH7006_SUBC_INC3_POUT_3_3V (1 << 5) +#define CH7006_SUBC_INC3_POUT_INV (1 << 4) +#define CH7006_SUBC_INC3_16 16, 3:0 + +#define CH7006_SUBC_INC4 0x1c +#define CH7006_SUBC_INC4_GPIO1_IN (1 << 7) +#define CH7006_SUBC_INC4_GPIO0_IN (1 << 6) +#define CH7006_SUBC_INC4_DS_INPUT (1 << 4) +#define CH7006_SUBC_INC4_12 12, 3:0 + +#define CH7006_SUBC_INC5 0x1d +#define CH7006_SUBC_INC5_8 8, 3:0 + +#define CH7006_SUBC_INC6 0x1e +#define CH7006_SUBC_INC6_4 4, 3:0 + +#define CH7006_SUBC_INC7 0x1f +#define CH7006_SUBC_INC7_0 0, 3:0 + +#define CH7006_PLL_CONTROL 0x20 +#define CH7006_PLL_CONTROL_CPI (1 << 5) +#define CH7006_PLL_CONTROL_CAPACITOR (1 << 4) +#define CH7006_PLL_CONTROL_7STAGES (1 << 3) +#define CH7006_PLL_CONTROL_DIGITAL_5V (1 << 2) +#define CH7006_PLL_CONTROL_ANALOG_5V (1 << 1) +#define CH7006_PLL_CONTROL_MEMORY_5V (1 << 0) + +#define CH7006_CALC_SUBC_INC0 0x21 +#define CH7006_CALC_SUBC_INC0_24 24, 4:3 +#define CH7006_CALC_SUBC_INC0_HYST 0, 2:1 +#define CH7006_CALC_SUBC_INC0_AUTO (1 << 0) + +#define CH7006_CALC_SUBC_INC1 0x22 +#define CH7006_CALC_SUBC_INC1_16 16, 7:0 + +#define CH7006_CALC_SUBC_INC2 0x23 +#define CH7006_CALC_SUBC_INC2_8 8, 7:0 + +#define CH7006_CALC_SUBC_INC3 0x24 +#define CH7006_CALC_SUBC_INC3_0 0, 7:0 + +#define CH7006_VERSION_ID 0x25 + +#endif diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c new file mode 100644 index 000000000000..39b01c897518 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +#include +#include +#include +#include + +#include + +struct sil164_priv { + struct sil164_encoder_params config; + struct i2c_client *duallink_slave; + + uint8_t saved_state[0x10]; + uint8_t saved_slave_state[0x10]; +}; + +#define to_sil164_priv(x) \ + ((struct sil164_priv *)to_encoder_slave(x)->slave_priv) + +#define sil164_dbg(client, format, ...) do { \ + if (drm_debug_enabled(DRM_UT_KMS)) \ + dev_printk(KERN_DEBUG, &client->dev, \ + "%s: " format, __func__, ## __VA_ARGS__); \ + } while (0) +#define sil164_info(client, format, ...) \ + dev_info(&client->dev, format, __VA_ARGS__) +#define sil164_err(client, format, ...) \ + dev_err(&client->dev, format, __VA_ARGS__) + +#define SIL164_I2C_ADDR_MASTER 0x38 +#define SIL164_I2C_ADDR_SLAVE 0x39 + +/* HW register definitions */ + +#define SIL164_VENDOR_LO 0x0 +#define SIL164_VENDOR_HI 0x1 +#define SIL164_DEVICE_LO 0x2 +#define SIL164_DEVICE_HI 0x3 +#define SIL164_REVISION 0x4 +#define SIL164_FREQ_MIN 0x6 +#define SIL164_FREQ_MAX 0x7 +#define SIL164_CONTROL0 0x8 +# define SIL164_CONTROL0_POWER_ON 0x01 +# define SIL164_CONTROL0_EDGE_RISING 0x02 +# define SIL164_CONTROL0_INPUT_24BIT 0x04 +# define SIL164_CONTROL0_DUAL_EDGE 0x08 +# define SIL164_CONTROL0_HSYNC_ON 0x10 +# define SIL164_CONTROL0_VSYNC_ON 0x20 +#define SIL164_DETECT 0x9 +# define SIL164_DETECT_INTR_STAT 0x01 +# define SIL164_DETECT_HOTPLUG_STAT 0x02 +# define SIL164_DETECT_RECEIVER_STAT 0x04 +# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00 +# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08 +# define SIL164_DETECT_OUT_MODE_HIGH 0x00 +# define SIL164_DETECT_OUT_MODE_INTR 0x10 +# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20 +# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30 +# define SIL164_DETECT_VSWING_STAT 0x80 +#define SIL164_CONTROL1 0xa +# define SIL164_CONTROL1_DESKEW_ENABLE 0x10 +# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5 +#define SIL164_GPIO 0xb +#define SIL164_CONTROL2 0xc +# define SIL164_CONTROL2_FILTER_ENABLE 0x01 +# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1 +# define SIL164_CONTROL2_DUALLINK_MASTER 0x40 +# define SIL164_CONTROL2_SYNC_CONT 0x80 +#define SIL164_DUALLINK 0xd +# define SIL164_DUALLINK_ENABLE 0x10 +# define SIL164_DUALLINK_SKEW_SHIFT 5 +#define SIL164_PLLZONE 0xe +# define SIL164_PLLZONE_STAT 0x08 +# define SIL164_PLLZONE_FORCE_ON 0x10 +# define SIL164_PLLZONE_FORCE_HIGH 0x20 + +/* HW access functions */ + +static void +sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val) +{ + uint8_t buf[] = {addr, val}; + int ret; + + ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); + if (ret < 0) + sil164_err(client, "Error %d writing to subaddress 0x%x\n", + ret, addr); +} + +static uint8_t +sil164_read(struct i2c_client *client, uint8_t addr) +{ + uint8_t val; + int ret; + + ret = i2c_master_send(client, &addr, sizeof(addr)); + if (ret < 0) + goto fail; + + ret = i2c_master_recv(client, &val, sizeof(val)); + if (ret < 0) + goto fail; + + return val; + +fail: + sil164_err(client, "Error %d reading from subaddress 0x%x\n", + ret, addr); + return 0; +} + +static void +sil164_save_state(struct i2c_client *client, uint8_t *state) +{ + int i; + + for (i = 0x8; i <= 0xe; i++) + state[i] = sil164_read(client, i); +} + +static void +sil164_restore_state(struct i2c_client *client, uint8_t *state) +{ + int i; + + for (i = 0x8; i <= 0xe; i++) + sil164_write(client, i, state[i]); +} + +static void +sil164_set_power_state(struct i2c_client *client, bool on) +{ + uint8_t control0 = sil164_read(client, SIL164_CONTROL0); + + if (on) + control0 |= SIL164_CONTROL0_POWER_ON; + else + control0 &= ~SIL164_CONTROL0_POWER_ON; + + sil164_write(client, SIL164_CONTROL0, control0); +} + +static void +sil164_init_state(struct i2c_client *client, + struct sil164_encoder_params *config, + bool duallink) +{ + sil164_write(client, SIL164_CONTROL0, + SIL164_CONTROL0_HSYNC_ON | + SIL164_CONTROL0_VSYNC_ON | + (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) | + (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) | + (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0)); + + sil164_write(client, SIL164_DETECT, + SIL164_DETECT_INTR_STAT | + SIL164_DETECT_OUT_MODE_RECEIVER); + + sil164_write(client, SIL164_CONTROL1, + (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) | + (((config->input_skew + 4) & 0x7) + << SIL164_CONTROL1_DESKEW_INCR_SHIFT)); + + sil164_write(client, SIL164_CONTROL2, + SIL164_CONTROL2_SYNC_CONT | + (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) | + (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT)); + + sil164_write(client, SIL164_PLLZONE, 0); + + if (duallink) + sil164_write(client, SIL164_DUALLINK, + SIL164_DUALLINK_ENABLE | + (((config->duallink_skew + 4) & 0x7) + << SIL164_DUALLINK_SKEW_SHIFT)); + else + sil164_write(client, SIL164_DUALLINK, 0); +} + +/* DRM encoder functions */ + +static void +sil164_encoder_set_config(struct drm_encoder *encoder, void *params) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + priv->config = *(struct sil164_encoder_params *)params; +} + +static void +sil164_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + bool on = (mode == DRM_MODE_DPMS_ON); + bool duallink = (on && encoder->crtc->mode.clock > 165000); + + sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on); + + if (priv->duallink_slave) + sil164_set_power_state(priv->duallink_slave, duallink); +} + +static void +sil164_encoder_save(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + sil164_save_state(drm_i2c_encoder_get_client(encoder), + priv->saved_state); + + if (priv->duallink_slave) + sil164_save_state(priv->duallink_slave, + priv->saved_slave_state); +} + +static void +sil164_encoder_restore(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + sil164_restore_state(drm_i2c_encoder_get_client(encoder), + priv->saved_state); + + if (priv->duallink_slave) + sil164_restore_state(priv->duallink_slave, + priv->saved_slave_state); +} + +static int +sil164_encoder_mode_valid(struct drm_encoder *encoder, + const struct drm_display_mode *mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + if (mode->clock < 32000) + return MODE_CLOCK_LOW; + + if (mode->clock > 330000 || + (mode->clock > 165000 && !priv->duallink_slave)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void +sil164_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + bool duallink = adjusted_mode->clock > 165000; + + sil164_init_state(drm_i2c_encoder_get_client(encoder), + &priv->config, duallink); + + if (priv->duallink_slave) + sil164_init_state(priv->duallink_slave, + &priv->config, duallink); + + sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static enum drm_connector_status +sil164_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + + if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static int +sil164_encoder_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + return 0; +} + +static int +sil164_encoder_create_resources(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + return 0; +} + +static int +sil164_encoder_set_property(struct drm_encoder *encoder, + struct drm_connector *connector, + struct drm_property *property, + uint64_t val) +{ + return 0; +} + +static void +sil164_encoder_destroy(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + i2c_unregister_device(priv->duallink_slave); + + kfree(priv); + drm_i2c_encoder_destroy(encoder); +} + +static const struct drm_encoder_slave_funcs sil164_encoder_funcs = { + .set_config = sil164_encoder_set_config, + .destroy = sil164_encoder_destroy, + .dpms = sil164_encoder_dpms, + .save = sil164_encoder_save, + .restore = sil164_encoder_restore, + .mode_valid = sil164_encoder_mode_valid, + .mode_set = sil164_encoder_mode_set, + .detect = sil164_encoder_detect, + .get_modes = sil164_encoder_get_modes, + .create_resources = sil164_encoder_create_resources, + .set_property = sil164_encoder_set_property, +}; + +/* I2C driver functions */ + +static int +sil164_probe(struct i2c_client *client) +{ + int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 | + sil164_read(client, SIL164_VENDOR_LO); + int device = sil164_read(client, SIL164_DEVICE_HI) << 8 | + sil164_read(client, SIL164_DEVICE_LO); + int rev = sil164_read(client, SIL164_REVISION); + + if (vendor != 0x1 || device != 0x6) { + sil164_dbg(client, "Unknown device %x:%x.%x\n", + vendor, device, rev); + return -ENODEV; + } + + sil164_info(client, "Detected device %x:%x.%x\n", + vendor, device, rev); + + return 0; +} + +static struct i2c_client * +sil164_detect_slave(struct i2c_client *client) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg = { + .addr = SIL164_I2C_ADDR_SLAVE, + .len = 0, + }; + const struct i2c_board_info info = { + I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE) + }; + + if (i2c_transfer(adap, &msg, 1) != 1) { + sil164_dbg(adap, "No dual-link slave found."); + return NULL; + } + + return i2c_new_client_device(adap, &info); +} + +static int +sil164_encoder_init(struct i2c_client *client, + struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + struct sil164_priv *priv; + struct i2c_client *slave_client; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + encoder->slave_priv = priv; + encoder->slave_funcs = &sil164_encoder_funcs; + + slave_client = sil164_detect_slave(client); + if (!IS_ERR(slave_client)) + priv->duallink_slave = slave_client; + + return 0; +} + +static const struct i2c_device_id sil164_ids[] = { + { "sil164" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sil164_ids); + +static struct drm_i2c_encoder_driver sil164_driver = { + .i2c_driver = { + .probe = sil164_probe, + .driver = { + .name = "sil164", + }, + .id_table = sil164_ids, + }, + .encoder_init = sil164_encoder_init, +}; + +/* Module initialization */ + +static int __init +sil164_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver); +} + +static void __exit +sil164_exit(void) +{ + drm_i2c_encoder_unregister(&sil164_driver); +} + +MODULE_AUTHOR("Francisco Jerez "); +MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver"); +MODULE_LICENSE("GPL and additional rights"); + +module_init(sil164_init); +module_exit(sil164_exit); diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index d3014027a812..4ffd8af6bf8b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -32,7 +32,7 @@ #include "hw.h" #include -#include +#include static struct nvkm_i2c_bus_probe nv04_tv_encoder_info[] = { { diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/ch7006.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/ch7006.h new file mode 100644 index 000000000000..1a6fa405f85b --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/ch7006.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __NOUVEAU_I2C_CH7006_H__ +#define __NOUVEAU_I2C_CH7006_H__ + +/** + * struct ch7006_encoder_params + * + * Describes how the ch7006 is wired up with the GPU. It should be + * used as the @params parameter of its @set_config method. + * + * See "http://www.chrontel.com/pdf/7006.pdf" for their precise + * meaning. + */ +struct ch7006_encoder_params { + /* private: FIXME: document the members */ + enum { + CH7006_FORMAT_RGB16 = 0, + CH7006_FORMAT_YCrCb24m16, + CH7006_FORMAT_RGB24m16, + CH7006_FORMAT_RGB15, + CH7006_FORMAT_RGB24m12C, + CH7006_FORMAT_RGB24m12I, + CH7006_FORMAT_RGB24m8, + CH7006_FORMAT_RGB16m8, + CH7006_FORMAT_RGB15m8, + CH7006_FORMAT_YCrCb24m8, + } input_format; + + enum { + CH7006_CLOCK_SLAVE = 0, + CH7006_CLOCK_MASTER, + } clock_mode; + + enum { + CH7006_CLOCK_EDGE_NEG = 0, + CH7006_CLOCK_EDGE_POS, + } clock_edge; + + int xcm, pcm; + + enum { + CH7006_SYNC_SLAVE = 0, + CH7006_SYNC_MASTER, + } sync_direction; + + enum { + CH7006_SYNC_SEPARATED = 0, + CH7006_SYNC_EMBEDDED, + } sync_encoding; + + enum { + CH7006_POUT_1_8V = 0, + CH7006_POUT_3_3V, + } pout_level; + + enum { + CH7006_ACTIVE_HSYNC = 0, + CH7006_ACTIVE_DSTART, + } active_detect; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/sil164.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/sil164.h new file mode 100644 index 000000000000..b86750d7abe1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/sil164.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __NOUVEAU_I2C_SIL164_H__ +#define __NOUVEAU_I2C_SIL164_H__ + +/** + * struct sil164_encoder_params + * + * Describes how the sil164 is connected to the GPU. It should be used + * as the @params parameter of its @set_config method. + * + * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf". + */ +struct sil164_encoder_params { + /* private: FIXME: document the members */ + enum { + SIL164_INPUT_EDGE_FALLING = 0, + SIL164_INPUT_EDGE_RISING + } input_edge; + + enum { + SIL164_INPUT_WIDTH_12BIT = 0, + SIL164_INPUT_WIDTH_24BIT + } input_width; + + enum { + SIL164_INPUT_SINGLE_EDGE = 0, + SIL164_INPUT_DUAL_EDGE + } input_dual; + + enum { + SIL164_PLL_FILTER_ON = 0, + SIL164_PLL_FILTER_OFF, + } pll_filter; + + int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */ + int duallink_skew; /** < Allowed range [-4, 3]. */ +}; + +#endif diff --git a/include/drm/i2c/ch7006.h b/include/drm/i2c/ch7006.h deleted file mode 100644 index 5305b9797f93..000000000000 --- a/include/drm/i2c/ch7006.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __DRM_I2C_CH7006_H__ -#define __DRM_I2C_CH7006_H__ - -/** - * struct ch7006_encoder_params - * - * Describes how the ch7006 is wired up with the GPU. It should be - * used as the @params parameter of its @set_config method. - * - * See "http://www.chrontel.com/pdf/7006.pdf" for their precise - * meaning. - */ -struct ch7006_encoder_params { - /* private: FIXME: document the members */ - enum { - CH7006_FORMAT_RGB16 = 0, - CH7006_FORMAT_YCrCb24m16, - CH7006_FORMAT_RGB24m16, - CH7006_FORMAT_RGB15, - CH7006_FORMAT_RGB24m12C, - CH7006_FORMAT_RGB24m12I, - CH7006_FORMAT_RGB24m8, - CH7006_FORMAT_RGB16m8, - CH7006_FORMAT_RGB15m8, - CH7006_FORMAT_YCrCb24m8, - } input_format; - - enum { - CH7006_CLOCK_SLAVE = 0, - CH7006_CLOCK_MASTER, - } clock_mode; - - enum { - CH7006_CLOCK_EDGE_NEG = 0, - CH7006_CLOCK_EDGE_POS, - } clock_edge; - - int xcm, pcm; - - enum { - CH7006_SYNC_SLAVE = 0, - CH7006_SYNC_MASTER, - } sync_direction; - - enum { - CH7006_SYNC_SEPARATED = 0, - CH7006_SYNC_EMBEDDED, - } sync_encoding; - - enum { - CH7006_POUT_1_8V = 0, - CH7006_POUT_3_3V, - } pout_level; - - enum { - CH7006_ACTIVE_HSYNC = 0, - CH7006_ACTIVE_DSTART, - } active_detect; -}; - -#endif diff --git a/include/drm/i2c/sil164.h b/include/drm/i2c/sil164.h deleted file mode 100644 index ddf248693c8b..000000000000 --- a/include/drm/i2c/sil164.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __DRM_I2C_SIL164_H__ -#define __DRM_I2C_SIL164_H__ - -/** - * struct sil164_encoder_params - * - * Describes how the sil164 is connected to the GPU. It should be used - * as the @params parameter of its @set_config method. - * - * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf". - */ -struct sil164_encoder_params { - /* private: FIXME: document the members */ - enum { - SIL164_INPUT_EDGE_FALLING = 0, - SIL164_INPUT_EDGE_RISING - } input_edge; - - enum { - SIL164_INPUT_WIDTH_12BIT = 0, - SIL164_INPUT_WIDTH_24BIT - } input_width; - - enum { - SIL164_INPUT_SINGLE_EDGE = 0, - SIL164_INPUT_DUAL_EDGE - } input_dual; - - enum { - SIL164_PLL_FILTER_ON = 0, - SIL164_PLL_FILTER_OFF, - } pll_filter; - - int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */ - int duallink_skew; /** < Allowed range [-4, 3]. */ -}; - -#endif -- cgit v1.2.3 From a73583107af9b42c0a28045e4e30ec3fab2dbcd1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 6 Jan 2025 01:00:14 +0200 Subject: drm/nouveau: vendor in drm_encoder_slave API Nouveau driver is the only user of the drm_encoder_slave API. Rework necessary bits of drm_encoder_slave into the nouveau_i2c_encoder API and drop drm_encoder_slave.c from the DRM KMS helper. Suggested-by: Laurent Pinchart Signed-off-by: Dmitry Baryshkov Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20250106-nouveau-encoder-slave-v3-2-1d37d2f2c67f@linaro.org --- drivers/gpu/drm/Makefile | 1 - drivers/gpu/drm/drm_encoder_slave.c | 182 ---------------- drivers/gpu/drm/nouveau/dispnv04/Kbuild | 1 + drivers/gpu/drm/nouveau/dispnv04/dfp.c | 15 +- drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c | 30 +-- drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c | 8 +- drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h | 4 +- drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c | 30 +-- .../gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c | 145 +++++++++++++ drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | 22 +- drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | 4 +- .../drm/nouveau/include/dispnv04/i2c/encoder_i2c.h | 220 +++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_connector.c | 10 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 13 +- include/drm/drm_encoder_slave.h | 241 --------------------- 15 files changed, 433 insertions(+), 493 deletions(-) delete mode 100644 drivers/gpu/drm/drm_encoder_slave.c create mode 100644 drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c create mode 100644 drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h delete mode 100644 include/drm/drm_encoder_slave.h (limited to 'include') diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 19fb370fbc56..85af94bb907d 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -135,7 +135,6 @@ drm_kms_helper-y := \ drm_atomic_state_helper.o \ drm_crtc_helper.o \ drm_damage_helper.o \ - drm_encoder_slave.o \ drm_flip_work.o \ drm_format_helper.o \ drm_gem_atomic_helper.o \ diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c deleted file mode 100644 index e464429d32df..000000000000 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include - -#include - -/** - * drm_i2c_encoder_init - Initialize an I2C slave encoder - * @dev: DRM device. - * @encoder: Encoder to be attached to the I2C device. You aren't - * required to have called drm_encoder_init() before. - * @adap: I2C adapter that will be used to communicate with - * the device. - * @info: Information that will be used to create the I2C device. - * Required fields are @addr and @type. - * - * Create an I2C device on the specified bus (the module containing its - * driver is transparently loaded) and attach it to the specified - * &drm_encoder_slave. The @slave_funcs field will be initialized with - * the hooks provided by the slave driver. - * - * If @info.platform_data is non-NULL it will be used as the initial - * slave config. - * - * Returns 0 on success or a negative errno on failure, in particular, - * -ENODEV is returned when no matching driver is found. - */ -int drm_i2c_encoder_init(struct drm_device *dev, - struct drm_encoder_slave *encoder, - struct i2c_adapter *adap, - const struct i2c_board_info *info) -{ - struct module *module = NULL; - struct i2c_client *client; - struct drm_i2c_encoder_driver *encoder_drv; - int err = 0; - - request_module("%s%s", I2C_MODULE_PREFIX, info->type); - - client = i2c_new_client_device(adap, info); - if (!i2c_client_has_driver(client)) { - err = -ENODEV; - goto fail_unregister; - } - - module = client->dev.driver->owner; - if (!try_module_get(module)) { - err = -ENODEV; - goto fail_unregister; - } - - encoder->bus_priv = client; - - encoder_drv = to_drm_i2c_encoder_driver(to_i2c_driver(client->dev.driver)); - - err = encoder_drv->encoder_init(client, dev, encoder); - if (err) - goto fail_module_put; - - if (info->platform_data) - encoder->slave_funcs->set_config(&encoder->base, - info->platform_data); - - return 0; - -fail_module_put: - module_put(module); -fail_unregister: - i2c_unregister_device(client); - return err; -} -EXPORT_SYMBOL(drm_i2c_encoder_init); - -/** - * drm_i2c_encoder_destroy - Unregister the I2C device backing an encoder - * @drm_encoder: Encoder to be unregistered. - * - * This should be called from the @destroy method of an I2C slave - * encoder driver once I2C access is no longer needed. - */ -void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder) -{ - struct drm_encoder_slave *encoder = to_encoder_slave(drm_encoder); - struct i2c_client *client = drm_i2c_encoder_get_client(drm_encoder); - struct module *module = client->dev.driver->owner; - - i2c_unregister_device(client); - encoder->bus_priv = NULL; - - module_put(module); -} -EXPORT_SYMBOL(drm_i2c_encoder_destroy); - -/* - * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: - */ - -static inline const struct drm_encoder_slave_funcs * -get_slave_funcs(struct drm_encoder *enc) -{ - return to_encoder_slave(enc)->slave_funcs; -} - -void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - get_slave_funcs(encoder)->dpms(encoder, mode); -} -EXPORT_SYMBOL(drm_i2c_encoder_dpms); - -bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - if (!get_slave_funcs(encoder)->mode_fixup) - return true; - - return get_slave_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode); -} -EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup); - -void drm_i2c_encoder_prepare(struct drm_encoder *encoder) -{ - drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); -} -EXPORT_SYMBOL(drm_i2c_encoder_prepare); - -void drm_i2c_encoder_commit(struct drm_encoder *encoder) -{ - drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_ON); -} -EXPORT_SYMBOL(drm_i2c_encoder_commit); - -void drm_i2c_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode); -} -EXPORT_SYMBOL(drm_i2c_encoder_mode_set); - -enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - return get_slave_funcs(encoder)->detect(encoder, connector); -} -EXPORT_SYMBOL(drm_i2c_encoder_detect); - -void drm_i2c_encoder_save(struct drm_encoder *encoder) -{ - get_slave_funcs(encoder)->save(encoder); -} -EXPORT_SYMBOL(drm_i2c_encoder_save); - -void drm_i2c_encoder_restore(struct drm_encoder *encoder) -{ - get_slave_funcs(encoder)->restore(encoder); -} -EXPORT_SYMBOL(drm_i2c_encoder_restore); diff --git a/drivers/gpu/drm/nouveau/dispnv04/Kbuild b/drivers/gpu/drm/nouveau/dispnv04/Kbuild index 949802882ebd..4c7bc6bb81b3 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/Kbuild +++ b/drivers/gpu/drm/nouveau/dispnv04/Kbuild @@ -6,6 +6,7 @@ nouveau-y += dispnv04/dac.o nouveau-y += dispnv04/dfp.o nouveau-y += dispnv04/disp.o nouveau-y += dispnv04/hw.o +nouveau-y += dispnv04/nouveau_i2c_encoder.o nouveau-y += dispnv04/overlay.o nouveau-y += dispnv04/tvmodesnv17.o nouveau-y += dispnv04/tvnv04.o diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 25fa41edcb3c..c724bacc67f8 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -171,7 +171,7 @@ static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder) list_for_each_entry(slave, &dev->mode_config.encoder_list, head) { struct dcb_output *slave_dcb = nouveau_encoder(slave)->dcb; - if (slave_dcb->type == DCB_OUTPUT_TMDS && get_slave_funcs(slave) && + if (slave_dcb->type == DCB_OUTPUT_TMDS && get_encoder_i2c_funcs(slave) && slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr) return slave; } @@ -473,8 +473,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) /* Init external transmitters */ slave_encoder = get_tmds_slave(encoder); if (slave_encoder) - get_slave_funcs(slave_encoder)->mode_set( - slave_encoder, &nv_encoder->mode, &nv_encoder->mode); + get_encoder_i2c_funcs(slave_encoder)->mode_set(slave_encoder, + &nv_encoder->mode, + &nv_encoder->mode); helper->dpms(encoder, DRM_MODE_DPMS_ON); @@ -614,8 +615,8 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - if (get_slave_funcs(encoder)) - get_slave_funcs(encoder)->destroy(encoder); + if (get_encoder_i2c_funcs(encoder)) + get_encoder_i2c_funcs(encoder)->destroy(encoder); drm_encoder_cleanup(encoder); kfree(nv_encoder); @@ -649,8 +650,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) if (type < 0) return; - drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &bus->i2c, &info[type].dev); + nouveau_i2c_encoder_init(dev, to_encoder_i2c(encoder), + &bus->i2c, &info[type].dev); } static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c index db4f95020fae..fd2150e07e36 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_drv.c @@ -47,14 +47,14 @@ static void ch7006_encoder_destroy(struct drm_encoder *encoder) drm_property_destroy(encoder->dev, priv->scale_property); kfree(priv); - to_encoder_slave(encoder)->slave_priv = NULL; + to_encoder_i2c(encoder)->encoder_i2c_priv = NULL; - drm_i2c_encoder_destroy(encoder); + nouveau_i2c_encoder_destroy(encoder); } static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_state *state = &priv->state; @@ -71,7 +71,7 @@ static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) static void ch7006_encoder_save(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); ch7006_dbg(client, "\n"); @@ -81,7 +81,7 @@ static void ch7006_encoder_save(struct drm_encoder *encoder) static void ch7006_encoder_restore(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); ch7006_dbg(client, "\n"); @@ -116,7 +116,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *drm_mode, struct drm_display_mode *adjusted_mode) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_encoder_params *params = &priv->params; struct ch7006_state *state = &priv->state; @@ -179,7 +179,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder, struct drm_connector *connector) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_state *state = &priv->state; int det; @@ -285,7 +285,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, struct drm_property *property, uint64_t val) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_state *state = &priv->state; struct drm_mode_config *conf = &encoder->dev->mode_config; @@ -370,7 +370,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, return 0; } -static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = { +static const struct nouveau_i2c_encoder_funcs ch7006_encoder_funcs = { .set_config = ch7006_encoder_set_config, .destroy = ch7006_encoder_destroy, .dpms = ch7006_encoder_dpms, @@ -437,7 +437,7 @@ static int ch7006_resume(struct device *dev) static int ch7006_encoder_init(struct i2c_client *client, struct drm_device *dev, - struct drm_encoder_slave *encoder) + struct nouveau_i2c_encoder *encoder) { struct ch7006_priv *priv; int i; @@ -448,8 +448,8 @@ static int ch7006_encoder_init(struct i2c_client *client, if (!priv) return -ENOMEM; - encoder->slave_priv = priv; - encoder->slave_funcs = &ch7006_encoder_funcs; + encoder->encoder_i2c_priv = priv; + encoder->encoder_i2c_funcs = &ch7006_encoder_funcs; priv->norm = TV_NORM_PAL; priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic; @@ -495,7 +495,7 @@ static const struct dev_pm_ops ch7006_pm_ops = { .resume = ch7006_resume, }; -static struct drm_i2c_encoder_driver ch7006_driver = { +static struct nouveau_i2c_encoder_driver ch7006_driver = { .i2c_driver = { .probe = ch7006_probe, .remove = ch7006_remove, @@ -516,12 +516,12 @@ static struct drm_i2c_encoder_driver ch7006_driver = { static int __init ch7006_init(void) { - return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver); + return i2c_add_driver(&ch7006_driver.i2c_driver); } static void __exit ch7006_exit(void) { - drm_i2c_encoder_unregister(&ch7006_driver); + i2c_del_driver(&ch7006_driver.i2c_driver); } int ch7006_debug; diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c index 6afe6d0ee630..e58d94451959 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_mode.c @@ -198,7 +198,7 @@ const struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, void ch7006_setup_levels(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); uint8_t *regs = priv->state.regs; const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; @@ -229,7 +229,7 @@ void ch7006_setup_levels(struct drm_encoder *encoder) void ch7006_setup_subcarrier(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_state *state = &priv->state; const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; @@ -253,7 +253,7 @@ void ch7006_setup_subcarrier(struct drm_encoder *encoder) void ch7006_setup_pll(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); uint8_t *regs = priv->state.regs; const struct ch7006_mode *mode = priv->mode; @@ -324,7 +324,7 @@ void ch7006_setup_power_state(struct drm_encoder *encoder) void ch7006_setup_properties(struct drm_encoder *encoder) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_state *state = &priv->state; const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h index d7a91e17510f..5ad5157a2c02 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/ch7006_priv.h @@ -27,9 +27,9 @@ #ifndef __NOUVEAU_I2C_CH7006_PRIV_H__ #define __NOUVEAU_I2C_CH7006_PRIV_H__ -#include #include +#include #include typedef int64_t fixed; @@ -100,7 +100,7 @@ struct ch7006_priv { }; #define to_ch7006_priv(x) \ - ((struct ch7006_priv *)to_encoder_slave(x)->slave_priv) + ((struct ch7006_priv *)to_encoder_i2c(x)->encoder_i2c_priv) extern int ch7006_debug; extern char *ch7006_tv_norm; diff --git a/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c b/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c index 39b01c897518..54ea8459332d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c +++ b/drivers/gpu/drm/nouveau/dispnv04/i2c/sil164_drv.c @@ -27,10 +27,10 @@ #include #include -#include #include #include +#include #include struct sil164_priv { @@ -42,7 +42,7 @@ struct sil164_priv { }; #define to_sil164_priv(x) \ - ((struct sil164_priv *)to_encoder_slave(x)->slave_priv) + ((struct sil164_priv *)to_encoder_i2c(x)->encoder_i2c_priv) #define sil164_dbg(client, format, ...) do { \ if (drm_debug_enabled(DRM_UT_KMS)) \ @@ -222,7 +222,7 @@ sil164_encoder_dpms(struct drm_encoder *encoder, int mode) bool on = (mode == DRM_MODE_DPMS_ON); bool duallink = (on && encoder->crtc->mode.clock > 165000); - sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on); + sil164_set_power_state(nouveau_i2c_encoder_get_client(encoder), on); if (priv->duallink_slave) sil164_set_power_state(priv->duallink_slave, duallink); @@ -233,7 +233,7 @@ sil164_encoder_save(struct drm_encoder *encoder) { struct sil164_priv *priv = to_sil164_priv(encoder); - sil164_save_state(drm_i2c_encoder_get_client(encoder), + sil164_save_state(nouveau_i2c_encoder_get_client(encoder), priv->saved_state); if (priv->duallink_slave) @@ -246,7 +246,7 @@ sil164_encoder_restore(struct drm_encoder *encoder) { struct sil164_priv *priv = to_sil164_priv(encoder); - sil164_restore_state(drm_i2c_encoder_get_client(encoder), + sil164_restore_state(nouveau_i2c_encoder_get_client(encoder), priv->saved_state); if (priv->duallink_slave) @@ -278,7 +278,7 @@ sil164_encoder_mode_set(struct drm_encoder *encoder, struct sil164_priv *priv = to_sil164_priv(encoder); bool duallink = adjusted_mode->clock > 165000; - sil164_init_state(drm_i2c_encoder_get_client(encoder), + sil164_init_state(nouveau_i2c_encoder_get_client(encoder), &priv->config, duallink); if (priv->duallink_slave) @@ -292,7 +292,7 @@ static enum drm_connector_status sil164_encoder_detect(struct drm_encoder *encoder, struct drm_connector *connector) { - struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(encoder); if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT) return connector_status_connected; @@ -331,10 +331,10 @@ sil164_encoder_destroy(struct drm_encoder *encoder) i2c_unregister_device(priv->duallink_slave); kfree(priv); - drm_i2c_encoder_destroy(encoder); + nouveau_i2c_encoder_destroy(encoder); } -static const struct drm_encoder_slave_funcs sil164_encoder_funcs = { +static const struct nouveau_i2c_encoder_funcs sil164_encoder_funcs = { .set_config = sil164_encoder_set_config, .destroy = sil164_encoder_destroy, .dpms = sil164_encoder_dpms, @@ -394,7 +394,7 @@ sil164_detect_slave(struct i2c_client *client) static int sil164_encoder_init(struct i2c_client *client, struct drm_device *dev, - struct drm_encoder_slave *encoder) + struct nouveau_i2c_encoder *encoder) { struct sil164_priv *priv; struct i2c_client *slave_client; @@ -403,8 +403,8 @@ sil164_encoder_init(struct i2c_client *client, if (!priv) return -ENOMEM; - encoder->slave_priv = priv; - encoder->slave_funcs = &sil164_encoder_funcs; + encoder->encoder_i2c_priv = priv; + encoder->encoder_i2c_funcs = &sil164_encoder_funcs; slave_client = sil164_detect_slave(client); if (!IS_ERR(slave_client)) @@ -419,7 +419,7 @@ static const struct i2c_device_id sil164_ids[] = { }; MODULE_DEVICE_TABLE(i2c, sil164_ids); -static struct drm_i2c_encoder_driver sil164_driver = { +static struct nouveau_i2c_encoder_driver sil164_driver = { .i2c_driver = { .probe = sil164_probe, .driver = { @@ -435,13 +435,13 @@ static struct drm_i2c_encoder_driver sil164_driver = { static int __init sil164_init(void) { - return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver); + return i2c_add_driver(&sil164_driver.i2c_driver); } static void __exit sil164_exit(void) { - drm_i2c_encoder_unregister(&sil164_driver); + i2c_del_driver(&sil164_driver.i2c_driver); } MODULE_AUTHOR("Francisco Jerez "); diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c new file mode 100644 index 000000000000..e2bf99c43336 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +#include + +/** + * nouveau_i2c_encoder_init - Initialize an I2C slave encoder + * @dev: DRM device. + * @encoder: Encoder to be attached to the I2C device. You aren't + * required to have called drm_encoder_init() before. + * @adap: I2C adapter that will be used to communicate with + * the device. + * @info: Information that will be used to create the I2C device. + * Required fields are @addr and @type. + * + * Create an I2C device on the specified bus (the module containing its + * driver is transparently loaded) and attach it to the specified + * &nouveau_i2c_encoder. The @encoder_i2c_funcs field will be initialized with + * the hooks provided by the slave driver. + * + * If @info.platform_data is non-NULL it will be used as the initial + * slave config. + * + * Returns 0 on success or a negative errno on failure, in particular, + * -ENODEV is returned when no matching driver is found. + */ +int nouveau_i2c_encoder_init(struct drm_device *dev, + struct nouveau_i2c_encoder *encoder, + struct i2c_adapter *adap, + const struct i2c_board_info *info) +{ + struct module *module = NULL; + struct i2c_client *client; + struct nouveau_i2c_encoder_driver *encoder_drv; + int err = 0; + + request_module("%s%s", I2C_MODULE_PREFIX, info->type); + + client = i2c_new_client_device(adap, info); + if (!i2c_client_has_driver(client)) { + err = -ENODEV; + goto fail_unregister; + } + + module = client->dev.driver->owner; + if (!try_module_get(module)) { + err = -ENODEV; + goto fail_unregister; + } + + encoder->i2c_client = client; + + encoder_drv = to_nouveau_i2c_encoder_driver(to_i2c_driver(client->dev.driver)); + + err = encoder_drv->encoder_init(client, dev, encoder); + if (err) + goto fail_module_put; + + if (info->platform_data) + encoder->encoder_i2c_funcs->set_config(&encoder->base, + info->platform_data); + + return 0; + +fail_module_put: + module_put(module); +fail_unregister: + i2c_unregister_device(client); + return err; +} + +/** + * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder + * @drm_encoder: Encoder to be unregistered. + * + * This should be called from the @destroy method of an I2C slave + * encoder driver once I2C access is no longer needed. + */ +void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); + struct module *module = client->dev.driver->owner; + + i2c_unregister_device(client); + encoder->i2c_client = NULL; + + module_put(module); +} +EXPORT_SYMBOL(nouveau_i2c_encoder_destroy); + +/* + * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: + */ + +bool nouveau_i2c_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + if (!get_encoder_i2c_funcs(encoder)->mode_fixup) + return true; + + return get_encoder_i2c_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode); +} + +enum drm_connector_status nouveau_i2c_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + return get_encoder_i2c_funcs(encoder)->detect(encoder, connector); +} + +void nouveau_i2c_encoder_save(struct drm_encoder *encoder) +{ + get_encoder_i2c_funcs(encoder)->save(encoder); +} + +void nouveau_i2c_encoder_restore(struct drm_encoder *encoder) +{ + get_encoder_i2c_funcs(encoder)->restore(encoder); +} diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index 4ffd8af6bf8b..c61ab083f62e 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -99,7 +99,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); - get_slave_funcs(encoder)->dpms(encoder, mode); + get_encoder_i2c_funcs(encoder)->dpms(encoder, mode); } static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) @@ -158,7 +158,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder, regp->tv_vskew = 1; regp->tv_vsync_delay = 1; - get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode); + get_encoder_i2c_funcs(encoder)->mode_set(encoder, mode, adjusted_mode); } static void nv04_tv_commit(struct drm_encoder *encoder) @@ -178,7 +178,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { - get_slave_funcs(encoder)->destroy(encoder); + get_encoder_i2c_funcs(encoder)->destroy(encoder); drm_encoder_cleanup(encoder); kfree(encoder->helper_private); @@ -191,11 +191,11 @@ static const struct drm_encoder_funcs nv04_tv_funcs = { static const struct drm_encoder_helper_funcs nv04_tv_helper_funcs = { .dpms = nv04_tv_dpms, - .mode_fixup = drm_i2c_encoder_mode_fixup, + .mode_fixup = nouveau_i2c_encoder_mode_fixup, .prepare = nv04_tv_prepare, .commit = nv04_tv_commit, .mode_set = nv04_tv_mode_set, - .detect = drm_i2c_encoder_detect, + .detect = nouveau_i2c_encoder_detect, }; int @@ -226,8 +226,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) NULL); drm_encoder_helper_add(encoder, &nv04_tv_helper_funcs); - nv_encoder->enc_save = drm_i2c_encoder_save; - nv_encoder->enc_restore = drm_i2c_encoder_restore; + nv_encoder->enc_save = nouveau_i2c_encoder_save; + nv_encoder->enc_restore = nouveau_i2c_encoder_restore; encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; @@ -235,14 +235,14 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) nv_encoder->or = ffs(entry->or) - 1; /* Run the slave-specific initialization */ - ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &bus->i2c, - &nv04_tv_encoder_info[type].dev); + ret = nouveau_i2c_encoder_init(dev, to_encoder_i2c(encoder), + &bus->i2c, + &nv04_tv_encoder_info[type].dev); if (ret < 0) goto fail_cleanup; /* Attach it to the specified connector. */ - get_slave_funcs(encoder)->create_resources(encoder, connector); + get_encoder_i2c_funcs(encoder)->create_resources(encoder, connector); drm_connector_attach_encoder(connector, encoder); return 0; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 35ad4e10d273..06de05fe5db6 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -779,7 +779,7 @@ static const struct drm_encoder_helper_funcs nv17_tv_helper_funcs = { .detect = nv17_tv_detect, }; -static const struct drm_encoder_slave_funcs nv17_tv_slave_funcs = { +static const struct nouveau_i2c_encoder_funcs nv17_tv_encoder_i2c_funcs = { .get_modes = nv17_tv_get_modes, .mode_valid = nv17_tv_mode_valid, .create_resources = nv17_tv_create_resources, @@ -818,7 +818,7 @@ nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry) drm_encoder_init(dev, encoder, &nv17_tv_funcs, DRM_MODE_ENCODER_TVDAC, NULL); drm_encoder_helper_add(encoder, &nv17_tv_helper_funcs); - to_encoder_slave(encoder)->slave_funcs = &nv17_tv_slave_funcs; + to_encoder_i2c(encoder)->encoder_i2c_funcs = &nv17_tv_encoder_i2c_funcs; tv_enc->base.enc_save = nv17_tv_save; tv_enc->base.enc_restore = nv17_tv_restore; diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h new file mode 100644 index 000000000000..31334aa90781 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __NOUVEAU_ENCODER_I2C_H__ +#define __NOUVEAU_ENCODER_I2C_H__ + +#include + +#include +#include + +/** + * struct nouveau_i2c_encoder_funcs - Entry points exposed by a I2C encoder driver + * + * Most of its members are analogous to the function pointers in + * &drm_encoder_helper_funcs and they can optionally be used to + * initialize the latter. Connector-like methods (e.g. @get_modes and + * @set_property) will typically be wrapped around and only be called + * if the encoder is the currently selected one for the connector. + */ +struct nouveau_i2c_encoder_funcs { + /** + * @set_config: Initialize any encoder-specific modesetting parameters. + * The meaning of the @params parameter is implementation dependent. It + * will usually be a structure with DVO port data format settings or + * timings. It's not required for the new parameters to take effect + * until the next mode is set. + */ + void (*set_config)(struct drm_encoder *encoder, + void *params); + + /** + * @destroy: Analogous to &drm_encoder_funcs @destroy callback. + */ + void (*destroy)(struct drm_encoder *encoder); + + /** + * @dpms: Analogous to &drm_encoder_helper_funcs @dpms callback. + */ + void (*dpms)(struct drm_encoder *encoder, int mode); + + /** + * @save: Save state. Wrapped by nouveau_i2c_encoder_save(). + */ + void (*save)(struct drm_encoder *encoder); + + /** + * @restore: Restore state. Wrapped by nouveau_i2c_encoder_restore(). + */ + void (*restore)(struct drm_encoder *encoder); + + /** + * @mode_fixup: Analogous to &drm_encoder_helper_funcs @mode_fixup + * callback. Wrapped by nouveau_i2c_encoder_mode_fixup(). + */ + bool (*mode_fixup)(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + /** + * @mode_valid: Analogous to &drm_encoder_helper_funcs @mode_valid. + */ + int (*mode_valid)(struct drm_encoder *encoder, + const struct drm_display_mode *mode); + /** + * @mode_set: Analogous to &drm_encoder_helper_funcs @mode_set + * callback. + */ + void (*mode_set)(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + /** + * @detect: Analogous to &drm_encoder_helper_funcs @detect + * callback. Wrapped by nouveau_i2c_encoder_detect(). + */ + enum drm_connector_status (*detect)(struct drm_encoder *encoder, + struct drm_connector *connector); + /** + * @get_modes: Get modes. + */ + int (*get_modes)(struct drm_encoder *encoder, + struct drm_connector *connector); + /** + * @create_resources: Create resources. + */ + int (*create_resources)(struct drm_encoder *encoder, + struct drm_connector *connector); + /** + * @set_property: Set property. + */ + int (*set_property)(struct drm_encoder *encoder, + struct drm_connector *connector, + struct drm_property *property, + uint64_t val); +}; + +/** + * struct nouveau_i2c_encoder - I2C encoder struct + * + * A &nouveau_i2c_encoder has two sets of callbacks, @encoder_i2c_funcs and the + * ones in @base. The former are never actually called by the common + * CRTC code, it's just a convenience for splitting the encoder + * functions in an upper, GPU-specific layer and a (hopefully) + * GPU-agnostic lower layer: It's the GPU driver responsibility to + * call the nouveau_i2c_encoder methods when appropriate. + * + * nouveau_i2c_encoder_init() provides a way to get an implementation of + * this. + */ +struct nouveau_i2c_encoder { + /** + * @base: DRM encoder object. + */ + struct drm_encoder base; + + /** + * @encoder_i2c_funcs: I2C encoder callbacks. + */ + const struct nouveau_i2c_encoder_funcs *encoder_i2c_funcs; + + /** + * @encoder_i2c_priv: I2C encoder private data. + */ + void *encoder_i2c_priv; + + /** + * @i2c_client: corresponding I2C client structure + */ + struct i2c_client *i2c_client; +}; + +#define to_encoder_i2c(x) container_of((x), struct nouveau_i2c_encoder, base) + +int nouveau_i2c_encoder_init(struct drm_device *dev, + struct nouveau_i2c_encoder *encoder, + struct i2c_adapter *adap, + const struct i2c_board_info *info); + +static inline const struct nouveau_i2c_encoder_funcs * +get_encoder_i2c_funcs(struct drm_encoder *enc) +{ + return to_encoder_i2c(enc)->encoder_i2c_funcs; +} + +/** + * struct nouveau_i2c_encoder_driver + * + * Describes a device driver for an encoder connected to the GPU through an I2C + * bus. + */ +struct nouveau_i2c_encoder_driver { + /** + * @i2c_driver: I2C device driver description. + */ + struct i2c_driver i2c_driver; + + /** + * @encoder_init: Callback to allocate any per-encoder data structures + * and to initialize the @encoder_i2c_funcs and (optionally) @encoder_i2c_priv + * members of @encoder. + */ + int (*encoder_init)(struct i2c_client *client, + struct drm_device *dev, + struct nouveau_i2c_encoder *encoder); + +}; + +#define to_nouveau_i2c_encoder_driver(x) container_of((x), \ + struct nouveau_i2c_encoder_driver, \ + i2c_driver) + +/** + * nouveau_i2c_encoder_get_client - Get the I2C client corresponding to an encoder + * @encoder: The encoder + */ +static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encoder *encoder) +{ + return to_encoder_i2c(encoder)->i2c_client; +} + +void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder); + +/* + * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: + */ + +bool nouveau_i2c_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +enum drm_connector_status nouveau_i2c_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector); +void nouveau_i2c_encoder_save(struct drm_encoder *encoder); +void nouveau_i2c_encoder_restore(struct drm_encoder *encoder); + + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 2d26784bde74..6fb9719d721f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -797,8 +797,10 @@ nouveau_connector_set_property(struct drm_connector *connector, property, value); if (ret) { if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV) - return get_slave_funcs(encoder)->set_property( - encoder, connector, property, value); + return get_encoder_i2c_funcs(encoder)->set_property(encoder, + connector, + property, + value); return ret; } @@ -1015,7 +1017,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) nouveau_connector_detect_depth(connector); if (nv_encoder->dcb->type == DCB_OUTPUT_TV) - ret = get_slave_funcs(encoder)->get_modes(encoder, connector); + ret = get_encoder_i2c_funcs(encoder)->get_modes(encoder, connector); if (nv_connector->type == DCB_CONNECTOR_LVDS || nv_connector->type == DCB_CONNECTOR_LVDS_SPWG || @@ -1100,7 +1102,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 350000; break; case DCB_OUTPUT_TV: - return get_slave_funcs(encoder)->mode_valid(encoder, mode); + return get_encoder_i2c_funcs(encoder)->mode_valid(encoder, mode); case DCB_OUTPUT_DP: return nv50_dp_mode_valid(nv_encoder, mode, NULL); default: diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 333042fc493f..dce8e5d9d496 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -31,7 +31,8 @@ #include #include -#include + +#include #include "dispnv04/disp.h" @@ -43,7 +44,7 @@ struct nouveau_connector; struct nvkm_i2c_port; struct nouveau_encoder { - struct drm_encoder_slave base; + struct nouveau_i2c_encoder base; struct dcb_output *dcb; struct nvif_outp outp; @@ -137,7 +138,7 @@ find_encoder(struct drm_connector *connector, int type); static inline struct nouveau_encoder *nouveau_encoder(struct drm_encoder *enc) { - struct drm_encoder_slave *slave = to_encoder_slave(enc); + struct nouveau_i2c_encoder *slave = to_encoder_i2c(enc); return container_of(slave, struct nouveau_encoder, base); } @@ -147,12 +148,6 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) return &enc->base.base; } -static inline const struct drm_encoder_slave_funcs * -get_slave_funcs(struct drm_encoder *enc) -{ - return to_encoder_slave(enc)->slave_funcs; -} - /* nouveau_dp.c */ enum nouveau_dp_status { NOUVEAU_DP_NONE, diff --git a/include/drm/drm_encoder_slave.h b/include/drm/drm_encoder_slave.h deleted file mode 100644 index b526643833dc..000000000000 --- a/include/drm/drm_encoder_slave.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2009 Francisco Jerez. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __DRM_ENCODER_SLAVE_H__ -#define __DRM_ENCODER_SLAVE_H__ - -#include - -#include -#include - -/** - * struct drm_encoder_slave_funcs - Entry points exposed by a slave encoder driver - * - * Most of its members are analogous to the function pointers in - * &drm_encoder_helper_funcs and they can optionally be used to - * initialize the latter. Connector-like methods (e.g. @get_modes and - * @set_property) will typically be wrapped around and only be called - * if the encoder is the currently selected one for the connector. - */ -struct drm_encoder_slave_funcs { - /** - * @set_config: Initialize any encoder-specific modesetting parameters. - * The meaning of the @params parameter is implementation dependent. It - * will usually be a structure with DVO port data format settings or - * timings. It's not required for the new parameters to take effect - * until the next mode is set. - */ - void (*set_config)(struct drm_encoder *encoder, - void *params); - - /** - * @destroy: Analogous to &drm_encoder_funcs @destroy callback. - */ - void (*destroy)(struct drm_encoder *encoder); - - /** - * @dpms: Analogous to &drm_encoder_helper_funcs @dpms callback. Wrapped - * by drm_i2c_encoder_dpms(). - */ - void (*dpms)(struct drm_encoder *encoder, int mode); - - /** - * @save: Save state. Wrapped by drm_i2c_encoder_save(). - */ - void (*save)(struct drm_encoder *encoder); - - /** - * @restore: Restore state. Wrapped by drm_i2c_encoder_restore(). - */ - void (*restore)(struct drm_encoder *encoder); - - /** - * @mode_fixup: Analogous to &drm_encoder_helper_funcs @mode_fixup - * callback. Wrapped by drm_i2c_encoder_mode_fixup(). - */ - bool (*mode_fixup)(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - - /** - * @mode_valid: Analogous to &drm_encoder_helper_funcs @mode_valid. - */ - int (*mode_valid)(struct drm_encoder *encoder, - const struct drm_display_mode *mode); - /** - * @mode_set: Analogous to &drm_encoder_helper_funcs @mode_set - * callback. Wrapped by drm_i2c_encoder_mode_set(). - */ - void (*mode_set)(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - - /** - * @detect: Analogous to &drm_encoder_helper_funcs @detect - * callback. Wrapped by drm_i2c_encoder_detect(). - */ - enum drm_connector_status (*detect)(struct drm_encoder *encoder, - struct drm_connector *connector); - /** - * @get_modes: Get modes. - */ - int (*get_modes)(struct drm_encoder *encoder, - struct drm_connector *connector); - /** - * @create_resources: Create resources. - */ - int (*create_resources)(struct drm_encoder *encoder, - struct drm_connector *connector); - /** - * @set_property: Set property. - */ - int (*set_property)(struct drm_encoder *encoder, - struct drm_connector *connector, - struct drm_property *property, - uint64_t val); -}; - -/** - * struct drm_encoder_slave - Slave encoder struct - * - * A &drm_encoder_slave has two sets of callbacks, @slave_funcs and the - * ones in @base. The former are never actually called by the common - * CRTC code, it's just a convenience for splitting the encoder - * functions in an upper, GPU-specific layer and a (hopefully) - * GPU-agnostic lower layer: It's the GPU driver responsibility to - * call the slave methods when appropriate. - * - * drm_i2c_encoder_init() provides a way to get an implementation of - * this. - */ -struct drm_encoder_slave { - /** - * @base: DRM encoder object. - */ - struct drm_encoder base; - - /** - * @slave_funcs: Slave encoder callbacks. - */ - const struct drm_encoder_slave_funcs *slave_funcs; - - /** - * @slave_priv: Slave encoder private data. - */ - void *slave_priv; - - /** - * @bus_priv: Bus specific data. - */ - void *bus_priv; -}; -#define to_encoder_slave(x) container_of((x), struct drm_encoder_slave, base) - -int drm_i2c_encoder_init(struct drm_device *dev, - struct drm_encoder_slave *encoder, - struct i2c_adapter *adap, - const struct i2c_board_info *info); - - -/** - * struct drm_i2c_encoder_driver - * - * Describes a device driver for an encoder connected to the GPU through an I2C - * bus. - */ -struct drm_i2c_encoder_driver { - /** - * @i2c_driver: I2C device driver description. - */ - struct i2c_driver i2c_driver; - - /** - * @encoder_init: Callback to allocate any per-encoder data structures - * and to initialize the @slave_funcs and (optionally) @slave_priv - * members of @encoder. - */ - int (*encoder_init)(struct i2c_client *client, - struct drm_device *dev, - struct drm_encoder_slave *encoder); - -}; -#define to_drm_i2c_encoder_driver(x) container_of((x), \ - struct drm_i2c_encoder_driver, \ - i2c_driver) - -/** - * drm_i2c_encoder_get_client - Get the I2C client corresponding to an encoder - * @encoder: The encoder - */ -static inline struct i2c_client *drm_i2c_encoder_get_client(struct drm_encoder *encoder) -{ - return (struct i2c_client *)to_encoder_slave(encoder)->bus_priv; -} - -/** - * drm_i2c_encoder_register - Register an I2C encoder driver - * @owner: Module containing the driver. - * @driver: Driver to be registered. - */ -static inline int drm_i2c_encoder_register(struct module *owner, - struct drm_i2c_encoder_driver *driver) -{ - return i2c_register_driver(owner, &driver->i2c_driver); -} - -/** - * drm_i2c_encoder_unregister - Unregister an I2C encoder driver - * @driver: Driver to be unregistered. - */ -static inline void drm_i2c_encoder_unregister(struct drm_i2c_encoder_driver *driver) -{ - i2c_del_driver(&driver->i2c_driver); -} - -void drm_i2c_encoder_destroy(struct drm_encoder *encoder); - - -/* - * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: - */ - -void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode); -bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -void drm_i2c_encoder_prepare(struct drm_encoder *encoder); -void drm_i2c_encoder_commit(struct drm_encoder *encoder); -void drm_i2c_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder, - struct drm_connector *connector); -void drm_i2c_encoder_save(struct drm_encoder *encoder); -void drm_i2c_encoder_restore(struct drm_encoder *encoder); - - -#endif -- cgit v1.2.3 From eee0912a7185d5dc0a700d48f7ff620bb7f5389b Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Mon, 16 Dec 2024 16:43:12 -0800 Subject: drm: add clone mode check for CRTC Add a common helper to check if the given CRTC state is in clone mode. This can be used by drivers to help detect if a CRTC is being shared by multiple encoders Signed-off-by: Jessica Zhang Reviewed-by: Abhinav Kumar Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20241216-concurrent-wb-v4-1-fe220297a7f0@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/drm_crtc.c | 20 ++++++++++++++++++++ include/drm/drm_crtc.h | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3488ff067c69..46655339003d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -939,3 +939,23 @@ int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc, return 0; } EXPORT_SYMBOL(drm_crtc_create_scaling_filter_property); + +/** + * drm_crtc_in_clone_mode - check if the given CRTC state is in clone mode + * + * @crtc_state: CRTC state to check + * + * This function determines if the given CRTC state is being cloned by multiple + * encoders. + * + * RETURNS: + * True if the CRTC state is in clone mode. False otherwise + */ +bool drm_crtc_in_clone_mode(struct drm_crtc_state *crtc_state) +{ + if (!crtc_state) + return false; + + return hweight32(crtc_state->encoder_mask) > 1; +} +EXPORT_SYMBOL(drm_crtc_in_clone_mode); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8b48a1974da3..caa56e039da2 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1323,5 +1323,5 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc, unsigned int supported_filters); - +bool drm_crtc_in_clone_mode(struct drm_crtc_state *crtc_state); #endif /* __DRM_CRTC_H__ */ -- cgit v1.2.3 From 465a3914b254f82608a8dfb580ac9930722dfd88 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Tue, 7 Jan 2025 18:32:25 +0100 Subject: accel/ivpu: Add API for command queue create/destroy/submit Implement support for explicit command queue management. To allow more flexible control over command queues add capabilities to create, destroy and submit jobs to specific command queues. Signed-off-by: Karol Wachowski Signed-off-by: Maciej Falkowski Reviewed-by: Jacek Lawrynowicz Signed-off-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250107173238.381120-3-maciej.falkowski@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 6 + drivers/accel/ivpu/ivpu_job.c | 369 +++++++++++++++++++++++++----------------- drivers/accel/ivpu/ivpu_job.h | 5 +- include/uapi/drm/ivpu_accel.h | 84 ++++++++++ 4 files changed, 319 insertions(+), 145 deletions(-) (limited to 'include') diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 1e8ffbe25eee..f4171536640b 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -137,6 +137,9 @@ static int ivpu_get_capabilities(struct ivpu_device *vdev, struct drm_ivpu_param case DRM_IVPU_CAP_DMA_MEMORY_RANGE: args->value = 1; break; + case DRM_IVPU_CAP_MANAGE_CMDQ: + args->value = 1; + break; default: return -EINVAL; } @@ -310,6 +313,9 @@ static const struct drm_ioctl_desc ivpu_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_GET_DATA, ivpu_ms_get_data_ioctl, 0), DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_STOP, ivpu_ms_stop_ioctl, 0), DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_GET_INFO, ivpu_ms_get_info_ioctl, 0), + DRM_IOCTL_DEF_DRV(IVPU_CMDQ_CREATE, ivpu_cmdq_create_ioctl, 0), + DRM_IOCTL_DEF_DRV(IVPU_CMDQ_DESTROY, ivpu_cmdq_destroy_ioctl, 0), + DRM_IOCTL_DEF_DRV(IVPU_CMDQ_SUBMIT, ivpu_cmdq_submit_ioctl, 0), }; static int ivpu_wait_for_ready(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 98e53cb38ecd..43507d3aea51 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -100,15 +100,43 @@ err_free_cmdq: static void ivpu_cmdq_free(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) { - if (!cmdq) - return; - ivpu_preemption_buffers_free(file_priv->vdev, file_priv, cmdq); ivpu_bo_free(cmdq->mem); - xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); kfree(cmdq); } +static struct ivpu_cmdq *ivpu_cmdq_create(struct ivpu_file_priv *file_priv, u8 priority, + bool is_legacy) +{ + struct ivpu_device *vdev = file_priv->vdev; + struct ivpu_cmdq *cmdq = NULL; + int ret; + + lockdep_assert_held(&file_priv->lock); + + cmdq = ivpu_cmdq_alloc(file_priv); + if (!cmdq) { + ivpu_err(vdev, "Failed to allocate command queue\n"); + return NULL; + } + + cmdq->priority = priority; + cmdq->is_legacy = is_legacy; + + ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, file_priv->cmdq_limit, + &file_priv->cmdq_id_next, GFP_KERNEL); + if (ret < 0) { + ivpu_err(vdev, "Failed to allocate command queue ID: %d\n", ret); + goto err_free_cmdq; + } + + return cmdq; + +err_free_cmdq: + ivpu_cmdq_free(file_priv, cmdq); + return NULL; +} + static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 engine, u8 priority) { @@ -134,6 +162,13 @@ static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq * struct ivpu_device *vdev = file_priv->vdev; int ret; + ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, &vdev->db_next, + GFP_KERNEL); + if (ret < 0) { + ivpu_err(vdev, "Failed to allocate doorbell ID: %d\n", ret); + return ret; + } + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->id, cmdq->db_id, cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); @@ -142,41 +177,52 @@ static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq * cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); if (!ret) - ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d\n", - cmdq->db_id, cmdq->id, file_priv->ctx.id); + ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d priority %d\n", + cmdq->db_id, cmdq->id, file_priv->ctx.id, cmdq->priority); + else + xa_erase(&vdev->db_xa, cmdq->db_id); return ret; } -static int -ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u8 priority) +static void ivpu_cmdq_jobq_init(struct ivpu_device *vdev, struct vpu_job_queue *jobq) +{ + jobq->header.engine_idx = VPU_ENGINE_COMPUTE; + jobq->header.head = 0; + jobq->header.tail = 0; + + if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) { + ivpu_dbg(vdev, JOB, "Turbo mode enabled"); + jobq->header.flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE; + } + + wmb(); /* Flush WC buffer for jobq->header */ +} + +static inline u32 ivpu_cmdq_get_entry_count(struct ivpu_cmdq *cmdq) +{ + size_t size = ivpu_bo_size(cmdq->mem) - sizeof(struct vpu_job_queue_header); + + return size / sizeof(struct vpu_job_queue_entry); +} + +static int ivpu_cmdq_register(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) { struct ivpu_device *vdev = file_priv->vdev; - struct vpu_job_queue_header *jobq_header; int ret; lockdep_assert_held(&file_priv->lock); - if (cmdq->db_registered) + if (cmdq->db_id) return 0; - cmdq->entry_count = (u32)((ivpu_bo_size(cmdq->mem) - sizeof(struct vpu_job_queue_header)) / - sizeof(struct vpu_job_queue_entry)); - + cmdq->entry_count = ivpu_cmdq_get_entry_count(cmdq); cmdq->jobq = (struct vpu_job_queue *)ivpu_bo_vaddr(cmdq->mem); - jobq_header = &cmdq->jobq->header; - jobq_header->engine_idx = VPU_ENGINE_COMPUTE; - jobq_header->head = 0; - jobq_header->tail = 0; - if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) { - ivpu_dbg(vdev, JOB, "Turbo mode enabled"); - jobq_header->flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE; - } - wmb(); /* Flush WC buffer for jobq->header */ + ivpu_cmdq_jobq_init(vdev, cmdq->jobq); if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { - ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, priority); + ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, cmdq->priority); if (ret) return ret; } @@ -185,23 +231,19 @@ ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u8 prio if (ret) return ret; - cmdq->db_registered = true; - return 0; } -static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) +static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) { struct ivpu_device *vdev = file_priv->vdev; int ret; lockdep_assert_held(&file_priv->lock); - if (!cmdq->db_registered) + if (!cmdq->db_id) return 0; - cmdq->db_registered = false; - if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id); if (!ret) @@ -212,91 +254,61 @@ static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cm if (!ret) ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id); + xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); + cmdq->db_id = 0; + return 0; } -static int ivpu_db_id_alloc(struct ivpu_device *vdev, u32 *db_id) +static inline u8 ivpu_job_to_jsm_priority(u8 priority) { - int ret; - u32 id; - - ret = xa_alloc_cyclic(&vdev->db_xa, &id, NULL, vdev->db_limit, &vdev->db_next, GFP_KERNEL); - if (ret < 0) - return ret; + if (priority == DRM_IVPU_JOB_PRIORITY_DEFAULT) + return VPU_JOB_SCHEDULING_PRIORITY_BAND_NORMAL; - *db_id = id; - return 0; + return priority - 1; } -static int ivpu_cmdq_id_alloc(struct ivpu_file_priv *file_priv, u32 *cmdq_id) +static void ivpu_cmdq_destroy(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) { - int ret; - u32 id; - - ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &id, NULL, file_priv->cmdq_limit, - &file_priv->cmdq_id_next, GFP_KERNEL); - if (ret < 0) - return ret; - - *cmdq_id = id; - return 0; + ivpu_cmdq_unregister(file_priv, cmdq); + xa_erase(&file_priv->cmdq_xa, cmdq->id); + ivpu_cmdq_free(file_priv, cmdq); } -static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u8 priority) +static struct ivpu_cmdq *ivpu_cmdq_acquire_legacy(struct ivpu_file_priv *file_priv, u8 priority) { - struct ivpu_device *vdev = file_priv->vdev; struct ivpu_cmdq *cmdq; unsigned long id; - int ret; lockdep_assert_held(&file_priv->lock); xa_for_each(&file_priv->cmdq_xa, id, cmdq) - if (cmdq->priority == priority) + if (cmdq->is_legacy && cmdq->priority == priority) break; if (!cmdq) { - cmdq = ivpu_cmdq_alloc(file_priv); - if (!cmdq) { - ivpu_err(vdev, "Failed to allocate command queue\n"); + cmdq = ivpu_cmdq_create(file_priv, priority, true); + if (!cmdq) return NULL; - } + } - ret = ivpu_db_id_alloc(vdev, &cmdq->db_id); - if (ret) { - ivpu_err(file_priv->vdev, "Failed to allocate doorbell ID: %d\n", ret); - goto err_free_cmdq; - } + return cmdq; +} - ret = ivpu_cmdq_id_alloc(file_priv, &cmdq->id); - if (ret) { - ivpu_err(vdev, "Failed to allocate command queue ID: %d\n", ret); - goto err_erase_db_id; - } +static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u32 cmdq_id) +{ + struct ivpu_device *vdev = file_priv->vdev; + struct ivpu_cmdq *cmdq; - cmdq->priority = priority; - ret = xa_err(xa_store(&file_priv->cmdq_xa, cmdq->id, cmdq, GFP_KERNEL)); - if (ret) { - ivpu_err(vdev, "Failed to store command queue in cmdq_xa: %d\n", ret); - goto err_erase_cmdq_id; - } - } + lockdep_assert_held(&file_priv->lock); - ret = ivpu_cmdq_init(file_priv, cmdq, priority); - if (ret) { - ivpu_err(vdev, "Failed to initialize command queue: %d\n", ret); - goto err_free_cmdq; + cmdq = xa_load(&file_priv->cmdq_xa, cmdq_id); + if (!cmdq) { + ivpu_err(vdev, "Failed to find command queue with ID: %u\n", cmdq_id); + return NULL; } return cmdq; - -err_erase_cmdq_id: - xa_erase(&file_priv->cmdq_xa, cmdq->id); -err_erase_db_id: - xa_erase(&vdev->db_xa, cmdq->db_id); -err_free_cmdq: - ivpu_cmdq_free(file_priv, cmdq); - return NULL; } void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) @@ -306,11 +318,8 @@ void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) lockdep_assert_held(&file_priv->lock); - xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) { - xa_erase(&file_priv->cmdq_xa, cmdq_id); - ivpu_cmdq_fini(file_priv, cmdq); - ivpu_cmdq_free(file_priv, cmdq); - } + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) + ivpu_cmdq_destroy(file_priv, cmdq); } /* @@ -326,8 +335,10 @@ static void ivpu_cmdq_reset(struct ivpu_file_priv *file_priv) mutex_lock(&file_priv->lock); - xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) - cmdq->db_registered = false; + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) { + xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); + cmdq->db_id = 0; + } mutex_unlock(&file_priv->lock); } @@ -345,13 +356,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev) mutex_unlock(&vdev->context_list_lock); } -static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv) +static void ivpu_cmdq_unregister_all(struct ivpu_file_priv *file_priv) { struct ivpu_cmdq *cmdq; unsigned long cmdq_id; xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) - ivpu_cmdq_fini(file_priv, cmdq); + ivpu_cmdq_unregister(file_priv, cmdq); } void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) @@ -360,7 +371,7 @@ void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) lockdep_assert_held(&file_priv->lock); - ivpu_cmdq_fini_all(file_priv); + ivpu_cmdq_unregister_all(file_priv); if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_OS) ivpu_jsm_context_release(vdev, file_priv->ctx.id); @@ -549,7 +560,7 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev) ivpu_job_signal_and_destroy(vdev, id, DRM_IVPU_JOB_STATUS_ABORTED); } -static int ivpu_job_submit(struct ivpu_job *job, u8 priority) +static int ivpu_job_submit(struct ivpu_job *job, u8 priority, u32 cmdq_id) { struct ivpu_file_priv *file_priv = job->file_priv; struct ivpu_device *vdev = job->vdev; @@ -563,14 +574,22 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) mutex_lock(&file_priv->lock); - cmdq = ivpu_cmdq_acquire(file_priv, priority); + if (cmdq_id == 0) + cmdq = ivpu_cmdq_acquire_legacy(file_priv, priority); + else + cmdq = ivpu_cmdq_acquire(file_priv, cmdq_id); if (!cmdq) { - ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d engine %d prio %d\n", - file_priv->ctx.id, job->engine_idx, priority); + ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d\n", file_priv->ctx.id); ret = -EINVAL; goto err_unlock_file_priv; } + ret = ivpu_cmdq_register(file_priv, cmdq); + if (ret) { + ivpu_err(vdev, "Failed to register command queue: %d\n", ret); + goto err_unlock_file_priv; + } + xa_lock(&vdev->submitted_jobs_xa); is_first_job = xa_empty(&vdev->submitted_jobs_xa); ret = __xa_alloc_cyclic(&vdev->submitted_jobs_xa, &job->job_id, job, file_priv->job_limit, @@ -599,7 +618,7 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) trace_job("submit", job); ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d prio %d addr 0x%llx next %d\n", - job->job_id, file_priv->ctx.id, job->engine_idx, priority, + job->job_id, file_priv->ctx.id, job->engine_idx, cmdq->priority, job->cmd_buf_vpu_addr, cmdq->jobq->header.tail); xa_unlock(&vdev->submitted_jobs_xa); @@ -625,7 +644,7 @@ static int ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 *buf_handles, u32 buf_count, u32 commands_offset) { - struct ivpu_file_priv *file_priv = file->driver_priv; + struct ivpu_file_priv *file_priv = job->file_priv; struct ivpu_device *vdev = file_priv->vdev; struct ww_acquire_ctx acquire_ctx; enum dma_resv_usage usage; @@ -687,49 +706,20 @@ unlock_reservations: return ret; } -static inline u8 ivpu_job_to_hws_priority(struct ivpu_file_priv *file_priv, u8 priority) +static int ivpu_submit(struct drm_file *file, struct ivpu_file_priv *file_priv, u32 cmdq_id, + u32 buffer_count, u32 engine, void __user *buffers_ptr, u32 cmds_offset, + u8 priority) { - if (priority == DRM_IVPU_JOB_PRIORITY_DEFAULT) - return DRM_IVPU_JOB_PRIORITY_NORMAL; - - return priority - 1; -} - -int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) -{ - struct ivpu_file_priv *file_priv = file->driver_priv; struct ivpu_device *vdev = file_priv->vdev; - struct drm_ivpu_submit *params = data; struct ivpu_job *job; u32 *buf_handles; int idx, ret; - u8 priority; - - if (params->engine != DRM_IVPU_ENGINE_COMPUTE) - return -EINVAL; - - if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) - return -EINVAL; - - if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT) - return -EINVAL; - - if (!IS_ALIGNED(params->commands_offset, 8)) - return -EINVAL; - if (!file_priv->ctx.id) - return -EINVAL; - - if (file_priv->has_mmu_faults) - return -EBADFD; - - buf_handles = kcalloc(params->buffer_count, sizeof(u32), GFP_KERNEL); + buf_handles = kcalloc(buffer_count, sizeof(u32), GFP_KERNEL); if (!buf_handles) return -ENOMEM; - ret = copy_from_user(buf_handles, - (void __user *)params->buffers_ptr, - params->buffer_count * sizeof(u32)); + ret = copy_from_user(buf_handles, buffers_ptr, buffer_count * sizeof(u32)); if (ret) { ret = -EFAULT; goto err_free_handles; @@ -740,27 +730,23 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto err_free_handles; } - ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", - file_priv->ctx.id, params->buffer_count); + ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", file_priv->ctx.id, buffer_count); - job = ivpu_job_create(file_priv, params->engine, params->buffer_count); + job = ivpu_job_create(file_priv, engine, buffer_count); if (!job) { ivpu_err(vdev, "Failed to create job\n"); ret = -ENOMEM; goto err_exit_dev; } - ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count, - params->commands_offset); + ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, buffer_count, cmds_offset); if (ret) { ivpu_err(vdev, "Failed to prepare job: %d\n", ret); goto err_destroy_job; } - priority = ivpu_job_to_hws_priority(file_priv, params->priority); - down_read(&vdev->pm->reset_lock); - ret = ivpu_job_submit(job, priority); + ret = ivpu_job_submit(job, priority, cmdq_id); up_read(&vdev->pm->reset_lock); if (ret) goto err_signal_fence; @@ -780,6 +766,101 @@ err_free_handles: return ret; } +int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct drm_ivpu_submit *args = data; + u8 priority; + + if (args->engine != DRM_IVPU_ENGINE_COMPUTE) + return -EINVAL; + + if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) + return -EINVAL; + + if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT) + return -EINVAL; + + if (!IS_ALIGNED(args->commands_offset, 8)) + return -EINVAL; + + if (!file_priv->ctx.id) + return -EINVAL; + + if (file_priv->has_mmu_faults) + return -EBADFD; + + priority = ivpu_job_to_jsm_priority(args->priority); + + return ivpu_submit(file, file_priv, 0, args->buffer_count, args->engine, + (void __user *)args->buffers_ptr, args->commands_offset, priority); +} + +int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct drm_ivpu_cmdq_submit *args = data; + + if (args->cmdq_id < IVPU_CMDQ_MIN_ID || args->cmdq_id > IVPU_CMDQ_MAX_ID) + return -EINVAL; + + if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT) + return -EINVAL; + + if (!IS_ALIGNED(args->commands_offset, 8)) + return -EINVAL; + + if (!file_priv->ctx.id) + return -EINVAL; + + if (file_priv->has_mmu_faults) + return -EBADFD; + + return ivpu_submit(file, file_priv, args->cmdq_id, args->buffer_count, VPU_ENGINE_COMPUTE, + (void __user *)args->buffers_ptr, args->commands_offset, 0); +} + +int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct drm_ivpu_cmdq_create *args = data; + struct ivpu_cmdq *cmdq; + + if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) + return -EINVAL; + + mutex_lock(&file_priv->lock); + + cmdq = ivpu_cmdq_create(file_priv, ivpu_job_to_jsm_priority(args->priority), false); + if (cmdq) + args->cmdq_id = cmdq->id; + + mutex_unlock(&file_priv->lock); + + return cmdq ? 0 : -ENOMEM; +} + +int ivpu_cmdq_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct drm_ivpu_cmdq_destroy *args = data; + struct ivpu_cmdq *cmdq; + int ret = 0; + + mutex_lock(&file_priv->lock); + + cmdq = xa_load(&file_priv->cmdq_xa, args->cmdq_id); + if (!cmdq || cmdq->is_legacy) { + ret = -ENOENT; + goto unlock; + } + + ivpu_cmdq_destroy(file_priv, cmdq); +unlock: + mutex_unlock(&file_priv->lock); + return ret; +} + static void ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg) diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index 8b19e3f8b4cf..4d31277bcc41 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -30,8 +30,8 @@ struct ivpu_cmdq { u32 entry_count; u32 id; u32 db_id; - bool db_registered; u8 priority; + bool is_legacy; }; /** @@ -58,6 +58,9 @@ struct ivpu_job { }; int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int ivpu_cmdq_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file); void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv); diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h index a35b97b097bf..746c43bd3eb6 100644 --- a/include/uapi/drm/ivpu_accel.h +++ b/include/uapi/drm/ivpu_accel.h @@ -22,6 +22,9 @@ extern "C" { #define DRM_IVPU_METRIC_STREAMER_STOP 0x08 #define DRM_IVPU_METRIC_STREAMER_GET_DATA 0x09 #define DRM_IVPU_METRIC_STREAMER_GET_INFO 0x0a +#define DRM_IVPU_CMDQ_CREATE 0x0b +#define DRM_IVPU_CMDQ_DESTROY 0x0c +#define DRM_IVPU_CMDQ_SUBMIT 0x0d #define DRM_IOCTL_IVPU_GET_PARAM \ DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_GET_PARAM, struct drm_ivpu_param) @@ -57,6 +60,15 @@ extern "C" { DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_METRIC_STREAMER_GET_INFO, \ struct drm_ivpu_metric_streamer_get_data) +#define DRM_IOCTL_IVPU_CMDQ_CREATE \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_CREATE, struct drm_ivpu_cmdq_create) + +#define DRM_IOCTL_IVPU_CMDQ_DESTROY \ + DRM_IOW(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_DESTROY, struct drm_ivpu_cmdq_destroy) + +#define DRM_IOCTL_IVPU_CMDQ_SUBMIT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_SUBMIT, struct drm_ivpu_cmdq_submit) + /** * DOC: contexts * @@ -107,6 +119,13 @@ extern "C" { * accessible by hardware DMA. */ #define DRM_IVPU_CAP_DMA_MEMORY_RANGE 2 +/** + * DRM_IVPU_CAP_MANAGE_CMDQ + * + * Driver supports explicit command queue operations like command queue create, + * command queue destroy and submit job on specific command queue. + */ +#define DRM_IVPU_CAP_MANAGE_CMDQ 3 /** * struct drm_ivpu_param - Get/Set VPU parameters @@ -316,6 +335,44 @@ struct drm_ivpu_submit { __u32 priority; }; +/** + * struct drm_ivpu_cmdq_submit - Submit commands to the VPU using explicit command queue + * + * Execute a single command buffer on a given command queue. + * Handles to all referenced buffer objects have to be provided in @buffers_ptr. + * + * User space may wait on job completion using %DRM_IVPU_BO_WAIT ioctl. + */ +struct drm_ivpu_cmdq_submit { + /** + * @buffers_ptr: + * + * A pointer to an u32 array of GEM handles of the BOs required for this job. + * The number of elements in the array must be equal to the value given by @buffer_count. + * + * The first BO is the command buffer. The rest of array has to contain all + * BOs referenced from the command buffer. + */ + __u64 buffers_ptr; + + /** @buffer_count: Number of elements in the @buffers_ptr */ + __u32 buffer_count; + + /** @cmdq_id: ID for the command queue where job will be submitted */ + __u32 cmdq_id; + + /** @flags: Reserved for future use - must be zero */ + __u32 flags; + + /** + * @commands_offset: + * + * Offset inside the first buffer in @buffers_ptr containing commands + * to be executed. The offset has to be 8-byte aligned. + */ + __u32 commands_offset; +}; + /* drm_ivpu_bo_wait job status codes */ #define DRM_IVPU_JOB_STATUS_SUCCESS 0 #define DRM_IVPU_JOB_STATUS_ABORTED 256 @@ -388,6 +445,33 @@ struct drm_ivpu_metric_streamer_get_data { __u64 data_size; }; +/** + * struct drm_ivpu_cmdq_create - Create command queue for job submission + */ +struct drm_ivpu_cmdq_create { + /** @cmdq_id: Returned ID of created command queue */ + __u32 cmdq_id; + /** + * @priority: + * + * Priority to be set for related job command queue, can be one of the following: + * %DRM_IVPU_JOB_PRIORITY_DEFAULT + * %DRM_IVPU_JOB_PRIORITY_IDLE + * %DRM_IVPU_JOB_PRIORITY_NORMAL + * %DRM_IVPU_JOB_PRIORITY_FOCUS + * %DRM_IVPU_JOB_PRIORITY_REALTIME + */ + __u32 priority; +}; + +/** + * struct drm_ivpu_cmdq_destroy - Destroy a command queue + */ +struct drm_ivpu_cmdq_destroy { + /** @cmdq_id: ID of command queue to destroy */ + __u32 cmdq_id; +}; + /** * struct drm_ivpu_metric_streamer_stop - Stop collecting metric data */ -- cgit v1.2.3 From 573b73e5ac2ce0d58859eace8218f3a7e9212186 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 10 Jan 2025 11:13:01 +0000 Subject: drm/sched: Delete unused update_job_credits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No driver is using the update_job_credits() schduler vfunc so lets remove it. Signed-off-by: Tvrtko Ursulin Cc: Christian König Cc: Danilo Krummrich Cc: Matthew Brost Cc: Philipp Stanner Acked-by: Danilo Krummrich Acked-by: Boris Brezillon Acked-by: Matt Coster Signed-off-by: Philipp Stanner Link: https://patchwork.freedesktop.org/patch/msgid/20250110111301.76909-1-tvrtko.ursulin@igalia.com --- drivers/gpu/drm/scheduler/sched_main.c | 13 ------------- include/drm/gpu_scheduler.h | 13 ------------- 2 files changed, 26 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 57da84908752..81d69c2ff6ab 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -64,12 +64,6 @@ * credit limit, the job won't be executed. Instead, the scheduler will wait * until the credit count has decreased enough to not overflow its credit limit. * This implies waiting for previously executed jobs. - * - * Optionally, drivers may register a callback (update_job_credits) provided by - * struct drm_sched_backend_ops to update the job's credits dynamically. The - * scheduler executes this callback every time the scheduler considers a job for - * execution and subsequently checks whether the job fits the scheduler's credit - * limit. */ #include @@ -133,13 +127,6 @@ static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched, if (!s_job) return false; - if (sched->ops->update_job_credits) { - s_job->credits = sched->ops->update_job_credits(s_job); - - drm_WARN(sched, !s_job->credits, - "Jobs with zero credits bypass job-flow control.\n"); - } - /* If a job exceeds the credit limit, truncate it to the credit limit * itself to guarantee forward progress. */ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 95e17504e46a..e2e6af8849c6 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -476,19 +476,6 @@ struct drm_sched_backend_ops { * and it's time to clean it up. */ void (*free_job)(struct drm_sched_job *sched_job); - - /** - * @update_job_credits: Called when the scheduler is considering this - * job for execution. - * - * This callback returns the number of credits the job would take if - * pushed to the hardware. Drivers may use this to dynamically update - * the job's credit count. For instance, deduct the number of credits - * for already signalled native fences. - * - * This callback is optional. - */ - u32 (*update_job_credits)(struct drm_sched_job *sched_job); }; /** -- cgit v1.2.3 From 1f463794097dcdf4c64fffd31de2177681525e35 Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Tue, 17 Dec 2024 15:58:44 +0100 Subject: drm/ttm: Balance ttm_resource_cursor_init() and ttm_resource_cursor_fini() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the interface more symmetric by providing and using a ttm_resource_cursor_init(). v10: - Fix a stray newline (Matthew Brost) - Update kerneldoc (Matthew Brost) Signed-off-by: Thomas Hellström Reviewed-by: Matthew Brost Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20241217145852.37342-2-thomas.hellstrom@linux.intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- drivers/gpu/drm/ttm/ttm_bo_util.c | 3 ++- drivers/gpu/drm/ttm/ttm_resource.c | 35 ++++++++++++++++++++++++----------- include/drm/ttm/ttm_resource.h | 11 ++++++----- 4 files changed, 34 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 48c5365efca1..06d6a452c4f4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -450,7 +450,8 @@ int ttm_bo_evict_first(struct ttm_device *bdev, struct ttm_resource_manager *man int ret = 0; spin_lock(&bdev->lru_lock); - res = ttm_resource_manager_first(man, &cursor); + ttm_resource_cursor_init(&cursor, man); + res = ttm_resource_manager_first(&cursor); ttm_resource_cursor_fini(&cursor); if (!res) { ret = -ENOENT; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index d939925efa81..917096bd5f68 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -865,7 +865,8 @@ s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev, s64 lret; spin_lock(&bdev->lru_lock); - ttm_resource_manager_for_each_res(man, &cursor, res) { + ttm_resource_cursor_init(&cursor, man); + ttm_resource_manager_for_each_res(&cursor, res) { struct ttm_buffer_object *bo = res->bo; bool bo_needs_unlock = false; bool bo_locked = false; diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index a87665eb28a6..e19360cc7930 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -81,6 +81,23 @@ static void ttm_bulk_move_drop_cursors(struct ttm_lru_bulk_move *bulk) ttm_resource_cursor_clear_bulk(cursor); } +/** + * ttm_resource_cursor_init() - Initialize a struct ttm_resource_cursor + * @cursor: The cursor to initialize. + * @man: The resource manager. + * + * Initialize the cursor before using it for iteration. + */ +void ttm_resource_cursor_init(struct ttm_resource_cursor *cursor, + struct ttm_resource_manager *man) +{ + cursor->priority = 0; + cursor->man = man; + ttm_lru_item_init(&cursor->hitch, TTM_LRU_HITCH); + INIT_LIST_HEAD(&cursor->bulk_link); + INIT_LIST_HEAD(&cursor->hitch.link); +} + /** * ttm_resource_cursor_fini() - Finalize the LRU list cursor usage * @cursor: The struct ttm_resource_cursor to finalize. @@ -593,7 +610,6 @@ ttm_resource_cursor_check_bulk(struct ttm_resource_cursor *cursor, /** * ttm_resource_manager_first() - Start iterating over the resources * of a resource manager - * @man: resource manager to iterate over * @cursor: cursor to record the position * * Initializes the cursor and starts iterating. When done iterating, @@ -602,17 +618,16 @@ ttm_resource_cursor_check_bulk(struct ttm_resource_cursor *cursor, * Return: The first resource from the resource manager. */ struct ttm_resource * -ttm_resource_manager_first(struct ttm_resource_manager *man, - struct ttm_resource_cursor *cursor) +ttm_resource_manager_first(struct ttm_resource_cursor *cursor) { - lockdep_assert_held(&man->bdev->lru_lock); + struct ttm_resource_manager *man = cursor->man; - cursor->priority = 0; - cursor->man = man; - ttm_lru_item_init(&cursor->hitch, TTM_LRU_HITCH); - INIT_LIST_HEAD(&cursor->bulk_link); - list_add(&cursor->hitch.link, &man->lru[cursor->priority]); + if (WARN_ON_ONCE(!man)) + return NULL; + + lockdep_assert_held(&man->bdev->lru_lock); + list_move(&cursor->hitch.link, &man->lru[cursor->priority]); return ttm_resource_manager_next(cursor); } @@ -648,8 +663,6 @@ ttm_resource_manager_next(struct ttm_resource_cursor *cursor) ttm_resource_cursor_clear_bulk(cursor); } - ttm_resource_cursor_fini(cursor); - return NULL; } diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h index be034be56ba1..e1f3b95d73b6 100644 --- a/include/drm/ttm/ttm_resource.h +++ b/include/drm/ttm/ttm_resource.h @@ -325,6 +325,9 @@ struct ttm_resource_cursor { unsigned int priority; }; +void ttm_resource_cursor_init(struct ttm_resource_cursor *cursor, + struct ttm_resource_manager *man); + void ttm_resource_cursor_fini(struct ttm_resource_cursor *cursor); /** @@ -456,8 +459,7 @@ void ttm_resource_manager_debug(struct ttm_resource_manager *man, struct drm_printer *p); struct ttm_resource * -ttm_resource_manager_first(struct ttm_resource_manager *man, - struct ttm_resource_cursor *cursor); +ttm_resource_manager_first(struct ttm_resource_cursor *cursor); struct ttm_resource * ttm_resource_manager_next(struct ttm_resource_cursor *cursor); @@ -466,14 +468,13 @@ ttm_lru_first_res_or_null(struct list_head *head); /** * ttm_resource_manager_for_each_res - iterate over all resources - * @man: the resource manager * @cursor: struct ttm_resource_cursor for the current position * @res: the current resource * * Iterate over all the evictable resources in a resource manager. */ -#define ttm_resource_manager_for_each_res(man, cursor, res) \ - for (res = ttm_resource_manager_first(man, cursor); res; \ +#define ttm_resource_manager_for_each_res(cursor, res) \ + for (res = ttm_resource_manager_first(cursor); res; \ res = ttm_resource_manager_next(cursor)) struct ttm_kmap_iter * -- cgit v1.2.3 From c5e3306a424b52e38ad2c28c7f3399fcd03e383d Mon Sep 17 00:00:00 2001 From: Simona Vetter Date: Wed, 8 Jan 2025 18:24:16 +0100 Subject: drm/atomic: clarify the rules around drm_atomic_state->allow_modeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msm is automagically upgrading normal commits to full modesets, and that's a big no-no: - for one this results in full on->off->on transitions on all these crtc, at least if you're using the usual helpers. Which seems to be the case, and is breaking uapi - further even if the ctm change itself would not result in flicker, this can hide modesets for other reasons. Which again breaks the uapi v2: I forgot the case of adding unrelated crtc state. Add that case and link to the existing kerneldoc explainers. This has come up in an irc discussion with Manasi and Ville about intel's bigjoiner mode. Also cc everyone involved in the msm irc discussion, more people joined after I sent out v1. v3: Wording polish from Pekka and Thomas Acked-by: Pekka Paalanen Acked-by: Dmitry Baryshkov Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Cc: Pekka Paalanen Cc: Rob Clark Cc: Simon Ser Cc: Manasi Navare Cc: Ville Syrjälä Cc: Abhinav Kumar Cc: Dmitry Baryshkov Signed-off-by: Simona Vetter Signed-off-by: Simona Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20250108172417.160831-1-simona.vetter@ffwll.ch --- include/drm/drm_atomic.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 31ca88deb10d..1ded9a8d4e84 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -376,8 +376,27 @@ struct drm_atomic_state { * * Allow full modeset. This is used by the ATOMIC IOCTL handler to * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should - * never consult this flag, instead looking at the output of - * drm_atomic_crtc_needs_modeset(). + * generally not consult this flag, but instead look at the output of + * drm_atomic_crtc_needs_modeset(). The detailed rules are: + * + * - Drivers must not consult @allow_modeset in the atomic commit path. + * Use drm_atomic_crtc_needs_modeset() instead. + * + * - Drivers must consult @allow_modeset before adding unrelated struct + * drm_crtc_state to this commit by calling + * drm_atomic_get_crtc_state(). See also the warning in the + * documentation for that function. + * + * - Drivers must never change this flag, it is under the exclusive + * control of userspace. + * + * - Drivers may consult @allow_modeset in the atomic check path, if + * they have the choice between an optimal hardware configuration + * which requires a modeset, and a less optimal configuration which + * can be committed without a modeset. An example would be suboptimal + * scanout FIFO allocation resulting in increased idle power + * consumption. This allows userspace to avoid flickering and delays + * for the normal composition loop at reasonable cost. */ bool allow_modeset : 1; /** -- cgit v1.2.3 From 51678bb9a7fb25e44f38a4f0b1bd283fec809917 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 13 Jan 2025 10:33:40 +0000 Subject: drm/sched: Add helper to check job dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets isolate scheduler internals from drivers such as pvr which currently walks the dependency array to look for fences. Signed-off-by: Tvrtko Ursulin Cc: Christian König Cc: Danilo Krummrich Cc: Matthew Brost Cc: Philipp Stanner Reviewed-by: Matt Coster Acked-by: Danilo Krummrich Signed-off-by: Philipp Stanner Link: https://patchwork.freedesktop.org/patch/msgid/20250113103341.43914-1-tvrtko.ursulin@igalia.com --- drivers/gpu/drm/scheduler/sched_main.c | 23 +++++++++++++++++++++++ include/drm/gpu_scheduler.h | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index d172e3158880..a48be16ab84f 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -984,6 +984,29 @@ int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, } EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies); +/** + * drm_sched_job_has_dependency - check whether fence is the job's dependency + * @job: scheduler job to check + * @fence: fence to look for + * + * Returns: + * True if @fence is found within the job's dependencies, or otherwise false. + */ +bool drm_sched_job_has_dependency(struct drm_sched_job *job, + struct dma_fence *fence) +{ + struct dma_fence *f; + unsigned long index; + + xa_for_each(&job->dependencies, index, f) { + if (f == fence) + return true; + } + + return false; +} +EXPORT_SYMBOL(drm_sched_job_has_dependency); + /** * drm_sched_job_cleanup - clean up scheduler job resources * @job: scheduler job to clean up diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index e2e6af8849c6..a0ff08123f07 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -564,7 +564,8 @@ int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, struct drm_gem_object *obj, bool write); - +bool drm_sched_job_has_dependency(struct drm_sched_job *job, + struct dma_fence *fence); void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, -- cgit v1.2.3 From c367b772e6d89d8c7b560c7df7e3803ce6b8bcea Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Thu, 16 Jan 2025 18:47:15 +0100 Subject: drm/managed: Add DRM-managed alloc_ordered_workqueue Add drmm_alloc_ordered_workqueue(), a helper that provides managed ordered workqueue cleanup. The workqueue will be destroyed with the final reference of the DRM device. Reviewed-by: Thomas Zimmermann Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20250116-google-vkms-managed-v9-3-3e4ae1bd05a0@bootlin.com Signed-off-by: Louis Chauvet --- drivers/gpu/drm/drm_managed.c | 8 ++++++++ include/drm/drm_managed.h | 12 ++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c index 79ce86a5bd67..cc4c463daae7 100644 --- a/drivers/gpu/drm/drm_managed.c +++ b/drivers/gpu/drm/drm_managed.c @@ -310,3 +310,11 @@ void __drmm_mutex_release(struct drm_device *dev, void *res) mutex_destroy(lock); } EXPORT_SYMBOL(__drmm_mutex_release); + +void __drmm_workqueue_release(struct drm_device *device, void *res) +{ + struct workqueue_struct *wq = res; + + destroy_workqueue(wq); +} +EXPORT_SYMBOL(__drmm_workqueue_release); diff --git a/include/drm/drm_managed.h b/include/drm/drm_managed.h index f547b09ca023..53017cc609ac 100644 --- a/include/drm/drm_managed.h +++ b/include/drm/drm_managed.h @@ -127,4 +127,16 @@ void __drmm_mutex_release(struct drm_device *dev, void *res); drmm_add_action_or_reset(dev, __drmm_mutex_release, lock); \ }) \ +void __drmm_workqueue_release(struct drm_device *device, void *wq); + +#define drmm_alloc_ordered_workqueue(dev, fmt, flags, args...) \ + ({ \ + struct workqueue_struct *wq = alloc_ordered_workqueue(fmt, flags, ##args); \ + wq ? ({ \ + int ret = drmm_add_action_or_reset(dev, __drmm_workqueue_release, wq); \ + ret ? ERR_PTR(ret) : wq; \ + }) : \ + wq; \ + }) + #endif -- cgit v1.2.3 From 1914ba2b91ea8eff674e2369f610bb6bb9056745 Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Thu, 16 Jan 2025 18:47:19 +0100 Subject: drm: writeback: Create drmm variants for drm_writeback_connector initialization To allows driver to only use drmm objects, add helper to create drm_writeback_connectors with automated lifetime management. Acked-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20250116-google-vkms-managed-v9-7-3e4ae1bd05a0@bootlin.com Signed-off-by: Louis Chauvet --- drivers/gpu/drm/drm_writeback.c | 74 +++++++++++++++++++++++++++++++++++++++++ include/drm/drm_writeback.h | 6 ++++ 2 files changed, 80 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 4cdc6cdcf76b..3628fbef7752 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -340,6 +340,80 @@ int drm_writeback_connector_init_with_encoder(struct drm_device *dev, } EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder); +/** + * drm_writeback_connector_cleanup - Cleanup the writeback connector + * @dev: DRM device + * @wb_connector: Pointer to the writeback connector to clean up + * + * This will decrement the reference counter of blobs and destroy properties. It + * will also clean the remaining jobs in this writeback connector. Caution: This helper will not + * clean up the attached encoder and the drm_connector. + */ +static void drm_writeback_connector_cleanup(struct drm_device *dev, + struct drm_writeback_connector *wb_connector) +{ + unsigned long flags; + struct drm_writeback_job *pos, *n; + + delete_writeback_properties(dev); + drm_property_blob_put(wb_connector->pixel_formats_blob_ptr); + + spin_lock_irqsave(&wb_connector->job_lock, flags); + list_for_each_entry_safe(pos, n, &wb_connector->job_queue, list_entry) { + drm_writeback_cleanup_job(pos); + list_del(&pos->list_entry); + } + spin_unlock_irqrestore(&wb_connector->job_lock, flags); +} + +/** + * drmm_writeback_connector_init - Initialize a writeback connector with + * a custom encoder + * + * @dev: DRM device + * @wb_connector: Writeback connector to initialize + * @con_funcs: Connector funcs vtable + * @enc: Encoder to connect this writeback connector + * @formats: Array of supported pixel formats for the writeback engine + * @n_formats: Length of the formats array + * + * This function initialize a writeback connector and register its cleanup. + * + * This function creates the writeback-connector-specific properties if they + * have not been already created, initializes the connector as + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property + * values. + * + * Returns: 0 on success, or a negative error code + */ +int drmm_writeback_connector_init(struct drm_device *dev, + struct drm_writeback_connector *wb_connector, + const struct drm_connector_funcs *con_funcs, + struct drm_encoder *enc, + const u32 *formats, int n_formats) +{ + struct drm_connector *connector = &wb_connector->base; + int ret; + + ret = drmm_connector_init(dev, connector, con_funcs, + DRM_MODE_CONNECTOR_WRITEBACK, NULL); + if (ret) + return ret; + + ret = __drm_writeback_connector_init(dev, wb_connector, enc, formats, + n_formats); + if (ret) + return ret; + + ret = drmm_add_action_or_reset(dev, (void *)drm_writeback_connector_cleanup, + wb_connector); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(drmm_writeback_connector_init); + int drm_writeback_set_fb(struct drm_connector_state *conn_state, struct drm_framebuffer *fb) { diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index 17e576c80169..c380a7b8f55a 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h @@ -161,6 +161,12 @@ int drm_writeback_connector_init_with_encoder(struct drm_device *dev, const struct drm_connector_funcs *con_funcs, const u32 *formats, int n_formats); +int drmm_writeback_connector_init(struct drm_device *dev, + struct drm_writeback_connector *wb_connector, + const struct drm_connector_funcs *con_funcs, + struct drm_encoder *enc, + const u32 *formats, int n_formats); + int drm_writeback_set_fb(struct drm_connector_state *conn_state, struct drm_framebuffer *fb); -- cgit v1.2.3 From 3ab334814dc7dff39075e055e12847d51878916e Mon Sep 17 00:00:00 2001 From: "Eric R. Smith" Date: Thu, 19 Dec 2024 13:49:28 -0400 Subject: drm: add modifiers for MediaTek tiled formats MediaTek (MTK) uses some unique tiled memory formats for video decoding. Add these to the uapi drm_fourcc.h so that we can use them in Mesa, GStreamer, and other tools/libraries. v2: - Classify the modifier bits into categories and provide room for expansion (Daniel S.) Signed-off-by: Eric R. Smith Reviewed-by: Daniel Stone Link: https://patchwork.freedesktop.org/patch/msgid/20241219174929.126205-1-eric.smith@collabora.com Signed-off-by: Daniel Stone --- include/uapi/drm/drm_fourcc.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 70f3b00b0681..e41a3cec6a9e 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -421,6 +421,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a +#define DRM_FORMAT_MOD_VENDOR_MTK 0x0b /* add more to the end as needed */ @@ -1453,6 +1454,46 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) */ #define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) +/* MediaTek modifiers + * Bits Parameter Notes + * ----- ------------------------ --------------------------------------------- + * 7: 0 TILE LAYOUT Values are MTK_FMT_MOD_TILE_* + * 15: 8 COMPRESSION Values are MTK_FMT_MOD_COMPRESS_* + * 23:16 10 BIT LAYOUT Values are MTK_FMT_MOD_10BIT_LAYOUT_* + * + */ + +#define DRM_FORMAT_MOD_MTK(__flags) fourcc_mod_code(MTK, __flags) + +/* + * MediaTek Tiled Modifier + * The lowest 8 bits of the modifier is used to specify the tiling + * layout. Only the 16L_32S tiling is used for now, but we define an + * "untiled" version and leave room for future expansion. + */ +#define MTK_FMT_MOD_TILE_MASK 0xf +#define MTK_FMT_MOD_TILE_NONE 0x0 +#define MTK_FMT_MOD_TILE_16L32S 0x1 + +/* + * Bits 8-15 specify compression options + */ +#define MTK_FMT_MOD_COMPRESS_MASK (0xf << 8) +#define MTK_FMT_MOD_COMPRESS_NONE (0x0 << 8) +#define MTK_FMT_MOD_COMPRESS_V1 (0x1 << 8) + +/* + * Bits 16-23 specify how the bits of 10 bit formats are + * stored out in memory + */ +#define MTK_FMT_MOD_10BIT_LAYOUT_MASK (0xf << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_PACKED (0x0 << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_LSBTILED (0x1 << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_LSBRASTER (0x2 << 16) + +/* alias for the most common tiling format */ +#define DRM_FORMAT_MOD_MTK_16L_32S_TILE DRM_FORMAT_MOD_MTK(MTK_FMT_MOD_TILE_16L32S) + /* * AMD modifiers * -- cgit v1.2.3 From 6bbce873a9c97cb12f5455c497be279ac58e707f Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Mon, 13 Jan 2025 17:10:59 +0800 Subject: drm/dp_mst: Fix drm RAD print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why] The RAD of sideband message printed today is incorrect. For RAD stored within MST branch - If MST branch LCT is 1, it's RAD array is untouched and remained as 0. - If MST branch LCT is larger than 1, use nibble to store the up facing port number in cascaded sequence as illustrated below: u8 RAD[0] = (LCT_2_UFP << 4) | LCT_3_UFP RAD[1] = (LCT_4_UFP << 4) | LCT_5_UFP ... In drm_dp_mst_rad_to_str(), it wrongly to use BIT_MASK(4) to fetch the port number of one nibble. [How] Adjust the code by: - RAD array items are valuable only for LCT >= 1. - Use 0xF as the mask to replace BIT_MASK(4) V2: - Document how RAD is constructed (Imre) V3: - Adjust the comment for rad[] so kdoc formats it properly (Lyude) Fixes: 2f015ec6eab6 ("drm/dp_mst: Add sideband down request tracing + selftests") Cc: Imre Deak Cc: Ville Syrjälä Cc: Harry Wentland Cc: Lyude Paul Reviewed-by: Lyude Paul Signed-off-by: Wayne Lin Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20250113091100.3314533-2-Wayne.Lin@amd.com --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 8 ++++---- include/drm/display/drm_dp_mst_helper.h | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index f8cd094efa3c..271a00b81264 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -175,13 +175,13 @@ static int drm_dp_mst_rad_to_str(const u8 rad[8], u8 lct, char *out, size_t len) { int i; - u8 unpacked_rad[16]; + u8 unpacked_rad[16] = {}; - for (i = 0; i < lct; i++) { + for (i = 1; i < lct; i++) { if (i % 2) - unpacked_rad[i] = rad[i / 2] >> 4; + unpacked_rad[i] = rad[(i - 1) / 2] >> 4; else - unpacked_rad[i] = rad[i / 2] & BIT_MASK(4); + unpacked_rad[i] = rad[(i - 1) / 2] & 0xF; } /* TODO: Eventually add something to printk so we can format the rad diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index a80ba457a858..6398a6b50bd1 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -222,6 +222,13 @@ struct drm_dp_mst_branch { */ struct list_head destroy_next; + /** + * @rad: Relative Address of the MST branch. + * For &drm_dp_mst_topology_mgr.mst_primary, it's rad[8] are all 0, + * unset and unused. For MST branches connected after mst_primary, + * in each element of rad[] the nibbles are ordered by the most + * signifcant 4 bits first and the least significant 4 bits second. + */ u8 rad[8]; u8 lct; int num_ports; -- cgit v1.2.3 From 038f79638e0676359e44c5db458d52994f9b5ac1 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Wed, 8 Jan 2025 18:03:55 +0100 Subject: ASoC: hdmi-codec: allow to refine formats actually supported Currently the hdmi-codec driver registers all the formats that are allowed on the I2S bus. Add i2s_formats field to codec data, to allow the hdmi codec client to refine the list of the audio I2S formats actually supported. Signed-off-by: Olivier Moysan Acked-by: Mark Brown Link: https://patchwork.freedesktop.org/patch/msgid/20250108170356.413063-3-olivier.moysan@foss.st.com Signed-off-by: Dmitry Baryshkov --- include/sound/hdmi-codec.h | 1 + sound/soc/codecs/hdmi-codec.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index b220072cfa1b..273f4c36fad9 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -120,6 +120,7 @@ struct hdmi_codec_ops { /* HDMI codec initalization data */ struct hdmi_codec_pdata { const struct hdmi_codec_ops *ops; + u64 i2s_formats; uint i2s:1; uint no_i2s_playback:1; uint no_i2s_capture:1; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 69f98975e14a..5c47aa0551c9 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -1077,6 +1077,10 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (hcd->i2s) { daidrv[i] = hdmi_i2s_dai; daidrv[i].playback.channels_max = hcd->max_i2s_channels; + if (hcd->i2s_formats) { + daidrv[i].playback.formats = hcd->i2s_formats; + daidrv[i].capture.formats = hcd->i2s_formats; + } if (hcd->no_i2s_playback) memset(&daidrv[i].playback, 0, sizeof(daidrv[i].playback)); -- cgit v1.2.3 From e5e8367d25abcf1ed5f9f84df7c856bd4e1e12c9 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Wed, 22 Jan 2025 11:03:56 +0530 Subject: drm/dp: Add the DPCD register required for Extended wake timeout Add DPCD registers required to configure Extended Wake Timeout for LTTPR. Signed-off-by: Suraj Kandpal Reviewed-by: Arun R Murthy Link: https://patchwork.freedesktop.org/patch/msgid/20250122053358.1545039-2-suraj.kandpal@intel.com --- include/drm/display/drm_dp.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include') diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index a6f8b098c56f..480370bba1de 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -696,6 +696,9 @@ #define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */ # define DP_PWR_NOT_NEEDED (1 << 0) +#define DP_EXTENDED_DPRX_SLEEP_WAKE_TIMEOUT_GRANT 0x119 /* 1.4a */ +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_GRANTED (1 << 0) + #define DP_FEC_CONFIGURATION 0x120 /* 1.4 */ # define DP_FEC_READY (1 << 0) # define DP_FEC_ERR_COUNT_SEL_MASK (7 << 1) @@ -1168,6 +1171,15 @@ # define DP_VSC_EXT_CEA_SDP_SUPPORTED (1 << 6) /* DP 1.4 */ # define DP_VSC_EXT_CEA_SDP_CHAINING_SUPPORTED (1 << 7) /* DP 1.4 */ +#define DP_EXTENDED_DPRX_SLEEP_WAKE_TIMEOUT_REQUEST 0x2211 /* 1.4a */ +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_MASK 0xff +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_1_MS 0x00 +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_20_MS 0x01 +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_40_MS 0x02 +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_60_MS 0x03 +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_80_MS 0x04 +# define DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_100_MS 0x05 + #define DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1 0x2214 /* 2.0 E11 */ # define DP_ADAPTIVE_SYNC_SDP_SUPPORTED (1 << 0) # define DP_ADAPTIVE_SYNC_SDP_OPERATION_MODE GENMASK(1, 0) @@ -1473,6 +1485,8 @@ #define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ #define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ #define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ +# define DP_EXTENDED_WAKE_TIMEOUT_REQUEST_MASK 0x7f +# define DP_EXTENDED_WAKE_TIMEOUT_GRANT (1 << 7) #define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER 0xf0006 /* 2.0 */ # define DP_PHY_REPEATER_128B132B_SUPPORTED (1 << 0) /* See DP_128B132B_SUPPORTED_LINK_RATES for values */ -- cgit v1.2.3 From eaf53ac4901fbb06a94cc0b7842567b3d13c0492 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Wed, 22 Jan 2025 11:03:57 +0530 Subject: drm/display/dp: Define function to setup Extended wake time Extended wake timeout request helps to give additional time by reading the DPCD register through which sink requests the minimal amount of time required to wake the sink up. Source device shall keep retying the AUX tansaction till the extended timeout that is being granted for LTTPRs from the sink device. --v2 -Add documentation [Dmitry] Spec: DP v2.1 Section 3.6.12.3 Signed-off-by: Suraj Kandpal Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20250122053358.1545039-3-suraj.kandpal@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 58 +++++++++++++++++++++++++++++++++ include/drm/display/drm_dp_helper.h | 1 + 2 files changed, 59 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index da3c8521a7fa..c488d160a3c1 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -459,6 +459,64 @@ void drm_dp_lttpr_link_train_channel_eq_delay(const struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay); +/** + * drm_dp_lttpr_wake_timeout_setup() - Grant extended time for sink to wake up + * @aux: The DP AUX channel to use + * @transparent_mode: This is true if lttpr is in transparent mode + * + * This function checks if the sink needs any extended wake time, if it does + * it grants this request. Post this setup the source device can keep trying + * the Aux transaction till the granted wake timeout. + * If this function is not called all Aux transactions are expected to take + * a default of 1ms before they throw an error. + */ +void drm_dp_lttpr_wake_timeout_setup(struct drm_dp_aux *aux, bool transparent_mode) +{ + u8 val = 1; + int ret; + + if (transparent_mode) { + static const u8 timeout_mapping[] = { + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_1_MS] = 1, + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_20_MS] = 20, + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_40_MS] = 40, + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_60_MS] = 60, + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_80_MS] = 80, + [DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_100_MS] = 100, + }; + + ret = drm_dp_dpcd_readb(aux, DP_EXTENDED_DPRX_SLEEP_WAKE_TIMEOUT_REQUEST, &val); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, + "Failed to read Extended sleep wake timeout request\n"); + return; + } + + val = (val < sizeof(timeout_mapping) && timeout_mapping[val]) ? + timeout_mapping[val] : 1; + + if (val > 1) + drm_dp_dpcd_writeb(aux, + DP_EXTENDED_DPRX_SLEEP_WAKE_TIMEOUT_GRANT, + DP_DPRX_SLEEP_WAKE_TIMEOUT_PERIOD_GRANTED); + } else { + ret = drm_dp_dpcd_readb(aux, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &val); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, + "Failed to read Extended sleep wake timeout request\n"); + return; + } + + val = (val & DP_EXTENDED_WAKE_TIMEOUT_REQUEST_MASK) ? + (val & DP_EXTENDED_WAKE_TIMEOUT_REQUEST_MASK) * 10 : 1; + + if (val > 1) + drm_dp_dpcd_writeb(aux, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, + DP_EXTENDED_WAKE_TIMEOUT_GRANT); + } +} +EXPORT_SYMBOL(drm_dp_lttpr_wake_timeout_setup); + u8 drm_dp_link_rate_to_bw_code(int link_rate) { switch (link_rate) { diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 8f4054a56039..89a34dff85a4 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -633,6 +633,7 @@ int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); bool drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); +void drm_dp_lttpr_wake_timeout_setup(struct drm_dp_aux *aux, bool transparent_mode); void drm_dp_remote_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux); -- cgit v1.2.3 From f269e5eac4dbf55d89409257ec794c9c3c51e515 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Tue, 4 Feb 2025 09:51:58 +0100 Subject: drm/drm_mode_object: fix typo in kerneldoc Remove unintended extra word. Reviewed-by: Dmitry Baryshkov Acked-by: Louis Chauvet Signed-off-by: Luca Ceresoli Link: https://patchwork.freedesktop.org/patch/msgid/20250204-drm-small-improvements-v4-1-d6bbc92f12f1@bootlin.com Signed-off-by: Louis Chauvet --- include/drm/drm_mode_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index 08d7a7f0188f..c68edbd126d0 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -35,7 +35,7 @@ struct drm_file; * @id: userspace visible identifier * @type: type of the object, one of DRM_MODE_OBJECT\_\* * @properties: properties attached to this object, including values - * @refcount: reference count for objects which with dynamic lifetime + * @refcount: reference count for objects with dynamic lifetime * @free_cb: free function callback, only set for objects with dynamic lifetime * * Base structure for modeset objects visible to userspace. Objects can be -- cgit v1.2.3 From 2eca617f12586abff62038db1c14cb3aa60a15aa Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 5 Feb 2025 11:04:10 +0000 Subject: drm/scheduler: Remove some unused prototypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As far as I can tell some removed prototypes were introduced by probably bad conflict resolution in fc58764bbf60 ("Merge tag 'amd-drm-next-6.2-2022-11-18' of https://gitlab.freedesktop.org/agd5f/linux into drm-next"). Remove them. Signed-off-by: Tvrtko Ursulin Cc: Christian König Cc: Danilo Krummrich Cc: Matthew Brost Cc: Philipp Stanner Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20250205110410.7941-1-tvrtko.ursulin@igalia.com --- include/drm/gpu_scheduler.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index a0ff08123f07..cf88f2bd020f 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -581,10 +581,6 @@ void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); void drm_sched_start(struct drm_gpu_scheduler *sched, int errno); void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); void drm_sched_increase_karma(struct drm_sched_job *bad); -void drm_sched_reset_karma(struct drm_sched_job *bad); -void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type); -bool drm_sched_dependency_optimized(struct dma_fence* fence, - struct drm_sched_entity *entity); void drm_sched_fault(struct drm_gpu_scheduler *sched); void drm_sched_rq_add_entity(struct drm_sched_rq *rq, -- cgit v1.2.3 From af6c2b7c46e16701fba44a21326cb634786e3e71 Mon Sep 17 00:00:00 2001 From: Adrián Larumbe Date: Thu, 30 Jan 2025 17:28:10 +0000 Subject: drm/file: Add fdinfo helper for printing regions with prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is motivated by the desire of some drivers (eg. Panthor) to print the size of internal memory regions with a prefix that reflects the driver name, as suggested in the previous documentation commit. That means adding a new argument to print_size and making it available for DRM users. Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Adrián Larumbe Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20250130172851.941597-3-adrian.larumbe@collabora.com --- drivers/gpu/drm/drm_file.c | 26 ++++++++++++++++++-------- include/drm/drm_file.h | 5 +++++ 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 2289e71e2fa2..c299cd94d3f7 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -830,8 +830,11 @@ void drm_send_event(struct drm_device *dev, struct drm_pending_event *e) } EXPORT_SYMBOL(drm_send_event); -static void print_size(struct drm_printer *p, const char *stat, - const char *region, u64 sz) +void drm_fdinfo_print_size(struct drm_printer *p, + const char *prefix, + const char *stat, + const char *region, + u64 sz) { const char *units[] = {"", " KiB", " MiB"}; unsigned u; @@ -842,8 +845,10 @@ static void print_size(struct drm_printer *p, const char *stat, sz = div_u64(sz, SZ_1K); } - drm_printf(p, "drm-%s-%s:\t%llu%s\n", stat, region, sz, units[u]); + drm_printf(p, "%s-%s-%s:\t%llu%s\n", + prefix, stat, region, sz, units[u]); } +EXPORT_SYMBOL(drm_fdinfo_print_size); int drm_memory_stats_is_zero(const struct drm_memory_stats *stats) { @@ -868,17 +873,22 @@ void drm_print_memory_stats(struct drm_printer *p, enum drm_gem_object_status supported_status, const char *region) { - print_size(p, "total", region, stats->private + stats->shared); - print_size(p, "shared", region, stats->shared); + const char *prefix = "drm"; + + drm_fdinfo_print_size(p, prefix, "total", region, + stats->private + stats->shared); + drm_fdinfo_print_size(p, prefix, "shared", region, stats->shared); if (supported_status & DRM_GEM_OBJECT_ACTIVE) - print_size(p, "active", region, stats->active); + drm_fdinfo_print_size(p, prefix, "active", region, stats->active); if (supported_status & DRM_GEM_OBJECT_RESIDENT) - print_size(p, "resident", region, stats->resident); + drm_fdinfo_print_size(p, prefix, "resident", region, + stats->resident); if (supported_status & DRM_GEM_OBJECT_PURGEABLE) - print_size(p, "purgeable", region, stats->purgeable); + drm_fdinfo_print_size(p, prefix, "purgeable", region, + stats->purgeable); } EXPORT_SYMBOL(drm_print_memory_stats); diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index ef817926cddd..94d365b22505 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -495,6 +495,11 @@ struct drm_memory_stats { enum drm_gem_object_status; int drm_memory_stats_is_zero(const struct drm_memory_stats *stats); +void drm_fdinfo_print_size(struct drm_printer *p, + const char *prefix, + const char *stat, + const char *region, + u64 sz); void drm_print_memory_stats(struct drm_printer *p, const struct drm_memory_stats *stats, enum drm_gem_object_status supported_status, -- cgit v1.2.3 From 4f5f701c55c1dfa287c6ad55a4bcb4bc6cad974a Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 4 Feb 2025 17:28:24 -0600 Subject: drm/panthor: Convert IOCTL defines to an enum Use an enum instead of #defines for panthor IOCTLs. This allows the header to be used with Rust code as bindgen can't handle complex defines. Cc: Beata Michalska Signed-off-by: Rob Herring (Arm) Reviewed-by: Alice Ryhl Acked-by: Boris Brezillon Reviewed-by: Steven Price Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20250204232824.3819437-1-robh@kernel.org --- include/uapi/drm/panthor_drm.h | 86 +++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/include/uapi/drm/panthor_drm.h b/include/uapi/drm/panthor_drm.h index b99763cbae48..97e2c4510e69 100644 --- a/include/uapi/drm/panthor_drm.h +++ b/include/uapi/drm/panthor_drm.h @@ -129,48 +129,6 @@ enum drm_panthor_ioctl_id { DRM_PANTHOR_TILER_HEAP_DESTROY, }; -/** - * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number - * @__access: Access type. Must be R, W or RW. - * @__id: One of the DRM_PANTHOR_xxx id. - * @__type: Suffix of the type being passed to the IOCTL. - * - * Don't use this macro directly, use the DRM_IOCTL_PANTHOR_xxx - * values instead. - * - * Return: An IOCTL number to be passed to ioctl() from userspace. - */ -#define DRM_IOCTL_PANTHOR(__access, __id, __type) \ - DRM_IO ## __access(DRM_COMMAND_BASE + DRM_PANTHOR_ ## __id, \ - struct drm_panthor_ ## __type) - -#define DRM_IOCTL_PANTHOR_DEV_QUERY \ - DRM_IOCTL_PANTHOR(WR, DEV_QUERY, dev_query) -#define DRM_IOCTL_PANTHOR_VM_CREATE \ - DRM_IOCTL_PANTHOR(WR, VM_CREATE, vm_create) -#define DRM_IOCTL_PANTHOR_VM_DESTROY \ - DRM_IOCTL_PANTHOR(WR, VM_DESTROY, vm_destroy) -#define DRM_IOCTL_PANTHOR_VM_BIND \ - DRM_IOCTL_PANTHOR(WR, VM_BIND, vm_bind) -#define DRM_IOCTL_PANTHOR_VM_GET_STATE \ - DRM_IOCTL_PANTHOR(WR, VM_GET_STATE, vm_get_state) -#define DRM_IOCTL_PANTHOR_BO_CREATE \ - DRM_IOCTL_PANTHOR(WR, BO_CREATE, bo_create) -#define DRM_IOCTL_PANTHOR_BO_MMAP_OFFSET \ - DRM_IOCTL_PANTHOR(WR, BO_MMAP_OFFSET, bo_mmap_offset) -#define DRM_IOCTL_PANTHOR_GROUP_CREATE \ - DRM_IOCTL_PANTHOR(WR, GROUP_CREATE, group_create) -#define DRM_IOCTL_PANTHOR_GROUP_DESTROY \ - DRM_IOCTL_PANTHOR(WR, GROUP_DESTROY, group_destroy) -#define DRM_IOCTL_PANTHOR_GROUP_SUBMIT \ - DRM_IOCTL_PANTHOR(WR, GROUP_SUBMIT, group_submit) -#define DRM_IOCTL_PANTHOR_GROUP_GET_STATE \ - DRM_IOCTL_PANTHOR(WR, GROUP_GET_STATE, group_get_state) -#define DRM_IOCTL_PANTHOR_TILER_HEAP_CREATE \ - DRM_IOCTL_PANTHOR(WR, TILER_HEAP_CREATE, tiler_heap_create) -#define DRM_IOCTL_PANTHOR_TILER_HEAP_DESTROY \ - DRM_IOCTL_PANTHOR(WR, TILER_HEAP_DESTROY, tiler_heap_destroy) - /** * DOC: IOCTL arguments */ @@ -1019,6 +977,50 @@ struct drm_panthor_tiler_heap_destroy { __u32 pad; }; +/** + * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number + * @__access: Access type. Must be R, W or RW. + * @__id: One of the DRM_PANTHOR_xxx id. + * @__type: Suffix of the type being passed to the IOCTL. + * + * Don't use this macro directly, use the DRM_IOCTL_PANTHOR_xxx + * values instead. + * + * Return: An IOCTL number to be passed to ioctl() from userspace. + */ +#define DRM_IOCTL_PANTHOR(__access, __id, __type) \ + DRM_IO ## __access(DRM_COMMAND_BASE + DRM_PANTHOR_ ## __id, \ + struct drm_panthor_ ## __type) + +enum { + DRM_IOCTL_PANTHOR_DEV_QUERY = + DRM_IOCTL_PANTHOR(WR, DEV_QUERY, dev_query), + DRM_IOCTL_PANTHOR_VM_CREATE = + DRM_IOCTL_PANTHOR(WR, VM_CREATE, vm_create), + DRM_IOCTL_PANTHOR_VM_DESTROY = + DRM_IOCTL_PANTHOR(WR, VM_DESTROY, vm_destroy), + DRM_IOCTL_PANTHOR_VM_BIND = + DRM_IOCTL_PANTHOR(WR, VM_BIND, vm_bind), + DRM_IOCTL_PANTHOR_VM_GET_STATE = + DRM_IOCTL_PANTHOR(WR, VM_GET_STATE, vm_get_state), + DRM_IOCTL_PANTHOR_BO_CREATE = + DRM_IOCTL_PANTHOR(WR, BO_CREATE, bo_create), + DRM_IOCTL_PANTHOR_BO_MMAP_OFFSET = + DRM_IOCTL_PANTHOR(WR, BO_MMAP_OFFSET, bo_mmap_offset), + DRM_IOCTL_PANTHOR_GROUP_CREATE = + DRM_IOCTL_PANTHOR(WR, GROUP_CREATE, group_create), + DRM_IOCTL_PANTHOR_GROUP_DESTROY = + DRM_IOCTL_PANTHOR(WR, GROUP_DESTROY, group_destroy), + DRM_IOCTL_PANTHOR_GROUP_SUBMIT = + DRM_IOCTL_PANTHOR(WR, GROUP_SUBMIT, group_submit), + DRM_IOCTL_PANTHOR_GROUP_GET_STATE = + DRM_IOCTL_PANTHOR(WR, GROUP_GET_STATE, group_get_state), + DRM_IOCTL_PANTHOR_TILER_HEAP_CREATE = + DRM_IOCTL_PANTHOR(WR, TILER_HEAP_CREATE, tiler_heap_create), + DRM_IOCTL_PANTHOR_TILER_HEAP_DESTROY = + DRM_IOCTL_PANTHOR(WR, TILER_HEAP_DESTROY, tiler_heap_destroy), +}; + #if defined(__cplusplus) } #endif -- cgit v1.2.3 From 66ac08bb7788a130f731614423a133c9c333c64e Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 6 Feb 2025 18:02:33 +0100 Subject: drm/panel: remove unnecessary forward declaration 'struct drm_device' is not used at all in this file since commit aa6c43644bc5 ("drm/panel: drop drm_device from drm_panel"). Signed-off-by: Luca Ceresoli Reviewed-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20250206-drm-cleanups-v1-1-93df60faa756@bootlin.com --- include/drm/drm_panel.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 10015891b056..a9c042c8dea1 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -33,7 +33,6 @@ struct backlight_device; struct dentry; struct device_node; struct drm_connector; -struct drm_device; struct drm_panel_follower; struct drm_panel; struct display_timing; -- cgit v1.2.3