18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Rockchip SoC DP (Display Port) interface driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Andy Yan <andy.yan@rock-chips.com> 78c2ecf20Sopenharmony_ci * Yakir Yang <ykk@rock-chips.com> 88c2ecf20Sopenharmony_ci * Jeff Chen <jeff.chen@rock-chips.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/component.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 138c2ecf20Sopenharmony_ci#include <linux/of_device.h> 148c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/reset.h> 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <video/of_videomode.h> 208c2ecf20Sopenharmony_ci#include <video/videomode.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 238c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 248c2ecf20Sopenharmony_ci#include <drm/bridge/analogix_dp.h> 258c2ecf20Sopenharmony_ci#include <drm/drm_dp_helper.h> 268c2ecf20Sopenharmony_ci#include <drm/drm_of.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 288c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "rockchip_drm_drv.h" 328c2ecf20Sopenharmony_ci#include "rockchip_drm_vop.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define RK3288_GRF_SOC_CON6 0x25c 358c2ecf20Sopenharmony_ci#define RK3288_EDP_LCDC_SEL BIT(5) 368c2ecf20Sopenharmony_ci#define RK3399_GRF_SOC_CON20 0x6250 378c2ecf20Sopenharmony_ci#define RK3399_EDP_LCDC_SEL BIT(5) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 478c2ecf20Sopenharmony_ci * @lcdsel_grf_reg: grf register offset of lcdc select 488c2ecf20Sopenharmony_ci * @lcdsel_big: reg value of selecting vop big for eDP 498c2ecf20Sopenharmony_ci * @lcdsel_lit: reg value of selecting vop little for eDP 508c2ecf20Sopenharmony_ci * @chip_type: specific chip type 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistruct rockchip_dp_chip_data { 538c2ecf20Sopenharmony_ci u32 lcdsel_grf_reg; 548c2ecf20Sopenharmony_ci u32 lcdsel_big; 558c2ecf20Sopenharmony_ci u32 lcdsel_lit; 568c2ecf20Sopenharmony_ci u32 chip_type; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct rockchip_dp_device { 608c2ecf20Sopenharmony_ci struct drm_device *drm_dev; 618c2ecf20Sopenharmony_ci struct device *dev; 628c2ecf20Sopenharmony_ci struct drm_encoder encoder; 638c2ecf20Sopenharmony_ci struct drm_display_mode mode; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci struct clk *pclk; 668c2ecf20Sopenharmony_ci struct clk *grfclk; 678c2ecf20Sopenharmony_ci struct regmap *grf; 688c2ecf20Sopenharmony_ci struct reset_control *rst; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci const struct rockchip_dp_chip_data *data; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci struct analogix_dp_device *adp; 738c2ecf20Sopenharmony_ci struct analogix_dp_plat_data plat_data; 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int rockchip_dp_pre_init(struct rockchip_dp_device *dp) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci reset_control_assert(dp->rst); 798c2ecf20Sopenharmony_ci usleep_range(10, 20); 808c2ecf20Sopenharmony_ci reset_control_deassert(dp->rst); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = to_dp(plat_data); 888c2ecf20Sopenharmony_ci int ret; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dp->pclk); 918c2ecf20Sopenharmony_ci if (ret < 0) { 928c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = rockchip_dp_pre_init(dp); 978c2ecf20Sopenharmony_ci if (ret < 0) { 988c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "failed to dp pre init %d\n", ret); 998c2ecf20Sopenharmony_ci clk_disable_unprepare(dp->pclk); 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return ret; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = to_dp(plat_data); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci clk_disable_unprepare(dp->pclk); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, 1168c2ecf20Sopenharmony_ci struct drm_connector *connector) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct drm_display_info *di = &connector->display_info; 1198c2ecf20Sopenharmony_ci /* VOP couldn't output YUV video format for eDP rightly */ 1208c2ecf20Sopenharmony_ci u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if ((di->color_formats & mask)) { 1238c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); 1248c2ecf20Sopenharmony_ci di->color_formats &= ~mask; 1258c2ecf20Sopenharmony_ci di->color_formats |= DRM_COLOR_FORMAT_RGB444; 1268c2ecf20Sopenharmony_ci di->bpc = 8; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic bool 1338c2ecf20Sopenharmony_cirockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, 1348c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 1358c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci /* do nothing */ 1388c2ecf20Sopenharmony_ci return true; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, 1428c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 1438c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci /* do nothing */ 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic 1498c2ecf20Sopenharmony_cistruct drm_crtc *rockchip_dp_drm_get_new_crtc(struct drm_encoder *encoder, 1508c2ecf20Sopenharmony_ci struct drm_atomic_state *state) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct drm_connector *connector; 1538c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci connector = drm_atomic_get_new_connector_for_encoder(state, encoder); 1568c2ecf20Sopenharmony_ci if (!connector) 1578c2ecf20Sopenharmony_ci return NULL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci conn_state = drm_atomic_get_new_connector_state(state, connector); 1608c2ecf20Sopenharmony_ci if (!conn_state) 1618c2ecf20Sopenharmony_ci return NULL; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return conn_state->crtc; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, 1678c2ecf20Sopenharmony_ci struct drm_atomic_state *state) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = to_dp(encoder); 1708c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 1718c2ecf20Sopenharmony_ci struct drm_crtc_state *old_crtc_state; 1728c2ecf20Sopenharmony_ci int ret; 1738c2ecf20Sopenharmony_ci u32 val; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci crtc = rockchip_dp_drm_get_new_crtc(encoder, state); 1768c2ecf20Sopenharmony_ci if (!crtc) 1778c2ecf20Sopenharmony_ci return; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); 1808c2ecf20Sopenharmony_ci /* Coming back from self refresh, nothing to do */ 1818c2ecf20Sopenharmony_ci if (old_crtc_state && old_crtc_state->self_refresh_active) 1828c2ecf20Sopenharmony_ci return; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); 1858c2ecf20Sopenharmony_ci if (ret < 0) 1868c2ecf20Sopenharmony_ci return; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (ret) 1898c2ecf20Sopenharmony_ci val = dp->data->lcdsel_lit; 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci val = dp->data->lcdsel_big; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dp->grfclk); 1968c2ecf20Sopenharmony_ci if (ret < 0) { 1978c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret); 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); 2028c2ecf20Sopenharmony_ci if (ret != 0) 2038c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci clk_disable_unprepare(dp->grfclk); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder, 2098c2ecf20Sopenharmony_ci struct drm_atomic_state *state) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = to_dp(encoder); 2128c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 2138c2ecf20Sopenharmony_ci struct drm_crtc_state *new_crtc_state = NULL; 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci crtc = rockchip_dp_drm_get_new_crtc(encoder, state); 2178c2ecf20Sopenharmony_ci /* No crtc means we're doing a full shutdown */ 2188c2ecf20Sopenharmony_ci if (!crtc) 2198c2ecf20Sopenharmony_ci return; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 2228c2ecf20Sopenharmony_ci /* If we're not entering self-refresh, no need to wait for vact */ 2238c2ecf20Sopenharmony_ci if (!new_crtc_state || !new_crtc_state->self_refresh_active) 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ret = rockchip_drm_wait_vact_end(crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS); 2278c2ecf20Sopenharmony_ci if (ret) 2288c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "line flag irq timed out\n"); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int 2328c2ecf20Sopenharmony_cirockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, 2338c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state, 2348c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 2378c2ecf20Sopenharmony_ci struct drm_display_info *di = &conn_state->connector->display_info; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * The hardware IC designed that VOP must output the RGB10 video 2418c2ecf20Sopenharmony_ci * format to eDP controller, and if eDP panel only support RGB8, 2428c2ecf20Sopenharmony_ci * then eDP controller should cut down the video data, not via VOP 2438c2ecf20Sopenharmony_ci * controller, that's why we need to hardcode the VOP output mode 2448c2ecf20Sopenharmony_ci * to RGA10 here. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 2488c2ecf20Sopenharmony_ci s->output_type = DRM_MODE_CONNECTOR_eDP; 2498c2ecf20Sopenharmony_ci s->output_bpc = di->bpc; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { 2558c2ecf20Sopenharmony_ci .mode_fixup = rockchip_dp_drm_encoder_mode_fixup, 2568c2ecf20Sopenharmony_ci .mode_set = rockchip_dp_drm_encoder_mode_set, 2578c2ecf20Sopenharmony_ci .atomic_enable = rockchip_dp_drm_encoder_enable, 2588c2ecf20Sopenharmony_ci .atomic_disable = rockchip_dp_drm_encoder_disable, 2598c2ecf20Sopenharmony_ci .atomic_check = rockchip_dp_drm_encoder_atomic_check, 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int rockchip_dp_of_probe(struct rockchip_dp_device *dp) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct device *dev = dp->dev; 2658c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 2688c2ecf20Sopenharmony_ci if (IS_ERR(dp->grf)) { 2698c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); 2708c2ecf20Sopenharmony_ci return PTR_ERR(dp->grf); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci dp->grfclk = devm_clk_get(dev, "grf"); 2748c2ecf20Sopenharmony_ci if (PTR_ERR(dp->grfclk) == -ENOENT) { 2758c2ecf20Sopenharmony_ci dp->grfclk = NULL; 2768c2ecf20Sopenharmony_ci } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { 2778c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 2788c2ecf20Sopenharmony_ci } else if (IS_ERR(dp->grfclk)) { 2798c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get grf clock\n"); 2808c2ecf20Sopenharmony_ci return PTR_ERR(dp->grfclk); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci dp->pclk = devm_clk_get(dev, "pclk"); 2848c2ecf20Sopenharmony_ci if (IS_ERR(dp->pclk)) { 2858c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get pclk property\n"); 2868c2ecf20Sopenharmony_ci return PTR_ERR(dp->pclk); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci dp->rst = devm_reset_control_get(dev, "dp"); 2908c2ecf20Sopenharmony_ci if (IS_ERR(dp->rst)) { 2918c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get dp reset control\n"); 2928c2ecf20Sopenharmony_ci return PTR_ERR(dp->rst); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct drm_encoder *encoder = &dp->encoder; 3018c2ecf20Sopenharmony_ci struct drm_device *drm_dev = dp->drm_dev; 3028c2ecf20Sopenharmony_ci struct device *dev = dp->dev; 3038c2ecf20Sopenharmony_ci int ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, 3068c2ecf20Sopenharmony_ci dev->of_node); 3078c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci ret = drm_simple_encoder_init(drm_dev, encoder, 3108c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_TMDS); 3118c2ecf20Sopenharmony_ci if (ret) { 3128c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize encoder with drm\n"); 3138c2ecf20Sopenharmony_ci return ret; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int rockchip_dp_bind(struct device *dev, struct device *master, 3228c2ecf20Sopenharmony_ci void *data) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = dev_get_drvdata(dev); 3258c2ecf20Sopenharmony_ci struct drm_device *drm_dev = data; 3268c2ecf20Sopenharmony_ci int ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci dp->drm_dev = drm_dev; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = rockchip_dp_drm_create_encoder(dp); 3318c2ecf20Sopenharmony_ci if (ret) { 3328c2ecf20Sopenharmony_ci DRM_ERROR("failed to create drm encoder\n"); 3338c2ecf20Sopenharmony_ci return ret; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dp->plat_data.encoder = &dp->encoder; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = analogix_dp_bind(dp->adp, drm_dev); 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci goto err_cleanup_encoder; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_cierr_cleanup_encoder: 3448c2ecf20Sopenharmony_ci dp->encoder.funcs->destroy(&dp->encoder); 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void rockchip_dp_unbind(struct device *dev, struct device *master, 3498c2ecf20Sopenharmony_ci void *data) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = dev_get_drvdata(dev); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci analogix_dp_unbind(dp->adp); 3548c2ecf20Sopenharmony_ci dp->encoder.funcs->destroy(&dp->encoder); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const struct component_ops rockchip_dp_component_ops = { 3588c2ecf20Sopenharmony_ci .bind = rockchip_dp_bind, 3598c2ecf20Sopenharmony_ci .unbind = rockchip_dp_unbind, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int rockchip_dp_probe(struct platform_device *pdev) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3658c2ecf20Sopenharmony_ci const struct rockchip_dp_chip_data *dp_data; 3668c2ecf20Sopenharmony_ci struct drm_panel *panel = NULL; 3678c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp; 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci dp_data = of_device_get_match_data(dev); 3718c2ecf20Sopenharmony_ci if (!dp_data) 3728c2ecf20Sopenharmony_ci return -ENODEV; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); 3758c2ecf20Sopenharmony_ci if (ret < 0) 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); 3798c2ecf20Sopenharmony_ci if (!dp) 3808c2ecf20Sopenharmony_ci return -ENOMEM; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci dp->dev = dev; 3838c2ecf20Sopenharmony_ci dp->adp = ERR_PTR(-ENODEV); 3848c2ecf20Sopenharmony_ci dp->data = dp_data; 3858c2ecf20Sopenharmony_ci dp->plat_data.panel = panel; 3868c2ecf20Sopenharmony_ci dp->plat_data.dev_type = dp->data->chip_type; 3878c2ecf20Sopenharmony_ci dp->plat_data.power_on_start = rockchip_dp_poweron_start; 3888c2ecf20Sopenharmony_ci dp->plat_data.power_off = rockchip_dp_powerdown; 3898c2ecf20Sopenharmony_ci dp->plat_data.get_modes = rockchip_dp_get_modes; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = rockchip_dp_of_probe(dp); 3928c2ecf20Sopenharmony_ci if (ret < 0) 3938c2ecf20Sopenharmony_ci return ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dp); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci dp->adp = analogix_dp_probe(dev, &dp->plat_data); 3988c2ecf20Sopenharmony_ci if (IS_ERR(dp->adp)) 3998c2ecf20Sopenharmony_ci return PTR_ERR(dp->adp); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ret = component_add(dev, &rockchip_dp_component_ops); 4028c2ecf20Sopenharmony_ci if (ret) 4038c2ecf20Sopenharmony_ci goto err_dp_remove; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cierr_dp_remove: 4088c2ecf20Sopenharmony_ci analogix_dp_remove(dp->adp); 4098c2ecf20Sopenharmony_ci return ret; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int rockchip_dp_remove(struct platform_device *pdev) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = platform_get_drvdata(pdev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci component_del(&pdev->dev, &rockchip_dp_component_ops); 4178c2ecf20Sopenharmony_ci analogix_dp_remove(dp->adp); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4238c2ecf20Sopenharmony_cistatic int rockchip_dp_suspend(struct device *dev) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = dev_get_drvdata(dev); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (IS_ERR(dp->adp)) 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return analogix_dp_suspend(dp->adp); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int rockchip_dp_resume(struct device *dev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct rockchip_dp_device *dp = dev_get_drvdata(dev); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (IS_ERR(dp->adp)) 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return analogix_dp_resume(dp->adp); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci#endif 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rockchip_dp_pm_ops = { 4458c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4468c2ecf20Sopenharmony_ci .suspend_late = rockchip_dp_suspend, 4478c2ecf20Sopenharmony_ci .resume_early = rockchip_dp_resume, 4488c2ecf20Sopenharmony_ci#endif 4498c2ecf20Sopenharmony_ci}; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic const struct rockchip_dp_chip_data rk3399_edp = { 4528c2ecf20Sopenharmony_ci .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, 4538c2ecf20Sopenharmony_ci .lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL), 4548c2ecf20Sopenharmony_ci .lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL), 4558c2ecf20Sopenharmony_ci .chip_type = RK3399_EDP, 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic const struct rockchip_dp_chip_data rk3288_dp = { 4598c2ecf20Sopenharmony_ci .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 4608c2ecf20Sopenharmony_ci .lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL), 4618c2ecf20Sopenharmony_ci .lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL), 4628c2ecf20Sopenharmony_ci .chip_type = RK3288_DP, 4638c2ecf20Sopenharmony_ci}; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_dp_dt_ids[] = { 4668c2ecf20Sopenharmony_ci {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, 4678c2ecf20Sopenharmony_ci {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, 4688c2ecf20Sopenharmony_ci {} 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistruct platform_driver rockchip_dp_driver = { 4738c2ecf20Sopenharmony_ci .probe = rockchip_dp_probe, 4748c2ecf20Sopenharmony_ci .remove = rockchip_dp_remove, 4758c2ecf20Sopenharmony_ci .driver = { 4768c2ecf20Sopenharmony_ci .name = "rockchip-dp", 4778c2ecf20Sopenharmony_ci .pm = &rockchip_dp_pm_ops, 4788c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(rockchip_dp_dt_ids), 4798c2ecf20Sopenharmony_ci }, 4808c2ecf20Sopenharmony_ci}; 481