From patchwork Fri Aug 9 16:24:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Guido_G=C3=BCnther?= X-Patchwork-Id: 11087223 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14A4514D5 for ; Fri, 9 Aug 2019 16:24:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0188F1FFCA for ; Fri, 9 Aug 2019 16:24:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E7D682012F; Fri, 9 Aug 2019 16:24:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 33F671FFCA for ; Fri, 9 Aug 2019 16:24:31 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3E87C89CE2; Fri, 9 Aug 2019 16:24:30 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from honk.sigxcpu.org (honk.sigxcpu.org [24.134.29.49]) by gabe.freedesktop.org (Postfix) with ESMTPS id 76BA589309 for ; Fri, 9 Aug 2019 16:24:29 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by honk.sigxcpu.org (Postfix) with ESMTP id 8677FFB06; Fri, 9 Aug 2019 18:24:26 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at honk.sigxcpu.org Received: from honk.sigxcpu.org ([127.0.0.1]) by localhost (honk.sigxcpu.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zhSWzhnDUXoG; Fri, 9 Aug 2019 18:24:24 +0200 (CEST) Received: by bogon.sigxcpu.org (Postfix, from userid 1000) id B0B2540B40; Fri, 9 Aug 2019 18:24:23 +0200 (CEST) From: =?utf-8?q?Guido_G=C3=BCnther?= To: David Airlie , Daniel Vetter , Rob Herring , Mark Rutland , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , NXP Linux Team , Andrzej Hajda , Neil Armstrong , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Lee Jones , =?utf-8?q?Guido_G=C3=BCnther?= , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Robert Chiras , Sam Ravnborg Subject: [PATCH v2 1/3] arm64: imx8mq: add imx8mq iomux-gpr field defines Date: Fri, 9 Aug 2019 18:24:21 +0200 Message-Id: X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP This adds all the gpr registers and the define needed for selecting the input source in the imx-nwl drm bridge. Signed-off-by: Guido Günther --- include/linux/mfd/syscon/imx8mq-iomuxc-gpr.h | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 include/linux/mfd/syscon/imx8mq-iomuxc-gpr.h diff --git a/include/linux/mfd/syscon/imx8mq-iomuxc-gpr.h b/include/linux/mfd/syscon/imx8mq-iomuxc-gpr.h new file mode 100644 index 000000000000..62e85ffacfad --- /dev/null +++ b/include/linux/mfd/syscon/imx8mq-iomuxc-gpr.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017 NXP + * 2019 Purism SPC + */ + +#ifndef __LINUX_IMX8MQ_IOMUXC_GPR_H +#define __LINUX_IMX8MQ_IOMUXC_GPR_H + +#define IOMUXC_GPR0 0x00 +#define IOMUXC_GPR1 0x04 +#define IOMUXC_GPR2 0x08 +#define IOMUXC_GPR3 0x0c +#define IOMUXC_GPR4 0x10 +#define IOMUXC_GPR5 0x14 +#define IOMUXC_GPR6 0x18 +#define IOMUXC_GPR7 0x1c +#define IOMUXC_GPR8 0x20 +#define IOMUXC_GPR9 0x24 +#define IOMUXC_GPR10 0x28 +#define IOMUXC_GPR11 0x2c +#define IOMUXC_GPR12 0x30 +#define IOMUXC_GPR13 0x34 +#define IOMUXC_GPR14 0x38 +#define IOMUXC_GPR15 0x3c +#define IOMUXC_GPR16 0x40 +#define IOMUXC_GPR17 0x44 +#define IOMUXC_GPR18 0x48 +#define IOMUXC_GPR19 0x4c +#define IOMUXC_GPR20 0x50 +#define IOMUXC_GPR21 0x54 +#define IOMUXC_GPR22 0x58 +#define IOMUXC_GPR23 0x5c +#define IOMUXC_GPR24 0x60 +#define IOMUXC_GPR25 0x64 +#define IOMUXC_GPR26 0x68 +#define IOMUXC_GPR27 0x6c +#define IOMUXC_GPR28 0x70 +#define IOMUXC_GPR29 0x74 +#define IOMUXC_GPR30 0x78 +#define IOMUXC_GPR31 0x7c +#define IOMUXC_GPR32 0x80 +#define IOMUXC_GPR33 0x84 +#define IOMUXC_GPR34 0x88 +#define IOMUXC_GPR35 0x8c +#define IOMUXC_GPR36 0x90 +#define IOMUXC_GPR37 0x94 +#define IOMUXC_GPR38 0x98 +#define IOMUXC_GPR39 0x9c +#define IOMUXC_GPR40 0xa0 +#define IOMUXC_GPR41 0xa4 +#define IOMUXC_GPR42 0xa8 +#define IOMUXC_GPR43 0xac +#define IOMUXC_GPR44 0xb0 +#define IOMUXC_GPR45 0xb4 +#define IOMUXC_GPR46 0xb8 +#define IOMUXC_GPR47 0xbc + +/* i.MX8Mq iomux gpr register field defines */ +#define IMX8MQ_GPR13_MIPI_MUX_SEL BIT(2) + +#endif /* __LINUX_IMX8MQ_IOMUXC_GPR_H */ From patchwork Fri Aug 9 16:24:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Guido_G=C3=BCnther?= X-Patchwork-Id: 11087227 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 23CD314D5 for ; Fri, 9 Aug 2019 16:24:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 127B5200CB for ; Fri, 9 Aug 2019 16:24:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 06E27201BD; Fri, 9 Aug 2019 16:24:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8450A200CB for ; Fri, 9 Aug 2019 16:24:36 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A7A9F6EE5C; Fri, 9 Aug 2019 16:24:35 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from honk.sigxcpu.org (honk.sigxcpu.org [24.134.29.49]) by gabe.freedesktop.org (Postfix) with ESMTPS id 846DA89CF5 for ; Fri, 9 Aug 2019 16:24:31 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by honk.sigxcpu.org (Postfix) with ESMTP id D3A35FB02; Fri, 9 Aug 2019 18:24:28 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at honk.sigxcpu.org Received: from honk.sigxcpu.org ([127.0.0.1]) by localhost (honk.sigxcpu.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3YWp7d4m5v1w; Fri, 9 Aug 2019 18:24:26 +0200 (CEST) Received: by bogon.sigxcpu.org (Postfix, from userid 1000) id B904E41DAD; Fri, 9 Aug 2019 18:24:23 +0200 (CEST) From: =?utf-8?q?Guido_G=C3=BCnther?= To: David Airlie , Daniel Vetter , Rob Herring , Mark Rutland , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , NXP Linux Team , Andrzej Hajda , Neil Armstrong , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Lee Jones , =?utf-8?q?Guido_G=C3=BCnther?= , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Robert Chiras , Sam Ravnborg Subject: [PATCH v2 2/3] dt-bindings: display/bridge: Add binding for NWL mipi dsi host controller Date: Fri, 9 Aug 2019 18:24:22 +0200 Message-Id: <9c906bb6592424acdb1a67447a482e010a113b49.1565367567.git.agx@sigxcpu.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP The Northwest Logic MIPI DSI IP core can be found in NXPs i.MX8 SoCs. Signed-off-by: Guido Günther --- .../bindings/display/bridge/nwl-dsi.yaml | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml b/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml new file mode 100644 index 000000000000..5ed8bc4a4d18 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/imx-nwl-dsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Northwest Logic MIPI-DSI on imx SoCs + +maintainers: + - Guido Gúnther + - Robert Chiras + +description: | + NWL MIPI-DSI host controller found on i.MX8 platforms. This is a dsi bridge for + the SOCs NWL MIPI-DSI host controller. + +properties: + compatible: + oneOf: + - items: + - const: fsl,imx8mq-nwl-dsi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: DSI core clock + - description: RX_ESC clock (used in escape mode) + - description: TX_ESC clock (used in escape mode) + - description: PHY_REF clock + + clock-names: + items: + - const: core + - const: rx_esc + - const: tx_esc + - const: phy_ref + + phys: + maxItems: 1 + description: + A phandle to the phy module representing the DPHY + + phy-names: + items: + - const: dphy + + power-domains: + maxItems: 1 + description: + A phandle to the power domain + + resets: + maxItems: 4 + description: + A phandle to the reset controller + + reset-names: + items: + - const: byte + - const: dpi + - const: esc + - const: pclk + + mux-sel: + maxItems: 1 + description: + A phandle to the MUX register set + + port: + type: object + description: + A input put or output port node. + + ports: + type: object + description: + A node containing DSI input & output port nodes with endpoint + definitions as documented in + Documentation/devicetree/bindings/graph.txt. + +patternProperties: + "^panel@[0-9]+$": true + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mq-nwl-dsi + then: + required: + - resets + - reset-names + - mux-sel + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - phys + - phy-names + +examples: + - | + + mipi_dsi: mipi_dsi@30a00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx8mq-nwl-dsi"; + reg = <0x30A00000 0x300>; + clocks = <&clk 163>, <&clk 244>, <&clk 245>, <&clk 164>; + clock-names = "core", "rx_esc", "tx_esc", "phy_ref"; + interrupts = <0 34 4>; + power-domains = <&pgc_mipi>; + resets = <&src 0>, <&src 1>, <&src 2>, <&src 3>; + reset-names = "byte", "dpi", "esc", "pclk"; + mux-sel = <&iomuxc_gpr>; + phys = <&dphy>; + phy-names = "dphy"; + + panel@0 { + compatible = "..."; + port@0 { + panel_in: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mipi_dsi_in: endpoint { + remote-endpoint = <&lcdif_mipi_dsi>; + }; + }; + port@1 { + reg = <1>; + mipi_dsi_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; From patchwork Fri Aug 9 16:24:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Guido_G=C3=BCnther?= X-Patchwork-Id: 11087233 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8449314D5 for ; Fri, 9 Aug 2019 16:24:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6ECBA1FFD9 for ; Fri, 9 Aug 2019 16:24:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 618292015F; Fri, 9 Aug 2019 16:24:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 35E87201BC for ; Fri, 9 Aug 2019 16:24:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9190D6EE5D; Fri, 9 Aug 2019 16:24:38 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from honk.sigxcpu.org (honk.sigxcpu.org [24.134.29.49]) by gabe.freedesktop.org (Postfix) with ESMTPS id 071646EE5C for ; Fri, 9 Aug 2019 16:24:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by honk.sigxcpu.org (Postfix) with ESMTP id 45ABBFB07; Fri, 9 Aug 2019 18:24:33 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at honk.sigxcpu.org Received: from honk.sigxcpu.org ([127.0.0.1]) by localhost (honk.sigxcpu.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vQSvo3y51yAa; Fri, 9 Aug 2019 18:24:27 +0200 (CEST) Received: by bogon.sigxcpu.org (Postfix, from userid 1000) id C686C41E06; Fri, 9 Aug 2019 18:24:23 +0200 (CEST) From: =?utf-8?q?Guido_G=C3=BCnther?= To: David Airlie , Daniel Vetter , Rob Herring , Mark Rutland , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , NXP Linux Team , Andrzej Hajda , Neil Armstrong , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Lee Jones , =?utf-8?q?Guido_G=C3=BCnther?= , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Robert Chiras , Sam Ravnborg Subject: [PATCH v2 3/3] drm/bridge: Add NWL MIPI DSI host controller support Date: Fri, 9 Aug 2019 18:24:23 +0200 Message-Id: <42b0f14d3b58fa2f116a34d052828d1befa25de9.1565367567.git.agx@sigxcpu.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP This adds initial support for the NWL MIPI DSI Host controller found on i.MX8 SoCs. It adds support for the i.MX8MQ but the same IP can be found on e.g. the i.MX8QXP. It has been tested on the Librem 5 devkit using mxsfb. Signed-off-by: Guido Günther Co-developed-by: Robert Chiras --- drivers/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/nwl-dsi/Kconfig | 15 + drivers/gpu/drm/bridge/nwl-dsi/Makefile | 4 + drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c | 484 ++++++++++++++++ drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h | 66 +++ drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c | 700 +++++++++++++++++++++++ drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.h | 112 ++++ 8 files changed, 1384 insertions(+) create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/Kconfig create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/Makefile create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c create mode 100644 drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.h diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 1cc9f502c1f2..7980b5c2156f 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -154,6 +154,8 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig" +source "drivers/gpu/drm/bridge/nwl-dsi/Kconfig" + source "drivers/gpu/drm/bridge/synopsys/Kconfig" endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 4934fcf5a6f8..d9f6c0f77592 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o +obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-dsi/ obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/nwl-dsi/Kconfig b/drivers/gpu/drm/bridge/nwl-dsi/Kconfig new file mode 100644 index 000000000000..27ec86c05401 --- /dev/null +++ b/drivers/gpu/drm/bridge/nwl-dsi/Kconfig @@ -0,0 +1,15 @@ +config DRM_NWL_MIPI_DSI + tristate "Support for Northwest Logic MIPI DSI Host controller" + depends on DRM + depends on COMMON_CLK + depends on OF && HAS_IOMEM + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE + select GENERIC_PHY_MIPI_DPHY + select MFD_SYSCON + select REGMAP_MMIO + help + This enables the Northwest Logic MIPI DSI Host controller as + for example found on NXP's i.MX8 Processors. + diff --git a/drivers/gpu/drm/bridge/nwl-dsi/Makefile b/drivers/gpu/drm/bridge/nwl-dsi/Makefile new file mode 100644 index 000000000000..804baf2f1916 --- /dev/null +++ b/drivers/gpu/drm/bridge/nwl-dsi/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +nwl-mipi-dsi-y := nwl-drv.o nwl-dsi.o +obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-mipi-dsi.o +header-test-y += nwl-drv.h nwl-dsi.h diff --git a/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c b/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c new file mode 100644 index 000000000000..0bd3a4184885 --- /dev/null +++ b/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * i.MX8 NWL MIPI DSI host driver + * + * Copyright (C) 2017 NXP + * Copyright (C) 2019 Purism SPC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nwl-drv.h" +#include "nwl-dsi.h" + +#define DRV_NAME "nwl-dsi" + +/* Possible platform specific clocks */ +#define NWL_DSI_CLK_CORE "core" + +enum nwl_dsi_ext_regs { + NWL_DSI_IMX_REG_GPR = BIT(1), +}; + +static const struct regmap_config nwl_dsi_regmap_config = { + .reg_bits = 16, + .val_bits = 32, + .reg_stride = 4, + .max_register = NWL_DSI_IRQ_MASK2, + .name = DRV_NAME, +}; + +struct nwl_dsi_platform_data { + int (*poweron)(struct nwl_dsi *dsi); + int (*poweroff)(struct nwl_dsi *dsi); + void (*probe)(struct nwl_dsi *dsi); + void (*select_input)(struct nwl_dsi *dsi); + u32 ext_regs; /* required external registers */ + struct nwl_dsi_plat_clk_config clk_config[NWL_DSI_MAX_PLATFORM_CLOCKS]; +}; + +static inline struct nwl_dsi *bridge_to_dsi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct nwl_dsi, bridge); +} + +static int nwl_dsi_set_platform_clocks(struct nwl_dsi *dsi, bool enable) +{ + struct device *dev = dsi->dev; + const char *id; + struct clk *clk; + size_t i; + unsigned long rate; + int ret, result = 0; + + DRM_DEV_DEBUG_DRIVER(dev, "%s platform clocks\n", + enable ? "enabling" : "disabling"); + for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) { + if (!dsi->clk_config[i].present) + continue; + id = dsi->clk_config[i].id; + clk = dsi->clk_config[i].clk; + + if (enable) { + ret = clk_prepare_enable(clk); + if (ret < 0) { + DRM_DEV_ERROR(dev, + "Failed to enable %s clk: %d\n", + id, ret); + result = result ?: ret; + } + rate = clk_get_rate(clk); + DRM_DEV_DEBUG_DRIVER(dev, "Enabled %s clk @%lu Hz\n", + id, rate); + } else { + clk_disable_unprepare(clk); + DRM_DEV_DEBUG_DRIVER(dev, "Disabled %s clk\n", id); + } + } + + return result; +} + +static int nwl_dsi_plat_enable(struct nwl_dsi *dsi) +{ + struct device *dev = dsi->dev; + int ret; + + ret = nwl_dsi_set_platform_clocks(dsi, true); + if (ret < 0) + return ret; + + ret = dsi->pdata->poweron(dsi); + if (ret < 0) + DRM_DEV_ERROR(dev, "Failed to power on DSI: %d\n", ret); + return ret; +} + +static void nwl_dsi_plat_disable(struct nwl_dsi *dsi) +{ + dsi->pdata->poweroff(dsi); + nwl_dsi_set_platform_clocks(dsi, false); +} + +static void nwl_dsi_bridge_disable(struct drm_bridge *bridge) +{ + struct nwl_dsi *dsi = bridge_to_dsi(bridge); + + nwl_dsi_disable(dsi); + nwl_dsi_plat_disable(dsi); + pm_runtime_put(dsi->dev); +} + +static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi, + const struct drm_display_mode *mode, + union phy_configure_opts *phy_opts) +{ + unsigned long rate; + int ret; + + if (dsi->lanes < 1 || dsi->lanes > 4) + return -EINVAL; + + /* + * So far the DPHY spec minimal timings work for both mixel + * dphy and nwl dsi host + */ + ret = phy_mipi_dphy_get_default_config( + mode->crtc_clock * 1000, + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes, + &phy_opts->mipi_dphy); + if (ret < 0) + return ret; + + rate = clk_get_rate(dsi->tx_esc_clk); + DRM_DEV_DEBUG_DRIVER(dsi->dev, "LP clk is @%lu Hz\n", rate); + phy_opts->mipi_dphy.lp_clk_rate = rate; + + return 0; +} + +static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* At least LCDIF + NWL needs active high sync */ + adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); + adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); + + return true; +} + +static enum drm_mode_status +nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct nwl_dsi *dsi = bridge_to_dsi(bridge); + int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); + + if (mode->clock * bpp > 15000000) + return MODE_CLOCK_HIGH; + + if (mode->clock * bpp < 80000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static void +nwl_dsi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct nwl_dsi *dsi = bridge_to_dsi(bridge); + struct device *dev = dsi->dev; + union phy_configure_opts new_cfg; + unsigned long phy_ref_rate; + int ret; + + ret = nwl_dsi_get_dphy_params(dsi, adjusted_mode, &new_cfg); + if (ret < 0) + return; + + /* + * If hs clock is unchanged, we're all good - all parameters are + * derived from it atm. + */ + if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate) + return; + + phy_ref_rate = clk_get_rate(dsi->phy_ref_clk); + DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate); + /* Save the new desired phy config */ + memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg)); + + memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode)); + drm_mode_debug_printmodeline(adjusted_mode); +} + +static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct nwl_dsi *dsi = bridge_to_dsi(bridge); + + dsi->pdata->select_input(dsi); + pm_runtime_get_sync(dsi->dev); + nwl_dsi_plat_enable(dsi); + nwl_dsi_enable(dsi); +} + +static int nwl_dsi_bridge_attach(struct drm_bridge *bridge) +{ + struct nwl_dsi *dsi = bridge->driver_private; + + return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge); +} + +static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = { + .pre_enable = nwl_dsi_bridge_pre_enable, + .disable = nwl_dsi_bridge_disable, + .mode_fixup = nwl_dsi_bridge_mode_fixup, + .mode_set = nwl_dsi_bridge_mode_set, + .mode_valid = nwl_dsi_bridge_mode_valid, + .attach = nwl_dsi_bridge_attach, +}; + +static int nwl_dsi_parse_dt(struct nwl_dsi *dsi) +{ + struct device_node *np = dsi->dev->of_node; + struct platform_device *pdev = to_platform_device(dsi->dev); + struct clk *clk; + const char *clk_id; + void __iomem *base; + int i, ret; + + dsi->phy = devm_phy_get(dsi->dev, "dphy"); + if (IS_ERR(dsi->phy)) { + ret = PTR_ERR(dsi->phy); + DRM_DEV_ERROR(dsi->dev, "Could not get PHY: %d\n", ret); + return ret; + } + + /* Platform dependent clocks */ + memcpy(dsi->clk_config, dsi->pdata->clk_config, + sizeof(dsi->pdata->clk_config)); + + for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) { + if (!dsi->clk_config[i].present) + continue; + + clk_id = dsi->clk_config[i].id; + clk = devm_clk_get(dsi->dev, clk_id); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + DRM_DEV_ERROR(dsi->dev, "Failed to get %s clock: %d\n", + clk_id, ret); + return ret; + } + DRM_DEV_DEBUG_DRIVER(dsi->dev, "Setup clk %s (rate: %lu)\n", + clk_id, clk_get_rate(clk)); + dsi->clk_config[i].clk = clk; + } + + /* DSI clocks */ + clk = devm_clk_get(dsi->dev, "phy_ref"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + DRM_DEV_ERROR(dsi->dev, "Failed to get phy_ref clock: %d\n", + ret); + return ret; + } + dsi->phy_ref_clk = clk; + + clk = devm_clk_get(dsi->dev, "rx_esc"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + DRM_DEV_ERROR(dsi->dev, "Failed to get rx_esc clock: %d\n", + ret); + return ret; + } + dsi->rx_esc_clk = clk; + + clk = devm_clk_get(dsi->dev, "tx_esc"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + DRM_DEV_ERROR(dsi->dev, "Failed to get tx_esc clock: %d\n", + ret); + return ret; + } + dsi->tx_esc_clk = clk; + + dsi->mux_sel = syscon_regmap_lookup_by_phandle(np, "mux-sel"); + if (IS_ERR(dsi->mux_sel) && + (dsi->pdata->ext_regs & NWL_DSI_IMX_REG_GPR)) { + ret = PTR_ERR(dsi->mux_sel); + DRM_DEV_ERROR(dsi->dev, "Failed to get GPR regmap: %d\n", ret); + return ret; + } + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + dsi->regmap = + devm_regmap_init_mmio(dsi->dev, base, &nwl_dsi_regmap_config); + if (IS_ERR(dsi->regmap)) { + ret = PTR_ERR(dsi->regmap); + DRM_DEV_ERROR(dsi->dev, "Failed to create NWL DSI regmap: %d\n", + ret); + return ret; + } + + dsi->irq = platform_get_irq(pdev, 0); + if (dsi->irq < 0) { + DRM_DEV_ERROR(dsi->dev, "Failed to get device IRQ: %d\n", + dsi->irq); + return dsi->irq; + } + + dsi->rstc = devm_reset_control_array_get(dsi->dev, false, true); + if (IS_ERR(dsi->rstc)) { + DRM_DEV_ERROR(dsi->dev, "Failed to get resets: %ld\n", + PTR_ERR(dsi->rstc)); + return PTR_ERR(dsi->rstc); + } + + return 0; +} + +static void imx8mq_dsi_select_input(struct nwl_dsi *dsi) +{ + struct device_node *remote; + u32 mux_val = IMX8MQ_GPR13_MIPI_MUX_SEL; + + remote = of_graph_get_remote_node(dsi->dev->of_node, 0, 0); + if (strcmp(remote->name, "lcdif") == 0) + mux_val = 0; + + DRM_DEV_INFO(dsi->dev, "Using %s as input source\n", + (mux_val) ? "DCSS" : "LCDIF"); + regmap_update_bits(dsi->mux_sel, IOMUXC_GPR13, + IMX8MQ_GPR13_MIPI_MUX_SEL, mux_val); + of_node_put(remote); +} + +static int imx8mq_dsi_poweron(struct nwl_dsi *dsi) +{ + int ret = 0; + + /* otherwise the display stays blank */ + usleep_range(200, 300); + + if (dsi->rstc) + ret = reset_control_deassert(dsi->rstc); + + return ret; +} + +static int imx8mq_dsi_poweroff(struct nwl_dsi *dsi) +{ + int ret = 0; + + if (dsi->quirks & SRC_RESET_QUIRK) + return 0; + + if (dsi->rstc) + ret = reset_control_assert(dsi->rstc); + return ret; +} + +static const struct drm_bridge_timings nwl_dsi_timings = { + .input_bus_flags = DRM_BUS_FLAG_DE_LOW, +}; + +static const struct nwl_dsi_platform_data imx8mq_dev = { + .poweron = &imx8mq_dsi_poweron, + .poweroff = &imx8mq_dsi_poweroff, + .select_input = &imx8mq_dsi_select_input, + .clk_config = { + { .id = NWL_DSI_CLK_CORE, .present = true }, + }, + .ext_regs = NWL_DSI_IMX_REG_GPR, +}; + +static const struct of_device_id nwl_dsi_dt_ids[] = { + { .compatible = "fsl,imx8mq-nwl-dsi", .data = &imx8mq_dev, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids); + +static const struct soc_device_attribute nwl_dsi_quirks_match[] = { + { .soc_id = "i.MX8MQ", .revision = "2.0", + .data = (void *)(E11418_HS_MODE_QUIRK | SRC_RESET_QUIRK) }, + { /* sentinel. */ }, +}; + +static int nwl_dsi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = of_match_device(nwl_dsi_dt_ids, dev); + const struct nwl_dsi_platform_data *pdata = of_id->data; + const struct soc_device_attribute *attr; + struct nwl_dsi *dsi; + int ret; + + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return -ENOMEM; + + dsi->dev = dev; + dsi->pdata = pdata; + + ret = nwl_dsi_parse_dt(dsi); + if (ret) + return ret; + + ret = devm_request_irq(dev, dsi->irq, nwl_dsi_irq_handler, 0, + dev_name(dev), dsi); + if (ret < 0) { + DRM_DEV_ERROR(dev, "Failed to request IRQ %d: %d\n", dsi->irq, + ret); + return ret; + } + + dsi->dsi_host.ops = &nwl_dsi_host_ops; + dsi->dsi_host.dev = dev; + ret = mipi_dsi_host_register(&dsi->dsi_host); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret); + return ret; + } + + attr = soc_device_match(nwl_dsi_quirks_match); + if (attr) + dsi->quirks = (uintptr_t)attr->data; + + dsi->bridge.driver_private = dsi; + dsi->bridge.funcs = &nwl_dsi_bridge_funcs; + dsi->bridge.of_node = dev->of_node; + dsi->bridge.timings = &nwl_dsi_timings; + + drm_bridge_add(&dsi->bridge); + + dev_set_drvdata(dev, dsi); + pm_runtime_enable(dev); + return 0; +} + +static int nwl_dsi_remove(struct platform_device *pdev) +{ + struct nwl_dsi *dsi = platform_get_drvdata(pdev); + + mipi_dsi_host_unregister(&dsi->dsi_host); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static struct platform_driver nwl_dsi_driver = { + .probe = nwl_dsi_probe, + .remove = nwl_dsi_remove, + .driver = { + .of_match_table = nwl_dsi_dt_ids, + .name = DRV_NAME, + }, +}; + +module_platform_driver(nwl_dsi_driver); + +MODULE_AUTHOR("NXP Semiconductor"); +MODULE_AUTHOR("Purism SPC"); +MODULE_DESCRIPTION("Northwest Logic MIPI-DSI driver"); +MODULE_LICENSE("GPL"); /* GPLv2 or later */ diff --git a/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h b/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h new file mode 100644 index 000000000000..65fed25fc9b9 --- /dev/null +++ b/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * NWL MIPI DSI host driver + * + * Copyright (C) 2017 NXP + * Copyright (C) 2019 Purism SPC + */ + +#ifndef __NWL_DRV_H__ +#define __NWL_DRV_H__ + +#include + +#include +#include + +struct nwl_dsi_platform_data; + +/* i.MX8 NWL quirks */ +/* i.MX8MQ errata E11418 */ +#define E11418_HS_MODE_QUIRK BIT(0) +/* Skip DSI bits in SRC on disable to avoid blank display on enable */ +#define SRC_RESET_QUIRK BIT(1) + +#define NWL_DSI_MAX_PLATFORM_CLOCKS 1 +struct nwl_dsi_plat_clk_config { + const char *id; + struct clk *clk; + bool present; +}; + +struct nwl_dsi { + struct drm_bridge bridge; + struct mipi_dsi_host dsi_host; + struct drm_bridge *panel_bridge; + struct device *dev; + struct phy *phy; + union phy_configure_opts phy_cfg; + unsigned int quirks; + + struct regmap *regmap; + int irq; + struct reset_control *rstc; + + /* External registers */ + struct regmap *mux_sel; + + /* DSI clocks */ + struct clk *phy_ref_clk; + struct clk *rx_esc_clk; + struct clk *tx_esc_clk; + /* Platform dependent clocks */ + struct nwl_dsi_plat_clk_config clk_config[NWL_DSI_MAX_PLATFORM_CLOCKS]; + + /* dsi lanes */ + u32 lanes; + enum mipi_dsi_pixel_format format; + struct drm_display_mode mode; + unsigned long dsi_mode_flags; + + struct nwl_dsi_transfer *xfer; + + const struct nwl_dsi_platform_data *pdata; +}; + +#endif /* __NWL_DRV_H__ */ diff --git a/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c new file mode 100644 index 000000000000..fd030af55bb4 --- /dev/null +++ b/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NWL MIPI DSI host driver + * + * Copyright (C) 2017 NXP + * Copyright (C) 2019 Purism SPC + */ + +#include +#include +#include +#include +#include + +#include