diff mbox series

[v3,3/9] drm/rockchip: Add RK3588 DPTX output support

Message ID 20250403033748.245007-4-andyshrk@163.com (mailing list archive)
State New
Headers show
Series Add support for RK3588 DisplayPort Controller | expand

Commit Message

Andy Yan April 3, 2025, 3:37 a.m. UTC
From: Andy Yan <andy.yan@rock-chips.com>

Add driver extension for Synopsys DesignWare DPTX IP used
on Rockchip RK3588 SoC.

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Acked-by: Dmitry Baryshkov <lumag@kernel.org>

---

(no changes since v2)

Changes in v2:
- no include uapi path
- switch to drmm_encoder_init

 drivers/gpu/drm/rockchip/Kconfig            |   9 ++
 drivers/gpu/drm/rockchip/Makefile           |   1 +
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c   | 154 ++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
 5 files changed, 166 insertions(+)
 create mode 100644 drivers/gpu/drm/rockchip/dw_dp-rockchip.c

Comments

kernel test robot April 4, 2025, 9:06 a.m. UTC | #1
Hi Andy,

kernel test robot noticed the following build errors:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on robh/for-next drm-exynos/exynos-drm-next linus/master v6.14 next-20250404]
[cannot apply to drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Andy-Yan/dt-bindings-display-rockchip-Add-schema-for-RK3588-DPTX-Controller/20250403-114203
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
patch link:    https://lore.kernel.org/r/20250403033748.245007-4-andyshrk%40163.com
patch subject: [PATCH v3 3/9] drm/rockchip: Add RK3588 DPTX output support
config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20250404/202504041655.rA3EV7B8-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250404/202504041655.rA3EV7B8-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504041655.rA3EV7B8-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1599:3: error: call to undeclared function 'drm_dp_link_power_down'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    1599 |                 drm_dp_link_power_down(&dp->aux, dp->link.revision);
         |                 ^
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1617:8: error: call to undeclared function 'drm_dp_link_power_up'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    1617 |         ret = drm_dp_link_power_up(&dp->aux, dp->link.revision);
         |               ^
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1790:19: error: incompatible function pointer types initializing 'void (*)(struct drm_bridge *, struct drm_bridge_state *)' with an expression of type 'void (struct drm_bridge *, struct drm_atomic_state *)' [-Wincompatible-function-pointer-types]
    1790 |         .atomic_enable = dw_dp_bridge_atomic_enable,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-dp.c:1791:20: error: incompatible function pointer types initializing 'void (*)(struct drm_bridge *, struct drm_bridge_state *)' with an expression of type 'void (struct drm_bridge *, struct drm_atomic_state *)' [-Wincompatible-function-pointer-types]
    1791 |         .atomic_disable = dw_dp_bridge_atomic_disable,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   4 errors generated.


vim +1790 drivers/gpu/drm/bridge/synopsys/dw-dp.c

d366451bed980ac Andy Yan 2025-04-03  1593  
d366451bed980ac Andy Yan 2025-04-03  1594  static void dw_dp_link_disable(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1595  {
d366451bed980ac Andy Yan 2025-04-03  1596  	struct dw_dp_link *link = &dp->link;
d366451bed980ac Andy Yan 2025-04-03  1597  
d366451bed980ac Andy Yan 2025-04-03  1598  	if (dw_dp_hpd_detect(dp))
d366451bed980ac Andy Yan 2025-04-03 @1599  		drm_dp_link_power_down(&dp->aux, dp->link.revision);
d366451bed980ac Andy Yan 2025-04-03  1600  
d366451bed980ac Andy Yan 2025-04-03  1601  	dw_dp_phy_xmit_enable(dp, 0);
d366451bed980ac Andy Yan 2025-04-03  1602  
d366451bed980ac Andy Yan 2025-04-03  1603  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1604  
d366451bed980ac Andy Yan 2025-04-03  1605  	link->train.clock_recovered = false;
d366451bed980ac Andy Yan 2025-04-03  1606  	link->train.channel_equalized = false;
d366451bed980ac Andy Yan 2025-04-03  1607  }
d366451bed980ac Andy Yan 2025-04-03  1608  
d366451bed980ac Andy Yan 2025-04-03  1609  static int dw_dp_link_enable(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1610  {
d366451bed980ac Andy Yan 2025-04-03  1611  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1612  
d366451bed980ac Andy Yan 2025-04-03  1613  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1614  	if (ret)
d366451bed980ac Andy Yan 2025-04-03  1615  		return ret;
d366451bed980ac Andy Yan 2025-04-03  1616  
d366451bed980ac Andy Yan 2025-04-03 @1617  	ret = drm_dp_link_power_up(&dp->aux, dp->link.revision);
d366451bed980ac Andy Yan 2025-04-03  1618  	if (ret < 0)
d366451bed980ac Andy Yan 2025-04-03  1619  		return ret;
d366451bed980ac Andy Yan 2025-04-03  1620  
d366451bed980ac Andy Yan 2025-04-03  1621  	ret = dw_dp_link_train(dp);
d366451bed980ac Andy Yan 2025-04-03  1622  
d366451bed980ac Andy Yan 2025-04-03  1623  	return ret;
d366451bed980ac Andy Yan 2025-04-03  1624  }
d366451bed980ac Andy Yan 2025-04-03  1625  
d366451bed980ac Andy Yan 2025-04-03  1626  static void dw_dp_bridge_atomic_enable(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1627  				       struct drm_atomic_state *state)
d366451bed980ac Andy Yan 2025-04-03  1628  {
d366451bed980ac Andy Yan 2025-04-03  1629  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1630  	struct drm_connector *connector;
d366451bed980ac Andy Yan 2025-04-03  1631  	struct drm_connector_state *conn_state;
d366451bed980ac Andy Yan 2025-04-03  1632  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1633  
d366451bed980ac Andy Yan 2025-04-03  1634  	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
d366451bed980ac Andy Yan 2025-04-03  1635  	if (!connector) {
d366451bed980ac Andy Yan 2025-04-03  1636  		dev_err(dp->dev, "failed to get connector\n");
d366451bed980ac Andy Yan 2025-04-03  1637  		return;
d366451bed980ac Andy Yan 2025-04-03  1638  	}
d366451bed980ac Andy Yan 2025-04-03  1639  
d366451bed980ac Andy Yan 2025-04-03  1640  	conn_state = drm_atomic_get_new_connector_state(state, connector);
d366451bed980ac Andy Yan 2025-04-03  1641  	if (!conn_state) {
d366451bed980ac Andy Yan 2025-04-03  1642  		dev_err(dp->dev, "failed to get connector state\n");
d366451bed980ac Andy Yan 2025-04-03  1643  		return;
d366451bed980ac Andy Yan 2025-04-03  1644  	}
d366451bed980ac Andy Yan 2025-04-03  1645  
d366451bed980ac Andy Yan 2025-04-03  1646  	set_bit(0, dp->sdp_reg_bank);
d366451bed980ac Andy Yan 2025-04-03  1647  
d366451bed980ac Andy Yan 2025-04-03  1648  	ret = dw_dp_link_enable(dp);
d366451bed980ac Andy Yan 2025-04-03  1649  	if (ret < 0) {
d366451bed980ac Andy Yan 2025-04-03  1650  		dev_err(dp->dev, "failed to enable link: %d\n", ret);
d366451bed980ac Andy Yan 2025-04-03  1651  		return;
d366451bed980ac Andy Yan 2025-04-03  1652  	}
d366451bed980ac Andy Yan 2025-04-03  1653  
d366451bed980ac Andy Yan 2025-04-03  1654  	ret = dw_dp_video_enable(dp);
d366451bed980ac Andy Yan 2025-04-03  1655  	if (ret < 0) {
d366451bed980ac Andy Yan 2025-04-03  1656  		dev_err(dp->dev, "failed to enable video: %d\n", ret);
d366451bed980ac Andy Yan 2025-04-03  1657  		return;
d366451bed980ac Andy Yan 2025-04-03  1658  	}
d366451bed980ac Andy Yan 2025-04-03  1659  }
d366451bed980ac Andy Yan 2025-04-03  1660  
d366451bed980ac Andy Yan 2025-04-03  1661  static void dw_dp_reset(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1662  {
d366451bed980ac Andy Yan 2025-04-03  1663  	int val;
d366451bed980ac Andy Yan 2025-04-03  1664  
d366451bed980ac Andy Yan 2025-04-03  1665  	disable_irq(dp->irq);
d366451bed980ac Andy Yan 2025-04-03  1666  	regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,
d366451bed980ac Andy Yan 2025-04-03  1667  			   FIELD_PREP(CONTROLLER_RESET, 1));
d366451bed980ac Andy Yan 2025-04-03  1668  	udelay(10);
d366451bed980ac Andy Yan 2025-04-03  1669  	regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,
d366451bed980ac Andy Yan 2025-04-03  1670  			   FIELD_PREP(CONTROLLER_RESET, 0));
d366451bed980ac Andy Yan 2025-04-03  1671  
d366451bed980ac Andy Yan 2025-04-03  1672  	dw_dp_init_hw(dp);
d366451bed980ac Andy Yan 2025-04-03  1673  	regmap_read_poll_timeout(dp->regmap, DW_DP_HPD_STATUS, val,
d366451bed980ac Andy Yan 2025-04-03  1674  				 FIELD_GET(HPD_HOT_PLUG, val), 200, 200000);
d366451bed980ac Andy Yan 2025-04-03  1675  	regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG);
d366451bed980ac Andy Yan 2025-04-03  1676  	enable_irq(dp->irq);
d366451bed980ac Andy Yan 2025-04-03  1677  }
d366451bed980ac Andy Yan 2025-04-03  1678  
d366451bed980ac Andy Yan 2025-04-03  1679  static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1680  					struct drm_atomic_state *state)
d366451bed980ac Andy Yan 2025-04-03  1681  {
d366451bed980ac Andy Yan 2025-04-03  1682  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1683  
d366451bed980ac Andy Yan 2025-04-03  1684  	dw_dp_video_disable(dp);
d366451bed980ac Andy Yan 2025-04-03  1685  	dw_dp_link_disable(dp);
d366451bed980ac Andy Yan 2025-04-03  1686  	bitmap_zero(dp->sdp_reg_bank, SDP_REG_BANK_SIZE);
d366451bed980ac Andy Yan 2025-04-03  1687  	dw_dp_reset(dp);
d366451bed980ac Andy Yan 2025-04-03  1688  }
d366451bed980ac Andy Yan 2025-04-03  1689  
d366451bed980ac Andy Yan 2025-04-03  1690  static bool dw_dp_hpd_detect_link(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1691  {
d366451bed980ac Andy Yan 2025-04-03  1692  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1693  
d366451bed980ac Andy Yan 2025-04-03  1694  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1695  	if (ret < 0)
d366451bed980ac Andy Yan 2025-04-03  1696  		return false;
d366451bed980ac Andy Yan 2025-04-03  1697  	ret = dw_dp_link_parse(dp);
d366451bed980ac Andy Yan 2025-04-03  1698  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1699  
d366451bed980ac Andy Yan 2025-04-03  1700  	return !ret;
d366451bed980ac Andy Yan 2025-04-03  1701  }
d366451bed980ac Andy Yan 2025-04-03  1702  
d366451bed980ac Andy Yan 2025-04-03  1703  static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *bridge)
d366451bed980ac Andy Yan 2025-04-03  1704  {
d366451bed980ac Andy Yan 2025-04-03  1705  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1706  
d366451bed980ac Andy Yan 2025-04-03  1707  	if (!dw_dp_hpd_detect(dp))
d366451bed980ac Andy Yan 2025-04-03  1708  		return connector_status_disconnected;
d366451bed980ac Andy Yan 2025-04-03  1709  
d366451bed980ac Andy Yan 2025-04-03  1710  	if (!dw_dp_hpd_detect_link(dp))
d366451bed980ac Andy Yan 2025-04-03  1711  		return connector_status_disconnected;
d366451bed980ac Andy Yan 2025-04-03  1712  
d366451bed980ac Andy Yan 2025-04-03  1713  	return connector_status_connected;
d366451bed980ac Andy Yan 2025-04-03  1714  }
d366451bed980ac Andy Yan 2025-04-03  1715  
d366451bed980ac Andy Yan 2025-04-03  1716  static const struct drm_edid *dw_dp_bridge_edid_read(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1717  						     struct drm_connector *connector)
d366451bed980ac Andy Yan 2025-04-03  1718  {
d366451bed980ac Andy Yan 2025-04-03  1719  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1720  	const struct drm_edid *edid;
d366451bed980ac Andy Yan 2025-04-03  1721  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1722  
d366451bed980ac Andy Yan 2025-04-03  1723  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1724  	if (ret)
d366451bed980ac Andy Yan 2025-04-03  1725  		return NULL;
d366451bed980ac Andy Yan 2025-04-03  1726  
d366451bed980ac Andy Yan 2025-04-03  1727  	edid = drm_edid_read_ddc(connector, &dp->aux.ddc);
d366451bed980ac Andy Yan 2025-04-03  1728  
d366451bed980ac Andy Yan 2025-04-03  1729  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1730  
d366451bed980ac Andy Yan 2025-04-03  1731  	return edid;
d366451bed980ac Andy Yan 2025-04-03  1732  }
d366451bed980ac Andy Yan 2025-04-03  1733  
d366451bed980ac Andy Yan 2025-04-03  1734  static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1735  						    struct drm_bridge_state *bridge_state,
d366451bed980ac Andy Yan 2025-04-03  1736  						    struct drm_crtc_state *crtc_state,
d366451bed980ac Andy Yan 2025-04-03  1737  						    struct drm_connector_state *conn_state,
d366451bed980ac Andy Yan 2025-04-03  1738  						    unsigned int *num_output_fmts)
d366451bed980ac Andy Yan 2025-04-03  1739  {
d366451bed980ac Andy Yan 2025-04-03  1740  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1741  	struct dw_dp_link *link = &dp->link;
d366451bed980ac Andy Yan 2025-04-03  1742  	struct drm_display_info *di = &conn_state->connector->display_info;
d366451bed980ac Andy Yan 2025-04-03  1743  	struct drm_display_mode mode = crtc_state->mode;
d366451bed980ac Andy Yan 2025-04-03  1744  	const struct dw_dp_output_format *fmt;
d366451bed980ac Andy Yan 2025-04-03  1745  	u32 i, j = 0;
d366451bed980ac Andy Yan 2025-04-03  1746  	u32 *output_fmts;
d366451bed980ac Andy Yan 2025-04-03  1747  
d366451bed980ac Andy Yan 2025-04-03  1748  	*num_output_fmts = 0;
d366451bed980ac Andy Yan 2025-04-03  1749  
d366451bed980ac Andy Yan 2025-04-03  1750  	output_fmts = kcalloc(ARRAY_SIZE(dw_dp_output_formats), sizeof(*output_fmts), GFP_KERNEL);
d366451bed980ac Andy Yan 2025-04-03  1751  	if (!output_fmts)
d366451bed980ac Andy Yan 2025-04-03  1752  		return NULL;
d366451bed980ac Andy Yan 2025-04-03  1753  
d366451bed980ac Andy Yan 2025-04-03  1754  	for (i = 0; i < ARRAY_SIZE(dw_dp_output_formats); i++) {
d366451bed980ac Andy Yan 2025-04-03  1755  		fmt = &dw_dp_output_formats[i];
d366451bed980ac Andy Yan 2025-04-03  1756  
d366451bed980ac Andy Yan 2025-04-03  1757  		if (fmt->bpc > conn_state->max_bpc)
d366451bed980ac Andy Yan 2025-04-03  1758  			continue;
d366451bed980ac Andy Yan 2025-04-03  1759  
d366451bed980ac Andy Yan 2025-04-03  1760  		if (!(fmt->color_format & di->color_formats))
d366451bed980ac Andy Yan 2025-04-03  1761  			continue;
d366451bed980ac Andy Yan 2025-04-03  1762  
d366451bed980ac Andy Yan 2025-04-03  1763  		if (fmt->color_format == DRM_COLOR_FORMAT_YCBCR420 &&
d366451bed980ac Andy Yan 2025-04-03  1764  		    !link->vsc_sdp_supported)
d366451bed980ac Andy Yan 2025-04-03  1765  			continue;
d366451bed980ac Andy Yan 2025-04-03  1766  
d366451bed980ac Andy Yan 2025-04-03  1767  		if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420 &&
d366451bed980ac Andy Yan 2025-04-03  1768  		    drm_mode_is_420_only(di, &mode))
d366451bed980ac Andy Yan 2025-04-03  1769  			continue;
d366451bed980ac Andy Yan 2025-04-03  1770  
d366451bed980ac Andy Yan 2025-04-03  1771  		if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->rate))
d366451bed980ac Andy Yan 2025-04-03  1772  			continue;
d366451bed980ac Andy Yan 2025-04-03  1773  
d366451bed980ac Andy Yan 2025-04-03  1774  		output_fmts[j++] = fmt->bus_format;
d366451bed980ac Andy Yan 2025-04-03  1775  	}
d366451bed980ac Andy Yan 2025-04-03  1776  
d366451bed980ac Andy Yan 2025-04-03  1777  	*num_output_fmts = j;
d366451bed980ac Andy Yan 2025-04-03  1778  
d366451bed980ac Andy Yan 2025-04-03  1779  	return output_fmts;
d366451bed980ac Andy Yan 2025-04-03  1780  }
d366451bed980ac Andy Yan 2025-04-03  1781  
d366451bed980ac Andy Yan 2025-04-03  1782  static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
d366451bed980ac Andy Yan 2025-04-03  1783  	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
d366451bed980ac Andy Yan 2025-04-03  1784  	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
d366451bed980ac Andy Yan 2025-04-03  1785  	.atomic_reset = drm_atomic_helper_bridge_reset,
d366451bed980ac Andy Yan 2025-04-03  1786  	.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
d366451bed980ac Andy Yan 2025-04-03  1787  	.atomic_get_output_bus_fmts = dw_dp_bridge_atomic_get_output_bus_fmts,
d366451bed980ac Andy Yan 2025-04-03  1788  	.atomic_check = dw_dp_bridge_atomic_check,
d366451bed980ac Andy Yan 2025-04-03  1789  	.mode_valid = dw_dp_bridge_mode_valid,
d366451bed980ac Andy Yan 2025-04-03 @1790  	.atomic_enable = dw_dp_bridge_atomic_enable,
d366451bed980ac Andy Yan 2025-04-03  1791  	.atomic_disable = dw_dp_bridge_atomic_disable,
d366451bed980ac Andy Yan 2025-04-03  1792  	.detect = dw_dp_bridge_detect,
d366451bed980ac Andy Yan 2025-04-03  1793  	.edid_read = dw_dp_bridge_edid_read,
d366451bed980ac Andy Yan 2025-04-03  1794  };
d366451bed980ac Andy Yan 2025-04-03  1795
kernel test robot April 4, 2025, 12:11 p.m. UTC | #2
Hi Andy,

kernel test robot noticed the following build errors:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on robh/for-next drm-exynos/exynos-drm-next linus/master v6.14 next-20250404]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Andy-Yan/dt-bindings-display-rockchip-Add-schema-for-RK3588-DPTX-Controller/20250403-114203
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
patch link:    https://lore.kernel.org/r/20250403033748.245007-4-andyshrk%40163.com
patch subject: [PATCH v3 3/9] drm/rockchip: Add RK3588 DPTX output support
config: s390-allyesconfig (https://download.01.org/0day-ci/archive/20250404/202504041920.g5XTp8Xp-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250404/202504041920.g5XTp8Xp-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504041920.g5XTp8Xp-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/gpu/drm/bridge/synopsys/dw-dp.c: In function 'dw_dp_link_disable':
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1599:17: error: implicit declaration of function 'drm_dp_link_power_down' [-Wimplicit-function-declaration]
    1599 |                 drm_dp_link_power_down(&dp->aux, dp->link.revision);
         |                 ^~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-dp.c: In function 'dw_dp_link_enable':
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1617:15: error: implicit declaration of function 'drm_dp_link_power_up' [-Wimplicit-function-declaration]
    1617 |         ret = drm_dp_link_power_up(&dp->aux, dp->link.revision);
         |               ^~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-dp.c: At top level:
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c:1790:26: error: initialization of 'void (*)(struct drm_bridge *, struct drm_bridge_state *)' from incompatible pointer type 'void (*)(struct drm_bridge *, struct drm_atomic_state *)' [-Wincompatible-pointer-types]
    1790 |         .atomic_enable = dw_dp_bridge_atomic_enable,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-dp.c:1790:26: note: (near initialization for 'dw_dp_bridge_funcs.atomic_enable')
   drivers/gpu/drm/bridge/synopsys/dw-dp.c:1791:27: error: initialization of 'void (*)(struct drm_bridge *, struct drm_bridge_state *)' from incompatible pointer type 'void (*)(struct drm_bridge *, struct drm_atomic_state *)' [-Wincompatible-pointer-types]
    1791 |         .atomic_disable = dw_dp_bridge_atomic_disable,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-dp.c:1791:27: note: (near initialization for 'dw_dp_bridge_funcs.atomic_disable')


vim +1790 drivers/gpu/drm/bridge/synopsys/dw-dp.c

d366451bed980ac Andy Yan 2025-04-03  1593  
d366451bed980ac Andy Yan 2025-04-03  1594  static void dw_dp_link_disable(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1595  {
d366451bed980ac Andy Yan 2025-04-03  1596  	struct dw_dp_link *link = &dp->link;
d366451bed980ac Andy Yan 2025-04-03  1597  
d366451bed980ac Andy Yan 2025-04-03  1598  	if (dw_dp_hpd_detect(dp))
d366451bed980ac Andy Yan 2025-04-03 @1599  		drm_dp_link_power_down(&dp->aux, dp->link.revision);
d366451bed980ac Andy Yan 2025-04-03  1600  
d366451bed980ac Andy Yan 2025-04-03  1601  	dw_dp_phy_xmit_enable(dp, 0);
d366451bed980ac Andy Yan 2025-04-03  1602  
d366451bed980ac Andy Yan 2025-04-03  1603  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1604  
d366451bed980ac Andy Yan 2025-04-03  1605  	link->train.clock_recovered = false;
d366451bed980ac Andy Yan 2025-04-03  1606  	link->train.channel_equalized = false;
d366451bed980ac Andy Yan 2025-04-03  1607  }
d366451bed980ac Andy Yan 2025-04-03  1608  
d366451bed980ac Andy Yan 2025-04-03  1609  static int dw_dp_link_enable(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1610  {
d366451bed980ac Andy Yan 2025-04-03  1611  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1612  
d366451bed980ac Andy Yan 2025-04-03  1613  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1614  	if (ret)
d366451bed980ac Andy Yan 2025-04-03  1615  		return ret;
d366451bed980ac Andy Yan 2025-04-03  1616  
d366451bed980ac Andy Yan 2025-04-03 @1617  	ret = drm_dp_link_power_up(&dp->aux, dp->link.revision);
d366451bed980ac Andy Yan 2025-04-03  1618  	if (ret < 0)
d366451bed980ac Andy Yan 2025-04-03  1619  		return ret;
d366451bed980ac Andy Yan 2025-04-03  1620  
d366451bed980ac Andy Yan 2025-04-03  1621  	ret = dw_dp_link_train(dp);
d366451bed980ac Andy Yan 2025-04-03  1622  
d366451bed980ac Andy Yan 2025-04-03  1623  	return ret;
d366451bed980ac Andy Yan 2025-04-03  1624  }
d366451bed980ac Andy Yan 2025-04-03  1625  
d366451bed980ac Andy Yan 2025-04-03  1626  static void dw_dp_bridge_atomic_enable(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1627  				       struct drm_atomic_state *state)
d366451bed980ac Andy Yan 2025-04-03  1628  {
d366451bed980ac Andy Yan 2025-04-03  1629  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1630  	struct drm_connector *connector;
d366451bed980ac Andy Yan 2025-04-03  1631  	struct drm_connector_state *conn_state;
d366451bed980ac Andy Yan 2025-04-03  1632  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1633  
d366451bed980ac Andy Yan 2025-04-03  1634  	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
d366451bed980ac Andy Yan 2025-04-03  1635  	if (!connector) {
d366451bed980ac Andy Yan 2025-04-03  1636  		dev_err(dp->dev, "failed to get connector\n");
d366451bed980ac Andy Yan 2025-04-03  1637  		return;
d366451bed980ac Andy Yan 2025-04-03  1638  	}
d366451bed980ac Andy Yan 2025-04-03  1639  
d366451bed980ac Andy Yan 2025-04-03  1640  	conn_state = drm_atomic_get_new_connector_state(state, connector);
d366451bed980ac Andy Yan 2025-04-03  1641  	if (!conn_state) {
d366451bed980ac Andy Yan 2025-04-03  1642  		dev_err(dp->dev, "failed to get connector state\n");
d366451bed980ac Andy Yan 2025-04-03  1643  		return;
d366451bed980ac Andy Yan 2025-04-03  1644  	}
d366451bed980ac Andy Yan 2025-04-03  1645  
d366451bed980ac Andy Yan 2025-04-03  1646  	set_bit(0, dp->sdp_reg_bank);
d366451bed980ac Andy Yan 2025-04-03  1647  
d366451bed980ac Andy Yan 2025-04-03  1648  	ret = dw_dp_link_enable(dp);
d366451bed980ac Andy Yan 2025-04-03  1649  	if (ret < 0) {
d366451bed980ac Andy Yan 2025-04-03  1650  		dev_err(dp->dev, "failed to enable link: %d\n", ret);
d366451bed980ac Andy Yan 2025-04-03  1651  		return;
d366451bed980ac Andy Yan 2025-04-03  1652  	}
d366451bed980ac Andy Yan 2025-04-03  1653  
d366451bed980ac Andy Yan 2025-04-03  1654  	ret = dw_dp_video_enable(dp);
d366451bed980ac Andy Yan 2025-04-03  1655  	if (ret < 0) {
d366451bed980ac Andy Yan 2025-04-03  1656  		dev_err(dp->dev, "failed to enable video: %d\n", ret);
d366451bed980ac Andy Yan 2025-04-03  1657  		return;
d366451bed980ac Andy Yan 2025-04-03  1658  	}
d366451bed980ac Andy Yan 2025-04-03  1659  }
d366451bed980ac Andy Yan 2025-04-03  1660  
d366451bed980ac Andy Yan 2025-04-03  1661  static void dw_dp_reset(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1662  {
d366451bed980ac Andy Yan 2025-04-03  1663  	int val;
d366451bed980ac Andy Yan 2025-04-03  1664  
d366451bed980ac Andy Yan 2025-04-03  1665  	disable_irq(dp->irq);
d366451bed980ac Andy Yan 2025-04-03  1666  	regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,
d366451bed980ac Andy Yan 2025-04-03  1667  			   FIELD_PREP(CONTROLLER_RESET, 1));
d366451bed980ac Andy Yan 2025-04-03  1668  	udelay(10);
d366451bed980ac Andy Yan 2025-04-03  1669  	regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,
d366451bed980ac Andy Yan 2025-04-03  1670  			   FIELD_PREP(CONTROLLER_RESET, 0));
d366451bed980ac Andy Yan 2025-04-03  1671  
d366451bed980ac Andy Yan 2025-04-03  1672  	dw_dp_init_hw(dp);
d366451bed980ac Andy Yan 2025-04-03  1673  	regmap_read_poll_timeout(dp->regmap, DW_DP_HPD_STATUS, val,
d366451bed980ac Andy Yan 2025-04-03  1674  				 FIELD_GET(HPD_HOT_PLUG, val), 200, 200000);
d366451bed980ac Andy Yan 2025-04-03  1675  	regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG);
d366451bed980ac Andy Yan 2025-04-03  1676  	enable_irq(dp->irq);
d366451bed980ac Andy Yan 2025-04-03  1677  }
d366451bed980ac Andy Yan 2025-04-03  1678  
d366451bed980ac Andy Yan 2025-04-03  1679  static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1680  					struct drm_atomic_state *state)
d366451bed980ac Andy Yan 2025-04-03  1681  {
d366451bed980ac Andy Yan 2025-04-03  1682  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1683  
d366451bed980ac Andy Yan 2025-04-03  1684  	dw_dp_video_disable(dp);
d366451bed980ac Andy Yan 2025-04-03  1685  	dw_dp_link_disable(dp);
d366451bed980ac Andy Yan 2025-04-03  1686  	bitmap_zero(dp->sdp_reg_bank, SDP_REG_BANK_SIZE);
d366451bed980ac Andy Yan 2025-04-03  1687  	dw_dp_reset(dp);
d366451bed980ac Andy Yan 2025-04-03  1688  }
d366451bed980ac Andy Yan 2025-04-03  1689  
d366451bed980ac Andy Yan 2025-04-03  1690  static bool dw_dp_hpd_detect_link(struct dw_dp *dp)
d366451bed980ac Andy Yan 2025-04-03  1691  {
d366451bed980ac Andy Yan 2025-04-03  1692  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1693  
d366451bed980ac Andy Yan 2025-04-03  1694  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1695  	if (ret < 0)
d366451bed980ac Andy Yan 2025-04-03  1696  		return false;
d366451bed980ac Andy Yan 2025-04-03  1697  	ret = dw_dp_link_parse(dp);
d366451bed980ac Andy Yan 2025-04-03  1698  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1699  
d366451bed980ac Andy Yan 2025-04-03  1700  	return !ret;
d366451bed980ac Andy Yan 2025-04-03  1701  }
d366451bed980ac Andy Yan 2025-04-03  1702  
d366451bed980ac Andy Yan 2025-04-03  1703  static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *bridge)
d366451bed980ac Andy Yan 2025-04-03  1704  {
d366451bed980ac Andy Yan 2025-04-03  1705  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1706  
d366451bed980ac Andy Yan 2025-04-03  1707  	if (!dw_dp_hpd_detect(dp))
d366451bed980ac Andy Yan 2025-04-03  1708  		return connector_status_disconnected;
d366451bed980ac Andy Yan 2025-04-03  1709  
d366451bed980ac Andy Yan 2025-04-03  1710  	if (!dw_dp_hpd_detect_link(dp))
d366451bed980ac Andy Yan 2025-04-03  1711  		return connector_status_disconnected;
d366451bed980ac Andy Yan 2025-04-03  1712  
d366451bed980ac Andy Yan 2025-04-03  1713  	return connector_status_connected;
d366451bed980ac Andy Yan 2025-04-03  1714  }
d366451bed980ac Andy Yan 2025-04-03  1715  
d366451bed980ac Andy Yan 2025-04-03  1716  static const struct drm_edid *dw_dp_bridge_edid_read(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1717  						     struct drm_connector *connector)
d366451bed980ac Andy Yan 2025-04-03  1718  {
d366451bed980ac Andy Yan 2025-04-03  1719  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1720  	const struct drm_edid *edid;
d366451bed980ac Andy Yan 2025-04-03  1721  	int ret;
d366451bed980ac Andy Yan 2025-04-03  1722  
d366451bed980ac Andy Yan 2025-04-03  1723  	ret = phy_power_on(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1724  	if (ret)
d366451bed980ac Andy Yan 2025-04-03  1725  		return NULL;
d366451bed980ac Andy Yan 2025-04-03  1726  
d366451bed980ac Andy Yan 2025-04-03  1727  	edid = drm_edid_read_ddc(connector, &dp->aux.ddc);
d366451bed980ac Andy Yan 2025-04-03  1728  
d366451bed980ac Andy Yan 2025-04-03  1729  	phy_power_off(dp->phy);
d366451bed980ac Andy Yan 2025-04-03  1730  
d366451bed980ac Andy Yan 2025-04-03  1731  	return edid;
d366451bed980ac Andy Yan 2025-04-03  1732  }
d366451bed980ac Andy Yan 2025-04-03  1733  
d366451bed980ac Andy Yan 2025-04-03  1734  static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
d366451bed980ac Andy Yan 2025-04-03  1735  						    struct drm_bridge_state *bridge_state,
d366451bed980ac Andy Yan 2025-04-03  1736  						    struct drm_crtc_state *crtc_state,
d366451bed980ac Andy Yan 2025-04-03  1737  						    struct drm_connector_state *conn_state,
d366451bed980ac Andy Yan 2025-04-03  1738  						    unsigned int *num_output_fmts)
d366451bed980ac Andy Yan 2025-04-03  1739  {
d366451bed980ac Andy Yan 2025-04-03  1740  	struct dw_dp *dp = bridge_to_dp(bridge);
d366451bed980ac Andy Yan 2025-04-03  1741  	struct dw_dp_link *link = &dp->link;
d366451bed980ac Andy Yan 2025-04-03  1742  	struct drm_display_info *di = &conn_state->connector->display_info;
d366451bed980ac Andy Yan 2025-04-03  1743  	struct drm_display_mode mode = crtc_state->mode;
d366451bed980ac Andy Yan 2025-04-03  1744  	const struct dw_dp_output_format *fmt;
d366451bed980ac Andy Yan 2025-04-03  1745  	u32 i, j = 0;
d366451bed980ac Andy Yan 2025-04-03  1746  	u32 *output_fmts;
d366451bed980ac Andy Yan 2025-04-03  1747  
d366451bed980ac Andy Yan 2025-04-03  1748  	*num_output_fmts = 0;
d366451bed980ac Andy Yan 2025-04-03  1749  
d366451bed980ac Andy Yan 2025-04-03  1750  	output_fmts = kcalloc(ARRAY_SIZE(dw_dp_output_formats), sizeof(*output_fmts), GFP_KERNEL);
d366451bed980ac Andy Yan 2025-04-03  1751  	if (!output_fmts)
d366451bed980ac Andy Yan 2025-04-03  1752  		return NULL;
d366451bed980ac Andy Yan 2025-04-03  1753  
d366451bed980ac Andy Yan 2025-04-03  1754  	for (i = 0; i < ARRAY_SIZE(dw_dp_output_formats); i++) {
d366451bed980ac Andy Yan 2025-04-03  1755  		fmt = &dw_dp_output_formats[i];
d366451bed980ac Andy Yan 2025-04-03  1756  
d366451bed980ac Andy Yan 2025-04-03  1757  		if (fmt->bpc > conn_state->max_bpc)
d366451bed980ac Andy Yan 2025-04-03  1758  			continue;
d366451bed980ac Andy Yan 2025-04-03  1759  
d366451bed980ac Andy Yan 2025-04-03  1760  		if (!(fmt->color_format & di->color_formats))
d366451bed980ac Andy Yan 2025-04-03  1761  			continue;
d366451bed980ac Andy Yan 2025-04-03  1762  
d366451bed980ac Andy Yan 2025-04-03  1763  		if (fmt->color_format == DRM_COLOR_FORMAT_YCBCR420 &&
d366451bed980ac Andy Yan 2025-04-03  1764  		    !link->vsc_sdp_supported)
d366451bed980ac Andy Yan 2025-04-03  1765  			continue;
d366451bed980ac Andy Yan 2025-04-03  1766  
d366451bed980ac Andy Yan 2025-04-03  1767  		if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420 &&
d366451bed980ac Andy Yan 2025-04-03  1768  		    drm_mode_is_420_only(di, &mode))
d366451bed980ac Andy Yan 2025-04-03  1769  			continue;
d366451bed980ac Andy Yan 2025-04-03  1770  
d366451bed980ac Andy Yan 2025-04-03  1771  		if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->rate))
d366451bed980ac Andy Yan 2025-04-03  1772  			continue;
d366451bed980ac Andy Yan 2025-04-03  1773  
d366451bed980ac Andy Yan 2025-04-03  1774  		output_fmts[j++] = fmt->bus_format;
d366451bed980ac Andy Yan 2025-04-03  1775  	}
d366451bed980ac Andy Yan 2025-04-03  1776  
d366451bed980ac Andy Yan 2025-04-03  1777  	*num_output_fmts = j;
d366451bed980ac Andy Yan 2025-04-03  1778  
d366451bed980ac Andy Yan 2025-04-03  1779  	return output_fmts;
d366451bed980ac Andy Yan 2025-04-03  1780  }
d366451bed980ac Andy Yan 2025-04-03  1781  
d366451bed980ac Andy Yan 2025-04-03  1782  static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
d366451bed980ac Andy Yan 2025-04-03  1783  	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
d366451bed980ac Andy Yan 2025-04-03  1784  	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
d366451bed980ac Andy Yan 2025-04-03  1785  	.atomic_reset = drm_atomic_helper_bridge_reset,
d366451bed980ac Andy Yan 2025-04-03  1786  	.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
d366451bed980ac Andy Yan 2025-04-03  1787  	.atomic_get_output_bus_fmts = dw_dp_bridge_atomic_get_output_bus_fmts,
d366451bed980ac Andy Yan 2025-04-03  1788  	.atomic_check = dw_dp_bridge_atomic_check,
d366451bed980ac Andy Yan 2025-04-03  1789  	.mode_valid = dw_dp_bridge_mode_valid,
d366451bed980ac Andy Yan 2025-04-03 @1790  	.atomic_enable = dw_dp_bridge_atomic_enable,
d366451bed980ac Andy Yan 2025-04-03  1791  	.atomic_disable = dw_dp_bridge_atomic_disable,
d366451bed980ac Andy Yan 2025-04-03  1792  	.detect = dw_dp_bridge_detect,
d366451bed980ac Andy Yan 2025-04-03  1793  	.edid_read = dw_dp_bridge_edid_read,
d366451bed980ac Andy Yan 2025-04-03  1794  };
d366451bed980ac Andy Yan 2025-04-03  1795
diff mbox series

Patch

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 26c4410b2407c..00315cc6be5a8 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -8,6 +8,7 @@  config DRM_ROCKCHIP
 	select DRM_PANEL
 	select VIDEOMODE_HELPERS
 	select DRM_ANALOGIX_DP 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
@@ -58,6 +59,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 2b867cebbc121..097f062399c7a 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/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
new file mode 100644
index 0000000000000..5ff8a6a54997e
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -0,0 +1,154 @@ 
+// 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 inline struct rockchip_dw_dp *encoder_to_dp(struct drm_encoder *encoder)
+{
+	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+	return container_of(rkencoder, struct rockchip_dw_dp, 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 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;
+	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/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index ed88788e04dd2..687bb7b252e8e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -531,6 +531,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 c183e82a42a51..2e86ad00979c4 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;