diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
20 files changed, 1010 insertions, 876 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index ab525668939a..b7b025814e72 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -10,6 +10,7 @@ config DRM_ROCKCHIP select VIDEOMODE_HELPERS select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP select DRM_DISPLAY_DP_AUX_BUS if ROCKCHIP_ANALOGIX_DP + select DRM_DW_DP if ROCKCHIP_DW_DP select DRM_DW_HDMI if ROCKCHIP_DW_HDMI select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI @@ -53,6 +54,7 @@ config ROCKCHIP_CDN_DP bool "Rockchip cdn DP" depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m) select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_DP_HELPER help This selects support for Rockchip SoC specific extensions @@ -60,6 +62,14 @@ config ROCKCHIP_CDN_DP RK3399 based SoC, you should select this option. +config ROCKCHIP_DW_DP + bool "Rockchip specific extensions for Synopsys DW DP" + help + This selects support for Rockchip SoC specific extensions + to enable Synopsys DesignWare Cores based DisplayPort transmit + controller support on Rockchip SoC, If you want to enable DP on + rk3588 based SoC, you should select this option. + config ROCKCHIP_DW_HDMI bool "Rockchip specific extensions for Synopsys DW HDMI" help diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 2b867cebbc12..097f062399c7 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -14,6 +14,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi2-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_DP) += dw_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o 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-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 3398160ad75e..5523911b990d 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -7,6 +7,7 @@ */ #include <linux/clk.h> +#include <linux/hw_bitfield.h> #include <linux/iopoll.h> #include <linux/math64.h> #include <linux/mfd/syscon.h> @@ -148,7 +149,7 @@ #define DW_MIPI_NEEDS_GRF_CLK BIT(1) #define PX30_GRF_PD_VO_CON1 0x0438 -#define PX30_DSI_FORCETXSTOPMODE (0xf << 7) +#define PX30_DSI_FORCETXSTOPMODE (0xfUL << 7) #define PX30_DSI_FORCERXMODE BIT(6) #define PX30_DSI_TURNDISABLE BIT(5) #define PX30_DSI_LCDC_SEL BIT(0) @@ -167,16 +168,16 @@ #define RK3399_DSI1_LCDC_SEL BIT(4) #define RK3399_GRF_SOC_CON22 0x6258 -#define RK3399_DSI0_TURNREQUEST (0xf << 12) -#define RK3399_DSI0_TURNDISABLE (0xf << 8) -#define RK3399_DSI0_FORCETXSTOPMODE (0xf << 4) -#define RK3399_DSI0_FORCERXMODE (0xf << 0) +#define RK3399_DSI0_TURNREQUEST (0xfUL << 12) +#define RK3399_DSI0_TURNDISABLE (0xfUL << 8) +#define RK3399_DSI0_FORCETXSTOPMODE (0xfUL << 4) +#define RK3399_DSI0_FORCERXMODE (0xfUL << 0) #define RK3399_GRF_SOC_CON23 0x625c -#define RK3399_DSI1_TURNDISABLE (0xf << 12) -#define RK3399_DSI1_FORCETXSTOPMODE (0xf << 8) -#define RK3399_DSI1_FORCERXMODE (0xf << 4) -#define RK3399_DSI1_ENABLE (0xf << 0) +#define RK3399_DSI1_TURNDISABLE (0xfUL << 12) +#define RK3399_DSI1_FORCETXSTOPMODE (0xfUL << 8) +#define RK3399_DSI1_FORCERXMODE (0xfUL << 4) +#define RK3399_DSI1_ENABLE (0xfUL << 0) #define RK3399_GRF_SOC_CON24 0x6260 #define RK3399_TXRX_MASTERSLAVEZ BIT(7) @@ -186,8 +187,8 @@ #define RK3399_TXRX_TURNREQUEST GENMASK(3, 0) #define RK3568_GRF_VO_CON2 0x0368 -#define RK3568_DSI0_SKEWCALHS (0x1f << 11) -#define RK3568_DSI0_FORCETXSTOPMODE (0xf << 4) +#define RK3568_DSI0_SKEWCALHS (0x1fUL << 11) +#define RK3568_DSI0_FORCETXSTOPMODE (0xfUL << 4) #define RK3568_DSI0_TURNDISABLE BIT(2) #define RK3568_DSI0_FORCERXMODE BIT(0) @@ -197,18 +198,16 @@ * come from. Name GRF_VO_CON3 is assumed. */ #define RK3568_GRF_VO_CON3 0x36c -#define RK3568_DSI1_SKEWCALHS (0x1f << 11) -#define RK3568_DSI1_FORCETXSTOPMODE (0xf << 4) +#define RK3568_DSI1_SKEWCALHS (0x1fUL << 11) +#define RK3568_DSI1_FORCETXSTOPMODE (0xfUL << 4) #define RK3568_DSI1_TURNDISABLE BIT(2) #define RK3568_DSI1_FORCERXMODE BIT(0) #define RV1126_GRF_DSIPHY_CON 0x10220 -#define RV1126_DSI_FORCETXSTOPMODE (0xf << 4) +#define RV1126_DSI_FORCETXSTOPMODE (0xfUL << 4) #define RV1126_DSI_TURNDISABLE BIT(2) #define RV1126_DSI_FORCERXMODE BIT(0) -#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) - enum { DW_DSI_USAGE_IDLE, DW_DSI_USAGE_DSI, @@ -1484,14 +1483,13 @@ static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = { { .reg = 0xff450000, .lcdsel_grf_reg = PX30_GRF_PD_VO_CON1, - .lcdsel_big = HIWORD_UPDATE(0, PX30_DSI_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(PX30_DSI_LCDC_SEL, - PX30_DSI_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(PX30_DSI_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(PX30_DSI_LCDC_SEL, 1), .lanecfg1_grf_reg = PX30_GRF_PD_VO_CON1, - .lanecfg1 = HIWORD_UPDATE(0, PX30_DSI_TURNDISABLE | - PX30_DSI_FORCERXMODE | - PX30_DSI_FORCETXSTOPMODE), + .lanecfg1 = FIELD_PREP_WM16_CONST((PX30_DSI_TURNDISABLE | + PX30_DSI_FORCERXMODE | + PX30_DSI_FORCETXSTOPMODE), 0), .max_data_lanes = 4, }, @@ -1502,9 +1500,9 @@ static const struct rockchip_dw_dsi_chip_data rk3128_chip_data[] = { { .reg = 0x10110000, .lanecfg1_grf_reg = RK3128_GRF_LVDS_CON0, - .lanecfg1 = HIWORD_UPDATE(0, RK3128_DSI_TURNDISABLE | - RK3128_DSI_FORCERXMODE | - RK3128_DSI_FORCETXSTOPMODE), + .lanecfg1 = FIELD_PREP_WM16_CONST((RK3128_DSI_TURNDISABLE | + RK3128_DSI_FORCERXMODE | + RK3128_DSI_FORCETXSTOPMODE), 0), .max_data_lanes = 4, }, { /* sentinel */ } @@ -1514,16 +1512,16 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = { { .reg = 0xff960000, .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, - .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI0_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI0_LCDC_SEL, RK3288_DSI0_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3288_DSI0_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI0_LCDC_SEL, 1), .max_data_lanes = 4, }, { .reg = 0xff964000, .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, - .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI1_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI1_LCDC_SEL, RK3288_DSI1_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3288_DSI1_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI1_LCDC_SEL, 1), .max_data_lanes = 4, }, @@ -1539,13 +1537,13 @@ static int rk3399_dphy_tx1rx1_init(struct phy *phy) * Assume ISP0 is supplied by the RX0 dphy. */ regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(0, RK3399_TXRX_SRC_SEL_ISP0)); + FIELD_PREP_WM16(RK3399_TXRX_SRC_SEL_ISP0, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(0, RK3399_TXRX_MASTERSLAVEZ)); + FIELD_PREP_WM16(RK3399_TXRX_MASTERSLAVEZ, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(0, RK3399_TXRX_BASEDIR)); + FIELD_PREP_WM16(RK3399_TXRX_BASEDIR, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(0, RK3399_DSI1_ENABLE)); + FIELD_PREP_WM16(RK3399_DSI1_ENABLE, 0)); return 0; } @@ -1559,21 +1557,20 @@ static int rk3399_dphy_tx1rx1_power_on(struct phy *phy) usleep_range(100, 150); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(0, RK3399_TXRX_MASTERSLAVEZ)); + FIELD_PREP_WM16(RK3399_TXRX_MASTERSLAVEZ, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(RK3399_TXRX_BASEDIR, RK3399_TXRX_BASEDIR)); + FIELD_PREP_WM16(RK3399_TXRX_BASEDIR, 1)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(0, RK3399_DSI1_FORCERXMODE)); + FIELD_PREP_WM16(RK3399_DSI1_FORCERXMODE, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(0, RK3399_DSI1_FORCETXSTOPMODE)); + FIELD_PREP_WM16(RK3399_DSI1_FORCETXSTOPMODE, 0)); /* Disable lane turn around, which is ignored in receive mode */ regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, - HIWORD_UPDATE(0, RK3399_TXRX_TURNREQUEST)); + FIELD_PREP_WM16(RK3399_TXRX_TURNREQUEST, 0)); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(RK3399_DSI1_TURNDISABLE, - RK3399_DSI1_TURNDISABLE)); + FIELD_PREP_WM16(RK3399_DSI1_TURNDISABLE, 0xf)); usleep_range(100, 150); dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR); @@ -1581,8 +1578,8 @@ static int rk3399_dphy_tx1rx1_power_on(struct phy *phy) /* Enable dphy lanes */ regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(GENMASK(dsi->dphy_config.lanes - 1, 0), - RK3399_DSI1_ENABLE)); + FIELD_PREP_WM16(RK3399_DSI1_ENABLE, + GENMASK(dsi->dphy_config.lanes - 1, 0))); usleep_range(100, 150); @@ -1594,7 +1591,7 @@ static int rk3399_dphy_tx1rx1_power_off(struct phy *phy) struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, - HIWORD_UPDATE(0, RK3399_DSI1_ENABLE)); + FIELD_PREP_WM16(RK3399_DSI1_ENABLE, 0)); return 0; } @@ -1603,15 +1600,14 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { { .reg = 0xff960000, .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, - .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL, - RK3399_DSI0_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3399_DSI0_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3399_DSI0_LCDC_SEL, 1), .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22, - .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST | - RK3399_DSI0_TURNDISABLE | - RK3399_DSI0_FORCETXSTOPMODE | - RK3399_DSI0_FORCERXMODE), + .lanecfg1 = FIELD_PREP_WM16_CONST((RK3399_DSI0_TURNREQUEST | + RK3399_DSI0_TURNDISABLE | + RK3399_DSI0_FORCETXSTOPMODE | + RK3399_DSI0_FORCERXMODE), 0), .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, .max_data_lanes = 4, @@ -1619,25 +1615,23 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { { .reg = 0xff968000, .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, - .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL, - RK3399_DSI1_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3399_DSI1_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3399_DSI1_LCDC_SEL, 1), + .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23, - .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE | - RK3399_DSI1_FORCETXSTOPMODE | - RK3399_DSI1_FORCERXMODE | - RK3399_DSI1_ENABLE), + .lanecfg1 = FIELD_PREP_WM16_CONST((RK3399_DSI1_TURNDISABLE | + RK3399_DSI1_FORCETXSTOPMODE | + RK3399_DSI1_FORCERXMODE | + RK3399_DSI1_ENABLE), 0), .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24, - .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ | - RK3399_TXRX_ENABLECLK, - RK3399_TXRX_MASTERSLAVEZ | - RK3399_TXRX_ENABLECLK | - RK3399_TXRX_BASEDIR), + .lanecfg2 = (FIELD_PREP_WM16_CONST(RK3399_TXRX_MASTERSLAVEZ, 1) | + FIELD_PREP_WM16_CONST(RK3399_TXRX_ENABLECLK, 1) | + FIELD_PREP_WM16_CONST(RK3399_TXRX_BASEDIR, 0)), .enable_grf_reg = RK3399_GRF_SOC_CON23, - .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE), + .enable = FIELD_PREP_WM16_CONST(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE), .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, .max_data_lanes = 4, @@ -1653,19 +1647,19 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { { .reg = 0xfe060000, .lanecfg1_grf_reg = RK3568_GRF_VO_CON2, - .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI0_SKEWCALHS | - RK3568_DSI0_FORCETXSTOPMODE | - RK3568_DSI0_TURNDISABLE | - RK3568_DSI0_FORCERXMODE), + .lanecfg1 = (FIELD_PREP_WM16_CONST(RK3568_DSI0_SKEWCALHS, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI0_FORCETXSTOPMODE, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI0_TURNDISABLE, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI0_FORCERXMODE, 0)), .max_data_lanes = 4, }, { .reg = 0xfe070000, .lanecfg1_grf_reg = RK3568_GRF_VO_CON3, - .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI1_SKEWCALHS | - RK3568_DSI1_FORCETXSTOPMODE | - RK3568_DSI1_TURNDISABLE | - RK3568_DSI1_FORCERXMODE), + .lanecfg1 = (FIELD_PREP_WM16_CONST(RK3568_DSI1_SKEWCALHS, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI1_FORCETXSTOPMODE, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI1_TURNDISABLE, 0) | + FIELD_PREP_WM16_CONST(RK3568_DSI1_FORCERXMODE, 0)), .max_data_lanes = 4, }, { /* sentinel */ } @@ -1675,9 +1669,9 @@ static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = { { .reg = 0xffb30000, .lanecfg1_grf_reg = RV1126_GRF_DSIPHY_CON, - .lanecfg1 = HIWORD_UPDATE(0, RV1126_DSI_TURNDISABLE | - RV1126_DSI_FORCERXMODE | - RV1126_DSI_FORCETXSTOPMODE), + .lanecfg1 = (FIELD_PREP_WM16_CONST(RV1126_DSI_TURNDISABLE, 0) | + FIELD_PREP_WM16_CONST(RV1126_DSI_FORCERXMODE, 0) | + FIELD_PREP_WM16_CONST(RV1126_DSI_FORCETXSTOPMODE, 0)), .max_data_lanes = 4, }, { /* sentinel */ } diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index cdd490778756..0aea764e29b2 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -437,6 +437,15 @@ static void dw_mipi_dsi2_rockchip_remove(struct platform_device *pdev) dw_mipi_dsi2_remove(dsi2->dmd); } +static const struct dsigrf_reg rk3576_dsi_grf_reg_fields[MAX_FIELDS] = { + [TXREQCLKHS_EN] = { 0x0028, 1, 1 }, + [GATING_EN] = { 0x0028, 0, 0 }, + [IPI_SHUTDN] = { 0x0028, 3, 3 }, + [IPI_COLORM] = { 0x0028, 2, 2 }, + [IPI_COLOR_DEPTH] = { 0x0028, 8, 11 }, + [IPI_FORMAT] = { 0x0028, 4, 7 }, +}; + static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = { [TXREQCLKHS_EN] = { 0x0000, 11, 11 }, [GATING_EN] = { 0x0000, 10, 10 }, @@ -455,6 +464,15 @@ static const struct dsigrf_reg rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = { [IPI_FORMAT] = { 0x0004, 0, 3 }, }; +static const struct rockchip_dw_dsi2_chip_data rk3576_chip_data[] = { + { + .reg = 0x27d80000, + .grf_regs = rk3576_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 2500000ULL, + }, + { /* sentinel */ } +}; + static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = { { .reg = 0xfde20000, @@ -470,6 +488,9 @@ static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = { static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = { { + .compatible = "rockchip,rk3576-mipi-dsi2", + .data = &rk3576_chip_data, + }, { .compatible = "rockchip,rk3588-mipi-dsi2", .data = &rk3588_chip_data, }, diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c new file mode 100644 index 000000000000..25ab4e46301e --- /dev/null +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * + * Author: Zhang Yubing <yubing.zhang@rock-chips.com> + * Author: Andy Yan <andy.yan@rock-chips.com> + */ + +#include <linux/component.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <drm/bridge/dw_dp.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> +#include <drm/drm_of.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_simple_kms_helper.h> + +#include <linux/media-bus-format.h> +#include <linux/videodev2.h> + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_vop.h" + +struct rockchip_dw_dp { + struct dw_dp *base; + struct device *dev; + struct rockchip_encoder encoder; +}; + +static int dw_dp_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct drm_atomic_state *state = conn_state->state; + struct drm_display_info *di = &conn_state->connector->display_info; + struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder); + struct drm_bridge_state *bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + u32 bus_format = bridge_state->input_bus_cfg.format; + + switch (bus_format) { + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + s->output_mode = ROCKCHIP_OUT_MODE_YUV420; + break; + case MEDIA_BUS_FMT_YUYV10_1X20: + case MEDIA_BUS_FMT_YUYV8_1X16: + s->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_YUV8_1X24: + default: + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + break; + } + + s->output_type = DRM_MODE_CONNECTOR_DisplayPort; + s->bus_format = bus_format; + s->bus_flags = di->bus_flags; + s->color_space = V4L2_COLORSPACE_DEFAULT; + + return 0; +} + +static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = { + .atomic_check = dw_dp_encoder_atomic_check, +}; + +static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dw_dp_plat_data plat_data; + struct drm_device *drm_dev = data; + struct rockchip_dw_dp *dp; + struct drm_encoder *encoder; + struct drm_connector *connector; + int ret; + + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return -ENOMEM; + + dp->dev = dev; + platform_set_drvdata(pdev, dp); + + plat_data.max_link_rate = 810000; + encoder = &dp->encoder.encoder; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node); + rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, dev->of_node, 0, 0); + + ret = drmm_encoder_init(drm_dev, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL); + if (ret) + return ret; + drm_encoder_helper_add(encoder, &dw_dp_encoder_helper_funcs); + + dp->base = dw_dp_bind(dev, encoder, &plat_data); + if (IS_ERR(dp->base)) { + ret = PTR_ERR(dp->base); + return ret; + } + + connector = drm_bridge_connector_init(drm_dev, encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + return dev_err_probe(dev, ret, "Failed to init bridge connector"); + } + + drm_connector_attach_encoder(connector, encoder); + + return 0; +} + +static const struct component_ops dw_dp_rockchip_component_ops = { + .bind = dw_dp_rockchip_bind, +}; + +static int dw_dp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + return component_add(dev, &dw_dp_rockchip_component_ops); +} + +static void dw_dp_remove(struct platform_device *pdev) +{ + struct rockchip_dw_dp *dp = platform_get_drvdata(pdev); + + component_del(dp->dev, &dw_dp_rockchip_component_ops); +} + +static const struct of_device_id dw_dp_of_match[] = { + { .compatible = "rockchip,rk3588-dp", }, + {} +}; +MODULE_DEVICE_TABLE(of, dw_dp_of_match); + +struct platform_driver dw_dp_driver = { + .probe = dw_dp_probe, + .remove = dw_dp_remove, + .driver = { + .name = "dw-dp", + .of_match_table = dw_dp_of_match, + }, +}; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index f737e7d46e66..7b613997bb50 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -4,6 +4,7 @@ */ #include <linux/clk.h> +#include <linux/hw_bitfield.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -54,8 +55,6 @@ #define RK3568_HDMI_SDAIN_MSK BIT(15) #define RK3568_HDMI_SCLIN_MSK BIT(14) -#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) - /** * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips * @lcdsel_grf_reg: grf register offset of lcdc select @@ -213,17 +212,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"); @@ -359,17 +354,14 @@ static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) dw_hdmi_phy_setup_hpd(dw_hdmi, data); - regmap_write(hdmi->regmap, - RK3228_GRF_SOC_CON6, - HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | - RK3228_HDMI_SCL_VSEL, - RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | - RK3228_HDMI_SCL_VSEL)); - - regmap_write(hdmi->regmap, - RK3228_GRF_SOC_CON2, - HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK, - RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK)); + regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON6, + FIELD_PREP_WM16(RK3228_HDMI_HPD_VSEL, 1) | + FIELD_PREP_WM16(RK3228_HDMI_SDA_VSEL, 1) | + FIELD_PREP_WM16(RK3228_HDMI_SCL_VSEL, 1)); + + regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON2, + FIELD_PREP_WM16(RK3228_HDMI_SDAIN_MSK, 1) | + FIELD_PREP_WM16(RK3328_HDMI_SCLIN_MSK, 1)); } static enum drm_connector_status @@ -381,15 +373,13 @@ dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data) status = dw_hdmi_phy_read_hpd(dw_hdmi, data); if (status == connector_status_connected) - regmap_write(hdmi->regmap, - RK3328_GRF_SOC_CON4, - HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V, - RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V)); + regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4, + FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 1) | + FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 1)); else - regmap_write(hdmi->regmap, - RK3328_GRF_SOC_CON4, - HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V | - RK3328_HDMI_SCL_5V)); + regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4, + FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 0) | + FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 0)); return status; } @@ -400,21 +390,21 @@ static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) dw_hdmi_phy_setup_hpd(dw_hdmi, data); /* Enable and map pins to 3V grf-controlled io-voltage */ - regmap_write(hdmi->regmap, - RK3328_GRF_SOC_CON4, - HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V | - RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V | - RK3328_HDMI_HPD_5V)); - regmap_write(hdmi->regmap, - RK3328_GRF_SOC_CON3, - HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF | - RK3328_HDMI_HPD5V_GRF | - RK3328_HDMI_CEC5V_GRF)); - regmap_write(hdmi->regmap, - RK3328_GRF_SOC_CON2, - HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK, - RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK | - RK3328_HDMI_HPD_IOE)); + regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4, + FIELD_PREP_WM16(RK3328_HDMI_HPD_SARADC, 0) | + FIELD_PREP_WM16(RK3328_HDMI_CEC_5V, 0) | + FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 0) | + FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 0) | + FIELD_PREP_WM16(RK3328_HDMI_HPD_5V, 0)); + regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON3, + FIELD_PREP_WM16(RK3328_HDMI_SDA5V_GRF, 0) | + FIELD_PREP_WM16(RK3328_HDMI_SCL5V_GRF, 0) | + FIELD_PREP_WM16(RK3328_HDMI_HPD5V_GRF, 0) | + FIELD_PREP_WM16(RK3328_HDMI_CEC5V_GRF, 0)); + regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON2, + FIELD_PREP_WM16(RK3328_HDMI_SDAIN_MSK, 1) | + FIELD_PREP_WM16(RK3328_HDMI_SCLIN_MSK, 1) | + FIELD_PREP_WM16(RK3328_HDMI_HPD_IOE, 0)); dw_hdmi_rk3328_read_hpd(dw_hdmi, data); } @@ -442,8 +432,8 @@ static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { static struct rockchip_hdmi_chip_data rk3288_chip_data = { .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, - .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3288_HDMI_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_HDMI_LCDC_SEL, 1), .max_tmds_clock = 340000, }; @@ -479,8 +469,8 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { static struct rockchip_hdmi_chip_data rk3399_chip_data = { .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, - .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), - .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), + .lcdsel_big = FIELD_PREP_WM16_CONST(RK3399_HDMI_LCDC_SEL, 0), + .lcdsel_lit = FIELD_PREP_WM16_CONST(RK3399_HDMI_LCDC_SEL, 1), .max_tmds_clock = 594000, }; @@ -573,17 +563,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) { @@ -597,10 +583,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, if (hdmi->chip_data == &rk3568_chip_data) { regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, - HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | - RK3568_HDMI_SCLIN_MSK, - RK3568_HDMI_SDAIN_MSK | - RK3568_HDMI_SCLIN_MSK)); + FIELD_PREP_WM16(RK3568_HDMI_SDAIN_MSK, 1) | + FIELD_PREP_WM16(RK3568_HDMI_SCLIN_MSK, 1)); } drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index 7d531b6f4c09..ed6e8f036f4b 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/gpio/consumer.h> +#include <linux/hw_bitfield.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -66,7 +67,8 @@ #define RK3588_HDMI1_HPD_INT_MSK BIT(15) #define RK3588_HDMI1_HPD_INT_CLR BIT(14) #define RK3588_GRF_SOC_CON7 0x031c -#define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12) +#define RK3588_HPD_HDMI0_IO_EN_MASK BIT(12) +#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13) #define RK3588_GRF_SOC_STATUS1 0x0384 #define RK3588_HDMI0_LEVEL_INT BIT(16) #define RK3588_HDMI1_LEVEL_INT BIT(24) @@ -80,7 +82,6 @@ #define RK3588_HDMI0_GRANT_SEL BIT(10) #define RK3588_HDMI1_GRANT_SEL BIT(12) -#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) #define HOTPLUG_DEBOUNCE_MS 150 #define MAX_HDMI_PORT_NUM 2 @@ -185,11 +186,11 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) u32 val; if (hdmi->port_id) - val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, - RK3588_HDMI1_HPD_INT_CLR | RK3588_HDMI1_HPD_INT_MSK); + val = (FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1) | + FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0)); else - val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, - RK3588_HDMI0_HPD_INT_CLR | RK3588_HDMI0_HPD_INT_MSK); + val = (FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1) | + FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0)); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); } @@ -218,8 +219,8 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; u32 val; - val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_CLR, - RK3576_HDMI_HPD_INT_CLR | RK3576_HDMI_HPD_INT_MSK); + val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) | + FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0)); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); regmap_write(hdmi->regmap, 0xa404, 0xffff0102); @@ -254,7 +255,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id) regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat); if (intr_stat) { - val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_MSK, RK3576_HDMI_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); return IRQ_WAKE_THREAD; @@ -273,12 +274,12 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id) if (!intr_stat) return IRQ_NONE; - val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_CLR, RK3576_HDMI_HPD_INT_CLR); + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); mod_delayed_work(system_wq, &hdmi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); - val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); return IRQ_HANDLED; @@ -293,11 +294,9 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id) if (intr_stat) { if (hdmi->port_id) - val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, - RK3588_HDMI1_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1); else - val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, - RK3588_HDMI0_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); return IRQ_WAKE_THREAD; } @@ -315,20 +314,18 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) return IRQ_NONE; if (hdmi->port_id) - val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR, - RK3588_HDMI1_HPD_INT_CLR); + val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1); else - val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, - RK3588_HDMI0_HPD_INT_CLR); + val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); mod_delayed_work(system_wq, &hdmi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); if (hdmi->port_id) - val |= HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK); + val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0); else - val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); + val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); return IRQ_HANDLED; @@ -338,14 +335,14 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi) { u32 val; - val = HIWORD_UPDATE(RK3576_SCLIN_MASK, RK3576_SCLIN_MASK) | - HIWORD_UPDATE(RK3576_SDAIN_MASK, RK3576_SDAIN_MASK) | - HIWORD_UPDATE(RK3576_HDMI_GRANT_SEL, RK3576_HDMI_GRANT_SEL) | - HIWORD_UPDATE(RK3576_I2S_SEL_MASK, RK3576_I2S_SEL_MASK); + val = FIELD_PREP_WM16(RK3576_SCLIN_MASK, 1) | + FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) | + FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) | + FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1); regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val); - val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); } @@ -353,27 +350,28 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi) { u32 val; - val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | - HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | - HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | - HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); + val = FIELD_PREP_WM16(RK3588_SCLIN_MASK, 1) | + FIELD_PREP_WM16(RK3588_SDAIN_MASK, 1) | + FIELD_PREP_WM16(RK3588_MODE_MASK, 1) | + FIELD_PREP_WM16(RK3588_I2S_SEL_MASK, 1); regmap_write(hdmi->vo_regmap, hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3, val); - val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, RK3588_SET_HPD_PATH_MASK); + val = FIELD_PREP_WM16(RK3588_HPD_HDMI0_IO_EN_MASK, 1) | + FIELD_PREP_WM16(RK3588_HPD_HDMI1_IO_EN_MASK, 1); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); if (hdmi->port_id) - val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL, RK3588_HDMI1_GRANT_SEL); + val = FIELD_PREP_WM16(RK3588_HDMI1_GRANT_SEL, 1); else - val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, RK3588_HDMI0_GRANT_SEL); + val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1); regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); if (hdmi->port_id) - val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1); else - val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); + val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); } diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index db4b4038e51d..f24827dc1421 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/hdmi.h> +#include <linux/hw_bitfield.h> #include <linux/mfd/syscon.h> #include <linux/mod_devicetable.h> #include <linux/module.h> @@ -29,11 +30,358 @@ #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 RK3036_GRF_SOC_CON2 0x148 #define RK3036_HDMI_PHSYNC BIT(4) @@ -255,22 +603,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, @@ -392,10 +755,10 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, int value, psync; if (hdmi->variant->dev_type == RK3036_HDMI) { - psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? RK3036_HDMI_PHSYNC : 0; - value = HIWORD_UPDATE(psync, RK3036_HDMI_PHSYNC); - psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? RK3036_HDMI_PVSYNC : 0; - value |= HIWORD_UPDATE(psync, RK3036_HDMI_PVSYNC); + psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 : 0; + value = FIELD_PREP_WM16(RK3036_HDMI_PHSYNC, psync); + psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 : 0; + value |= FIELD_PREP_WM16(RK3036_HDMI_PVSYNC, psync); regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value); } @@ -775,8 +1138,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 +1229,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 +1268,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 +1309,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 +1319,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_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 180fad5d49ad..eb77bde9f628 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -529,6 +529,7 @@ static int __init rockchip_drm_init(void) ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, CONFIG_ROCKCHIP_ANALOGIX_DP); ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); + ADD_ROCKCHIP_SUB_DRIVER(dw_dp_driver, CONFIG_ROCKCHIP_DW_DP); ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, CONFIG_ROCKCHIP_DW_HDMI); ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index c183e82a42a5..2e86ad00979c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -87,6 +87,7 @@ int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder, struct device_node *np, int port, int reg); int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); extern struct platform_driver cdn_dp_driver; +extern struct platform_driver dw_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver; extern struct platform_driver dw_mipi_dsi_rockchip_driver; 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..b50927a824b4 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 */ @@ -2589,12 +2579,13 @@ static int vop2_win_init(struct vop2 *vop2) } /* - * The window registers are only updated when config done is written. - * Until that they read back the old value. As we read-modify-write - * these registers mark them as non-volatile. This makes sure we read - * the new values from the regmap register cache. + * The window and video port registers are only updated when config + * done is written. Until that they read back the old value. As we + * read-modify-write these registers mark them as non-volatile. This + * makes sure we read the new values from the regmap register cache. */ static const struct regmap_range vop2_nonvolatile_range[] = { + regmap_reg_range(RK3568_VP0_CTRL_BASE, RK3588_VP3_CTRL_BASE + 255), regmap_reg_range(0x1000, 0x23ff), }; @@ -2724,6 +2715,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..9124191899ba 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -33,7 +33,6 @@ #define WIN_FEATURE_AFBDC BIT(0) #define WIN_FEATURE_CLUSTER BIT(1) -#define HIWORD_UPDATE(v, h, l) ((GENMASK(h, l) << 16) | ((v) << (l))) /* * the delay number of a window in different mode. */ @@ -334,6 +333,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 +739,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 +844,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_lvds.h b/drivers/gpu/drm/rockchip/rockchip_lvds.h index ca83d7b6bea7..2d92447d819b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.h +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.h @@ -9,6 +9,9 @@ #ifndef _ROCKCHIP_LVDS_ #define _ROCKCHIP_LVDS_ +#include <linux/bits.h> +#include <linux/hw_bitfield.h> + #define RK3288_LVDS_CH0_REG0 0x00 #define RK3288_LVDS_CH0_REG0_LVDS_EN BIT(7) #define RK3288_LVDS_CH0_REG0_TTL_EN BIT(6) @@ -106,18 +109,16 @@ #define LVDS_VESA_18 2 #define LVDS_JEIDA_18 3 -#define HIWORD_UPDATE(v, h, l) ((GENMASK(h, l) << 16) | ((v) << (l))) - #define PX30_LVDS_GRF_PD_VO_CON0 0x434 -#define PX30_LVDS_TIE_CLKS(val) HIWORD_UPDATE(val, 8, 8) -#define PX30_LVDS_INVERT_CLKS(val) HIWORD_UPDATE(val, 9, 9) -#define PX30_LVDS_INVERT_DCLK(val) HIWORD_UPDATE(val, 5, 5) +#define PX30_LVDS_TIE_CLKS(val) FIELD_PREP_WM16(BIT(8), (val)) +#define PX30_LVDS_INVERT_CLKS(val) FIELD_PREP_WM16(BIT(9), (val)) +#define PX30_LVDS_INVERT_DCLK(val) FIELD_PREP_WM16(BIT(5), (val)) #define PX30_LVDS_GRF_PD_VO_CON1 0x438 -#define PX30_LVDS_FORMAT(val) HIWORD_UPDATE(val, 14, 13) -#define PX30_LVDS_MODE_EN(val) HIWORD_UPDATE(val, 12, 12) -#define PX30_LVDS_MSBSEL(val) HIWORD_UPDATE(val, 11, 11) -#define PX30_LVDS_P2S_EN(val) HIWORD_UPDATE(val, 6, 6) -#define PX30_LVDS_VOP_SEL(val) HIWORD_UPDATE(val, 1, 1) +#define PX30_LVDS_FORMAT(val) FIELD_PREP_WM16(GENMASK(14, 13), (val)) +#define PX30_LVDS_MODE_EN(val) FIELD_PREP_WM16(BIT(12), (val)) +#define PX30_LVDS_MSBSEL(val) FIELD_PREP_WM16(BIT(11), (val)) +#define PX30_LVDS_P2S_EN(val) FIELD_PREP_WM16(BIT(6), (val)) +#define PX30_LVDS_VOP_SEL(val) FIELD_PREP_WM16(BIT(1), (val)) #endif /* _ROCKCHIP_LVDS_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 32c4ed685739..38c49030c7ab 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -7,6 +7,7 @@ #include <linux/bitfield.h> #include <linux/kernel.h> #include <linux/component.h> +#include <linux/hw_bitfield.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/of.h> @@ -1695,8 +1696,9 @@ static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 die |= RK3588_SYS_DSP_INFACE_EN_HDMI0 | FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id); val = rk3588_get_hdmi_pol(polflags); - regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 1, 1)); - regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 6, 5)); + regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, FIELD_PREP_WM16(BIT(1), 1)); + regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, + FIELD_PREP_WM16(GENMASK(6, 5), val)); break; case ROCKCHIP_VOP2_EP_HDMI1: div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; @@ -1707,8 +1709,9 @@ static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 die |= RK3588_SYS_DSP_INFACE_EN_HDMI1 | FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id); val = rk3588_get_hdmi_pol(polflags); - regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 4, 4)); - regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 8, 7)); + regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, FIELD_PREP_WM16(BIT(4), 1)); + regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, + FIELD_PREP_WM16(GENMASK(8, 7), val)); break; case ROCKCHIP_VOP2_EP_EDP0: div &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV; @@ -1718,7 +1721,7 @@ static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX; die |= RK3588_SYS_DSP_INFACE_EN_EDP0 | FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id); - regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 0, 0)); + regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, FIELD_PREP_WM16(BIT(0), 1)); break; case ROCKCHIP_VOP2_EP_EDP1: div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; @@ -1728,7 +1731,7 @@ static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX; die |= RK3588_SYS_DSP_INFACE_EN_EDP1 | FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id); - regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 3, 3)); + regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, FIELD_PREP_WM16(BIT(3), 1)); break; case ROCKCHIP_VOP2_EP_MIPI0: div &= ~RK3588_DSP_IF_MIPI0_PCLK_DIV; @@ -2052,12 +2055,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 +2115,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 +2147,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 +2237,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) |