diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-core.c | 293 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-core.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.c | 452 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.h | 349 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_lvds.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 89 |
11 files changed, 661 insertions, 698 deletions
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 292c31de18f1..b7e3f5dcf8d5 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -16,7 +16,9 @@ #include <sound/hdmi-codec.h> #include <drm/display/drm_dp_helper.h> +#include <drm/display/drm_hdmi_audio_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -25,9 +27,9 @@ #include "cdn-dp-core.h" #include "cdn-dp-reg.h" -static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector) +static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge) { - return container_of(connector, struct cdn_dp_device, connector); + return container_of(bridge, struct cdn_dp_device, bridge); } static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder) @@ -231,9 +233,9 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) } static enum drm_connector_status -cdn_dp_connector_detect(struct drm_connector *connector, bool force) +cdn_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) { - struct cdn_dp_device *dp = connector_to_dp(connector); + struct cdn_dp_device *dp = bridge_to_dp(bridge); enum drm_connector_status status = connector_status_disconnected; mutex_lock(&dp->lock); @@ -244,41 +246,25 @@ cdn_dp_connector_detect(struct drm_connector *connector, bool force) return status; } -static void cdn_dp_connector_destroy(struct drm_connector *connector) +static const struct drm_edid * +cdn_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector) { - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { - .detect = cdn_dp_connector_detect, - .destroy = cdn_dp_connector_destroy, - .fill_modes = drm_helper_probe_single_connector_modes, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int cdn_dp_connector_get_modes(struct drm_connector *connector) -{ - struct cdn_dp_device *dp = connector_to_dp(connector); - int ret = 0; + struct cdn_dp_device *dp = bridge_to_dp(bridge); + const struct drm_edid *drm_edid; mutex_lock(&dp->lock); - - ret = drm_edid_connector_add_modes(connector); - + drm_edid = drm_edid_read_custom(connector, cdn_dp_get_edid_block, dp); mutex_unlock(&dp->lock); - return ret; + return drm_edid; } static enum drm_mode_status -cdn_dp_connector_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode) +cdn_dp_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *display_info, + 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; + struct cdn_dp_device *dp = bridge_to_dp(bridge); u32 requested, actual, rate, sink_max, source_max = 0; u8 lanes, bpc; @@ -323,11 +309,6 @@ cdn_dp_connector_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = { - .get_modes = cdn_dp_connector_get_modes, - .mode_valid = cdn_dp_connector_mode_valid, -}; - static int cdn_dp_firmware_init(struct cdn_dp_device *dp) { int ret; @@ -360,7 +341,6 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp) static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) { - const struct drm_display_info *info = &dp->connector.display_info; int ret; if (!cdn_dp_check_sink_connection(dp)) @@ -373,17 +353,6 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) return ret; } - drm_edid_free(dp->drm_edid); - dp->drm_edid = drm_edid_read_custom(&dp->connector, - cdn_dp_get_edid_block, dp); - drm_edid_connector_update(&dp->connector, dp->drm_edid); - - dp->sink_has_audio = info->has_audio; - - if (dp->drm_edid) - DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", - info->width_mm / 10, info->height_mm / 10); - return 0; } @@ -488,10 +457,6 @@ static int cdn_dp_disable(struct cdn_dp_device *dp) dp->active = false; dp->max_lanes = 0; dp->max_rate = 0; - if (!dp->connected) { - drm_edid_free(dp->drm_edid); - dp->drm_edid = NULL; - } return 0; } @@ -546,26 +511,13 @@ err_clk_disable: return ret; } -static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted) +static void cdn_dp_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted) { - struct cdn_dp_device *dp = encoder_to_dp(encoder); - struct drm_display_info *display_info = &dp->connector.display_info; + struct cdn_dp_device *dp = bridge_to_dp(bridge); struct video_info *video = &dp->video_info; - switch (display_info->bpc) { - case 10: - video->color_depth = 10; - break; - case 6: - video->color_depth = 6; - break; - default: - video->color_depth = 8; - break; - } - video->color_fmt = PXL_RGB; video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); @@ -592,19 +544,37 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes)); } -static void cdn_dp_audio_handle_plugged_change(struct cdn_dp_device *dp, - bool plugged) +static void cdn_dp_display_info_update(struct cdn_dp_device *dp, + struct drm_display_info *display_info) { - if (dp->codec_dev) - dp->plugged_cb(dp->codec_dev, plugged); + struct video_info *video = &dp->video_info; + + switch (display_info->bpc) { + case 10: + video->color_depth = 10; + break; + case 6: + video->color_depth = 6; + break; + default: + video->color_depth = 8; + break; + } } -static void cdn_dp_encoder_enable(struct drm_encoder *encoder) +static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { - struct cdn_dp_device *dp = encoder_to_dp(encoder); + struct cdn_dp_device *dp = bridge_to_dp(bridge); + struct drm_connector *connector; int ret, val; - ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (!connector) + return; + + cdn_dp_display_info_update(dp, &connector->display_info); + + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.encoder); if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); return; @@ -625,7 +595,7 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) ret = cdn_dp_enable(dp); if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n", + DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n", ret); goto out; } @@ -655,24 +625,21 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - cdn_dp_audio_handle_plugged_change(dp, true); - out: mutex_unlock(&dp->lock); } -static void cdn_dp_encoder_disable(struct drm_encoder *encoder) +static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_atomic_state *state) { - struct cdn_dp_device *dp = encoder_to_dp(encoder); + struct cdn_dp_device *dp = bridge_to_dp(bridge); int ret; mutex_lock(&dp->lock); - cdn_dp_audio_handle_plugged_change(dp, false); if (dp->active) { ret = cdn_dp_disable(dp); if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n", + DRM_DEV_ERROR(dp->dev, "Failed to disable bridge %d\n", ret); } } @@ -704,9 +671,6 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, } static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { - .mode_set = cdn_dp_encoder_mode_set, - .enable = cdn_dp_encoder_enable, - .disable = cdn_dp_encoder_disable, .atomic_check = cdn_dp_encoder_atomic_check, }; @@ -779,11 +743,12 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp) return 0; } -static int cdn_dp_audio_hw_params(struct device *dev, void *data, - struct hdmi_codec_daifmt *daifmt, - struct hdmi_codec_params *params) +static int cdn_dp_audio_prepare(struct drm_bridge *bridge, + struct drm_connector *connector, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) { - struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct cdn_dp_device *dp = bridge_to_dp(bridge); struct audio_info audio = { .sample_width = params->sample_width, .sample_rate = params->sample_rate, @@ -805,7 +770,7 @@ static int cdn_dp_audio_hw_params(struct device *dev, void *data, audio.format = AFMT_SPDIF; break; default: - DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); + drm_err(bridge->dev, "Invalid format %d\n", daifmt->fmt); ret = -EINVAL; goto out; } @@ -819,9 +784,10 @@ out: return ret; } -static void cdn_dp_audio_shutdown(struct device *dev, void *data) +static void cdn_dp_audio_shutdown(struct drm_bridge *bridge, + struct drm_connector *connector) { - struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct cdn_dp_device *dp = bridge_to_dp(bridge); int ret; mutex_lock(&dp->lock); @@ -835,10 +801,11 @@ out: mutex_unlock(&dp->lock); } -static int cdn_dp_audio_mute_stream(struct device *dev, void *data, +static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge, + struct drm_connector *connector, bool enable, int direction) { - struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct cdn_dp_device *dp = bridge_to_dp(bridge); int ret; mutex_lock(&dp->lock); @@ -854,57 +821,22 @@ out: return ret; } -static int cdn_dp_audio_get_eld(struct device *dev, void *data, - u8 *buf, size_t len) -{ - struct cdn_dp_device *dp = dev_get_drvdata(dev); - - memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len)); - - return 0; -} - -static int cdn_dp_audio_hook_plugged_cb(struct device *dev, void *data, - hdmi_codec_plugged_cb fn, - struct device *codec_dev) -{ - struct cdn_dp_device *dp = dev_get_drvdata(dev); - - mutex_lock(&dp->lock); - dp->plugged_cb = fn; - dp->codec_dev = codec_dev; - cdn_dp_audio_handle_plugged_change(dp, dp->connected); - mutex_unlock(&dp->lock); - - return 0; -} - -static const struct hdmi_codec_ops audio_codec_ops = { - .hw_params = cdn_dp_audio_hw_params, - .audio_shutdown = cdn_dp_audio_shutdown, - .mute_stream = cdn_dp_audio_mute_stream, - .get_eld = cdn_dp_audio_get_eld, - .hook_plugged_cb = cdn_dp_audio_hook_plugged_cb, +static const struct drm_bridge_funcs cdn_dp_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .detect = cdn_dp_bridge_detect, + .edid_read = cdn_dp_bridge_edid_read, + .atomic_enable = cdn_dp_bridge_atomic_enable, + .atomic_disable = cdn_dp_bridge_atomic_disable, + .mode_valid = cdn_dp_bridge_mode_valid, + .mode_set = cdn_dp_bridge_mode_set, + + .dp_audio_prepare = cdn_dp_audio_prepare, + .dp_audio_mute_stream = cdn_dp_audio_mute_stream, + .dp_audio_shutdown = cdn_dp_audio_shutdown, }; -static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, - struct device *dev) -{ - struct hdmi_codec_pdata codec_data = { - .i2s = 1, - .spdif = 1, - .ops = &audio_codec_ops, - .max_i2s_channels = 8, - .no_capture_mute = 1, - }; - - dp->audio_pdev = platform_device_register_data( - dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, - &codec_data, sizeof(codec_data)); - - return PTR_ERR_OR_ZERO(dp->audio_pdev); -} - static int cdn_dp_request_firmware(struct cdn_dp_device *dp) { int ret; @@ -1006,7 +938,9 @@ static void cdn_dp_pd_event_work(struct work_struct *work) out: mutex_unlock(&dp->lock); - drm_connector_helper_hpd_irq_event(&dp->connector); + drm_bridge_hpd_notify(&dp->bridge, + dp->connected ? connector_status_connected + : connector_status_disconnected); } static int cdn_dp_pd_event(struct notifier_block *nb, @@ -1062,26 +996,35 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); - connector = &dp->connector; - connector->polled = DRM_CONNECTOR_POLL_HPD; - connector->dpms = DRM_MODE_DPMS_OFF; - - ret = drm_connector_init(drm_dev, connector, - &cdn_dp_atomic_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) { - DRM_ERROR("failed to initialize connector with drm\n"); - goto err_free_encoder; - } + dp->bridge.ops = + DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HPD | + DRM_BRIDGE_OP_DP_AUDIO; + dp->bridge.of_node = dp->dev->of_node; + dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; + dp->bridge.hdmi_audio_dev = dp->dev; + dp->bridge.hdmi_audio_max_i2s_playback_channels = 8; + dp->bridge.hdmi_audio_spdif_playback = 1; + dp->bridge.hdmi_audio_dai_port = -1; + + ret = devm_drm_bridge_add(dev, &dp->bridge); + if (ret) + return ret; - drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); + ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) { - DRM_ERROR("failed to attach connector and encoder\n"); - goto err_free_connector; + connector = drm_bridge_connector_init(drm_dev, encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + dev_err(dp->dev, "failed to init bridge connector: %d\n", ret); + return ret; } + drm_connector_attach_encoder(connector, encoder); + for (i = 0; i < dp->ports; i++) { port = dp->port[i]; @@ -1092,7 +1035,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) if (ret) { DRM_DEV_ERROR(dev, "register EXTCON_DISP_DP notifier err\n"); - goto err_free_connector; + return ret; } } @@ -1101,30 +1044,19 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) schedule_work(&dp->event_work); return 0; - -err_free_connector: - drm_connector_cleanup(connector); -err_free_encoder: - drm_encoder_cleanup(encoder); - return ret; } static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); struct drm_encoder *encoder = &dp->encoder.encoder; - struct drm_connector *connector = &dp->connector; cancel_work_sync(&dp->event_work); - cdn_dp_encoder_disable(encoder); encoder->funcs->destroy(encoder); - connector->funcs->destroy(connector); pm_runtime_disable(dev); if (dp->fw_loaded) release_firmware(dp->fw); - drm_edid_free(dp->drm_edid); - dp->drm_edid = NULL; } static const struct component_ops cdn_dp_component_ops = { @@ -1171,9 +1103,10 @@ static int cdn_dp_probe(struct platform_device *pdev) int ret; int i; - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); - if (!dp) - return -ENOMEM; + dp = devm_drm_bridge_alloc(dev, struct cdn_dp_device, bridge, + &cdn_dp_bridge_funcs); + if (IS_ERR(dp)) + return PTR_ERR(dp); dp->dev = dev; match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); @@ -1209,19 +1142,11 @@ static int cdn_dp_probe(struct platform_device *pdev) mutex_init(&dp->lock); dev_set_drvdata(dev, dp); - ret = cdn_dp_audio_codec_init(dp, dev); - if (ret) - return ret; - ret = component_add(dev, &cdn_dp_component_ops); if (ret) - goto err_audio_deinit; + return ret; return 0; - -err_audio_deinit: - platform_device_unregister(dp->audio_pdev); - return ret; } static void cdn_dp_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 17498f576ce7..e9c30b9fd543 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -8,6 +8,7 @@ #define _CDN_DP_CORE_H #include <drm/display/drm_dp_helper.h> +#include <drm/drm_bridge.h> #include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> #include <sound/hdmi-codec.h> @@ -65,12 +66,11 @@ struct cdn_dp_port { struct cdn_dp_device { struct device *dev; struct drm_device *drm_dev; - struct drm_connector connector; + struct drm_bridge bridge; struct rockchip_encoder encoder; struct drm_display_mode mode; struct platform_device *audio_pdev; struct work_struct event_work; - const struct drm_edid *drm_edid; struct mutex lock; bool connected; @@ -101,9 +101,5 @@ struct cdn_dp_device { int active_port; u8 dpcd[DP_RECEIVER_CAP_SIZE]; - bool sink_has_audio; - - hdmi_codec_plugged_cb plugged_cb; - struct device *codec_dev; }; #endif /* _CDN_DP_CORE_H */ diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index f737e7d46e66..acb59b25d928 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -213,17 +213,13 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) if (IS_ERR(hdmi->ref_clk)) { ret = PTR_ERR(hdmi->ref_clk); - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "failed to get reference clock\n"); - return ret; + return dev_err_probe(hdmi->dev, ret, "failed to get reference clock\n"); } hdmi->grf_clk = devm_clk_get_optional(hdmi->dev, "grf"); if (IS_ERR(hdmi->grf_clk)) { ret = PTR_ERR(hdmi->grf_clk); - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "failed to get grf clock\n"); - return ret; + return dev_err_probe(hdmi->dev, ret, "failed to get grf clock\n"); } ret = devm_regulator_get_enable(hdmi->dev, "avdd-0v9"); @@ -573,17 +569,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, ret = rockchip_hdmi_parse_dt(hdmi); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "Unable to parse OF data\n"); - return ret; + return dev_err_probe(hdmi->dev, ret, "Unable to parse OF data\n"); } hdmi->phy = devm_phy_optional_get(dev, "hdmi"); if (IS_ERR(hdmi->phy)) { ret = PTR_ERR(hdmi->phy); - if (ret != -EPROBE_DEFER) - dev_err(hdmi->dev, "failed to get phy\n"); - return ret; + return dev_err_probe(hdmi->dev, ret, "failed to get phy\n"); } if (hdmi->phy) { diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index db4b4038e51d..1ab3ad4bde9e 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,11 +29,360 @@ #include "rockchip_drm_drv.h" -#include "inno_hdmi.h" +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U -#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) +#define DDC_SEGMENT_ADDR 0x30 + +#define HDMI_SCL_RATE (100 * 1000) + +#define DDC_BUS_FREQ_L 0x4b +#define DDC_BUS_FREQ_H 0x4c + +#define HDMI_SYS_CTRL 0x00 +#define m_RST_ANALOG BIT(6) +#define v_RST_ANALOG (0 << 6) +#define v_NOT_RST_ANALOG BIT(6) +#define m_RST_DIGITAL BIT(5) +#define v_RST_DIGITAL (0 << 5) +#define v_NOT_RST_DIGITAL BIT(5) +#define m_REG_CLK_INV BIT(4) +#define v_REG_CLK_NOT_INV (0 << 4) +#define v_REG_CLK_INV BIT(4) +#define m_VCLK_INV BIT(3) +#define v_VCLK_NOT_INV (0 << 3) +#define v_VCLK_INV BIT(3) +#define m_REG_CLK_SOURCE BIT(2) +#define v_REG_CLK_SOURCE_TMDS (0 << 2) +#define v_REG_CLK_SOURCE_SYS BIT(2) +#define m_POWER BIT(1) +#define v_PWR_ON (0 << 1) +#define v_PWR_OFF BIT(1) +#define m_INT_POL BIT(0) +#define v_INT_POL_HIGH 1 +#define v_INT_POL_LOW 0 + +#define HDMI_VIDEO_CONTRL1 0x01 +#define m_VIDEO_INPUT_FORMAT (7 << 1) +#define m_DE_SOURCE BIT(0) +#define v_VIDEO_INPUT_FORMAT(n) ((n) << 1) +#define v_DE_EXTERNAL 1 +#define v_DE_INTERNAL 0 +enum { + VIDEO_INPUT_SDR_RGB444 = 0, + VIDEO_INPUT_DDR_RGB444 = 5, + VIDEO_INPUT_DDR_YCBCR422 = 6 +}; -#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U +#define HDMI_VIDEO_CONTRL2 0x02 +#define m_VIDEO_OUTPUT_COLOR (3 << 6) +#define m_VIDEO_INPUT_BITS (3 << 4) +#define m_VIDEO_INPUT_CSP BIT(0) +#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6) +#define v_VIDEO_INPUT_BITS(n) ((n) << 4) +#define v_VIDEO_INPUT_CSP(n) ((n) << 0) +enum { + VIDEO_INPUT_12BITS = 0, + VIDEO_INPUT_10BITS = 1, + VIDEO_INPUT_REVERT = 2, + VIDEO_INPUT_8BITS = 3, +}; + +#define HDMI_VIDEO_CONTRL 0x03 +#define m_VIDEO_AUTO_CSC BIT(7) +#define v_VIDEO_AUTO_CSC(n) ((n) << 7) +#define m_VIDEO_C0_C2_SWAP BIT(0) +#define v_VIDEO_C0_C2_SWAP(n) ((n) << 0) +enum { + C0_C2_CHANGE_ENABLE = 0, + C0_C2_CHANGE_DISABLE = 1, + AUTO_CSC_DISABLE = 0, + AUTO_CSC_ENABLE = 1, +}; + +#define HDMI_VIDEO_CONTRL3 0x04 +#define m_COLOR_DEPTH_NOT_INDICATED BIT(4) +#define m_SOF BIT(3) +#define m_COLOR_RANGE BIT(2) +#define m_CSC BIT(0) +#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4) +#define v_SOF_ENABLE (0 << 3) +#define v_SOF_DISABLE BIT(3) +#define v_COLOR_RANGE_FULL BIT(2) +#define v_COLOR_RANGE_LIMITED (0 << 2) +#define v_CSC_ENABLE 1 +#define v_CSC_DISABLE 0 + +#define HDMI_AV_MUTE 0x05 +#define m_AVMUTE_CLEAR BIT(7) +#define m_AVMUTE_ENABLE BIT(6) +#define m_AUDIO_MUTE BIT(1) +#define m_VIDEO_BLACK BIT(0) +#define v_AVMUTE_CLEAR(n) ((n) << 7) +#define v_AVMUTE_ENABLE(n) ((n) << 6) +#define v_AUDIO_MUTE(n) ((n) << 1) +#define v_VIDEO_MUTE(n) ((n) << 0) + +#define HDMI_VIDEO_TIMING_CTL 0x08 +#define v_HSYNC_POLARITY(n) ((n) << 3) +#define v_VSYNC_POLARITY(n) ((n) << 2) +#define v_INETLACE(n) ((n) << 1) +#define v_EXTERANL_VIDEO(n) ((n) << 0) + +#define HDMI_VIDEO_EXT_HTOTAL_L 0x09 +#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a +#define HDMI_VIDEO_EXT_HBLANK_L 0x0b +#define HDMI_VIDEO_EXT_HBLANK_H 0x0c +#define HDMI_VIDEO_EXT_HDELAY_L 0x0d +#define HDMI_VIDEO_EXT_HDELAY_H 0x0e +#define HDMI_VIDEO_EXT_HDURATION_L 0x0f +#define HDMI_VIDEO_EXT_HDURATION_H 0x10 +#define HDMI_VIDEO_EXT_VTOTAL_L 0x11 +#define HDMI_VIDEO_EXT_VTOTAL_H 0x12 +#define HDMI_VIDEO_EXT_VBLANK 0x13 +#define HDMI_VIDEO_EXT_VDELAY 0x14 +#define HDMI_VIDEO_EXT_VDURATION 0x15 + +#define HDMI_VIDEO_CSC_COEF 0x18 + +#define HDMI_AUDIO_CTRL1 0x35 +enum { + CTS_SOURCE_INTERNAL = 0, + CTS_SOURCE_EXTERNAL = 1, +}; + +#define v_CTS_SOURCE(n) ((n) << 7) + +enum { + DOWNSAMPLE_DISABLE = 0, + DOWNSAMPLE_1_2 = 1, + DOWNSAMPLE_1_4 = 2, +}; + +#define v_DOWN_SAMPLE(n) ((n) << 5) + +enum { + AUDIO_SOURCE_IIS = 0, + AUDIO_SOURCE_SPDIF = 1, +}; + +#define v_AUDIO_SOURCE(n) ((n) << 3) + +#define v_MCLK_ENABLE(n) ((n) << 2) + +enum { + MCLK_128FS = 0, + MCLK_256FS = 1, + MCLK_384FS = 2, + MCLK_512FS = 3, +}; + +#define v_MCLK_RATIO(n) (n) + +#define AUDIO_SAMPLE_RATE 0x37 + +enum { + AUDIO_32K = 0x3, + AUDIO_441K = 0x0, + AUDIO_48K = 0x2, + AUDIO_882K = 0x8, + AUDIO_96K = 0xa, + AUDIO_1764K = 0xc, + AUDIO_192K = 0xe, +}; + +#define AUDIO_I2S_MODE 0x38 + +enum { + I2S_CHANNEL_1_2 = 1, + I2S_CHANNEL_3_4 = 3, + I2S_CHANNEL_5_6 = 7, + I2S_CHANNEL_7_8 = 0xf +}; + +#define v_I2S_CHANNEL(n) ((n) << 2) + +enum { + I2S_STANDARD = 0, + I2S_LEFT_JUSTIFIED = 1, + I2S_RIGHT_JUSTIFIED = 2, +}; + +#define v_I2S_MODE(n) (n) + +#define AUDIO_I2S_MAP 0x39 +#define AUDIO_I2S_SWAPS_SPDIF 0x3a +#define v_SPIDF_FREQ(n) (n) + +#define N_32K 0x1000 +#define N_441K 0x1880 +#define N_882K 0x3100 +#define N_1764K 0x6200 +#define N_48K 0x1800 +#define N_96K 0x3000 +#define N_192K 0x6000 + +#define HDMI_AUDIO_CHANNEL_STATUS 0x3e +#define m_AUDIO_STATUS_NLPCM BIT(7) +#define m_AUDIO_STATUS_USE BIT(6) +#define m_AUDIO_STATUS_COPYRIGHT BIT(5) +#define m_AUDIO_STATUS_ADDITION (3 << 2) +#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0) +#define v_AUDIO_STATUS_NLPCM(n) (((n) & 1) << 7) +#define AUDIO_N_H 0x3f +#define AUDIO_N_M 0x40 +#define AUDIO_N_L 0x41 + +#define HDMI_AUDIO_CTS_H 0x45 +#define HDMI_AUDIO_CTS_M 0x46 +#define HDMI_AUDIO_CTS_L 0x47 + +#define HDMI_DDC_CLK_L 0x4b +#define HDMI_DDC_CLK_H 0x4c + +#define HDMI_EDID_SEGMENT_POINTER 0x4d +#define HDMI_EDID_WORD_ADDR 0x4e +#define HDMI_EDID_FIFO_OFFSET 0x4f +#define HDMI_EDID_FIFO_ADDR 0x50 + +#define HDMI_PACKET_SEND_MANUAL 0x9c +#define HDMI_PACKET_SEND_AUTO 0x9d +#define m_PACKET_GCP_EN BIT(7) +#define m_PACKET_MSI_EN BIT(6) +#define m_PACKET_SDI_EN BIT(5) +#define m_PACKET_VSI_EN BIT(4) +#define v_PACKET_GCP_EN(n) (((n) & 1) << 7) +#define v_PACKET_MSI_EN(n) (((n) & 1) << 6) +#define v_PACKET_SDI_EN(n) (((n) & 1) << 5) +#define v_PACKET_VSI_EN(n) (((n) & 1) << 4) + +#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f + +enum { + INFOFRAME_VSI = 0x05, + INFOFRAME_AVI = 0x06, + INFOFRAME_AAI = 0x08, +}; + +#define HDMI_CONTROL_PACKET_ADDR 0xa0 +#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11 + +enum { + AVI_COLOR_MODE_RGB = 0, + AVI_COLOR_MODE_YCBCR422 = 1, + AVI_COLOR_MODE_YCBCR444 = 2, + AVI_COLORIMETRY_NO_DATA = 0, + + AVI_COLORIMETRY_SMPTE_170M = 1, + AVI_COLORIMETRY_ITU709 = 2, + AVI_COLORIMETRY_EXTENDED = 3, + + AVI_CODED_FRAME_ASPECT_NO_DATA = 0, + AVI_CODED_FRAME_ASPECT_4_3 = 1, + AVI_CODED_FRAME_ASPECT_16_9 = 2, + + ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08, + ACTIVE_ASPECT_RATE_4_3 = 0x09, + ACTIVE_ASPECT_RATE_16_9 = 0x0A, + ACTIVE_ASPECT_RATE_14_9 = 0x0B, +}; + +#define HDMI_HDCP_CTRL 0x52 +#define m_HDMI_DVI BIT(1) +#define v_HDMI_DVI(n) ((n) << 1) + +#define HDMI_INTERRUPT_MASK1 0xc0 +#define HDMI_INTERRUPT_STATUS1 0xc1 +#define m_INT_ACTIVE_VSYNC BIT(5) +#define m_INT_EDID_READY BIT(2) + +#define HDMI_INTERRUPT_MASK2 0xc2 +#define HDMI_INTERRUPT_STATUS2 0xc3 +#define m_INT_HDCP_ERR BIT(7) +#define m_INT_BKSV_FLAG BIT(6) +#define m_INT_HDCP_OK BIT(4) + +#define HDMI_STATUS 0xc8 +#define m_HOTPLUG BIT(7) +#define m_MASK_INT_HOTPLUG BIT(5) +#define m_INT_HOTPLUG BIT(1) +#define v_MASK_INT_HOTPLUG(n) (((n) & 0x1) << 5) + +#define HDMI_COLORBAR 0xc9 + +#define HDMI_PHY_SYNC 0xce +#define HDMI_PHY_SYS_CTL 0xe0 +#define m_TMDS_CLK_SOURCE BIT(5) +#define v_TMDS_FROM_PLL (0 << 5) +#define v_TMDS_FROM_GEN BIT(5) +#define m_PHASE_CLK BIT(4) +#define v_DEFAULT_PHASE (0 << 4) +#define v_SYNC_PHASE BIT(4) +#define m_TMDS_CURRENT_PWR BIT(3) +#define v_TURN_ON_CURRENT (0 << 3) +#define v_CAT_OFF_CURRENT BIT(3) +#define m_BANDGAP_PWR BIT(2) +#define v_BANDGAP_PWR_UP (0 << 2) +#define v_BANDGAP_PWR_DOWN BIT(2) +#define m_PLL_PWR BIT(1) +#define v_PLL_PWR_UP (0 << 1) +#define v_PLL_PWR_DOWN BIT(1) +#define m_TMDS_CHG_PWR BIT(0) +#define v_TMDS_CHG_PWR_UP (0 << 0) +#define v_TMDS_CHG_PWR_DOWN BIT(0) + +#define HDMI_PHY_CHG_PWR 0xe1 +#define v_CLK_CHG_PWR(n) (((n) & 1) << 3) +#define v_DATA_CHG_PWR(n) (((n) & 7) << 0) + +#define HDMI_PHY_DRIVER 0xe2 +#define v_CLK_MAIN_DRIVER(n) ((n) << 4) +#define v_DATA_MAIN_DRIVER(n) ((n) << 0) + +#define HDMI_PHY_PRE_EMPHASIS 0xe3 +#define v_PRE_EMPHASIS(n) (((n) & 7) << 4) +#define v_CLK_PRE_DRIVER(n) (((n) & 3) << 2) +#define v_DATA_PRE_DRIVER(n) (((n) & 3) << 0) + +#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7 +#define v_FEEDBACK_DIV_LOW(n) ((n) & 0xff) +#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8 +#define v_FEEDBACK_DIV_HIGH(n) ((n) & 1) + +#define HDMI_PHY_PRE_DIV_RATIO 0xed +#define v_PRE_DIV_RATIO(n) ((n) & 0x1f) + +#define HDMI_CEC_CTRL 0xd0 +#define m_ADJUST_FOR_HISENSE BIT(6) +#define m_REJECT_RX_BROADCAST BIT(5) +#define m_BUSFREETIME_ENABLE BIT(2) +#define m_REJECT_RX BIT(1) +#define m_START_TX BIT(0) + +#define HDMI_CEC_DATA 0xd1 +#define HDMI_CEC_TX_OFFSET 0xd2 +#define HDMI_CEC_RX_OFFSET 0xd3 +#define HDMI_CEC_CLK_H 0xd4 +#define HDMI_CEC_CLK_L 0xd5 +#define HDMI_CEC_TX_LENGTH 0xd6 +#define HDMI_CEC_RX_LENGTH 0xd7 +#define HDMI_CEC_TX_INT_MASK 0xd8 +#define m_TX_DONE BIT(3) +#define m_TX_NOACK BIT(2) +#define m_TX_BROADCAST_REJ BIT(1) +#define m_TX_BUSNOTFREE BIT(0) + +#define HDMI_CEC_RX_INT_MASK 0xd9 +#define m_RX_LA_ERR BIT(4) +#define m_RX_GLITCH BIT(3) +#define m_RX_DONE BIT(0) + +#define HDMI_CEC_TX_INT 0xda +#define HDMI_CEC_RX_INT 0xdb +#define HDMI_CEC_BUSFREETIME_L 0xdc +#define HDMI_CEC_BUSFREETIME_H 0xdd +#define HDMI_CEC_LOGICADDR 0xde + +#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) #define RK3036_GRF_SOC_CON2 0x148 #define RK3036_HDMI_PHSYNC BIT(4) @@ -255,22 +604,37 @@ static void inno_hdmi_power_up(struct inno_hdmi *hdmi, inno_hdmi_sys_power(hdmi, true); }; -static void inno_hdmi_reset(struct inno_hdmi *hdmi) +static void inno_hdmi_init_hw(struct inno_hdmi *hdmi) { u32 val; u32 msk; hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL); - udelay(100); + usleep_range(100, 150); hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG); - udelay(100); + usleep_range(100, 150); msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL; val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); inno_hdmi_standby(hdmi); + + /* + * When the controller isn't configured to an accurate + * video timing and there is no reference clock available, + * then the TMDS clock source would be switched to PCLK_HDMI, + * so we need to init the TMDS rate to PCLK rate, and + * reconfigure the DDC clock. + */ + if (hdmi->refclk) + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk)); + else + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); + + /* Unmute hotplug interrupt */ + hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1)); } static int inno_hdmi_disable_frame(struct drm_connector *connector, @@ -775,8 +1139,7 @@ static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs) * we assume that each word write to this i2c adapter * should be the offset of EDID word address. */ - if ((msgs->len != 1) || - ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR))) + if (msgs->len != 1 || (msgs->addr != DDC_ADDR && msgs->addr != DDC_SEGMENT_ADDR)) return -EINVAL; reinit_completion(&hdmi->i2c->cmp); @@ -867,10 +1230,9 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) strscpy(adap->name, "Inno HDMI", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); - ret = i2c_add_adapter(adap); + ret = devm_i2c_add_adapter(hdmi->dev, adap); if (ret) { dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); - devm_kfree(hdmi->dev, i2c); return ERR_PTR(ret); } @@ -907,71 +1269,37 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); - hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); + hdmi->pclk = devm_clk_get_enabled(hdmi->dev, "pclk"); if (IS_ERR(hdmi->pclk)) return dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n"); - ret = clk_prepare_enable(hdmi->pclk); - if (ret) - return dev_err_probe(dev, ret, "Cannot enable HDMI pclk: %d\n", ret); - - hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); - if (IS_ERR(hdmi->refclk)) { - ret = dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n"); - goto err_disable_pclk; - } - - ret = clk_prepare_enable(hdmi->refclk); - if (ret) { - ret = dev_err_probe(dev, ret, "Cannot enable HDMI refclk: %d\n", ret); - goto err_disable_pclk; - } + hdmi->refclk = devm_clk_get_optional_enabled(hdmi->dev, "ref"); + if (IS_ERR(hdmi->refclk)) + return dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n"); if (hdmi->variant->dev_type == RK3036_HDMI) { hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); - if (IS_ERR(hdmi->grf)) { - ret = dev_err_probe(dev, PTR_ERR(hdmi->grf), - "Unable to get rockchip,grf\n"); - goto err_disable_clk; - } + if (IS_ERR(hdmi->grf)) + return dev_err_probe(dev, + PTR_ERR(hdmi->grf), "Unable to get rockchip,grf\n"); } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; - inno_hdmi_reset(hdmi); + inno_hdmi_init_hw(hdmi); hdmi->ddc = inno_hdmi_i2c_adapter(hdmi); - if (IS_ERR(hdmi->ddc)) { - ret = PTR_ERR(hdmi->ddc); - hdmi->ddc = NULL; - goto err_disable_clk; - } - - /* - * When the controller isn't configured to an accurate - * video timing and there is no reference clock available, - * then the TMDS clock source would be switched to PCLK_HDMI, - * so we need to init the TMDS rate to PCLK rate, and - * reconfigure the DDC clock. - */ - if (hdmi->refclk) - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk)); - else - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); + if (IS_ERR(hdmi->ddc)) + return PTR_ERR(hdmi->ddc); ret = inno_hdmi_register(drm, hdmi); if (ret) - goto err_put_adapter; + return ret; dev_set_drvdata(dev, hdmi); - /* Unmute hotplug interrupt */ - hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1)); - ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq, inno_hdmi_irq, IRQF_SHARED, dev_name(dev), hdmi); @@ -982,12 +1310,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, err_cleanup_hdmi: hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); -err_put_adapter: - i2c_put_adapter(hdmi->ddc); -err_disable_clk: - clk_disable_unprepare(hdmi->refclk); -err_disable_pclk: - clk_disable_unprepare(hdmi->pclk); return ret; } @@ -998,10 +1320,6 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); - - i2c_put_adapter(hdmi->ddc); - clk_disable_unprepare(hdmi->refclk); - clk_disable_unprepare(hdmi->pclk); } static const struct component_ops inno_hdmi_ops = { diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h deleted file mode 100644 index 8b7ef3fac485..000000000000 --- a/drivers/gpu/drm/rockchip/inno_hdmi.h +++ /dev/null @@ -1,349 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) Rockchip Electronics Co., Ltd. - * Zheng Yang <zhengyang@rock-chips.com> - * Yakir Yang <ykk@rock-chips.com> - */ - -#ifndef __INNO_HDMI_H__ -#define __INNO_HDMI_H__ - -#define DDC_SEGMENT_ADDR 0x30 - -#define HDMI_SCL_RATE (100*1000) -#define DDC_BUS_FREQ_L 0x4b -#define DDC_BUS_FREQ_H 0x4c - -#define HDMI_SYS_CTRL 0x00 -#define m_RST_ANALOG (1 << 6) -#define v_RST_ANALOG (0 << 6) -#define v_NOT_RST_ANALOG (1 << 6) -#define m_RST_DIGITAL (1 << 5) -#define v_RST_DIGITAL (0 << 5) -#define v_NOT_RST_DIGITAL (1 << 5) -#define m_REG_CLK_INV (1 << 4) -#define v_REG_CLK_NOT_INV (0 << 4) -#define v_REG_CLK_INV (1 << 4) -#define m_VCLK_INV (1 << 3) -#define v_VCLK_NOT_INV (0 << 3) -#define v_VCLK_INV (1 << 3) -#define m_REG_CLK_SOURCE (1 << 2) -#define v_REG_CLK_SOURCE_TMDS (0 << 2) -#define v_REG_CLK_SOURCE_SYS (1 << 2) -#define m_POWER (1 << 1) -#define v_PWR_ON (0 << 1) -#define v_PWR_OFF (1 << 1) -#define m_INT_POL (1 << 0) -#define v_INT_POL_HIGH 1 -#define v_INT_POL_LOW 0 - -#define HDMI_VIDEO_CONTRL1 0x01 -#define m_VIDEO_INPUT_FORMAT (7 << 1) -#define m_DE_SOURCE (1 << 0) -#define v_VIDEO_INPUT_FORMAT(n) (n << 1) -#define v_DE_EXTERNAL 1 -#define v_DE_INTERNAL 0 -enum { - VIDEO_INPUT_SDR_RGB444 = 0, - VIDEO_INPUT_DDR_RGB444 = 5, - VIDEO_INPUT_DDR_YCBCR422 = 6 -}; - -#define HDMI_VIDEO_CONTRL2 0x02 -#define m_VIDEO_OUTPUT_COLOR (3 << 6) -#define m_VIDEO_INPUT_BITS (3 << 4) -#define m_VIDEO_INPUT_CSP (1 << 0) -#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6) -#define v_VIDEO_INPUT_BITS(n) (n << 4) -#define v_VIDEO_INPUT_CSP(n) (n << 0) -enum { - VIDEO_INPUT_12BITS = 0, - VIDEO_INPUT_10BITS = 1, - VIDEO_INPUT_REVERT = 2, - VIDEO_INPUT_8BITS = 3, -}; - -#define HDMI_VIDEO_CONTRL 0x03 -#define m_VIDEO_AUTO_CSC (1 << 7) -#define v_VIDEO_AUTO_CSC(n) (n << 7) -#define m_VIDEO_C0_C2_SWAP (1 << 0) -#define v_VIDEO_C0_C2_SWAP(n) (n << 0) -enum { - C0_C2_CHANGE_ENABLE = 0, - C0_C2_CHANGE_DISABLE = 1, - AUTO_CSC_DISABLE = 0, - AUTO_CSC_ENABLE = 1, -}; - -#define HDMI_VIDEO_CONTRL3 0x04 -#define m_COLOR_DEPTH_NOT_INDICATED (1 << 4) -#define m_SOF (1 << 3) -#define m_COLOR_RANGE (1 << 2) -#define m_CSC (1 << 0) -#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4) -#define v_SOF_ENABLE (0 << 3) -#define v_SOF_DISABLE (1 << 3) -#define v_COLOR_RANGE_FULL (1 << 2) -#define v_COLOR_RANGE_LIMITED (0 << 2) -#define v_CSC_ENABLE 1 -#define v_CSC_DISABLE 0 - -#define HDMI_AV_MUTE 0x05 -#define m_AVMUTE_CLEAR (1 << 7) -#define m_AVMUTE_ENABLE (1 << 6) -#define m_AUDIO_MUTE (1 << 1) -#define m_VIDEO_BLACK (1 << 0) -#define v_AVMUTE_CLEAR(n) (n << 7) -#define v_AVMUTE_ENABLE(n) (n << 6) -#define v_AUDIO_MUTE(n) (n << 1) -#define v_VIDEO_MUTE(n) (n << 0) - -#define HDMI_VIDEO_TIMING_CTL 0x08 -#define v_HSYNC_POLARITY(n) (n << 3) -#define v_VSYNC_POLARITY(n) (n << 2) -#define v_INETLACE(n) (n << 1) -#define v_EXTERANL_VIDEO(n) (n << 0) - -#define HDMI_VIDEO_EXT_HTOTAL_L 0x09 -#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a -#define HDMI_VIDEO_EXT_HBLANK_L 0x0b -#define HDMI_VIDEO_EXT_HBLANK_H 0x0c -#define HDMI_VIDEO_EXT_HDELAY_L 0x0d -#define HDMI_VIDEO_EXT_HDELAY_H 0x0e -#define HDMI_VIDEO_EXT_HDURATION_L 0x0f -#define HDMI_VIDEO_EXT_HDURATION_H 0x10 -#define HDMI_VIDEO_EXT_VTOTAL_L 0x11 -#define HDMI_VIDEO_EXT_VTOTAL_H 0x12 -#define HDMI_VIDEO_EXT_VBLANK 0x13 -#define HDMI_VIDEO_EXT_VDELAY 0x14 -#define HDMI_VIDEO_EXT_VDURATION 0x15 - -#define HDMI_VIDEO_CSC_COEF 0x18 - -#define HDMI_AUDIO_CTRL1 0x35 -enum { - CTS_SOURCE_INTERNAL = 0, - CTS_SOURCE_EXTERNAL = 1, -}; -#define v_CTS_SOURCE(n) (n << 7) - -enum { - DOWNSAMPLE_DISABLE = 0, - DOWNSAMPLE_1_2 = 1, - DOWNSAMPLE_1_4 = 2, -}; -#define v_DOWN_SAMPLE(n) (n << 5) - -enum { - AUDIO_SOURCE_IIS = 0, - AUDIO_SOURCE_SPDIF = 1, -}; -#define v_AUDIO_SOURCE(n) (n << 3) - -#define v_MCLK_ENABLE(n) (n << 2) -enum { - MCLK_128FS = 0, - MCLK_256FS = 1, - MCLK_384FS = 2, - MCLK_512FS = 3, -}; -#define v_MCLK_RATIO(n) (n) - -#define AUDIO_SAMPLE_RATE 0x37 -enum { - AUDIO_32K = 0x3, - AUDIO_441K = 0x0, - AUDIO_48K = 0x2, - AUDIO_882K = 0x8, - AUDIO_96K = 0xa, - AUDIO_1764K = 0xc, - AUDIO_192K = 0xe, -}; - -#define AUDIO_I2S_MODE 0x38 -enum { - I2S_CHANNEL_1_2 = 1, - I2S_CHANNEL_3_4 = 3, - I2S_CHANNEL_5_6 = 7, - I2S_CHANNEL_7_8 = 0xf -}; -#define v_I2S_CHANNEL(n) ((n) << 2) -enum { - I2S_STANDARD = 0, - I2S_LEFT_JUSTIFIED = 1, - I2S_RIGHT_JUSTIFIED = 2, -}; -#define v_I2S_MODE(n) (n) - -#define AUDIO_I2S_MAP 0x39 -#define AUDIO_I2S_SWAPS_SPDIF 0x3a -#define v_SPIDF_FREQ(n) (n) - -#define N_32K 0x1000 -#define N_441K 0x1880 -#define N_882K 0x3100 -#define N_1764K 0x6200 -#define N_48K 0x1800 -#define N_96K 0x3000 -#define N_192K 0x6000 - -#define HDMI_AUDIO_CHANNEL_STATUS 0x3e -#define m_AUDIO_STATUS_NLPCM (1 << 7) -#define m_AUDIO_STATUS_USE (1 << 6) -#define m_AUDIO_STATUS_COPYRIGHT (1 << 5) -#define m_AUDIO_STATUS_ADDITION (3 << 2) -#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0) -#define v_AUDIO_STATUS_NLPCM(n) ((n & 1) << 7) -#define AUDIO_N_H 0x3f -#define AUDIO_N_M 0x40 -#define AUDIO_N_L 0x41 - -#define HDMI_AUDIO_CTS_H 0x45 -#define HDMI_AUDIO_CTS_M 0x46 -#define HDMI_AUDIO_CTS_L 0x47 - -#define HDMI_DDC_CLK_L 0x4b -#define HDMI_DDC_CLK_H 0x4c - -#define HDMI_EDID_SEGMENT_POINTER 0x4d -#define HDMI_EDID_WORD_ADDR 0x4e -#define HDMI_EDID_FIFO_OFFSET 0x4f -#define HDMI_EDID_FIFO_ADDR 0x50 - -#define HDMI_PACKET_SEND_MANUAL 0x9c -#define HDMI_PACKET_SEND_AUTO 0x9d -#define m_PACKET_GCP_EN (1 << 7) -#define m_PACKET_MSI_EN (1 << 6) -#define m_PACKET_SDI_EN (1 << 5) -#define m_PACKET_VSI_EN (1 << 4) -#define v_PACKET_GCP_EN(n) ((n & 1) << 7) -#define v_PACKET_MSI_EN(n) ((n & 1) << 6) -#define v_PACKET_SDI_EN(n) ((n & 1) << 5) -#define v_PACKET_VSI_EN(n) ((n & 1) << 4) - -#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f -enum { - INFOFRAME_VSI = 0x05, - INFOFRAME_AVI = 0x06, - INFOFRAME_AAI = 0x08, -}; - -#define HDMI_CONTROL_PACKET_ADDR 0xa0 -#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11 -enum { - AVI_COLOR_MODE_RGB = 0, - AVI_COLOR_MODE_YCBCR422 = 1, - AVI_COLOR_MODE_YCBCR444 = 2, - AVI_COLORIMETRY_NO_DATA = 0, - - AVI_COLORIMETRY_SMPTE_170M = 1, - AVI_COLORIMETRY_ITU709 = 2, - AVI_COLORIMETRY_EXTENDED = 3, - - AVI_CODED_FRAME_ASPECT_NO_DATA = 0, - AVI_CODED_FRAME_ASPECT_4_3 = 1, - AVI_CODED_FRAME_ASPECT_16_9 = 2, - - ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08, - ACTIVE_ASPECT_RATE_4_3 = 0x09, - ACTIVE_ASPECT_RATE_16_9 = 0x0A, - ACTIVE_ASPECT_RATE_14_9 = 0x0B, -}; - -#define HDMI_HDCP_CTRL 0x52 -#define m_HDMI_DVI (1 << 1) -#define v_HDMI_DVI(n) (n << 1) - -#define HDMI_INTERRUPT_MASK1 0xc0 -#define HDMI_INTERRUPT_STATUS1 0xc1 -#define m_INT_ACTIVE_VSYNC (1 << 5) -#define m_INT_EDID_READY (1 << 2) - -#define HDMI_INTERRUPT_MASK2 0xc2 -#define HDMI_INTERRUPT_STATUS2 0xc3 -#define m_INT_HDCP_ERR (1 << 7) -#define m_INT_BKSV_FLAG (1 << 6) -#define m_INT_HDCP_OK (1 << 4) - -#define HDMI_STATUS 0xc8 -#define m_HOTPLUG (1 << 7) -#define m_MASK_INT_HOTPLUG (1 << 5) -#define m_INT_HOTPLUG (1 << 1) -#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5) - -#define HDMI_COLORBAR 0xc9 - -#define HDMI_PHY_SYNC 0xce -#define HDMI_PHY_SYS_CTL 0xe0 -#define m_TMDS_CLK_SOURCE (1 << 5) -#define v_TMDS_FROM_PLL (0 << 5) -#define v_TMDS_FROM_GEN (1 << 5) -#define m_PHASE_CLK (1 << 4) -#define v_DEFAULT_PHASE (0 << 4) -#define v_SYNC_PHASE (1 << 4) -#define m_TMDS_CURRENT_PWR (1 << 3) -#define v_TURN_ON_CURRENT (0 << 3) -#define v_CAT_OFF_CURRENT (1 << 3) -#define m_BANDGAP_PWR (1 << 2) -#define v_BANDGAP_PWR_UP (0 << 2) -#define v_BANDGAP_PWR_DOWN (1 << 2) -#define m_PLL_PWR (1 << 1) -#define v_PLL_PWR_UP (0 << 1) -#define v_PLL_PWR_DOWN (1 << 1) -#define m_TMDS_CHG_PWR (1 << 0) -#define v_TMDS_CHG_PWR_UP (0 << 0) -#define v_TMDS_CHG_PWR_DOWN (1 << 0) - -#define HDMI_PHY_CHG_PWR 0xe1 -#define v_CLK_CHG_PWR(n) ((n & 1) << 3) -#define v_DATA_CHG_PWR(n) ((n & 7) << 0) - -#define HDMI_PHY_DRIVER 0xe2 -#define v_CLK_MAIN_DRIVER(n) (n << 4) -#define v_DATA_MAIN_DRIVER(n) (n << 0) - -#define HDMI_PHY_PRE_EMPHASIS 0xe3 -#define v_PRE_EMPHASIS(n) ((n & 7) << 4) -#define v_CLK_PRE_DRIVER(n) ((n & 3) << 2) -#define v_DATA_PRE_DRIVER(n) ((n & 3) << 0) - -#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7 -#define v_FEEDBACK_DIV_LOW(n) (n & 0xff) -#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8 -#define v_FEEDBACK_DIV_HIGH(n) (n & 1) - -#define HDMI_PHY_PRE_DIV_RATIO 0xed -#define v_PRE_DIV_RATIO(n) (n & 0x1f) - -#define HDMI_CEC_CTRL 0xd0 -#define m_ADJUST_FOR_HISENSE (1 << 6) -#define m_REJECT_RX_BROADCAST (1 << 5) -#define m_BUSFREETIME_ENABLE (1 << 2) -#define m_REJECT_RX (1 << 1) -#define m_START_TX (1 << 0) - -#define HDMI_CEC_DATA 0xd1 -#define HDMI_CEC_TX_OFFSET 0xd2 -#define HDMI_CEC_RX_OFFSET 0xd3 -#define HDMI_CEC_CLK_H 0xd4 -#define HDMI_CEC_CLK_L 0xd5 -#define HDMI_CEC_TX_LENGTH 0xd6 -#define HDMI_CEC_RX_LENGTH 0xd7 -#define HDMI_CEC_TX_INT_MASK 0xd8 -#define m_TX_DONE (1 << 3) -#define m_TX_NOACK (1 << 2) -#define m_TX_BROADCAST_REJ (1 << 1) -#define m_TX_BUSNOTFREE (1 << 0) - -#define HDMI_CEC_RX_INT_MASK 0xd9 -#define m_RX_LA_ERR (1 << 4) -#define m_RX_GLITCH (1 << 3) -#define m_RX_DONE (1 << 0) - -#define HDMI_CEC_TX_INT 0xda -#define HDMI_CEC_RX_INT 0xdb -#define HDMI_CEC_BUSFREETIME_L 0xdc -#define HDMI_CEC_BUSFREETIME_H 0xdd -#define HDMI_CEC_LOGICADDR 0xde - -#endif /* __INNO_HDMI_H__ */ diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index e7875b52f298..ae4a5ac2299a 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -450,7 +450,7 @@ struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = { }; static enum drm_connector_status -rk3066_hdmi_bridge_detect(struct drm_bridge *bridge) +rk3066_hdmi_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) { struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index dcc1f07632c3..2f469d370021 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -30,21 +30,18 @@ static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = static struct drm_framebuffer * rockchip_fb_create(struct drm_device *dev, struct drm_file *file, + const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_afbc_framebuffer *afbc_fb; - const struct drm_format_info *info; int ret; - info = drm_get_format_info(dev, mode_cmd); - if (!info) - return ERR_PTR(-ENOMEM); - afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); if (!afbc_fb) return ERR_PTR(-ENOMEM); - ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, + ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, + file, info, mode_cmd, &rockchip_drm_fb_funcs); if (ret) { kfree(afbc_fb); @@ -52,16 +49,9 @@ rockchip_fb_create(struct drm_device *dev, struct drm_file *file, } if (drm_is_afbc(mode_cmd->modifier[0])) { - int ret, i; - - ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); + ret = drm_gem_fb_afbc_init(dev, info, mode_cmd, afbc_fb); if (ret) { - struct drm_gem_object **obj = afbc_fb->base.obj; - - for (i = 0; i < info->num_planes; ++i) - drm_gem_object_put(obj[i]); - - kfree(afbc_fb); + drm_framebuffer_put(&afbc_fb->base); return ERR_PTR(ret); } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index d0f5fea15e21..186f6452a7d3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -146,25 +146,6 @@ static void vop2_unlock(struct vop2 *vop2) mutex_unlock(&vop2->vop2_lock); } -/* - * Note: - * The write mask function is documented but missing on rk3566/8, writes - * to these bits have no effect. For newer soc(rk3588 and following) the - * write mask is needed for register writes. - * - * GLB_CFG_DONE_EN has no write mask bit. - * - */ -static void vop2_cfg_done(struct vop2_video_port *vp) -{ - struct vop2 *vop2 = vp->vop2; - u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN; - - val |= BIT(vp->id) | (BIT(vp->id) << 16); - - regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val); -} - static void vop2_win_disable(struct vop2_win *win) { vop2_win_write(win, VOP2_WIN_ENABLE, 0); @@ -854,6 +835,11 @@ static void vop2_enable(struct vop2 *vop2) if (vop2->version == VOP_VERSION_RK3588) rk3588_vop2_power_domain_enable_all(vop2); + if (vop2->version <= VOP_VERSION_RK3588) { + vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL); + } + vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); /* @@ -2422,6 +2408,10 @@ static int vop2_create_crtcs(struct vop2 *vop2) break; } } + + if (!vp->primary_plane) + return dev_err_probe(drm->dev, -ENOENT, + "no primary plane for vp %d\n", i); } /* Register all unused window as overlay plane */ @@ -2724,6 +2714,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n"); mutex_init(&vop2->vop2_lock); + mutex_init(&vop2->ovl_lock); ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); if (ret) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index fc3ecb9fcd95..fa5c56f16047 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -334,6 +334,19 @@ struct vop2 { /* optional internal rgb encoder */ struct rockchip_rgb *rgb; + /* + * Used to record layer selection configuration on rk356x/rk3588 + * as register RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are + * shared for all the Video Ports. + */ + u32 old_layer_sel; + u32 old_port_sel; + /* + * Ensure that the updates to these two registers(RKK3568_OVL_LAYER_SEL/RK3568_OVL_PORT_SEL) + * take effect in sequence. + */ + struct mutex ovl_lock; + /* must be put at the end of the struct */ struct vop2_win win[]; }; @@ -727,6 +740,7 @@ enum dst_factor_mode { #define RK3588_OVL_PORT_SEL__CLUSTER2 GENMASK(21, 20) #define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18) #define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16) +#define RK3588_OVL_PORT_SET__PORT3_MUX GENMASK(15, 12) #define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8) #define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4) #define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0) @@ -831,4 +845,23 @@ static inline struct vop2_win *to_vop2_win(struct drm_plane *p) return container_of(p, struct vop2_win, base); } +/* + * Note: + * The write mask function is documented but missing on rk3566/8, writes + * to these bits have no effect. For newer soc(rk3588 and following) the + * write mask is needed for register writes. + * + * GLB_CFG_DONE_EN has no write mask bit. + * + */ +static inline void vop2_cfg_done(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN; + + val |= BIT(vp->id) | (BIT(vp->id) << 16); + + regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val); +} + #endif /* _ROCKCHIP_DRM_VOP2_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index a673779de3d2..2411260db51d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -56,14 +56,13 @@ struct rockchip_lvds { struct drm_device *drm_dev; struct drm_panel *panel; struct drm_bridge *bridge; - struct drm_connector connector; struct rockchip_encoder encoder; struct dev_pin_info *pins; }; -static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *connector) +static inline struct rockchip_lvds *brige_to_lvds(struct drm_bridge *bridge) { - return container_of(connector, struct rockchip_lvds, connector); + return (struct rockchip_lvds *)bridge->driver_private; } static inline struct rockchip_lvds *encoder_to_lvds(struct drm_encoder *encoder) @@ -106,25 +105,21 @@ static inline int rockchip_lvds_name_to_output(const char *s) return -EINVAL; } -static const struct drm_connector_funcs rockchip_lvds_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int rockchip_lvds_connector_get_modes(struct drm_connector *connector) +static int +rockchip_lvds_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector) { - struct rockchip_lvds *lvds = connector_to_lvds(connector); + struct rockchip_lvds *lvds = brige_to_lvds(bridge); struct drm_panel *panel = lvds->panel; return drm_panel_get_modes(panel, connector); } static const -struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = { - .get_modes = rockchip_lvds_connector_get_modes, +struct drm_bridge_funcs rockchip_lvds_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .get_modes = rockchip_lvds_bridge_get_modes, }; static int @@ -606,26 +601,23 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, } drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs); - connector = &lvds->connector; if (lvds->panel) { - connector->dpms = DRM_MODE_DPMS_OFF; - ret = drm_connector_init(drm_dev, connector, - &rockchip_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); - if (ret < 0) { - drm_err(drm_dev, - "failed to initialize connector: %d\n", ret); + lvds->bridge = drm_panel_bridge_add_typed(lvds->panel, DRM_MODE_CONNECTOR_LVDS); + if (IS_ERR(lvds->bridge)) { + ret = PTR_ERR(lvds->bridge); goto err_free_encoder; } + } - drm_connector_helper_add(connector, - &rockchip_lvds_connector_helper_funcs); - } else { - ret = drm_bridge_attach(encoder, lvds->bridge, NULL, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (lvds->bridge) { + lvds->bridge->driver_private = lvds; + lvds->bridge->ops = DRM_BRIDGE_OP_MODES; + lvds->bridge->funcs = &rockchip_lvds_bridge_funcs; + + ret = drm_bridge_attach(encoder, lvds->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) - goto err_free_encoder; + goto err_free_bridge; connector = drm_bridge_connector_init(lvds->drm_dev, encoder); if (IS_ERR(connector)) { @@ -633,14 +625,14 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, "failed to initialize bridge connector: %pe\n", connector); ret = PTR_ERR(connector); - goto err_free_encoder; + goto err_free_bridge; } - } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - drm_err(drm_dev, "failed to attach encoder: %d\n", ret); - goto err_free_connector; + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) { + drm_err(drm_dev, "failed to attach encoder: %d\n", ret); + goto err_free_bridge; + } } pm_runtime_enable(dev); @@ -649,8 +641,8 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, return 0; -err_free_connector: - drm_connector_cleanup(connector); +err_free_bridge: + drm_panel_bridge_remove(lvds->bridge); err_free_encoder: drm_encoder_cleanup(encoder); err_put_remote: @@ -670,8 +662,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, encoder_funcs = lvds->soc_data->helper_funcs; encoder_funcs->disable(&lvds->encoder.encoder); pm_runtime_disable(dev); - drm_connector_cleanup(&lvds->connector); - drm_encoder_cleanup(&lvds->encoder.encoder); } static const struct component_ops rockchip_lvds_component_ops = { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 32c4ed685739..45c5e3987813 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2052,12 +2052,55 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) } } +static u32 rk3568_vop2_read_port_mux(struct vop2 *vop2) +{ + return vop2_readl(vop2, RK3568_OVL_PORT_SEL); +} + +static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2) +{ + u32 port_mux_sel; + int ret; + + /* + * Spin until the previous port_mux figuration is done. + */ + ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel, + port_mux_sel == vop2->old_port_sel, 0, 50 * 1000); + if (ret) + DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n", + port_mux_sel, vop2->old_port_sel); +} + +static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2) +{ + return vop2_readl(vop2, RK3568_OVL_LAYER_SEL); +} + +static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg) +{ + u32 atv_layer_cfg; + int ret; + + /* + * Spin until the previous layer configuration is done. + */ + ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg, + atv_layer_cfg == cfg, 0, 50 * 1000); + if (ret) + DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n", + atv_layer_cfg, cfg); +} + static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) { struct vop2 *vop2 = vp->vop2; struct drm_plane *plane; u32 layer_sel = 0; u32 port_sel; + u32 old_layer_sel = 0; + u32 atv_layer_sel = 0; + u32 old_port_sel = 0; u8 layer_id; u8 old_layer_id; u8 layer_sel_id; @@ -2069,19 +2112,18 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) struct vop2_video_port *vp2 = &vop2->vps[2]; struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); + mutex_lock(&vop2->ovl_lock); ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL; - ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id); if (vcstate->yuv_overlay) ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); else ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id); - vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl); - - port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL); + old_port_sel = vop2->old_port_sel; + port_sel = old_port_sel; port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT; if (vp0->nlayers) @@ -2102,7 +2144,13 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) else port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8); - layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + /* Fixed value for rk3588 */ + if (vop2->version == VOP_VERSION_RK3588) + port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7); + + atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + old_layer_sel = vop2->old_layer_sel; + layer_sel = old_layer_sel; ofs = 0; for (i = 0; i < vp->id; i++) @@ -2186,8 +2234,37 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) old_win->data->layer_sel_id[vp->id]); } + vop2->old_layer_sel = layer_sel; + vop2->old_port_sel = port_sel; + /* + * As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports, + * and the configuration take effect by one Video Port's vsync. + * When performing layer migration or change the zpos of layers, there are two things + * to be observed and followed: + * 1. When a layer is migrated from one VP to another, the configuration of the layer + * can only take effect after the Port mux configuration is enabled. + * + * 2. When we change the zpos of layers, we must ensure that the change for the previous + * VP takes effect before we proceed to change the next VP. Otherwise, the new + * configuration might overwrite the previous one for the previous VP, or it could + * lead to the configuration of the previous VP being take effect along with the VSYNC + * of the new VP. + */ + if (layer_sel != old_layer_sel || port_sel != old_port_sel) + ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id); + vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl); + + if (port_sel != old_port_sel) { + vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); + vop2_cfg_done(vp); + rk3568_vop2_wait_for_port_mux_done(vop2); + } + + if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) + rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel); + vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); - vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); + mutex_unlock(&vop2->ovl_lock); } static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp) |