From patchwork Tue May 21 10:58:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668824 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C100EC25B77 for ; Tue, 21 May 2024 02:58:37 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 435C210E215; Tue, 21 May 2024 02:58:33 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2139.outbound.protection.partner.outlook.cn [139.219.17.139]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7FE8E10E051 for ; Tue, 21 May 2024 02:58:31 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=bDvf08b3mYfLZqMxLL/YU/cAuzI+YgriLKHVlP22sjIQA3MBomL8XBSG24hZfmgSJU0Gi/9+rMrF0ngHkldh/NvSgBTjGNNst7cE8hWaffgi+R1rrBYaD5TEj5Emg9oKyEdLEFTr2wM9QC3ty0BqP5ozusqS/N56gWv4bdntL1dIV9WLVrwRK0eqcORetB57TdxgK1tA8NOzNq8eGlnH3/MBgguf+JPdBu1ep3x1iUqmhV9JNNKpjq4t+/6m6OpMG9Asueoaf7iXsILKLwF0daKTs+Hzz6xNfZIuVhtdQO2asrUdmLjTBXeqZnTbPNOVZiNGX2AUWNEYRrqgUwNhoQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=k5VUIs5MMdlJBghMXADd8XuNM290vTkawbPugNbSF5c=; b=ljGx9q7j0sRSB6nEJm/FHbxzwkZPrdYd4eW9T0/5avrHr+niRE3U6evA/Ot6oTs1eVLi49ET+oazDDSPpAsM2AO5McKZORLNv0XsCAVPrVKtIxEeLDq93kH/Rb++ZXKQFugryHzEeqnH06fvBpeX4sXX7JJmXv3hSX+dVeppNZkiDaGRQcDAu8ZxGSFqbhHzPGOFyXmSKIz6tI3lf8gHrdQZjuVRU63SAAZOG495tg49nNzLEJOC7HZoE+eBHBxvI00nKa0AKFAPBVmwgraGfAC/4rdpBjPf5NYn0LDhKe32dhdp/bWbEktv+ettmNdH2e6cfgk2hOHv5dCLqT96Sw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1255.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:19::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.36; Tue, 21 May 2024 02:58:26 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:26 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 01/10] dt-bindings: display: Add YAML schema for JH7110 display pipeline Date: Tue, 21 May 2024 18:58:08 +0800 Message-Id: <20240521105817.3301-2-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1255:EE_ X-MS-Office365-Filtering-Correlation-Id: 9a9bd704-9c9c-4091-1f94-08dc7941e2d4 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; ARA:13230031|366007|41320700004|1800799015|7416005|52116005|921011|38350700005; X-Microsoft-Antispam-Message-Info: n2h6KG2idrbtjLH3cJrOZlvC3/zpleNsoJzW3tkBtC8tGqzFfjQXlBM6lH7i69g9M3plRsnlvSfL5dCqhcPGrKCElMxceb7jnQvXrRHsK8VoqkQ+gs/CMwC2Ho/ofWxeG3/kc0TqDLfGSbTwVQfxAd5Rdxvb6lUUCJ+OXIqEG+Jkz74HX5t3JwqAjf0wnJR4qYFVqytaH/HFfPh5k87VdoQYXVtz9RBp7UdludA8uBXL2vtJUjXTzSyLFRUssLDvnRr5Odzh885OyDm58PkAXtW6zUW06P4ciETtWRQVH/OCAYJdNwBY/kYaje/1evF3Ei/EFe/YZa9EvVtyBqLTglxTj3pKzvy+02tJmhy9lxayRwzc82shL/iLXAiy0hdj82n6Gw3mUbaMjM8Fd4Uf2RiFJnFY2PiNI5XzovhRpAX111pENaJNPqXt0xnr9O4mQrwy+4vPf3z+6DJ/6o9T7h8XaEKQDuA5piyIDIrUS92y9RpnkWWlJLlctQfcdLbswpMmWPzKqchlz/5W8TPvVgXFUFDxJoIPEp2g5nmSyB525RoK9VCADaxcrWLpRP1bDzbIaJDAmzGEKIqD2Mev3YpjvP+vMtb5yeqXJ4ZqzU5T0kqU7D89/msokFNIaw3ZxnCUd7QWBKcs3fZq/hUIwg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(366007)(41320700004)(1800799015)(7416005)(52116005)(921011)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: BuR1p1pSS4aaMoRyH50CHuQ4U72whXbfr7+BlvFAmVMv1HYkOpid9/W+AD9OTm1G4puPBJTR5lwNwm1P7suBSHyhbaxYRP1yW8OfhBIuonW/JS68TxAfDzjo6to1Fhq4vcdRAC39havT2sCF1OdHug448vveF/h7sgf5rRfkQPOv1MmKkhx3dDQWIEntLMh1kzETXYIF861jopGDuUmpgT8W7Z893JZ8QeNe3SRpWhb99mx6kzCgnOrluQfnSXsSMlFasEpVnEH0lg3Si1vWIT/5U3Zv941VNUl+u7E+nBv6SrW6XzTbMhFdPv2w68MPkzvjs5jRPuRxArPGH39xLDopeDRSPYSGEI9dHmD8sRUKreedFfuZmngXk782faiVvyItSLOMrUZvI8j3Nu5ybG85CBMrFRFT0Jjrbsw3vCXmXvqxTSqq9lJMNuU2a23U3McAnrG51KxE0iPoscdLjA21ftLIkwSx7Prsep3brZcXElAcD+v7nB2pIL5esPUvxajqRDEOgtjSP7opF+5+4yHB+tzjA5RVqgKOyYNkeosqiVqD9yiB5KhPdLC0HOXevU89fieesx5VTpzxish1L5f+cA9tUGkkpDlbl9Q0+vSV2E3T2i+1WB6aKAkPWUYa1cOgLn1syowjYm+fx/plQWQXdTpKF5Iuhg29k9HBvVGRIk1mNYPFNyVg0EmBKl2AxVCTfVqOj1Xj2nTPcznMQOgYUUNhW15QepeFEZKZIiEbHvJx4aJAHHhhp/6f3DPPDkS9xv8ikvkpjzk95+G/m0hZcIaTGFM8nVvlZxKmegrNU+Ct8716Qv3DmdiGpGPBUL8xPSchbv6Wz4nzoIe35sI2OA18DfNgGK3FxdL6swfZM6T9YSShGIoW5SHlnAuFb+KNytHogfeAMlk2TI7HC7aex+y4icV1sAE+cvOz97XDWANkC99KrYZj9kzqhiTetZwpLkYLFi3dDYcah+1TjPZL4WeFM0j536ncSqf73dBnARUwuL3QZpcihmzunSNrFGzCkCRVqDWQMe6GbDjdY5pWuRn+91BOYncxxHFfxrVPJY5IB2bizw++baJNP78nPZj2WfBVVeiIVs82dkyvx+5gazy4ASSQOuY9zimpEUDL1vfbZ1cMkS4iMPH59WkeFDQVNsws5V0qOD0JKlWsOtzFGvbNnut6qoWKD7MDoCtz4Dvoagm0J/moXc5eu9DrEm/CDAOKFL9SakVgVmwciTEeuDJbOs0uQJ3uLzUot58q0weU//jQ0WpCy7L0p6KYjMbbfqjdB3qoqrZMZ9ls6aUtSfmpk43xB3XBKQ6OKCp7Hd1znHAw4wCU021wDdlmQTOoJb2cRHyI4jp6YrfW2F8bvWnt0eKW2FObU3xxO2jEPyNjS5Xuq822JihAAFzayaeJ3h1Md2pGAj9BBonQIWy6BopCjQQQxxD9tDLFv5+LhZglDr8in2jIwaSeBaHuXOyI+BH4VnNChunLd90BVIgydt4Vauk/WgmjT3CgfvZJgmn2/SHh1n3TFQlHngnFcG5tOMgugyfaxIIz/lTfLJztT0/pzEyR4zfKeBa71bwrjwQZccH3jHybPyCgTJBMW4XwzofsghP2W2YFYBxVKA== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9a9bd704-9c9c-4091-1f94-08dc7941e2d4 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:26.5977 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 4Ij55wm/vMphgWFYssISW5nuOES20StNfwQdRiMC0eKRB3pjy1y/WaHMiY/t/Hp15n8bf0YxKdcUeO92pCbvagAzTqpTCoA6F55i8WoSiIw= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1255 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" JH7110 SoC display pipeline includes a display controller and hdmi. Dc controller IP : Vivante DC8200 Dual Display HDMI IP : INNOSILICON HDMI2.0 As the INNO hdmi ip is also used by rockchip SoC in the driver code, the innosilicon,inno-hdmi.yaml schema containing the common properties for the INNO DesignWare HDMI TX controller isn't a full device tree binding specification, but is meant to be referenced by platform-specific bindings for the IP core. Signed-off-by: keith --- .../display/bridge/innosilicon,inno-hdmi.yaml | 49 +++++ .../display/rockchip/rockchip,inno-hdmi.yaml | 27 +-- .../starfive/starfive,dsi-encoder.yaml | 92 ++++++++++ .../starfive/starfive,jh7110-dc8200.yaml | 169 ++++++++++++++++++ .../starfive/starfive,jh7110-inno-hdmi.yaml | 75 ++++++++ .../soc/starfive/starfive,jh7110-syscon.yaml | 1 + MAINTAINERS | 8 + 7 files changed, 396 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml create mode 100644 Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml new file mode 100644 index 000000000000..8540174dcaeb --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/innosilicon,inno-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Common Properties for Innosilicon HDMI TX IP + +maintainers: + - Keith Zhao + +description: | + This document defines device tree properties for the Innosilicon HDMI TX + controller (INNO HDMI) IP core. It doesn't constitute a full device tree + binding specification by itself but is meant to be referenced by device tree + bindings for the platform-specific integrations of the INNO HDMI. + + When referenced from platform device tree bindings the properties defined in + this document are defined as follows. The platform device tree bindings are + responsible for defining whether each property is required or optional. + +properties: + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a display controller node. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a hdmi-connector node. + + required: + - port@0 + - port@1 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml index 5b87b0f1963e..589dedfcbee0 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml @@ -16,12 +16,6 @@ properties: - rockchip,rk3036-inno-hdmi - rockchip,rk3128-inno-hdmi - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - clocks: minItems: 1 items: @@ -40,24 +34,6 @@ properties: "#sound-dai-cells": const: 0 - ports: - $ref: /schemas/graph.yaml#/properties/ports - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: - Port node with one endpoint connected to a vop node. - - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: - Port node with one endpoint connected to a hdmi-connector node. - - required: - - port@0 - - port@1 - required: - compatible - reg @@ -69,6 +45,7 @@ required: - ports allOf: + - $ref: ../bridge/innosilicon,inno-hdmi.yaml# - $ref: /schemas/sound/dai-common.yaml# - if: properties: @@ -95,7 +72,7 @@ allOf: required: - power-domains -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml new file mode 100644 index 000000000000..07aa147a9db1 --- /dev/null +++ b/Documentation/devicetree/bindings/display/starfive/starfive,dsi-encoder.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/starfive/starfive,dsi-encoder.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: starfive jh7110 SoC Encoder + +maintainers: + - Keith Zhao + +description: + Device-Tree bindings for simple encoder. + Simple encoder driver only has basic functionality. + the hardware of dc8200 has 2 output interface, and uses + syscon to select which one to be used. + +properties: + compatible: + const: starfive,dsi-encoder + + starfive,syscon: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to syscon that select crtc output. + - description: Offset of crtc selection + - description: Shift of crtc selection + description: + A phandle to syscon with two arguments that configure select output. + The argument one is the offset of crtc selection, the + argument two is the shift of crtc selection. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + The first port should be the input coming from the associated dc channel. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + The second port should be the output coming from the associated bridge. + + required: + - port@0 + - port@1 + +required: + - compatible + - ports + +additionalProperties: false + +examples: + - | + dssctrl: dssctrl@295b0000 { + compatible = "starfive,jh7110-vout-syscon", "syscon"; + reg = <0x295b0000 0x90>; + }; + + dsi_encoder: dsi_encoder { + compatible = "starfive,dsi-encoder"; + starfive,syscon = <&dssctrl 0x8 0x12>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + /* input */ + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + dsi_input0:endpoint@0 { + reg = <0>; + remote-endpoint = <&dc_out_dpi1>; + }; + }; + /* output */ + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + dsi_out:endpoint { + remote-endpoint = <&mipi_in>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml new file mode 100644 index 000000000000..a28dfdd471b6 --- /dev/null +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-dc8200.yaml @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-dc8200.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STARFIVE JH7110 SoC display controller + +description: + The STARFIVE JH7110 SoC uses the display controller based on Verisilicon IP(DC8200) + to transfer the image data from a video memory buffer to an external LCD interface. + + pipe0 binds HDMI for primary display, + pipe1 binds DSI for external display. + + +------------------------------+ + | | + | | + +----+ | +-------------------+ | +-------+ +------+ +------+ + | +----->+ dc controller 0 +--->----->+HDMICtl| ->+ PHY +-->+PANEL0+ + |AXI | | +-------------------+ | +-------+ +------+ +------+ + | | | | + | | | | + | | | | + | | | | + |APB | | +-------------------+ +---------+ +------+ +-------+ + | +----->+ dc controller 1 +--->---->+ dsiTx +--->+DPHY +->+ PANEL1+ + | | | +-------------------+ +---------+ +------+ +-------+ + +----+ | | + +------------------------------+ + +maintainers: + - Keith Zhao + +properties: + compatible: + const: starfive,jh7110-dc8200 + + reg: + items: + - description: host interface address and length + - description: display physical base address and length + + reg-names: + items: + - const: host + - const: base + + clocks: + items: + - description: Clock for display system noc bus. + - description: Core clock for display controller. + - description: Clock for axi bus to access ddr. + - description: Clock for ahb bus to R/W the phy regs. + - description: Pixel clock for display channel 0. + - description: Pixel clock for display channel 1. + - description: Pixel clock from hdmi. + - description: Pixel clock for soc . + + clock-names: + items: + - const: noc_bus + - const: dc_core + - const: axi_core + - const: ahb + - const: channel0 + - const: channel1 + - const: hdmi_tx + - const: dc_parent + + resets: + items: + - description: Reset for axi bus. + - description: Reset for ahb bus. + - description: Core reset of display controller. + + reset-names: + items: + - const: axi + - const: ahb + - const: core + + interrupts: + items: + - description: The interrupt will be generated when DC finish one frame + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + channel 0 output + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + channel 1 output + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - ports + +additionalProperties: false + +examples: + - | + #include + #include + dc8200: lcd-controller@29400000 { + compatible = "starfive,jh7110-dc8200"; + reg = <0x29400000 0x100>, + <0x29400800 0x2000>; + reg-names = "host", "base"; + + interrupts = <95>; + clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>, + <&voutcrg JH7110_VOUTCLK_DC8200_CORE>, + <&voutcrg JH7110_VOUTCLK_DC8200_AXI>, + <&voutcrg JH7110_VOUTCLK_DC8200_AHB>, + <&voutcrg JH7110_VOUTCLK_DC8200_PIX0>, + <&voutcrg JH7110_VOUTCLK_DC8200_PIX1>, + <&hdmitx0_pixelclk>, + <&voutcrg JH7110_VOUTCLK_DC8200_PIX>; + clock-names = "noc_bus", "dc_core", "axi_core", "ahb", + "channel0", "channel1", "hdmi_tx", "dc_parent"; + resets = <&voutcrg JH7110_VOUTRST_DC8200_AXI>, + <&voutcrg JH7110_VOUTRST_DC8200_AHB>, + <&voutcrg JH7110_VOUTRST_DC8200_CORE>; + reset-names = "axi","ahb", "core"; + + crtc_out: ports { + #address-cells = <1>; + #size-cells = <0>; + + dc_out0: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dc_out_dpi0: endpoint@0 { + reg = <0>; + remote-endpoint = <&hdmi_enc>; + }; + + }; + + dc_out1: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dc_out_dpi1: endpoint@1 { + reg = <1>; + remote-endpoint = <&dsi_enc>; + }; + + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml new file mode 100644 index 000000000000..bfd7dc41fc14 --- /dev/null +++ b/Documentation/devicetree/bindings/display/starfive/starfive,jh7110-inno-hdmi.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/starfive/starfive,jh7110-inno-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Starfive JH7110 Innosilicon HDMI controller + +maintainers: + - Keith Zhao + +allOf: + - $ref: ../bridge/innosilicon,inno-hdmi.yaml# + +properties: + compatible: + const: "starfive,jh7110-inno-hdmi" + + clocks: + items: + - description: System clock of HDMI module. + - description: Mclk clock of HDMI audio. + - description: Bclk clock of HDMI audio. + + clock-names: + items: + - const: sysclk + - const: mclk + - const: bclk + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - ports + +unevaluatedProperties: false + +examples: + - | + #include + #include + hdmi: hdmi@29590000 { + compatible = "starfive,jh7110-inno-hdmi"; + reg = <0x29590000 0x4000>; + interrupts = <99>; + clocks = <&voutcrg 17>, <&voutcrg 15>, <&voutcrg 16>; + clock-names = "sysclk", "mclk","bclk"; + resets = <&voutcrg 9>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + hdmi_in_vop: endpoint { + remote-endpoint = <&dc_out_dpi0>; + }; + }; + + hdmi_out: port@1 { + reg = <1>; + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml b/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml index 0039319e91fe..cf9b657d0e8a 100644 --- a/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml +++ b/Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml @@ -24,6 +24,7 @@ properties: - enum: - starfive,jh7110-aon-syscon - starfive,jh7110-stg-syscon + - starfive,jh7110-vout-syscon - const: syscon reg: diff --git a/MAINTAINERS b/MAINTAINERS index c675fc296b19..8881652bb8b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7148,6 +7148,14 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/ste,mcde.yaml F: drivers/gpu/drm/mcde/ +DRM DRIVERS FOR STARFIVE +M: Keith Zhao +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml +F: Documentation/devicetree/bindings/display/starfive/ + DRM DRIVER FOR SYNAPTICS R63353 PANELS M: Michael Trimarchi S: Maintained From patchwork Tue May 21 10:58:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668830 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5C9A9C25B7C for ; Tue, 21 May 2024 02:58:54 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 642FC10E660; Tue, 21 May 2024 02:58:52 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2139.outbound.protection.partner.outlook.cn [139.219.17.139]) by gabe.freedesktop.org (Postfix) with ESMTPS id 107D810E215 for ; Tue, 21 May 2024 02:58:32 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ALdcEwi4Li8DdjEza142bOgMfxG11+YezloMr0iXhAdmiv9mx8652x7DJyFw/2BvGnUvygNpqs6fZrs5fUdsE2tGYMiuspgSBEaj4JMKnxcIrviVDoxYbfdAjGaLkVZ8jfIdfCyQ3NjT+y1+EEuP5PNIOeVL5Sg+rNnaG37GwsQfoWKQqBmUMwCaf28aCr/PA7hMD4LlwlUIsHH9TaMrHPsPBw9QMfKj3jpJiBXP6JUH4DBB0OgV7M3xh0AZLz30r8kLhQFY3tqgZa42R0f/SUHcIjve9fvy/sDcOsslNE7la01JSTyxBI6pwujRWiMPAGPoBbRgjvOwQ06clLV2Tw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=fw7zHDNSaeaHhDq6UHj6zwYm5NlE7ogweguqdhMtzw8=; b=N56ogKYwJPMejIPEOt26caIDVRN1Dh9pD5AxPPBVwjfn3yEcBKCAA26HbaTtryF+EIpsdpN6Y2g7Pmjfdi7QU8UhKIvnwhNOEbhumkKPIxJopbj0sB1fzLC9cd/u5lQxM6z2JutKlWvWHl377RRsrMlvGpXRGDMlEVQFtJAVwS5Gat8vDrah8IUe6NRt36Z/d1+oIqIlcygeDn9IYTDGH4rn2DlQeNh7JbkACWfA05jzdyXCZh59uijJ3mOwvQ0FuJGhQ9WTtaX9plE7CQgHC2Q0N7S6jC2Swp73QEWAUmcjzpWr991QXoFC4tQviWPGD7NuGPAneSEaBlYTpMl1tQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1255.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:19::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.36; Tue, 21 May 2024 02:58:27 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:27 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 02/10] drm/bridge: add common api for inno hdmi Date: Tue, 21 May 2024 18:58:09 +0800 Message-Id: <20240521105817.3301-3-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1255:EE_ X-MS-Office365-Filtering-Correlation-Id: fde06dff-31ec-4c0f-6a89-08dc7941e37a X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; ARA:13230031|366007|41320700004|1800799015|7416005|52116005|921011|38350700005; X-Microsoft-Antispam-Message-Info: 8tSDE7KQLrPdDGNVsL0dYaXcM1nzS1sDAc62mimRMpaMa/1OKKdplkUX5lQLW+3VWLZtNRsIej+jeDKOXpqSIKDdkWFzS5fZPE1znzOva4fJikqhUWDa4e43/53lZKJwi5PHH3LiK2kixXTjlR8a0xfl4qAQdl3hQLWtL8OrZuaxROEGQbfMV6qIZGgkV3xhtEmo2GWmesFCcmPBR8RNAPBCM67Hu+U//bBmpeN4fNRrGYKcDdhazQgRuH6eRoP7Jro1xAAzy7weaV67sX9P7XQfmzTy9TpkAR+dUtKLQNEWvl9tKf9CQIPStQ2huwOYMyv3NQ44YbS9gR4iqJroyN6GLF8Pqr6RYnEUVmrbJttmlutQMkiPTxm5kumREmRbmDpjXXgBSzYrUExcdNl9oQDxuVUoYuvA6H73s17pRUEDaoGly29rpa7xzAd7o2kHy6HKb626c53a6KplNhQtq8T4IVyx3K5L3wzRFiyINl8zb8tc6HxW13XeKx5hgYzvTs1CqXReSdQXZs2b6qDfQsdXbF9/Tgay2oaGm6gLJiRvHpU8w6FUQSZCFFLDKvEpnpa+w1IGlbGsLfiXdlXdjw8GQLUGlGP0EMpO2579XPXNaVtyjWhMPq06580Fhyv5Q+XbGL8FELFaQpFHqX46Tw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(366007)(41320700004)(1800799015)(7416005)(52116005)(921011)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: YddRQ+BPx9dqhcf2U0h6TgO7HffHR1OTDHJrMXq8As4ElJPN8SOs7/jZ+BUrq3K8jqB2OP5JbgCUWvsEFKe3PNZXrSHA2hemFJ508ttXF2JI33IzV/liRWQXH/tO119gHFztnr8SS7BRQvnlQG/k5n+o0hlb98gVCXNXzwoB+BlmPlJbRBWnn/YtUhjmxZDtu2RFE7+DrRHXlIimehMXCJU+UbODKQDk9ZIv6N2fyh4+ZW+JuJq+vhTp4yL99JZfDIYShJBOmlXCDWDjkYDguPo3rWtK0H0V9Sssly+nfh5N0olRvJ0fu6Rt7zvNmmcoiuyMOkfe8iIwNqNR4u/M7F9johu9YalPoRNJTzuEcNPxSQf4fqBIpIRb3G5etk7XhbANpz/pDSdzt1eDf6lzNI2KdxUgtRE46l2Hvmq9Ddk0btSTwA3es0U4V06ZDv2Nc1t3jKi4woJZE9FU8K69XOVa8mg7Aqj32d1bvhb8AYkNSxkI/PJ8EfHiE0ZdNFKL6l8aWw7V733YKFG9UqMpiFMjNweEsUlDvtHN00Fz08UdDreYdZ5eg/jcOPy2YmYTUOlCpUzWJPJFwnv8AKdscsriFW242xnG7+ugGndWvK7POrMybrH583HIJBGqwc39aKulivVOEJ/YOq1FaG/bomSCjaabR9PsEqdKQn2FXJYKuIE/OGY+9Sra0m2Pl/13hBpxaTomhKJJLlAA1vjTnh5qbhoo+ktFBqEHiLVTlHm/Q2vv4VY9xONOWXrWBnST+8atkZseaS3jsXvMP00jJwCOZ1nT7vhmJMqE5CNTrhiQNlWSkL2vEmCovibwzCjB+HE18bfdsU19sHqce0VclToKOVnJsZAk5GHMyiXEZXlzpCA/ErHbgdbK6u3ciIYwK4aZ59Q8ZFM9P4dO6sIHeFgO0P0hX3IE4VTE7NkNs3FzPnTspgwq40PdC3BkQWZUPfbK9pO9rsRpLigjA4ZCqYRcHFBJHddWDMDrIX9YGC9gFcloUpVfo0xXArvzpTH1LVnmPGD3J4BSIDLkVX2GU3a8JOJK6VpmIxDCNDMSBmuPfGMXgjS8IiqtWMUepMECyZMrwqLwKyhGTF0wuvmm6Rp5R4khdMhk3cTizZPKvrzSLmnk0GEKgF26dyVT75aXks5olbzp6Bzr24D3eh39kDIxK9Qe+ns6bUMrVU+cV7uYfaeqHWSPiYSg7Bu37abNsYsfmr5/DDEn/buhX5Kz9RNZEsXo+jlzEqSir4v6MT5IfuwldybSO1FQ64odaAF3lowWLit7rJtBazm1xp+bpT5HJaIQi99tyuipV5tmZWfsDFr8bUpkCndRc4TIT14wiRoyyeWKJUQlSISvZC1iVXO+NBh613oz8UDw2PxkrGIPVDO5AG6EsQFvCQvyJ4m7/5hKHxdd+/b1qaEuLvGkOJ8rPVYZIHM/YP3FRDtEVNeruW2EO97DZINo1xLsupvWSN3jwNpeC4Kq4nMDUS5GCnJlLg4xZ/i4kvENnubn6vbslaXOdpSDyNYeNMeMz++c5WoF5IB32nej2+SKu//pgG1m4Aw6/FE3diabruqCi/s0Jzah4T6snhVABXEg3pZHEZC4PaVOz+sHndNocgDUIw== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: fde06dff-31ec-4c0f-6a89-08dc7941e37a X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:27.7462 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: woSGgMTPJGHa7YycTil/0aVAbaJESHQulkW0pHtTLPbvdSp+Mf6DlH7cMdAC4QIn60UrDltwVmVa56SUKNxf21Q+uh+T3fBsnElNQsPh7qU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1255 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" Add INNO common api so that it can be used by vendor drivers which implement vendor specific extensions to Innosilicon HDMI. Signed-off-by: keith --- MAINTAINERS | 2 + drivers/gpu/drm/bridge/Kconfig | 2 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/innosilicon/Kconfig | 6 + drivers/gpu/drm/bridge/innosilicon/Makefile | 2 + .../gpu/drm/bridge/innosilicon/inno-hdmi.c | 587 ++++++++++++++++++ .../gpu/drm/bridge/innosilicon/inno-hdmi.h | 97 +++ include/drm/bridge/inno_hdmi.h | 69 ++ 8 files changed, 766 insertions(+) create mode 100644 drivers/gpu/drm/bridge/innosilicon/Kconfig create mode 100644 drivers/gpu/drm/bridge/innosilicon/Makefile create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c create mode 100644 drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h create mode 100644 include/drm/bridge/inno_hdmi.h diff --git a/MAINTAINERS b/MAINTAINERS index 8881652bb8b6..cf2d66f88a83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7155,6 +7155,8 @@ S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml F: Documentation/devicetree/bindings/display/starfive/ +F: drivers/gpu/drm/bridge/innosilicon/ +F: include/drm/bridge/inno_hdmi.h DRM DRIVER FOR SYNAPTICS R63353 PANELS M: Michael Trimarchi diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index c621be1a99a8..59fcdb810125 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -415,6 +415,8 @@ source "drivers/gpu/drm/bridge/cadence/Kconfig" source "drivers/gpu/drm/bridge/imx/Kconfig" +source "drivers/gpu/drm/bridge/innosilicon/Kconfig" + source "drivers/gpu/drm/bridge/synopsys/Kconfig" endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 7df87b582dca..cca7400566b2 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -40,4 +40,5 @@ obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o obj-y += analogix/ obj-y += cadence/ obj-y += imx/ +obj-y += innosilicon/ obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/innosilicon/Kconfig b/drivers/gpu/drm/bridge/innosilicon/Kconfig new file mode 100644 index 000000000000..73dbed3b1c4d --- /dev/null +++ b/drivers/gpu/drm/bridge/innosilicon/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_INNO_HDMI + tristate + help + Support the common interface which is part of the INNO + Designware HDMI block. diff --git a/drivers/gpu/drm/bridge/innosilicon/Makefile b/drivers/gpu/drm/bridge/innosilicon/Makefile new file mode 100644 index 000000000000..3b3a961ab9fb --- /dev/null +++ b/drivers/gpu/drm/bridge/innosilicon/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_DRM_INNO_HDMI) += inno-hdmi.o diff --git a/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c new file mode 100644 index 000000000000..2378ce06a876 --- /dev/null +++ b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.c @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Zheng Yang + * Yakir Yang + * Copyright (C) 2024 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inno-hdmi.h" + +struct inno_hdmi_i2c { + struct i2c_adapter adap; + + u8 ddc_addr; + u8 segment_addr; + + struct mutex lock; /* For i2c operation. */ + struct completion cmp; +}; + +struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) +{ + return container_of(connector, struct inno_hdmi, connector); +} +EXPORT_SYMBOL_GPL(connector_to_inno_hdmi); + +u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) +{ + return readl_relaxed(hdmi->regs + (offset) * 0x04); +} +EXPORT_SYMBOL_GPL(hdmi_readb); + +void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val) +{ + writel_relaxed(val, hdmi->regs + (offset) * 0x04); +} +EXPORT_SYMBOL_GPL(hdmi_writeb); + +void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, u32 msk, u32 val) +{ + u8 temp = hdmi_readb(hdmi, offset) & ~msk; + + temp |= val & msk; + hdmi_writeb(hdmi, offset, temp); +} +EXPORT_SYMBOL_GPL(hdmi_modb); + +void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate) +{ + unsigned long long ddc_bus_freq = rate >> 2; + + do_div(ddc_bus_freq, HDMI_SCL_RATE); + + hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); + hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); + + /* Clear the EDID interrupt flag and mute the interrupt */ + hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); + hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); +} +EXPORT_SYMBOL_GPL(inno_hdmi_i2c_init); + +void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) +{ + if (enable) + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON); + else + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF); +} +EXPORT_SYMBOL_GPL(inno_hdmi_sys_power); + +static enum drm_connector_status +inno_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + + return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? + connector_status_connected : connector_status_disconnected; +} + +static int inno_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + const struct drm_edid *drm_edid; + int ret = 0; + + if (!hdmi->ddc) + return 0; + + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); + drm_edid_connector_update(connector, drm_edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); + + return ret; +} + +static enum drm_mode_status +inno_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) +{ + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + + const struct inno_hdmi_plat_data *pdata = hdmi->plat_data; + enum drm_mode_status mode_status = MODE_OK; + + if (pdata->mode_valid) + mode_status = pdata->mode_valid(connector, mode); + + return mode_status; +} + +static void +inno_hdmi_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(state); + + __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base); + kfree(inno_conn_state); +} + +static void inno_hdmi_connector_reset(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (connector->state) { + inno_hdmi_connector_destroy_state(connector, connector->state); + connector->state = NULL; + } + + inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); + if (!inno_conn_state) + return; + + __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); + + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = false; +} + +static struct drm_connector_state * +inno_hdmi_connector_duplicate_state(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (WARN_ON(!connector->state)) + return NULL; + + inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state), + sizeof(*inno_conn_state), GFP_KERNEL); + + if (!inno_conn_state) + return NULL; + + __drm_atomic_helper_connector_duplicate_state(connector, + &inno_conn_state->base); + + return &inno_conn_state->base; +} + +static const struct drm_connector_funcs inno_hdmi_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = inno_hdmi_connector_detect, + .reset = inno_hdmi_connector_reset, + .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, + .atomic_destroy_state = inno_hdmi_connector_destroy_state, +}; + +static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { + .get_modes = inno_hdmi_connector_get_modes, + .mode_valid = inno_hdmi_connector_mode_valid, +}; + +static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi, + struct drm_encoder *encoder) +{ + struct device *dev = hdmi->dev; + const struct inno_hdmi_plat_data *pdata = hdmi->plat_data; + + if (RK3128_HDMI == pdata->soc_type || RK3036_HDMI == pdata->soc_type) + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); + + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (encoder->possible_crtcs == 0) + return -EPROBE_DEFER; + + drm_encoder_helper_add(encoder, pdata->helper_private); + + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; + + drm_connector_helper_add(&hdmi->connector, + &inno_hdmi_connector_helper_funcs); + + drmm_connector_init(drm, &hdmi->connector, + &inno_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->ddc); + + drm_connector_attach_encoder(&hdmi->connector, encoder); + + return 0; +} + +static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi) +{ + struct inno_hdmi_i2c *i2c = hdmi->i2c; + u8 stat; + + stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1); + if (!(stat & m_INT_EDID_READY)) + return IRQ_NONE; + + /* Clear HDMI EDID interrupt flag */ + hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); + + complete(&i2c->cmp); + + return IRQ_HANDLED; +} + +static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id) +{ + struct inno_hdmi *hdmi = dev_id; + irqreturn_t ret = IRQ_NONE; + u8 interrupt; + + if (hdmi->i2c) + ret = inno_hdmi_i2c_irq(hdmi); + + interrupt = hdmi_readb(hdmi, HDMI_STATUS); + if (interrupt & m_INT_HOTPLUG) { + hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG); + ret = IRQ_WAKE_THREAD; + } + + return ret; +} + +static irqreturn_t inno_hdmi_irq(int irq, void *dev_id) +{ + struct inno_hdmi *hdmi = dev_id; + + drm_helper_hpd_irq_event(hdmi->connector.dev); + + return IRQ_HANDLED; +} + +static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs) +{ + int length = msgs->len; + u8 *buf = msgs->buf; + int ret; + + ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10); + if (!ret) + return -EAGAIN; + + while (length--) + *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR); + + return 0; +} + +static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs) +{ + /* + * The DDC module only support read EDID message, so + * we assume that each word write to this i2c adapter + * should be the offset of EDID word address. + */ + if (msgs->len != 1 || (msgs->addr != DDC_ADDR && msgs->addr != DDC_SEGMENT_ADDR)) + return -EINVAL; + + reinit_completion(&hdmi->i2c->cmp); + + if (msgs->addr == DDC_SEGMENT_ADDR) + hdmi->i2c->segment_addr = msgs->buf[0]; + if (msgs->addr == DDC_ADDR) + hdmi->i2c->ddc_addr = msgs->buf[0]; + + /* Set edid fifo first addr */ + hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00); + + /* Set edid word address 0x00/0x80 */ + hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr); + + /* Set edid segment pointer */ + hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr); + + return 0; +} + +static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct inno_hdmi *hdmi = i2c_get_adapdata(adap); + struct inno_hdmi_i2c *i2c = hdmi->i2c; + int i, ret = 0; + + mutex_lock(&i2c->lock); + + /* Clear the EDID interrupt flag and unmute the interrupt */ + hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY); + hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); + + for (i = 0; i < num; i++) { + DRM_DEV_DEBUG(hdmi->dev, + "xfer: num: %d/%d, len: %d, flags: %#x\n", + i + 1, num, msgs[i].len, msgs[i].flags); + + if (msgs[i].flags & I2C_M_RD) + ret = inno_hdmi_i2c_read(hdmi, &msgs[i]); + else + ret = inno_hdmi_i2c_write(hdmi, &msgs[i]); + + if (ret < 0) + break; + } + + if (!ret) + ret = num; + + /* Mute HDMI EDID interrupt */ + hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); + + mutex_unlock(&i2c->lock); + + return ret; +} + +static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm inno_hdmi_algorithm = { + .master_xfer = inno_hdmi_i2c_xfer, + .functionality = inno_hdmi_i2c_func, +}; + +static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) +{ + struct i2c_adapter *adap; + struct inno_hdmi_i2c *i2c; + int ret; + + i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return ERR_PTR(-ENOMEM); + + mutex_init(&i2c->lock); + init_completion(&i2c->cmp); + + adap = &i2c->adap; + adap->owner = THIS_MODULE; + adap->dev.parent = hdmi->dev; + adap->dev.of_node = hdmi->dev->of_node; + adap->algo = &inno_hdmi_algorithm; + strscpy(adap->name, "Inno HDMI", sizeof(adap->name)); + i2c_set_adapdata(adap, hdmi); + + ret = i2c_add_adapter(adap); + if (ret) { + dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); + devm_kfree(hdmi->dev, i2c); + return ERR_PTR(ret); + } + + hdmi->i2c = i2c; + + DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name); + + return adap; +} + +int inno_hdmi_bind(struct drm_device *drm, struct inno_hdmi *hdmi, struct drm_encoder *encoder) +{ + int ret, irq; + struct platform_device *pdev = to_platform_device(hdmi->dev); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + return ret; + } + + hdmi->ddc = inno_hdmi_i2c_adapter(hdmi); + if (IS_ERR(hdmi->ddc)) { + ret = PTR_ERR(hdmi->ddc); + hdmi->ddc = NULL; + return ret; + } + + ret = inno_hdmi_register(drm, hdmi, encoder); + if (ret) + goto err_put_adapter; + + /* Unmute hotplug interrupt */ + hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1)); + + ret = devm_request_threaded_irq(hdmi->dev, irq, inno_hdmi_hardirq, + inno_hdmi_irq, IRQF_SHARED, + dev_name(hdmi->dev), hdmi); + if (ret) + goto err_put_adapter; + + return ret; +err_put_adapter: + i2c_put_adapter(hdmi->ddc); + return ret; +} +EXPORT_SYMBOL_GPL(inno_hdmi_bind); + +static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, + enum hdmi_infoframe_type type) +{ + struct drm_connector *connector = &hdmi->connector; + + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", type); + return; + } + + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); +} + +static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, + union hdmi_infoframe *frame, enum hdmi_infoframe_type type) +{ + struct drm_connector *connector = &hdmi->connector; + u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; + ssize_t rc, i; + + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", type); + return 0; + } + + inno_hdmi_disable_frame(hdmi, type); + + rc = hdmi_infoframe_pack(frame, packed_frame, + sizeof(packed_frame)); + if (rc < 0) + return rc; + + for (i = 0; i < rc; i++) + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, + packed_frame[i]); + + return 0; +} + +int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode) +{ + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); + union hdmi_infoframe frame; + int rc; + + rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + &hdmi->connector, + mode); + if (rc) { + inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI); + return rc; + } + + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) + frame.avi.colorspace = HDMI_COLORSPACE_YUV444; + else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422) + frame.avi.colorspace = HDMI_COLORSPACE_YUV422; + else + frame.avi.colorspace = HDMI_COLORSPACE_RGB; + + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + connector, mode, + inno_conn_state->rgb_limited_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); + } else { + frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + frame.avi.ycc_quantization_range = + HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + } + + return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); +} +EXPORT_SYMBOL_GPL(inno_hdmi_config_video_avi); + +int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, struct drm_display_mode *mode) +{ + int value; + + /* Set detail external video timing polarity and interlace mode */ + value = v_EXTERANL_VIDEO(1); + if (hdmi->plat_data->soc_type == STARFIVE_HDMI) { + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? + v_HSYNC_POLARITY_SF(1) : v_HSYNC_POLARITY_SF(0); + value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? + v_VSYNC_POLARITY_SF(1) : v_VSYNC_POLARITY_SF(0); + } else { + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? + v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0); + value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? + v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0); + } + value |= mode->flags & DRM_MODE_FLAG_INTERLACE ? + v_INETLACE(1) : v_INETLACE(0); + hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value); + + /* Set detail external video timing */ + value = mode->htotal; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF); + + value = mode->htotal - mode->hdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + + value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + + value = mode->hsync_end - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF); + + value = mode->vtotal; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF); + + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + + value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF); + + if (hdmi->plat_data->soc_type == STARFIVE_HDMI) + return 0; + + hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e); + hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c); + hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01); + + return 0; +} +EXPORT_SYMBOL_GPL(inno_hdmi_config_video_timing); + +MODULE_DESCRIPTION("INNO HDMI transmitter driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:inno-hdmi"); diff --git a/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h new file mode 100644 index 000000000000..233077cfb136 --- /dev/null +++ b/drivers/gpu/drm/bridge/innosilicon/inno-hdmi.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Zheng Yang + * Yakir Yang + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#ifndef __INNO_H__ +#define __INNO_H__ + +#define DDC_SEGMENT_ADDR 0x30 + +#define HDMI_SCL_RATE (100 * 1000) +#define DDC_BUS_FREQ_L 0x4b +#define DDC_BUS_FREQ_H 0x4c + +#define HDMI_SYS_CTRL 0x00 +#define m_RST_ANALOG (1 << 6) +#define v_RST_ANALOG (0 << 6) +#define v_NOT_RST_ANALOG (1 << 6) +#define m_RST_DIGITAL (1 << 5) +#define v_RST_DIGITAL (0 << 5) +#define v_NOT_RST_DIGITAL (1 << 5) +#define m_REG_CLK_INV (1 << 4) +#define v_REG_CLK_NOT_INV (0 << 4) +#define v_REG_CLK_INV (1 << 4) +#define m_VCLK_INV (1 << 3) +#define v_VCLK_NOT_INV (0 << 3) +#define v_VCLK_INV (1 << 3) +#define m_REG_CLK_SOURCE (1 << 2) +#define v_REG_CLK_SOURCE_TMDS (0 << 2) +#define v_REG_CLK_SOURCE_SYS (1 << 2) +#define m_POWER (1 << 1) +#define v_PWR_ON (0 << 1) +#define v_PWR_OFF (1 << 1) +#define m_INT_POL (1 << 0) +#define v_INT_POL_HIGH 1 +#define v_INT_POL_LOW 0 + +#define HDMI_VIDEO_TIMING_CTL 0x08 +#define v_HSYNC_POLARITY(n) ((n) << 3) +#define v_VSYNC_POLARITY(n) ((n) << 2) +#define v_VSYNC_POLARITY_SF(n) ((n) << 3) +#define v_HSYNC_POLARITY_SF(n) ((n) << 2) +#define v_INETLACE(n) ((n) << 1) +#define v_EXTERANL_VIDEO(n) ((n) << 0) + +#define HDMI_VIDEO_EXT_HTOTAL_L 0x09 +#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a +#define HDMI_VIDEO_EXT_HBLANK_L 0x0b +#define HDMI_VIDEO_EXT_HBLANK_H 0x0c +#define HDMI_VIDEO_EXT_HDELAY_L 0x0d +#define HDMI_VIDEO_EXT_HDELAY_H 0x0e +#define HDMI_VIDEO_EXT_HDURATION_L 0x0f +#define HDMI_VIDEO_EXT_HDURATION_H 0x10 +#define HDMI_VIDEO_EXT_VTOTAL_L 0x11 +#define HDMI_VIDEO_EXT_VTOTAL_H 0x12 +#define HDMI_VIDEO_EXT_VBLANK 0x13 +#define HDMI_VIDEO_EXT_VDELAY 0x14 +#define HDMI_VIDEO_EXT_VDURATION 0x15 + +#define HDMI_EDID_SEGMENT_POINTER 0x4d +#define HDMI_EDID_WORD_ADDR 0x4e +#define HDMI_EDID_FIFO_OFFSET 0x4f +#define HDMI_EDID_FIFO_ADDR 0x50 + +#define HDMI_INTERRUPT_MASK1 0xc0 +#define HDMI_INTERRUPT_STATUS1 0xc1 +#define m_INT_ACTIVE_VSYNC (1 << 5) +#define m_INT_EDID_READY (1 << 2) + +#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f +enum { + INFOFRAME_VSI = 0x05, + INFOFRAME_AVI = 0x06, + INFOFRAME_AAI = 0x08, +}; + +#define HDMI_CONTROL_PACKET_ADDR 0xa0 +#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11 + +#define HDMI_STATUS 0xc8 +#define m_HOTPLUG (1 << 7) +#define m_MASK_INT_HOTPLUG (1 << 5) +#define m_INT_HOTPLUG (1 << 1) +#define v_MASK_INT_HOTPLUG(n) (((n) & 0x1) << 5) + +#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7 +#define v_FEEDBACK_DIV_LOW(n) ((n) & 0xff) +#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8 +#define v_FEEDBACK_DIV_HIGH(n) ((n) & 1) + +#define HDMI_PHY_PRE_DIV_RATIO 0xed +#define v_PRE_DIV_RATIO(n) ((n) & 0x1f) + +#endif /* __INNO_H__ */ diff --git a/include/drm/bridge/inno_hdmi.h b/include/drm/bridge/inno_hdmi.h new file mode 100644 index 000000000000..bc865f5343ce --- /dev/null +++ b/include/drm/bridge/inno_hdmi.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#ifndef __INNO_COMMON_HDMI__ +#define __INNO_COMMON_HDMI__ + +#include +#include + +struct inno_hdmi_connector_state { + struct drm_connector_state base; + unsigned int enc_out_format; + unsigned int colorimetry; + bool rgb_limited_range; +}; + +enum inno_hdmi_devtype { + RK3036_HDMI, + RK3128_HDMI, + STARFIVE_HDMI, +}; + +#define to_inno_hdmi_conn_state(conn_state) \ + container_of_const(conn_state, struct inno_hdmi_connector_state, base) + +struct inno_hdmi_phy_config { + unsigned long pixelclock; + u8 pre_emphasis; + u8 voltage_level_control; +}; + +struct inno_hdmi_plat_data { + enum inno_hdmi_devtype soc_type; + + /* Platform-specific mode validation*/ + enum drm_mode_status (*mode_valid)(struct drm_connector *connector, + struct drm_display_mode *mode); + /* Platform-specific encoder helper funcs*/ + const struct drm_encoder_helper_funcs *helper_private; + + /* Platform-specific phy_configs Optional*/ + struct inno_hdmi_phy_config *phy_configs; + struct inno_hdmi_phy_config *default_phy_config; +}; + +struct inno_hdmi { + struct device *dev; + void __iomem *regs; + + struct drm_connector connector; + struct inno_hdmi_i2c *i2c; + struct i2c_adapter *ddc; + const struct inno_hdmi_plat_data *plat_data; +}; + +u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset); +void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val); +void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, u32 msk, u32 val); + +struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector); +void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate); +int inno_hdmi_bind(struct drm_device *drm, struct inno_hdmi *hdmi, struct drm_encoder *encoder); +void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable); +int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode); +int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, struct drm_display_mode *mode); + +#endif /* __INNO_COMMON_HDMI__ */ From patchwork Tue May 21 10:58:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668826 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 75F0AC25B77 for ; Tue, 21 May 2024 02:58:45 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4AD1910E228; Tue, 21 May 2024 02:58:44 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2139.outbound.protection.partner.outlook.cn [139.219.17.139]) by gabe.freedesktop.org (Postfix) with ESMTPS id D72D710E051 for ; Tue, 21 May 2024 02:58:32 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ci08D7IUTqWZPlrjPlER646qHFWA7EPy0WGZv8ovit6cOJhggNhTOdZCaGdaeGtwJPARTcfFcTi/boTUL0SMl77KRE+K609IimUOew9Ma5TO4+Ev2y/KvZ135/b0y1RB+OEoJL4y16IbJOravIeVkA4neNj1zOGDSmtD4MLWwXOso9Xtq2LtCMGjueodtz1tz666Md33zCtl0S7RUZoGWKAnbitdqd8OJbEAUNxPw4iHCrRfDf+ah37ssP58TPLSSZaaxW6YaIquLyUymmNzpzz4T2NhxPLcZNmo6lncLmMuq3SJT0P3eXdwOctF7H1U6NJM3VW7DXOKmLykUy61Lw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vtoJn6t7pvX80lMxrVsWfBiBB9KYSygPQjhD8HVQA3M=; b=J1CGecr5YKU7Wk3xFXB6zdoVaX2akjxdDNjyjeXjOMzwXg5LhCEO0F2qrG8kXuYo8F/DXVMKM8Gjbb3Puv+4KNzzQrnZhbDnPw5/4Wgd9W6fQd9WadhUnu2pW0BeG3n1pnjk7SRCXLNc+VkzjJTN1HIYsqD1XFF1Y8RgJLfS5FkE3qkd5QaJ+JAmGI0Mb+s72sPYI89NKyJNiTgpNNxjcXcGCApTYdooB2QEPgc01trzX8JNvZPNqiu/MPTWuhbWPjPNCsfqspT45YqOgldWgEkphtE4/Va/x/uB2UR3xsVFvjFS5g5R+y+prAjWKhfZfAmR9mwA67Gw97JpeVfSpw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1255.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:19::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.36; Tue, 21 May 2024 02:58:28 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:28 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver Date: Tue, 21 May 2024 18:58:10 +0800 Message-Id: <20240521105817.3301-4-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1255:EE_ X-MS-Office365-Filtering-Correlation-Id: be952e03-a2ea-458e-3c23-08dc7941e428 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; ARA:13230031|366007|41320700004|1800799015|7416005|52116005|921011|38350700005; X-Microsoft-Antispam-Message-Info: RblV+Ix60hjj+OCxK44X4jK+tpZaw1qotgklFivwv51R+ih/KTVMADp+imRk+9lSTpyA9mdOWmjOceUuyue0A9va6kIs/f9KDxYpkdjJCzM8L5rrEm1paJ38zfeMGsnlNhGfilTmemIEb7b6s+sigCTgFBq/Su74dhxGirwtg7elRnJyZajr+I34obkQ1gKOEIzUNjwy/NA7aWomu57gtGr0p3eTU0i9XHI0FNjwlwf5jjRvEAUjvsnQbaU2GfY/Qd9QEBpLdDexkICnkYvHwaFu5S6kOQpozOJXRhHol9jpgPlCPWzx1+xM1UbNlGz2EGfkErceb7qpsNRtBYPfwQJZOxo/gJEB0GUWRjcbJUQiBsug5W2bPWGSsu/5C2UjYgVuvjeZoQSKvPXb/FMyR6O9pQcSwMbp+IU5fUSbYGAvWnvkGYbCxFORYxXsQQCpRnh9mJvmdASS+mH3PELIXAPMJR66oMVa5wbkvuL/BQqjrAgUFox0/RrmHPJpb+S1QVLOghpEif2pcPe8OwC4XsmdosTiYWumRKYU54wzvmHsdpVj6tKjY4vG0VwAdYxKHKCFc9Y44i0ttgNw3uDisNZNLqjeY4kO+wnXtNI3Ze69BOiOb7DgXNrdx9DMUwbeuZk4LEtUhrwHWXyzf2GIAQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(366007)(41320700004)(1800799015)(7416005)(52116005)(921011)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: bxJCVkwVEcOBWwXnEkfL9ysFRyEw2fKeJLdKu5jkIlfARfM1PWrRpTXTBYhhqTvk9ALfGntl0UnFWYaNdu4QFdsd0NKmSxftEizLElKcrU96gBQd6pHXfOcgZSDtSbwaLwGNGtCLnOOJJJ4PWrFsbkQ6Kq0YPnHYAMgHuZtWLJDYAV5VAzXrk6KKAhASHVNz0xxIC2ar74fvbYh2igg8yNuHvDACzsJVCG7RfH9xaDsc0t5kyS2FcSLYN1eV9vx/1umcFx057e3kcN/5gQlHzaw4MTQ4OAOsZp+cuI7hdQBNCePd5I6gxjEj2uxrkmGbcsLz8lrZgYXZXRYNunIi7sgg3jnEVPD6JKZ1oMf3QV0gbVS6Th1Jq9pc8O2qG1Zz3BWJS/FY7isQGCuNkxd0KSgZ8WFRt9W67B1DKEannAG13iezlA8Te5GVQy/gryTC0w1UNzlWw1hkErfDpdUpe+8RzM9WsWeArr8y9PcULUtpO5XeqC365NyOJ10IkLgKx7gEOpuIDR/HfkjRyTPFVkAaQPZ6rcQgVOxnHr6Z42JENI58decsCChOunq0SccFS5QqUGrjL0GAaoE5JhAd8OoNWb2jPLy9UTsvu9U0bFiOp3Tvx66u+vRU7EOecZnm/exIlGg94o/Q91nNHkRVXFsHqjswuFjHMogPC/SD3Uu1lCjdm774ttpRlAEzpHUWW4Og0Q0aH9sYg9pEr0+i3PStDGqkjhP0mN1JVVDeNBq1ZtVqUZXaBLWdaGtnqDa5rQD1f5d7teRIkKlggzgUXqVBRgMQmp6ue2Eagm9/655SthSygNslfheuqbQmhkByWJ5gmtGXbsBUs6UPqfbRBzmHNEvyQlOK2lBqeYuJUV1mXRy3efRS+crEP5syOz33djwjEsSAOz0JZClLIyWf5vO76w16/RgPIllm89g5rp7YO3zT7remEsgpMlcXgOXdDWM4sh4vQDgn0CuE8voZx+gEb1IGaeQS/c6qt9aRZkn23Z5T2rH/mo1miKJoCh5dD4MhGjU50HGypfg6zOl636vkWFKYVlTLZfTVLfUjtJZFczj4tOJvVT569TGJTqg80g0tykNItc6WjK0HTMsZ67ZVdu0nHgidy2l0ju/906vYiQorgIKbSA4oO/Fv3Pymc8FzpNeiS3axMKsiM9+PyzwIG/1mv8SDJux/Ysjj24EB3ebxLRi3aUZGM3CIyb/MdpskUwq4ibN1M8hXIkgWwRqwYcKedypmMWqInfZEgWi9KnA82hccLHJ6jqBrmH4T/W5fK8V5cP57CKvmVLFFfSVPa/sRsis/ehuRXouCqljMtbkS1D8q+roSwurhCPQKAONdKzJw1JPBn2D6ZjFenDhz7FZHyBbAjyo1ILUxXP8WnCXRhhDVduqSAHvVUaow3qVLsww6EOLk8QQ0V55WOwKEBAxZ93e7GI/ssIeQcAZ8XMp0UD1bnioDqmkuAhlolnZuk6XUFcXRJt/onpl6YMdJRFDgXGMQbu4l2a1ZwVNcXWM4XbYOaY5Ne9daCOOqylanWkxfBMD6hxfIzljrYcAojpo3Ro0J06z21g3GfL2xQ418PhoFpufCiasim2DvSWy5MFPsuVqU1ldcXNT9Nw== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: be952e03-a2ea-458e-3c23-08dc7941e428 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:28.8600 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: KWltm+oc/WbKreqc8VzEq94Gp3c3O67jBpIO08r/5y+kkI1uJPH0YxVOkCLsI0Uc0rJ84ZHzmrMYGbDEgT3w9KpdmvsxOB5uVbzJCZuiMbM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1255 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare HDMI TX bridge and remove the old separate one. Signed-off-by: keith --- drivers/gpu/drm/rockchip/Kconfig | 1 + drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c | 517 ++++++++ .../{inno_hdmi.h => inno_hdmi-rockchip.h} | 45 - drivers/gpu/drm/rockchip/inno_hdmi.c | 1073 ----------------- 5 files changed, 519 insertions(+), 1119 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%) delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 1bf3e2829cd0..cc6cfd5a30d6 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI config ROCKCHIP_INNO_HDMI bool "Rockchip specific extensions for Innosilicon HDMI" + select DRM_INNO_HDMI help This selects support for Rockchip SoC specific extensions for the Innosilicon HDMI driver. If you want to enable diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 3ff7b21c0414..4b2d0cba8db3 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c new file mode 100644 index 000000000000..69d0e913e13b --- /dev/null +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Zheng Yang + * Yakir Yang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_drm_drv.h" + +#include "inno_hdmi-rockchip.h" + +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U + +struct rk_inno_hdmi { + struct rockchip_encoder encoder; + struct inno_hdmi inno_hdmi; + struct clk *pclk; + struct clk *refclk; +}; + +static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct rk_inno_hdmi, encoder); + + return &rk_hdmi->inno_hdmi; +} + +enum { + CSC_RGB_0_255_TO_ITU601_16_235_8BIT, + CSC_RGB_0_255_TO_ITU709_16_235_8BIT, + CSC_RGB_0_255_TO_RGB_16_235_8BIT, +}; + +static const char coeff_csc[][24] = { + /* + * RGB2YUV:601 SD mode: + * Cb = -0.291G - 0.148R + 0.439B + 128 + * Y = 0.504G + 0.257R + 0.098B + 16 + * Cr = -0.368G + 0.439R - 0.071B + 128 + */ + { + 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80, + 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e, + 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80 + }, + /* + * RGB2YUV:709 HD mode: + * Cb = - 0.338G - 0.101R + 0.439B + 128 + * Y = 0.614G + 0.183R + 0.062B + 16 + * Cr = - 0.399G + 0.439R - 0.040B + 128 + */ + { + 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80, + 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10, + 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80 + }, + /* + * RGB[0:255]2RGB[16:235]: + * R' = R x (235-16)/255 + 16; + * G' = G x (235-16)/255 + 16; + * B' = B x (235-16)/255 + 16; + */ + { + 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10, + 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10 + }, +}; + +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xbb }, + { 165000000, 0x6f, 0xbb }, + { ~0UL, 0x00, 0x00 } +}; + +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xaa }, + { 165000000, 0x5f, 0xaa }, + { ~0UL, 0x00, 0x00 } +}; + +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, + unsigned long pixelclk) +{ + const struct inno_hdmi_phy_config *phy_configs = hdmi->plat_data->phy_configs; + int i; + + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) { + if (pixelclk <= phy_configs[i].pixelclock) + return i; + } + + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n", + pixelclk); + + return -EINVAL; +} + +static void inno_hdmi_standby(struct inno_hdmi *hdmi) +{ + inno_hdmi_sys_power(hdmi, false); + + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +}; + +static void inno_hdmi_power_up(struct inno_hdmi *hdmi, + unsigned long mpixelclock) +{ + struct inno_hdmi_phy_config *phy_config; + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock); + + if (ret < 0) { + phy_config = hdmi->plat_data->default_phy_config; + DRM_DEV_ERROR(hdmi->dev, + "Using default phy configuration for TMDS rate %lu", + mpixelclock); + } else { + phy_config = &hdmi->plat_data->phy_configs[ret]; + } + + inno_hdmi_sys_power(hdmi, false); + + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); + + inno_hdmi_sys_power(hdmi, true); +}; + +static void inno_hdmi_reset(struct inno_hdmi *hdmi) +{ + u32 val; + u32 msk; + + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL); + udelay(100); + + hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG); + udelay(100); + + msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL; + val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; + hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); + + inno_hdmi_standby(hdmi); +} + +static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) +{ + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); + int c0_c2_change = 0; + int csc_enable = 0; + int csc_mode = 0; + int auto_csc = 0; + int value; + int i; + + /* Input video mode is SDR RGB24bit, data enable signal from external */ + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL | + v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444)); + + /* Input color hardcode to RGB, and output color hardcode to RGB888 */ + value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | + v_VIDEO_OUTPUT_COLOR(0) | + v_VIDEO_INPUT_CSP(0); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); + + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { + if (inno_conn_state->rgb_limited_range) { + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + + } else { + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); + return 0; + } + } else { + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } + } else { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } + } + } + + for (i = 0; i < 24; i++) + hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i, + coeff_csc[csc_mode][i]); + + value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC | + m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) | + v_VIDEO_C0_C2_SWAP(c0_c2_change)); + + return 0; +} + +static int inno_hdmi_setup(struct inno_hdmi *hdmi, + struct drm_display_mode *mode) +{ + struct drm_display_info *display = &hdmi->connector.display_info; + unsigned long mpixelclock = mode->clock * 1000; + + /* Mute video and audio output */ + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, + v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); + + /* Set HDMI Mode */ + hdmi_writeb(hdmi, HDMI_HDCP_CTRL, + v_HDMI_DVI(display->is_hdmi)); + + inno_hdmi_config_video_timing(hdmi, mode); + + inno_hdmi_config_video_csc(hdmi); + + if (display->is_hdmi) + inno_hdmi_config_video_avi(hdmi, mode); + + /* + * When IP controller have configured to an accurate video + * timing, then the TMDS clock source would be switched to + * DCLK_LCDC, so we need to init the TMDS rate to mode pixel + * clock rate, and reconfigure the DDC clock. + */ + inno_hdmi_i2c_init(hdmi, mpixelclock); + + /* Unmute video and audio output */ + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, + v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + + inno_hdmi_power_up(hdmi, mpixelclock); + + return 0; +} + +static enum drm_mode_status rk_inno_hdmi_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + struct rk_inno_hdmi *rk_hdmi = dev_get_drvdata(hdmi->dev); + + unsigned long mpixelclk, max_tolerance; + long rounded_refclk; + + /* No support for double-clock modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + + mpixelclk = mode->clock * 1000; + + if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK) + return MODE_CLOCK_LOW; + + if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0) + return MODE_CLOCK_HIGH; + + if (rk_hdmi->refclk) { + rounded_refclk = clk_round_rate(rk_hdmi->refclk, mpixelclk); + if (rounded_refclk < 0) + return MODE_BAD; + + /* Vesa DMT standard mentions +/- 0.5% max tolerance */ + max_tolerance = mpixelclk / 200; + if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance) + return MODE_NOCLOCK; + } + + return MODE_OK; +} + +static void rk_inno_hdmi_encoder_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct inno_hdmi *hdmi = rk_encoder_to_inno_hdmi(encoder); + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + + conn_state = drm_atomic_get_new_connector_state(state, &hdmi->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; + + inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); +} + +static void rk_inno_hdmi_encoder_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct inno_hdmi *hdmi = rk_encoder_to_inno_hdmi(encoder); + + inno_hdmi_standby(hdmi); +} + +static int +rk_inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + u8 vic = drm_match_cea_mode(mode); + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); + + s->output_mode = ROCKCHIP_OUT_MODE_P888; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + + if (vic == 6 || vic == 7 || + vic == 21 || vic == 22 || + vic == 2 || vic == 3 || + vic == 17 || vic == 18) + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; + else + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; + + return rk_inno_hdmi_connector_mode_valid(conn_state->connector, + &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; +} + +static const struct drm_encoder_helper_funcs rk_inno_encoder_helper_funcs = { + .atomic_check = rk_inno_hdmi_encoder_atomic_check, + .atomic_enable = rk_inno_hdmi_encoder_enable, + .atomic_disable = rk_inno_hdmi_encoder_disable, +}; + +static int rk_inno_hdmi_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct inno_hdmi *hdmi; + int ret; + struct rk_inno_hdmi *rk_hdmi; + + rk_hdmi = devm_kzalloc(dev, sizeof(*rk_hdmi), GFP_KERNEL); + if (!rk_hdmi) + return -ENOMEM; + hdmi = &rk_hdmi->inno_hdmi; + + hdmi->dev = dev; + hdmi->plat_data = (struct inno_hdmi_plat_data *)of_device_get_match_data(dev); + + hdmi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + + rk_hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); + if (IS_ERR(rk_hdmi->pclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); + return PTR_ERR(rk_hdmi->pclk); + } + + ret = clk_prepare_enable(rk_hdmi->pclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI pclk clock: %d\n", ret); + return ret; + } + + rk_hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); + if (IS_ERR(rk_hdmi->refclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n"); + ret = PTR_ERR(rk_hdmi->refclk); + goto err_disable_pclk; + } + + ret = clk_prepare_enable(rk_hdmi->refclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI reference clock: %d\n", ret); + goto err_disable_pclk; + } + + inno_hdmi_reset(hdmi); + /* + * When the controller isn't configured to an accurate + * video timing and there is no reference clock available, + * then the TMDS clock source would be switched to PCLK_HDMI, + * so we need to init the TMDS rate to PCLK rate, and + * reconfigure the DDC clock. + */ + if (rk_hdmi->refclk) + inno_hdmi_i2c_init(hdmi, clk_get_rate(rk_hdmi->refclk)); + else + inno_hdmi_i2c_init(hdmi, clk_get_rate(rk_hdmi->pclk)); + + ret = inno_hdmi_bind(drm, hdmi, &rk_hdmi->encoder.encoder); + if (ret) + goto err_cleanup_hdmi; + + dev_set_drvdata(dev, rk_hdmi); + + return 0; + +err_cleanup_hdmi: + rk_hdmi->encoder.encoder.funcs->destroy(&rk_hdmi->encoder.encoder); + clk_disable_unprepare(rk_hdmi->refclk); +err_disable_pclk: + clk_disable_unprepare(rk_hdmi->pclk); + return ret; +} + +static void rk_inno_hdmi_unbind(struct device *dev, struct device *master, void *data) +{ + struct rk_inno_hdmi *rk_hdmi = dev_get_drvdata(dev); + struct inno_hdmi *hdmi = &rk_hdmi->inno_hdmi; + + rk_hdmi->encoder.encoder.funcs->destroy(&rk_hdmi->encoder.encoder); + i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(rk_hdmi->refclk); + clk_disable_unprepare(rk_hdmi->pclk); +} + +static const struct component_ops inno_hdmi_ops = { + .bind = rk_inno_hdmi_bind, + .unbind = rk_inno_hdmi_unbind, +}; + +static int inno_hdmi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &inno_hdmi_ops); +} + +static void inno_hdmi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &inno_hdmi_ops); +} + +static const struct inno_hdmi_plat_data rk3036_inno_info = { + .soc_type = RK3036_HDMI, + .mode_valid = rk_inno_hdmi_connector_mode_valid, + .helper_private = &rk_inno_encoder_helper_funcs, + .phy_configs = rk3036_hdmi_phy_configs, + .default_phy_config = &rk3036_hdmi_phy_configs[1], +}; + +static const struct inno_hdmi_plat_data rk3128_inno_info = { + .soc_type = RK3128_HDMI, + .mode_valid = rk_inno_hdmi_connector_mode_valid, + .helper_private = &rk_inno_encoder_helper_funcs, + .phy_configs = rk3128_hdmi_phy_configs, + .default_phy_config = &rk3128_hdmi_phy_configs[1], +}; + +static const struct of_device_id inno_hdmi_dt_ids[] = { + { .compatible = "rockchip,rk3036-inno-hdmi", + .data = &rk3036_inno_info, + }, + { .compatible = "rockchip,rk3128-inno-hdmi", + .data = &rk3128_inno_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); + +struct platform_driver inno_hdmi_driver = { + .probe = inno_hdmi_probe, + .remove_new = inno_hdmi_remove, + .driver = { + .name = "innohdmi-rockchip", + .of_match_table = inno_hdmi_dt_ids, + }, +}; diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h similarity index 85% rename from drivers/gpu/drm/rockchip/inno_hdmi.h rename to drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h index a7edf3559e60..c90458d75378 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.h +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.h @@ -8,12 +8,6 @@ #ifndef __INNO_HDMI_H__ #define __INNO_HDMI_H__ -#define DDC_SEGMENT_ADDR 0x30 - -#define HDMI_SCL_RATE (100*1000) -#define DDC_BUS_FREQ_L 0x4b -#define DDC_BUS_FREQ_H 0x4c - #define HDMI_SYS_CTRL 0x00 #define m_RST_ANALOG (1 << 6) #define v_RST_ANALOG (0 << 6) @@ -98,26 +92,6 @@ enum { #define v_AUDIO_MUTE(n) (n << 1) #define v_VIDEO_MUTE(n) (n << 0) -#define HDMI_VIDEO_TIMING_CTL 0x08 -#define v_HSYNC_POLARITY(n) (n << 3) -#define v_VSYNC_POLARITY(n) (n << 2) -#define v_INETLACE(n) (n << 1) -#define v_EXTERANL_VIDEO(n) (n << 0) - -#define HDMI_VIDEO_EXT_HTOTAL_L 0x09 -#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a -#define HDMI_VIDEO_EXT_HBLANK_L 0x0b -#define HDMI_VIDEO_EXT_HBLANK_H 0x0c -#define HDMI_VIDEO_EXT_HDELAY_L 0x0d -#define HDMI_VIDEO_EXT_HDELAY_H 0x0e -#define HDMI_VIDEO_EXT_HDURATION_L 0x0f -#define HDMI_VIDEO_EXT_HDURATION_H 0x10 -#define HDMI_VIDEO_EXT_VTOTAL_L 0x11 -#define HDMI_VIDEO_EXT_VTOTAL_H 0x12 -#define HDMI_VIDEO_EXT_VBLANK 0x13 -#define HDMI_VIDEO_EXT_VDELAY 0x14 -#define HDMI_VIDEO_EXT_VDURATION 0x15 - #define HDMI_VIDEO_CSC_COEF 0x18 #define HDMI_AUDIO_CTRL1 0x35 @@ -202,14 +176,6 @@ enum { #define HDMI_AUDIO_CTS_M 0x46 #define HDMI_AUDIO_CTS_L 0x47 -#define HDMI_DDC_CLK_L 0x4b -#define HDMI_DDC_CLK_H 0x4c - -#define HDMI_EDID_SEGMENT_POINTER 0x4d -#define HDMI_EDID_WORD_ADDR 0x4e -#define HDMI_EDID_FIFO_OFFSET 0x4f -#define HDMI_EDID_FIFO_ADDR 0x50 - #define HDMI_PACKET_SEND_MANUAL 0x9c #define HDMI_PACKET_SEND_AUTO 0x9d #define m_PACKET_GCP_EN (1 << 7) @@ -254,23 +220,12 @@ enum { #define m_HDMI_DVI (1 << 1) #define v_HDMI_DVI(n) (n << 1) -#define HDMI_INTERRUPT_MASK1 0xc0 -#define HDMI_INTERRUPT_STATUS1 0xc1 -#define m_INT_ACTIVE_VSYNC (1 << 5) -#define m_INT_EDID_READY (1 << 2) - #define HDMI_INTERRUPT_MASK2 0xc2 #define HDMI_INTERRUPT_STATUS2 0xc3 #define m_INT_HDCP_ERR (1 << 7) #define m_INT_BKSV_FLAG (1 << 6) #define m_INT_HDCP_OK (1 << 4) -#define HDMI_STATUS 0xc8 -#define m_HOTPLUG (1 << 7) -#define m_MASK_INT_HOTPLUG (1 << 5) -#define m_INT_HOTPLUG (1 << 1) -#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5) - #define HDMI_COLORBAR 0xc9 #define HDMI_PHY_SYNC 0xce diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c deleted file mode 100644 index 3df2cfcf9998..000000000000 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ /dev/null @@ -1,1073 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd - * Zheng Yang - * Yakir Yang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "rockchip_drm_drv.h" - -#include "inno_hdmi.h" - -#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U - -struct inno_hdmi_phy_config { - unsigned long pixelclock; - u8 pre_emphasis; - u8 voltage_level_control; -}; - -struct inno_hdmi_variant { - struct inno_hdmi_phy_config *phy_configs; - struct inno_hdmi_phy_config *default_phy_config; -}; - -struct inno_hdmi_i2c { - struct i2c_adapter adap; - - u8 ddc_addr; - u8 segment_addr; - - struct mutex lock; - struct completion cmp; -}; - -struct inno_hdmi { - struct device *dev; - - struct clk *pclk; - struct clk *refclk; - void __iomem *regs; - - struct drm_connector connector; - struct rockchip_encoder encoder; - - struct inno_hdmi_i2c *i2c; - struct i2c_adapter *ddc; - - const struct inno_hdmi_variant *variant; -}; - -struct inno_hdmi_connector_state { - struct drm_connector_state base; - unsigned int enc_out_format; - unsigned int colorimetry; - bool rgb_limited_range; -}; - -static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) -{ - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); - - return container_of(rkencoder, struct inno_hdmi, encoder); -} - -static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) -{ - return container_of(connector, struct inno_hdmi, connector); -} - -#define to_inno_hdmi_conn_state(conn_state) \ - container_of_const(conn_state, struct inno_hdmi_connector_state, base) - -enum { - CSC_RGB_0_255_TO_ITU601_16_235_8BIT, - CSC_RGB_0_255_TO_ITU709_16_235_8BIT, - CSC_RGB_0_255_TO_RGB_16_235_8BIT, -}; - -static const char coeff_csc[][24] = { - /* - * RGB2YUV:601 SD mode: - * Cb = -0.291G - 0.148R + 0.439B + 128 - * Y = 0.504G + 0.257R + 0.098B + 16 - * Cr = -0.368G + 0.439R - 0.071B + 128 - */ - { - 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80, - 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e, - 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80 - }, - /* - * RGB2YUV:709 HD mode: - * Cb = - 0.338G - 0.101R + 0.439B + 128 - * Y = 0.614G + 0.183R + 0.062B + 16 - * Cr = - 0.399G + 0.439R - 0.040B + 128 - */ - { - 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80, - 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10, - 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80 - }, - /* - * RGB[0:255]2RGB[16:235]: - * R' = R x (235-16)/255 + 16; - * G' = G x (235-16)/255 + 16; - * B' = B x (235-16)/255 + 16; - */ - { - 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10, - 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10 - }, -}; - -static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { - { 74250000, 0x3f, 0xbb }, - { 165000000, 0x6f, 0xbb }, - { ~0UL, 0x00, 0x00 } -}; - -static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { - { 74250000, 0x3f, 0xaa }, - { 165000000, 0x5f, 0xaa }, - { ~0UL, 0x00, 0x00 } -}; - -static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, - unsigned long pixelclk) -{ - const struct inno_hdmi_phy_config *phy_configs = - hdmi->variant->phy_configs; - int i; - - for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) { - if (pixelclk <= phy_configs[i].pixelclock) - return i; - } - - DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n", - pixelclk); - - return -EINVAL; -} - -static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) -{ - return readl_relaxed(hdmi->regs + (offset) * 0x04); -} - -static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val) -{ - writel_relaxed(val, hdmi->regs + (offset) * 0x04); -} - -static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, - u32 msk, u32 val) -{ - u8 temp = hdmi_readb(hdmi, offset) & ~msk; - - temp |= val & msk; - hdmi_writeb(hdmi, offset, temp); -} - -static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate) -{ - unsigned long long ddc_bus_freq = rate >> 2; - - do_div(ddc_bus_freq, HDMI_SCL_RATE); - - hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); - hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); - - /* Clear the EDID interrupt flag and mute the interrupt */ - hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); - hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); -} - -static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) -{ - if (enable) - hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON); - else - hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF); -} - -static void inno_hdmi_standby(struct inno_hdmi *hdmi) -{ - inno_hdmi_sys_power(hdmi, false); - - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); -}; - -static void inno_hdmi_power_up(struct inno_hdmi *hdmi, - unsigned long mpixelclock) -{ - struct inno_hdmi_phy_config *phy_config; - int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock); - - if (ret < 0) { - phy_config = hdmi->variant->default_phy_config; - DRM_DEV_ERROR(hdmi->dev, - "Using default phy configuration for TMDS rate %lu", - mpixelclock); - } else { - phy_config = &hdmi->variant->phy_configs[ret]; - } - - inno_hdmi_sys_power(hdmi, false); - - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); - - inno_hdmi_sys_power(hdmi, true); -}; - -static void inno_hdmi_reset(struct inno_hdmi *hdmi) -{ - u32 val; - u32 msk; - - hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL); - udelay(100); - - hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG); - udelay(100); - - msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL; - val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; - hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); - - inno_hdmi_standby(hdmi); -} - -static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, - enum hdmi_infoframe_type type) -{ - struct drm_connector *connector = &hdmi->connector; - - if (type != HDMI_INFOFRAME_TYPE_AVI) { - drm_err(connector->dev, - "Unsupported infoframe type: %u\n", type); - return; - } - - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); -} - -static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, - union hdmi_infoframe *frame, enum hdmi_infoframe_type type) -{ - struct drm_connector *connector = &hdmi->connector; - u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; - ssize_t rc, i; - - if (type != HDMI_INFOFRAME_TYPE_AVI) { - drm_err(connector->dev, - "Unsupported infoframe type: %u\n", type); - return 0; - } - - inno_hdmi_disable_frame(hdmi, type); - - rc = hdmi_infoframe_pack(frame, packed_frame, - sizeof(packed_frame)); - if (rc < 0) - return rc; - - for (i = 0; i < rc; i++) - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, - packed_frame[i]); - - return 0; -} - -static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - struct drm_connector *connector = &hdmi->connector; - struct drm_connector_state *conn_state = connector->state; - struct inno_hdmi_connector_state *inno_conn_state = - to_inno_hdmi_conn_state(conn_state); - union hdmi_infoframe frame; - int rc; - - rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - &hdmi->connector, - mode); - if (rc) { - inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI); - return rc; - } - - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) - frame.avi.colorspace = HDMI_COLORSPACE_YUV444; - else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422) - frame.avi.colorspace = HDMI_COLORSPACE_YUV422; - else - frame.avi.colorspace = HDMI_COLORSPACE_RGB; - - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - drm_hdmi_avi_infoframe_quant_range(&frame.avi, - connector, mode, - inno_conn_state->rgb_limited_range ? - HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL); - } else { - frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; - frame.avi.ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - } - - return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); -} - -static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) -{ - struct drm_connector *connector = &hdmi->connector; - struct drm_connector_state *conn_state = connector->state; - struct inno_hdmi_connector_state *inno_conn_state = - to_inno_hdmi_conn_state(conn_state); - int c0_c2_change = 0; - int csc_enable = 0; - int csc_mode = 0; - int auto_csc = 0; - int value; - int i; - - /* Input video mode is SDR RGB24bit, data enable signal from external */ - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL | - v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444)); - - /* Input color hardcode to RGB, and output color hardcode to RGB888 */ - value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | - v_VIDEO_OUTPUT_COLOR(0) | - v_VIDEO_INPUT_CSP(0); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - if (inno_conn_state->rgb_limited_range) { - csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; - auto_csc = AUTO_CSC_DISABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_ENABLE; - - } else { - value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, - m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, - v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | - v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); - return 0; - } - } else { - if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; - auto_csc = AUTO_CSC_DISABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_ENABLE; - } - } else { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; - auto_csc = AUTO_CSC_DISABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_ENABLE; - } - } - } - - for (i = 0; i < 24; i++) - hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i, - coeff_csc[csc_mode][i]); - - value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC | - m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) | - v_VIDEO_C0_C2_SWAP(c0_c2_change)); - - return 0; -} - -static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - int value; - - /* Set detail external video timing polarity and interlace mode */ - value = v_EXTERANL_VIDEO(1); - value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? - v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0); - value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? - v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0); - value |= mode->flags & DRM_MODE_FLAG_INTERLACE ? - v_INETLACE(1) : v_INETLACE(0); - hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value); - - /* Set detail external video timing */ - value = mode->htotal; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF); - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF); - - value = mode->htotal - mode->hdisplay; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); - - value = mode->htotal - mode->hsync_start; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); - - value = mode->hsync_end - mode->hsync_start; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF); - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF); - - value = mode->vtotal; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF); - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF); - - value = mode->vtotal - mode->vdisplay; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); - - value = mode->vtotal - mode->vsync_start; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); - - value = mode->vsync_end - mode->vsync_start; - hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF); - - hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e); - hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c); - hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01); - - return 0; -} - -static int inno_hdmi_setup(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - struct drm_display_info *display = &hdmi->connector.display_info; - unsigned long mpixelclock = mode->clock * 1000; - - /* Mute video and audio output */ - hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); - - /* Set HDMI Mode */ - hdmi_writeb(hdmi, HDMI_HDCP_CTRL, - v_HDMI_DVI(display->is_hdmi)); - - inno_hdmi_config_video_timing(hdmi, mode); - - inno_hdmi_config_video_csc(hdmi); - - if (display->is_hdmi) - inno_hdmi_config_video_avi(hdmi, mode); - - /* - * When IP controller have configured to an accurate video - * timing, then the TMDS clock source would be switched to - * DCLK_LCDC, so we need to init the TMDS rate to mode pixel - * clock rate, and reconfigure the DDC clock. - */ - inno_hdmi_i2c_init(hdmi, mpixelclock); - - /* Unmute video and audio output */ - hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); - - inno_hdmi_power_up(hdmi, mpixelclock); - - return 0; -} - -static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - unsigned long mpixelclk, max_tolerance; - long rounded_refclk; - - /* No support for double-clock modes */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - return MODE_BAD; - - mpixelclk = mode->clock * 1000; - - if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK) - return MODE_CLOCK_LOW; - - if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0) - return MODE_CLOCK_HIGH; - - if (hdmi->refclk) { - rounded_refclk = clk_round_rate(hdmi->refclk, mpixelclk); - if (rounded_refclk < 0) - return MODE_BAD; - - /* Vesa DMT standard mentions +/- 0.5% max tolerance */ - max_tolerance = mpixelclk / 200; - if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance) - return MODE_NOCLOCK; - } - - return MODE_OK; -} - -static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - struct drm_connector_state *conn_state; - struct drm_crtc_state *crtc_state; - - conn_state = drm_atomic_get_new_connector_state(state, &hdmi->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; - - inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); -} - -static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - - inno_hdmi_standby(hdmi); -} - -static int -inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - struct drm_display_mode *mode = &crtc_state->adjusted_mode; - u8 vic = drm_match_cea_mode(mode); - struct inno_hdmi_connector_state *inno_conn_state = - to_inno_hdmi_conn_state(conn_state); - - s->output_mode = ROCKCHIP_OUT_MODE_P888; - s->output_type = DRM_MODE_CONNECTOR_HDMIA; - - if (vic == 6 || vic == 7 || - vic == 21 || vic == 22 || - vic == 2 || vic == 3 || - vic == 17 || vic == 18) - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; - else - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; - - inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; - inno_conn_state->rgb_limited_range = - drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; - - return inno_hdmi_display_mode_valid(hdmi, - &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; -} - -static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { - .atomic_check = inno_hdmi_encoder_atomic_check, - .atomic_enable = inno_hdmi_encoder_enable, - .atomic_disable = inno_hdmi_encoder_disable, -}; - -static enum drm_connector_status -inno_hdmi_connector_detect(struct drm_connector *connector, bool force) -{ - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); - - return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? - connector_status_connected : connector_status_disconnected; -} - -static int inno_hdmi_connector_get_modes(struct drm_connector *connector) -{ - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); - const struct drm_edid *drm_edid; - int ret = 0; - - if (!hdmi->ddc) - return 0; - - drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); - drm_edid_connector_update(connector, drm_edid); - ret = drm_edid_connector_add_modes(connector); - drm_edid_free(drm_edid); - - return ret; -} - -static enum drm_mode_status -inno_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); - - return inno_hdmi_display_mode_valid(hdmi, mode); -} - -static void inno_hdmi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static void -inno_hdmi_connector_destroy_state(struct drm_connector *connector, - struct drm_connector_state *state) -{ - struct inno_hdmi_connector_state *inno_conn_state = - to_inno_hdmi_conn_state(state); - - __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base); - kfree(inno_conn_state); -} - -static void inno_hdmi_connector_reset(struct drm_connector *connector) -{ - struct inno_hdmi_connector_state *inno_conn_state; - - if (connector->state) { - inno_hdmi_connector_destroy_state(connector, connector->state); - connector->state = NULL; - } - - inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); - if (!inno_conn_state) - return; - - __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); - - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; - inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; - inno_conn_state->rgb_limited_range = false; -} - -static struct drm_connector_state * -inno_hdmi_connector_duplicate_state(struct drm_connector *connector) -{ - struct inno_hdmi_connector_state *inno_conn_state; - - if (WARN_ON(!connector->state)) - return NULL; - - inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state), - sizeof(*inno_conn_state), GFP_KERNEL); - - if (!inno_conn_state) - return NULL; - - __drm_atomic_helper_connector_duplicate_state(connector, - &inno_conn_state->base); - - return &inno_conn_state->base; -} - -static const struct drm_connector_funcs inno_hdmi_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = inno_hdmi_connector_detect, - .destroy = inno_hdmi_connector_destroy, - .reset = inno_hdmi_connector_reset, - .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, - .atomic_destroy_state = inno_hdmi_connector_destroy_state, -}; - -static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { - .get_modes = inno_hdmi_connector_get_modes, - .mode_valid = inno_hdmi_connector_mode_valid, -}; - -static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) -{ - struct drm_encoder *encoder = &hdmi->encoder.encoder; - struct device *dev = hdmi->dev; - - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); - - /* - * If we failed to find the CRTC(s) which this encoder is - * supposed to be connected to, it's because the CRTC has - * not been registered yet. Defer probing, and hope that - * the required CRTC is added later. - */ - if (encoder->possible_crtcs == 0) - return -EPROBE_DEFER; - - drm_encoder_helper_add(encoder, &inno_hdmi_encoder_helper_funcs); - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); - - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; - - drm_connector_helper_add(&hdmi->connector, - &inno_hdmi_connector_helper_funcs); - drm_connector_init_with_ddc(drm, &hdmi->connector, - &inno_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); - - drm_connector_attach_encoder(&hdmi->connector, encoder); - - return 0; -} - -static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi) -{ - struct inno_hdmi_i2c *i2c = hdmi->i2c; - u8 stat; - - stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1); - if (!(stat & m_INT_EDID_READY)) - return IRQ_NONE; - - /* Clear HDMI EDID interrupt flag */ - hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); - - complete(&i2c->cmp); - - return IRQ_HANDLED; -} - -static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id) -{ - struct inno_hdmi *hdmi = dev_id; - irqreturn_t ret = IRQ_NONE; - u8 interrupt; - - if (hdmi->i2c) - ret = inno_hdmi_i2c_irq(hdmi); - - interrupt = hdmi_readb(hdmi, HDMI_STATUS); - if (interrupt & m_INT_HOTPLUG) { - hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG); - ret = IRQ_WAKE_THREAD; - } - - return ret; -} - -static irqreturn_t inno_hdmi_irq(int irq, void *dev_id) -{ - struct inno_hdmi *hdmi = dev_id; - - drm_helper_hpd_irq_event(hdmi->connector.dev); - - return IRQ_HANDLED; -} - -static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs) -{ - int length = msgs->len; - u8 *buf = msgs->buf; - int ret; - - ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10); - if (!ret) - return -EAGAIN; - - while (length--) - *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR); - - return 0; -} - -static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs) -{ - /* - * The DDC module only support read EDID message, so - * we assume that each word write to this i2c adapter - * should be the offset of EDID word address. - */ - if ((msgs->len != 1) || - ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR))) - return -EINVAL; - - reinit_completion(&hdmi->i2c->cmp); - - if (msgs->addr == DDC_SEGMENT_ADDR) - hdmi->i2c->segment_addr = msgs->buf[0]; - if (msgs->addr == DDC_ADDR) - hdmi->i2c->ddc_addr = msgs->buf[0]; - - /* Set edid fifo first addr */ - hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00); - - /* Set edid word address 0x00/0x80 */ - hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr); - - /* Set edid segment pointer */ - hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr); - - return 0; -} - -static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct inno_hdmi *hdmi = i2c_get_adapdata(adap); - struct inno_hdmi_i2c *i2c = hdmi->i2c; - int i, ret = 0; - - mutex_lock(&i2c->lock); - - /* Clear the EDID interrupt flag and unmute the interrupt */ - hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY); - hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); - - for (i = 0; i < num; i++) { - DRM_DEV_DEBUG(hdmi->dev, - "xfer: num: %d/%d, len: %d, flags: %#x\n", - i + 1, num, msgs[i].len, msgs[i].flags); - - if (msgs[i].flags & I2C_M_RD) - ret = inno_hdmi_i2c_read(hdmi, &msgs[i]); - else - ret = inno_hdmi_i2c_write(hdmi, &msgs[i]); - - if (ret < 0) - break; - } - - if (!ret) - ret = num; - - /* Mute HDMI EDID interrupt */ - hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0); - - mutex_unlock(&i2c->lock); - - return ret; -} - -static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm inno_hdmi_algorithm = { - .master_xfer = inno_hdmi_i2c_xfer, - .functionality = inno_hdmi_i2c_func, -}; - -static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) -{ - struct i2c_adapter *adap; - struct inno_hdmi_i2c *i2c; - int ret; - - i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) - return ERR_PTR(-ENOMEM); - - mutex_init(&i2c->lock); - init_completion(&i2c->cmp); - - adap = &i2c->adap; - adap->owner = THIS_MODULE; - adap->dev.parent = hdmi->dev; - adap->dev.of_node = hdmi->dev->of_node; - adap->algo = &inno_hdmi_algorithm; - strscpy(adap->name, "Inno HDMI", sizeof(adap->name)); - i2c_set_adapdata(adap, hdmi); - - ret = i2c_add_adapter(adap); - if (ret) { - dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); - devm_kfree(hdmi->dev, i2c); - return ERR_PTR(ret); - } - - hdmi->i2c = i2c; - - DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name); - - return adap; -} - -static int inno_hdmi_bind(struct device *dev, struct device *master, - void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct drm_device *drm = data; - struct inno_hdmi *hdmi; - const struct inno_hdmi_variant *variant; - int irq; - int ret; - - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; - - hdmi->dev = dev; - - variant = of_device_get_match_data(hdmi->dev); - if (!variant) - return -EINVAL; - - hdmi->variant = variant; - - hdmi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hdmi->regs)) - return PTR_ERR(hdmi->regs); - - hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); - if (IS_ERR(hdmi->pclk)) { - DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); - return PTR_ERR(hdmi->pclk); - } - - ret = clk_prepare_enable(hdmi->pclk); - if (ret) { - DRM_DEV_ERROR(hdmi->dev, - "Cannot enable HDMI pclk clock: %d\n", ret); - return ret; - } - - hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); - if (IS_ERR(hdmi->refclk)) { - DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n"); - ret = PTR_ERR(hdmi->refclk); - goto err_disable_pclk; - } - - ret = clk_prepare_enable(hdmi->refclk); - if (ret) { - DRM_DEV_ERROR(hdmi->dev, - "Cannot enable HDMI reference clock: %d\n", ret); - goto err_disable_pclk; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } - - inno_hdmi_reset(hdmi); - - hdmi->ddc = inno_hdmi_i2c_adapter(hdmi); - if (IS_ERR(hdmi->ddc)) { - ret = PTR_ERR(hdmi->ddc); - hdmi->ddc = NULL; - goto err_disable_clk; - } - - /* - * When the controller isn't configured to an accurate - * video timing and there is no reference clock available, - * then the TMDS clock source would be switched to PCLK_HDMI, - * so we need to init the TMDS rate to PCLK rate, and - * reconfigure the DDC clock. - */ - if (hdmi->refclk) - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk)); - else - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); - - ret = inno_hdmi_register(drm, hdmi); - if (ret) - goto err_put_adapter; - - dev_set_drvdata(dev, hdmi); - - /* Unmute hotplug interrupt */ - hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1)); - - ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq, - inno_hdmi_irq, IRQF_SHARED, - dev_name(dev), hdmi); - if (ret < 0) - goto err_cleanup_hdmi; - - return 0; -err_cleanup_hdmi: - hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); -err_put_adapter: - i2c_put_adapter(hdmi->ddc); -err_disable_clk: - clk_disable_unprepare(hdmi->refclk); -err_disable_pclk: - clk_disable_unprepare(hdmi->pclk); - return ret; -} - -static void inno_hdmi_unbind(struct device *dev, struct device *master, - void *data) -{ - struct inno_hdmi *hdmi = dev_get_drvdata(dev); - - hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); - - i2c_put_adapter(hdmi->ddc); - clk_disable_unprepare(hdmi->refclk); - clk_disable_unprepare(hdmi->pclk); -} - -static const struct component_ops inno_hdmi_ops = { - .bind = inno_hdmi_bind, - .unbind = inno_hdmi_unbind, -}; - -static int inno_hdmi_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &inno_hdmi_ops); -} - -static void inno_hdmi_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &inno_hdmi_ops); -} - -static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { - .phy_configs = rk3036_hdmi_phy_configs, - .default_phy_config = &rk3036_hdmi_phy_configs[1], -}; - -static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { - .phy_configs = rk3128_hdmi_phy_configs, - .default_phy_config = &rk3128_hdmi_phy_configs[1], -}; - -static const struct of_device_id inno_hdmi_dt_ids[] = { - { .compatible = "rockchip,rk3036-inno-hdmi", - .data = &rk3036_inno_hdmi_variant, - }, - { .compatible = "rockchip,rk3128-inno-hdmi", - .data = &rk3128_inno_hdmi_variant, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); - -struct platform_driver inno_hdmi_driver = { - .probe = inno_hdmi_probe, - .remove_new = inno_hdmi_remove, - .driver = { - .name = "innohdmi-rockchip", - .of_match_table = inno_hdmi_dt_ids, - }, -}; From patchwork Tue May 21 10:58:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668831 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3017AC25B7B for ; Tue, 21 May 2024 02:58:55 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D26CD10E6BC; Tue, 21 May 2024 02:58:53 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2139.outbound.protection.partner.outlook.cn [139.219.17.139]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1419710E228 for ; Tue, 21 May 2024 02:58:34 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fEXClifMsBX5kAMEo30YxRO/QSy3zMJ/UK3iyqNfgRatXn9qXz/WREZestd8N7/JImFYWgz8isoUB/PcS7hcpmY3G46PTY8XJ0HZxnp9UjIflRHqxyFzW/xaB7FZKtzQlU7XrmDJYPRJiFSc9ebfjc5mRMMomQ4oF79sXIPldS7Gb9qyZM6Z/vXEmdHhGbO5fUYwyCrrQxxOtPawlNN75cfTh8TfQExDqdxG4SdB4bdhyXXhpfd1+ytEg6eXVaQ0NPcW2TbFWBlAJ/08HkTsxyLyI3uqc0OIiF++XJpYhYfPs15hSflqVFYlLSWWlIn1ps1U43t0z0th/SWHXei82w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ApQx65Uq/nJ6PhVgzQi3lKuYgz09IZ3/dwIw664cNls=; b=TSeCSpF44zS0IOjdWUxUl+XuOZ0biKb4X1TTKqrveqDVxez0vsn1zgLxc51b2lh1X7unL0xe5/jOI6/jF+rto3MY0S1/mnK56RL3mJszpAExuDGyWitrGj5Q6Pkoz0Igbqvapvsg5fI0gQ5+qYEMh+xqUnmmB9sX/0sAecxIkuLupjQJa/dWlCHq+wqw8b0Jt8IQBFjpBHkf24euz7j7aUPKh3pbslWyJBTQQ9ASY/Pb9WyFAJabPoi4u4+iG40QL15rEz9T032iN/M+Dz1Jcx0OtxxmIgpVUhIPPyySDkkGRzi1Oa7jXQa8c9x8QLLXkD2WrBqSLITvBgSWU9EfsA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1255.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:19::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.36; Tue, 21 May 2024 02:58:30 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:30 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 04/10] drm/vs: Add hardware funcs for vs. Date: Tue, 21 May 2024 18:58:11 +0800 Message-Id: <20240521105817.3301-5-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1255:EE_ X-MS-Office365-Filtering-Correlation-Id: cda4fd93-d43d-4423-87c1-08dc7941e4d3 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; ARA:13230031|366007|41320700004|1800799015|7416005|52116005|921011|38350700005; X-Microsoft-Antispam-Message-Info: GsKi38QmMrPM5ziIdCzJOwqHq0lfmnXNSXxdSSxCPlKV+T8MEzwIJ0ivSWjasMpaO6QiYKDgHJGkT4PdJwKNU2V7mfiaB0I3ILuFhZjP8dIM0LeUoRDYMeFyX3DKkYXTTTUj7UZKU0Gmbv03XQqg5eMn2FFUsyjkBu3njfYbgYeSj9AwVk9cgshpKxfLLmGxhZE3vGFCvoejLrqY/BO2OhgQvA4+4+0E7QWHTV7syJNW+1+Ae/GwoVRgE9px5d9nmckzwCarQqBwnbrF/XLD86NUKqbotv4lmuHmlN4XZ/bTJSZEFTqCTHMmnXjydRd4MAEHFGo9pHIHrsP4ZR/svi+W48SjRhIYV5jNZiQ5iVNdpNQQiGSLNQ7Wl18Ja82uTlT2A3qZmX6zz/Bz2pYt2kwwmhlX8rfRrffhD3vHhPSm7palrShzAHCgng/JQUZnVd13Pc//6btjvc3zfYcMwpLegQruZk7VBbFtR5v0CBTigSFRq/sdN97FxaKKi4209KxgvJr5eesMr6c4mVCPsHm4+p+JAleUI+ef/FdtXI41dgdwhnfRMrrc8IU6p2rkEpTtEx1S493seaeYfSbVijtOC5lRZNGxGwhvxCYeRp3li8xPG1stkWKC8//UHICqFpvFJCDJSRtd0iRg53UBYg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(366007)(41320700004)(1800799015)(7416005)(52116005)(921011)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: ejVOXr8s/yra8x47+CqRGQGOww0Wbd5Jzzj0HncT33JW2CPWOcE14KIP/8drbyaoD8XhApp3Ee7dU60+uKLEo9Nb3fM2GyC8OCBMQPNdza/KWRFqH98kg8ZIt4atTQqzxefy0XpBwOa5kpfAUJsPywdGgeQmjQ/2GQPBMKsaMkKnW0BUvDGF6R8hC7NiNyT1vpuGqYMS/2D5lDwU8/l07BUJVhWgORyt9SIHdu906S8nnW9MFjYbH3z49tF0ZjeDifNa1Ljj3nnGm8KB4XHKqdgv7uabFIvMooRoRsKeJzhy39wDs30bllIxt3IxNCb6L8XFRTLAqVLmeAAPafANSpjkucWTU7qFmH8lmpufOHlM6sHslorK9G8vln6fjrMxM04AbDFo/ZYQCeKJvj88e1hC8xAZo/z8ua2vx7AT04U5mT0ulWru8p4yOgxFDAyUIhctAe13IpGIk1mETGPKeYSqEhdU0/3Mv/A7+VP1bH/wFDC12Ow9RxA7t47kfU9ifSRNciNX+Y2u/VbImG3MF9yYYjgN3+5K8TbMHNyPE0pxxLDVqQ3E6YncDQpIqdO3lxNl8dQEZDuEfKyIZ6Zp+G2e33PwCqmF2TSSwD+v759FcXRdxONIqQ0EN+Vmh6qDHW5vwrChEhKc5POb8+ecENEp9y7+LjMGWN6ksK98uHQtvmsV16mP7bLS77Yp7pqmlCo4UjHI7QGqBmKoACJA6E6NY20PirFqMhGHadp8FMCUxTjz9LwqbP5jeDmFtV5HWCUfKwm5t1JgUzIiHkFqVYv51yhhIM+K7obskdaRP+jrl4IVQcqQ1KTwqNMwtU/ZkWJ5sPHBj0XuU5C+oWuO/vCje+71eopp36KoGmGcxs5im8U0iDheB/1wWWYpVSUR+0dgELHjv7ji0DJPuu04d6zX/dwAB4WlSwojTlD7BHILSeMLHPQJWUinMIhu70nzHkRZ5NPDJvBVzycDxr75ogLwW58wP6DpTbdV1YCh3syYuWcN4fA1xUq8MnbAC2NSgkqD1ylhvWN7cEquK1QiWMdCbPwh8oKkO075pff6FnHIGC2WM+S6KRZqAMGrvQAKKnSKOyRRL8ak4fjxxkFFoHhBLGUJf1Ziw+QnEYhuHaCmKFNIGKBA0Pbsr4TbH3UKTlnV9yhQ8lxctiClrApkGQnoGpBvRzVjzVI21tvY5E0wwHFrSTGOGOe8Dgtx69dHQjOHycYWRNwh3ECOaJLxIoGNrsg66IZTsRBu2nXD9nJXzh3FpUtKlu5FOHiVpaRB+x/9gnbpI0tu9aIZtsLghKDgN7NW3YkUkd0H30vFQ4L5aHVhAk6a31oVX3JRa3uso9GaNx6gQJFnOIlMB1IRw+LYgFGkjivumYNpiL4IRJ51M6cRDyjBMDLbilrz9zvgeWEm6kjzJUF153tZ4rBmiZSLzKDDClFrwE4VZ4q1Edbvjc+PYLu6DTb9tpwknLc1Etuy33WjGCi++thD7WQTlgvRFeFayGyWtrEZdLGThPOLCdeOKpd0SHoVN9btRWTB6T2JH5I/rX3MDW4Hrgi7DZsQIC5GwrhbQ+3RUUH0aGsBqt7AWikzyk3JXAz1roPtLIg0H+UsHQNcOcO0DuieGw== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: cda4fd93-d43d-4423-87c1-08dc7941e4d3 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:29.9976 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: +teN81CXgOzQueS3CE14dDv/8/AFOUxgwblv0Ij9q9s47b/+WRSmrvnclzGAwGulpANaHvSGfouAmD2BOydvAostC28idp8Eb5XTZ2dbcZw= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1255 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add hardware base api for vs drm Signed-off-by: keith --- MAINTAINERS | 1 + drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/verisilicon/Kconfig | 13 + drivers/gpu/drm/verisilicon/Makefile | 5 + drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1060 ++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_dc_hw.h | 493 +++++++++++ drivers/gpu/drm/verisilicon/vs_type.h | 84 ++ 8 files changed, 1659 insertions(+) create mode 100644 drivers/gpu/drm/verisilicon/Kconfig create mode 100644 drivers/gpu/drm/verisilicon/Makefile create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h diff --git a/MAINTAINERS b/MAINTAINERS index cf2d66f88a83..9cb376f76f74 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7156,6 +7156,7 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/bridge/innosilicon,inno-hdmi.yaml F: Documentation/devicetree/bindings/display/starfive/ F: drivers/gpu/drm/bridge/innosilicon/ +F: drivers/gpu/drm/verisilicon F: include/drm/bridge/inno_hdmi.h DRM DRIVER FOR SYNAPTICS R63353 PANELS diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 026444eeb5c6..5413d87ef1d6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -423,6 +423,8 @@ source "drivers/gpu/drm/sprd/Kconfig" source "drivers/gpu/drm/imagination/Kconfig" +source "drivers/gpu/drm/verisilicon/Kconfig" + config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f9ca4f8fa6c5..cb27092b1672 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -219,3 +219,4 @@ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-$(CONFIG_DRM_LOONGSON) += loongson/ obj-$(CONFIG_DRM_POWERVR) += imagination/ +obj-$(CONFIG_DRM_VERISILICON_DC8200) += verisilicon/ diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig new file mode 100644 index 000000000000..2d733f93439e --- /dev/null +++ b/drivers/gpu/drm/verisilicon/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +config DRM_VERISILICON_DC8200 + tristate "DRM Support for VeriSilicon DC8200" + depends on DRM + select DRM_KMS_HELPER + select DRM_GEM_DMA_HELPER + select CMA + select DMA_CMA + help + Choose this option if you have a VeriSilicon DC8200 chipset. + This driver provides VeriSilicon kernel mode + setting and buffer management. It does not + provide 2D or 3D acceleration. diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile new file mode 100644 index 000000000000..7da54b259940 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +vs_drm-objs := vs_dc_hw.o + +obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c new file mode 100644 index 000000000000..69f020f8352f --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c @@ -0,0 +1,1060 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#include +#include +#include +//#include +#include +#include +#include +#include + +#include "vs_dc_hw.h" + +static const u32 horkernel[] = { + 0x00000000, 0x20000000, 0x00002000, 0x00000000, + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000, + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1, + 0x00000000, 0x00000000, 0x00000000, 0x2b981468, + 0x00000000, 0x00000000, 0x00000000, 0x10f00000, + 0x00002f10, 0x00000000, 0x00000000, 0x00000000, + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000, + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000, + 0x00000000, 0x3781087f, 0x00000000, 0x00000000, + 0x00000000, 0x06660000, 0x0000399a, 0x00000000, + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000, + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4, + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f, + 0x00000000, 0x00000000, 0x00000000, 0x01470000, + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000, + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000, + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000, + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00004000, 0x00000000, + 0x00000000, 0x00000000, 0x20002000, 0x00000000, + 0x00000000, 0x00000000, 0x1c030000, 0x000023fd, + 0x00000000, 0x00000000, 0x00000000, 0x27e1181f, + 0x00000000, 0x00000000, 0x00000000, 0x14680000, + 0x00002b98, 0x00000000, 0x00000000, 0x00000000, + 0x2f1010f0, 0x00000000, 0x00000000, 0x00000000, + 0x0dc70000, 0x00003239, 0x00000000, 0x00000000, + 0x00000000, 0x350b0af5, 0x00000000, 0x00000000, + 0x00000000, 0x087f0000, 0x00003781, 0x00000000, + 0x00000000, 0x00000000, 0x399a0666, 0x00000000, + 0x00000000, 0x00000000, 0x04a70000, 0x00003b59, + 0x00000000, 0x00000000, 0x00000000, 0x3cc4033c, + 0x00000000, 0x00000000, 0x00000000, 0x021f0000, +}; + +#define H_COEF_SIZE ARRAY_SIZE(horkernel) + +static const u32 verkernel[] = { + 0x00000000, 0x20000000, 0x00002000, 0x00000000, + 0x00000000, 0x00000000, 0x23fd1c03, 0x00000000, + 0x00000000, 0x00000000, 0x181f0000, 0x000027e1, + 0x00000000, 0x00000000, 0x00000000, 0x2b981468, + 0x00000000, 0x00000000, 0x00000000, 0x10f00000, + 0x00002f10, 0x00000000, 0x00000000, 0x00000000, + 0x32390dc7, 0x00000000, 0x00000000, 0x00000000, + 0x0af50000, 0x0000350b, 0x00000000, 0x00000000, + 0x00000000, 0x3781087f, 0x00000000, 0x00000000, + 0x00000000, 0x06660000, 0x0000399a, 0x00000000, + 0x00000000, 0x00000000, 0x3b5904a7, 0x00000000, + 0x00000000, 0x00000000, 0x033c0000, 0x00003cc4, + 0x00000000, 0x00000000, 0x00000000, 0x3de1021f, + 0x00000000, 0x00000000, 0x00000000, 0x01470000, + 0x00003eb9, 0x00000000, 0x00000000, 0x00000000, + 0x3f5300ad, 0x00000000, 0x00000000, 0x00000000, + 0x00480000, 0x00003fb8, 0x00000000, 0x00000000, + 0x00000000, 0x3fef0011, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00004000, 0x00000000, + 0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab, + 0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58, + 0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, + 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee, +}; + +#define V_COEF_SIZE ARRAY_SIZE(verkernel) + +/* + * RGB 709->2020 conversion parameters + */ +static const u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = { + 10279, 5395, 709, + 1132, 15065, 187, + 269, 1442, 14674 +}; + +/* + * YUV601 to RGB conversion parameters + * YUV2RGB[0] - [8] : C0 - C8; + * YUV2RGB[9] - [11]: D0 - D2; + * YUV2RGB[12] - [13]: Y clamp min & max calue; + * YUV2RGB[14] - [15]: UV clamp min & max calue; + */ +static const s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = { + 1196, 0, 1640, 1196, + -404, -836, 1196, 2076, + 0, -916224, 558336, -1202944, + 64, 940, 64, 960 +}; + +/* + * YUV709 to RGB conversion parameters + * YUV2RGB[0] - [8] : C0 - C8; + * YUV2RGB[9] - [11]: D0 - D2; + * YUV2RGB[12] - [13]: Y clamp min & max calue; + * YUV2RGB[14] - [15]: UV clamp min & max calue; + */ +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = { + 1196, 0, 1844, 1196, + -220, -548, 1196, 2172, + 0, -1020672, 316672, -1188608, + 64, 940, 64, 960 +}; + +/* + * YUV2020 to RGB conversion parameters + * YUV2RGB[0] - [8] : C0 - C8; + * YUV2RGB[9] - [11]: D0 - D2; + * YUV2RGB[12] - [13]: Y clamp min & max calue; + * YUV2RGB[14] - [15]: UV clamp min & max calue; + */ +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = { + 1196, 0, 1724, 1196, + -192, -668, 1196, 2200, + 0, -959232, 363776, -1202944, + 64, 940, 64, 960 +}; + +/* + * RGB to YUV2020 conversion parameters + * RGB2YUV[0] - [8] : C0 - C8; + * RGB2YUV[9] - [11]: D0 - D2; + */ +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = { + 230, 594, 52, + -125, -323, 448, + 448, -412, -36, + 64, 512, 512 +}; + +/* one is for primary plane and the other is for all overlay planes */ +static const struct dc_hw_plane_reg dc_plane_reg[] = { + { + .y_address = DC_FRAMEBUFFER_ADDRESS, + .u_address = DC_FRAMEBUFFER_U_ADDRESS, + .v_address = DC_FRAMEBUFFER_V_ADDRESS, + .y_stride = DC_FRAMEBUFFER_STRIDE, + .u_stride = DC_FRAMEBUFFER_U_STRIDE, + .v_stride = DC_FRAMEBUFFER_V_STRIDE, + .size = DC_FRAMEBUFFER_SIZE, + .top_left = DC_FRAMEBUFFER_TOP_LEFT, + .bottom_right = DC_FRAMEBUFFER_BOTTOM_RIGHT, + .scale_factor_x = DC_FRAMEBUFFER_SCALE_FACTOR_X, + .scale_factor_y = DC_FRAMEBUFFER_SCALE_FACTOR_Y, + .h_filter_coef_index = DC_FRAMEBUFFER_H_FILTER_COEF_INDEX, + .h_filter_coef_data = DC_FRAMEBUFFER_H_FILTER_COEF_DATA, + .v_filter_coef_index = DC_FRAMEBUFFER_V_FILTER_COEF_INDEX, + .v_filter_coef_data = DC_FRAMEBUFFER_V_FILTER_COEF_DATA, + .init_offset = DC_FRAMEBUFFER_INIT_OFFSET, + .color_key = DC_FRAMEBUFFER_COLOR_KEY, + .color_key_high = DC_FRAMEBUFFER_COLOR_KEY_HIGH, + .clear_value = DC_FRAMEBUFFER_CLEAR_VALUE, + .color_table_index = DC_FRAMEBUFFER_COLOR_TABLE_INDEX, + .color_table_data = DC_FRAMEBUFFER_COLOR_TABLE_DATA, + .scale_config = DC_FRAMEBUFFER_SCALE_CONFIG, + .water_mark = DC_FRAMEBUFFER_WATER_MARK, + .degamma_index = DC_FRAMEBUFFER_DEGAMMA_INDEX, + .degamma_data = DC_FRAMEBUFFER_DEGAMMA_DATA, + .degamma_ex_data = DC_FRAMEBUFFER_DEGAMMA_EX_DATA, + .src_global_color = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR, + .dst_global_color = DC_FRAMEBUFFER_DST_GLOBAL_COLOR, + .blend_config = DC_FRAMEBUFFER_BLEND_CONFIG, + .roi_origin = DC_FRAMEBUFFER_ROI_ORIGIN, + .roi_size = DC_FRAMEBUFFER_ROI_SIZE, + .yuv_to_rgb_coef0 = DC_FRAMEBUFFER_YUVTORGB_COEF0, + .yuv_to_rgb_coef1 = DC_FRAMEBUFFER_YUVTORGB_COEF1, + .yuv_to_rgb_coef2 = DC_FRAMEBUFFER_YUVTORGB_COEF2, + .yuv_to_rgb_coef3 = DC_FRAMEBUFFER_YUVTORGB_COEF3, + .yuv_to_rgb_coef4 = DC_FRAMEBUFFER_YUVTORGB_COEF4, + .yuv_to_rgb_coefd0 = DC_FRAMEBUFFER_YUVTORGB_COEFD0, + .yuv_to_rgb_coefd1 = DC_FRAMEBUFFER_YUVTORGB_COEFD1, + .yuv_to_rgb_coefd2 = DC_FRAMEBUFFER_YUVTORGB_COEFD2, + .y_clamp_bound = DC_FRAMEBUFFER_Y_CLAMP_BOUND, + .uv_clamp_bound = DC_FRAMEBUFFER_UV_CLAMP_BOUND, + .rgb_to_rgb_coef0 = DC_FRAMEBUFFER_RGBTORGB_COEF0, + .rgb_to_rgb_coef1 = DC_FRAMEBUFFER_RGBTORGB_COEF1, + .rgb_to_rgb_coef2 = DC_FRAMEBUFFER_RGBTORGB_COEF2, + .rgb_to_rgb_coef3 = DC_FRAMEBUFFER_RGBTORGB_COEF3, + .rgb_to_rgb_coef4 = DC_FRAMEBUFFER_RGBTORGB_COEF4, + }, + { + .y_address = DC_OVERLAY_ADDRESS, + .u_address = DC_OVERLAY_U_ADDRESS, + .v_address = DC_OVERLAY_V_ADDRESS, + .y_stride = DC_OVERLAY_STRIDE, + .u_stride = DC_OVERLAY_U_STRIDE, + .v_stride = DC_OVERLAY_V_STRIDE, + .size = DC_OVERLAY_SIZE, + .top_left = DC_OVERLAY_TOP_LEFT, + .bottom_right = DC_OVERLAY_BOTTOM_RIGHT, + .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X, + .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y, + .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX, + .h_filter_coef_data = DC_OVERLAY_H_FILTER_COEF_DATA, + .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX, + .v_filter_coef_data = DC_OVERLAY_V_FILTER_COEF_DATA, + .init_offset = DC_OVERLAY_INIT_OFFSET, + .color_key = DC_OVERLAY_COLOR_KEY, + .color_key_high = DC_OVERLAY_COLOR_KEY_HIGH, + .clear_value = DC_OVERLAY_CLEAR_VALUE, + .color_table_index = DC_OVERLAY_COLOR_TABLE_INDEX, + .color_table_data = DC_OVERLAY_COLOR_TABLE_DATA, + .scale_config = DC_OVERLAY_SCALE_CONFIG, + .water_mark = DC_OVERLAY_WATER_MARK, + .degamma_index = DC_OVERLAY_DEGAMMA_INDEX, + .degamma_data = DC_OVERLAY_DEGAMMA_DATA, + .degamma_ex_data = DC_OVERLAY_DEGAMMA_EX_DATA, + .src_global_color = DC_OVERLAY_SRC_GLOBAL_COLOR, + .dst_global_color = DC_OVERLAY_DST_GLOBAL_COLOR, + .blend_config = DC_OVERLAY_BLEND_CONFIG, + .roi_origin = DC_OVERLAY_ROI_ORIGIN, + .roi_size = DC_OVERLAY_ROI_SIZE, + .yuv_to_rgb_coef0 = DC_OVERLAY_YUVTORGB_COEF0, + .yuv_to_rgb_coef1 = DC_OVERLAY_YUVTORGB_COEF1, + .yuv_to_rgb_coef2 = DC_OVERLAY_YUVTORGB_COEF2, + .yuv_to_rgb_coef3 = DC_OVERLAY_YUVTORGB_COEF3, + .yuv_to_rgb_coef4 = DC_OVERLAY_YUVTORGB_COEF4, + .yuv_to_rgb_coefd0 = DC_OVERLAY_YUVTORGB_COEFD0, + .yuv_to_rgb_coefd1 = DC_OVERLAY_YUVTORGB_COEFD1, + .yuv_to_rgb_coefd2 = DC_OVERLAY_YUVTORGB_COEFD2, + .y_clamp_bound = DC_OVERLAY_Y_CLAMP_BOUND, + .uv_clamp_bound = DC_OVERLAY_UV_CLAMP_BOUND, + .rgb_to_rgb_coef0 = DC_OVERLAY_RGBTORGB_COEF0, + .rgb_to_rgb_coef1 = DC_OVERLAY_RGBTORGB_COEF1, + .rgb_to_rgb_coef2 = DC_OVERLAY_RGBTORGB_COEF2, + .rgb_to_rgb_coef3 = DC_OVERLAY_RGBTORGB_COEF3, + .rgb_to_rgb_coef4 = DC_OVERLAY_RGBTORGB_COEF4, + }, +}; + +static inline u32 hi_read(struct dc_hw *hw, u32 reg) +{ + return readl(hw->hi_base + reg); +} + +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value) +{ + writel(value, hw->hi_base + reg); +} + +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value) +{ + writel(value, hw->reg_base + reg - DC_REG_BASE); +} + +static inline u32 dc_read(struct dc_hw *hw, u32 reg) +{ + u32 value = readl(hw->reg_base + reg - DC_REG_BASE); + + return value; +} + +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear) +{ + u32 value = dc_read(hw, reg); + + value &= ~clear; + value |= set; + dc_write(hw, reg, value); +} + +static void load_default_filter(struct dc_hw *hw, + const struct dc_hw_plane_reg *reg, u32 offset) +{ + u8 i; + + dc_write(hw, reg->scale_config + offset, 0x33); + dc_write(hw, reg->init_offset + offset, 0x80008000); + dc_write(hw, reg->h_filter_coef_index + offset, 0x00); + for (i = 0; i < H_COEF_SIZE; i++) + dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]); + + dc_write(hw, reg->v_filter_coef_index + offset, 0x00); + for (i = 0; i < V_COEF_SIZE; i++) + dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]); +} + +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg, + u32 offset, const u16 *table) +{ + dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16)); + dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16)); + dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16)); + dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16)); + dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]); +} + +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg, + u32 offset, const s32 *table) +{ + dc_write(hw, reg->yuv_to_rgb_coef0 + offset, + (0xFFFF & table[0]) | (table[1] << 16)); + dc_write(hw, reg->yuv_to_rgb_coef1 + offset, + (0xFFFF & table[2]) | (table[3] << 16)); + dc_write(hw, reg->yuv_to_rgb_coef2 + offset, + (0xFFFF & table[4]) | (table[5] << 16)); + dc_write(hw, reg->yuv_to_rgb_coef3 + offset, + (0xFFFF & table[6]) | (table[7] << 16)); + dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]); + dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]); + dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]); + dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]); + dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16)); + dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16)); +} + +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table) +{ + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset, + table[0] | (table[1] << 16)); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset, + table[2] | (table[3] << 16)); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset, + table[4] | (table[5] << 16)); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset, + table[6] | (table[7] << 16)); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]); + dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]); +} + +static int update_vs_format(u32 drm_format) +{ + u8 f = FORMAT_A8R8G8B8; + + switch (drm_format) { + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_BGRX4444: + f = FORMAT_X4R4G4B4; + break; + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_BGRA4444: + f = FORMAT_A4R4G4B4; + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_BGRX5551: + f = FORMAT_X1R5G5B5; + break; + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_BGRA5551: + f = FORMAT_A1R5G5B5; + break; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + f = FORMAT_R5G6B5; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_BGRX8888: + f = FORMAT_X8R8G8B8; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_BGRA8888: + f = FORMAT_A8R8G8B8; + break; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + f = FORMAT_YUY2; + break; + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + f = FORMAT_UYVY; + break; + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + f = FORMAT_YV12; + break; + case DRM_FORMAT_NV21: + f = FORMAT_NV12; + break; + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + f = FORMAT_NV16; + break; + case DRM_FORMAT_P010: + f = FORMAT_P010; + break; + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_BGRA1010102: + f = FORMAT_A2R10G10B10; + break; + case DRM_FORMAT_NV12: + f = FORMAT_NV12; + break; + case DRM_FORMAT_YUV444: + f = FORMAT_YUV444; + break; + default: + break; + } + + return f; +} + +int dc_hw_init(struct vs_dc *dc) +{ + u8 i, id, panel_num, layer_num; + struct dc_hw *hw = &dc->hw; + u32 offset; + + layer_num = hw->info->layer_num; + for (i = 0; i < layer_num; i++) { + id = dc->planes[i].id; + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + hw->reg[i] = dc_plane_reg[0]; + else + hw->reg[i] = dc_plane_reg[1]; + + load_default_filter(hw, &hw->reg[i], dc->planes[i].offset); + load_rgb_to_rgb(hw, &hw->reg[i], dc->planes[i].offset, RGB2RGB); + } + + panel_num = hw->info->panel_num; + for (i = 0; i < panel_num; i++) { + offset = i << 2; + + load_rgb_to_yuv(hw, offset, RGB2YUV); + dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111); + + offset = i ? DC_CURSOR_OFFSET : 0; + dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF); + dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA); + } + + return 0; +} + +void dc_hw_disable_plane(struct vs_dc *dc, u8 id) +{ + struct dc_hw *hw = &dc->hw; + + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + dc->planes[id].offset, + PRIMARY_EN(false), PRIMARY_EN_MASK); + else + dc_set_clear(hw, DC_OVERLAY_CONFIG + dc->planes[id].offset, + OVERLAY_FB_EN(false), OVERLAY_FB_EN_MASK); +} + +static int update_cursor_size(uint32_t crtc_w) +{ + u8 size_type; + + switch (crtc_w) { + case 32: + size_type = CURSOR_SIZE_32X32; + break; + case 64: + size_type = CURSOR_SIZE_64X64; + break; + default: + size_type = CURSOR_SIZE_32X32; + break; + } + + return size_type; +} + +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr, + u32 crtc_w, u32 crtc_x, u32 crtc_y, + s32 hotspot_x, s32 hotspot_y) +{ + u32 offset, size; + + offset = id ? DC_CURSOR_OFFSET : 0; + size = update_cursor_size(crtc_w); + + dc_write(hw, DC_CURSOR_ADDRESS + offset, + dma_addr); + dc_write(hw, DC_CURSOR_LOCATION + offset, + X_LCOTION(crtc_x) | + Y_LCOTION(crtc_y)); + dc_set_clear(hw, DC_CURSOR_CONFIG + offset, + CURSOR_HOT_X(hotspot_x) | + CURSOR_HOT_y(hotspot_y) | + CURSOR_SIZE(size) | + CURSOR_VALID(1) | + CURSOR_TRIG_FETCH(1) | + CURSOR_FORMAT(CURSOR_FORMAT_A8R8G8B8), + CURSOR_HOT_X_MASK | + CURSOR_HOT_y_MASK | + CURSOR_SIZE_MASK | + CURSOR_VALID_MASK | + CURSOR_TRIG_FETCH_MASK | + CURSOR_FORMAT_MASK); +} + +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id) +{ + u32 offset = 0; + + offset = id ? DC_CURSOR_OFFSET : 0; + dc_set_clear(hw, DC_CURSOR_CONFIG + offset, CURSOR_VALID(1), CURSOR_FORMAT_MASK); +} + +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index, + u16 r, u16 g, u16 b) +{ + if (index >= hw->info->gamma_size) + return; + + hw->gamma[id].gamma[index][0] = r; + hw->gamma[id].gamma[index][1] = g; + hw->gamma[id].gamma[index][2] = b; +} + +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable) +{ + u32 value; + + if (enable) { + dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (id << 2), 0x00); + for (int i = 0; i < GAMMA_EX_SIZE; i++) { + value = hw->gamma[id].gamma[i][2] | + (hw->gamma[id].gamma[i][1] << 12); + dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (id << 2), value); + dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (id << 2), + hw->gamma[id].gamma[i][0]); + } + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), PANEL_GAMMA_EN, 0); + } else { + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (id << 2), 0, PANEL_GAMMA_EN); + } +} + +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode, + u8 encoder_type, u32 output_fmt) +{ + u32 dp_cfg, dpi_cfg, offset = id << 2; + bool is_yuv = false; + + if (encoder_type != DRM_MODE_ENCODER_DSI) { + switch (output_fmt) { + case MEDIA_BUS_FMT_RGB565_1X16: + dp_cfg = 0; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + dp_cfg = 1; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + dp_cfg = 2; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + dp_cfg = 3; + break; + case MEDIA_BUS_FMT_UYVY8_1X16: + dp_cfg = 2 << 4; + is_yuv = true; + break; + case MEDIA_BUS_FMT_YUV8_1X24: + dp_cfg = 4 << 4; + is_yuv = true; + break; + case MEDIA_BUS_FMT_UYVY10_1X20: + dp_cfg = 8 << 4; + is_yuv = true; + break; + case MEDIA_BUS_FMT_YUV10_1X30: + dp_cfg = 10 << 4; + is_yuv = true; + break; + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + dp_cfg = 12 << 4; + is_yuv = true; + break; + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + dp_cfg = 13 << 4; + is_yuv = true; + break; + default: + dp_cfg = 2; + break; + } + if (is_yuv) + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_RGB2YUV_EN, 0); + else + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_RGB2YUV_EN); + dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | DP_SELECT); + } + + if (hw->out[id] == OUT_DPI) + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT); + + switch (output_fmt) { + case MEDIA_BUS_FMT_RGB565_1X16: + dpi_cfg = 0; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + dpi_cfg = 3; + break; + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + dpi_cfg = 4; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + dpi_cfg = 5; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + dpi_cfg = 6; + break; + default: + dpi_cfg = 5; + break; + } + dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg); + + if (id == 0) + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL0_EN | TWO_PANEL_EN); + else + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, PANEL1_EN | TWO_PANEL_EN); + + dc_write(hw, DC_DISPLAY_H + offset, + H_ACTIVE_LEN(mode->hdisplay) | + H_TOTAL_LEN(mode->htotal)); + + dc_write(hw, DC_DISPLAY_H_SYNC + offset, + H_SYNC_START_LEN(mode->hsync_start) | + H_SYNC_END_LEN(mode->hsync_end) | + H_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PHSYNC ? 0 : 1) | + H_PLUS_LEN(1)); + + dc_write(hw, DC_DISPLAY_V + offset, + V_ACTIVE_LEN(mode->vdisplay) | + V_TOTAL_LEN(mode->vtotal)); + + dc_write(hw, DC_DISPLAY_V_SYNC + offset, + V_SYNC_START_LEN(mode->vsync_start) | + V_SYNC_END_LEN(mode->vsync_end) | + V_POLARITY_LEN(mode->flags & DRM_MODE_FLAG_PVSYNC ? 0 : 1) | + V_PLUS_LEN(1)); + + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, PANEL_OUTPUT_EN, 0); + dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(id), SYNC_EN); +} + +void dc_hw_disable(struct dc_hw *hw, int id) +{ + u32 offset = id << 2; + + if (hw->out[id] == OUT_DPI) + dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, DP_SELECT); + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, PANEL_OUTPUT_EN); + dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(id) | TWO_PANEL_EN); +} + +void dc_hw_enable_interrupt(struct dc_hw *hw) +{ + hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF); +} + +void dc_hw_disable_interrupt(struct dc_hw *hw) +{ + hi_write(hw, AQ_INTR_ENBL, 0); +} + +u32 dc_hw_get_interrupt(struct dc_hw *hw) +{ + return hi_read(hw, AQ_INTR_ACKNOWLEDGE); +} + +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable) +{ + u32 i, offset; + struct dc_hw *hw = &dc->hw; + u8 id, layer_num = hw->info->layer_num; + u8 panel_num = hw->info->panel_num; + + for (i = 0; i < layer_num; i++) { + id = dc->planes[i].id; + offset = dc->planes[i].offset; + if (enable) { + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, + PRIMARY_SHADOW_EN, 0); + else + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, + OVERLAY_SHADOW_EN, 0); + } else { + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, + 0, PRIMARY_SHADOW_EN); + else + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, + 0, OVERLAY_SHADOW_EN); + } + } + + for (i = 0; i < panel_num; i++) { + offset = i << 2; + if (enable) + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, PANEL_SHADOW_EN); + else + dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, PANEL_SHADOW_EN, 0); + } +} + +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id) +{ + if (out <= OUT_DP) + hw->out[id] = out; +} + +static inline u8 to_vs_yuv_color_space(u32 color_space) +{ + u8 cs; + + switch (color_space) { + case DRM_COLOR_YCBCR_BT601: + cs = COLOR_SPACE_601; + break; + case DRM_COLOR_YCBCR_BT709: + cs = COLOR_SPACE_709; + break; + case DRM_COLOR_YCBCR_BT2020: + cs = COLOR_SPACE_2020; + break; + default: + cs = COLOR_SPACE_601; + break; + } + + return cs; +} + +static inline u8 update_uv_swizzle(u32 format) +{ + u8 uv_swizzle = 0; + + switch (format) { + case DRM_FORMAT_YVYU: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV61: + uv_swizzle = 1; + break; + default: + break; + } + + return uv_swizzle; +} + +static inline u8 update_swizzle(u32 format) +{ + u8 swizzle = SWIZZLE_ARGB; + + switch (format) { + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBA1010102: + swizzle = SWIZZLE_RGBA; + break; + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_ABGR2101010: + swizzle = SWIZZLE_ABGR; + break; + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRA1010102: + swizzle = SWIZZLE_BGRA; + break; + default: + break; + } + + return swizzle; +} + +static inline u8 to_vs_rotation(unsigned int rotation) +{ + u8 rot; + + switch (rotation & DRM_MODE_REFLECT_MASK) { + case DRM_MODE_REFLECT_X: + rot = FLIP_X; + return rot; + case DRM_MODE_REFLECT_Y: + rot = FLIP_Y; + return rot; + case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y: + rot = FLIP_XY; + return rot; + default: + break; + } + + switch (rotation & DRM_MODE_ROTATE_MASK) { + case DRM_MODE_ROTATE_0: + rot = ROT_0; + break; + case DRM_MODE_ROTATE_90: + rot = ROT_90; + break; + case DRM_MODE_ROTATE_180: + rot = ROT_180; + break; + case DRM_MODE_ROTATE_270: + rot = ROT_270; + break; + default: + rot = ROT_0; + break; + } + + return rot; +} + +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format, + enum drm_color_encoding encoding, u8 id, bool is_yuv) +{ + u32 offset = dc->planes[id].offset; + struct dc_hw *hw = &dc->hw; + + if (is_yuv) { + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, + PRIMARY_YUVCLAMP_EN, PRIMARY_RGB2RGB_EN); + else + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, + OVERLAY_CLAMP_EN, OVERLAY_RGB2RGB_EN); + + switch (to_vs_yuv_color_space(encoding)) { + case COLOR_SPACE_601: + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV601_2RGB); + break; + case COLOR_SPACE_709: + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV709_2RGB); + break; + case COLOR_SPACE_2020: + load_yuv_to_rgb(hw, &hw->reg[id], offset, YUV2020_2RGB); + break; + default: + break; + } + } else { + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, + PRIMARY_RGB2RGB_EN, PRIMARY_YUVCLAMP_EN); + else + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, + OVERLAY_RGB2RGB_EN, OVERLAY_CLAMP_EN); + } +} + +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr, + struct drm_framebuffer *drm_fb, struct drm_rect *src) +{ + u32 offset = dc->planes[id].offset; + struct dc_hw *hw = &dc->hw; + + dc_write(hw, hw->reg[id].y_address + offset, dma_addr[0]); + dc_write(hw, hw->reg[id].u_address + offset, + format == DRM_FORMAT_YVU420 ? + dma_addr[2] : dma_addr[1]); + dc_write(hw, hw->reg[id].v_address + offset, + format == DRM_FORMAT_YVU420 ? + dma_addr[1] : dma_addr[2]); + dc_write(hw, hw->reg[id].y_stride + offset, drm_fb->pitches[0]); + dc_write(hw, hw->reg[id].u_stride + offset, + format == DRM_FORMAT_YVU420 ? + drm_fb->pitches[2] : drm_fb->pitches[1]); + dc_write(hw, hw->reg[id].v_stride + offset, + format == DRM_FORMAT_YVU420 ? + drm_fb->pitches[1] : drm_fb->pitches[2]); + dc_write(hw, hw->reg[id].size + offset, + FB_SIZE(drm_rect_width(src) >> 16, drm_rect_height(src) >> 16)); +} + +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding, + unsigned int rotation, bool visible, unsigned int zpos, + u8 id, u8 display_id) +{ + u32 offset = dc->planes[id].offset; + struct dc_hw *hw = &dc->hw; + + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) { + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, + PRIMARY_FORMAT(update_vs_format(format)) | + PRIMARY_UV_SWIZ(update_uv_swizzle(format)) | + PRIMARY_SWIZ(update_swizzle(format)) | + PRIMARY_TILE(DRM_FORMAT_MOD_LINEAR) | + PRIMARY_YUV_COLOR(to_vs_yuv_color_space(encoding)) | + PRIMARY_ROTATION(to_vs_rotation(rotation)), + PRIMARY_FORMAT_MASK | + PRIMARY_UV_SWIZ_MASK | + PRIMARY_SWIZ_MASK | + PRIMARY_TILE_MASK | + PRIMARY_YUV_COLOR_MASK | + PRIMARY_ROTATION_MASK | + PRIMARY_CLEAR_EN_MASK); + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, + PRIMARY_DECODER_EN(false) | + PRIMARY_EN(visible) | + PRIMARY_ZPOS(zpos) | + PRIMARY_CHANNEL(display_id), + PRIMARY_DECODER_EN_EN_MASK | + PRIMARY_EN_MASK | + PRIMARY_ZPOS_MASK | + PRIMARY_CHANNEL_MASK); + } else { + dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, + OVERLAY_FB_EN(visible) | + OVERLAY_FORMAT(update_vs_format(format)) | + OVERLAY_UV_SWIZ(update_uv_swizzle(format)) | + OVERLAY_SWIZ(update_swizzle(format)) | + OVERLAY_TILE(DRM_FORMAT_MOD_LINEAR) | + OVERLAY_YUV_COLOR(to_vs_yuv_color_space(encoding)) | + OVERLAY_ROTATION(to_vs_rotation(rotation)), + OVERLAY_DEC_EN_MASK | + OVERLAY_CLEAR_EN_MASK | + OVERLAY_FB_EN_MASK | + OVERLAY_FORMAT_MASK | + OVERLAY_UV_SWIZ_MASK | + OVERLAY_SWIZ_MASK | + OVERLAY_TILE_MASK | + OVERLAY_YUV_COLOR_MASK | + OVERLAY_ROTATION_MASK); + + dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset, + OVERLAY_LAYER_SEL(zpos) | + OVERLAY_PANEL_SEL(display_id), + OVERLAY_LAYER_SEL_MASK | + OVERLAY_PANEL_SEL_MASK); + } +} + +static u32 calc_factor(u32 src, u32 dest) +{ + u32 factor = 1 << 16; + + if (src > 1 && dest > 1) + factor = ((src - 1) << 16) / (dest - 1); + + return factor; +} + +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst, + u8 id, u8 display_id, unsigned int rotation) +{ + u32 offset = dc->planes[id].offset; + struct dc_hw *hw = &dc->hw; + + int dst_w = drm_rect_width(dst); + int dst_h = drm_rect_height(dst); + int src_w, src_h, temp; + u32 scale_factor_x; + u32 scale_factor_y; + bool enable_scale = false; + + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + + if (drm_rotation_90_or_270(rotation)) { + temp = src_w; + src_w = src_h; + src_h = temp; + } + + if (src_w != dst_w) { + scale_factor_x = calc_factor(src_w, dst_w); + enable_scale = true; + } else { + scale_factor_x = 1 << 16; + } + if (src_h != dst_h) { + scale_factor_y = calc_factor(src_h, dst_h); + enable_scale = true; + } else { + scale_factor_y = 1 << 16; + } + if (enable_scale) { + dc_write(hw, hw->reg[id].scale_factor_x + offset, scale_factor_x); + dc_write(hw, hw->reg[id].scale_factor_y + offset, scale_factor_y); + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, PRIMARY_SCALE_EN, 0); + else + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, OVERLAY_SCALE_EN, 0); + } else { + if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) + dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset, 0, PRIMARY_SCALE_EN); + else + dc_set_clear(hw, DC_OVERLAY_SCALE_CONFIG + offset, 0, OVERLAY_SCALE_EN); + } + + dc_write(hw, hw->reg[id].top_left + offset, X_POS(dst->x1) | Y_POS(dst->y1)); + dc_write(hw, hw->reg[id].bottom_right + offset, X_POS(dst->x2) | Y_POS(dst->y2)); +} + +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, + u16 pixel_blend_mode, u8 id, u8 display_id) +{ + u32 offset = dc->planes[id].offset; + struct dc_hw *hw = &dc->hw; + + dc_write(hw, hw->reg[id].src_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8)); + dc_write(hw, hw->reg[id].dst_global_color + offset, PRIMARY_ALPHA_LEN(alpha >> 8)); + switch (pixel_blend_mode) { + case DRM_MODE_BLEND_PREMULTI: + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PREMULTI); + break; + case DRM_MODE_BLEND_COVERAGE: + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_COVERAGE); + break; + case DRM_MODE_BLEND_PIXEL_NONE: + dc_write(hw, hw->reg[id].blend_config + offset, BLEND_PIXEL_NONE); + break; + default: + break; + } +} diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h new file mode 100644 index 000000000000..63d8d153f57f --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h @@ -0,0 +1,493 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_DC_HW_H__ +#define __VS_DC_HW_H__ + +#include +#include +#include + +#include "vs_type.h" + +#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x) + +#define AQ_INTR_ACKNOWLEDGE 0x0010 +#define AQ_INTR_ENBL 0x0014 +#define DC_HW_REVISION 0x0024 +#define DC_HW_CHIP_CID 0x0030 + +#define DC_REG_BASE 0x0800 +#define DC_REG_RANGE 0x2000 +#define DC_SEC_REG_OFFSET 0x100000 + +#define DC_FRAMEBUFFER_CONFIG 0x1518 +# define PRIMARY_FORMAT(x) ((x) << 26) +# define PRIMARY_FORMAT_MASK GENMASK(31, 26) +# define PRIMARY_UV_SWIZ(x) ((x) << 25) +# define PRIMARY_UV_SWIZ_MASK GENMASK(25, 25) +# define PRIMARY_SWIZ(x) ((x) << 23) +# define PRIMARY_SWIZ_MASK GENMASK(24, 23) +# define PRIMARY_SCALE_EN BIT(12) +# define PRIMARY_TILE(x) ((x) << 17) +# define PRIMARY_TILE_MASK GENMASK(21, 17) +# define PRIMARY_YUV_COLOR(x) ((x) << 14) +# define PRIMARY_YUV_COLOR_MASK GENMASK(16, 14) +# define PRIMARY_ROTATION(x) ((x) << 11) +# define PRIMARY_ROTATION_MASK GENMASK(13, 11) +# define PRIMARY_CLEAR_EN(x) ((x) << 8) +# define PRIMARY_CLEAR_EN_MASK GENMASK(8, 8) + +#define DC_FRAMEBUFFER_CONFIG_EX 0x1CC0 +# define PRIMARY_CHANNEL(x) ((x) << 19) +# define PRIMARY_CHANNEL_MASK GENMASK(19, 19) +# define PRIMARY_ZPOS(x) ((x) << 16) +# define PRIMARY_ZPOS_MASK GENMASK(18, 16) +# define PRIMARY_EN(x) ((x) << 13) +# define PRIMARY_EN_MASK GENMASK(13, 13) +# define PRIMARY_SHADOW_EN BIT(12) +# define PRIMARY_YUVCLAMP_EN BIT(8) +# define PRIMARY_RGB2RGB_EN BIT(6) +# define PRIMARY_SYNC1_EN BIT(4) +# define PRIMARY_SYNC0_EN BIT(3) +# define PRIMARY_DECODER_EN(x) ((x) << 1) +# define PRIMARY_DECODER_EN_EN_MASK GENMASK(1, 1) + +#define DC_FRAMEBUFFER_SCALE_CONFIG 0x1520 +#define DC_FRAMEBUFFER_TOP_LEFT 0x24D8 +#define X_POS(x) (x) +#define Y_POS(x) ((x) << 15) + +#define DC_FRAMEBUFFER_BOTTOM_RIGHT 0x24E0 +#define DC_FRAMEBUFFER_ADDRESS 0x1400 +#define DC_FRAMEBUFFER_U_ADDRESS 0x1530 +#define DC_FRAMEBUFFER_V_ADDRESS 0x1538 +#define DC_FRAMEBUFFER_STRIDE 0x1408 +#define DC_FRAMEBUFFER_U_STRIDE 0x1800 +#define DC_FRAMEBUFFER_V_STRIDE 0x1808 +#define DC_FRAMEBUFFER_SIZE 0x1810 +#define FB_SIZE(w, h) ((w) | ((h) << 15)) + +#define DC_FRAMEBUFFER_SCALE_FACTOR_X 0x1828 +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y 0x1830 +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX 0x1838 +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA 0x1A00 +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX 0x1A08 +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA 0x1A10 +#define DC_FRAMEBUFFER_INIT_OFFSET 0x1A20 +#define DC_FRAMEBUFFER_COLOR_KEY 0x1508 +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH 0x1510 +#define DC_FRAMEBUFFER_CLEAR_VALUE 0x1A18 +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX 0x1818 +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA 0x1820 +#define DC_FRAMEBUFFER_BG_COLOR 0x1528 +#define DC_FRAMEBUFFER_ROI_ORIGIN 0x1CB0 +#define DC_FRAMEBUFFER_ROI_SIZE 0x1CB8 +#define DC_FRAMEBUFFER_WATER_MARK 0x1CE8 +#define DC_FRAMEBUFFER_DEGAMMA_INDEX 0x1D88 +#define DC_FRAMEBUFFER_DEGAMMA_DATA 0x1D90 +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA 0x1D98 +#define DC_FRAMEBUFFER_YUVTORGB_COEF0 0x1DA0 +#define DC_FRAMEBUFFER_YUVTORGB_COEF1 0x1DA8 +#define DC_FRAMEBUFFER_YUVTORGB_COEF2 0x1DB0 +#define DC_FRAMEBUFFER_YUVTORGB_COEF3 0x1DB8 +#define DC_FRAMEBUFFER_YUVTORGB_COEF4 0x1E00 +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0 0x1E08 +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1 0x1E10 +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2 0x1E18 +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND 0x1E88 +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND 0x1E90 +#define DC_FRAMEBUFFER_RGBTORGB_COEF0 0x1E20 +#define DC_FRAMEBUFFER_RGBTORGB_COEF1 0x1E28 +#define DC_FRAMEBUFFER_RGBTORGB_COEF2 0x1E30 +#define DC_FRAMEBUFFER_RGBTORGB_COEF3 0x1E38 +#define DC_FRAMEBUFFER_RGBTORGB_COEF4 0x1E40 +#define DC_FRAMEBUFFER_BLEND_CONFIG 0x2510 +# define BLEND_PREMULTI 0x3450 +# define BLEND_COVERAGE 0x3950 +# define BLEND_PIXEL_NONE 0x3548 + +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR 0x2500 +# define PRIMARY_ALPHA_LEN(x) ((x) << 24) + +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR 0x2508 + +#define DC_OVERLAY_CONFIG 0x1540 +# define OVERLAY_SHADOW_EN BIT(31) +# define OVERLAY_CLAMP_EN BIT(30) +# define OVERLAY_RGB2RGB_EN BIT(29) +# define OVERLAY_DEC_EN(x) ((x) << 27) +# define OVERLAY_DEC_EN_MASK GENMASK(27, 27) +# define OVERLAY_CLEAR_EN(x) ((x) << 25) +# define OVERLAY_CLEAR_EN_MASK GENMASK(25, 25) +# define OVERLAY_FB_EN(x) ((x) << 24) +# define OVERLAY_FB_EN_MASK GENMASK(24, 24) +# define OVERLAY_FORMAT(x) ((x) << 16) +# define OVERLAY_FORMAT_MASK GENMASK(21, 16) +# define OVERLAY_UV_SWIZ(x) ((x) << 15) +# define OVERLAY_UV_SWIZ_MASK GENMASK(15, 15) +# define OVERLAY_SWIZ(x) ((x) << 13) +# define OVERLAY_SWIZ_MASK GENMASK(14, 13) +# define OVERLAY_TILE(x) ((x) << 8) +# define OVERLAY_TILE_MASK GENMASK(12, 8) +# define OVERLAY_YUV_COLOR(x) ((x) << 5) +# define OVERLAY_YUV_COLOR_MASK GENMASK(7, 5) +# define OVERLAY_ROTATION(x) ((x) << 2) +# define OVERLAY_ROTATION_MASK GENMASK(4, 2) + +#define DC_OVERLAY_CONFIG_EX 0x2540 +# define OVERLAY_LAYER_SEL(x) ((x) << 0) +# define OVERLAY_LAYER_SEL_MASK GENMASK(2, 0) +# define OVERLAY_PANEL_SEL(x) ((x) << 3) +# define OVERLAY_PANEL_SEL_MASK GENMASK(3, 3) + +#define DC_OVERLAY_SCALE_CONFIG 0x1C00 +# define OVERLAY_SCALE_EN BIT(8) + +#define DC_OVERLAY_BLEND_CONFIG 0x1580 +#define DC_OVERLAY_TOP_LEFT 0x1640 +#define DC_OVERLAY_BOTTOM_RIGHT 0x1680 +#define DC_OVERLAY_ADDRESS 0x15C0 +#define DC_OVERLAY_U_ADDRESS 0x1840 +#define DC_OVERLAY_V_ADDRESS 0x1880 +#define DC_OVERLAY_STRIDE 0x1600 +#define DC_OVERLAY_U_STRIDE 0x18C0 +#define DC_OVERLAY_V_STRIDE 0x1900 +#define DC_OVERLAY_SIZE 0x17C0 +#define DC_OVERLAY_SCALE_FACTOR_X 0x1A40 +#define DC_OVERLAY_SCALE_FACTOR_Y 0x1A80 +#define DC_OVERLAY_H_FILTER_COEF_INDEX 0x1AC0 +#define DC_OVERLAY_H_FILTER_COEF_DATA 0x1B00 +#define DC_OVERLAY_V_FILTER_COEF_INDEX 0x1B40 +#define DC_OVERLAY_V_FILTER_COEF_DATA 0x1B80 +#define DC_OVERLAY_INIT_OFFSET 0x1BC0 +#define DC_OVERLAY_COLOR_KEY 0x1740 +#define DC_OVERLAY_COLOR_KEY_HIGH 0x1780 +#define DC_OVERLAY_CLEAR_VALUE 0x1940 +#define DC_OVERLAY_COLOR_TABLE_INDEX 0x1980 +#define DC_OVERLAY_COLOR_TABLE_DATA 0x19C0 +#define DC_OVERLAY_SRC_GLOBAL_COLOR 0x16C0 +# define OVERLAY_ALPHA_LEN(x) ((x) << 24) + +#define DC_OVERLAY_DST_GLOBAL_COLOR 0x1700 +#define DC_OVERLAY_ROI_ORIGIN 0x1D00 +#define DC_OVERLAY_ROI_SIZE 0x1D40 +#define DC_OVERLAY_WATER_MARK 0x1DC0 +#define DC_OVERLAY_DEGAMMA_INDEX 0x2200 +#define DC_OVERLAY_DEGAMMA_DATA 0x2240 +#define DC_OVERLAY_DEGAMMA_EX_DATA 0x2280 +#define DC_OVERLAY_YUVTORGB_COEF0 0x1EC0 +#define DC_OVERLAY_YUVTORGB_COEF1 0x1F00 +#define DC_OVERLAY_YUVTORGB_COEF2 0x1F40 +#define DC_OVERLAY_YUVTORGB_COEF3 0x1F80 +#define DC_OVERLAY_YUVTORGB_COEF4 0x1FC0 +#define DC_OVERLAY_YUVTORGB_COEFD0 0x2000 +#define DC_OVERLAY_YUVTORGB_COEFD1 0x2040 +#define DC_OVERLAY_YUVTORGB_COEFD2 0x2080 +#define DC_OVERLAY_Y_CLAMP_BOUND 0x22C0 +#define DC_OVERLAY_UV_CLAMP_BOUND 0x2300 +#define DC_OVERLAY_RGBTORGB_COEF0 0x20C0 +#define DC_OVERLAY_RGBTORGB_COEF1 0x2100 +#define DC_OVERLAY_RGBTORGB_COEF2 0x2140 +#define DC_OVERLAY_RGBTORGB_COEF3 0x2180 +#define DC_OVERLAY_RGBTORGB_COEF4 0x21C0 + +#define DC_CURSOR_CONFIG 0x1468 +# define CURSOR_HOT_X(x) ((x) << 16) +# define CURSOR_HOT_X_MASK GENMASK(23, 16) +# define CURSOR_HOT_y(x) ((x) << 8) +# define CURSOR_HOT_y_MASK GENMASK(15, 8) +# define CURSOR_SIZE(x) ((x) << 5) +# define CURSOR_SIZE_MASK GENMASK(7, 5) +# define CURSOR_VALID(x) ((x) << 3) +# define CURSOR_VALID_MASK GENMASK(3, 3) +# define CURSOR_TRIG_FETCH(x) ((x) << 2) +# define CURSOR_TRIG_FETCH_MASK GENMASK(2, 2) +# define CURSOR_FORMAT(x) ((x) << 0) +# define CURSOR_FORMAT_MASK GENMASK(1, 0) +# define CURSOR_FORMAT_DISABLE 0 +# define CURSOR_FORMAT_MARK 1 +# define CURSOR_FORMAT_A8R8G8B8 2 + +#define DC_CURSOR_ADDRESS 0x146C +#define DC_CURSOR_LOCATION 0x1470 +# define X_LCOTION(x) (x) +# define Y_LCOTION(x) ((x) << 16) + +#define DC_CURSOR_BACKGROUND 0x1474 +#define DC_CURSOR_FOREGROUND 0x1478 +#define DC_CURSOR_CLK_GATING 0x1484 +#define DC_CURSOR_CONFIG_EX 0x24E8 +#define DC_CURSOR_OFFSET 0x1080 + +#define DC_DISPLAY_DITHER_CONFIG 0x1410 +#define DC_DISPLAY_PANEL_CONFIG 0x1418 +# define PANEL_RGB2YUV_EN BIT(16) +# define PANEL_GAMMA_EN BIT(13) +# define PANEL_OUTPUT_EN BIT(12) + +#define DC_DISPLAY_PANEL_CONFIG_EX 0x2518 +# define PANEL_SHADOW_EN BIT(0) + +#define DC_DISPLAY_DITHER_TABLE_LOW 0x1420 +#define DC_DISPLAY_DITHER_TABLE_HIGH 0x1428 +#define DC_DISPLAY_H 0x1430 +# define H_ACTIVE_LEN(x) (x) +# define H_TOTAL_LEN(x) ((x) << 16) + +#define DC_DISPLAY_H_SYNC 0x1438 +# define H_SYNC_START_LEN(x) (x) +# define H_SYNC_END_LEN(x) ((x) << 15) +# define H_PLUS_LEN(x) ((x) << 30) +# define H_POLARITY_LEN(x) ((x) << 31) + +#define DC_DISPLAY_V 0x1440 +# define V_ACTIVE_LEN(x) (x) +# define V_TOTAL_LEN(x) ((x) << 16) + +#define DC_DISPLAY_V_SYNC 0x1448 +# define V_SYNC_START_LEN(x) (x) +# define V_SYNC_END_LEN(x) ((x) << 15) +# define V_PLUS_LEN(x) ((x) << 30) +# define V_POLARITY_LEN(x) ((x) << 31) + +#define DC_DISPLAY_CURRENT_LOCATION 0x1450 +#define DC_DISPLAY_GAMMA_INDEX 0x1458 +#define DC_DISPLAY_GAMMA_DATA 0x1460 +#define DC_DISPLAY_INT 0x147C +#define DC_DISPLAY_INT_ENABLE 0x1480 +#define DC_DISPLAY_DBI_CONFIG 0x1488 +#define DC_DISPLAY_GENERAL_CONFIG 0x14B0 +#define DC_DISPLAY_DPI_CONFIG 0x14B8 +#define DC_DISPLAY_PANEL_START 0x1CCC +# define PANEL0_EN BIT(0) +# define PANEL1_EN BIT(1) +# define TWO_PANEL_EN BIT(2) +# define SYNC_EN BIT(3) + +#define DC_DISPLAY_DEBUG_COUNTER_SELECT 0x14D0 +#define DC_DISPLAY_DEBUG_COUNTER_VALUE 0x14D8 +#define DC_DISPLAY_DP_CONFIG 0x1CD0 +# define DP_SELECT BIT(3) + +#define DC_DISPLAY_GAMMA_EX_INDEX 0x1CF0 +#define DC_DISPLAY_GAMMA_EX_DATA 0x1CF8 +#define DC_DISPLAY_GAMMA_EX_ONE_DATA 0x1D80 +#define DC_DISPLAY_RGBTOYUV_COEF0 0x1E48 +#define DC_DISPLAY_RGBTOYUV_COEF1 0x1E50 +#define DC_DISPLAY_RGBTOYUV_COEF2 0x1E58 +#define DC_DISPLAY_RGBTOYUV_COEF3 0x1E60 +#define DC_DISPLAY_RGBTOYUV_COEF4 0x1E68 +#define DC_DISPLAY_RGBTOYUV_COEFD0 0x1E70 +#define DC_DISPLAY_RGBTOYUV_COEFD1 0x1E78 +#define DC_DISPLAY_RGBTOYUV_COEFD2 0x1E80 + +#define DC_CLK_GATTING 0x1A28 +#define DC_QOS_CONFIG 0x1A38 + +#define DC_TRANSPARENCY_OPAQUE 0x00 +#define DC_TRANSPARENCY_KEY 0x02 +#define DC_DISPLAY_DITHERTABLE_LOW 0x7B48F3C0 +#define DC_DISPLAY_DITHERTABLE_HIGH 0x596AD1E2 + +#define DC_TILE_MODE4X4 0x15 + +#define GAMMA_SIZE 256 +#define GAMMA_EX_SIZE 300 +#define DEGAMMA_SIZE 260 + +#define RGB_TO_RGB_TABLE_SIZE 9 +#define YUV_TO_RGB_TABLE_SIZE 16 +#define RGB_TO_YUV_TABLE_SIZE 12 + +#define DC_LAYER_NUM 6 +#define DC_DISPLAY_NUM 2 +#define DC_CURSOR_NUM 2 + +enum dc_hw_plane_id { + PRIMARY_PLANE_0, + OVERLAY_PLANE_0, + OVERLAY_PLANE_1, + PRIMARY_PLANE_1, + OVERLAY_PLANE_2, + OVERLAY_PLANE_3, + CURSOR_PLANE_0, + CURSOR_PLANE_1, + PLANE_NUM +}; + +enum dc_hw_color_format { + FORMAT_X4R4G4B4, + FORMAT_A4R4G4B4, + FORMAT_X1R5G5B5, + FORMAT_A1R5G5B5, + FORMAT_R5G6B5, + FORMAT_X8R8G8B8, + FORMAT_A8R8G8B8, + FORMAT_YUY2, + FORMAT_UYVY, + FORMAT_INDEX8, + FORMAT_MONOCHROME, + FORMAT_YV12 = 0xf, + FORMAT_A8, + FORMAT_NV12, + FORMAT_NV16, + FORMAT_RG16, + FORMAT_R8, + FORMAT_NV12_10BIT, + FORMAT_A2R10G10B10, + FORMAT_NV16_10BIT, + FORMAT_INDEX1, + FORMAT_INDEX2, + FORMAT_INDEX4, + FORMAT_P010, + FORMAT_YUV444, + FORMAT_YUV444_10BIT, +}; + +enum dc_hw_yuv_color_space { + COLOR_SPACE_601 = 0, + COLOR_SPACE_709 = 1, + COLOR_SPACE_2020 = 3, +}; + +enum dc_hw_rotation { + ROT_0 = 0, + ROT_90 = 4, + ROT_180 = 5, + ROT_270 = 6, + FLIP_X = 1, + FLIP_Y = 2, + FLIP_XY = 3, +}; + +enum dc_hw_swizzle { + SWIZZLE_ARGB = 0, + SWIZZLE_RGBA, + SWIZZLE_ABGR, + SWIZZLE_BGRA, +}; + +enum dc_hw_out { + OUT_DPI, + OUT_DP, +}; + +enum dc_hw_cursor_size { + CURSOR_SIZE_32X32 = 0, + CURSOR_SIZE_64X64, +}; + +struct dc_hw_plane_reg { + u32 y_address; + u32 u_address; + u32 v_address; + u32 y_stride; + u32 u_stride; + u32 v_stride; + u32 size; + u32 top_left; + u32 bottom_right; + u32 scale_factor_x; + u32 scale_factor_y; + u32 h_filter_coef_index; + u32 h_filter_coef_data; + u32 v_filter_coef_index; + u32 v_filter_coef_data; + u32 init_offset; + u32 color_key; + u32 color_key_high; + u32 clear_value; + u32 color_table_index; + u32 color_table_data; + u32 scale_config; + u32 water_mark; + u32 degamma_index; + u32 degamma_data; + u32 degamma_ex_data; + u32 src_global_color; + u32 dst_global_color; + u32 blend_config; + u32 roi_origin; + u32 roi_size; + u32 yuv_to_rgb_coef0; + u32 yuv_to_rgb_coef1; + u32 yuv_to_rgb_coef2; + u32 yuv_to_rgb_coef3; + u32 yuv_to_rgb_coef4; + u32 yuv_to_rgb_coefd0; + u32 yuv_to_rgb_coefd1; + u32 yuv_to_rgb_coefd2; + u32 y_clamp_bound; + u32 uv_clamp_bound; + u32 rgb_to_rgb_coef0; + u32 rgb_to_rgb_coef1; + u32 rgb_to_rgb_coef2; + u32 rgb_to_rgb_coef3; + u32 rgb_to_rgb_coef4; +}; + +struct dc_hw_gamma { + u16 gamma[GAMMA_EX_SIZE][3]; +}; + +struct dc_hw_read { + u32 reg; + u32 value; +}; + +struct dc_hw { + enum dc_hw_out out[DC_DISPLAY_NUM]; + void *hi_base; + void *reg_base; + struct dc_hw_plane_reg reg[DC_LAYER_NUM]; + + struct dc_hw_gamma gamma[DC_DISPLAY_NUM]; + struct vs_dc_info *info; +}; + +struct vs_dc_plane { + enum dc_hw_plane_id id; + u32 offset; +}; + +struct vs_dc { + struct vs_crtc *crtc[DC_DISPLAY_NUM]; + struct dc_hw hw; + + struct vs_dc_plane planes[PLANE_NUM]; +}; + +int dc_hw_init(struct vs_dc *dc); +void dc_hw_disable_plane(struct vs_dc *dc, u8 id); +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, dma_addr_t dma_addr, + u32 crtc_w, u32 crtc_x, u32 crtc_y, + s32 hotspot_x, int32_t hotspot_y); +void dc_hw_disable_cursor(struct dc_hw *hw, u8 id); +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index, + u16 r, u16 g, u16 b); +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable); +void dc_hw_enable(struct dc_hw *hw, int id, struct drm_display_mode *mode, + u8 encoder_type, u32 output_fmt); +void dc_hw_disable(struct dc_hw *hw, int id); +void dc_hw_enable_interrupt(struct dc_hw *hw); +void dc_hw_disable_interrupt(struct dc_hw *hw); +u32 dc_hw_get_interrupt(struct dc_hw *hw); +void dc_hw_enable_shadow_register(struct vs_dc *dc, bool enable); +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id); +void dc_hw_commit(struct dc_hw *hw); +void plane_hw_update_format_colorspace(struct vs_dc *dc, u32 format, + enum drm_color_encoding encoding, u8 id, bool is_yuv); +void plane_hw_update_address(struct vs_dc *dc, u8 id, u32 format, dma_addr_t *dma_addr, + struct drm_framebuffer *drm_fb, struct drm_rect *src); +void plane_hw_update_format(struct vs_dc *dc, u32 format, enum drm_color_encoding encoding, + unsigned int rotation, bool visible, unsigned int zpos, + u8 id, u8 display_id); +void plane_hw_update_scale(struct vs_dc *dc, struct drm_rect *src, struct drm_rect *dst, + u8 id, u8 display_id, unsigned int rotation); +void plane_hw_update_blend(struct vs_dc *dc, u16 alpha, u16 pixel_blend_mode, + u8 id, u8 display_id); + +#endif /* __VS_DC_HW_H__ */ diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h new file mode 100644 index 000000000000..30ccc2eda48b --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_type.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_TYPE_H__ +#define __VS_TYPE_H__ + +#include + +struct vs_plane_primary_info { + u8 id; + unsigned int num_formats; + const u32 *formats; + u8 num_modifiers; + const u64 *modifiers; + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + unsigned int rotation; + unsigned int color_encoding; + + int min_scale; /* 16.16 fixed point */ + int max_scale; /* 16.16 fixed point */ + + u8 zpos; + +}; + +struct vs_plane_overlay_info { + u8 id; + unsigned int num_formats; + const u32 *formats; + u8 num_modifiers; + const u64 *modifiers; + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + unsigned int rotation; + unsigned int color_encoding; + + int min_scale; /* 16.16 fixed point */ + int max_scale; /* 16.16 fixed point */ + + u8 zpos; + +}; + +struct vs_plane_cursor_info { + u8 id; + unsigned int num_formats; + const u32 *formats; + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + u8 zpos; + +}; + +struct vs_dc_info { + const char *name; + + u8 panel_num; + + /* planes */ + u8 layer_num; + u8 primary_num; + u8 overlay_num; + u8 cursor_num; + const struct vs_plane_primary_info *primary; + const struct vs_plane_overlay_info *overlay; + const struct vs_plane_cursor_info *cursor; + + /* 0 means no gamma LUT */ + u16 gamma_size; + u8 gamma_bits; + + u16 pitch_alignment; +}; + +#endif /* __VS_TYPE_H__ */ From patchwork Tue May 21 10:58:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668827 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DD5C8C25B79 for ; Tue, 21 May 2024 02:58:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6EC1110E051; Tue, 21 May 2024 02:58:46 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2139.outbound.protection.partner.outlook.cn [139.219.17.139]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3057B10E051 for ; Tue, 21 May 2024 02:58:36 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=HXzKzeY9BZklV87c1b5xBD0l8wjagp303AR+vaigQwaaZfUnkADHbaFfkgRwmO172FZbA88VJ4ekagxEBOCf6I5dc6h6TGRprcZvrASI+LH2qjsn6H53LjzFRiYBvIu3Nr8qk6ZNdXX7vEOzHTLkdObSPMBf0DEejuLK18d61gqkQPE24dRdFw1qYZEziqHM2b4idHpQnU3hGcwsriusu+byjvqW8dtQz0yjrvs2375XmTR1VDyeEIcUVtINBi7/siL9DEUyj6V2ZG/FUuIJKivCC7H0T4iphrLKouxs72JgfqU7vAFQ7WsoVrRg+OgGDnnW49+86WRxXOM2lt1H0Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=W++pRmxoPDdJvPI/iKzomS2ZqHbsM40diYc7PmtnUCw=; b=gSGIfEYif7lUR03QqYKRCCggKzyTg9H2UmxLcGdsLg11h4gEsoplEVIb+aNmguvvrptXHk7uafr6tFxXTNy7NeHEmyZS1wdg92v4pciXUUiqxlz4rAAmrXnAn6ZbagbDPW3Hk7hKKuyrlTMEUFU4t6rpSuKT9f0oW2l2mg0u/Uug3X6IF0s6L4hzfzgG0phwcURUSevRqF4gqM2gUPWQThDcsht2oDFoh66z3EPR5leVkR03mMM8lUqKP9NCwVkoINxl5gLaoxnuHbXgeQZ9ao/28DGVdci70/RhvlJYc+7ZO90pa4YVEWiZ0CQP/4h+tDKTw2J9AUS4MqYASjMmtg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1255.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:19::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.36; Tue, 21 May 2024 02:58:31 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:31 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 05/10] drm/vs: add vs mode config init Date: Tue, 21 May 2024 18:58:12 +0800 Message-Id: <20240521105817.3301-6-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1255:EE_ X-MS-Office365-Filtering-Correlation-Id: 7b81af45-4ec3-4454-7cab-08dc7941e580 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; ARA:13230031|366007|41320700004|1800799015|7416005|52116005|921011|38350700005; X-Microsoft-Antispam-Message-Info: DyL5NCnOY0pZ9jUs94HsZMB4AfKxVdxVpf8lhra7JK0lKpMzKW0gajEeMhloBbVe4jOyWrnt8RZUnd4v+WoJgiclocmLDPNJe9ysD61QWofka7/r4L0wYo4orBAJcjqLvtHzYzSaSx6qIKnBkcv5LN1YPrN2At6jFpb4ROJlm68b4sqJbcSynBrMpD7S8uPZC8vNCjw/NVN4tP+btbmo6fGlhrCx0HY9a721W4WRlh1jo+FKxKWkZOOrVTvXrOFteHPNru9DVQNucgiOcfDqSz8j0rDyK5PiJcu3Hy70J03p4jxKBQ+nj4OYtIlsYseCQO/ToTrECxR4MgJv2W410shRtW4POGkq2m33JpF5kZhspBwOnBiOCNVgnNhmitN5c7De8/BMV+JkcwoH3vGDdJjGNLi9k0QPOlJYxl7A4EFqcePZSa07lQv+sHR1vCCS/HTUMyEZCiJhPsLNUcYmqj4BFTjsaXtqft0kwhRB+tNaWQWKE5iJaLaPbG3wwLzjwDcjtiLlBE5iYoCjSYhKyv/3P0Q1STbpIy9RsZsCxnl+Jy9nuSmiJcvySWUMWGZrtzJf/m2jddSKMEAY6Vt8t2PIxL2avI5vTrW1GI6qEB4qd3MyYeR4gh21aOlwGnGKyq34k7tLnWF9JipKaMeemQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(366007)(41320700004)(1800799015)(7416005)(52116005)(921011)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: DEG9ouOA7UQ5Kh72liSD6AWqlrqZHGRjmQ2BYBpxJF/OYjpKW8tfIwsABGl6RWSSG0ueXFNj3eYLSyfwkks2nx1VD6R0vnMxMck3GUtFhzdCD1/Zv3An97gM8xgs1ZqqytQ6x3OnanE/IoVNsMs+/jtrn3SLM+enxtkz7wmLr8xIt60lH8oMY+aOJSTrhKlMkUOVpk3eyxl476KJmb4QuiBO/izOQxKJUfUkvN7fjmUklYa2OT1ISCe3Lgjv4mZM9KkwtQPUHa7Wg9G0evAMYsWjKGZgykQLnmNjle7rDDbY0GAuKUrSfYzss5G4dkqCxKy9vA+vQJaM2FBPB4TOmYMMtFvHxPF71kyOiEEQPkGeJ1dBnF48RwJi0CGdS6Ktxwt795SXBPkoq8vxBdfstTDO5tWbIAZpa0yTfNQsZCEkP4B3qLio7Q0Vba8LvXeBfc2Qjw0HTE4Xgo0+vWu1jwwM9oB7CqQotqmKjwNei/owOAOHaEVlAUYyacrvRlJqMFf0TImoevP4/r7b400ZKZkNMWtkvSk8Oo1/+6LvMQSl7qoiYZR/3dyufFoFBncUDj4TMo7Y1ZubGMrvXTbHPFR7GEdVAL9K3kJxUA/+9ZvH9Y0+6RvqtCsVxV7hQ3nZu0ZBIwktwylhX6hM+Ok6RCoPSywSET1eU5kLANSYOc5ZqgeSer6g+w68OjKfVSZi1wfKMCeTVxceKLUZrFtBkrVVmuytvQCz6LB3bEFm2J3BDSvGzTcxQJQlRpzJYNnzW62fnNrq9rugjcy9pA2MJHoBFeLwJQSjHXpSYMIImz8EF48xfnYbKkzw3kuEbVMWfI/XZ7rj1PjQTMUNdzcx2fdyRLYr3jmUFdgcPuAcft0TyU/I0OhxS1kliA2fts18NsFM6OoYIILO0Fpjx6qZ46oWr8Ft+TIFhgQ/ZHhljFexPk2Cmq+l8L+DA22VdbybB5/asGvjx3bunP2hJvf6sMqH8kxZPunJBc0NtXvInhyGQJp8RfFBoxv9bRBsQxWjotby6kwsnfQ6170zrhfaJjtMi8mfO8rqF1s2bDnt/dW9OsxgSggbcvbS4VN1joRZf06sUsK3nZoTQHoAW9UZtxgsl/816WkG+9V5lKkfnEGb9mSuW7XQBXeHVFEzVQqQq9pwQuDIVgp6/SbO/r7zMsIhX329YB5Tk+5Vy1UaDsTj9JePtjRT1X9SevCpj93+t0hTI9melr4txQXT8CxL3huoUKnJcNNqm7u0vXEkXh3Pn1sP6o5jltPhWl/D9dxPKE5vqrF70Mujszn6Ah5V8bGDlwKiD4SCd/ep3t7jSr6jIUcZ9WfDNiMVRZQFzC9laP7QqSsHDdxmjzExfD5ui/Xge2NJioFXHXX3cuL7d6D81yDTkie+129puYvkWtwU6QhlD9hhd4tR364XVb3lhSOxMnaF3K4RCyL5cImOdENzJBr5sYGMdbO4bdftIEf3tzkCl25hkaReEJ1cGM/nw8GtcP0rd+XAYoZcZCPiTM33OvhdGCrnIPLAufojQnGSWarvmnm+ZuOj9AIrZOj646o2kP4CEeU4s5lgB3vpp9DhtmI49OT4XDCSyXecyMVbMM+t0uN4oij6aovAk3yNBw== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7b81af45-4ec3-4454-7cab-08dc7941e580 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:31.1042 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: a2v5yBDiymup/cVmt+I+9Z7lh1mcXel3zGYfkkCk1Fws14b0IBazE6jTkZwhxSf7ma8pZz21gvGk4LEhN+/MHCmM+g3LVOB5uO1Eq+fEbHo= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1255 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add vs mode config base api Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_modeset.c | 36 ++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_modeset.h | 10 +++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.c create mode 100644 drivers/gpu/drm/verisilicon/vs_modeset.h diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 7da54b259940..536091f37378 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -vs_drm-objs := vs_dc_hw.o +vs_drm-objs := vs_dc_hw.o \ + vs_modeset.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.c b/drivers/gpu/drm/verisilicon/vs_modeset.c new file mode 100644 index 000000000000..c71fe0d32504 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_modeset.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ +#include +#include +#include + +#include "vs_modeset.h" + +static const struct drm_mode_config_funcs vs_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static struct drm_mode_config_helper_funcs vs_mode_config_helpers = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +}; + +void vs_mode_config_init(struct drm_device *dev) +{ + int ret; + + ret = drmm_mode_config_init(dev); + if (ret) + return; + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + + dev->mode_config.funcs = &vs_mode_config_funcs; + dev->mode_config.helper_private = &vs_mode_config_helpers; +} diff --git a/drivers/gpu/drm/verisilicon/vs_modeset.h b/drivers/gpu/drm/verisilicon/vs_modeset.h new file mode 100644 index 000000000000..bd04f81d2ad2 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_modeset.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_MODESET_H__ +#define __VS_MODESET_H__ + +void vs_mode_config_init(struct drm_device *dev); +#endif /* __VS_FB_H__ */ From patchwork Tue May 21 10:58:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668825 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AD1D6C25B7B for ; Tue, 21 May 2024 02:58:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D024410E4F7; Tue, 21 May 2024 02:58:44 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2106.outbound.protection.partner.outlook.cn [139.219.17.106]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2D69810E465 for ; Tue, 21 May 2024 02:58:38 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=i4k37yqLATooloVufU9q1vQdK/5p06x6JQggI7qoEYdhHFpE+MooIr8IyaWaBaSe/PmwXzkW3IM1yY05QgQRuZbbNb5QXpUuOciDoeQmiRe+hrTBd4qA0nNNbkpS+fHAQ3aHNH6Ot70lCFPedPL6jJQw08pJGNBbneKC1s/AzJUg5CAzQdR9KMfociS8/kUx+gjHlbJEP4GJqqeB02W6AgqfPZxBni3oF5ezrH1Zw/B54QUggvixrhs7QFcO02UktdaSvOzTZghSet5W5XWBlkFsqO8r7Os77qQ/R7k4I9rLhW9bkcpeY/PAgSrhZ2VQG9C1J48zb2YroDe1ERkr5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=JkFPBug7fAvc3Hc9QKfOTgfWdoMaeaBBl7zHyK5APLc=; b=JnvjWNaawuUrynWaDUzemP/N+3maA3cqI6DrxMCBx/p39NiEgN17IGIdIHvgC8u5tJf5hdUBFp0JFzf7tOu4EsMbrkzoGRIhpOMwi2zzoYsmbzlcU0BDeklN3UIZHjy4cag1Arh7lNZmNytI8JFLPeOlI0ILkWC9xcyLdUjqoemW/DJV0kqww8J9pjbZmZ80dBy8fOsHBQesylsYsR4vmHM7HE1p6ljCdNUpGynR10h5lgwUVR3051p73Rep6al5/WsXpQPHTQ61IsSxKPx8LlwHhvOO2tShzPr6PecEq65BZsFyR1L3vXTMbngZe2L8i5zmC/J4KVFBbtmc1fPpnA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1128.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.44; Tue, 21 May 2024 02:58:32 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:32 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 06/10] drm/vs: add vs plane api Date: Tue, 21 May 2024 18:58:13 +0800 Message-Id: <20240521105817.3301-7-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1128:EE_ X-MS-Office365-Filtering-Correlation-Id: 4aca330b-e8c7-4baa-8519-08dc7941e629 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RbBW4JOV0jDrrEqtZaHmNAB+e8CJmD1bwJl/lkI9W0g4a4150689rR9LkwKatrbZ7519OZIMw+SHdZzJ5n+8Bz24o/hyGCbDxNxDpmq6bisqjrkwOJF7KS9b6HFPKkJunqD4eJRU9wNZ3sqC1lVPixscEq862iCZlWvjEIG1Tc9jmcUfckRn5CpSAKq0C6QAJTcPLF3UOb3sw8Fh7oxkLVoKENxde7UaPiTmFyR3xVrnyM9lUiubkdIsgg2tcZlH/MHboxp3SLI0onDq8sovILtoh0zJ8+MmXnRbnm4WouUlyt10SpVr+zXRPLqn+6tv39LLx9JGS1LYXfyMKeu4aHxDvLWEnTD0r4w1hSQJJ4js1cGZ5hD43JTu16NIaG/46AMFyvRq+zQHklUuok/ALAA6nFixdybfuVlrLiUO16zGadkfhv5f+kgTWiV2OL5udK7PmJHBbobrXDhMbEToU/4dWwjIiM9SlIF+gO5ZzdcMh5mqqHitBc2KkLCe2EGw7j49wrTvARFDejZpVIOn2UbIcrRVJiqLGP+XJaIjrg3z6DDvqejWYOBrI7CZBIsmzF6sj97zS6c2FjCrDoLL0Jb70gfwK9XGQncOGIFEy2sK1/5Aj0/S1strvn346HFc2izLnOztBJGtwGJkV5s7ZA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(41320700004)(52116005)(7416005)(1800799015)(366007)(38350700005)(921011); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: ntqESfK8k82UsGJbZMJdNvs+7DR8OBt771VVlOdaoq8qoRazrhnDD3BkmTW2zghNMspWdVNNdEEeoCKx5uxWE6w6UgUD25RfXokBmDCwNbKFqMHCFItfO3yAVbhGqYcpE6vkU2GorFzt1/AWrGHm4PRtQB349/+zdbqjHNXut2PngsTLAdLfjcCex/T5q5wI2o/6RjG9SBpfB4ly3Z0uPq8VaAnW1LrykiEw8cDxyMRitVRpWh+rXruYK2kdp35ja+LghEZAicuKjkni2518xSAiXvq7MhmIRIZ+WK1DRBbkmACzd1mzNqJRxxT8YHf6/Xs6Ok+z2j5M/UB8x/e9w0M/wixCOXh1IkD5m8PUkClreJuNdd8C6+V6XbEljWG5zdrhuE4BhZBxC/rjNMXW1AMML1xRLuk1dGb3Kiq8vxCQftZlOnY8Z9IpynheGh21OUe9Rme7AQS4Iozw7jVow/M3rY7uFCeR/hqatPle8t8UnhCxx4G08J9ZrtS2q3yFMuQHsZ5YVTvNl/gEKduJhjaQ3Z+AKeX7fJPYAfFHeObHv7Au9BUE6aHdVxIofVcce330BOfISWDjoe2UCOTrIsEJCAMm+nKHLEWCmM9wkgjBlaKCGVDvynQzMO0C/zCVBZwu1OxdWZqsvjnWQIYUmVMDxUZy5LfLEFiPjtF0xMJsBylZ1rPibBE6cjCBSYcMrjipHE2AteS+WtILTPQsdiQXGpY7Op5iFEGHEvvDUqIQuvtccOLT4E5I6U5JM3IXgsjEEGqysRz09zASlVXTGIOoDbVGu12YphsIRptqN6mMgENM8qVuMCtA1GR6KsLWvvV7qkKcFaqwoi3M8NSF6FP6Hturt13BiVG4X5SnYGCor2De6L8Kdc1EloZW3TY8bIBuNEz0ie7C3Q5GX4I8UOVZoDWXcPLrMPF3YW1P+IntQbs6bO1p4TyD9g/r2A1+ZJYeUf0mw7zlLjf7GxPw3svdzOu1R1LDPADBsxcuyPPN/efipjW74btbTZIxRuaenFOagYAcpQYD6+QFe5Me7HepW/11GPBl8C2VJQx5GL6w1oqdgXrFLo4AeEmPqIE6cym4MaegIPpVK772FzT5C0htrqEt2Jox96a4bYOKqRFFbNXQt4nVK984iQ6+Jf0J4Y+TjkHJeb9/2WnhU0wQ9pvvkmuaNrxO6f+Ed1zarLSKOn1XyuCWS63k/5h+AKOF8sb1OJ6+NRwIUT97r5mX34aIiqA6A2AcNYIfod3oi/QJE3WDAzMO10ULvrj52Zo82ph+CLuyJmirx+fuxLyHUnE+76CYKuTX6ruY7W0Z7Pd202aUpnWf90Z3jEVR/YZhPTQZiTBGoj/sKk6o7d697irFWITKW+vL6Pd8yNM9C5G1fN8pfixIx9No+g2QuDsUavGg3QUZ8c/Q1Z8L1RJz9widP++6iVN8krjLda2Fb3QktSPPrWdgjqNHRAUHyL3ZXHwnWdK/V1mOwCZx7e1urmcE0em53xaWrrtJXnYsYqbIoKVrpS9sPYNlIsI4GfTFwkcG/t9gXg3FNd9xfu0mZROzduwYApzKIAshTGGK8vJPsbqzJcz4z5Sry6RBUVQkg90Z/UnBtCzw4/1PavEJfA== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4aca330b-e8c7-4baa-8519-08dc7941e629 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:32.2439 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: SRCA/kseaVHpeCRkixBBNO74yRxIRWw/LZfFLrj2kXJbopAXpYkWluw6jCM+Y3X2g9LnZzUC9mPCUWRb6oGgr7mmcXeVVzHUAlpEMiMeE6I= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1128 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add plane funs and helper funs add vs drm common struct and funs Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++ drivers/gpu/drm/verisilicon/vs_plane.c | 487 +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h | 26 ++ 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 536091f37378..1c593b943261 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 vs_drm-objs := vs_dc_hw.o \ - vs_modeset.o + vs_modeset.o \ + vs_plane.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h new file mode 100644 index 000000000000..d9f6efa7c8f9 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_drv.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_DRV_H__ +#define __VS_DRV_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vs_dc_hw.h" + +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ +struct vs_drm_device { + struct drm_device base; + unsigned int pitch_alignment; + /* clocks */ + unsigned int clk_count; + struct clk_bulk_data *clks; + struct reset_control *rsts; + struct vs_dc dc; + int irq; +}; + +static inline struct vs_drm_device * +to_vs_drm_private(const struct drm_device *dev) +{ + return container_of(dev, struct vs_drm_device, base); +} + +struct vs_crtc_state { + struct drm_crtc_state base; + + u32 output_fmt; + u8 encoder_type; + u8 bpp; +}; + +struct vs_crtc { + struct drm_crtc base; + struct device *dev; +}; + +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc) +{ + u8 panel_num = dc->hw.info->panel_num; + u32 index = drm_crtc_index(crtc); + int i; + + for (i = 0; i < panel_num; i++) { + if (index == dc->crtc[i]->base.index) + return i; + } + + return 0; +} + +static inline struct vs_crtc_state * +to_vs_crtc_state(struct drm_crtc_state *state) +{ + return container_of(state, struct vs_crtc_state, base); +} + +struct vs_plane_state { + struct drm_plane_state base; + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; +}; + +struct vs_plane { + struct drm_plane base; + u8 id; +}; + +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane) +{ + return container_of(plane, struct vs_plane, base); +} + +static inline struct vs_plane_state * +to_vs_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct vs_plane_state, base); +} + +#endif /* __VS_DRV_H__ */ diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c new file mode 100644 index 000000000000..653f0ce72ed6 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vs_plane.h" + +static void vs_plane_atomic_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state); + + __drm_atomic_helper_plane_destroy_state(state); + kfree(vs_plane_state); +} + +static void vs_plane_reset(struct drm_plane *plane) +{ + struct vs_plane_state *state; + struct vs_plane *vs_plane = to_vs_plane(plane); + + if (plane->state) + vs_plane_atomic_destroy_state(plane, plane->state); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return; + + state->base.zpos = vs_plane->id; + __drm_atomic_helper_plane_reset(plane, &state->base); +} + +static struct drm_plane_state * +vs_plane_atomic_duplicate_state(struct drm_plane *plane) +{ + struct vs_plane_state *state; + + if (WARN_ON(!plane->state)) + return NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + + return &state->base; +} + +static bool vs_format_mod_supported(struct drm_plane *plane, + u32 format, + u64 modifier) +{ + int i; + + /* We always have to allow these modifiers: + * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers. + * 2. Not passing any modifiers is the same as explicitly passing INVALID. + */ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + /* Check that the modifier is on the list of the plane's supported modifiers. */ + for (i = 0; i < plane->modifier_count; i++) { + if (modifier == plane->modifiers[i]) + break; + } + + if (i == plane->modifier_count) + return false; + + return true; +} + +const struct drm_plane_funcs vs_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = vs_plane_reset, + .atomic_duplicate_state = vs_plane_atomic_duplicate_state, + .atomic_destroy_state = vs_plane_atomic_destroy_state, + .format_mod_supported = vs_format_mod_supported, +}; + +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb) +{ + const struct drm_format_info *info; + + if (!fb) + return 0; + + info = drm_format_info(fb->format->format); + if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES) + return 0; + + return info->num_planes; +} + +static bool vs_dc_mod_supported(const u64 *info_modifiers, u64 modifier) +{ + const u64 *mods; + + if (!info_modifiers) + return false; + + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) { + if (*mods == modifier) + return true; + } + + return false; +} + +static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_primary_info *primary_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + for (i = 0; i < dc->hw.info->primary_num; i++) { + primary_info = (struct vs_plane_primary_info *)&dc->hw.info->primary[i]; + if (primary_info->id == to_vs_plane(plane)->id) + break; + } + + primary_info = &dc->hw.info->primary[i]; + + if (fb->width < primary_info->min_width || + fb->width > primary_info->max_width || + fb->height < primary_info->min_height || + fb->height > primary_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) { + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); + return -EINVAL; + } + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + primary_info->min_scale, + primary_info->max_scale, + true, true); +} + +static int vs_overlay_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_overlay_info *overlay_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + + for (i = 0; i < dc->hw.info->overlay_num; i++) { + overlay_info = (struct vs_plane_overlay_info *)&dc->hw.info->overlay[i]; + if (overlay_info->id == to_vs_plane(plane)->id) + break; + } + + overlay_info = &dc->hw.info->overlay[i]; + + if (fb->width < overlay_info->min_width || + fb->width > overlay_info->max_width || + fb->height < overlay_info->min_height || + fb->height > overlay_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) { + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); + return -EINVAL; +} + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + overlay_info->min_scale, + overlay_info->max_scale, + true, true); +} + +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_cursor_info *cursor_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + + for (i = 0; i < dc->hw.info->cursor_num; i++) { + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i]; + if (cursor_info->id == to_vs_plane(plane)->id) + break; + } + + cursor_info = &dc->hw.info->cursor[i]; + + if (fb->width < cursor_info->min_width || + fb->width > cursor_info->max_width || + fb->height < cursor_info->min_height || + fb->height > cursor_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true, true); +} + +static void vs_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + + unsigned char i, num_planes, display_id, id; + u32 format; + bool is_yuv; + struct vs_plane *vs_plane = to_vs_plane(plane); + struct vs_plane_state *plane_state = to_vs_plane_state(new_state); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + + if (!new_state->fb || !new_state->crtc) + return; + + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state); + + num_planes = vs_get_plane_number(new_state->fb); + + for (i = 0; i < num_planes; i++) { + dma_addr_t dma_addr; + + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, i); + plane_state->dma_addr[i] = dma_addr; + } + + display_id = to_vs_display_id(dc, new_state->crtc); + format = new_state->fb->format->format; + is_yuv = new_state->fb->format->is_yuv; + id = vs_plane->id; + + plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv); + if (new_state->visible) + plane_hw_update_address(dc, id, format, plane_state->dma_addr, + new_state->fb, &new_state->src); + plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation, + new_state->visible, new_state->zpos, id, display_id); + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id, + display_id, new_state->rotation); + plane_hw_update_blend(dc, new_state->alpha, new_state->pixel_blend_mode, + id, display_id); +} + +static void vs_cursor_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, + plane); + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, + plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + unsigned char display_id; + u32 crtc_w, crtc_x, crtc_y; + s32 hotspot_x, hotspot_y; + dma_addr_t dma_addr; + + display_id = to_vs_display_id(dc, new_state->crtc); + + if (!new_state->fb || !new_state->crtc) + return; + + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, new_state); + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0); + crtc_w = new_state->crtc_w; + + if (new_state->crtc_x > 0) { + crtc_x = new_state->crtc_x; + hotspot_x = 0; + } else { + hotspot_x = -new_state->crtc_x; + crtc_x = 0; + } + if (new_state->crtc_y > 0) { + crtc_y = new_state->crtc_y; + hotspot_y = 0; + } else { + hotspot_y = -new_state->crtc_y; + crtc_y = 0; + } + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x, + crtc_y, hotspot_x, hotspot_y); +} + +static void vs_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct vs_plane *vs_plane = to_vs_plane(plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + + dc_hw_disable_plane(dc, vs_plane->id); +} + +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + unsigned char display_id; + + display_id = to_vs_display_id(dc, old_state->crtc); + dc_hw_disable_cursor(&dc->hw, display_id); +} + +const struct drm_plane_helper_funcs primary_plane_helpers = { + .atomic_check = vs_primary_plane_atomic_check, + .atomic_update = vs_plane_atomic_update, + .atomic_disable = vs_plane_atomic_disable, +}; + +const struct drm_plane_helper_funcs overlay_plane_helpers = { + .atomic_check = vs_overlay_plane_atomic_check, + .atomic_update = vs_plane_atomic_update, + .atomic_disable = vs_plane_atomic_disable, +}; + +const struct drm_plane_helper_funcs cursor_plane_helpers = { + .atomic_check = vs_cursor_plane_atomic_check, + .atomic_update = vs_cursor_plane_atomic_update, + .atomic_disable = vs_cursor_plane_atomic_disable, +}; + +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, + struct vs_plane_primary_info *info, + unsigned int layer_num, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + info->modifiers, DRM_PLANE_TYPE_PRIMARY, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &primary_plane_helpers); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + if (info->color_encoding) { + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return NULL; + } + + if (info->rotation) { + ret = drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + info->rotation); + if (ret) + return NULL; + } + + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); + if (ret) + return NULL; + + return plane; +} + +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, + struct vs_plane_overlay_info *info, + unsigned int layer_num, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + info->modifiers, DRM_PLANE_TYPE_OVERLAY, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &overlay_plane_helpers); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + if (info->color_encoding) { + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return NULL; + } + + if (info->rotation) { + ret = drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + info->rotation); + if (ret) + return NULL; + } + + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); + if (ret) + return NULL; + + return plane; +} + +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, + struct vs_plane_cursor_info *info, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + NULL, DRM_PLANE_TYPE_CURSOR, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &cursor_plane_helpers); + + ret = drm_plane_create_zpos_immutable_property(&plane->base, info->zpos); + if (ret) + return NULL; + + return plane; +} diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h new file mode 100644 index 000000000000..0416146226a8 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_PLANE_H__ +#define __VS_PLANE_H__ + +#include + +#include "vs_drv.h" + +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, + struct vs_plane_primary_info *info, + unsigned int layer_num, + unsigned int possible_crtcs); + +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, + struct vs_plane_overlay_info *info, + unsigned int layer_num, + unsigned int possible_crtcs); + +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, + struct vs_plane_cursor_info *info, + unsigned int possible_crtcs); +#endif /* __VS_PLANE_H__ */ From patchwork Tue May 21 10:58:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668828 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 940DCC25B7B for ; Tue, 21 May 2024 02:58:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2579610E52C; Tue, 21 May 2024 02:58:47 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2106.outbound.protection.partner.outlook.cn [139.219.17.106]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7E70F10E228 for ; Tue, 21 May 2024 02:58:42 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Poyf+Cu75sIK8pyVfbXwJ8VN1zgJhhA4f3hO7dI8keNDkEzm6T24Jjx/A9apgS9tIRajWE0wRRQ9h5IO3SIuShIKfNb+lFyEWvltv7Te13hejGaDBTxF5UP30t0gF1xmLN3eWsaUuGC4fB2QzMYpLKV1/ILW0HqsHkB5XGqgaNUuh/XwEtIEmOqFd50Q9YCgrZ/vWlIZhphkFI3pCFONqQ4+S1mD6fkmlTH1u1Zgkb9lL/WZYURedi2T+Z0u4tF0Molt/yyPP8nQhOcd4HBABM8k2xLtBeL7FzMh8vvDcpQUgi3LMiCLKQqioOqWenOpLWX1ooCfSE3LGrf0sYGAVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=oFrygtI1BCGEewVkP9fmPC8AE5wzJFZ2jbPDfi3E2f0=; b=C/WIKgrandmjF6yJGhztuDOp5f+YyH5QfVkfavRsUR3IVyc4SYkMukiRPY71zLYhxDBq4rnoUwfRJDzIere9o0yZEiK42XutedkN89bHxxc6Ci4NQyuNFVrIQumne8dc+IoVwOtjVLj6zD5rTFI0VOaJEHMiJHdw6HxIv3VJcjk9HKvw5LlHFYFW5cpyEXmV3ScG4LmGmox1yF5qyzZapMpFU/9+Dt7p4/pQxiIx9mm/DSIaw+U1AeLe36le7TRfxqnIoR+haBxXMlG9SFsGI010qJa8N4jS9OwkJ6N4TnWKqerErK5Kqnkjxoe9FSmfk53vkaHR2AlmbxljjmLBxg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1128.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.44; Tue, 21 May 2024 02:58:33 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:33 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 07/10] drm/vs: add ctrc fun Date: Tue, 21 May 2024 18:58:14 +0800 Message-Id: <20240521105817.3301-8-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1128:EE_ X-MS-Office365-Filtering-Correlation-Id: 5f8686af-1db6-41ac-4c08-08dc7941e6d8 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: sYJmhHDbFhxdupu8bGo/sSEEV7VhfLSEIY/V5uAzuZ7BppLsvEkde90V5TBfhsAi/Fp1S4qDMz3AX904osCjC6ajIwRrRREvjEew9zuKV7OJZcP51DgQ+8AC/V2TBSlcVclab1oMi4Ra13wPK2f1Gu/tCjYke8YGWY6LgL3VmbsfHqWnhj3Hr5u2XBrybVWFUYuCNjgjg3/gQqdxs+sdK5uzLX3d3mblSOYN8xm1waEIOnmc0xUog6RbMHeIgRIKq92AYB93p4BFu6HzrwjGbm8EjEqMAquXMk4dETqi51MJpevqWYumdcml5Ib4anFQe5K8GVv+hZw1g67M8rcVL3fXRE68tJ1/1DAIhrvcwxGCAxpkdkn/XFaQ72GMID1ORE2jb4gzMo+Zu+YmNbvalaofriUboI99PwZFKvVv2+f2kujnGJqYSnmNAC0gToFMd1XkhyiGunnSkZFfG3KHsfyYlsiuVKtkVusr+zIf56Uq4vDxVwX0CGj9S5sn2QD8w84swyKbEXxHNmzGF5Bydxb4x0hnvymPnGg81iApHRJFbGn7VodGqKMgArHxDZ0sbzRY105q/RRjI9DxkL/Z7jMJCe4TaArrgpziEYD+hGcc9wGFiZYvLAazmQBXFCYuGQWE8v9QPInxGUtScAKPgw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(41320700004)(52116005)(7416005)(1800799015)(366007)(38350700005)(921011); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: pUXU3+OSC5pFeweOB3HNTRsyOclwSXskNZZ2zHNZDtb9AfrJpZmTiyQgtoNw9HT8C8zlRppI6bk64zmwpisJYBYgJqGpTKhLoU0a+cyRl4lMDoHg9jeHX3heWpXPSYT+Yb6ir8TSTZ0RD9LI5wFUPvg/hzJcqOKj9UCVsxIK2C1KLCBCWMGtzpag2AKkMGaD34oxJIANVl5RUFrUmOjClcbA1RE1R06nXg7FVnHG6DBeysSxoPNpWulxOulOUPNJu/RYUjIBUEOe9aMvmLENIvv+c+xnoZLzZ++6cOVX7/gmc6/YEjf9oLxqm3rxgmvOA5eFaO/DAixhfuStJa0k0HAsZNAJiMe0JWmDdaqoc/ZQOauCN9+pUNdLHZyK4mcaXmMhvgZHq0NHtB+2IIWGvoazL0vUfnYhFS0hKGNCVQjX5hsflN2mI1qXoNH5TpjtnS7rKdzJ7SkZJc2t8DtT1YgGF3qhAPMlHajNkOH/MOsAabF4L14fnE7XsrGW/LJDYrXivylAWf+n6RYXPr2uiLHkKsEKS1DEmvv3cN5FZ8pSAq/4C6bfWm+2yc7TQDPLf9u9CIpTSnmgxPTsdtiNm20n1qfhb/OkfBizwF5I0GTsFP2wIhX39VvPmUoX6/gQV9/miAG90wBG52ml+OYaETXUrIbFA2fxes9HZ2MgqaoIfeYG98NRWTvS49fp8H8IVDSeX5wriGcK2mByAp7aQpsQ1uoh7n15M12oAKTOFrl5VEO06lrPUn8sv3SYFYvKD4xaKn0mUWBNo2apXJXNyElpEiaKYP07HsEaZ9ryVIQ7E34NsufCgE9cYMDKt1/2fhC25Ab6EjdcEt2ETeS1nWN8Jq2k8IWq+25G9bR6Se9kQiVdEXfVpKAcOoJqNIgMi1oF9XSZpHTB/vv2CZi0DZL/q5qH7K1KBYO42h3q9S3r1uFzwDLOh2TpVJUuWIDD3sBmXm9Neu5wjZ3xVFQnpPsYFrTCCpzBaqO6zSoQjzK0qZ4JB73Avd4k1f5aiRbENL/MrU92w7TaSj/c8k0GcuGUNHKp5hZTNonGIhn1HBBeTryulJxiTNhBHgIXZYC6xZSPL0+Mz0Ah9QGJ7Cp3li3cRNLNau82oZwWFp+LrWfB8uZVINFNxQh2AXBzvYjjMf5jnZsjWUkBSDI/Lnl8Xwdrk3S844X8c37kqt7L+Gn9P+r3I9Rim63VrdsdmIkBFieP71SJeG1E28NTDCpiQfEhsGo149wdRrjjgl+/LPQ62oj2towjFEXlGeVyN8Pn77J5I6bvm3Y8h8dCuOPXECBbS8byZXhuIjGpxUWfhfMuJbpahMNVNI2bMft5V28Z3u9E/KKM88k8vGAhDKzmxxp68CKoJtnrGcl+gYg0XUx/21UKf21+5HfgVX9/LnnA8gn2Ld0q9J3XFE2VSExDhlyN0j6qbtJV4vy3dGgiVxKMP3Oqnk15PNvTzEFZcDD6e0005nKkKr9pYczdi4INFMUUN2DnHx+VIukcuOaMhpQMHWcdmQ3KQbW43nBUf2HzDkpUE/LBBdzjsTKwyiAmPA1CDDCoioC5TKOoUPqrKs83sj3ZKPn0649Fh4jd8VTWp1fPVsZ7lMrKyjvMRm7BVA== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5f8686af-1db6-41ac-4c08-08dc7941e6d8 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:33.3375 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: UyMIkt9DJLTPYoL7mjzNUV0tu4Az8vAuA28BECwnkH79NjgtRNKa2C1KfFH+6FYx7RUEpH82XRpsMuNi/X9VdBBZdouTuo9YraNunHIGhIc= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1128 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add crtc funs and helper funs Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_crtc.c | 241 ++++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_crtc.h | 17 ++ 3 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 1c593b943261..26a43ca0fd36 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -2,6 +2,7 @@ vs_drm-objs := vs_dc_hw.o \ vs_modeset.o \ - vs_plane.o + vs_plane.o \ + vs_crtc.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c new file mode 100644 index 000000000000..ea7640a63c28 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + * + */ +#include +#include +#include +#include +#include + +#include "vs_crtc.h" + +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(to_vs_crtc_state(state)); +} + +static void vs_crtc_reset(struct drm_crtc *crtc) +{ + struct vs_crtc_state *state; + + if (crtc->state) + vs_crtc_atomic_destroy_state(crtc, crtc->state); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return; + + __drm_atomic_helper_crtc_reset(crtc, &state->base); +} + +static struct drm_crtc_state * +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc) +{ + struct vs_crtc_state *old_state; + struct vs_crtc_state *state; + + if (!crtc->state) + return NULL; + + old_state = to_vs_crtc_state(crtc->state); + + state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + return &state->base; +} + +static int vs_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + + dc_hw_enable_interrupt(&dc->hw); + + return 0; +} + +static void vs_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + + dc_hw_disable_interrupt(&dc->hw); +} + +static const struct drm_crtc_funcs vs_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = vs_crtc_reset, + .atomic_duplicate_state = vs_crtc_atomic_duplicate_state, + .atomic_destroy_state = vs_crtc_atomic_destroy_state, + .enable_vblank = vs_crtc_enable_vblank, + .disable_vblank = vs_crtc_disable_vblank, +}; + +static void vs_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + + struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + int id; + + id = to_vs_display_id(dc, crtc); + if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) { + dc_hw_set_out(&dc->hw, OUT_DPI, id); + clk_set_rate(priv->clks[7].clk, mode->clock * 1000); + clk_set_parent(priv->clks[5].clk, priv->clks[7].clk); + } else { + dc_hw_set_out(&dc->hw, OUT_DP, id); + clk_set_parent(priv->clks[4].clk, priv->clks[6].clk); + } + + dc_hw_enable(&dc->hw, id, mode, crtc_state->encoder_type, crtc_state->output_fmt); + + enable_irq(priv->irq); + + drm_crtc_vblank_on(crtc); +} + +static void vs_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + int id; + + drm_crtc_vblank_off(crtc); + + disable_irq(priv->irq); + + id = to_vs_display_id(dc, crtc); + dc_hw_disable(&dc->hw, id); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +static void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc, + struct drm_color_lut *lut, unsigned int size) +{ + u16 i, r, g, b; + u8 bits, id; + + if (size != dc->hw.info->gamma_size) { + drm_err(crtc->dev, "gamma size does not match!\n"); + return; + } + + id = to_vs_display_id(dc, crtc); + + bits = dc->hw.info->gamma_bits; + for (i = 0; i < size; i++) { + r = drm_color_lut_extract(lut[i].red, bits); + g = drm_color_lut_extract(lut[i].green, bits); + b = drm_color_lut_extract(lut[i].blue, bits); + dc_hw_update_gamma(&dc->hw, id, i, r, g, b); + + if (i >= dc->hw.info->gamma_size) + return; + + dc->hw.gamma[id].gamma[i][0] = r; + dc->hw.gamma[id].gamma[i][1] = g; + dc->hw.gamma[id].gamma[i][2] = b; + } +} + +static void vs_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, + crtc); + + struct drm_property_blob *blob = new_state->gamma_lut; + struct drm_color_lut *lut; + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + u8 id; + + id = to_vs_display_id(dc, crtc); + if (new_state->color_mgmt_changed) { + if (blob && blob->length) { + lut = blob->data; + vs_dc_set_gamma(dc, crtc, lut, + blob->length / sizeof(*lut)); + dc_hw_enable_gamma(&dc->hw, id, true); + } else { + dc_hw_enable_gamma(&dc->hw, id, false); + } + } +} + +static void vs_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_pending_vblank_event *event = crtc->state->event; + struct vs_drm_device *priv = to_vs_drm_private(crtc->dev); + struct vs_dc *dc = &priv->dc; + + dc_hw_enable_shadow_register(dc, false); + + if (event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_arm_vblank_event(crtc, event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } + + dc_hw_enable_shadow_register(dc, true); +} + +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = { + .atomic_check = drm_crtc_helper_atomic_check, + .atomic_enable = vs_crtc_atomic_enable, + .atomic_disable = vs_crtc_atomic_disable, + .atomic_begin = vs_crtc_atomic_begin, + .atomic_flush = vs_crtc_atomic_flush, +}; + +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev, + struct vs_dc_info *info) +{ + struct vs_crtc *crtc; + int ret; + + if (!info) + return NULL; + + crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base, NULL, + NULL, &vs_crtc_funcs, + info->name ? info->name : NULL); + + drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs); + + if (info->gamma_size) { + ret = drm_mode_crtc_set_gamma_size(&crtc->base, + info->gamma_size); + if (ret) + return NULL; + + drm_crtc_enable_color_mgmt(&crtc->base, 0, false, + info->gamma_size); + } + + return crtc; +} diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h new file mode 100644 index 000000000000..b1e588bb780d --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_CRTC_H__ +#define __VS_CRTC_H__ + +#include +#include + +#include "vs_drv.h" + +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev, + struct vs_dc_info *info); + +#endif /* __VS_CRTC_H__ */ From patchwork Tue May 21 10:58:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 243C8C25B77 for ; Tue, 21 May 2024 02:58:52 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9C65410E465; Tue, 21 May 2024 02:58:48 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2106.outbound.protection.partner.outlook.cn [139.219.17.106]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5908B10E465 for ; Tue, 21 May 2024 02:58:43 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fdklX/9wIhq8thQvTsZpCEUGRrWZdQL5nNKAwcO6RsSAQGE5BuO34wcYmmSwC6i7HfIHKpAoHsGFO4pO/EaoyaDO8egz5o6aBS0QiN4a7TWe4MM9FSAch7RWoaG3gu5mubnlCmJaTYEw9w9K9IWjLdRvjvsN7uzg/zuFKqKNcSwhcLJXyFqjEaW1n51irCPxYw0W1Mb6fKkBQcsmly8KHBBOwKN8gepS1XoN3lHFCI7ZmVIGjrHxFtXalXrxqX/OgHp4/5od8Hu/3dJjOx5V8QssgnSLh7vmxlFYVach2tmtb1aMKCVyZLoBQuRTV0qMV7B/uRmEs1NV7Fmmz5ieZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=WtKFCKRO5L1v4IcU4Rq0x1MMrsUrK41w+oVQOWZBCYI=; b=I05sfMRETfvd7irj1DI2ZpXCiL+D+buMB0x8uikdB1sTF0vcng+lS6ISVT7Ofe7S8/meMzxoBPqoCMJikJPBgaufPCVUDhDCLQ2DjZqyfQA8hf402a8kRDyf6hDW93Z4N7SU7SxmzOZhiNwPusLQPKwlL0x9JRJ0XtYQAy8WP3yw/KZATjWWMlo41ByqEH+Ng2uZ52XkXPSrIWpCGgy/T++kngCSpR0VrLBcPNsJxgQ7Lc3tvvwfl/nLqpKzvQOofHgtbtespGBuUy1lrsrhcji+23ZA76dg12QiHB8ZNvmik47wkUHaLl03S4rEc0pXBrJUU12S8E2/ULTgU8pVfw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1128.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.44; Tue, 21 May 2024 02:58:34 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:34 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 08/10] drm/vs: add vs drm master driver Date: Tue, 21 May 2024 18:58:15 +0800 Message-Id: <20240521105817.3301-9-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1128:EE_ X-MS-Office365-Filtering-Correlation-Id: fd5de063-1dd6-4507-84e6-08dc7941e784 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: p6HOkAaU80PZzU2zIenjNFBYe+GVh6t8c+Wa7QUZCguVmGtaBp/5a3W32Aa9ZM1Wr3x2G2QwavHEOVqjDVKicFlTHf7fogKDXalkYF8d2S2qN8GtNSkSx87ZPg3xvscNswPbCm9DvxZrTh3W2f+hnTFksinDCLJqpFQJ3EctiZwaobJkv9xQOw8nBTEL9LR2OPl9YRLmwo8f+EUD+IOVdfIwITsJhlN1zafzj0Js+tLMI56X7j56U4LUsAXgXk2+VLwjmshVWmRtStWxklp3ouCckAPiPvhi0WlzLUMXtDiMV8Wi5SRa5LObOUQrEjJykBHyY3/UKytvHE2RULKNUPsNPjPeFU2dMVv5uoUH0/XpZFhKe3T4ao2LMfkF9UyCajmwjcok8pyCLIHF9agZmZfZ4rCLniyNzmEpZ1RXXxE+EBgIsU583M0VySZeqaJksKjlwdASuM1sbNHJ+LKRh0p5XCTHldWItFeawcFuftIDsWvsFSPlORZAYK/pgzmrI4//VGJYg2igWQrdXcKtvUKntX451EtSI0QcvZ+DTpUX3yTOUSTCqvIN9PXJpu5XL7g2VjLgQoRGfMH9b8Y5BPlftihzkvzLV1rwFnHN6Ub2e7oQ/AfIoAye+fgzbIGJ6UKViwNdUcEehJI3FT9z+A== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(41320700004)(52116005)(7416005)(1800799015)(366007)(38350700005)(921011); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: BSRIFqIUGGCbJ6wv5N8Rgflys62TyF23aLhHl8A0Rv0r000Erbnv67GoPM/9gFREeWl7ABm4bxp56CaKjbA/9JgyDk+9jVnqY+C8Dvfm96yc0eK8UUydJy0O5ic5znYT+6HBrN/Pm8lqBaCwOe8bxF9cpLUAz1T/3nW/nPR1elZlqytyLVjaqSbxEY7efld763NGXzw+u7dODmW+ndOq7HAISNh40Q+cHPtUUExbNwUu3A3ZwDPRN1x7+BbXt1ws9KswVrGsBlTnN+z9Bq9LOHM0jvkBXq/6hgvn4iTmAUX09PS5Hu7jU2UES+EJ0AcFOHKCknAfKpNFojMNfM92KCe67X1VIqwY3GicmsEXB4RC/7OAbAFNMXk+W+25u1Pp4APp6tDnIIqVAgPc6mJanVnDjG+BkB1b6elRoPWEno30ijxMsfedBrVRRQsSUsur83Ga13aADRW5XNBoKv9LfWkEWrLfcliqg/z10vvAPwVtrEbPDivuRDQoU4sNt3DjOk/Xjs4GMSDrMhnSt/FhVLk0VCc0lf8/ecDAtjjET5yaYTljZWdJ5l2WDtkiOMdHQDdSyR7Ht6BRScUwyY2xAtB3WuUVeCMrif8KGlPuoM6A/aoYWLZawAn07zzZYhfXXr4onkzFK0tk752bNkU9C2QUblgvmap2r9Sv31oyuKqdY46zuebLpTRlOuF0Ka/yb5xbWJmFqZTxfevgw/e3g8+eYFjbMSBdG55k9/KPp97D4f680suaw/mJChSWnIHA1bnF/JeyctL7SuOIOX52k60ez45LRsVvgqAAUjss+kVj+I9dmGdbdOTqQMN8ALGWCQCvLq7WcNSY6QOR9YuxXxgoQHc7AGfpi2eURGtLV+jfqasySw7jipLSL2ovgYz8AygFuVinDdt71SRXwiStPUGlxLlyXIFN1xfPMHBNrgx7/tymRajd0qIoMsrgn0equQYPfNMrVjdcTsHUPE45QdDQTo0T89pE5MqR8NS4wWBUtoFPP0taWJHNc1h6JJ2FuWh4A2q9wafbHOpKSsXq+4ZRJHp4KIPV7wCz38U3smzvrtzl/9O0oXa5+98fPSBzUvoNNqtBZfxNfggdLzGa4R6U6e1X6yY8nZABGjQnIQ5hYK8sxi1imLMrx2HyaqIdh+J9d0ZaZIdxZ6hjIUYYFhdREGnmJO6MFcbZkwDFsFVd1WMXmjOGG8pwtSmipdK5rANbdElWTayaN+r/gcTfyIhe2njylI2ZgckLsEqHTNrRQiMYRlKwAzKI4Bk6GHeYhLkrzRVH3pYHWMz17298oag9olkDu9dxJP3DKNVIu3Vk9WsCjrb+oa7NILiQcadiACl3Kvc+/DUSGXns7p2hGYsCxTP6RDB10AHRnf6pXSVh2Tax7+zYZEnfPQuB8VqQwIpUlmdMLQghTCuJ0j5GXdP0QI3H9ppdwh/wLLc3QwRP4rAhbOvjwiJn9MjIPwBP3q1XGg92Ycyf7FCrGbwUUKtdm/36eqAl1rewSPaKgqV0F8jxRMjtTVu3hOD/Mm1wls+wl3z1+ybLG+qTknFfOCPtjewsEe4rMiTYb+NrtHygZUvi9qdoVejkYh+R6gqUffK32jpZXvOLlqTDIiL9RQ== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: fd5de063-1dd6-4507-84e6-08dc7941e784 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:34.5329 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: TGJ4ojovCHPyfK4H2bBLym7wHjErTk2FmR4bFJGkyissZf70DUt2VqunkMy9N+W0UdhGpjDrLpXXc4eKu+fUueWJgfMI56XmojmqvOexRzk= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1128 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" Add vs DRM master driver for JH7110 SoC ADD DMA GEM driver Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_drv.c | 718 +++++++++++++++++++++++++++ 2 files changed, 720 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.c diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 26a43ca0fd36..88a07a308e31 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -3,6 +3,7 @@ vs_drm-objs := vs_dc_hw.o \ vs_modeset.o \ vs_plane.o \ - vs_crtc.o + vs_crtc.o \ + vs_drv.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c new file mode 100644 index 000000000000..c22fd2199fe2 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_drv.c @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vs_drv.h" +#include "vs_crtc.h" +#include "vs_plane.h" +#include "vs_modeset.h" + +#define DRV_NAME "verisilicon" +#define DRV_DESC "Verisilicon DRM driver" +#define DRV_DATE "20230516" +#define DRV_MAJOR 1 +#define DRV_MINOR 0 + +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + +static const u32 primary_overlay_format[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_XBGR4444, + DRM_FORMAT_RGBX4444, + DRM_FORMAT_BGRX4444, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ABGR4444, + DRM_FORMAT_RGBA4444, + DRM_FORMAT_BGRA4444, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_BGRX5551, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_RGBA1010102, + DRM_FORMAT_BGRA1010102, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_YVU420, + DRM_FORMAT_YUV420, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, + DRM_FORMAT_NV61, + DRM_FORMAT_P010, +}; + +static const u32 cursor_formats[] = { + DRM_FORMAT_ARGB8888 +}; + +static const u64 format_modifier[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 secondary_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const struct vs_plane_primary_info dc_hw_planes_primary[2] = { + { + .id = PRIMARY_PLANE_0, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(format_modifier), + .modifiers = format_modifier, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = FRAC_16_16(1, 3), + .max_scale = FRAC_16_16(10, 1), + .rotation = DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | + DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 0, + }, + { + .id = PRIMARY_PLANE_1, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(format_modifier), + .modifiers = format_modifier, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = FRAC_16_16(1, 3), + .max_scale = FRAC_16_16(10, 1), + .rotation = DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | + DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 3, + }, +}; + +static const struct vs_plane_overlay_info dc_hw_planes_overlay[4] = { + { + .id = OVERLAY_PLANE_0, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(format_modifier), + .modifiers = format_modifier, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = FRAC_16_16(1, 3), + .max_scale = FRAC_16_16(10, 1), + .rotation = DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | + DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 1, + }, + { + .id = OVERLAY_PLANE_1, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers), + .modifiers = secondary_format_modifiers, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .rotation = 0, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 2, + }, + { + .id = OVERLAY_PLANE_2, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(format_modifier), + .modifiers = format_modifier, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = FRAC_16_16(1, 3), + .max_scale = FRAC_16_16(10, 1), + .rotation = DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | + DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 4, + }, + { + .id = OVERLAY_PLANE_3, + .num_formats = ARRAY_SIZE(primary_overlay_format), + .formats = primary_overlay_format, + .num_modifiers = ARRAY_SIZE(secondary_format_modifiers), + .modifiers = secondary_format_modifiers, + .min_width = 0, + .min_height = 0, + .max_width = 4096, + .max_height = 4096, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .rotation = 0, + .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) | BIT(DRM_COLOR_YCBCR_BT2020), + .zpos = 5, + }, +}; + +static const struct vs_plane_cursor_info dc_hw_planes_cursor[2] = { + { + .id = CURSOR_PLANE_0, + .num_formats = ARRAY_SIZE(cursor_formats), + .formats = cursor_formats, + .min_width = 32, + .min_height = 32, + .max_width = 64, + .max_height = 64, + .zpos = 255, + }, + { + .id = CURSOR_PLANE_1, + .num_formats = ARRAY_SIZE(cursor_formats), + .formats = cursor_formats, + .min_width = 32, + .min_height = 32, + .max_width = 64, + .max_height = 64, + .zpos = 255, + }, +}; + +static const struct vs_dc_info dc8200_info = { + .name = "DC8200", + .panel_num = 2, + .primary_num = 2, + .overlay_num = 4, + .cursor_num = 2, + .primary = dc_hw_planes_primary, + .overlay = dc_hw_planes_overlay, + .cursor = dc_hw_planes_cursor, + .layer_num = 6, + .gamma_size = GAMMA_EX_SIZE, + .gamma_bits = 12, + .pitch_alignment = 128, +}; + +static int vs_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct vs_drm_device *priv = to_vs_drm_private(dev); + unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + + args->pitch = ALIGN(pitch, priv->pitch_alignment); + return drm_gem_dma_dumb_create_internal(file, dev, args); +} + +DEFINE_DRM_GEM_FOPS(vs_drm_fops); + +static struct drm_driver vs_drm_driver = { + .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, + + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vs_gem_dumb_create), + + .fops = &vs_drm_fops, + .name = DRV_NAME, + .desc = DRV_DESC, + .date = DRV_DATE, + .major = DRV_MAJOR, + .minor = DRV_MINOR, +}; + +static irqreturn_t vs_dc_isr(int irq, void *data) +{ + struct vs_drm_device *priv = data; + struct vs_dc *dc = &priv->dc; + struct vs_dc_info *dc_info = dc->hw.info; + u32 i; + + dc_hw_get_interrupt(&dc->hw); + + for (i = 0; i < dc_info->panel_num; i++) + drm_crtc_handle_vblank(&dc->crtc[i]->base); + + return IRQ_HANDLED; +} + +static int vs_drm_device_init_res(struct vs_drm_device *priv) +{ + struct device *dev = priv->base.dev; + struct platform_device *pdev = to_platform_device(dev); + int ret; + struct vs_dc *dc; + + dc = &priv->dc; + dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dc->hw.hi_base)) + return PTR_ERR(dc->hw.hi_base); + + dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(dc->hw.reg_base)) + return PTR_ERR(dc->hw.reg_base); + + dc->hw.info = (struct vs_dc_info *)of_device_get_match_data(dev); + + ret = devm_clk_bulk_get_all(dev, &priv->clks); + if (ret < 0) { + dev_err(dev, "can't get vout clock, ret=%d\n", ret); + return ret; + } + priv->clk_count = ret; + + priv->rsts = devm_reset_control_array_get_shared(dev); + if (IS_ERR(priv->rsts)) + return PTR_ERR(priv->rsts); + + priv->irq = platform_get_irq(pdev, 0); + + /* do not autoenable, will be enabled later */ + ret = devm_request_irq(dev, priv->irq, vs_dc_isr, IRQF_NO_AUTOEN, dev_name(dev), priv); + if (ret < 0) { + dev_err(dev, "Failed to install irq:%u.\n", priv->irq); + return ret; + } + + return ret; +} + +static u32 get_addr_offset(u32 id) +{ + u32 offset = 0; + + switch (id) { + case PRIMARY_PLANE_1: + case OVERLAY_PLANE_1: + offset = 0x04; + break; + case OVERLAY_PLANE_2: + offset = 0x08; + break; + case OVERLAY_PLANE_3: + offset = 0x0C; + break; + default: + break; + } + + return offset; +} + +static int vs_drm_device_crtc_plane_create(struct vs_drm_device *priv) +{ + struct vs_dc *dc; + struct drm_device *drm_dev; + int i, ret; + struct device_node *port; + struct vs_crtc *crtc; + struct vs_dc_info *dc_info; + struct vs_plane *plane; + struct vs_plane_primary_info *primary_info; + struct vs_plane_overlay_info *overlay_info; + struct vs_plane_cursor_info *cursor_info; + + struct device *dev = priv->base.dev; + u32 max_width = 0, max_height = 0; + u32 min_width = 0xffff, min_heigth = 0xffff; + u32 possible_crtc = 0; + + dc = &priv->dc; + dc_info = dc->hw.info; + drm_dev = &priv->base; + + for (i = 0; i < dc_info->panel_num; i++) { + crtc = vs_crtc_create(drm_dev, dc_info); + if (!crtc) { + drm_err(drm_dev, "Failed to create CRTC.\n"); + ret = -ENOMEM; + return ret; + } + crtc->dev = drm_dev->dev; + + port = of_graph_get_port_by_id(crtc->dev->of_node, i); + if (!port) { + drm_err(drm_dev, "no port node found for crtc_port%d\n", i); + return -ENOENT; + } + + crtc->base.port = port; + dc->crtc[i] = crtc; + + of_node_put(port); + } + + if (!dc->crtc[0]->base.port || !dc->crtc[1]->base.port) { + drm_err(drm_dev, "no port no crtc mask, fail to create plane\n"); + return -ENOENT; + } + + for (i = 0; i < dc_info->primary_num; i++) { + primary_info = (struct vs_plane_primary_info *)&dc_info->primary[i]; + + if (primary_info->id == PRIMARY_PLANE_0) + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base); + else + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base); + + plane = vs_plane_primary_create(drm_dev, primary_info, + dc_info->layer_num, possible_crtc); + if (IS_ERR(plane)) { + dev_err(dev, "failed to construct plane\n"); + return PTR_ERR(plane); + } + + plane->id = primary_info->id; + dc->planes[plane->id].id = primary_info->id; + dc->planes[plane->id].offset = get_addr_offset(primary_info->id); + + if (primary_info->id == PRIMARY_PLANE_0) + dc->crtc[0]->base.primary = &plane->base; + else + dc->crtc[1]->base.primary = &plane->base; + + min_width = min_t(u32, min_width, primary_info->min_width); + min_heigth = min_t(u32, min_heigth, primary_info->min_height); + /* + * Note: these values are used for multiple independent things: + * hw display mode filtering, plane buffer sizes ... + * Use the combined maximum values here to cover all use cases, + * and do more specific checking in the respective code paths. + */ + max_width = max_t(u32, max_width, primary_info->max_width); + max_height = max_t(u32, max_height, primary_info->max_height); + } + + for (i = 0; i < dc_info->overlay_num; i++) { + overlay_info = (struct vs_plane_overlay_info *)&dc_info->overlay[i]; + + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base) | + drm_crtc_mask(&dc->crtc[1]->base); + + plane = vs_plane_overlay_create(drm_dev, overlay_info, + dc_info->layer_num, possible_crtc); + if (IS_ERR(plane)) { + dev_err(dev, "failed to construct plane\n"); + return PTR_ERR(plane); + } + + plane->id = overlay_info->id; + dc->planes[plane->id].id = overlay_info->id; + dc->planes[plane->id].offset = get_addr_offset(overlay_info->id); + } + + for (i = 0; i < dc_info->cursor_num; i++) { + cursor_info = (struct vs_plane_cursor_info *)&dc_info->cursor[i]; + + if (cursor_info->id == CURSOR_PLANE_0) + possible_crtc = drm_crtc_mask(&dc->crtc[0]->base); + else + possible_crtc = drm_crtc_mask(&dc->crtc[1]->base); + + plane = vs_plane_cursor_create(drm_dev, cursor_info, possible_crtc); + if (IS_ERR(plane)) { + dev_err(dev, "failed to construct plane\n"); + return PTR_ERR(plane); + } + + plane->id = cursor_info->id; + dc->planes[plane->id].id = cursor_info->id; + dc->planes[plane->id].offset = get_addr_offset(cursor_info->id); + + if (cursor_info->id == CURSOR_PLANE_0) + dc->crtc[0]->base.cursor = &plane->base; + else + dc->crtc[1]->base.cursor = &plane->base; + drm_dev->mode_config.cursor_width = + max_t(u32, drm_dev->mode_config.cursor_width, + cursor_info->max_width); + drm_dev->mode_config.cursor_height = + max_t(u32, drm_dev->mode_config.cursor_height, + cursor_info->max_height); + } + + drm_dev->mode_config.min_width = min_width; + drm_dev->mode_config.min_height = min_heigth; + drm_dev->mode_config.max_width = max_width; + drm_dev->mode_config.max_height = max_height; + + if (dc_info->pitch_alignment > priv->pitch_alignment) + priv->pitch_alignment = dc_info->pitch_alignment; + + return 0; +} + +static int vs_load(struct vs_drm_device *priv) +{ + int ret; + + ret = clk_bulk_prepare_enable(priv->clk_count, priv->clks); + if (ret) + return ret; + + reset_control_deassert(priv->rsts); + + ret = dc_hw_init(&priv->dc); + if (ret) { + DRM_ERROR("failed to init DC HW\n"); + return ret; + } + + return 0; +} + +static int vs_drm_bind(struct device *dev) +{ + struct vs_drm_device *priv; + int ret; + struct drm_device *drm_dev; + + priv = devm_drm_dev_alloc(dev, &vs_drm_driver, struct vs_drm_device, base); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + priv->pitch_alignment = 64; + drm_dev = &priv->base; + dev_set_drvdata(dev, drm_dev); + + ret = dma_set_coherent_mask(drm_dev->dev, DMA_BIT_MASK(40)); + if (ret) + return ret; + + ret = vs_drm_device_init_res(priv); + if (ret) + return ret; + + vs_mode_config_init(drm_dev); + + /* Remove existing drivers that may own the framebuffer memory. */ + ret = drm_aperture_remove_framebuffers(&vs_drm_driver); + if (ret) + return ret; + + ret = vs_drm_device_crtc_plane_create(priv); + if (ret) { + DRM_ERROR("Failed to create ctrc and plane\n"); + return ret; + } + + ret = vs_load(priv); + if (ret) + return ret; + + /* Now try and bind all our sub-components */ + ret = component_bind_all(dev, drm_dev); + if (ret) { + ret = -EPROBE_DEFER; + goto unload; + } + ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); + if (ret) + goto err_unbind_all; + + drm_mode_config_reset(drm_dev); + + ret = drmm_kms_helper_poll_init(drm_dev); + if (ret) + goto err_unbind_all; + + ret = drm_dev_register(drm_dev, 0); + if (ret) + goto err_unbind_all; + + drm_fbdev_generic_setup(drm_dev, 32); + + return 0; + +err_unbind_all: + component_unbind_all(drm_dev->dev, drm_dev); +unload: + reset_control_assert(priv->rsts); + clk_bulk_disable_unprepare(priv->clk_count, priv->clks); + return ret; + +} + +static void vs_drm_unbind(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct vs_drm_device *priv = to_vs_drm_private(drm_dev); + + reset_control_assert(priv->rsts); + clk_bulk_disable_unprepare(priv->clk_count, priv->clks); + + drm_dev_unregister(drm_dev); + drm_atomic_helper_shutdown(drm_dev); + component_unbind_all(drm_dev->dev, drm_dev); +} + +static const struct component_master_ops vs_drm_ops = { + .bind = vs_drm_bind, + .unbind = vs_drm_unbind, +}; + +static struct platform_driver *drm_sub_drivers[] = { + +}; + +static struct component_match *vs_add_external_components(struct device *dev) +{ + struct component_match *match = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(drm_sub_drivers); ++i) { + struct platform_driver *drv = drm_sub_drivers[i]; + struct device *p = NULL, *d; + + while ((d = platform_find_device_by_driver(p, &drv->driver))) { + put_device(p); + + drm_of_component_match_add(dev, &match, component_compare_of, + d->of_node); + p = d; + } + put_device(p); + } + + return match ? match : ERR_PTR(-ENODEV); +} + +static int vs_drm_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct component_match *match; + + /* all the planes and CRTC would be created in this platform device + * , so external components are encoder + connector or self-defined + * encoder. + */ + match = vs_add_external_components(dev); + if (IS_ERR(match)) + return PTR_ERR(match); + + return component_master_add_with_match(dev, &vs_drm_ops, match); +} + +static int vs_drm_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &vs_drm_ops); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int vs_drm_suspend(struct device *dev) +{ + return drm_mode_config_helper_suspend(dev_get_drvdata(dev)); +} + +static int vs_drm_resume(struct device *dev) +{ + drm_mode_config_helper_resume(dev_get_drvdata(dev)); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(vs_drm_pm_ops, vs_drm_suspend, vs_drm_resume); + +static const struct of_device_id vs_drm_dt_ids[] = { + { .compatible = "starfive,jh7110-dc8200", .data = &dc8200_info,}, + { }, +}; + +MODULE_DEVICE_TABLE(of, vs_drm_dt_ids); + +static struct platform_driver vs_drm_platform_driver = { + .probe = vs_drm_platform_probe, + .remove = vs_drm_platform_remove, + + .driver = { + .name = DRV_NAME, + .of_match_table = vs_drm_dt_ids, + .pm = &vs_drm_pm_ops, + }, +}; + +static int __init vs_drm_init(void) +{ + int ret; + + ret = platform_register_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers)); + if (ret) + return ret; + + ret = drm_platform_driver_register(&vs_drm_platform_driver); + if (ret) + platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers)); + + return ret; +} + +static void __exit vs_drm_fini(void) +{ + platform_driver_unregister(&vs_drm_platform_driver); + platform_unregister_drivers(drm_sub_drivers, ARRAY_SIZE(drm_sub_drivers)); +} + +late_initcall_sync(vs_drm_init); +module_exit(vs_drm_fini); + +MODULE_DESCRIPTION("VeriSilicon DRM Driver"); +MODULE_LICENSE("GPL"); From patchwork Tue May 21 10:58:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668832 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B9776C25B77 for ; Tue, 21 May 2024 02:58:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C986A10E680; Tue, 21 May 2024 02:58:54 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2106.outbound.protection.partner.outlook.cn [139.219.17.106]) by gabe.freedesktop.org (Postfix) with ESMTPS id D5FED10E52C for ; Tue, 21 May 2024 02:58:44 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=YSRP7vjQrMYm6PRNkVpAmQoyCh5dV6Xs8LfxKruJUacUDTE/p+TbZh6YqHsaEckbM9S8iHtrq4yQdm9qEYYr+6yigndFi3kUDyQ8zJ7tdOdsS0jzd/0yLaOEzJYtpd7ghzReFFeeJvmN3/Vvzz2wTSjeviZbQV3OdnXon1fH2k+w+1SwczEuTXurqbXRHuz1fac+jW76/v+WrHBVQZNMoTRmF6/VXgEOApuqjjTibdvrb/OzRPh8zuevxQim6E+klbgZwkDgV0K+QtgpNUdaLTuMhawaTbjnjhCK3OqkApbXzdrBPNhhufzPRQ5Eq5rlQNMsCM+Gla9U+P9KAYCOzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=AkanxACpTfIFOqDB9PJsu6F6rwpEXlCbOXcNKMYl7AU=; b=GQgjTDXmnS/hCD0pksGGB61lqx8Cb+bE6oSrIeCWJVrOagVq21RpVb07oRjopDLsX5yX9//QGM7TIPNLa5sbmAFapFRf9Ucz+MBmxI85nIBx/UIIc/9gzHVlkgsYfwSAOAbNQFg9IcQAv3PspuW/4B10qj0UJuT9J5ZlB/Mag4YGiqjqR95tRN3VH9tYPag7Dp3BjGbXwo+KBycORb+FrV7pW2o38pnQiMCYq9SZ+BEpzBBmc+uFa2q7ZwawwrgJEX1x6lTzDAtoyW7thAX27FWlQ/pm1YAP/FK7PkVNQWZwp7fDSugkR0EsrZ2yit8YYTTkGF+drt4MGC6RzH+Pkw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1128.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.44; Tue, 21 May 2024 02:58:35 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:35 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 09/10] drm/vs: Innosilicon HDMI support Date: Tue, 21 May 2024 18:58:16 +0800 Message-Id: <20240521105817.3301-10-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1128:EE_ X-MS-Office365-Filtering-Correlation-Id: 22ab1e45-76b2-4aab-e552-08dc7941e835 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: wZWpK/wlW5M0EabwC0YpGPmOAy702Ym3vpaeD5k/eS6FdkxsbrasXnJxkRSFd1wL41r90ov450nPv6HaXz3XN7wO8oO9AvXBnNrejtGrWyR7ii/JKVjiMNeQV2TgaDMQCI+ujMGFcYC97O6DPIqJcW1DK7SKXpe7QIGILEVpaZCz4wTV52Wcf4NLZHytYfBPmtC5a6YtBauUpU5F67L6bvXpEAF1rCBO2+jtiqbAm2+8k793J/Tus/sRRZITr1ui0BHaxou50WHSb1+I1JEYa30rzKY0CRfFzJ9/IqlEUUKhrAooSldM2t48qq2l0R8gOIOSOBuG5cEOY+2RVpgkvXXpSNxNlc3dVQRcOY9RrHt1GPOux1aSdOC3kw/D/U/AudHYuUYvxU/kH9k11+Jjhmmp8G+Su6rnYiPm47zN9H0iKtenW1owu1ZBmFXFwt0oTI4FURarNCigGLOU/DwEI8BDjwsiWt5pYDTzOsBQyD6QRevonMHRBj0/wV+dnJMevAI3URSUeH/qjLDTYkVZ5PjYkdGZ+KIuVEpq1bUW1b18UbzRjwOahhggAU0pTwd8wYJWl5TgCPNp8z3sqBSN9NWVsX0TvsQDX4G/5771H4DbOHNOYRbHHHzScf9kmrm8AQ8sU9y6IyCX/LZqmoFuVA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(41320700004)(52116005)(7416005)(1800799015)(366007)(38350700005)(921011); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 1ppOXVrEYYka5dDmIUy2lYUsBfJvA9BvkBXW0u9xaKFo82Ig7XbnSbV4YB7uik8VfWsTFenbuQkmliHM91k0YIo5RExbRY9FLPKgpNO304r3JNiEJafn0SSsJYpQlvRFpkofZpBZUxE9dxusd0KbQKUc1WS/FKwRVPTBZzj5DauC+9FHf5pAC0bQrbq6NP0qUIZB9HRFuX8ofUAUbQvfp5UINhQqsvqC4zebOkJmSg9NQk3UAdfr6Hh7QYthXv4xESW/aQPjbzkbShPdcZdafLDpHgV+3YlByBV09lKXGYTVlNnAW6MrC9NnKg57tV9E9+w+mpwQxRNi2XUAGvpmurpOgaDqFsQ+5MrmtKU/j4z1WHVMoku4+VM5F1TdMMrrfDWjndxdzZ8FF44Qiw0wGqLCN0syNaH0CFdM7xopxVtwSaj5Bb1svUErmXZ/RYgGR+DPQEF02qzfdUfXGUoitFo8233d1eZS12DNc+lAJPgLp3aft4iZr6e8P2ol77WXJMRp3J79N/QnhdjP1s7TMtIWUdzIGhvCHdbeJQfIRpExmusJCewUQ1kcDqx6qlvFPh91sCEjAT38oIg8baZk3PVIeIHxMuzQeCQr1wpVeQQI6L6h7bgtkumjqPkldqhufHfT/AnZKdHcIjpf1zwiJ7/0zCSnmucikW0k1TGK4oIcWhutjwvFiLsGwUcNGw73smKHESh/EQ8y2eKiWPD4yONsfOZN8GCYrMgz1vLhNcCRRESgtyVaH44GNRTW54t1q5D/p9h3dfY/MrK0ANRNdHV7Mw+5bx0No+GcJkOXl9tnL24QWFdRHZIlZ0uo3Bh5NsgLhrAnEn0dSvMIwtiAsoEYDh3/7Lk/MJuqGkNbzigfCx5JTHIBF5e2FKWWxBenW/hVtaqwKH5wh+wIdwjicRKlCcS1OTLWr6FyoZ9AlInnmeTXftNwHQnb/YqxbaST3oImHp5qXo6fT7B7hF/9KpmKXCvnJFb+IyIXho5rODPy51jKR851pTKFeV8/zidmfPKrbI07n8e83cZQ6xwy9f8CLPmLNNM5UXamRYGAfCX1PRPKTFkFlHghFgywmRX5QcBHF+5rkPdVMIY2V6htaJ/J7kCREOjgFpFKqIfdDq/RN6XMh88lKHmfS+scvJAWJygKUNzqVSmjD9NmdzVGM1jqTqGSakttc8+475IiTRaTVOuRJXKoQ23F3Tmn4PK1wO7UuG/IgPSidr9K9cORzXMMKowmWU04oKGuG1Kg02G8pjZF9EvJ1D0O70JACxSJn0ulVsypwMcT+bVFbCDeo2Sz9lYusPZdwbW1TU8UiVAciLIkrXHv/oI8CNphiCJmHYhA568+4xC9Egs41ovUZJyqvKx5i3JsCili2dhNSQOU8QcXpuZkYclT2kG/XcWrCKZTxlFAKugvqsv7B/2vhMaq3nnwH1B2mhgJKWb49NOe/faSSmi2zPL3IWGami89RhIzmZweas0+Rx1Upq1or+N3arv78jw/EM9dw8Hm+S9uwLNU38yDLw+mfeKj4XNZ5vFTloyWZfYlttDKJ8ibkbqbsKBPso0fFByZt+hqW7i4pHrhlpI5DN+6s/gNRDng5/ssfiC5Sj5ZrDaCSCsFWA== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 22ab1e45-76b2-4aab-e552-08dc7941e835 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:35.6532 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: WuF7H/xdgXAFcXNoIucvUK3TmFObl81klAVIXPcCr+o8dyw/DUSzdjryGMTcwijOflqssuGswhLP3zNANAa+ZsWO6SwBfi38h8y5P6lLgVw= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1128 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add inno hdmi driver which binds to vs display controller and this driver uses the commom api from the inno hdmi Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Kconfig | 10 + drivers/gpu/drm/verisilicon/Makefile | 1 + .../gpu/drm/verisilicon/inno_hdmi-starfive.c | 481 ++++++++++++++++++ .../gpu/drm/verisilicon/inno_hdmi-starfive.h | 152 ++++++ drivers/gpu/drm/verisilicon/vs_drv.c | 4 +- drivers/gpu/drm/verisilicon/vs_drv.h | 4 + 6 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c create mode 100644 drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h diff --git a/drivers/gpu/drm/verisilicon/Kconfig b/drivers/gpu/drm/verisilicon/Kconfig index 2d733f93439e..228732d21e40 100644 --- a/drivers/gpu/drm/verisilicon/Kconfig +++ b/drivers/gpu/drm/verisilicon/Kconfig @@ -11,3 +11,13 @@ config DRM_VERISILICON_DC8200 This driver provides VeriSilicon kernel mode setting and buffer management. It does not provide 2D or 3D acceleration. + +if DRM_VERISILICON_DC8200 +config DRM_INNO_STARFIVE_HDMI + bool "Starfive JH7110 specific extensions for Innosilicon HDMI" + select DRM_INNO_HDMI + help + This selects support for StarFive SoC specific extensions + for the Innosilicon HDMI driver. If you want to enable + HDMI on JH7110 based SoC, you should select this option. +endif diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 88a07a308e31..2d02b4a3a567 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -6,4 +6,5 @@ vs_drm-objs := vs_dc_hw.o \ vs_crtc.o \ vs_drv.o +vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c new file mode 100644 index 000000000000..f27b04ef5690 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vs_drv.h" +#include "inno_hdmi-starfive.h" + +enum hdmi_clk { + CLK_SYS = 0, + CLK_M, + CLK_B, + CLK_HDMI_NUM +}; + +struct pre_pll_config { + unsigned long pixclock; + unsigned long tmdsclock; + u8 prediv; + u16 fbdiv; + u8 tmds_div_a; + u8 tmds_div_b; + u8 tmds_div_c; + u8 pclk_div_a; + u8 pclk_div_b; + u8 pclk_div_c; + u8 pclk_div_d; + u8 vco_div_5_en; + u32 fracdiv; +}; + +struct post_pll_config { + unsigned long tmdsclock; + u8 prediv; + u16 fbdiv; + u8 postdiv; + u8 post_div_en; + u8 version; +}; + +struct stf_inno_hdmi { + struct drm_encoder encoder; + struct inno_hdmi inno_hdmi; + struct clk_bulk_data clk_hdmi[CLK_HDMI_NUM]; + struct reset_control *tx_rst; + int nclks; + unsigned long tmds_rate; + struct pre_pll_config pre_cfg; + const struct post_pll_config *post_cfg; +}; + +static inline struct stf_inno_hdmi *to_starfive_inno_hdmi(struct drm_encoder *encoder) +{ + return container_of(encoder, struct stf_inno_hdmi, encoder); +} + +static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) +{ + struct stf_inno_hdmi *stf_hdmi = to_starfive_inno_hdmi(encoder); + + return &stf_hdmi->inno_hdmi; +} + +static const struct post_pll_config post_pll_cfg_table[] = { + {25200000, 1, 80, 13, 3, 1}, + {27000000, 1, 40, 11, 3, 1}, + {33750000, 1, 40, 11, 3, 1}, + {49000000, 1, 20, 1, 3, 3}, + {241700000, 1, 20, 1, 3, 3}, + {297000000, 4, 20, 0, 0, 3}, + { /* sentinel */ } +}; + +static int starfive_hdmi_enable_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_inno_hdmi) +{ + int ret; + + ret = clk_bulk_prepare_enable(stf_inno_hdmi->nclks, stf_inno_hdmi->clk_hdmi); + if (ret) { + dev_err(dev, "failed to enable clocks\n"); + return ret; + } + + ret = reset_control_deassert(stf_inno_hdmi->tx_rst); + if (ret < 0) { + dev_err(dev, "failed to deassert tx_rst\n"); + return ret; + } + return 0; +} + +static void starfive_hdmi_disable_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_inno_hdmi) +{ + int ret; + + ret = reset_control_assert(stf_inno_hdmi->tx_rst); + if (ret < 0) + dev_err(dev, "failed to assert tx_rst\n"); + + clk_bulk_disable_unprepare(stf_inno_hdmi->nclks, stf_inno_hdmi->clk_hdmi); +} + +static void starfive_hdmi_config_pll(struct stf_inno_hdmi *stf_inno_hdmi) +{ + u32 val; + struct inno_hdmi *hdmi; + + hdmi = &stf_inno_hdmi->inno_hdmi; + u8 reg_1ad_value = stf_inno_hdmi->post_cfg->post_div_en ? + stf_inno_hdmi->post_cfg->postdiv : 0x00; + u8 reg_1aa_value = stf_inno_hdmi->post_cfg->post_div_en ? + 0x0e : 0x02; + + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_CONTROL, STF_INNO_PRE_PLL_POWER_DOWN); + hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_1, + STF_INNO_POST_PLL_POST_DIV_ENABLE | + STF_INNO_POST_PLL_REFCLK_SEL_TMDS | + STF_INNO_POST_PLL_POWER_DOWN); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_1, + STF_INNO_PRE_PLL_PRE_DIV(stf_inno_hdmi->pre_cfg.prediv)); + + val = STF_INNO_SPREAD_SPECTRUM_MOD_DISABLE | STF_INNO_SPREAD_SPECTRUM_MOD_DOWN; + if (!stf_inno_hdmi->pre_cfg.fracdiv) + val |= STF_INNO_PRE_PLL_FRAC_DIV_DISABLE; + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_2, + STF_INNO_PRE_PLL_FB_DIV_11_8(stf_inno_hdmi->pre_cfg.fbdiv) | val); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_3, + STF_INNO_PRE_PLL_FB_DIV_7_0(stf_inno_hdmi->pre_cfg.fbdiv)); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_4, + STF_INNO_PRE_PLL_TMDSCLK_DIV_C(stf_inno_hdmi->pre_cfg.tmds_div_c) | + STF_INNO_PRE_PLL_TMDSCLK_DIV_A(stf_inno_hdmi->pre_cfg.tmds_div_a) | + STF_INNO_PRE_PLL_TMDSCLK_DIV_B(stf_inno_hdmi->pre_cfg.tmds_div_b)); + + if (stf_inno_hdmi->pre_cfg.fracdiv) { + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_L, + STF_INNO_PRE_PLL_FRAC_DIV_7_0(stf_inno_hdmi->pre_cfg.fracdiv)); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_M, + STF_INNO_PRE_PLL_FRAC_DIV_15_8(stf_inno_hdmi->pre_cfg.fracdiv)); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_FRAC_DIV_H, + STF_INNO_PRE_PLL_FRAC_DIV_23_16(stf_inno_hdmi->pre_cfg.fracdiv)); + } + + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_5, + STF_INNO_PRE_PLL_PCLK_DIV_A(stf_inno_hdmi->pre_cfg.pclk_div_a) | + STF_INNO_PRE_PLL_PCLK_DIV_B(stf_inno_hdmi->pre_cfg.pclk_div_b)); + hdmi_writeb(hdmi, STF_INNO_PRE_PLL_DIV_6, + STF_INNO_PRE_PLL_PCLK_DIV_C(stf_inno_hdmi->pre_cfg.pclk_div_c) | + STF_INNO_PRE_PLL_PCLK_DIV_D(stf_inno_hdmi->pre_cfg.pclk_div_d)); + + /*pre-pll power down*/ + hdmi_modb(hdmi, STF_INNO_PRE_PLL_CONTROL, STF_INNO_PRE_PLL_POWER_DOWN, 0); + + hdmi_modb(hdmi, STF_INNO_POST_PLL_DIV_2, STF_INNO_POST_PLL_Pre_DIV_MASK, + STF_INNO_POST_PLL_PRE_DIV(stf_inno_hdmi->post_cfg->prediv)); + hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_3, stf_inno_hdmi->post_cfg->fbdiv & 0xff); + hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_4, reg_1ad_value); + hdmi_writeb(hdmi, STF_INNO_POST_PLL_DIV_1, reg_1aa_value); +} + +static void starfive_hdmi_tmds_driver_on(struct inno_hdmi *hdmi) +{ + hdmi_modb(hdmi, STF_INNO_TMDS_CONTROL, + STF_INNO_TMDS_DRIVER_ENABLE, STF_INNO_TMDS_DRIVER_ENABLE); +} + +static void starfive_hdmi_sync_tmds(struct inno_hdmi *hdmi) +{ + /*first send 0 to this bit, then send 1 and keep 1 into this bit*/ + hdmi_writeb(hdmi, HDMI_SYNC, 0x0); + hdmi_writeb(hdmi, HDMI_SYNC, 0x1); +} + +static void starfive_hdmi_phy_get_pre_pll_cfg(struct stf_inno_hdmi *hdmi) +{ + if (hdmi->tmds_rate > 30000000) { + hdmi->pre_cfg.pixclock = hdmi->tmds_rate; + hdmi->pre_cfg.tmdsclock = hdmi->tmds_rate; + hdmi->pre_cfg.prediv = 1; + hdmi->pre_cfg.fbdiv = hdmi->tmds_rate / 3000000; + hdmi->pre_cfg.tmds_div_a = 0; + hdmi->pre_cfg.tmds_div_b = 1; + hdmi->pre_cfg.tmds_div_c = 1; + hdmi->pre_cfg.pclk_div_a = 1; + hdmi->pre_cfg.pclk_div_b = 0; + hdmi->pre_cfg.pclk_div_c = 2; + hdmi->pre_cfg.pclk_div_d = 2; + hdmi->pre_cfg.vco_div_5_en = hdmi->tmds_rate % 3000000 ? 1 : 0; + + if (hdmi->pre_cfg.vco_div_5_en) { + hdmi->pre_cfg.fracdiv = (hdmi->tmds_rate % 3000000) * + 0xffffff / 1000000; + } + } else { + hdmi->pre_cfg.pixclock = hdmi->tmds_rate; + hdmi->pre_cfg.tmdsclock = hdmi->tmds_rate; + hdmi->pre_cfg.prediv = 1; + hdmi->pre_cfg.fbdiv = hdmi->tmds_rate / 1000000; + hdmi->pre_cfg.tmds_div_a = 2; + hdmi->pre_cfg.tmds_div_b = 1; + hdmi->pre_cfg.tmds_div_c = 1; + hdmi->pre_cfg.pclk_div_a = 3; + hdmi->pre_cfg.pclk_div_b = 0; + hdmi->pre_cfg.pclk_div_c = 3; + hdmi->pre_cfg.pclk_div_d = 4; + hdmi->pre_cfg.vco_div_5_en = hdmi->tmds_rate % 1000000 ? 1 : 0; + + if (hdmi->pre_cfg.vco_div_5_en) { + hdmi->pre_cfg.fracdiv = (hdmi->tmds_rate % 1000000) * + 0xffffff / 1000000; + } + } +} + +static int starfive_hdmi_phy_clk_set_rate(struct stf_inno_hdmi *stf_inno_hdmi) +{ + stf_inno_hdmi->post_cfg = post_pll_cfg_table; + + starfive_hdmi_phy_get_pre_pll_cfg(stf_inno_hdmi); + + for (; stf_inno_hdmi->post_cfg->tmdsclock != 0; stf_inno_hdmi->post_cfg++) + if (stf_inno_hdmi->tmds_rate <= stf_inno_hdmi->post_cfg->tmdsclock) + break; + + starfive_hdmi_config_pll(stf_inno_hdmi); + + return 0; +} + +static int starfive_hdmi_setup(struct inno_hdmi *hdmi, + struct drm_display_mode *mode) +{ + struct stf_inno_hdmi *stf_inno_hdmi = dev_get_drvdata(hdmi->dev); + struct drm_display_info *display = &hdmi->connector.display_info; + int ret; + u32 val; + + hdmi_modb(hdmi, STF_INNO_BIAS_CONTROL, STF_INNO_BIAS_ENABLE, STF_INNO_BIAS_ENABLE); + hdmi_writeb(hdmi, STF_INNO_RX_CONTROL, STF_INNO_RX_ENABLE); + + stf_inno_hdmi->tmds_rate = mode->clock * 1000; + starfive_hdmi_phy_clk_set_rate(stf_inno_hdmi); + + ret = readx_poll_timeout(readl_relaxed, + hdmi->regs + (STF_INNO_PRE_PLL_LOCK_STATUS) * 0x04, + val, val & 0x1, 1000, 100000); + if (ret < 0) { + dev_err(hdmi->dev, "failed to wait pre-pll lock\n"); + return ret; + } + + ret = readx_poll_timeout(readl_relaxed, + hdmi->regs + (STF_INNO_POST_PLL_LOCK_STATUS) * 0x04, + val, val & 0x1, 1000, 100000); + if (ret < 0) { + dev_err(hdmi->dev, "failed to wait post-pll lock\n"); + return ret; + } + + /*turn on LDO*/ + hdmi_writeb(hdmi, STF_INNO_LDO_CONTROL, STF_INNO_LDO_ENABLE); + /*turn on serializer*/ + hdmi_writeb(hdmi, STF_INNO_SERIALIER_CONTROL, STF_INNO_SERIALIER_ENABLE); + + if (display->is_hdmi) + inno_hdmi_config_video_avi(hdmi, mode); + + inno_hdmi_sys_power(hdmi, false); + inno_hdmi_config_video_timing(hdmi, mode); + inno_hdmi_sys_power(hdmi, true); + + starfive_hdmi_tmds_driver_on(hdmi); + starfive_hdmi_sync_tmds(hdmi); + + return 0; +} + +static enum drm_mode_status +starfive_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) +{ + int pclk = mode->clock * 1000; + bool valid = false; + + if (pclk <= PIXCLOCK_4K_30FPS) + valid = true; + + return (valid) ? MODE_OK : MODE_BAD; +} + +static void starfive_hdmi_encoder_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + + conn_state = drm_atomic_get_new_connector_state(state, &hdmi->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; + + starfive_hdmi_setup(hdmi, &crtc_state->adjusted_mode); +} + +static void starfive_hdmi_encoder_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); + + inno_hdmi_sys_power(hdmi, false); +} + +static int +starfive_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + u8 vic = drm_match_cea_mode(mode); + struct inno_hdmi_connector_state *inno_conn_state = to_inno_hdmi_conn_state(conn_state); + + struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state); + + vs_crtc_state->encoder_type = encoder->encoder_type; + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24; + + if (vic == 6 || vic == 7 || vic == 21 || vic == 22 || + vic == 2 || vic == 3 || vic == 17 || vic == 18) + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; + else + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; + + return starfive_hdmi_connector_mode_valid(conn_state->connector, + &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; +} + +static const struct drm_encoder_helper_funcs stf_inno_encoder_helper_funcs = { + .atomic_check = starfive_hdmi_encoder_atomic_check, + .atomic_enable = starfive_hdmi_encoder_enable, + .atomic_disable = starfive_hdmi_encoder_disable, +}; + +static int starfive_hdmi_get_clk_rst(struct device *dev, struct stf_inno_hdmi *stf_hdmi) +{ + int ret; + + stf_hdmi->nclks = ARRAY_SIZE(stf_hdmi->clk_hdmi); + + ret = devm_clk_bulk_get(dev, stf_hdmi->nclks, stf_hdmi->clk_hdmi); + if (ret) { + dev_err(dev, "Failed to get clk controls\n"); + return ret; + } + + stf_hdmi->tx_rst = devm_reset_control_get_by_index(dev, 0); + if (IS_ERR(stf_hdmi->tx_rst)) { + dev_err(dev, "failed to get tx_rst reset\n"); + return PTR_ERR(stf_hdmi->tx_rst); + } + + return 0; +} + +static int starfive_hdmi_bind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct stf_inno_hdmi *stf_hdmi; + struct inno_hdmi *hdmi; + struct resource *iores; + + int ret; + unsigned long long rate; + + stf_hdmi = drmm_simple_encoder_alloc(drm, struct stf_inno_hdmi, + encoder, DRM_MODE_ENCODER_TMDS); + hdmi = &stf_hdmi->inno_hdmi; + + hdmi->dev = dev; + hdmi->plat_data = (struct inno_hdmi_plat_data *)of_device_get_match_data(dev); + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hdmi->regs = devm_ioremap_resource(dev, iores); + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + + ret = starfive_hdmi_get_clk_rst(dev, stf_hdmi); + if (ret < 0) + return ret; + + ret = starfive_hdmi_enable_clk_rst(dev, stf_hdmi); + if (ret) + return ret; + + rate = clk_get_rate(stf_hdmi->clk_hdmi[CLK_SYS].clk); + inno_hdmi_i2c_init(hdmi, rate); + + ret = inno_hdmi_bind(drm, hdmi, &stf_hdmi->encoder); + if (ret) + goto err_disable_clk; + + dev_set_drvdata(dev, stf_hdmi); + + return 0; + +err_disable_clk: + starfive_hdmi_disable_clk_rst(dev, stf_hdmi); + return ret; +} + +static void starfive_hdmi_unbind(struct device *dev, struct device *master, void *data) +{ + struct stf_inno_hdmi *stf_hdmi = dev_get_drvdata(dev); + + struct inno_hdmi *hdmi = &stf_hdmi->inno_hdmi; + + i2c_put_adapter(hdmi->ddc); + starfive_hdmi_disable_clk_rst(dev, stf_hdmi); +} + +static const struct component_ops starfive_hdmi_ops = { + .bind = starfive_hdmi_bind, + .unbind = starfive_hdmi_unbind, +}; + +static int starfive_hdmi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &starfive_hdmi_ops); +} + +static int starfive_hdmi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &starfive_hdmi_ops); + + return 0; +} + +static const struct inno_hdmi_plat_data stf_inno_info = { + .soc_type = STARFIVE_HDMI, + .mode_valid = starfive_hdmi_connector_mode_valid, + .helper_private = &stf_inno_encoder_helper_funcs, +}; + +static const struct of_device_id starfive_hdmi_dt_ids[] = { + { .compatible = "starfive,jh7110-inno-hdmi", .data = &stf_inno_info,}, + {}, +}; +MODULE_DEVICE_TABLE(of, starfive_hdmi_dt_ids); + +struct platform_driver starfive_hdmi_driver = { + .probe = starfive_hdmi_probe, + .remove = starfive_hdmi_remove, + .driver = { + .name = "starfive-hdmi", + .of_match_table = starfive_hdmi_dt_ids, + }, +}; + +MODULE_AUTHOR("StarFive Corporation"); +MODULE_DESCRIPTION("Starfive Specific INNO-HDMI Driver"); diff --git a/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h new file mode 100644 index 000000000000..c64374208b58 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/inno_hdmi-starfive.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + */ + +#ifndef __STARFIVE_HDMI_H__ +#define __STARFIVE_HDMI_H__ + +#include +#include + +#define HDMI_SYNC 0xce + +#define UPDATE(x, h, l) FIELD_PREP(GENMASK(h, l), x) + +/* REG: 0x1a0 */ +#define STF_INNO_PRE_PLL_CONTROL 0x1a0 +#define STF_INNO_PCLK_VCO_DIV_5_MASK BIT(1) +#define STF_INNO_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) +#define STF_INNO_PRE_PLL_POWER_DOWN BIT(0) + +/* REG: 0x1a1 */ +#define STF_INNO_PRE_PLL_DIV_1 0x1a1 +#define STF_INNO_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) +#define STF_INNO_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) + +/* REG: 0x1a2 */ +#define STF_INNO_PRE_PLL_DIV_2 0x1a2 +#define STF_INNO_SPREAD_SPECTRUM_MOD_DOWN BIT(7) +#define STF_INNO_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) +#define STF_INNO_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) +#define STF_INNO_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) +#define STF_INNO_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) + +/* REG: 0x1a3 */ +#define STF_INNO_PRE_PLL_DIV_3 0x1a3 +#define STF_INNO_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) + +/* REG: 0x1a4*/ +#define STF_INNO_PRE_PLL_DIV_4 0x1a4 +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) +#define STF_INNO_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) + +/* REG: 0x1a5 */ +#define STF_INNO_PRE_PLL_DIV_5 0x1a5 +#define STF_INNO_PRE_PLL_PCLK_DIV_B_SHIFT 5 +#define STF_INNO_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) +#define STF_INNO_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) +#define STF_INNO_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) +#define STF_INNO_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) + +/* REG: 0x1a6 */ +#define STF_INNO_PRE_PLL_DIV_6 0x1a6 +#define STF_INNO_PRE_PLL_PCLK_DIV_C_SHIFT 5 +#define STF_INNO_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) +#define STF_INNO_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) +#define STF_INNO_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) +#define STF_INNO_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) + +/* REG: 0x1a9 */ +#define STF_INNO_PRE_PLL_LOCK_STATUS 0x1a9 + +/* REG: 0x1aa */ +#define STF_INNO_POST_PLL_DIV_1 0x1aa +#define STF_INNO_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) +#define STF_INNO_POST_PLL_REFCLK_SEL_TMDS BIT(1) +#define STF_INNO_POST_PLL_POWER_DOWN BIT(0) +#define STF_INNO_POST_PLL_FB_DIV_8(x) UPDATE(((x) >> 8) << 4, 4, 4) + +/* REG:0x1ab */ +#define STF_INNO_POST_PLL_DIV_2 0x1ab +#define STF_INNO_POST_PLL_Pre_DIV_MASK GENMASK(5, 0) +#define STF_INNO_POST_PLL_PRE_DIV(x) UPDATE(x, 5, 0) + +/* REG: 0x1ac */ +#define STF_INNO_POST_PLL_DIV_3 0x1ac +#define STF_INNO_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) + +/* REG: 0x1ad */ +#define STF_INNO_POST_PLL_DIV_4 0x1ad +#define STF_INNO_POST_PLL_POST_DIV_MASK GENMASK(2, 0) +#define STF_INNO_POST_PLL_POST_DIV_2 0x0 +#define STF_INNO_POST_PLL_POST_DIV_4 0x1 +#define STF_INNO_POST_PLL_POST_DIV_8 0x3 + +/* REG: 0x1af */ +#define STF_INNO_POST_PLL_LOCK_STATUS 0x1af + +/* REG: 0x1b0 */ +#define STF_INNO_BIAS_CONTROL 0x1b0 +#define STF_INNO_BIAS_ENABLE BIT(2) + +/* REG: 0x1b2 */ +#define STF_INNO_TMDS_CONTROL 0x1b2 +#define STF_INNO_TMDS_CLK_DRIVER_EN BIT(3) +#define STF_INNO_TMDS_D2_DRIVER_EN BIT(2) +#define STF_INNO_TMDS_D1_DRIVER_EN BIT(1) +#define STF_INNO_TMDS_D0_DRIVER_EN BIT(0) +#define STF_INNO_TMDS_DRIVER_ENABLE (STF_INNO_TMDS_CLK_DRIVER_EN | \ + STF_INNO_TMDS_D2_DRIVER_EN | \ + STF_INNO_TMDS_D1_DRIVER_EN | \ + STF_INNO_TMDS_D0_DRIVER_EN) + +/* REG: 0x1b4 */ +#define STF_INNO_LDO_CONTROL 0x1b4 +#define STF_INNO_LDO_D2_EN BIT(2) +#define STF_INNO_LDO_D1_EN BIT(1) +#define STF_INNO_LDO_D0_EN BIT(0) +#define STF_INNO_LDO_ENABLE (STF_INNO_LDO_D2_EN | \ + STF_INNO_LDO_D1_EN | \ + STF_INNO_LDO_D0_EN) + +/* REG: 0x1be */ +#define STF_INNO_SERIALIER_CONTROL 0x1be +#define STF_INNO_SERIALIER_D2_EN BIT(6) +#define STF_INNO_SERIALIER_D1_EN BIT(5) +#define STF_INNO_SERIALIER_D0_EN BIT(4) +#define STF_INNO_SERIALIER_EN BIT(0) + +#define STF_INNO_SERIALIER_ENABLE (STF_INNO_SERIALIER_D2_EN | \ + STF_INNO_SERIALIER_D1_EN | \ + STF_INNO_SERIALIER_D0_EN | \ + STF_INNO_SERIALIER_EN) + +/* REG: 0x1cc */ +#define STF_INNO_RX_CONTROL 0x1cc +#define STF_INNO_RX_EN BIT(3) +#define STF_INNO_RX_CHANNEL_2_EN BIT(2) +#define STF_INNO_RX_CHANNEL_1_EN BIT(1) +#define STF_INNO_RX_CHANNEL_0_EN BIT(0) +#define STF_INNO_RX_ENABLE (STF_INNO_RX_EN | \ + STF_INNO_RX_CHANNEL_2_EN | \ + STF_INNO_RX_CHANNEL_1_EN | \ + STF_INNO_RX_CHANNEL_0_EN) + +/* REG: 0x1d1 */ +#define STF_INNO_PRE_PLL_FRAC_DIV_H 0x1d1 +#define STF_INNO_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) +/* REG: 0x1d2 */ +#define STF_INNO_PRE_PLL_FRAC_DIV_M 0x1d2 +#define STF_INNO_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) +/* REG: 0x1d3 */ +#define STF_INNO_PRE_PLL_FRAC_DIV_L 0x1d3 +#define STF_INNO_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) + +#define PIXCLOCK_4K_30FPS 297000000 + +#endif /* __STARFIVE_HDMI_H__ */ diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c index c22fd2199fe2..6f04102b05b3 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.c +++ b/drivers/gpu/drm/verisilicon/vs_drv.c @@ -609,7 +609,9 @@ static const struct component_master_ops vs_drm_ops = { }; static struct platform_driver *drm_sub_drivers[] = { - +#ifdef CONFIG_DRM_INNO_STARFIVE_HDMI + &starfive_hdmi_driver, +#endif }; static struct component_match *vs_add_external_components(struct device *dev) diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h index d9f6efa7c8f9..c3c08ed5f8ac 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.h +++ b/drivers/gpu/drm/verisilicon/vs_drv.h @@ -90,4 +90,8 @@ to_vs_plane_state(struct drm_plane_state *state) return container_of(state, struct vs_plane_state, base); } +#ifdef CONFIG_DRM_INNO_STARFIVE_HDMI +extern struct platform_driver starfive_hdmi_driver; +#endif + #endif /* __VS_DRV_H__ */ From patchwork Tue May 21 10:58:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Zhao X-Patchwork-Id: 13668833 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2FBA7C25B7B for ; Tue, 21 May 2024 02:59:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3C12410EA7F; Tue, 21 May 2024 02:58:58 +0000 (UTC) Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2106.outbound.protection.partner.outlook.cn [139.219.17.106]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6FA7710E465 for ; Tue, 21 May 2024 02:58:45 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IwQKgxlszXQIjm1CJ559Tyb9amWP6JCSrXPOISMBaExvR1IfFTBoJCQqTa3+Hjg+8ou30oTYWYXivss9cjLjgjj+1TPsvAdcwb1LlPVQTIOglMq96gCpeRsjLksy+lPVn01QmqxfyCWWe9l1EMaWwOcSgjyAvKhIKGqhYAdbRYBNEkiXcYKMD3SGAft/kalhLi5Sf5xLPzFCw4+5PyyOaaKD5Vy2Bf7bFcEXe8RlHXcNcq/sd8TJtTrseK45b/io0eVGTRi0r+1l39CmnhBxrvcyUNEkExItFIQEwQTPjpyTqYfoELwkgYUckBG749xYW8kasNZshM6LyOY503amRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ImRJqOjUKRUALgJH4yL5SYVCqs+ZZF49yWn6rduhMTM=; b=k3rfaZ9utWQrg3qoKf3hpHg4vZi3JF3krkbUDX8On7jS/1JZeJKlp2oOgJ1Akom5LvV1YTKeBJFRP+sjI/7tNJctuf0Xbo4zHyxktl3LSfIYmsIxE6pidIOYa3QAOzdpExZSvC7E53gRdSM2YXkg5ssa/njn6lQ8ABN9+hNUlUAai3cngMS8nlOO0zWzT+sMuawaX2KMXb1D+vlrxjhz7PeOiw6ToQAfZqIkSnLzg9VLEU5FkilbQnCCABCGizJArB3Br780seOe3hNmmKBN9lTJpQ/nebSB+GAMTfz9JKOMzM5/Kx2jR0wqA+0XZBtRXILYu2beBXB9jm0IDdVeSA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) by ZQ0PR01MB1128.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.44; Tue, 21 May 2024 02:58:36 +0000 Received: from ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6]) by ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn ([fe80::39be:8ed9:67b7:adc6%6]) with mapi id 15.20.7472.044; Tue, 21 May 2024 02:58:36 +0000 From: keith To: andrzej.hajda@intel.com, neil.armstrong@linaro.org, rfoss@kernel.org, Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se, jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, hjc@rock-chips.com, heiko@sntech.de, andy.yan@rock-chips.com, xingyu.wu@starfivetech.com, p.zabel@pengutronix.de, jack.zhu@starfivetech.com, shengyang.chen@starfivetech.com Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, keith.zhao@starfivetech.com Subject: [PATCH v4 10/10] drm/vs: add simple dsi encoder Date: Tue, 21 May 2024 18:58:17 +0800 Message-Id: <20240521105817.3301-11-keith.zhao@starfivetech.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20240521105817.3301-1-keith.zhao@starfivetech.com> References: <20240521105817.3301-1-keith.zhao@starfivetech.com> X-ClientProxiedBy: SHXPR01CA0020.CHNPR01.prod.partner.outlook.cn (2406:e500:c311:1b::29) To ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1047:EE_|ZQ0PR01MB1128:EE_ X-MS-Office365-Filtering-Correlation-Id: ee1c1c63-5995-4f54-43ec-08dc7941e8e0 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: X+anbPRpR4G3glKdGF5S/M0uZdIxmF63ePgLHKxPOa2Quk6oCxbZ4atbTvJB0XkF6ldl8UEftCE695qhgGmWiJXjk2mhkZ/pbxUI2BDy8ukRePZEK3A0bQg2qOL1pNOQOMposbiZWy4ZUsUkdXtwuB7AlyM8n3oceB+E9xX3yXfp1NRGI4Qn5QHH1kt2WW1Xk8OGWd2YuFBzo+htofe91QqIH1PhNfL/5tgFniNHH5xSFlsXLbE6MrxqvgCsEppH9qpo26Zyv2XHII/XzqL0GDm9bIk0LACa1/XOgeyvnU4rxXE+zF+SKIWbrpLeUSfbGTmObeVztKZli7M0RavpbSnMkbgk31ESE4qFcoi4nQ3YRYbvUg6Q0h1OQrKBIXer82PdoVRjTeKbyoSwwAZkJRb2lB4N5H41A2TSUYeyQCUCJmBTLgBJJ8GgdL59KURcNgrEU0N5vM2lc2LgE4QVUWweJr6AsyaacejJ18VyqjD6YLxIY11KQ1cEU6kdv1JNnye3ySl0rJ/DxxUHc8H7MenAhYNJ84Njt/80W1hrj2AZYEzFM919GORlNxBb3FpPqnuBQ7BuxzEsYRgfwkJ40F/1vniRLwa+cnFkZd0cJVGfjBUrxnOpXRrVWvV2z73c4JI/+aoe0Afu+PPxVy/V5g== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn; PTR:; CAT:NONE; SFS:(13230031)(41320700004)(52116005)(7416005)(1800799015)(366007)(38350700005)(921011); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: PODdSKnexI6aBQ2l46x+jGk9ocxa41YJNpuOkoq8yeLMgz+I/NCVLZoqRx1O18Vbt+82tY0IBe7k1Vf4rYaqA80yLeusXCbZfYUL50PVkQZrgx5sc669Fj6w0Mc4T8Q6NTanEbpBy94MruNDwdFrdz+L6V+mkh15YhUCujbOzcnBNqsD25jKGASIDHF2OuPshSGumQkKMc0VqEfHYqNJGbPqJjBoS2wYksvanZe4HhDpXPR3wb1i/W44YYvXQ4aFEPwr0HTWSguVQd60qZuXRuSiKghyRm9aJIsM3HtkSeWrfVFK7A/MkGwFZ+4+g7xLg7tFNr9FfKTXXJKbxuN9FLU2Q5WkJHXHcL+x6FFCzOKa/lX6SOcxeuFzGCW4rMbnowJgewQRQzNbKXGfxt8GKENvEy94WClsU3u5nzqQW5K/pFKXbTjq4Gc/+4Wm8QNtSGBPGaK2L9eNbWZSLsGZU830hX9XAp4l9NOMs2K0c++kAacCFkeGP/f+4AJChT+OVTFyiGSlSs45ncoWNc8Wa1aCFdzAKPcG4C6x58uhjHnacAW377arQflGd5Yv5vd/rVL3aMMmLUmNhDkM6ZKQ+7Eielip8s4S0G4xiY/T/urS5gnABsxCyAp/CsNq0yLTOJR2c8Sb4ELO9o4S03dZaRWElYLqbcpKDCYN5KyWxycrZ+VwFRTvAhnviFyEAlPbDY7oTBpXoWBvW1f4EteEKhd29HZujUcSkt6eOlacBRXC/Z5g0nfHaSgPbT5L9BSejyuWcFV5O2ew0G5W7yN4nQEX2MQk0J89ygWR783uRnovA20QAKPIEKmVK1ya4Y4cfRuqKSoOL/dZ7EPCWnlFcDcusY99uIgCTiCEKMbp9zoEwqAnIxAroMvqP1zyyL0cLwYNVHdEjJt3vylzp0EuuTUYNy6f6QTcFZ3zYfQRQFtfkANbJxGs3MYaREB+0OmsNoa51vxwhxqoNaBgZjlOo2cZcOp1FlXUrrFDgQFge+ag2YUDeNWcBiljP1O9udiydsRkFXTDT3UXeXsGbtktGG/D2D0hBl/LGKEK5cyz5kZgn5qv/l2KqCivyhKgXSx2/B2Hh8xioD8iTP2n8Gwdnaso8UxopHKLelozH8P+krobDBWAm6QLkVCkgaaS5bO14r6dCku0iIQCUWXDBfRC6wWCWeVlL4neI0UKOEMkTNzsilTl8HOe+lm3K+hZXsrMdVCY74OYMrTTcwXF3sPoCaGTW1Z6VlQjQNCdERHrpqP2/00SwS2Uw81XJzrQ9mv4SpdFR3ZztSIEd3K2cBeKPk7oUoXRUBrSlLUuKnWnlZT9VRD2gcAg+PNFHJ62Oyrv6AqnIM29zsuwd5LnkompEn86GkVWQtiix/31TlwcLkxD5IMJNqdBX/2RpOLuHWid3OGs5STdIxTmh7sf8OR6hkblDSN1WJP68lWhBFXhjmAahXmZ0itPIR1IWJgXm7ls8ByjGODB7VKR8UY4txDgxmJGwTVDrgtkdkQGFGWr/sWj29XAeeb1GQwd3iea0kZiuWjersANfbPk91c3Ri85D4SdRE0YjoP5x8fbKoj5jn+cVuYY+meqItlApOGYL5iDmZ9pPA1Wket7AwUdjGlkfQ== X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: ee1c1c63-5995-4f54-43ec-08dc7941e8e0 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1047.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2024 02:58:36.7699 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: PMRyhVvmRJxHiiRYTM4Poz0em0d2Zurn1A80bYQ6TFvm4Dgz+8wVPLjerPhTbQx3dnTaAz1uHpTnEUFsO6XPUZQdi8l82ToHXvoTpOYKNmc= X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1128 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 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" add encoder to match cdns dsi driver Signed-off-by: keith --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_drv.c | 1 + drivers/gpu/drm/verisilicon/vs_drv.h | 1 + drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 ++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_simple_enc.h | 25 +++ 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 2d02b4a3a567..c35ba9bd6f81 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \ vs_modeset.o \ vs_plane.o \ vs_crtc.o \ - vs_drv.o + vs_drv.o \ + vs_simple_enc.o vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c index 6f04102b05b3..2748d48f2c7e 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.c +++ b/drivers/gpu/drm/verisilicon/vs_drv.c @@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] = { #ifdef CONFIG_DRM_INNO_STARFIVE_HDMI &starfive_hdmi_driver, #endif + &simple_encoder_driver, }; static struct component_match *vs_add_external_components(struct device *dev) diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h index c3c08ed5f8ac..f3f0f170777d 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.h +++ b/drivers/gpu/drm/verisilicon/vs_drv.h @@ -17,6 +17,7 @@ #include #include "vs_dc_hw.h" +#include "vs_simple_enc.h" /*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ struct vs_drm_device { diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.c b/drivers/gpu/drm/verisilicon/vs_simple_enc.c new file mode 100644 index 000000000000..d0b1755d77d2 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vs_crtc.h" +#include "vs_simple_enc.h" + +static const struct simple_encoder_priv dsi_priv = { + .encoder_type = DRM_MODE_ENCODER_DSI +}; + +static inline struct vs_simple_encoder *to_simple_encoder(struct drm_encoder *enc) +{ + return container_of(enc, struct vs_simple_encoder, encoder); +} + +static int encoder_parse_dt(struct device *dev) +{ + struct vs_simple_encoder *simple = dev_get_drvdata(dev); + unsigned int args[2]; + + simple->dss_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, + "starfive,syscon", + 2, args); + + if (IS_ERR(simple->dss_regmap)) { + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap), + "getting the regmap failed\n"); + } + + simple->offset = args[0]; + simple->mask = args[1]; + + return 0; +} + +static void vs_encoder_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) +{ + struct vs_simple_encoder *simple = to_simple_encoder(encoder); + + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask, simple->mask); +} + +static int vs_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state); + struct drm_connector *connector = conn_state->connector; + int ret = 0; + + vs_crtc_state->encoder_type = encoder->encoder_type; + if (connector->display_info.num_bus_formats) + vs_crtc_state->output_fmt = connector->display_info.bus_formats[0]; + else + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_FIXED; + + switch (vs_crtc_state->output_fmt) { + case MEDIA_BUS_FMT_FIXED: + case MEDIA_BUS_FMT_RGB565_1X16: + case MEDIA_BUS_FMT_RGB666_1X18: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_YUV10_1X30: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + + /* If MEDIA_BUS_FMT_FIXED, set it to default value */ + if (vs_crtc_state->output_fmt == MEDIA_BUS_FMT_FIXED) + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24; + + return ret; +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .atomic_check = vs_encoder_atomic_check, + .atomic_enable = vs_encoder_atomic_enable, +}; + +static int vs_encoder_bind(struct device *dev, struct device *master, void *data) +{ + struct drm_device *drm_dev = data; + struct vs_simple_encoder *simple = dev_get_drvdata(dev); + struct drm_encoder *encoder; + struct drm_bridge *bridge; + int ret; + + encoder = &simple->encoder; + + ret = drmm_encoder_init(drm_dev, encoder, NULL, simple->priv->encoder_type, NULL); + if (ret) + return ret; + + drm_encoder_helper_add(encoder, &encoder_helper_funcs); + + encoder->possible_crtcs = + drm_of_find_possible_crtcs(drm_dev, dev->of_node); + + /* output port is port1*/ + bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + if (IS_ERR(bridge)) { + if (PTR_ERR(bridge) == -ENODEV) { + bridge = NULL; + return 0; + } + + return PTR_ERR(bridge); + } + + return drm_bridge_attach(encoder, bridge, NULL, 0); +} + +static const struct component_ops encoder_component_ops = { + .bind = vs_encoder_bind, +}; + +static int vs_encoder_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vs_simple_encoder *simple; + int ret; + + simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); + if (!simple) + return -ENOMEM; + + simple->priv = of_device_get_match_data(dev); + + simple->dev = dev; + + dev_set_drvdata(dev, simple); + + ret = encoder_parse_dt(dev); + if (ret) + return ret; + + return component_add(dev, &encoder_component_ops); +} + +static int vs_encoder_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + component_del(dev, &encoder_component_ops); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id simple_encoder_dt_match[] = { + { .compatible = "starfive,dsi-encoder", .data = &dsi_priv}, + {}, +}; +MODULE_DEVICE_TABLE(of, simple_encoder_dt_match); + +struct platform_driver simple_encoder_driver = { + .probe = vs_encoder_probe, + .remove = vs_encoder_remove, + .driver = { + .name = "vs-simple-encoder", + .of_match_table = of_match_ptr(simple_encoder_dt_match), + }, +}; + +MODULE_DESCRIPTION("Simple Encoder Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.h b/drivers/gpu/drm/verisilicon/vs_simple_enc.h new file mode 100644 index 000000000000..73e356bfeb2c --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_SIMPLE_ENC_H_ +#define __VS_SIMPLE_ENC_H_ + +#include + +struct simple_encoder_priv { + unsigned char encoder_type; +}; + +struct vs_simple_encoder { + struct drm_encoder encoder; + struct device *dev; + const struct simple_encoder_priv *priv; + struct regmap *dss_regmap; + unsigned int offset; + unsigned int mask; +}; + +extern struct platform_driver simple_encoder_driver; +#endif /* __VS_SIMPLE_ENC_H_ */