diff options
author | Dave Airlie <airlied@redhat.com> | 2023-06-09 11:42:02 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2023-06-09 11:42:06 +1000 |
commit | 45365b6588b3910c1699d818d0bf3e4c514258c8 (patch) | |
tree | 3a0247b4e921c1f386fa1397b3ce6ef56417b1df | |
parent | 7f4f4adb9ba1d9b292e4b3ade0235be2e5ad5da7 (diff) | |
parent | 13cdd12a9f934158f4ec817cf048fcb4384aa9dc (diff) | |
download | linux-45365b6588b3910c1699d818d0bf3e4c514258c8.tar.gz linux-45365b6588b3910c1699d818d0bf3e4c514258c8.tar.bz2 linux-45365b6588b3910c1699d818d0bf3e4c514258c8.zip |
Merge tag 'drm-misc-next-2023-06-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v6.5:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
Driver Changes:
* bridge
* imx: Fix module linking
* tc358762: Support reset GPIO
* meson
* Add support for MIPI DSI displays; plus fixes and DT bindings
* panel
* Add Support for Rocktech RK043FN48H; plus DT bindings
* Add support for Starry himax83102-j02; plus DT bindings
* Add support for Starry ili9882t; plus DT bindings
* virtio
* Support sync-object UAPI
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20230607085644.GA12673@linux-uq9g
32 files changed, 1989 insertions, 221 deletions
@@ -327,6 +327,7 @@ Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com> Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com> Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com> Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com> +Maxime Ripard <mripard@kernel.org> <maxime@cerno.tech> Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com> Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com> Mayuresh Janorkar <mayur@ti.com> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml new file mode 100644 index 000000000000..a3428f012005 --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-g12a-dw-mipi-dsi.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2020 BayLibre, SAS +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/amlogic,meson-g12a-dw-mipi-dsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic specific extensions to the Synopsys Designware MIPI DSI Host Controller + +maintainers: + - Neil Armstrong <neil.armstrong@linaro.org> + +description: | + The Amlogic Meson Synopsys Designware Integration is composed of + - A Synopsys DesignWare MIPI DSI Host Controller IP + - A TOP control block controlling the Clocks & Resets of the IP + +allOf: + - $ref: dsi-controller.yaml# + +properties: + compatible: + enum: + - amlogic,meson-g12a-dw-mipi-dsi + + reg: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 4 + + clock-names: + minItems: 3 + items: + - const: pclk + - const: bit + - const: px + - const: meas + + resets: + maxItems: 1 + + reset-names: + items: + - const: top + + phys: + maxItems: 1 + + phy-names: + items: + - const: dphy + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Input node to receive pixel data. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: DSI output node to panel. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - phys + - phy-names + - ports + +unevaluatedProperties: false + +examples: + - | + dsi@6000 { + compatible = "amlogic,meson-g12a-dw-mipi-dsi"; + reg = <0x6000 0x400>; + resets = <&reset_top>; + reset-names = "top"; + clocks = <&clk_pclk>, <&bit_clk>, <&clk_px>; + clock-names = "pclk", "bit", "px"; + phys = <&mipi_dphy>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + mipi_dsi_venc_port: port@0 { + reg = <0>; + + mipi_dsi_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + /* DSI Output */ + mipi_dsi_panel_port: port@1 { + reg = <1>; + + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml index 0c72120acc4f..cb0a90f02321 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml @@ -96,6 +96,11 @@ properties: description: A port node pointing to the HDMI-TX port node. + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node pointing to the DPI port node (e.g. DSI or LVDS transceiver). + "#address-cells": const: 1 diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml index 81ca3cbc7abe..6c1de0b21722 100644 --- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml @@ -21,6 +21,9 @@ properties: maxItems: 1 description: virtual channel number of a DSI peripheral + reset-gpios: + maxItems: 1 + vddc-supply: description: Regulator for 1.2V internal core power. diff --git a/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml b/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml index aed55608ebf6..906ef62709b8 100644 --- a/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml +++ b/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml @@ -32,6 +32,10 @@ properties: - innolux,hj110iz-01a # STARRY 2081101QFH032011-53G 10.1" WUXGA TFT LCD panel - starry,2081101qfh032011-53g + # STARRY himax83102-j02 10.51" WUXGA TFT LCD panel + - starry,himax83102-j02 + # STARRY ili9882t 10.51" WUXGA TFT LCD panel + - starry,ili9882t reg: description: the virtual channel number of a DSI peripheral diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index f7c45e38d4b7..1d4936fc5182 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -286,6 +286,8 @@ properties: - rocktech,rk101ii01d-ct # Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel - rocktech,rk070er9427 + # Rocktech Display Ltd. RK043FN48H 4.3" 480x272 LCD-TFT panel + - rocktech,rk043fn48h # Samsung 13.3" FHD (1920x1080 pixels) eDP AMOLED panel - samsung,atna33xc20 # Samsung 12.2" (2560x1600 pixels) TFT LCD panel diff --git a/MAINTAINERS b/MAINTAINERS index 38dc099ad8ff..4a53d061eebd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17387,6 +17387,8 @@ F: include/dt-bindings/clock/qcom,* QUALCOMM CLOUD AI (QAIC) DRIVER M: Jeffrey Hugo <quic_jhugo@quicinc.com> +R: Carl Vanderlip <quic_carlv@quicinc.com> +R: Pranjal Ramajor Asha Kanojiya <quic_pkanojiy@quicinc.com> L: linux-arm-msm@vger.kernel.org L: dri-devel@lists.freedesktop.org S: Supported diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index 608f47f41bcd..9fae28db6aa7 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -1,9 +1,13 @@ if ARCH_MXC || COMPILE_TEST +config DRM_IMX_LDB_HELPER + tristate + config DRM_IMX8QM_LDB tristate "Freescale i.MX8QM LVDS display bridge" depends on OF depends on COMMON_CLK + select DRM_IMX_LDB_HELPER select DRM_KMS_HELPER help Choose this to enable the internal LVDS Display Bridge(LDB) found in @@ -13,6 +17,7 @@ config DRM_IMX8QXP_LDB tristate "Freescale i.MX8QXP LVDS display bridge" depends on OF depends on COMMON_CLK + select DRM_IMX_LDB_HELPER select DRM_KMS_HELPER help Choose this to enable the internal LVDS Display Bridge(LDB) found in diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile index aa90ec8d5433..8e2ebf3399a1 100644 --- a/drivers/gpu/drm/bridge/imx/Makefile +++ b/drivers/gpu/drm/bridge/imx/Makefile @@ -1,9 +1,6 @@ -imx8qm-ldb-objs := imx-ldb-helper.o imx8qm-ldb-drv.o +obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o obj-$(CONFIG_DRM_IMX8QM_LDB) += imx8qm-ldb.o - -imx8qxp-ldb-objs := imx-ldb-helper.o imx8qxp-ldb-drv.o obj-$(CONFIG_DRM_IMX8QXP_LDB) += imx8qxp-ldb.o - obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c index 7338b84bc83d..6967325cd8ee 100644 --- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c +++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c @@ -4,8 +4,10 @@ * Copyright 2019,2020,2022 NXP */ +#include <linux/export.h> #include <linux/media-bus-format.h> #include <linux/mfd/syscon.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> @@ -19,12 +21,14 @@ bool ldb_channel_is_single_link(struct ldb_channel *ldb_ch) { return ldb_ch->link_type == LDB_CH_SINGLE_LINK; } +EXPORT_SYMBOL_GPL(ldb_channel_is_single_link); bool ldb_channel_is_split_link(struct ldb_channel *ldb_ch) { return ldb_ch->link_type == LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS || ldb_ch->link_type == LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS; } +EXPORT_SYMBOL_GPL(ldb_channel_is_split_link); int ldb_bridge_atomic_check_helper(struct drm_bridge *bridge, struct drm_bridge_state *bridge_state, @@ -38,6 +42,7 @@ int ldb_bridge_atomic_check_helper(struct drm_bridge *bridge, return 0; } +EXPORT_SYMBOL_GPL(ldb_bridge_atomic_check_helper); void ldb_bridge_mode_set_helper(struct drm_bridge *bridge, const struct drm_display_mode *mode, @@ -69,6 +74,7 @@ void ldb_bridge_mode_set_helper(struct drm_bridge *bridge, break; } } +EXPORT_SYMBOL_GPL(ldb_bridge_mode_set_helper); void ldb_bridge_enable_helper(struct drm_bridge *bridge) { @@ -81,6 +87,7 @@ void ldb_bridge_enable_helper(struct drm_bridge *bridge) */ regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl); } +EXPORT_SYMBOL_GPL(ldb_bridge_enable_helper); void ldb_bridge_disable_helper(struct drm_bridge *bridge) { @@ -95,6 +102,7 @@ void ldb_bridge_disable_helper(struct drm_bridge *bridge) regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl); } +EXPORT_SYMBOL_GPL(ldb_bridge_disable_helper); int ldb_bridge_attach_helper(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) @@ -117,6 +125,7 @@ int ldb_bridge_attach_helper(struct drm_bridge *bridge, ldb_ch->next_bridge, bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); } +EXPORT_SYMBOL_GPL(ldb_bridge_attach_helper); int ldb_init_helper(struct ldb *ldb) { @@ -157,6 +166,7 @@ int ldb_init_helper(struct ldb *ldb) return 0; } +EXPORT_SYMBOL_GPL(ldb_init_helper); int ldb_find_next_bridge_helper(struct ldb *ldb) { @@ -184,6 +194,7 @@ int ldb_find_next_bridge_helper(struct ldb *ldb) return 0; } +EXPORT_SYMBOL_GPL(ldb_find_next_bridge_helper); void ldb_add_bridge_helper(struct ldb *ldb, const struct drm_bridge_funcs *bridge_funcs) @@ -204,6 +215,7 @@ void ldb_add_bridge_helper(struct ldb *ldb, drm_bridge_add(&ldb_ch->bridge); } } +EXPORT_SYMBOL_GPL(ldb_add_bridge_helper); void ldb_remove_bridge_helper(struct ldb *ldb) { @@ -219,3 +231,8 @@ void ldb_remove_bridge_helper(struct ldb *ldb) drm_bridge_remove(&ldb_ch->bridge); } } +EXPORT_SYMBOL_GPL(ldb_remove_bridge_helper); + +MODULE_DESCRIPTION("i.MX8 LVDS Display Bridge(LDB)/Pixel Mapper bridge helper"); +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/imx/imx8qm-ldb-drv.c b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c index 386032a02599..386032a02599 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qm-ldb-drv.c +++ b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-ldb-drv.c b/drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c index c806576b1e22..c806576b1e22 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qxp-ldb-drv.c +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c index 77f7f7f54757..5641395fd310 100644 --- a/drivers/gpu/drm/bridge/tc358762.c +++ b/drivers/gpu/drm/bridge/tc358762.c @@ -11,6 +11,7 @@ */ #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of_graph.h> @@ -63,6 +64,7 @@ struct tc358762 { struct drm_bridge bridge; struct regulator *regulator; struct drm_bridge *panel_bridge; + struct gpio_desc *reset_gpio; bool pre_enabled; int error; }; @@ -138,6 +140,9 @@ static void tc358762_post_disable(struct drm_bridge *bridge) ctx->pre_enabled = false; + if (ctx->reset_gpio) + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + ret = regulator_disable(ctx->regulator); if (ret < 0) dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); @@ -152,6 +157,11 @@ static void tc358762_pre_enable(struct drm_bridge *bridge) if (ret < 0) dev_err(ctx->dev, "error enabling regulators (%d)\n", ret); + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 10000); + } + ret = tc358762_init(ctx); if (ret < 0) dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); @@ -185,6 +195,11 @@ static int tc358762_parse_dt(struct tc358762 *ctx) ctx->panel_bridge = panel_bridge; + /* Reset GPIO is optional */ + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) + return PTR_ERR(ctx->reset_gpio); + return 0; } diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index 823909da87db..615fdd0ce41b 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -17,3 +17,10 @@ config DRM_MESON_DW_HDMI default y if DRM_MESON select DRM_DW_HDMI imply DRM_DW_HDMI_I2S_AUDIO + +config DRM_MESON_DW_MIPI_DSI + tristate "MIPI DSI Synopsys Controller support for Amlogic Meson Display" + depends on DRM_MESON + default y if DRM_MESON + select DRM_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index 3afa31bdc950..43071bdbd4b9 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -2,7 +2,8 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_encoder_cvbs.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o meson-drm-y += meson_rdma.o meson_osd_afbcd.o -meson-drm-y += meson_encoder_hdmi.o +meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o +obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index ca6d1e59e5d9..747b639ea0c4 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -34,6 +34,7 @@ #include "meson_registers.h" #include "meson_encoder_cvbs.h" #include "meson_encoder_hdmi.h" +#include "meson_encoder_dsi.h" #include "meson_viu.h" #include "meson_vpp.h" #include "meson_rdma.h" @@ -316,32 +317,40 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) goto exit_afbcd; if (has_components) { - ret = component_bind_all(drm->dev, drm); + ret = component_bind_all(dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all components\n"); + /* Do not try to unbind */ + has_components = false; goto exit_afbcd; } } ret = meson_encoder_hdmi_init(priv); if (ret) - goto unbind_all; + goto exit_afbcd; + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + ret = meson_encoder_dsi_init(priv); + if (ret) + goto exit_afbcd; + } ret = meson_plane_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = meson_overlay_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = meson_crtc_create(priv); if (ret) - goto unbind_all; + goto exit_afbcd; ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); if (ret) - goto unbind_all; + goto exit_afbcd; drm_mode_config_reset(drm); @@ -359,15 +368,19 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) uninstall_irq: free_irq(priv->vsync_irq, drm); -unbind_all: - if (has_components) - component_unbind_all(drm->dev, drm); exit_afbcd: if (priv->afbcd.ops) priv->afbcd.ops->exit(priv); free_drm: drm_dev_put(drm); + meson_encoder_dsi_remove(priv); + meson_encoder_hdmi_remove(priv); + meson_encoder_cvbs_remove(priv); + + if (has_components) + component_unbind_all(dev, drm); + return ret; } @@ -394,6 +407,7 @@ static void meson_drv_unbind(struct device *dev) free_irq(priv->vsync_irq, drm); drm_dev_put(drm); + meson_encoder_dsi_remove(priv); meson_encoder_hdmi_remove(priv); meson_encoder_cvbs_remove(priv); @@ -446,10 +460,17 @@ static void meson_drv_shutdown(struct platform_device *pdev) drm_atomic_helper_shutdown(priv->drm); } -/* Possible connectors nodes to ignore */ -static const struct of_device_id connectors_match[] = { - { .compatible = "composite-video-connector" }, - { .compatible = "svideo-connector" }, +/* + * Only devices to use as components + * TOFIX: get rid of components when we can finally + * get meson_dx_hdmi to stop using the meson_drm + * private structure for HHI registers. + */ +static const struct of_device_id components_dev_match[] = { + { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, + { .compatible = "amlogic,meson-gxl-dw-hdmi" }, + { .compatible = "amlogic,meson-gxm-dw-hdmi" }, + { .compatible = "amlogic,meson-g12a-dw-hdmi" }, {} }; @@ -467,17 +488,12 @@ static int meson_drv_probe(struct platform_device *pdev) continue; } - /* If an analog connector is detected, count it as an output */ - if (of_match_node(connectors_match, remote)) { - ++count; - of_node_put(remote); - continue; - } + if (of_match_node(components_dev_match, remote)) { + component_match_add(&pdev->dev, &match, component_compare_of, remote); - dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n", - np, remote, dev_name(&pdev->dev)); - - component_match_add(&pdev->dev, &match, component_compare_of, remote); + dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n", + np, remote, dev_name(&pdev->dev)); + } of_node_put(remote); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index c62ee358456f..b23009a3380f 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -28,6 +28,7 @@ enum vpu_compatible { enum { MESON_ENC_CVBS = 0, MESON_ENC_HDMI, + MESON_ENC_DSI, MESON_ENC_LAST, }; diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c new file mode 100644 index 000000000000..57447abf1a29 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/reset.h> +#include <linux/phy/phy.h> +#include <linux/bitfield.h> + +#include <video/mipi_display.h> + +#include <drm/bridge/dw_mipi_dsi.h> +#include <drm/drm_mipi_dsi.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_print.h> + +#include "meson_drv.h" +#include "meson_dw_mipi_dsi.h" +#include "meson_registers.h" +#include "meson_venc.h" + +#define DRIVER_NAME "meson-dw-mipi-dsi" +#define DRIVER_DESC "Amlogic Meson MIPI-DSI DRM driver" + +struct meson_dw_mipi_dsi { + struct meson_drm *priv; + struct device *dev; + void __iomem *base; + struct phy *phy; + union phy_configure_opts phy_opts; + struct dw_mipi_dsi *dmd; + struct dw_mipi_dsi_plat_data pdata; + struct mipi_dsi_device *dsi_device; + const struct drm_display_mode *mode; + struct clk *bit_clk; + struct clk *px_clk; + struct reset_control *top_rst; +}; + +#define encoder_to_meson_dw_mipi_dsi(x) \ + container_of(x, struct meson_dw_mipi_dsi, encoder) + +static void meson_dw_mipi_dsi_hw_init(struct meson_dw_mipi_dsi *mipi_dsi) +{ + /* Software reset */ + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + mipi_dsi->base + MIPI_DSI_TOP_SW_RESET); + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR | + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING, + 0, mipi_dsi->base + MIPI_DSI_TOP_SW_RESET); + + /* Enable clocks */ + writel_bits_relaxed(MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN, + MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN, + mipi_dsi->base + MIPI_DSI_TOP_CLK_CNTL); + + /* Take memory out of power down */ + writel_relaxed(0, mipi_dsi->base + MIPI_DSI_TOP_MEM_PD); +} + +static int dw_mipi_dsi_phy_init(void *priv_data) +{ + struct meson_dw_mipi_dsi *mipi_dsi = priv_data; + unsigned int dpi_data_format, venc_data_width; + int ret; + + /* Set the bit clock rate to hs_clk_rate */ + ret = clk_set_rate(mipi_dsi->bit_clk, + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate); + if (ret) { + dev_err(mipi_dsi->dev, "Failed to set DSI Bit clock rate %lu (ret %d)\n", + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate, ret); + return ret; + } + + /* Make sure the rate of the bit clock is not modified by someone else */ + ret = clk_rate_exclusive_get(mipi_dsi->bit_clk); + if (ret) { + dev_err(mipi_dsi->dev, + "Failed to set the exclusivity on the bit clock rate (ret %d)\n", ret); + return ret; + } + + ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); + + if (ret) { + dev_err(mipi_dsi->dev, "Failed to set DSI Pixel clock rate %u (%d)\n", + mipi_dsi->mode->clock |