diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-22 18:28:03 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-22 18:28:03 -0800 |
commit | a5c95ca18a98d742d0a4a04063c32556b5b66378 (patch) | |
tree | fdd897b23a1c45b3d03bd1e75e5df42057f339d1 /drivers/gpu/drm/bridge | |
parent | 307e14c039063f0c9bd7a18a7add8f940580dcc9 (diff) | |
parent | a48bba98380cb0b43dcd01d276c7efc282e3c33f (diff) | |
download | linux-stable-a5c95ca18a98d742d0a4a04063c32556b5b66378.tar.gz linux-stable-a5c95ca18a98d742d0a4a04063c32556b5b66378.tar.bz2 linux-stable-a5c95ca18a98d742d0a4a04063c32556b5b66378.zip |
Merge tag 'drm-next-2023-02-23' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"There are a bunch of changes all over in the usual places.
Highlights:
- habanalabs moves from misc to accel
- first accel driver for Intel VPU (Versatile Processing Unit)
inference engine
- dropped all the ancient legacy DRI1 drivers. I think it's been at
least 10 years since anyone has heard about these.
- Intel DG2 updates and prelim Meteorlake enablement
- etnaviv adds support for Versilicon NPU device (a GPU like engine
with inference accelerators)
Detailed summary:
Removals:
- remove legacy dri1 drivers: i810, mga, r128, savage, sis, tdfx, via
New driver:
- intel VPU accelerator driver
- habanalabs comes via drm tree now
drm/core:
- use drm_dbg_ helpers in several places
- Document defaults for CRTC backgrounds
- Document use of drm_minor
edid:
- improve mode parsing and refactoring
connector:
- support analog TV mode property
media:
- add some common formats
udmabuf:
- add vmap/vunmap methods
fourcc:
- add XRGB1555 and RGB565 formats
- document open source user waiver
firmware:
- fix color-format selection for system framebuffer
format-helper:
- Add conversion from XRGB8888 to various sysfb formats
- Make XRGB8888 the only driver-emulated legacy format
- Add conversion from XRGB8888 to XBGR8888 and ABGR8888
fb-helper:
- fix preferred depth and bpp values across drivers
- Avoid blank consoles from selecting an incorrect color format
probe-helper:
- Enable/disable HPD on connectors
scheduler:
- Fix lockup in drm_sched_entity_kill()
- Deprecate drm_sched_resubmit_jobs()
bridge:
- remove unused functions
- implement i2c probe_new in various drivers
- ite-it6505: Locking fixes, Cache EDID data
- ite-it66121: Support IT6610 chip
- lontium-tl9611: Fix HDMI on DragonBoard 845c
- parade-ps8640: Use atomic bridge functions
- Support i.MX93 LDB plus DT bindings
debugfs:
- add per device helpers and convert drivers
displayport:
- mst fixes
- add DP adaptive sync DPCD definitions
fbdev:
- always pick 32bpp as default
- remove some unused code
simpledrm:
- support system memory framebuffers
panel:
- add orientation quirks for Lenovo Yoga Tab 3 X90F and DynaBook K50
- Use ktime_get_boottime() to measure power-down delay
- Fix auto-suspend delay
- Visionox VTDR6130 AMOLED DSI
- Support Himax HX8394
- Convert many drivers to common generic DSI write-sequence helper
- AUO A030JTN01
ttm:
- drop bo wait wrapper
- fix MIPS build
habanalabs:
- moved driver to accel subsystem
- gaudi2 decoder error improvement
- more trace events
- Gaudi2 abrupt reset by firmware support
- add uAPI to flush memory transactions
- add uAPI to pass through userspace reqs to fw
- remove dma-buf export by handle
amdgpu:
- add new INFO queries for peak and min sclk/mclk for profile modes
- Add PCIe info to the INFO IOCTL
- secure display support for multiple displays
- DML optimizations
- DCN 3.2 updates
- PSR updates
- DP 2.1 updates
- SR-IOV RAS updates
- VCN RAS support
- SMU 13.x updates
- Switch 1 element arrays to flexible arrays
- Add RAS support for DF 4.3
- Stack size improvements
- S0ix rework
- Allow 0 as a vram limit on APUs
- Handle profiling modes for SMU13.x
- Fix possible segfault in failure case
- Rework FW requests to happen in early_init for all IPs so that we
don't lose the sbios console if FW is missing
- Fix power reporting on certain firmwares for CZN/RN
- Allow S0ix without BIOS support
- Enable freesync over PCon
- Re-enable the AGP aperture on GMC 11.x
amdkfd:
- Error handling fixes
- PASID fixes
- Fix for cleared VRAM BOs
- Fix cleanup if GPUVM creation fails
- Memory accounting fix
- Use resource_size rather than open codeing it
- GC11 mGPU fix
radeon:
- Switch 1 element arrays to flexible arrays
- Fix memory leak on shutdown
- move to new logging
i915:
- Meteorlake display/OA/GSC fw/workarounds enabling
- DP MST DSC support
- Gamma/degamma readout support for the state checker
- Enable SDP split support for DP 2.0
- Add probe blocking support to i915.force_probe parameter
- Enable Xe HP 4tile support
- Avoid display direct calls to uncore
- Fix HuC delayed load memory leaks
- Add DG2 workarounds Wa_18018764978 and Wa_18019271663
- Improve suspend / resume times with VT-d scanout workaround active
- Fix DG2 visual corruption on small BAR systems by not forgetting to
copy CCS aux state
- Fix TLB invalidation for Gen12.50 video and compute engines
- Enable HF-EEODB by switching HDMI, DP and LVDS to use struct
drm_edid
- Start using unversioned DMC firmware paths for new platforms
- ELD refactor: Stop using hardware buffer, precompute ELD
- lots of display code refactoring
nouveau:
- drop legacy ioctl support
- replace 0-sized array
msm:
- dpu/dsi/mdss: Support for SM8350, SM8450 SM8550 and SC8280XP platform
- Added bindings for SM8150
- dpu: Partial support for DSC on SM8150 and SM8250
- dpu: Fixed color transformation matrix being lost on suspend/resume
- dp: Support SDM845 and SC8280XP platforms
- dp: Support for limiting DP link rate via DT property
- dsi: Validate display modes according to the DSI OPP table
- dsi: DSI PHY support for the SM6375 platform
- Add MSM_SUBMIT_BO_NO_IMPLICI
- a2xx: Support to load legacy firmware
- a6xx: GPU devcore dump updates for a650/a660
- GPU devfreq tuning and fixes
- Turn 8960 HDMI PHY into clock provider,
- Make 8960 HDMI PHY use PXO clock from DT
etnaviv:
- experimental versilicon NPU support
- report GPU load via fdinfo format
- MMU fault message improvements
tegra:
- rework syncpoint interrupt
mediatek:
- DSI timing fix
- fix config deps
ast:
- various fixes
exynos:
- restore bridge chain order fixes
gud:
- convert to shadow plane buffers
- perform flushing synchronously during atomic update
- Use new debugfs helpers
arm/hdlcd:
- Use new debugfs helper
ili9486:
- Support 16-bit pixel data
imx:
- Split off IPUv3 driver
mipi-dbi:
- convert to DRM shadow-plane helpers
- rsp driver changes
- Support separate I/O-voltage supply
mxsfb:
- Depend on ARCH_MXS or ARCH_MXC
sun4i:
- convert to new TV mode property
vc4:
- convert to new TV mode property
- kunit tests
- Support RGB565 and RGB666 formats
- convert dsi driver to bridge
- Various HVS an CRTC fixes
v3d:
- Do not opencode drm_gem_object_lookup()
virtio:
- improve tracing
vkms:
- support small cursors in IGT tests
- Fix SEGFAULT from incorrect GEM-buffer mapping
rcar-du:
- fixes and improvements"
* tag 'drm-next-2023-02-23' of git://anongit.freedesktop.org/drm/drm: (1455 commits)
msm/fbdev: fix unused variable warning with clang.
drm/fb-helper: Remove drm_fb_helper_unprepare() from drm_fb_helper_fini()
dma-buf: make kobj_type structure constant
drm/shmem-helper: Fix locking for drm_gem_shmem_get_pages_sgt()
drm/amd/display: disable SubVP + DRR to prevent underflow
drm/amd/display: Fail atomic_check early on normalize_zpos error
drm/amd/pm: avoid unaligned access warnings
drm/amd/display: avoid unaligned access warnings
drm/amd/display: Remove duplicate/repeating expressions
drm/amd/display: Remove duplicate/repeating expression
drm/amd/display: Make variables declaration inside ifdef guard
drm/amd/display: Fix excess arguments on kernel-doc
drm/amd/display: Add previously missing includes
drm/amd/amdgpu: Add function prototypes to headers
drm/amd/display: Add function prototypes to headers
drm/amd/display: Turn global functions into static
drm/amd/display: remove unused _calculate_degamma_curve function
drm/amd/display: remove unused func declaration from resource headers
drm/amd/display: unset initial value for tf since it's never used
drm/amd/display: camel case cleanup in color_gamma file
...
Diffstat (limited to 'drivers/gpu/drm/bridge')
37 files changed, 792 insertions, 580 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 57946d80b02d..8b2226f72b24 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -15,17 +15,6 @@ config DRM_PANEL_BRIDGE menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE -config DRM_CDNS_DSI - tristate "Cadence DPI/DSI bridge" - select DRM_KMS_HELPER - select DRM_MIPI_DSI - select DRM_PANEL_BRIDGE - select GENERIC_PHY_MIPI_DPHY - depends on OF - help - Support Cadence DPI to DSI bridge. This is an internal - bridge and is meant to be directly embedded in a SoC. - config DRM_CHIPONE_ICN6211 tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 1884803c6860..52f6e8b4a821 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index e7a6e456ed0d..ddceafa7b637 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1185,8 +1185,9 @@ static int adv7511_parse_dt(struct device_node *np, return 0; } -static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int adv7511_probe(struct i2c_client *i2c) { + const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct adv7511_link_config link_config; struct adv7511 *adv7511; struct device *dev = &i2c->dev; @@ -1392,7 +1393,7 @@ static struct i2c_driver adv7511_driver = { .of_match_table = adv7511_of_ids, }, .id_table = adv7511_i2c_ids, - .probe = adv7511_probe, + .probe_new = adv7511_probe, .remove = adv7511_remove, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 660a54857929..3577c532abb4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -22,7 +22,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -692,8 +691,7 @@ static bool anx6345_get_chip_id(struct anx6345 *anx6345) return false; } -static int anx6345_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int anx6345_i2c_probe(struct i2c_client *client) { struct anx6345 *anx6345; struct device *dev; @@ -817,7 +815,7 @@ static struct i2c_driver anx6345_driver = { .name = "anx6345", .of_match_table = of_match_ptr(anx6345_match_table), }, - .probe = anx6345_i2c_probe, + .probe_new = anx6345_i2c_probe, .remove = anx6345_i2c_remove, .id_table = anx6345_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 5997049fde5b..a3a38bbe2786 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1214,8 +1214,7 @@ static const u16 anx78xx_chipid_list[] = { 0x7818, }; -static int anx78xx_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int anx78xx_i2c_probe(struct i2c_client *client) { struct anx78xx *anx78xx; struct anx78xx_platform_data *pdata; @@ -1390,7 +1389,7 @@ static struct i2c_driver anx78xx_driver = { .name = "anx7814", .of_match_table = of_match_ptr(anx78xx_match_table), }, - .probe = anx78xx_i2c_probe, + .probe_new = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, .id_table = anx78xx_id, }; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index b0ff1ecb80a5..6846199a2ee1 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -26,7 +26,6 @@ #include <drm/display/drm_hdcp_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> @@ -1403,7 +1402,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx) { ctx->hpd_status = 0; ctx->hpd_high_cnt = 0; - ctx->display_timing_valid = 0; } static void anx7625_start_dp_work(struct anx7625_data *ctx) @@ -2562,8 +2560,7 @@ static void anx7625_runtime_disable(void *data) pm_runtime_disable(data); } -static int anx7625_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int anx7625_i2c_probe(struct i2c_client *client) { struct anx7625_data *platform; struct anx7625_platform_data *pdata; @@ -2756,7 +2753,7 @@ static struct i2c_driver anx7625_driver = { .of_match_table = anx_match_table, .pm = &anx7625_pm_ops, }, - .probe = anx7625_i2c_probe, + .probe_new = anx7625_i2c_probe, .remove = anx7625_i2c_remove, .id_table = anx7625_id, diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig index 1d06182bea71..ec35215a2003 100644 --- a/drivers/gpu/drm/bridge/cadence/Kconfig +++ b/drivers/gpu/drm/bridge/cadence/Kconfig @@ -1,4 +1,25 @@ # SPDX-License-Identifier: GPL-2.0-only +config DRM_CDNS_DSI + tristate "Cadence DPI/DSI bridge" + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE + select GENERIC_PHY_MIPI_DPHY + depends on OF + help + Support Cadence DPI to DSI bridge. This is an internal + bridge and is meant to be directly embedded in a SoC. + +if DRM_CDNS_DSI + +config DRM_CDNS_DSI_J721E + bool "J721E Cadence DSI wrapper support" + default y + help + Support J721E Cadence DSI wrapper. The wrapper manages + the routing of the DSS DPI signal to the Cadence DSI. +endif + config DRM_CDNS_MHDP8546 tristate "Cadence DPI/DP bridge" select DRM_DISPLAY_DP_HELPER diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile index 4d2db8df1bc6..c95fd5b81d13 100644 --- a/drivers/gpu/drm/bridge/cadence/Makefile +++ b/drivers/gpu/drm/bridge/cadence/Makefile @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o +cdns-dsi-y := cdns-dsi-core.o +cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c index 20bece84ff8c..5dbfc7226b31 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c @@ -6,10 +6,7 @@ */ #include <drm/drm_atomic_helper.h> -#include <drm/drm_bridge.h> #include <drm/drm_drv.h> -#include <drm/drm_mipi_dsi.h> -#include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> #include <video/mipi_display.h> @@ -18,14 +15,19 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> -#include <linux/phy/phy.h> #include <linux/phy/phy-mipi-dphy.h> +#include "cdns-dsi-core.h" +#ifdef CONFIG_DRM_CDNS_DSI_J721E +#include "cdns-dsi-j721e.h" +#endif + #define IP_CONF 0x0 #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21) @@ -424,48 +426,6 @@ #define DSI_NULL_FRAME_OVERHEAD 6 #define DSI_EOT_PKT_SIZE 4 -struct cdns_dsi_output { - struct mipi_dsi_device *dev; - struct drm_panel *panel; - struct drm_bridge *bridge; - union phy_configure_opts phy_opts; -}; - -enum cdns_dsi_input_id { - CDNS_SDI_INPUT, - CDNS_DPI_INPUT, - CDNS_DSC_INPUT, -}; - -struct cdns_dsi_cfg { - unsigned int hfp; - unsigned int hsa; - unsigned int hbp; - unsigned int hact; - unsigned int htotal; -}; - -struct cdns_dsi_input { - enum cdns_dsi_input_id id; - struct drm_bridge bridge; -}; - -struct cdns_dsi { - struct mipi_dsi_host base; - void __iomem *regs; - struct cdns_dsi_input input; - struct cdns_dsi_output output; - unsigned int direct_cmd_fifo_depth; - unsigned int rx_fifo_depth; - struct completion direct_cmd_comp; - struct clk *dsi_p_clk; - struct reset_control *dsi_p_rst; - struct clk *dsi_sys_clk; - bool link_initialized; - bool phy_initialized; - struct phy *dphy; -}; - static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) { return container_of(input, struct cdns_dsi, input); @@ -709,6 +669,10 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge) val = readl(dsi->regs + MCTL_MAIN_EN) & ~IF_EN(input->id); writel(val, dsi->regs + MCTL_MAIN_EN); + + if (dsi->platform_ops && dsi->platform_ops->disable) + dsi->platform_ops->disable(dsi); + pm_runtime_put(dsi->base.dev); } @@ -804,6 +768,9 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) return; + if (dsi->platform_ops && dsi->platform_ops->enable) + dsi->platform_ops->enable(dsi); + mode = &bridge->encoder->crtc->state->adjusted_mode; nlanes = output->dev->lanes; @@ -1244,6 +1211,8 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) goto err_disable_pclk; } + dsi->platform_ops = of_device_get_match_data(&pdev->dev); + val = readl(dsi->regs + IP_CONF); dsi->direct_cmd_fifo_depth = 1 << (DIRCMD_FIFO_DEPTH(val) + 2); dsi->rx_fifo_depth = RX_FIFO_DEPTH(val); @@ -1279,14 +1248,27 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) dsi->base.dev = &pdev->dev; dsi->base.ops = &cdns_dsi_ops; + if (dsi->platform_ops && dsi->platform_ops->init) { + ret = dsi->platform_ops->init(dsi); + if (ret != 0) { + dev_err(&pdev->dev, "platform initialization failed: %d\n", + ret); + goto err_disable_runtime_pm; + } + } + ret = mipi_dsi_host_register(&dsi->base); if (ret) - goto err_disable_runtime_pm; + goto err_deinit_platform; clk_disable_unprepare(dsi->dsi_p_clk); return 0; +err_deinit_platform: + if (dsi->platform_ops && dsi->platform_ops->deinit) + dsi->platform_ops->deinit(dsi); + err_disable_runtime_pm: pm_runtime_disable(&pdev->dev); @@ -1301,6 +1283,10 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev) struct cdns_dsi *dsi = platform_get_drvdata(pdev); mipi_dsi_host_unregister(&dsi->base); + + if (dsi->platform_ops && dsi->platform_ops->deinit) + dsi->platform_ops->deinit(dsi); + pm_runtime_disable(&pdev->dev); return 0; @@ -1308,6 +1294,9 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev) static const struct of_device_id cdns_dsi_of_match[] = { { .compatible = "cdns,dsi" }, +#ifdef CONFIG_DRM_CDNS_DSI_J721E + { .compatible = "ti,j721e-dsi", .data = &dsi_ti_j721e_ops, }, +#endif { }, }; MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h new file mode 100644 index 000000000000..ca7ea2da635c --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright: 2017 Cadence Design Systems, Inc. + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + */ + +#ifndef __CDNS_DSI_H__ +#define __CDNS_DSI_H__ + +#include <drm/drm_bridge.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#include <linux/bits.h> +#include <linux/completion.h> +#include <linux/phy/phy.h> + +struct clk; +struct reset_control; + +struct cdns_dsi_output { + struct mipi_dsi_device *dev; + struct drm_panel *panel; + struct drm_bridge *bridge; + union phy_configure_opts phy_opts; +}; + +enum cdns_dsi_input_id { + CDNS_SDI_INPUT, + CDNS_DPI_INPUT, + CDNS_DSC_INPUT, +}; + +struct cdns_dsi_cfg { + unsigned int hfp; + unsigned int hsa; + unsigned int hbp; + unsigned int hact; + unsigned int htotal; +}; + +struct cdns_dsi_input { + enum cdns_dsi_input_id id; + struct drm_bridge bridge; +}; + +struct cdns_dsi; + +/** + * struct cdns_dsi_platform_ops - CDNS DSI Platform operations + * @init: Called in the CDNS DSI probe + * @deinit: Called in the CDNS DSI remove + * @enable: Called at the beginning of CDNS DSI bridge enable + * @disable: Called at the end of CDNS DSI bridge disable + */ +struct cdns_dsi_platform_ops { + int (*init)(struct cdns_dsi *dsi); + void (*deinit)(struct cdns_dsi *dsi); + void (*enable)(struct cdns_dsi *dsi); + void (*disable)(struct cdns_dsi *dsi); +}; + +struct cdns_dsi { + struct mipi_dsi_host base; + void __iomem *regs; +#ifdef CONFIG_DRM_CDNS_DSI_J721E + void __iomem *j721e_regs; +#endif + const struct cdns_dsi_platform_ops *platform_ops; + struct cdns_dsi_input input; + struct cdns_dsi_output output; + unsigned int direct_cmd_fifo_depth; + unsigned int rx_fifo_depth; + struct completion direct_cmd_comp; + struct clk *dsi_p_clk; + struct reset_control *dsi_p_rst; + struct clk *dsi_sys_clk; + bool link_initialized; + bool phy_initialized; + struct phy *dphy; +}; + +#endif /* !__CDNS_DSI_H__ */ diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c new file mode 100644 index 000000000000..b654d4b3cb5c --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TI j721e Cadence DSI wrapper + * + * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Rahul T R <r-ravikumar@ti.com> + */ + +#include <linux/io.h> +#include <linux/platform_device.h> + +#include "cdns-dsi-j721e.h" + +#define DSI_WRAP_REVISION 0x0 +#define DSI_WRAP_DPI_CONTROL 0x4 +#define DSI_WRAP_DSC_CONTROL 0x8 +#define DSI_WRAP_DPI_SECURE 0xc +#define DSI_WRAP_DSI_0_ASF_STATUS 0x10 + +#define DSI_WRAP_DPI_0_EN BIT(0) +#define DSI_WRAP_DSI2_MUX_SEL BIT(4) + +static int cdns_dsi_j721e_init(struct cdns_dsi *dsi) +{ + struct platform_device *pdev = to_platform_device(dsi->base.dev); + + dsi->j721e_regs = devm_platform_ioremap_resource(pdev, 1); + return PTR_ERR_OR_ZERO(dsi->j721e_regs); +} + +static void cdns_dsi_j721e_enable(struct cdns_dsi *dsi) +{ + /* + * Enable DPI0 as its input. DSS0 DPI2 is connected + * to DSI DPI0. This is the only supported configuration on + * J721E. + */ + writel(DSI_WRAP_DPI_0_EN, dsi->j721e_regs + DSI_WRAP_DPI_CONTROL); +} + +static void cdns_dsi_j721e_disable(struct cdns_dsi *dsi) +{ + /* Put everything to defaults */ + writel(0, dsi->j721e_regs + DSI_WRAP_DPI_CONTROL); +} + +const struct cdns_dsi_platform_ops dsi_ti_j721e_ops = { + .init = cdns_dsi_j721e_init, + .enable = cdns_dsi_j721e_enable, + .disable = cdns_dsi_j721e_disable, +}; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h new file mode 100644 index 000000000000..275e5e8e7583 --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TI j721e Cadence DSI wrapper + * + * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Rahul T R <r-ravikumar@ti.com> + */ + +#ifndef __CDNS_DSI_J721E_H__ +#define __CDNS_DSI_J721E_H__ + +#include "cdns-dsi-core.h" + +extern const struct cdns_dsi_platform_ops dsi_ti_j721e_ops; + +#endif /* !__CDNS_DSI_J721E_H__ */ diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 31442a922502..f6822dfa3805 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -43,7 +43,6 @@ #include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_connector.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index bf920c3503aa..0e37840cd7a8 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -740,8 +740,7 @@ static int chipone_dsi_probe(struct mipi_dsi_device *dsi) return ret; } -static int chipone_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int chipone_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct chipone *icn; @@ -796,7 +795,7 @@ static struct i2c_device_id chipone_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, chipone_i2c_id); static struct i2c_driver chipone_i2c_driver = { - .probe = chipone_i2c_probe, + .probe_new = chipone_i2c_probe, .id_table = chipone_i2c_id, .driver = { .name = "chipone-icn6211-i2c", diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index b94f39a86846..339b759e4c81 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -528,8 +528,7 @@ static const struct regmap_config ch7033_regmap_config = { .max_register = 0x7f, }; -static int ch7033_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ch7033_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ch7033_priv *priv; @@ -604,7 +603,7 @@ static const struct i2c_device_id ch7033_ids[] = { MODULE_DEVICE_TABLE(i2c, ch7033_ids); static struct i2c_driver ch7033_driver = { - .probe = ch7033_probe, + .probe_new = ch7033_probe, .remove = ch7033_remove, .driver = { .name = "ch7033", diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c index f9e0f8d99268..6bac160b395b 100644 --- a/drivers/gpu/drm/bridge/fsl-ldb.c +++ b/drivers/gpu/drm/bridge/fsl-ldb.c @@ -18,7 +18,6 @@ #include <drm/drm_of.h> #include <drm/drm_panel.h> -#define LDB_CTRL 0x5c #define LDB_CTRL_CH0_ENABLE BIT(0) #define LDB_CTRL_CH0_DI_SELECT BIT(1) #define LDB_CTRL_CH1_ENABLE BIT(2) @@ -35,9 +34,13 @@ #define LDB_CTRL_ASYNC_FIFO_ENABLE BIT(24) #define LDB_CTRL_ASYNC_FIFO_THRESHOLD_MASK GENMASK(27, 25) -#define LVDS_CTRL 0x128 #define LVDS_CTRL_CH0_EN BIT(0) #define LVDS_CTRL_CH1_EN BIT(1) +/* + * LVDS_CTRL_LVDS_EN bit is poorly named in i.MX93 reference manual. + * Clear it to enable LVDS and set it to disable LVDS. + */ +#define LVDS_CTRL_LVDS_EN BIT(1) #define LVDS_CTRL_VBG_EN BIT(2) #define LVDS_CTRL_HS_EN BIT(3) #define LVDS_CTRL_PRE_EMPH_EN BIT(4) @@ -52,6 +55,29 @@ #define LVDS_CTRL_VBG_ADJ(n) (((n) & 0x7) << 17) #define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17) +enum fsl_ldb_devtype { + IMX8MP_LDB, + IMX93_LDB, +}; + +struct fsl_ldb_devdata { + u32 ldb_ctrl; + u32 lvds_ctrl; + bool lvds_en_bit; +}; + +static const struct fsl_ldb_devdata fsl_ldb_devdata[] = { + [IMX8MP_LDB] = { + .ldb_ctrl = 0x5c, + .lvds_ctrl = 0x128, + }, + [IMX93_LDB] = { + .ldb_ctrl = 0x20, + .lvds_ctrl = 0x24, + .lvds_en_bit = true, + }, +}; + struct fsl_ldb { struct device *dev; struct drm_bridge bridge; @@ -59,6 +85,7 @@ struct fsl_ldb { struct clk *clk; struct regmap *regmap; bool lvds_dual_link; + const struct fsl_ldb_devdata *devdata; }; static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge) @@ -66,6 +93,14 @@ static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge) return container_of(bridge, struct fsl_ldb, bridge); } +static unsigned long fsl_ldb_link_frequency(struct fsl_ldb *fsl_ldb, int clock) +{ + if (fsl_ldb->lvds_dual_link) + return clock * 3500; + else + return clock * 7000; +} + static int fsl_ldb_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -85,6 +120,8 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, const struct drm_display_mode *mode; struct drm_connector *connector; struct drm_crtc *crtc; + unsigned long configured_link_freq; + unsigned long requested_link_freq; bool lvds_format_24bpp; bool lvds_format_jeida; u32 reg; @@ -128,10 +165,15 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, crtc_state = drm_atomic_get_new_crtc_state(state, crtc); mode = &crtc_state->adjusted_mode; - if (fsl_ldb->lvds_dual_link) - clk_set_rate(fsl_ldb->clk, mode->clock * 3500); - else - clk_set_rate(fsl_ldb->clk, mode->clock * 7000); + requested_link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock); + clk_set_rate(fsl_ldb->clk, requested_link_freq); + + configured_link_freq = clk_get_rate(fsl_ldb->clk); + if (configured_link_freq != requested_link_freq) + dev_warn(fsl_ldb->dev, "Configured LDB clock (%lu Hz) does not match requested LVDS clock: %lu Hz", + configured_link_freq, + requested_link_freq); + clk_prepare_enable(fsl_ldb->clk); /* Program LDB_CTRL */ @@ -158,12 +200,12 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, reg |= LDB_CTRL_DI1_VSYNC_POLARITY; } - regmap_write(fsl_ldb->regmap, LDB_CTRL, reg); + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, reg); /* Program LVDS_CTRL */ reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN | LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN; - regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg); + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, reg); /* Wait for VBG to stabilize. */ usleep_range(15, 20); @@ -172,7 +214,7 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, if (fsl_ldb->lvds_dual_link) reg |= LVDS_CTRL_CH1_EN; - regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg); + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, reg); } static void fsl_ldb_atomic_disable(struct drm_bridge *bridge, @@ -180,9 +222,14 @@ static void fsl_ldb_atomic_disable(struct drm_bridge *bridge, { struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge); - /* Stop both channels. */ - regmap_write(fsl_ldb->regmap, LVDS_CTRL, 0); - regmap_write(fsl_ldb->regmap, LDB_CTRL, 0); + /* Stop channel(s). */ + if (fsl_ldb->devdata->lvds_en_bit) + /* Set LVDS_CTRL_LVDS_EN bit to disable. */ + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, + LVDS_CTRL_LVDS_EN); + else + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0); + regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, 0); clk_disable_unprepare(fsl_ldb->clk); } @@ -248,6 +295,10 @@ static int fsl_ldb_probe(struct platform_device *pdev) if (!fsl_ldb) return -ENOMEM; + fsl_ldb->devdata = of_device_get_match_data(dev); + if (!fsl_ldb->devdata) + return -EINVAL; + fsl_ldb->dev = &pdev->dev; fsl_ldb->bridge.funcs = &funcs; fsl_ldb->bridge.of_node = dev->of_node; @@ -306,7 +357,10 @@ static int fsl_ldb_remove(struct platform_device *pdev) } static const struct of_device_id fsl_ldb_match[] = { - { .compatible = "fsl,imx8mp-ldb", }, + { .compatible = "fsl,imx8mp-ldb", + .data = &fsl_ldb_devdata[IMX8MP_LDB], }, + { .compatible = "fsl,imx93-ldb", + .data = &fsl_ldb_devdata[IMX93_LDB], }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, fsl_ldb_match); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 21a9b8422bda..bc451b2a77c2 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -26,7 +26,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -412,7 +411,6 @@ struct it6505 { * Mutex protects extcon and interrupt functions from interfering * each other. */ - struct mutex irq_lock; struct mutex extcon_lock; struct mutex mode_lock; /* used to bridge_detect */ struct mutex aux_lock; /* used to aux data transfers */ @@ -438,6 +436,8 @@ struct it6505 { bool powered; bool hpd_state; u32 afe_setting; + u32 max_dpi_pixel_clock; + u32 max_lane_count; enum hdcp_state hdcp_status; struct delayed_work hdcp_work; struct work_struct hdcp_wait_ksv_list; @@ -457,6 +457,8 @@ struct it6505 { /* it6505 driver hold option */ bool enable_drv_hold; + + struct edid *cached_edid; }; struct it6505_step_train_para { @@ -1463,7 +1465,8 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505) it6505->lane_count = link->num_lanes; DRM_DEV_DEBUG_DRIVER(dev, "Sink support %d lanes training", it6505->lane_count); - it6505->lane_count = min_t(int, it6505->lane_count, MAX_LANE_COUNT); + it6505->lane_count = min_t(int, it6505->lane_count, + it6505->max_lane_count); it6505->branch_device = drm_dp_is_branch(it6505->dpcd); DRM_DEV_DEBUG_DRIVER(dev, "Sink %sbranch device", @@ -2244,6 +2247,12 @@ static void it6505_plugged_status_to_codec(struct it6505 *it6505) status == connector_status_connected); } +static void it6505_remove_edid(struct it6505 *it6505) +{ + kfree(it6505->cached_edid); + it6505->cached_edid = NULL; +} + static int it6505_process_hpd_irq(struct it6505 *it6505) { struct device *dev = &it6505->client->dev; @@ -2270,6 +2279,7 @@ static int it6505_process_hpd_irq(struct it6505 *it6505) it6505_reset_logic(it6505); it6505_int_mask_enable(it6505); it6505_init(it6505); + it6505_remove_edid(it6505); return 0; } @@ -2353,6 +2363,7 @@ static void it6505_irq_hpd(struct it6505 *it6505) it6505_video_reset(it6505); } else { memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); + it6505_remove_edid(it6505); if (it6505->hdcp_desired) it6505_stop_hdcp(it6505); @@ -2494,10 +2505,8 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) }; int int_status[3], i; - mutex_lock(&it6505->irq_lock); - - if (it6505->enable_drv_hold || !it6505->powered) - goto unlock; + if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0) + return IRQ_HANDLED; int_status[0] = it6505_read(it6505, INT_STATUS_01); int_status[1] = it6505_read(it6505, INT_STATUS_02); @@ -2515,16 +2524,14 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) if (it6505_test_bit(irq_vec[0].bit, (unsigned int *)int_status)) irq_vec[0].handler(it6505); - if (!it6505->hpd_state) - goto unlock; - - for (i = 1; i < ARRAY_SIZE(irq_vec); i++) { - if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status)) - irq_vec[i].handler(it6505); + if (it6505->hpd_state) { + for (i = 1; i < ARRAY_SIZE(irq_vec); i++) { + if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status)) + irq_vec[i].handler(it6505); + } } -unlock: - mutex_unlock(&it6505->irq_lock); + pm_runtime_put_sync(dev); return IRQ_HANDLED; } @@ -2902,7 +2909,7 @@ it6505_bridge_mode_valid(struct drm_bridge *bridge, if (mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE; - if (mode->clock > DPI_PIXEL_CLK_MAX) + if (mode->clock > it6505->max_dpi_pixel_clock) return MODE_CLOCK_HIGH; it6505->video_info.clock = mode->clock; @@ -3016,16 +3023,18 @@ static struct edid *it6505_bridge_get_edid(struct drm_bridge *bridge, { struct it6505 *it6505 = bridge_to_it6505(bridge); struct device *dev = &it6505->client->dev; - struct edid *edid; - edid = drm_do_get_edid(connector, it6505_get_edid_block, it6505); + if (!it6505->cached_edid) { + it6505->cached_edid = drm_do_get_edid(connector, it6505_get_edid_block, + it6505); - if (!edid) { - DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!"); - return NULL; + if (!it6505->cached_edid) { + DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!"); + return NULL; + } } - return edid; + return drm_edid_duplicate(it6505->cached_edid); } static const struct drm_bridge_funcs it6505_bridge_funcs = { @@ -3089,10 +3098,32 @@ static int it6505_init_pdata(struct it6505 *it6505) return 0; } +static int it6505_get_data_lanes_count(const struct device_node *endpoint, + const unsigned int min, + const unsigned int max) +{ + int ret; + + ret = of_property_count_u32_elems(endpoint, "data-lanes"); + if (ret < 0) + return ret; + + if (ret < min || ret > max) + return -EINVAL; + + return ret; +} + static void it6505_parse_dt(struct it6505 *it6505) { struct device *dev = &it6505->client->dev; + struct device_node *np = dev->of_node, *ep = NULL; + int len; + u64 link_frequencies; + u32 data_lanes[4]; u32 *afe_setting = &it6505->afe_setting; + u32 *max_lane_count = &it6505->max_lane_count; + u32 *max_dpi_pixel_clock = &it6505->max_dpi_pixel_clock; it6505->lane_swap_disabled = device_property_read_bool(dev, "no-laneswap"); @@ -3108,7 +3139,56 @@ static void it6505_parse_dt(struct it6505 *it6505) } else { *afe_setting = 0; } - DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %d", *afe_setting); + + ep = of_graph_get_endpoint_by_regs(np, 1, 0); + of_node_put(ep); + + if (ep) { + len = it6505_get_data_lanes_count(ep, 1, 4); + + if (len > 0 && len != 3) { + of_property_read_u32_array(ep, "data-lanes", + data_lanes, len); + *max_lane_count = len; + } else { + *max_lane_count = MAX_LANE_COUNT; + dev_err(dev, "error data-lanes, use default"); + } + } else { + *max_lane_count = MAX_LANE_COUNT; + dev_err(dev, "error endpoint, use default"); + } + + ep = of_graph_get_endpoint_by_regs(np, 0, 0); + of_node_put(ep); + + if (ep) { + len = of_property_read_variable_u64_array(ep, + "link-frequencies", + &link_frequencies, 0, + 1); + if (len >= 0) { + do_div(link_frequencies, 1000); + if (link_frequencies > 297000) { + dev_err(dev, + "max pixel clock error, use default"); + *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX; + } else { + *max_dpi_pixel_clock = link_frequencies; + } + } else { + dev_err(dev, "error link frequencies, use default"); + *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX; + } + } else { + dev_err(dev, "error endpoint, use default"); + *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX; + } + + DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %u, max_lane_count: %u", + it6505->afe_setting, it6505->max_lane_count); + DRM_DEV_DEBUG_DRIVER(dev, "using max_dpi_pixel_clock: %u kHz", + it6505->max_dpi_pixel_clock); } static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf, @@ -3265,8 +3345,7 @@ static void it6505_shutdown(struct i2c_client *client) it6505_lane_off(it6505); } -static int it6505_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int it6505_i2c_probe(struct i2c_client *client) { struct it6505 *it6505; struct device *dev = &client->dev; @@ -3277,7 +3356,6 @@ static int it6505_i2c_probe(struct i2c_client *client, if (!it6505) return -ENOMEM; - mutex_init(&it6505->irq_lock); mutex_init(&it6505->extcon_lock); mutex_init(&it6505->mode_lock); mutex_init(&it6505->aux_lock); @@ -3367,6 +3445,7 @@ static void it6505_i2c_remove(struct i2c_client *client) drm_dp_aux_unregister(&it6505->aux); it6505_debugfs_remove(it6505); it6505_poweroff(it6505); + it6505_remove_edid(it6505); } static const struct i2c_device_id it6505_id[] = { @@ -3387,7 +3466,7 @@ static struct i2c_driver it6505_i2c_driver = { .of_match_table = it6505_of_match, .pm = &it6505_bridge_pm_ops, }, - .probe = it6505_i2c_probe, + .probe_new = it6505_i2c_probe, .remove = it6505_i2c_remove, .shutdown = it6505_shutdown, .id_table = it6505_id, diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index 4f6f1deba28c..a2d723d6a4be 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -22,7 +22,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_modes.h> #include <drm/drm_print.h> @@ -35,10 +34,6 @@ #define IT66121_DEVICE_ID0_REG 0x02 #define IT66121_DEVICE_ID1_REG 0x03 -#define IT66121_VENDOR_ID0 0x54 -#define IT66121_VENDOR_ID1 0x49 -#define IT66121_DEVICE_ID0 0x12 -#define IT66121_DEVICE_ID1 0x06 #define IT66121_REVISION_MASK GENMASK(7, 4) #define IT66121_DEVICE_ID1_MASK GENMASK(3, 0) @@ -72,6 +67,7 @@ #define IT66121_AFE_XP_ENO BIT(4) #define IT66121_AFE_XP_RESETB BIT(3) #define IT66121_AFE_XP_PWDI BIT(2) +#define IT6610_AFE_XP_BYPASS BIT(0) #define IT66121_AFE_IP_REG 0x64 #define IT66121_AFE_IP_GAINBIT BIT(7) @@ -286,13 +282,18 @@ #define IT66121_AUD_SWL_16BIT 0x2 #define IT66121_AUD_SWL_NOT_INDICATED 0x0 -#define IT66121_VENDOR_ID0 0x54 -#define IT66121_VENDOR_ID1 0x49 -#define IT66121_DEVICE_ID0 0x12 -#define IT66121_DEVICE_ID1 0x06 -#define IT66121_DEVICE_MASK 0x0F #define IT66121_AFE_CLK_HIGH 80000 /* Khz */ +enum chip_id { + ID_IT6610, + ID_IT66121, +}; + +struct it66121_chip_info { + enum chip_id id; + u16 vid, pid; +}; + struct it66121_ctx { struct regmap *regmap; struct drm_bridge bridge; @@ -301,7 +302,6 @@ struct it66121_ctx { struct device *dev; struct gpio_desc *gpio_reset; struct i2c_client *client; - struct regulator_bulk_data supplies[3]; u32 bus_width; struct mutex lock; /* Protects fields below and device registers */ struct hdmi_avi_infoframe hdmi_avi_infoframe; @@ -312,6 +312,7 @@ struct it66121_ctx { u8 swl; bool auto_cts; } audio; + const struct it66121_chip_info *info; }; static const struct regmap_range_cfg it66121_regmap_banks[] = { @@ -342,16 +343,6 @@ static void it66121_hw_reset(struct it66121_ctx *ctx) gpiod_set_value(ctx->gpio_reset, 0); } -static inline int ite66121_power_on(struct it66121_ctx *ctx) -{ - return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); -} - -static inline int ite66121_power_off(struct it66121_ctx *ctx) -{ - return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); -} - static inline int it66121_preamble_ddc(struct it66121_ctx *ctx) { return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, IT66121_MASTER_SEL_HOST); @@ -406,16 +397,22 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, IT66121_AFE_IP_GAINBIT | - IT66121_AFE_IP_ER0 | - IT66121_AFE_IP_EC1, + IT66121_AFE_IP_ER0, IT66121_AFE_IP_GAINBIT); if (ret) return ret; - ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, - IT66121_AFE_XP_EC1_LOWCLK, 0x80); - if (ret) - return ret; + if (ctx->info->id == ID_IT66121) { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_EC1, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, + IT66121_AFE_XP_EC1_LOWCLK, 0x80); + if (ret) + return ret; + } } else { ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, IT66121_AFE_XP_GAINBIT | @@ -426,17 +423,24 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, IT66121_AFE_IP_GAINBIT | - IT66121_AFE_IP_ER0 | - IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 | - IT66121_AFE_IP_EC1); + IT66121_AFE_IP_ER0, + IT66121_AFE_IP_ER0); if (ret) return ret; - ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, - IT66121_AFE_XP_EC1_LOWCLK, - IT66121_AFE_XP_EC1_LOWCLK); - if (ret) - return ret; + if (ctx->info->id == ID_IT66121) { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_EC1, + IT66121_AFE_IP_EC1); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, + IT66121_AFE_XP_EC1_LOWCLK, + IT66121_AFE_XP_EC1_LOWCLK); + if (ret) + return ret; + } } /* Clear reset flags */ @@ -445,38 +449,36 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, if (ret) return ret; + if (ctx->info->id == ID_IT6610) { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT6610_AFE_XP_BYPASS, + IT6610_AFE_XP_BYPASS); + if (ret) + return ret; + } + return it66121_fire_afe(ctx); } static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx) { int ret, val; - u32 busy = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS | - IT66121_DDC_STATUS_ARBI_LOSE; + u32 error = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS | + IT66121_DDC_STATUS_ARBI_LOSE; + u32 done = IT66121_DDC_STATUS_TX_DONE; - ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val, true, - IT66121_EDID_SLEEP_US, IT66121_EDID_TIMEOUT_US); + ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val, + val & (error | done), IT66121_EDID_SLEEP_US, + IT66121_EDID_TIMEOUT_US); if (ret) return ret; - if (val & busy) + if (val & error) return -EAGAIN; return 0; } -static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx) -{ - int ret; - - ret = it66121_preamble_ddc(ctx); - if (ret) - return ret; - - return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, - IT66121_DDC_COMMAND_FIFO_CLR); -} - static int it66121_abort_ddc_ops(struct it66121_ctx *ctx) { int ret; @@ -516,7 +518,6 @@ static int it66121_get_edid_block(void *context, u8 *buf, unsigned int block, size_t len) { struct it66121_ctx *ctx = context; - unsigned int val; int remain = len; int offset = 0; int ret, cnt; @@ -524,26 +525,9 @@ static int it66121_get_edid_block(void *context, u8 *buf, offset = (block % 2) * len; block = block / 2; - ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); - if (ret) - return ret; - - if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { - ret = it66121_abort_ddc_ops(ctx); - if (ret) - return ret; - } - - ret = it66121_clear_ddc_fifo(ctx); - if (ret) - return ret; - while (remain > 0) { cnt = (remain > IT66121_EDID_FIFO_SIZE) ? IT66121_EDID_FIFO_SIZE : remain; - ret = it66121_preamble_ddc(ctx); - if (ret) - return ret; ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, IT66121_DDC_COMMAND_FIFO_CLR); @@ -554,25 +538,6 @@ static int it66121_get_edid_block(void *context, u8 *buf, if (ret) return ret; - ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); - if (ret) - return ret; - - if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { - ret = it66121_abort_ddc_ops(ctx); - if (ret) - return ret; - } - - ret = it66121_preamble_ddc(ctx); - if (ret) - return ret; - - ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, - IT66121_DDC_HEADER_EDID); - if (ret) - return ret; - ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset); if (ret) return ret; @@ -593,20 +558,18 @@ static int it66121_get_edid_block(void *context, u8 *buf, offset += cnt; remain -= cnt; - /* Per programming manual, sleep here before emptying the FIFO */ - msleep(20); - ret = it66121_wait_ddc_ready(ctx); + if (ret) { + it66121_abort_ddc_ops(ctx); + return ret; + } + + ret = regmap_noinc_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG, + buf, cnt); if (ret) return ret; - do { - ret = regmap_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG, &val); - if (ret) - return ret; - *(buf++) = val; - cnt--; - } while (cnt > 0); + buf += cnt; } return 0; @@ -635,10 +598,12 @@ static int it66121_bridge_attach(struct drm_bridge *bridge, if (ret) return ret; - ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, - IT66121_CLK_BANK_PWROFF_RCLK, 0); - if (ret) - return ret; + if (ctx->info->id == ID_IT66121) { + ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, + IT66121_CLK_BANK_PWROFF_RCLK, 0); + if (ret) + return ret; + } ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG, IT66121_INT_TX_CLK_OFF, 0); @@ -684,11 +649,7 @@ static int it66121_bridge_attach(struct drm_bridge *bridge, /* Per programming manual, sleep here for bridge to settle */ msleep(50); - /* Start interrupts */ - return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, - IT66121_INT_MASK1_DDC_NOACK | - IT66121_INT_MASK1_DDC_FIFOERR | - IT66121_INT_MASK1_DDC_BUSHANG, 0); + return 0; } static int it66121_set_mute(struct it66121_ctx *ctx, bool mute) @@ -780,29 +741,32 @@ static void it66121_bridge_disable(struct drm_bridge *bridge, ctx->connector = NULL; } +static int it66121_bridge_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + + if (ctx->info->id == ID_IT6610) { + /* The IT6610 only supports these settings */ + bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; + bridge_state->input_bus_cfg.flags &= + ~DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + } + + return 0; +} + static void it66121_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { - int ret, i; u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); - const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = { - IT66121_AVIINFO_DB1_REG, - IT66121_AVIINFO_DB2_REG, - IT66121_AVIINFO_DB3_REG, - IT66121_AVIINFO_DB4_REG, - IT66121_AVIINFO_DB5_REG, - IT66121_AVIINFO_DB6_REG, - IT66121_AVIINFO_DB7_REG, - IT66121_AVIINFO_DB8_REG, - IT66121_AVIINFO_DB9_REG, - IT66121_AVIINFO_DB10_REG, - IT66121_AVIINFO_DB11_REG, - IT66121_AVIINFO_DB12_REG, - IT66121_AVIINFO_DB13_REG - }; + int ret; mutex_lock(&ctx->lock); @@ -822,10 +786,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge, } /* Write new AVI infoframe packet */ - for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) { - if (regmap_write(ctx->regmap, aviinfo_reg[i], buf[i + HDMI_INFOFRAME_HEADER_SIZE])) - goto unlock; - } + ret = regmap_bulk_write(ctx->regmap, IT66121_AVIINFO_DB1_REG, + &buf[HDMI_INFOFRAME_HEADER_SIZE], + HDMI_AVI_INFOFRAME_SIZE); + if (ret) + goto unlock; + if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3])) goto unlock; @@ -838,9 +804,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge, if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI)) goto unlock; - if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, - IT66121_CLK_BANK_PWROFF_TXCLK, IT66121_CLK_BANK_PWROFF_TXCLK)) + if (ctx->info->id == ID_IT66121 && + regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, + IT66121_CLK_BANK_PWROFF_TXCLK, + IT66121_CLK_BANK_PWROFF_TXCLK)) { goto unlock; + } if (it66121_configure_input(ctx)) goto unlock; @@ -848,7 +817,11 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge, if (it66121_configure_afe(ctx, adjusted_mode)) goto unlock; - regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, IT66121_CLK_BANK_PWROFF_TXCLK, 0); + if (ctx->info->id == ID_IT66121 && + regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, + IT66121_CLK_BANK_PWROFF_TXCLK, 0)) { + goto unlock; + } unlock: mutex_unlock(&ctx->lock); @@ -906,9 +879,25 @@ static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge, { struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); struct edid *edid; + int ret; mutex_lock(&ctx->lock); + ret = it66121_preamble_ddc(ctx); + if (ret) { + edid = ERR_PTR(ret); + goto out_unlock; + } + + ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, + IT66121_DDC_HEADER_EDID); + if (ret) { + edid = ERR_PTR(ret); + goto out_unlock; + } + edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx); + +out_unlock: mutex_unlock(&ctx->lock); return edid; @@ -923,6 +912,7 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = { .atomic_get_input_bus_fmts = it66121_bridge_atomic_get_input_bus_fmts, .atomic_enable = it66121_bridge_enable, .atomic_disable = it66121_bridge_disable, + .atomic_check = it66121_bridge_check, .mode_set = it66121_bridge_mode_set, .mode_valid = it66121_bridge_mode_valid, .detect = it66121_bridge_detect, @@ -952,21 +942,14 @@ static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); if (ret) { dev_err(dev, "Cannot read STATUS1_REG %d\n", ret); - } else { - if (val & IT66121_INT_STATUS1_DDC_FIFOERR) - it66121_clear_ddc_fifo(ctx); - if (val & (IT66121_INT_STATUS1_DDC_BUSHANG | - IT66121_INT_STATUS1_DDC_NOACK)) - it66121_abort_ddc_ops(ctx); - if (val & IT66121_INT_STATUS1_HPD_STATUS) { - regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG, - IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD); + } else if (val & IT66121_INT_STATUS1_HPD_STATUS) { + regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG, + IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD); - status = it66121_is_hpd_detect(ctx) ? connector_status_connected - : connector_status_disconnected; + status = it66121_is_hpd_detect(ctx) ? connector_status_connected + : connector_status_disconnected; - event = true; - } + event = true; } regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG, @@ -1512,9 +1495,13 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev) return PTR_ERR_OR_ZERO(ctx->audio.pdev); } -static int it66121_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const char * const it66121_supplies[] = { + "vcn33", "vcn18", "vrf12" +}; + +static int it66121_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 }; struct device_node *ep; int ret; @@ -1536,6 +1523,7 @@ static int it66121_probe(struct i2c_client *client, ctx->dev = dev; ctx->client = client; + ctx->info = (const struct it66121_chip_info *) id->driver_data; of_property_read_u32(ep, "bus-width", &ctx->bus_width); of_node_put(ep); @@ -1565,26 +1553,18 @@ static int it66121_probe(struct i2c_client *client, i2c_set_clientdata(client, ctx); mutex_init(&ctx->lock); - ctx->supplies[0].supply = "vcn33"; - ctx->supplies[1].supply = "vcn18"; - ctx->supplies[2].supply = "vrf12"; - ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it66121_supplies), + it66121_supplies); if (ret) { - dev_err(ctx->dev, "regulator_bulk failed\n"); + dev_err(dev, "Failed to enable power supplies\n"); return ret; } - ret = ite66121_power_on(ctx); - if (ret) - return ret; - it66121_hw_reset(ctx); ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config); - if (IS_ERR(ctx->regmap)) { - ite66121_power_off(ctx); + if (IS_ERR(ctx->regmap)) return PTR_ERR(ctx->regmap); - } regmap_read(ctx->regmap, IT66121_VENDOR_ID0_REG, &vendor_ids[0]); regmap_read(ctx->regmap, IT66121_VENDOR_ID1_REG, &vendor_ids[1]); @@ -1595,9 +1575,8 @@ static int it66121_probe(struct i2c_client *client, revision_id = FIELD_GET(IT66121_REVISION_MASK, device_ids[1]); device_ids[1] &= IT66121_DEVICE_ID1_MASK; - if (vendor_ids[0] != IT66121_VENDOR_ID0 || vendor_ids[1] != IT66121_VENDOR_ID1 || - device_ids[0] != IT66121_DEVICE_ID0 || device_ids[1] != IT66121_DEVICE_ID1) { - ite66121_power_off(ctx); + if ((vendor_ids[1] << 8 | vendor_ids[0]) != ctx->info->vid || + (device_ids[1] << 8 | device_ids[0]) != ctx->info->pid) { return -ENODEV; } @@ -1610,7 +1589,6 @@ static int it66121_probe(struct i2c_client *client, IRQF_ONESHOT, dev_name(dev), ctx); if (ret < 0) { dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); - ite66121_power_off(ctx); return ret; } @@ -1627,19 +1605,32 @@ static void it66121_remove(struct i2c_client *client) { struct it66121_ctx *ctx = i2c_get_clientdata(client); - ite66121_power_off(ctx); drm_bridge_remove(&ctx->bridge); mutex_destroy(&ctx->lock); } static const struct of_device_id it66121_dt_match[] = { { .compatible = "ite,it66121" }, + { .compatible = "ite,it6610" }, { } }; MODULE_DEVICE_TABLE(of, it66121_dt_match); +static const struct it66121_chip_info it66121_chip_info = { + .id = ID_IT66121, + .vid = 0x4954, + .pid = 0x0612, +}; + +static const struct it66121_chip_info it6610_chip_info = { + .id = ID_IT6610, + .vid = 0xca00, + .pid = 0x0611, +}; + static const struct i2c_device_id it66121_id[] = { - { "it66121", 0 }, + { "it66121", (kernel_ulong_t) &it66121_chip_info }, + { "it6610", (kernel_ulong_t) &it6610_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, it66121_id); @@ -1649,7 +1640,7 @@ static struct i2c_driver it66121_driver = { .name = "it66121", .of_match_table = it66121_dt_match, }, - .probe = it66121_probe, + .probe_new = it66121_probe, .remove = it66121_remove, .id_table = it66121_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index a98efef0ba0e..2019a8167d69 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -517,14 +517,27 @@ static int lt8912_attach_dsi(struct lt8912 *lt) return 0; } +static void lt8912_bridge_hpd_cb(void *data, enum drm_connector_status status) +{ + struct lt8912 *lt = data; + + if (lt->bridge.dev) + drm_helper_hpd_irq_event(lt->bridge.dev); +} + static int lt8912_bridge_connector_init(struct drm_bridge *bridge) { int ret; struct lt8912 *lt = bridge_to_lt8912(bridge); struct drm_connector *connector = <->connector; - connector->polled = DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; + if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) { + drm_bridge_hpd_enable(lt->hdmi_port, lt8912_bridge_hpd_cb, lt); + connector->polled = DRM_CONNECTOR_POLL_HPD; + } else { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } ret = drm_connector_init(bridge->dev, connector, <8912_connector_funcs, @@ -578,6 +591,10 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge) if (lt->is_attached) { lt8912_hard_power_off(lt); + + if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) + drm_bridge_hpd_disable(lt->hdmi_port); + drm_connector_unregister(<->connector); drm_connector_cleanup(<->connector); } @@ -685,8 +702,7 @@ static int lt8912_put_dt(struct lt8912 *lt) return 0; } -static int lt8912_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lt8912_probe(struct i2c_client *client) { static struct lt8912 *lt; int ret = 0; @@ -758,7 +774,7 @@ static struct i2c_driver lt8912_i2c_driver = { .name = "lt8912", .of_match_table = lt8912_dt_match, }, - .probe = lt8912_probe, + .probe_new = lt8912_probe, .remove = lt8912_remove, .id_table = lt8912_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c index 933ca028d612..3e19fff6547a 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9211.c +++ b/drivers/gpu/drm/bridge/lontium-lt9211.c @@ -720,8 +720,7 @@ static int lt9211_host_attach(struct lt9211 *ctx) return 0; } -static int lt9211_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lt9211_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lt9211 *ctx; @@ -786,7 +785,7 @@ static const struct of_device_id lt9211_match_table[] = { MODULE_DEVICE_TABLE(of, lt9211_match_table); static struct i2c_driver lt9211_driver = { - .probe = lt9211_probe, + .probe_new = lt9211_probe, .remove = lt9211_remove, .id_table = lt9211_id, .driver = { diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 7c0a99173b39..a25d21a7d5c1 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -19,6 +19,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -33,7 +34,7 @@ struct lt9611 { struct device *dev; struct drm_bridge bridge; - struct drm_connector connector; + struct drm_bridge *next_bridge; struct regmap *regmap; @@ -58,7 +59,6 @@ struct lt9611 { enum drm_connector_status status; u8 edid_buf[EDID_SEG_SIZE]; - u32 vic; }; #define LT9611_PAGE_CONTROL 0xff @@ -84,34 +84,11 @@ static const struct regmap_config lt9611_regmap_config = { .num_ranges = ARRAY_SIZE(lt9611_ranges), }; -struct lt9611_mode { - u16 hdisplay; - u16 vdisplay; - u8 vrefresh; - u8 lanes; - u8 intfs; -}; - -static struct lt9611_mode lt9611_modes[] = { - { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */ - { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */ - { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */ - { 1920, 1080, 24, 3, 1 }, - { 720, 480, 60, 4, 1 }, - { 720, 576, 50, 2, 1 }, - { 640, 480, 60, 2, 1 }, -}; - static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge) { return container_of(bridge, struct lt9611, bridge); } -static struct lt9611 *connector_to_lt9611(struct drm_connector *connector) -{ - return container_of(connector, struct lt9611, connector); -} - static int lt9611_mipi_input_analog(struct lt9611 *lt9611) { const struct reg_sequence reg_cfg[] = { @@ -141,7 +118,7 @@ static int lt9611_mipi_input_digital(struct lt9611 *lt9611, { 0x8306, 0x0a }, }; - if (mode->hdisplay == 3840) + if (lt9611->dsi1_node) reg_cfg[1].def = 0x03; return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); @@ -159,12 +136,12 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611, hactive = mode->hdisplay; hsync_len = mode->hsync_end - mode->hsync_start; hfront_porch = mode->hsync_start - mode->hdisplay; - hsync_porch = hsync_len + mode->htotal - mode->hsync_end; + hsync_porch = mode->htotal - mode->hsync_start; vactive = mode->vdisplay; vsync_len = mode->vsync_end - mode->vsync_start; vfront_porch = mode->vsync_start - mode->vdisplay; - vsync_porch = vsync_len + mode->vtotal - mode->vsync_end; + vsync_porch = mode->vtotal - mode->vsync_start; regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256)); regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256)); @@ -187,12 +164,14 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611, regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256)); - regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256)); + regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256) | + ((hfront_porch / 256) << 4)); regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256)); } -static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) +static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int postdiv) { + unsigned int pcr_m = mode->clock * 5 * postdiv / 27000; const struct reg_sequence reg_cfg[] = { { 0x830b, 0x01 }, { 0x830c, 0x10 }, @@ -207,45 +186,40 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod /* stage 2 */ { 0x834a, 0x40 }, - { 0x831d, 0x10 }, /* MK limit */ { 0x832d, 0x38 }, { 0x8331, 0x08 }, }; - const struct reg_sequence reg_cfg2[] = { - { 0x830b, 0x03 }, - { 0x830c, 0xd0 }, - { 0x8348, 0x03 }, - { 0x8349, 0xe0 }, - { 0x8324, 0x72 }, - { 0x8325, 0x00 }, - { 0x832a, 0x01 }, - { 0x834a, 0x10 }, - { 0x831d, 0x10 }, - { 0x8326, 0x37 }, - }; + u8 pol = 0x10; - regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + pol |= 0x2; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + pol |= 0x1; + regmap_write(lt9611->regmap, 0x831d, pol); - switch (mode->hdisplay) { - case 640: - regmap_write(lt9611->regmap, 0x8326, 0x14); - break; - case 1920: - regmap_write(lt9611->regmap, 0x8326, 0x37); - break; - case 3840: - regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2)); - break; + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + if (lt9611->dsi1_node) { + unsigned int hact = mode->hdisplay; + + hact >>= 2; + hact += 0x50; + hact = min(hact, 0x3e0U); + regmap_write(lt9611->regmap, 0x830b, hact / 256); + regmap_write(lt9611->regmap, 0x830c, hact % 256); + regmap_write(lt9611->regmap, 0x8348, hact / 256); + regmap_write(lt9611->regmap, 0x8349, hact % 256); } + regmap_write(lt9611->regmap, 0x8326, pcr_m); + /* pcr rst */ regmap_write(lt9611->regmap, 0x8011, 0x5a); regmap_write(lt9611->regmap, 0x8011, 0xfa); } -static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) +static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int *postdiv) { unsigned int pclk = mode->clock; const struct reg_sequence reg_cfg[] = { @@ -259,16 +233,21 @@ static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode { 0x8126, 0x55 }, { 0x8127, 0x66 }, { 0x8128, 0x88 }, + { 0x812a, 0x20 }, }; regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); - if (pclk > 150000) + if (pclk > 150000) { regmap_write(lt9611->regmap, 0x812d, 0x88); - else if (pclk > 70000) + *postdiv = 1; + } else if (pclk > 70000) { regmap_write(lt9611->regmap, 0x812d, 0x99); - else + *postdiv = 2; + } else { regmap_write(lt9611->regmap, 0x812d, 0xaa); + *postdiv = 4; + } /* * first divide pclk by 2 first @@ -353,13 +332,55 @@ end: return temp; } -static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) +static void lt9611_hdmi_set_infoframes(struct lt9611 *lt9611, + struct drm_connector *connector, + struct drm_display_mode *mode) { - regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic); - regmap_write(lt9611->regmap, 0x8447, lt9611->vic); - regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */ + union hdmi_infoframe infoframe; + ssize_t len; + u8 iframes = 0x0a; /* UD1 infoframe */ + u8 buf[32]; + int ret; + int i; - regmap_write(lt9611->regmap, 0x82d6, 0x8c); + ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, + connector, + mode); + if (ret < 0) + goto out; + + len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); + if (len < 0) + goto out; + + for (i = 0; i < len; i++) + regmap_write(lt9611->regmap, 0x8440 + i, buf[i]); + + ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, + connector, + mode); + if (ret < 0) + goto out; + + len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); + if (len < 0) + goto out; + + for (i = 0; i < len; i++) + regmap_write(lt9611->regmap, 0x8474 + i, buf[i]); + + iframes |= 0x20; + +out: + regmap_write(lt9611->regmap, 0x843d, iframes); /* UD1 infoframe */ +} + +static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611, bool is_hdmi) +{ + if (is_hdmi) + regmap_write(lt9611->regmap, 0x82d6, 0x8c); + else + regmap_write(lt9611->regmap, 0x82d6, 0x0c); regmap_write(lt9611->regmap, 0x82d7, 0x04); } @@ -448,12 +469,11 @@ static void lt9611_sleep_setup(struct lt9611 *lt9611) { 0x8023, 0x01 }, { 0x8157, 0x03 }, /* set addr pin as output */ { 0x8149, 0x0b }, - { 0x8151, 0x30 }, /* disable IRQ */ + { 0x8102, 0x48 }, /* MIPI Rx power down */ { 0x8123, 0x80 }, { 0x8130, 0x00 }, - { 0x8100, 0x01 }, /* bandgap power down */ - { 0x8101, 0x00 }, /* system clk power down */ + { 0x8011, 0x0a }, }; regmap_multi_reg_write(lt9611->regmap, @@ -564,24 +584,9 @@ static int lt9611_regulator_enable(struct lt9611 *lt9611) return 0; } -static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) { - if (lt9611_modes[i].hdisplay == mode->hdisplay && - lt9611_modes[i].vdisplay == mode->vdisplay && - lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) { - return <9611_modes[i]; - } - } - - return NULL; -} - -/* connector funcs */ -static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) +static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); unsigned int reg_val = 0; int connected = 0; @@ -594,12 +599,6 @@ static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) return lt9611->status; } -static enum drm_connector_status -lt9611_connector_detect(struct drm_connector *connector, bool force) -{ - return __lt9611_detect(connector_to_lt9611(connector)); -} - static int lt9611_read_edid(struct lt9611 *lt9611) { unsigned int temp; @@ -681,36 +680,37 @@ lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) return 0; } -static int lt9611_connector_get_modes(struct drm_connector *connector) -{ - struct lt9611 *lt9611 = connector_to_lt9611(connector); - unsigned int count; - struct edid *edid; - - lt9611_power_on(lt9611); - edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - kfree(edid); - - return count; -} - -static enum drm_mode_status -lt9611_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); - - return lt9611_mode ? MODE_OK : MODE_BAD; -} - /* bridge funcs */ static void lt9611_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + struct drm_atomic_state *state = old_bridge_state->base.state; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; + unsigned int postdiv; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (WARN_ON(!connector)) + return; + + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + mode = &crtc_state->adjusted_mode; + + lt9611_mipi_input_digital(lt9611, mode); + lt9611_pll_setup(lt9611, mode, &postdiv); + lt9611_mipi_video_setup(lt9611, mode); + lt9611_pcr_setup(lt9611, mode, postdiv); if (lt9611_power_on(lt9611)) { dev_err(lt9611->dev, "power on failed\n"); @@ -718,7 +718,8 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, } lt9611_mipi_input_analog(lt9611); - lt9611_hdmi_tx_digital(lt9611); + lt9611_hdmi_set_infoframes(lt9611, connector, mode); + lt9611_hdmi_tx_digital(lt9611, connector->display_info.is_hdmi); lt9611_hdmi_tx_phy(lt9611); msleep(500); @@ -749,25 +750,10 @@ lt9611_bridge_atomic_disable(struct drm_bridge *bridge, } } -static struct -drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = { - .get_modes = lt9611_connector_get_modes, - .mode_valid = lt9611_connector_mode_valid, -}; - -static const struct drm_connector_funcs lt9611_bridge_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = lt9611_connector_detect, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, struct device_node *dsi_node) { - const struct mipi_dsi_device_info info = { "lt9611", 0, NULL }; + const struct mipi_dsi_device_info info = { "lt9611", 0, lt9611->dev->of_node}; struct mipi_dsi_device *dsi; struct mipi_dsi_host *host; struct device *dev = lt9611->dev; @@ -799,70 +785,54 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, return dsi; } -static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611) -{ - int ret; - - ret = drm_connector_init(bridge->dev, <9611->connector, - <9611_bridge_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; - } - - drm_connector_helper_add(<9611->connector, - <9611_bridge_connector_helper_funcs); - - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - - drm_connector_attach_encoder(<9611->connector, bridge->encoder); - - return 0; -} - static int lt9611_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - int ret; - if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { - ret = lt9611_connector_init(bridge, lt9611); - if (ret < 0) - return ret; - } - - return 0; + return drm_bridge_attach(bridge->encoder, lt9611->next_bridge, + bridge, flags); } static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, const struct drm_display_mode *mode) { - struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - if (!lt9611_mode) - return MODE_BAD; - else if (lt9611_mode->intfs > 1 && !lt9611->dsi1) + if (mode->hdisplay > 3840) + return MODE_BAD_HVALUE; + + if (mode->vdisplay > 2160) + return MODE_BAD_VVALUE; + + if (mode->hdisplay == 3840 && + mode->vdisplay == 2160 && + drm_mode_vrefresh(mode) > 30) + return MODE_CLOCK_HIGH; + + if (mode->hdisplay > 2000 && !lt9611->dsi1_node) return MODE_PANEL; else return MODE_OK; } -static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) +static void lt9611_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + static const struct reg_sequence reg_cfg[] = { + { 0x8102, 0x12 }, + { 0x8123, 0x40 }, + { 0x8130, 0xea }, + { 0x8011, 0xfa }, + }; if (!lt9611->sleep) return; - lt9611_reset(lt9611); - regmap_write(lt9611->regmap, 0x80ee, 0x01); + regmap_multi_reg_write(lt9611->regmap, + reg_cfg, ARRAY_SIZE(reg_cfg)); lt9611->sleep = false; } @@ -876,33 +846,6 @@ lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge, lt9611_sleep_setup(lt9611); } -static void lt9611_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adj_mode) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - struct hdmi_avi_infoframe avi_frame; - int ret; - - lt9611_bridge_pre_enable(bridge); - - lt9611_mipi_input_digital(lt9611, mode); - lt9611_pll_setup(lt9611, mode); - lt9611_mipi_video_setup(lt9611, mode); - lt9611_pcr_setup(lt9611, mode); - - ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, - <9611->connector, - mode); - if (!ret) - lt9611->vic = avi_frame.video_code; -} - -static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) -{ - return __lt9611_detect(bridge_to_lt9611(bridge)); -} - static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { @@ -948,11 +891,11 @@ lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs lt9611_bridge_funcs = { .attach = lt9611_bridge_attach, .mode_valid = lt9611_bridge_mode_valid, - .mode_set = lt9611_bridge_mode_set, .detect = lt9611_bridge_detect, .get_edid = lt9611_bridge_get_edid, .hpd_enable = lt9611_bridge_hpd_enable, + .atomic_pre_enable = lt9611_bridge_atomic_pre_enable, .atomic_enable = lt9611_bridge_atomic_enable, .atomic_disable = lt9611_bridge_atomic_disable, .atomic_post_disable = lt9611_bridge_atomic_post_disable, @@ -975,7 +918,7 @@ static int lt9611_parse_dt(struct device *dev, lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode"); - return 0; + return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611->next_bridge); } static int lt9611_gpio_init(struct lt9611 *lt9611) @@ -1108,8 +1051,7 @@ static void lt9611_audio_exit(struct lt9611 *lt9611) } } -static int lt9611_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lt9611_probe(struct i2c_client *client) { struct lt9611 *lt9611; struct device *dev = &client->dev; @@ -1248,7 +1190,7 @@ static struct i2c_driver lt9611_driver = { .name = "lt9611", .of_match_table = lt9611_match_table, }, - .probe = lt9611_probe, + .probe_new = lt9611_probe, .remove = lt9611_remove, .id_table = lt9611_id, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index fa1ee6264d92..583daacf3705 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -844,8 +844,7 @@ static const struct attribute_group *lt9611uxc_attr_groups[] = { NULL, }; -static int lt9611uxc_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lt9611uxc_probe(struct i2c_client *client) { struct lt9611uxc *lt9611uxc; struct device *dev = &client->dev; @@ -1012,7 +1011,7 @@ static struct i2c_driver lt9611uxc_driver = { .of_match_table = lt9611uxc_match_table, .dev_groups = lt9611uxc_attr_groups, }, - .probe = lt9611uxc_probe, + .probe_new = lt9611uxc_probe, .remove = lt9611uxc_remove, .id_table = lt9611uxc_id, }; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 97359f807bfc..4fc494d9084b 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -336,8 +336,7 @@ static int ge_b850v3_register(void) "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr); } -static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, - const struct i2c_device_id *id) +static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c) { struct device *dev = &stdp4028_i2c->dev; int ret; @@ -376,7 +375,7 @@ MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match); static struct i2c_driver stdp4028_ge_b850v3_fw_driver = { .id_table = stdp4028_ge_b850v3_fw_i2c_table, - .probe = stdp4028_ge_b850v3_fw_probe, + .probe_new = stdp4028_ge_b850v3_fw_probe, .remove = stdp4028_ge_b850v3_fw_remove, .driver = { .name = "stdp4028-ge-b850v3-fw", @@ -384,8 +383,7 @@ static struct i2c_driver stdp4028_ge_b850v3_fw_driver = { }, }; -static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c, - const struct i2c_device_id *id) +static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c) { struct device *dev = &stdp2690_i2c->dev; int ret; @@ -424,7 +422,7 @@ MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match); static struct i2c_driver stdp2690_ge_b850v3_fw_driver = { .id_table = stdp2690_ge_b850v3_fw_i2c_table, - .probe = stdp2690_ge_b850v3_fw_probe, + .probe_new = stdp2690_ge_b850v3_fw_probe, .remove = stdp2690_ge_b850v3_fw_remove, .driver = { .name = "stdp2690-ge-b850v3-fw", @@ -440,7 +438,11 @@ static int __init stdpxxxx_ge_b850v3_init(void) if (ret) return ret; - return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver); + ret = i2c_add_driver(&stdp2690_ge_b850v3_fw_driver); + if (ret) + i2c_del_driver(&stdp4028_ge_b850v3_fw_driver); + + return ret; } module_init(stdpxxxx_ge_b850v3_init); diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 0851101a8c72..cd292a2f894c 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -257,8 +257,7 @@ static const struct drm_bridge_funcs ptn3460_bridge_funcs = { .get_edid = ptn3460_get_edid, }; -static int ptn3460_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ptn3460_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ptn3460_bridge *ptn_bridge; @@ -336,7 +335,7 @@ MODULE_DEVICE_TABLE(of, ptn3460_match); static struct i2c_driver ptn3460_driver = { .id_table = ptn3460_i2c_table, - .probe = ptn3460_probe, + .probe_new = ptn3460_probe, .remove = ptn3460_remove, .driver = { .name = "nxp,ptn3460", diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 216af76d0042..e8aae3cdc73d 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -357,13 +357,16 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, return ERR_PTR(-ENOMEM); bridge = drm_panel_bridge_add_typed(panel, connector_type); - if (!IS_ERR(bridge)) { - *ptr = bridge; - devres_add(dev, ptr); - } else { + if (IS_ERR(bridge)) { devres_free(ptr); + return bridge; } + bridge->pre_enable_prev_first = panel->prepare_prev_first; + + *ptr = bridge; + devres_add(dev, ptr); + return bridge; } EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); @@ -402,6 +405,8 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm, if (ret) return ERR_PTR(ret); + bridge->pre_enable_prev_first = panel->prepare_prev_first; + return bridge; } EXPORT_SYMBOL(drmm_panel_bridge_add); diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index 309de802863d..530ee6a19e7e 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -442,9 +442,9 @@ static const struct of_device_id ps8622_devices[] = { }; MODULE_DEVICE_TABLE(of, ps8622_devices); -static int ps8622_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ps8622_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct ps8622_bridge *ps8622; struct drm_bridge *panel_bridge; @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table); static struct i2c_driver ps8622_driver = { .id_table = ps8622_i2c_table, - .probe = ps8622_probe, + .probe_new = ps8622_probe, .remove = ps8622_remove, .driver = { .name = "ps8622", diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 6a614e54b383..4b361d7d5e44 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -15,6 +15,7 @@ #include <drm/display/drm_dp_aux_bus.h> #include <drm/display/drm_dp_helper.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_edid.h> #include <drm/drm_mipi_dsi.h> @@ -442,7 +443,8 @@ static const struct dev_pm_ops ps8640_pm_ops = { pm_runtime_force_resume) }; -static void ps8640_pre_enable(struct drm_bridge *bridge) +static void ps8640_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; @@ -476,7 +478,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge) ps_bridge->pre_enabled = true; } -static void ps8640_post_disable(struct drm_bridge *bridge) +static void ps8640_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); @@ -554,7 +557,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, * EDID, for this chip, we need to do a full poweron, otherwise it will * fail. */ - drm_bridge_chain_pre_enable(bridge); + drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state); edid = drm_get_edid(connector, ps_bridge->page[PAGE0_DP_CNTL]->adapter); @@ -564,7 +567,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, * before, return the chip to its original power state. */ if (poweroff) - drm_bridge_chain_post_disable(bridge); + drm_atomic_bridge_chain_post_disable(bridge, connector->state->state); return edid; } @@ -579,8 +582,11 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = { .attach = ps8640_bridge_attach, .detach = ps8640_bridge_detach, .get_edid = ps8640_bridge_get_edid, - .post_disable = ps8640_post_disable, - .pre_enable = ps8640_pre_enable, + .atomic_post_disable = ps8640_atomic_post_disable, + .atomic_pre_enable = ps8640_atomic_pre_enable, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, }; static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 *ps_bridge) @@ -734,13 +740,13 @@ static int ps8640_probe(struct i2c_client *client) pm_runtime_enable(dev); /* * Powering on ps8640 takes ~300ms. To avoid wasting time on power - * cycling ps8640 too often, set autosuspend_delay to 1000ms to ensure + * cycling ps8640 too often, set autosuspend_delay to 2000ms to ensure * the bridge wouldn't suspend in between each _aux_transfer_msg() call * during EDID read (~20ms in my experiment) and in between the last * _aux_transfer_msg() call during EDID read and the _pre_enable() call * (~100ms in my experiment). */ - pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_set_autosuspend_delay(dev, 2000); pm_runtime_use_autosuspend(dev); pm_suspend_ignore_children(dev, true); ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev); diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 878fb7d3732b..ef66461e7f7c 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -171,7 +171,6 @@ struct sii902x { struct drm_connector connector; struct gpio_desc *reset_gpio; struct i2c_mux_core *i2cmux; - struct regulator_bulk_data supplies[2]; bool sink_is_hdmi; /* * Mutex protects audio and video functions from interfering @@ -240,12 +239,12 @@ static void sii902x_reset(struct sii902x *sii902x) if (!sii902x->reset_gpio) return; - gpiod_set_value(sii902x->reset_gpio, 1); + gpiod_set_value_cansleep(sii902x->reset_gpio, 1); /* The datasheet says treset-min = 100us. Make it 150us to be sure. */ usleep_range(150, 200); - gpiod_set_value(sii902x->reset_gpio, 0); + gpiod_set_value_cansleep(sii902x->reset_gpio, 0); } static enum drm_connector_status sii902x_detect(struct sii902x *sii902x) @@ -1066,12 +1065,12 @@ static int sii902x_init(struct sii902x *sii902x) return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); } -static int sii902x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sii902x_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *endpoint; struct sii902x *sii902x; + static const char * const supplies[] = {"iovcc", "cvcc12"}; int ret; ret = i2c_check_functionality(client->adapter, @@ -1117,32 +1116,17 @@ static int sii902x_probe(struct i2c_client *client, sii902x->next_bridge = of_drm_find_bridge(remote); of_node_put(remote); if (!sii902x->next_bridge) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, + "Failed to find remote bridge\n"); } mutex_init(&sii902x->mutex); - sii902x->supplies[0].supply = "iovcc"; - sii902x->supplies[1].supply = "cvcc12"; - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies), supplies); if (ret < 0) - return ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); - if (ret < 0) { - dev_err_probe(dev, ret, "Failed to enable supplies"); - return ret; - } + return dev_err_probe(dev, ret, "Failed to enable supplies"); - ret = sii902x_init(sii902x); - if (ret < 0) { - regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); - } - - return ret; + return sii902x_init(sii902x); } static void sii902x_remove(struct i2c_client *client) @@ -1152,8 +1136,6 @@ static void sii902x_remove(struct i2c_client *client) i2c_mux_del_adapters(sii902x->i2cmux); drm_bridge_remove(&sii902x->bridge); - regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); } static const struct of_device_id sii902x_dt_ids[] = { @@ -1169,7 +1151,7 @@ static const struct i2c_device_id sii902x_i2c_ids[] = { MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids); static struct i2c_driver sii902x_driver = { - .probe = sii902x_probe, + .probe_new = sii902x_probe, .remove = sii902x_remove, .driver = { .name = "sii902x", diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index 5b3061d4b5c3..099b510ff285 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -886,8 +886,7 @@ static const struct drm_bridge_funcs sii9234_bridge_funcs = { .mode_valid = sii9234_mode_valid, }; -static int sii9234_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sii9234_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct sii9234 *ctx; @@ -961,7 +960,7 @@ static struct i2c_driver sii9234_driver = { .name = "sii9234", .of_match_table = sii9234_dt_match, }, - .probe = sii9234_probe, + .probe_new = sii9234_probe, .remove = sii9234_remove, .id_table = sii9234_id, }; diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 511982a1cedb..b96d03cd878d 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2284,8 +2284,7 @@ static const struct drm_bridge_funcs sii8620_bridge_funcs = { .mode_valid = sii8620_mode_valid, }; -static int sii8620_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sii8620_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct sii8620 *ctx; @@ -2379,7 +2378,7 @@ static struct i2c_driver sii8620_driver = { .name = "sii8620", .of_match_table = of_match_ptr(sii8620_dt_match), }, - .probe = sii8620_probe, + .probe_new = sii8620_probe, .remove = sii8620_remove, .id_table = sii8620_id, }; diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 53259c12d777..f85654f1b104 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -369,6 +369,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi) ctx->bridge.funcs = &tc358764_bridge_funcs; ctx->bridge.of_node = dev->of_node; + ctx->bridge.pre_enable_prev_first = true; drm_bridge_add(&ctx->bridge); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 2a58eb271f70..6d16ec45ea61 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1264,10 +1264,10 @@ static int tc_dsi_rx_enable(struct tc_data *tc) u32 value; int ret; - regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 5); - regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 5); - regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 5); - regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 5); + regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 25); + regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 25); + regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 25); + regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 25); regmap_write(tc->regmap, PPI_D0S_ATMR, 0); regmap_write(tc->regmap, PPI_D1S_ATMR, 0); regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE); @@ -2029,7 +2029,7 @@ static void tc_clk_disable(void *data) clk_disable_unprepare(refclk); } -static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int tc_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc_data *tc; @@ -2209,7 +2209,7 @@ static struct i2c_driver tc358767_driver = { .of_match_table = tc358767_of_ids, }, .id_table = tc358767_i2c_ids, - .probe = tc_probe, + .probe_new = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358767_driver); diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 4c4b77ce8aba..7c0cbe84611b 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -15,7 +15,6 @@ #include <linux/slab.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> @@ -1018,8 +1017,7 @@ static int tc358768_get_regulators(struct tc358768_priv *priv) return ret; } -static int tc358768_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc358768_i2c_probe(struct i2c_client *client) { struct tc358768_priv *priv; struct device *dev = &client->dev; @@ -1085,7 +1083,7 @@ static struct i2c_driver tc358768_driver = { .of_match_table = tc358768_of_ids, }, .id_table = tc358768_i2c_ids, - .probe = tc358768_i2c_probe, + .probe_new = tc358768_i2c_probe, .remove = tc358768_i2c_remove, }; module_i2c_driver(tc358768_driver); diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index 3ceb0e9f9bdc..19316994ddd1 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -23,7 +23,6 @@ #include <drm/display/drm_dp_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -637,7 +636,7 @@ static int tc_attach_host(struct tc_data *tc) return 0; } -static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int tc_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc_data *tc; @@ -729,7 +728,7 @@ static struct i2c_driver tc358775_driver = { .of_match_table = tc358775_of_ids, }, .id_table = tc358775_i2c_ids, - .probe = tc_probe, + .probe_new = tc_probe, .remove = tc_remove, }; module_i2c_driver(tc358775_driver); diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 7ba9467fff12..91ecfbe45bf9 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -346,7 +346,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, /* Deassert reset */ gpiod_set_value_cansleep(ctx->enable_gpio, 1); - usleep_range(1000, 1100); + usleep_range(10000, 11000); /* Get the LVDS format from the bridge state. */ bridge_state = drm_atomic_get_new_bridge_state(state, bridge); @@ -653,9 +653,9 @@ static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) return 0; } -static int sn65dsi83_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sn65dsi83_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; enum sn65dsi83_model model; struct sn65dsi83 *ctx; @@ -730,7 +730,7 @@ static const struct of_device_id sn65dsi83_match_table[] = { MODULE_DEVICE_TABLE(of, sn65dsi83_match_table); static struct i2c_driver sn65dsi83_driver = { - .probe = sn65dsi83_probe, + .probe_new = sn65dsi83_probe, .remove = sn65dsi83_remove, .id_table = sn65dsi83_id, .driver = { diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 05f8756d1aaf..1e26fa63845a 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1852,8 +1852,7 @@ static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata) pdata->supplies); } -static int ti_sn65dsi86_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ti_sn65dsi86_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ti_sn65dsi86 *pdata; @@ -1952,7 +1951,7 @@ static struct i2c_driver ti_sn65dsi86_driver = { .of_match_table = ti_sn65dsi86_match_table, .pm = &ti_sn65dsi86_pm_ops, }, - .probe = ti_sn65dsi86_probe, + .probe_new = ti_sn65dsi86_probe, .id_table = ti_sn65dsi86_id, }; diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index b9635abbad16..6db69df0e18b 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -379,8 +379,7 @@ static struct platform_driver tfp410_platform_driver = { #if IS_ENABLED(CONFIG_I2C) /* There is currently no i2c functionality. */ -static int tfp410_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tfp410_i2c_probe(struct i2c_client *client) { int reg; @@ -411,7 +410,7 @@ static struct i2c_driver tfp410_i2c_driver = { .of_match_table = of_match_ptr(tfp410_match), }, .id_table = tfp410_i2c_ids, - .probe = tfp410_i2c_probe, + .probe_new = tfp410_i2c_probe, .remove = tfp410_i2c_remove, }; #endif /* IS_ENABLED(CONFIG_I2C) */ |