diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-21 14:56:17 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-21 14:56:17 -0800 |
commit | 28eb75e178d389d325f1666e422bc13bbbb9804c (patch) | |
tree | 20417b4e798f98fc5687e80c1e0126afcf437c70 /drivers/gpu/drm/rockchip | |
parent | 071b34dcf71523a559b6c39f5d21a268a9531b50 (diff) | |
parent | a163b895077861598be48c1cf7f4a88413c28b22 (diff) |
Merge tag 'drm-next-2024-11-21' of https://gitlab.freedesktop.org/drm/kernel
Pull drm updates from Dave Airlie:
"There's a lot of rework, the panic helper support is being added to
more drivers, v3d gets support for HW superpages, scheduler
documentation, drm client and video aperture reworks, some new
MAINTAINERS added, amdgpu has the usual lots of IP refactors, Intel
has some Pantherlake enablement and xe is getting some SRIOV bits, but
just lots of stuff everywhere.
core:
- split DSC helpers from DP helpers
- clang build fixes for drm/mm test
- drop simple pipeline support for gem vram
- document submission error signaling
- move drm_rect to drm core module from kms helper
- add default client setup to most drivers
- move to video aperture helpers instead of drm ones
tests:
- new framebuffer tests
ttm:
- remove swapped and pinned BOs from TTM lru
panic:
- fix uninit spinlock
- add ABGR2101010 support
bridge:
- add TI TDP158 support
- use standard PM OPS
dma-fence:
- use read_trylock instead of read_lock to help lockdep
scheduler:
- add errno to sched start to report different errors
- add locking to drm_sched_entity_modify_sched
- improve documentation
xe:
- add drm_line_printer
- lots of refactoring
- Enable Xe2 + PES disaggregation
- add new ARL PCI ID
- SRIOV development work
- fix exec unnecessary implicit fence
- define and parse OA sync props
- forcewake refactoring
i915:
- Enable BMG/LNL ultra joiner
- Enable 10bpx + CCS scanout on ICL+, fp16/CCS on TGL+
- use DSB for plane/color mgmt
- Arrow lake PCI IDs
- lots of i915/xe display refactoring
- enable PXP GuC autoteardown
- Pantherlake (PTL) Xe3 LPD display enablement
- Allow fastset HDR infoframe changes
- write DP source OUI for non-eDP sinks
- share PCI IDs between i915 and xe
amdgpu:
- SDMA queue reset support
- SMU 13.0.6, JPEG 4.0.3 updates
- Initial runtime repartitioning support
- rework IP structs for multiple IP instances
- Fetch EDID from _DDC if available
- SMU13 zero rpm user control
- lots of fixes/cleanups
amdkfd:
- Increase event FIFO size
- add topology cap flag for per queue reset
msm:
- DPU:
- SA8775P support
- (disabled by default) MSM8917, MSM8937, MSM8953 and MSM8996 support
- Enable large framebuffer support
- Drop MSM8998 and SDM845
- DP:
- SA8775P support
- GPU:
- a7xx preemption support
- Adreno A663 support
ast:
- warn about unsupported TX chips
ivpu:
- add coredump
- add pantherlake support
rockchip:
- 4K@60Hz display enablement
- generate pll programming tables
panthor:
- add timestamp query API
- add realtime group priority
- add fdinfo support
etnaviv:
- improve handling of DMA address limits
- improve GPU hangcheck
exynos:
- Decon Exynos7870 support
mediatek:
- add OF graph support
omap:
- locking fixes
bochs:
- convert to gem/shmem from simpledrm
v3d:
- support big/super pages
- add gemfs
vc4:
- BCM2712 support refactoring
- add YUV444 format support
udmabuf:
- folio related fixes
nouveau:
- add panic support on nv50+"
* tag 'drm-next-2024-11-21' of https://gitlab.freedesktop.org/drm/kernel: (1583 commits)
drm/xe/guc: Fix dereference before NULL check
drm/amd: Fix initialization mistake for NBIO 7.7.0
Revert "drm/amd/display: parse umc_info or vram_info based on ASIC"
drm/amd/display: Fix failure to read vram info due to static BP_RESULT
drm/amdgpu: enable GTT fallback handling for dGPUs only
drm/amd/amdgpu: limit single process inside MES
drm/fourcc: add AMD_FMT_MOD_TILE_GFX9_4K_D_X
drm/amdgpu/mes12: correct kiq unmap latency
drm/amdgpu: Support vcn and jpeg error info parsing
drm/amd : Update MES API header file for v11 & v12
drm/amd/amdkfd: add/remove kfd queues on start/stop KFD scheduling
drm/amdkfd: change kfd process kref count at creation
drm/amdgpu: Cleanup shift coding style
drm/amd/amdgpu: Increase MES log buffer to dump mes scratch data
drm/amdgpu: Implement virt req_ras_err_count
drm/amdgpu: VF Query RAS Caps from Host if supported
drm/amdgpu: Add msg handlers for SRIOV RAS Telemetry
drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support
drm/amd/display: 3.2.309
drm/amd/display: Adjust VSDB parser for replay feature
...
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-reg.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 162 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 424 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 |
7 files changed, 542 insertions, 91 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 23c49e91f1cc..3ac579615749 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -2,12 +2,14 @@ config DRM_ROCKCHIP tristate "DRM Support for Rockchip" depends on DRM && ROCKCHIP_IOMMU + select DRM_CLIENT_SELECTION select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL select VIDEOMODE_HELPERS select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_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 select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI @@ -63,6 +65,14 @@ config ROCKCHIP_DW_HDMI enable HDMI on RK3288 or RK3399 based SoC, you should select this option. +config ROCKCHIP_DW_HDMI_QP + bool "Rockchip specific extensions for Synopsys DW HDMI QP" + select DRM_BRIDGE_CONNECTOR + help + This selects support for Rockchip SoC specific extensions + for the Synopsys DesignWare HDMI QP driver. If you want to + enable HDMI on RK3588 based SoC, you should select this option. + config ROCKCHIP_DW_MIPI_DSI bool "Rockchip specific extensions for Synopsys DW MIPI DSI" select GENERIC_PHY_MIPI_DPHY diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 3ff7b21c0414..3eab662a5a1d 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -11,6 +11,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o 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_INNO_HDMI) += inno_hdmi.o rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h index 441248b7a79e..c7780ae3272a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h @@ -77,7 +77,7 @@ #define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 #define SOURCE_PIF_SW_RESET 0x30834 -/* bellow registers need access by mailbox */ +/* below registers need access by mailbox */ /* source car addr */ #define SOURCE_HDTX_CAR 0x0900 #define SOURCE_DPTX_CAR 0x0904 diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 240552eb517f..96e1097f993d 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -76,6 +76,7 @@ struct rockchip_hdmi { struct rockchip_encoder encoder; const struct rockchip_hdmi_chip_data *chip_data; const struct dw_hdmi_plat_data *plat_data; + struct clk *hdmiphy_clk; struct clk *ref_clk; struct clk *grf_clk; struct dw_hdmi *hdmi; @@ -91,74 +92,70 @@ static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder) static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { - 27000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + 30666000, { + { 0x00b3, 0x0000 }, + { 0x2153, 0x0000 }, + { 0x40f3, 0x0000 }, }, }, { - 36000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + 36800000, { + { 0x00b3, 0x0000 }, + { 0x2153, 0x0000 }, + { 0x40a2, 0x0001 }, }, }, { - 40000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + 46000000, { + { 0x00b3, 0x0000 }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, }, { - 54000000, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + 61333000, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, }, { - 65000000, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + 73600000, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x4061, 0x0002 }, }, }, { - 66000000, { - { 0x013e, 0x0003}, - { 0x217e, 0x0002}, - { 0x4061, 0x0002} + 92000000, { + { 0x0072, 0x0001 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, }, }, { - 74250000, { - { 0x0072, 0x0001}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + 122666000, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, }, }, { - 83500000, { - { 0x0072, 0x0001}, + 147200000, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4064, 0x0003 }, }, }, { - 108000000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + 184000000, { + { 0x0051, 0x0002 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, }, { - 106500000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} - }, - }, { - 146250000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + 226666000, { + { 0x0040, 0x0003 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, }, { - 148500000, { - { 0x0051, 0x0003}, - { 0x214c, 0x0003}, - { 0x4064, 0x0003} + 272000000, { + { 0x0040, 0x0003 }, + { 0x214c, 0x0003 }, + { 0x5a64, 0x0003 }, }, }, { 340000000, { @@ -167,10 +164,16 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { 0x5a64, 0x0003 }, }, }, { + 600000000, { + { 0x1a40, 0x0003 }, + { 0x3b4c, 0x0003 }, + { 0x5a64, 0x0003 }, + }, + }, { ~0UL, { - { 0x00a0, 0x000a }, - { 0x2001, 0x000f }, - { 0x4002, 0x000f }, + { 0x0000, 0x0000 }, + { 0x0000, 0x0000 }, + { 0x0000, 0x0000 }, }, } }; @@ -178,31 +181,18 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { /* pixelclk bpp8 bpp10 bpp12 */ { - 40000000, { 0x0018, 0x0018, 0x0018 }, - }, { - 65000000, { 0x0028, 0x0028, 0x0028 }, - }, { - 66000000, { 0x0038, 0x0038, 0x0038 }, - }, { - 74250000, { 0x0028, 0x0038, 0x0038 }, - }, { - 83500000, { 0x0028, 0x0038, 0x0038 }, - }, { - 146250000, { 0x0038, 0x0038, 0x0038 }, - }, { - 148500000, { 0x0000, 0x0038, 0x0038 }, - }, { 600000000, { 0x0000, 0x0000, 0x0000 }, }, { - ~0UL, { 0x0000, 0x0000, 0x0000}, + ~0UL, { 0x0000, 0x0000, 0x0000 }, } }; static const struct dw_hdmi_phy_config rockchip_phy_config[] = { /*pixelclk symbol term vlev*/ { 74250000, 0x8009, 0x0004, 0x0272}, - { 148500000, 0x802b, 0x0004, 0x028d}, + { 165000000, 0x802b, 0x0004, 0x0209}, { 297000000, 0x8039, 0x0005, 0x028d}, + { 594000000, 0x8039, 0x0000, 0x019d}, { ~0UL, 0x0000, 0x0000, 0x0000} }; @@ -251,10 +241,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, const struct drm_display_mode *mode) { struct rockchip_hdmi *hdmi = data; - const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; int pclk = mode->clock * 1000; - bool exact_match = hdmi->plat_data->phy_force_vendor; - int i; if (hdmi->chip_data->max_tmds_clock && mode->clock > hdmi->chip_data->max_tmds_clock) @@ -263,26 +250,18 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data, if (hdmi->ref_clk) { int rpclk = clk_round_rate(hdmi->ref_clk, pclk); - if (abs(rpclk - pclk) > pclk / 1000) + if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000) return MODE_NOCLOCK; } - for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { - /* - * For vendor specific phys force an exact match of the pixelclock - * to preserve the original behaviour of the driver. - */ - if (exact_match && pclk == mpll_cfg[i].mpixelclock) - return MODE_OK; - /* - * The Synopsys phy can work with pixelclocks up to the value given - * in the corresponding mpll_cfg entry. - */ - if (!exact_match && pclk <= mpll_cfg[i].mpixelclock) - return MODE_OK; + if (hdmi->hdmiphy_clk) { + int rpclk = clk_round_rate(hdmi->hdmiphy_clk, pclk); + + if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000) + return MODE_NOCLOCK; } - return MODE_BAD; + return MODE_OK; } static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) @@ -502,7 +481,7 @@ 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), - .max_tmds_clock = 340000, + .max_tmds_clock = 594000, }; static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { @@ -516,7 +495,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { static struct rockchip_hdmi_chip_data rk3568_chip_data = { .lcdsel_grf_reg = -1, - .max_tmds_clock = 340000, + .max_tmds_clock = 594000, }; static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { @@ -607,6 +586,15 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return ret; } + if (hdmi->phy) { + struct of_phandle_args clkspec; + + clkspec.np = hdmi->phy->dev.of_node; + hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(hdmi->hdmiphy_clk)) + hdmi->hdmiphy_clk = NULL; + } + if (hdmi->chip_data == &rk3568_chip_data) { regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c new file mode 100644 index 000000000000..9c796ee4c303 --- /dev/null +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 Collabora Ltd. + * + * Author: Algea Cao <algea.cao@rock-chips.com> + * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> + */ + +#include <linux/clk.h> +#include <linux/gpio/consumer.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/workqueue.h> + +#include <drm/bridge/dw_hdmi_qp.h> +#include <drm/display/drm_hdmi_helper.h> +#include <drm/drm_bridge_connector.h> +#include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_simple_kms_helper.h> + +#include "rockchip_drm_drv.h" + +#define RK3588_GRF_SOC_CON2 0x0308 +#define RK3588_HDMI0_HPD_INT_MSK BIT(13) +#define RK3588_HDMI0_HPD_INT_CLR BIT(12) +#define RK3588_GRF_SOC_CON7 0x031c +#define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12) +#define RK3588_GRF_SOC_STATUS1 0x0384 +#define RK3588_HDMI0_LEVEL_INT BIT(16) +#define RK3588_GRF_VO1_CON3 0x000c +#define RK3588_SCLIN_MASK BIT(9) +#define RK3588_SDAIN_MASK BIT(10) +#define RK3588_MODE_MASK BIT(11) +#define RK3588_I2S_SEL_MASK BIT(13) +#define RK3588_GRF_VO1_CON9 0x0024 +#define RK3588_HDMI0_GRANT_SEL BIT(10) + +#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) +#define HOTPLUG_DEBOUNCE_MS 150 + +struct rockchip_hdmi_qp { + struct device *dev; + struct regmap *regmap; + struct regmap *vo_regmap; + struct rockchip_encoder encoder; + struct clk *ref_clk; + struct dw_hdmi_qp *hdmi; + struct phy *phy; + struct gpio_desc *enable_gpio; + struct delayed_work hpd_work; +}; + +static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct rockchip_hdmi_qp, encoder); +} + +static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) +{ + struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); + struct drm_crtc *crtc = encoder->crtc; + unsigned long long rate; + + /* Unconditionally switch to TMDS as FRL is not yet supported */ + gpiod_set_value(hdmi->enable_gpio, 1); + + if (crtc && crtc->state) { + rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode, + 8, HDMI_COLORSPACE_RGB); + clk_set_rate(hdmi->ref_clk, rate); + /* + * FIXME: Temporary workaround to pass pixel clock rate + * to the PHY driver until phy_configure_opts_hdmi + * becomes available in the PHY API. See also the related + * comment in rk_hdptx_phy_power_on() from + * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c + */ + phy_set_bus_width(hdmi->phy, rate / 100); + } +} + +static int +dw_hdmi_qp_rockchip_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); + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + + return 0; +} + +static const struct +drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = { + .enable = dw_hdmi_qp_rockchip_encoder_enable, + .atomic_check = dw_hdmi_qp_rockchip_encoder_atomic_check, +}; + +static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data) +{ + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; + + return phy_power_on(hdmi->phy); +} + +static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi, + void *data) +{ + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; + + phy_power_off(hdmi->phy); +} + +static enum drm_connector_status +dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) +{ + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; + u32 val; + + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); + + return val & RK3588_HDMI0_LEVEL_INT ? + connector_status_connected : connector_status_disconnected; +} + +static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) +{ + struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; + + regmap_write(hdmi->regmap, + RK3588_GRF_SOC_CON2, + HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, + RK3588_HDMI0_HPD_INT_CLR | + RK3588_HDMI0_HPD_INT_MSK)); +} + +static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = { + .init = dw_hdmi_qp_rk3588_phy_init, + .disable = dw_hdmi_qp_rk3588_phy_disable, + .read_hpd = dw_hdmi_qp_rk3588_read_hpd, + .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd, +}; + +static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work) +{ + struct rockchip_hdmi_qp *hdmi = container_of(work, + struct rockchip_hdmi_qp, + hpd_work.work); + struct drm_device *drm = hdmi->encoder.encoder.dev; + bool changed; + + if (drm) { + changed = drm_helper_hpd_irq_event(drm); + if (changed) + drm_dbg(hdmi, "connector status changed\n"); + } +} + +static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id) +{ + struct rockchip_hdmi_qp *hdmi = dev_id; + u32 intr_stat, val; + + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); + + if (intr_stat) { + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, + RK3588_HDMI0_HPD_INT_MSK); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) +{ + struct rockchip_hdmi_qp *hdmi = dev_id; + u32 intr_stat, val; + + regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); + if (!intr_stat) + return IRQ_NONE; + + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, + RK3588_HDMI0_HPD_INT_CLR); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); + + mod_delayed_work(system_wq, &hdmi->hpd_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); + + val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); + + return IRQ_HANDLED; +} + +static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = { + { .compatible = "rockchip,rk3588-dw-hdmi-qp", + .data = &rk3588_hdmi_phy_ops }, + {}, +}; +MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids); + +static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, + void *data) +{ + static const char * const clk_names[] = { + "pclk", "earc", "aud", "hdp", "hclk_vo1", + "ref" /* keep "ref" last */ + }; + struct platform_device *pdev = to_platform_device(dev); + struct dw_hdmi_qp_plat_data plat_data; + struct drm_device *drm = data; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct rockchip_hdmi_qp *hdmi; + struct clk *clk; + int ret, irq, i; + u32 val; + + if (!pdev->dev.of_node) + return -ENODEV; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + plat_data.phy_ops = of_device_get_match_data(dev); + if (!plat_data.phy_ops) + return -ENODEV; + + plat_data.phy_data = hdmi; + hdmi->dev = &pdev->dev; + + encoder = &hdmi->encoder.encoder; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); + + rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, + dev->of_node, 0, 0); + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (encoder->possible_crtcs == 0) + return -EPROBE_DEFER; + + hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(hdmi->regmap)) { + drm_err(hdmi, "Unable to get rockchip,grf\n"); + return PTR_ERR(hdmi->regmap); + } + + hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,vo-grf"); + if (IS_ERR(hdmi->vo_regmap)) { + drm_err(hdmi, "Unable to get rockchip,vo-grf\n"); + return PTR_ERR(hdmi->vo_regmap); + } + + for (i = 0; i < ARRAY_SIZE(clk_names); i++) { + clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]); + + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + if (ret != -EPROBE_DEFER) + drm_err(hdmi, "Failed to get %s clock: %d\n", + clk_names[i], ret); + return ret; + } + } + hdmi->ref_clk = clk; + + hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(hdmi->enable_gpio)) { + ret = PTR_ERR(hdmi->enable_gpio); + drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret); + return ret; + } + + hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); + if (IS_ERR(hdmi->phy)) { + ret = PTR_ERR(hdmi->phy); + if (ret != -EPROBE_DEFER) + drm_err(hdmi, "failed to get phy: %d\n", ret); + return ret; + } + + 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); + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); + + val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, + RK3588_SET_HPD_PATH_MASK); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); + + val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, + RK3588_HDMI0_GRANT_SEL); + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); + + val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); + + INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work); + + plat_data.main_irq = platform_get_irq_byname(pdev, "main"); + if (plat_data.main_irq < 0) + return plat_data.main_irq; + + irq = platform_get_irq_byname(pdev, "hpd"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(hdmi->dev, irq, + dw_hdmi_qp_rk3588_hardirq, + dw_hdmi_qp_rk3588_irq, + IRQF_SHARED, "dw-hdmi-qp-hpd", + hdmi); + if (ret) + return ret; + + drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs); + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); + + platform_set_drvdata(pdev, hdmi); + + hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); + if (IS_ERR(hdmi->hdmi)) { + ret = PTR_ERR(hdmi->hdmi); + drm_encoder_cleanup(encoder); + return ret; + } + + connector = drm_bridge_connector_init(drm, encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + drm_err(hdmi, "failed to init bridge connector: %d\n", ret); + return ret; + } + + return drm_connector_attach_encoder(connector, encoder); +} + +static void dw_hdmi_qp_rockchip_unbind(struct device *dev, + struct device *master, + void *data) +{ + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&hdmi->hpd_work); + + drm_encoder_cleanup(&hdmi->encoder.encoder); +} + +static const struct component_ops dw_hdmi_qp_rockchip_ops = { + .bind = dw_hdmi_qp_rockchip_bind, + .unbind = dw_hdmi_qp_rockchip_unbind, +}; + +static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops); +} + +static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); +} + +static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) +{ + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + 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); + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); + + val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, + RK3588_SET_HPD_PATH_MASK); + regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); + + val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, + RK3588_HDMI0_GRANT_SEL); + regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); + + dw_hdmi_qp_resume(dev, hdmi->hdmi); + + if (hdmi->encoder.encoder.dev) + drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev); + + return 0; +} + +static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) +}; + +struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { + .probe = dw_hdmi_qp_rockchip_probe, + .remove = dw_hdmi_qp_rockchip_remove, + .driver = { + .name = "dwhdmiqp-rockchip", + .pm = &dw_hdmi_qp_rockchip_pm, + .of_match_table = dw_hdmi_qp_rockchip_dt_ids, + }, +}; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 11e5d10de4d7..585355de696b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -6,6 +6,7 @@ * based on exynos_drm_drv.c */ +#include <linux/aperture.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -16,7 +17,7 @@ #include <linux/console.h> #include <linux/iommu.h> -#include <drm/drm_aperture.h> +#include <drm/drm_client_setup.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_dma.h> #include <drm/drm_gem_dma_helper.h> @@ -145,7 +146,7 @@ static int rockchip_drm_bind(struct device *dev) int ret; /* Remove existing drivers that may own the framebuffer memory. */ - ret = drm_aperture_remove_framebuffers(&rockchip_drm_driver); + ret = aperture_remove_all_conflicting_devices(rockchip_drm_driver.name); if (ret) { DRM_DEV_ERROR(dev, "Failed to remove existing framebuffers - %d.\n", @@ -195,7 +196,7 @@ static int rockchip_drm_bind(struct device *dev) if (ret) goto err_kms_helper_poll_fini; - drm_fbdev_dma_setup(drm_dev, 0); + drm_client_setup(drm_dev, NULL); return 0; err_kms_helper_poll_fini: @@ -230,6 +231,7 @@ static const struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .dumb_create = rockchip_gem_dumb_create, .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &rockchip_drm_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -358,11 +360,34 @@ static void rockchip_drm_match_remove(struct device *dev) device_link_del(link); } +/* list of preferred vop devices */ +static const char *const rockchip_drm_match_preferred[] = { + "rockchip,rk3399-vop-big", + NULL, +}; + static struct component_match *rockchip_drm_match_add(struct device *dev) { struct component_match *match = NULL; + struct device_node *port; int i; + /* add preferred vop device match before adding driver device matches */ + for (i = 0; ; i++) { + port = of_parse_phandle(dev->of_node, "ports", i); + if (!port) + break; + + if (of_device_is_available(port->parent) && + of_device_compatible_match(port->parent, + rockchip_drm_match_preferred)) + drm_of_component_match_add(dev, &match, + component_compare_of, + port->parent); + + of_node_put(port); + } + for (i = 0; i < num_rockchip_sub_drivers; i++) { struct platform_driver *drv = rockchip_sub_drivers[i]; struct device *p = NULL, *d; @@ -507,6 +532,8 @@ static int __init rockchip_drm_init(void) ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, CONFIG_ROCKCHIP_DW_HDMI); + ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver, + CONFIG_ROCKCHIP_DW_HDMI_QP); ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver, CONFIG_ROCKCHIP_DW_MIPI_DSI); ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 8d566fcd80a2..24b4ce5ceaf1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -88,6 +88,7 @@ int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder, int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); extern struct platform_driver cdn_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; extern struct platform_driver inno_hdmi_driver; extern struct platform_driver rockchip_dp_driver; |