From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 95BF3C7EE29 for ; Mon, 29 May 2023 14:36:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229924AbjE2Ogs (ORCPT ); Mon, 29 May 2023 10:36:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229845AbjE2Ogm (ORCPT ); Mon, 29 May 2023 10:36:42 -0400 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10896B5 for ; Mon, 29 May 2023 07:36:40 -0700 (PDT) Received: by mail-ed1-x529.google.com with SMTP id 4fb4d7f45d1cf-51458187be1so5892204a12.2 for ; Mon, 29 May 2023 07:36:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685370998; x=1687962998; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Imn+CVwrZJtyv1pmcN9LMeOD3o4qWPh5+WMlc2rK8js=; b=mfkgAqW6EihS8kP8YQKChzyGM1xJlZeIAmp6lE5FzcBG6BVtF4TNGRCr0oLmJPVQT4 e7eGblhBxM/QbJCa5pIIAdjeIgfoFzqAdlelFZRT8/IAKoxdhEGRJbag4oS1VZv4YFOJ axLQ/Fo1l2hj6PhA3FZgOcPvt8jO3sprWPDhjsWI+gddAy9QzGj8i3ycSskytWN5x90k VxuIPpf1kaYnDaNwqMQYg7PMp9dtVoqTOqRUoRd7YVH2OK+g9QuoT2u3QG7cV9w4Vb7J KihElyPFF6u0TVaH5mXpSJLVZ3cOc3xqJpY7K8W4mLt5dP3oNbB/hievVGGY1l2aDMVp OzXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685370998; x=1687962998; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Imn+CVwrZJtyv1pmcN9LMeOD3o4qWPh5+WMlc2rK8js=; b=R0rcXPS+5Kc9HWjPNpzOJZBPWXnKm+iE5ZwkOKkqazkiXD5KLpjwZd2gSXAfwYwrVM fe9upKD6XaGbUK548+nQoynRazaRAnJCgOMMI7iiVMXwrxnMw3ES7/XQmjTuqLMEEox8 +yRR85Mjzfrzhi+SxI3MTuO6OHTGcCjEdw6vMTfuY9R6IeiSlg4ZdtXB740N6UTe4GhL f+Boy4mjocRecDLHcvMbdMnloKTZh32JpGMnFY/vda/r0CI9r+eqh2hl/7p/YXQL3bFj euKNqZzo778/NWAMH5N/cAX83yhrYNaeMr7P3MD6/MJiM+T5KDFej70q39BPT9nGRby2 ahGQ== X-Gm-Message-State: AC+VfDwhBSXiItRUYxthmD/4nsVWXKQfC4p98dxylNv3xLkBVPQaOG2/ 8h3o+KNh4/AuIB3yVxU7F8mTlQ== X-Google-Smtp-Source: ACHHUZ6HAi8OaiQCSTcRK5XREAVu/RA9lyqnqLEhBW3lss9xJehOUE8vu/vjAXFRGN/nRQr/mN6UVQ== X-Received: by 2002:a17:907:1c0d:b0:96b:4ed5:a1d8 with SMTP id nc13-20020a1709071c0d00b0096b4ed5a1d8mr12615395ejc.36.1685370998453; Mon, 29 May 2023 07:36:38 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:37 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:30:58 +0200 Subject: [PATCH v4 1/8] dt-bindings: display: mediatek: add MT8195 hdmi bindings MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-1-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add mt8195 SoC bindings for hdmi and hdmi-ddc On mt8195 the ddc i2c controller is part of the hdmi IP block and thus has = no specific register range, power domain or interrupt, making it simpler than the legacy "mediatek,hdmi-ddc" binding. Signed-off-by: Guillaume Ranquet --- .../bindings/display/mediatek/mediatek,hdmi.yaml | 59 ++++++++++++++++++= ---- .../display/mediatek/mediatek,mt8195-hdmi-ddc.yaml | 45 +++++++++++++++++ 2 files changed, 93 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,hd= mi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,hdmi.= yaml index b90b6d18a828..4f62e6b94048 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,hdmi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,hdmi.yaml @@ -21,6 +21,7 @@ properties: - mediatek,mt7623-hdmi - mediatek,mt8167-hdmi - mediatek,mt8173-hdmi + - mediatek,mt8195-hdmi =20 reg: maxItems: 1 @@ -29,18 +30,10 @@ properties: maxItems: 1 =20 clocks: - items: - - description: Pixel Clock - - description: HDMI PLL - - description: Bit Clock - - description: S/PDIF Clock + maxItems: 4 =20 clock-names: - items: - - const: pixel - - const: pll - - const: bclk - - const: spdif + maxItems: 4 =20 phys: maxItems: 1 @@ -58,6 +51,9 @@ properties: description: | phandle link and register offset to the system configuration registe= rs. =20 + power-domains: + maxItems: 1 + ports: $ref: /schemas/graph.yaml#/properties/ports =20 @@ -86,9 +82,50 @@ required: - clock-names - phys - phy-names - - mediatek,syscon-hdmi - ports =20 +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt8195-hdmi + then: + properties: + clocks: + items: + - description: APB + - description: HDCP + - description: HDCP 24M + - description: Split HDMI + clock-names: + items: + - const: hdmi_apb_sel + - const: hdcp_sel + - const: hdcp24_sel + - const: split_hdmi + + required: + - power-domains + else: + properties: + clocks: + items: + - description: Pixel Clock + - description: HDMI PLL + - description: Bit Clock + - description: S/PDIF Clock + + clock-names: + items: + - const: pixel + - const: pll + - const: bclk + - const: spdif + + required: + - mediatek,syscon-hdmi + additionalProperties: false =20 examples: diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt= 8195-hdmi-ddc.yaml b/Documentation/devicetree/bindings/display/mediatek/med= iatek,mt8195-hdmi-ddc.yaml new file mode 100644 index 000000000000..84c096835b47 --- /dev/null +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8195-hd= mi-ddc.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8195-hdmi-d= dc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek HDMI DDC for mt8195 + +maintainers: + - CK Hu + - Jitao shi + +description: | + The HDMI DDC i2c controller is used to interface with the HDMI DDC pins. + +properties: + compatible: + enum: + - mediatek,mt8195-hdmi-ddc + + clocks: + maxItems: 1 + + mediatek,hdmi: + $ref: /schemas/types.yaml#/definitions/phandle + description: + A phandle to the mt8195 hdmi controller + +required: + - compatible + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + hdmiddc0: i2c { + compatible =3D "mediatek,mt8195-hdmi-ddc"; + mediatek,hdmi =3D <&hdmi0>; + clocks =3D <&clk26m>; + }; + +... --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B315C77B7E for ; Mon, 29 May 2023 14:36:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229931AbjE2Ogv (ORCPT ); Mon, 29 May 2023 10:36:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229728AbjE2Ogo (ORCPT ); Mon, 29 May 2023 10:36:44 -0400 Received: from mail-ed1-x531.google.com (mail-ed1-x531.google.com [IPv6:2a00:1450:4864:20::531]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B0A7DD9 for ; Mon, 29 May 2023 07:36:41 -0700 (PDT) Received: by mail-ed1-x531.google.com with SMTP id 4fb4d7f45d1cf-510d6b939bfso6079974a12.0 for ; Mon, 29 May 2023 07:36:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371000; x=1687963000; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=H1juTYdxx/zPU0UJfM+zaRoUsw2VCwwOKhQQjPGU/Zg=; b=Pr+0ztUOv76Fb3oLHL1LQs3y0i0KaxGQ64Fgm8oWUEvQEax+h9Qfu3xurwJM7MH+jj QaInhBGgltvdn4lQIGH8oovRENsoYFCE9UthIRuA/4E5aU69PUFsBH9BslyZh4SPTxT4 R21YvdNXdybicEVUH8NTBqbezqIM6NyAXO3tMH8ISWd5S3YmkYIKkt5+Y0nJyakGQ5p3 a2ovn/ttfhBHCkOsQ4zmUi1I232L/Da1/jr+z1pCA3GBSsVXLcJzfVh89MfIIVstYpGP y2JNk8EGr4O6lovR2CjjhikNkptIlZgjtZuAf8Jl7NpckBjlPNj3T8SBQg8Pb3XtjwO8 XB2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371000; x=1687963000; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=H1juTYdxx/zPU0UJfM+zaRoUsw2VCwwOKhQQjPGU/Zg=; b=g+np5r+IclpeFj5B9Xc64vY19dmz0h43jEkm8ALUYh54dcBNVCnNTAufka7EdJLmOV fwZzI/KSGUpcbk/bfeDPoEAVJk6taToG0IGgBkzHY+NOo7S6LqUlWuR6SIl3OesTV3BH SO9hG8OOJXg9M2ePzewl+9J4qk6KRPtcG7mp+VpLP4KzgD6uyv1J1yjdYEqN1jTfyQPa xQr7cZAhA6W3SH9/r/85j8E0jtj4Wo8qocb96+btlULbs2U0J2wwRURzWbTuANMjoTgM hSg89BOBhwV7uPGAIwD8jrIDi3KMBdS39XGK5Nvsbqk6SywRP9BXSbvRLYXzZrMt68MM ZPUA== X-Gm-Message-State: AC+VfDysw6y5RjdwXJ85Pc1wAWydxgvkz+F4LIchnymNvd4sX5lET3n0 56fAuZY14JEC6L7NHBbsu4e4xA== X-Google-Smtp-Source: ACHHUZ6Ze5FPsqg3F+sPh0WpnG0nPJS0QU5k7CSZA8uOAGOzHIbumawDmkITfnLDC/12rMTbtP94gQ== X-Received: by 2002:a17:906:58c4:b0:961:78c2:1d27 with SMTP id e4-20020a17090658c400b0096178c21d27mr11332426ejs.19.1685371000068; Mon, 29 May 2023 07:36:40 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:39 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:30:59 +0200 Subject: [PATCH v4 2/8] drm/mediatek: hdmi: use a regmap instead of iomem MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-2-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org To prepare support for newer chips that need to share their address range with a dedicated ddc driver, use a regmap. Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 173 ++++++++++++++------------------= ---- 1 file changed, 65 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek= /mtk_hdmi.c index 0a8e0a13f516..b526a88663e7 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -171,7 +171,7 @@ struct mtk_hdmi { u32 ibias_up; struct regmap *sys_regmap; unsigned int sys_offset; - void __iomem *regs; + struct regmap *regs; enum hdmi_colorspace csp; struct hdmi_audio_param aud_param; bool audio_enable; @@ -187,50 +187,10 @@ static inline struct mtk_hdmi *hdmi_ctx_from_bridge(s= truct drm_bridge *b) return container_of(b, struct mtk_hdmi, bridge); } =20 -static u32 mtk_hdmi_read(struct mtk_hdmi *hdmi, u32 offset) -{ - return readl(hdmi->regs + offset); -} - -static void mtk_hdmi_write(struct mtk_hdmi *hdmi, u32 offset, u32 val) -{ - writel(val, hdmi->regs + offset); -} - -static void mtk_hdmi_clear_bits(struct mtk_hdmi *hdmi, u32 offset, u32 bit= s) -{ - void __iomem *reg =3D hdmi->regs + offset; - u32 tmp; - - tmp =3D readl(reg); - tmp &=3D ~bits; - writel(tmp, reg); -} - -static void mtk_hdmi_set_bits(struct mtk_hdmi *hdmi, u32 offset, u32 bits) -{ - void __iomem *reg =3D hdmi->regs + offset; - u32 tmp; - - tmp =3D readl(reg); - tmp |=3D bits; - writel(tmp, reg); -} - -static void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 = mask) -{ - void __iomem *reg =3D hdmi->regs + offset; - u32 tmp; - - tmp =3D readl(reg); - tmp =3D (tmp & ~mask) | (val & mask); - writel(tmp, reg); -} - static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) { - mtk_hdmi_mask(hdmi, VIDEO_CFG_4, black ? GEN_RGB : NORMAL_PATH, - VIDEO_SOURCE_SEL); + regmap_update_bits(hdmi->regs, VIDEO_SOURCE_SEL, + VIDEO_CFG_4, black ? GEN_RGB : NORMAL_PATH); } =20 static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enab= le) @@ -265,12 +225,12 @@ static void mtk_hdmi_hw_1p4_version_enable(struct mtk= _hdmi *hdmi, bool enable) =20 static void mtk_hdmi_hw_aud_mute(struct mtk_hdmi *hdmi) { - mtk_hdmi_set_bits(hdmi, GRL_AUDIO_CFG, AUDIO_ZERO); + regmap_set_bits(hdmi->regs, GRL_AUDIO_CFG, AUDIO_ZERO); } =20 static void mtk_hdmi_hw_aud_unmute(struct mtk_hdmi *hdmi) { - mtk_hdmi_clear_bits(hdmi, GRL_AUDIO_CFG, AUDIO_ZERO); + regmap_clear_bits(hdmi->regs, GRL_AUDIO_CFG, AUDIO_ZERO); } =20 static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi) @@ -279,25 +239,25 @@ static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi) HDMI_RST, HDMI_RST); regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG1C, HDMI_RST, 0); - mtk_hdmi_clear_bits(hdmi, GRL_CFG3, CFG3_CONTROL_PACKET_DELAY); + regmap_clear_bits(hdmi->regs, GRL_CFG3, CFG3_CONTROL_PACKET_DELAY); regmap_update_bits(hdmi->sys_regmap, hdmi->sys_offset + HDMI_SYS_CFG1C, ANLG_ON, ANLG_ON); } =20 static void mtk_hdmi_hw_enable_notice(struct mtk_hdmi *hdmi, bool enable_n= otice) { - mtk_hdmi_mask(hdmi, GRL_CFG2, enable_notice ? CFG2_NOTICE_EN : 0, - CFG2_NOTICE_EN); + regmap_update_bits(hdmi->regs, GRL_CFG2, CFG2_NOTICE_EN, + enable_notice ? CFG2_NOTICE_EN : 0); } =20 static void mtk_hdmi_hw_write_int_mask(struct mtk_hdmi *hdmi, u32 int_mask) { - mtk_hdmi_write(hdmi, GRL_INT_MASK, int_mask); + regmap_write(hdmi->regs, GRL_INT_MASK, int_mask); } =20 static void mtk_hdmi_hw_enable_dvi_mode(struct mtk_hdmi *hdmi, bool enable) { - mtk_hdmi_mask(hdmi, GRL_CFG1, enable ? CFG1_DVI : 0, CFG1_DVI); + regmap_update_bits(hdmi->regs, GRL_CFG1, CFG1_DVI, enable ? CFG1_DVI : 0); } =20 static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer, @@ -343,22 +303,22 @@ static void mtk_hdmi_hw_send_info_frame(struct mtk_hd= mi *hdmi, u8 *buffer, dev_err(hdmi->dev, "Unknown infoframe type %d\n", frame_type); return; } - mtk_hdmi_clear_bits(hdmi, ctrl_reg, ctrl_frame_en); - mtk_hdmi_write(hdmi, GRL_INFOFRM_TYPE, frame_type); - mtk_hdmi_write(hdmi, GRL_INFOFRM_VER, frame_ver); - mtk_hdmi_write(hdmi, GRL_INFOFRM_LNG, frame_len); + regmap_clear_bits(hdmi->regs, ctrl_reg, ctrl_frame_en); + regmap_write(hdmi->regs, GRL_INFOFRM_TYPE, frame_type); + regmap_write(hdmi->regs, GRL_INFOFRM_VER, frame_ver); + regmap_write(hdmi->regs, GRL_INFOFRM_LNG, frame_len); =20 - mtk_hdmi_write(hdmi, GRL_IFM_PORT, checksum); + regmap_write(hdmi->regs, GRL_IFM_PORT, checksum); for (i =3D 0; i < frame_len; i++) - mtk_hdmi_write(hdmi, GRL_IFM_PORT, frame_data[i]); + regmap_write(hdmi->regs, GRL_IFM_PORT, frame_data[i]); =20 - mtk_hdmi_set_bits(hdmi, ctrl_reg, ctrl_frame_en); + regmap_set_bits(hdmi->regs, ctrl_reg, ctrl_frame_en); } =20 static void mtk_hdmi_hw_send_aud_packet(struct mtk_hdmi *hdmi, bool enable) { - mtk_hdmi_mask(hdmi, GRL_SHIFT_R2, enable ? 0 : AUDIO_PACKET_OFF, - AUDIO_PACKET_OFF); + regmap_update_bits(hdmi->regs, AUDIO_PACKET_OFF, + GRL_SHIFT_R2, enable ? 0 : AUDIO_PACKET_OFF); } =20 static void mtk_hdmi_hw_config_sys(struct mtk_hdmi *hdmi) @@ -379,44 +339,44 @@ static void mtk_hdmi_hw_set_deep_color_mode(struct mt= k_hdmi *hdmi) =20 static void mtk_hdmi_hw_send_av_mute(struct mtk_hdmi *hdmi) { - mtk_hdmi_clear_bits(hdmi, GRL_CFG4, CTRL_AVMUTE); + regmap_clear_bits(hdmi->regs, GRL_CFG4, CTRL_AVMUTE); usleep_range(2000, 4000); - mtk_hdmi_set_bits(hdmi, GRL_CFG4, CTRL_AVMUTE); + regmap_set_bits(hdmi->regs, GRL_CFG4, CTRL_AVMUTE); } =20 static void mtk_hdmi_hw_send_av_unmute(struct mtk_hdmi *hdmi) { - mtk_hdmi_mask(hdmi, GRL_CFG4, CFG4_AV_UNMUTE_EN, - CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET); + regmap_update_bits(hdmi->regs, GRL_CFG4, CFG4_AV_UNMUTE_EN | CFG4_AV_UNMU= TE_SET, + CFG4_AV_UNMUTE_EN); usleep_range(2000, 4000); - mtk_hdmi_mask(hdmi, GRL_CFG4, CFG4_AV_UNMUTE_SET, - CFG4_AV_UNMUTE_EN | CFG4_AV_UNMUTE_SET); + regmap_update_bits(hdmi->regs, GRL_CFG4, CFG4_AV_UNMUTE_EN | CFG4_AV_UNMU= TE_SET, + CFG4_AV_UNMUTE_SET); } =20 static void mtk_hdmi_hw_ncts_enable(struct mtk_hdmi *hdmi, bool on) { - mtk_hdmi_mask(hdmi, GRL_CTS_CTRL, on ? 0 : CTS_CTRL_SOFT, - CTS_CTRL_SOFT); + regmap_update_bits(hdmi->regs, GRL_CTS_CTRL,CTS_CTRL_SOFT, + on ? 0 : CTS_CTRL_SOFT); } =20 static void mtk_hdmi_hw_ncts_auto_write_enable(struct mtk_hdmi *hdmi, bool enable) { - mtk_hdmi_mask(hdmi, GRL_CTS_CTRL, enable ? NCTS_WRI_ANYTIME : 0, - NCTS_WRI_ANYTIME); + regmap_update_bits(hdmi->regs, GRL_CTS_CTRL, NCTS_WRI_ANYTIME, + enable ? NCTS_WRI_ANYTIME : 0); } =20 static void mtk_hdmi_hw_msic_setting(struct mtk_hdmi *hdmi, struct drm_display_mode *mode) { - mtk_hdmi_clear_bits(hdmi, GRL_CFG4, CFG4_MHL_MODE); + regmap_clear_bits(hdmi->regs, GRL_CFG4, CFG4_MHL_MODE); =20 if (mode->flags & DRM_MODE_FLAG_INTERLACE && mode->clock =3D=3D 74250 && mode->vdisplay =3D=3D 1080) - mtk_hdmi_clear_bits(hdmi, GRL_CFG2, CFG2_MHL_DE_SEL); + regmap_clear_bits(hdmi->regs, GRL_CFG2, CFG2_MHL_DE_SEL); else - mtk_hdmi_set_bits(hdmi, GRL_CFG2, CFG2_MHL_DE_SEL); + regmap_set_bits(hdmi->regs, GRL_CFG2, CFG2_MHL_DE_SEL); } =20 static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk_hdmi *hdmi, @@ -444,7 +404,7 @@ static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk= _hdmi *hdmi, swap_bit =3D LFE_CC_SWAP; break; } - mtk_hdmi_mask(hdmi, GRL_CH_SWAP, swap_bit, 0xff); + regmap_update_bits(hdmi->regs, GRL_CH_SWAP, 0xff, swap_bit); } =20 static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi *hdmi, @@ -465,7 +425,7 @@ static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi= *hdmi, break; } =20 - mtk_hdmi_mask(hdmi, GRL_AOUT_CFG, val, AOUT_BNUM_SEL_MASK); + regmap_update_bits(hdmi->regs, GRL_AOUT_CFG, AOUT_BNUM_SEL_MASK, val); } =20 static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi, @@ -473,7 +433,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi= *hdmi, { u32 val; =20 - val =3D mtk_hdmi_read(hdmi, GRL_CFG0); + regmap_read(hdmi->regs, GRL_CFG0, &val); val &=3D ~(CFG0_W_LENGTH_MASK | CFG0_I2S_MODE_MASK); =20 switch (i2s_fmt) { @@ -497,7 +457,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi= *hdmi, val |=3D CFG0_I2S_MODE_I2S | CFG0_W_LENGTH_16BIT; break; } - mtk_hdmi_write(hdmi, GRL_CFG0, val); + regmap_write(hdmi->regs, GRL_CFG0, val); } =20 static void mtk_hdmi_hw_audio_config(struct mtk_hdmi *hdmi, bool dst) @@ -506,14 +466,14 @@ static void mtk_hdmi_hw_audio_config(struct mtk_hdmi = *hdmi, bool dst) u8 val; =20 /* Disable high bitrate, set DST packet normal/double */ - mtk_hdmi_clear_bits(hdmi, GRL_AOUT_CFG, HIGH_BIT_RATE_PACKET_ALIGN); + regmap_clear_bits(hdmi->regs, GRL_AOUT_CFG, HIGH_BIT_RATE_PACKET_ALIGN); =20 if (dst) val =3D DST_NORMAL_DOUBLE | SACD_DST; else val =3D 0; =20 - mtk_hdmi_mask(hdmi, GRL_AUDIO_CFG, val, mask); + regmap_update_bits(hdmi->regs, GRL_AUDIO_CFG, mask, val); } =20 static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct mtk_hdmi *hdmi, @@ -554,10 +514,10 @@ static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct m= tk_hdmi *hdmi, i2s_uv =3D I2S_UV_CH_EN(0); } =20 - mtk_hdmi_write(hdmi, GRL_CH_SW0, ch_switch & 0xff); - mtk_hdmi_write(hdmi, GRL_CH_SW1, (ch_switch >> 8) & 0xff); - mtk_hdmi_write(hdmi, GRL_CH_SW2, (ch_switch >> 16) & 0xff); - mtk_hdmi_write(hdmi, GRL_I2S_UV, i2s_uv); + regmap_write(hdmi->regs, GRL_CH_SW0, ch_switch & 0xff); + regmap_write(hdmi->regs, GRL_CH_SW1, (ch_switch >> 8) & 0xff); + regmap_write(hdmi->regs, GRL_CH_SW2, (ch_switch >> 16) & 0xff); + regmap_write(hdmi->regs, GRL_I2S_UV, i2s_uv); } =20 static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi, @@ -565,7 +525,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_h= dmi *hdmi, { u32 val; =20 - val =3D mtk_hdmi_read(hdmi, GRL_CFG1); + regmap_read(hdmi->regs, GRL_CFG1, &val); if (input_type =3D=3D HDMI_AUD_INPUT_I2S && (val & CFG1_SPDIF) =3D=3D CFG1_SPDIF) { val &=3D ~CFG1_SPDIF; @@ -573,7 +533,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_h= dmi *hdmi, (val & CFG1_SPDIF) =3D=3D 0) { val |=3D CFG1_SPDIF; } - mtk_hdmi_write(hdmi, GRL_CFG1, val); + regmap_write(hdmi->regs, GRL_CFG1, val); } =20 static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi, @@ -582,13 +542,13 @@ static void mtk_hdmi_hw_aud_set_channel_status(struct= mtk_hdmi *hdmi, int i; =20 for (i =3D 0; i < 5; i++) { - mtk_hdmi_write(hdmi, GRL_I2S_C_STA0 + i * 4, channel_status[i]); - mtk_hdmi_write(hdmi, GRL_L_STATUS_0 + i * 4, channel_status[i]); - mtk_hdmi_write(hdmi, GRL_R_STATUS_0 + i * 4, channel_status[i]); + regmap_write(hdmi->regs, GRL_I2S_C_STA0 + i * 4, channel_status[i]); + regmap_write(hdmi->regs, GRL_L_STATUS_0 + i * 4, channel_status[i]); + regmap_write(hdmi->regs, GRL_R_STATUS_0 + i * 4, channel_status[i]); } for (; i < 24; i++) { - mtk_hdmi_write(hdmi, GRL_L_STATUS_0 + i * 4, 0); - mtk_hdmi_write(hdmi, GRL_R_STATUS_0 + i * 4, 0); + regmap_write(hdmi->regs, GRL_L_STATUS_0 + i * 4, 0); + regmap_write(hdmi->regs, GRL_R_STATUS_0 + i * 4, 0); } } =20 @@ -596,13 +556,13 @@ static void mtk_hdmi_hw_aud_src_reenable(struct mtk_h= dmi *hdmi) { u32 val; =20 - val =3D mtk_hdmi_read(hdmi, GRL_MIX_CTRL); + regmap_read(hdmi->regs, GRL_MIX_CTRL, &val); if (val & MIX_CTRL_SRC_EN) { val &=3D ~MIX_CTRL_SRC_EN; - mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val); + regmap_write(hdmi->regs, GRL_MIX_CTRL, val); usleep_range(255, 512); val |=3D MIX_CTRL_SRC_EN; - mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val); + regmap_write(hdmi->regs, GRL_MIX_CTRL, val); } } =20 @@ -610,10 +570,10 @@ static void mtk_hdmi_hw_aud_src_disable(struct mtk_hd= mi *hdmi) { u32 val; =20 - val =3D mtk_hdmi_read(hdmi, GRL_MIX_CTRL); + regmap_read(hdmi->regs, GRL_MIX_CTRL, &val); val &=3D ~MIX_CTRL_SRC_EN; - mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val); - mtk_hdmi_write(hdmi, GRL_SHIFT_L1, 0x00); + regmap_write(hdmi->regs, GRL_MIX_CTRL, val); + regmap_write(hdmi->regs, GRL_SHIFT_L1, 0x00); } =20 static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi, @@ -621,7 +581,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *h= dmi, { u32 val; =20 - val =3D mtk_hdmi_read(hdmi, GRL_CFG5); + regmap_read(hdmi->regs, GRL_CFG5, &val); val &=3D CFG5_CD_RATIO_MASK; =20 switch (mclk) { @@ -644,7 +604,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *h= dmi, val |=3D CFG5_FS256; break; } - mtk_hdmi_write(hdmi, GRL_CFG5, val); + regmap_write(hdmi->regs, GRL_CFG5, val); } =20 struct hdmi_acr_n { @@ -728,9 +688,9 @@ static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hd= mi, unsigned int n, unsigned char val[NCTS_BYTES]; int i; =20 - mtk_hdmi_write(hdmi, GRL_NCTS, 0); - mtk_hdmi_write(hdmi, GRL_NCTS, 0); - mtk_hdmi_write(hdmi, GRL_NCTS, 0); + regmap_write(hdmi->regs, GRL_NCTS, 0); + regmap_write(hdmi->regs, GRL_NCTS, 0); + regmap_write(hdmi->regs, GRL_NCTS, 0); memset(val, 0, sizeof(val)); =20 val[0] =3D (cts >> 24) & 0xff; @@ -743,7 +703,7 @@ static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hd= mi, unsigned int n, val[6] =3D n & 0xff; =20 for (i =3D 0; i < NCTS_BYTES; i++) - mtk_hdmi_write(hdmi, GRL_NCTS, val[i]); + regmap_write(hdmi->regs, GRL_NCTS, val[i]); } =20 static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, @@ -758,8 +718,7 @@ static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *h= dmi, dev_dbg(hdmi->dev, "%s: sample_rate=3D%u, clock=3D%d, cts=3D%u, n=3D%u\n", __func__, sample_rate, clock, n, cts); =20 - mtk_hdmi_mask(hdmi, DUMMY_304, AUDIO_I2S_NCTS_SEL_64, - AUDIO_I2S_NCTS_SEL); + regmap_update_bits(hdmi->regs, DUMMY_304, AUDIO_I2S_NCTS_SEL, AUDIO_I2S_N= CTS_SEL_64); do_hdmi_hw_aud_set_ncts(hdmi, n, cts); } =20 @@ -879,7 +838,7 @@ static void mtk_hdmi_aud_set_input(struct mtk_hdmi *hdm= i) bool dst; =20 mtk_hdmi_hw_aud_set_channel_swap(hdmi, HDMI_AUD_SWAP_LFE_CC); - mtk_hdmi_set_bits(hdmi, GRL_MIX_CTRL, MIX_CTRL_FLAT); + regmap_set_bits(hdmi->regs, GRL_MIX_CTRL, MIX_CTRL_FLAT); =20 if (hdmi->aud_param.aud_input_type =3D=3D HDMI_AUD_INPUT_SPDIF && hdmi->aud_param.aud_codec =3D=3D HDMI_AUDIO_CODING_TYPE_DST) { @@ -911,7 +870,7 @@ static int mtk_hdmi_aud_set_src(struct mtk_hdmi *hdmi, =20 mtk_hdmi_hw_ncts_enable(hdmi, false); mtk_hdmi_hw_aud_src_disable(hdmi); - mtk_hdmi_clear_bits(hdmi, GRL_CFG2, CFG2_ACLK_INV); + regmap_clear_bits(hdmi->regs, GRL_CFG2, CFG2_ACLK_INV); =20 if (hdmi->aud_param.aud_input_type =3D=3D HDMI_AUD_INPUT_I2S) { switch (sample_rate) { @@ -1428,7 +1387,6 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *h= dmi, struct device_node *cec_np, *remote, *i2c_np; struct platform_device *cec_pdev; struct regmap *regmap; - struct resource *mem; int ret; =20 ret =3D mtk_hdmi_get_all_clk(hdmi, np); @@ -1474,8 +1432,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *h= dmi, } hdmi->sys_regmap =3D regmap; =20 - mem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdmi->regs =3D devm_ioremap_resource(dev, mem); + hdmi->regs =3D device_node_to_regmap(dev->of_node); if (IS_ERR(hdmi->regs)) { ret =3D PTR_ERR(hdmi->regs); goto put_device; --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA749C7EE23 for ; Mon, 29 May 2023 14:37:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230027AbjE2OhD (ORCPT ); Mon, 29 May 2023 10:37:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229907AbjE2Ogr (ORCPT ); Mon, 29 May 2023 10:36:47 -0400 Received: from mail-ej1-x62d.google.com (mail-ej1-x62d.google.com [IPv6:2a00:1450:4864:20::62d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61E3DA0 for ; Mon, 29 May 2023 07:36:43 -0700 (PDT) Received: by mail-ej1-x62d.google.com with SMTP id a640c23a62f3a-96fffe11714so626026666b.0 for ; Mon, 29 May 2023 07:36:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371002; x=1687963002; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=bV+0Nk5+Xy7cZrFq7WTQ2C2LD8ohvxxBKWBemBI+w9A=; b=h9nJLKAuSfl63CZBKrAVeZb1Xcxh/JTcy6NYEPMXq6e3fMl5lzK8bqF0a72e1+oKlG 43ZPC8zXWz+uosFNOCn3NqDrm3KVFncDO3isFtXuW32SVuxUZdGz1O5bNseCYDw/yJ/k MURX8MarGaHmyCX7tDMk7x/uasUdG0s8ZrtGgRvqqqo1xyhi+7qivNJ8LyMZJkQihVOn tYGhqyA9MSRumji4wYlVA8qdhs8Rf7dvNeVAF2IVJegEwJEXhnmkNY8gyIjgprGwIw5O xFygnnmlWm8rIB0PWA6ZO4gRO6JoDDBUwa7jiIKoRGxRzv5dQc8gorMjlHf4lawxx6Gt X0aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371002; x=1687963002; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bV+0Nk5+Xy7cZrFq7WTQ2C2LD8ohvxxBKWBemBI+w9A=; b=bPNSn4HKQwoUTSeyNsmhvDJUBjddDRmUc91b5Ob70PI83EO8rtWBOTMApTjOoFarJ+ klI4Ra9gNHb00uh77Xa+Nrgsyd0HNN3G9bCLs1BaYZcUpR5YjlFZvu/fK8RWJ1BAjF8c 2Bh54EuJ8pNI7G36PW9tdBmhF4MHwM4fwggBVBkA9vl9+olW5sRMTXLCHo41jNbLZt84 iZlnsUgYiBQlRpzXpKNZec+Q7uLC1rp4yfAxZNm2kL5stVwpI1rpLNsKfSJHW8CZHzJU DPGVFcEC3wcEC4g1HJzBfVEnqx9hWPA3uheJ6+g5lSefo+8B/zzJSHXI+LoacjaWvPTu rVug== X-Gm-Message-State: AC+VfDyvZF0dMN7fbhd09Uzw3SL3jSEPA33lJxV3PSUk7qGrQI1PKqaI 38Z/xIlVg/LsSGZ2Ji5iYv4PYA== X-Google-Smtp-Source: ACHHUZ7Mzve9Fx/NmyyiWZj/M+AoQznA7qJOk+EQFMREfcmFIiKjaBiLSATOjCXTFs/8NWp1Qd1xqQ== X-Received: by 2002:a17:907:72c7:b0:96f:87ae:49eb with SMTP id du7-20020a17090772c700b0096f87ae49ebmr10850770ejc.16.1685371001755; Mon, 29 May 2023 07:36:41 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:41 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:00 +0200 Subject: [PATCH v4 3/8] drm/mediatek: extract common functions from the mtk hdmi driver MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-3-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Create a common "framework" that can be used to add support for different hdmi IPs within the mediatek range of products. Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/Makefile | 3 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 596 ++-----------------------= ---- drivers/gpu/drm/mediatek/mtk_hdmi.h | 18 + drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 407 ++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_hdmi_common.h | 207 ++++++++++ 5 files changed, 666 insertions(+), 565 deletions(-) diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/M= akefile index d4d193f60271..79bbaa58893e 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -22,7 +22,8 @@ obj-$(CONFIG_DRM_MEDIATEK) +=3D mediatek-drm.o =20 mediatek-drm-hdmi-objs :=3D mtk_cec.o \ mtk_hdmi.o \ - mtk_hdmi_ddc.o + mtk_hdmi_common.o \ + mtk_hdmi_ddc.o \ =20 obj-$(CONFIG_DRM_MEDIATEK_HDMI) +=3D mediatek-drm-hdmi.o =20 diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek= /mtk_hdmi.c index b526a88663e7..41a7593887fb 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -31,162 +31,18 @@ #include =20 #include "mtk_cec.h" -#include "mtk_hdmi.h" +#include "mtk_hdmi_common.h" #include "mtk_hdmi_regs.h" =20 #define NCTS_BYTES 7 =20 -enum mtk_hdmi_clk_id { - MTK_HDMI_CLK_HDMI_PIXEL, - MTK_HDMI_CLK_HDMI_PLL, - MTK_HDMI_CLK_AUD_BCLK, - MTK_HDMI_CLK_AUD_SPDIF, - MTK_HDMI_CLK_COUNT +const char * const mtk_hdmi_clk_names_v1[MTK_HDMIV1_CLK_COUNT] =3D { + [MTK_HDMIV1_CLK_HDMI_PIXEL] =3D "pixel", + [MTK_HDMIV1_CLK_HDMI_PLL] =3D "pll", + [MTK_HDMIV1_CLK_AUD_BCLK] =3D "bclk", + [MTK_HDMIV1_CLK_AUD_SPDIF] =3D "spdif", }; =20 -enum hdmi_aud_input_type { - HDMI_AUD_INPUT_I2S =3D 0, - HDMI_AUD_INPUT_SPDIF, -}; - -enum hdmi_aud_i2s_fmt { - HDMI_I2S_MODE_RJT_24BIT =3D 0, - HDMI_I2S_MODE_RJT_16BIT, - HDMI_I2S_MODE_LJT_24BIT, - HDMI_I2S_MODE_LJT_16BIT, - HDMI_I2S_MODE_I2S_24BIT, - HDMI_I2S_MODE_I2S_16BIT -}; - -enum hdmi_aud_mclk { - HDMI_AUD_MCLK_128FS, - HDMI_AUD_MCLK_192FS, - HDMI_AUD_MCLK_256FS, - HDMI_AUD_MCLK_384FS, - HDMI_AUD_MCLK_512FS, - HDMI_AUD_MCLK_768FS, - HDMI_AUD_MCLK_1152FS, -}; - -enum hdmi_aud_channel_type { - HDMI_AUD_CHAN_TYPE_1_0 =3D 0, - HDMI_AUD_CHAN_TYPE_1_1, - HDMI_AUD_CHAN_TYPE_2_0, - HDMI_AUD_CHAN_TYPE_2_1, - HDMI_AUD_CHAN_TYPE_3_0, - HDMI_AUD_CHAN_TYPE_3_1, - HDMI_AUD_CHAN_TYPE_4_0, - HDMI_AUD_CHAN_TYPE_4_1, - HDMI_AUD_CHAN_TYPE_5_0, - HDMI_AUD_CHAN_TYPE_5_1, - HDMI_AUD_CHAN_TYPE_6_0, - HDMI_AUD_CHAN_TYPE_6_1, - HDMI_AUD_CHAN_TYPE_7_0, - HDMI_AUD_CHAN_TYPE_7_1, - HDMI_AUD_CHAN_TYPE_3_0_LRS, - HDMI_AUD_CHAN_TYPE_3_1_LRS, - HDMI_AUD_CHAN_TYPE_4_0_CLRS, - HDMI_AUD_CHAN_TYPE_4_1_CLRS, - HDMI_AUD_CHAN_TYPE_6_1_CS, - HDMI_AUD_CHAN_TYPE_6_1_CH, - HDMI_AUD_CHAN_TYPE_6_1_OH, - HDMI_AUD_CHAN_TYPE_6_1_CHR, - HDMI_AUD_CHAN_TYPE_7_1_LH_RH, - HDMI_AUD_CHAN_TYPE_7_1_LSR_RSR, - HDMI_AUD_CHAN_TYPE_7_1_LC_RC, - HDMI_AUD_CHAN_TYPE_7_1_LW_RW, - HDMI_AUD_CHAN_TYPE_7_1_LSD_RSD, - HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS, - HDMI_AUD_CHAN_TYPE_7_1_LHS_RHS, - HDMI_AUD_CHAN_TYPE_7_1_CS_CH, - HDMI_AUD_CHAN_TYPE_7_1_CS_OH, - HDMI_AUD_CHAN_TYPE_7_1_CS_CHR, - HDMI_AUD_CHAN_TYPE_7_1_CH_OH, - HDMI_AUD_CHAN_TYPE_7_1_CH_CHR, - HDMI_AUD_CHAN_TYPE_7_1_OH_CHR, - HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS_LSR_RSR, - HDMI_AUD_CHAN_TYPE_6_0_CS, - HDMI_AUD_CHAN_TYPE_6_0_CH, - HDMI_AUD_CHAN_TYPE_6_0_OH, - HDMI_AUD_CHAN_TYPE_6_0_CHR, - HDMI_AUD_CHAN_TYPE_7_0_LH_RH, - HDMI_AUD_CHAN_TYPE_7_0_LSR_RSR, - HDMI_AUD_CHAN_TYPE_7_0_LC_RC, - HDMI_AUD_CHAN_TYPE_7_0_LW_RW, - HDMI_AUD_CHAN_TYPE_7_0_LSD_RSD, - HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS, - HDMI_AUD_CHAN_TYPE_7_0_LHS_RHS, - HDMI_AUD_CHAN_TYPE_7_0_CS_CH, - HDMI_AUD_CHAN_TYPE_7_0_CS_OH, - HDMI_AUD_CHAN_TYPE_7_0_CS_CHR, - HDMI_AUD_CHAN_TYPE_7_0_CH_OH, - HDMI_AUD_CHAN_TYPE_7_0_CH_CHR, - HDMI_AUD_CHAN_TYPE_7_0_OH_CHR, - HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS_LSR_RSR, - HDMI_AUD_CHAN_TYPE_8_0_LH_RH_CS, - HDMI_AUD_CHAN_TYPE_UNKNOWN =3D 0xFF -}; - -enum hdmi_aud_channel_swap_type { - HDMI_AUD_SWAP_LR, - HDMI_AUD_SWAP_LFE_CC, - HDMI_AUD_SWAP_LSRS, - HDMI_AUD_SWAP_RLS_RRS, - HDMI_AUD_SWAP_LR_STATUS, -}; - -struct hdmi_audio_param { - enum hdmi_audio_coding_type aud_codec; - enum hdmi_audio_sample_size aud_sampe_size; - enum hdmi_aud_input_type aud_input_type; - enum hdmi_aud_i2s_fmt aud_i2s_fmt; - enum hdmi_aud_mclk aud_mclk; - enum hdmi_aud_channel_type aud_input_chan_type; - struct hdmi_codec_params codec_params; -}; - -struct mtk_hdmi_conf { - bool tz_disabled; - bool cea_modes_only; - unsigned long max_mode_clock; -}; - -struct mtk_hdmi { - struct drm_bridge bridge; - struct drm_bridge *next_bridge; - struct drm_connector *curr_conn;/* current connector (only valid when 'en= abled') */ - struct device *dev; - const struct mtk_hdmi_conf *conf; - struct phy *phy; - struct device *cec_dev; - struct i2c_adapter *ddc_adpt; - struct clk *clk[MTK_HDMI_CLK_COUNT]; - struct drm_display_mode mode; - bool dvi_mode; - u32 min_clock; - u32 max_clock; - u32 max_hdisplay; - u32 max_vdisplay; - u32 ibias; - u32 ibias_up; - struct regmap *sys_regmap; - unsigned int sys_offset; - struct regmap *regs; - enum hdmi_colorspace csp; - struct hdmi_audio_param aud_param; - bool audio_enable; - bool powered; - bool enabled; - hdmi_codec_plugged_cb plugged_cb; - struct device *codec_dev; - struct mutex update_plugged_status_lock; -}; - -static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b) -{ - return container_of(b, struct mtk_hdmi, bridge); -} - static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) { regmap_update_bits(hdmi->regs, VIDEO_SOURCE_SEL, @@ -798,14 +654,14 @@ static int mtk_hdmi_video_change_vpll(struct mtk_hdmi= *hdmi, u32 clock) int ret; =20 /* The DPI driver already should have set TVDPLL to the correct rate */ - ret =3D clk_set_rate(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL], clock); + ret =3D clk_set_rate(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PLL], clock); if (ret) { dev_err(hdmi->dev, "Failed to set PLL to %u Hz: %d\n", clock, ret); return ret; } =20 - rate =3D clk_get_rate(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]); + rate =3D clk_get_rate(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PLL]); =20 if (DIV_ROUND_CLOSEST(rate, 1000) !=3D DIV_ROUND_CLOSEST(clock, 1000)) dev_warn(hdmi->dev, "Want PLL %u Hz, got %lu Hz\n", clock, @@ -830,7 +686,6 @@ static void mtk_hdmi_video_set_display_mode(struct mtk_= hdmi *hdmi, mtk_hdmi_hw_msic_setting(hdmi, mode); } =20 - static void mtk_hdmi_aud_set_input(struct mtk_hdmi *hdmi) { enum hdmi_aud_channel_type chan_type; @@ -921,56 +776,6 @@ static int mtk_hdmi_aud_output_config(struct mtk_hdmi = *hdmi, return 0; } =20 -static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi, - struct drm_display_mode *mode) -{ - struct hdmi_avi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - ssize_t err; - - err =3D drm_hdmi_avi_infoframe_from_display_mode(&frame, - hdmi->curr_conn, mode); - if (err < 0) { - dev_err(hdmi->dev, - "Failed to get AVI infoframe from mode: %zd\n", err); - return err; - } - - err =3D hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - dev_err(hdmi->dev, "Failed to pack AVI infoframe: %zd\n", err); - return err; - } - - mtk_hdmi_hw_send_info_frame(hdmi, buffer, sizeof(buffer)); - return 0; -} - -static int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi, - const char *vendor, - const char *product) -{ - struct hdmi_spd_infoframe frame; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_SPD_INFOFRAME_SIZE]; - ssize_t err; - - err =3D hdmi_spd_infoframe_init(&frame, vendor, product); - if (err < 0) { - dev_err(hdmi->dev, "Failed to initialize SPD infoframe: %zd\n", - err); - return err; - } - - err =3D hdmi_spd_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - dev_err(hdmi->dev, "Failed to pack SDP infoframe: %zd\n", err); - return err; - } - - mtk_hdmi_hw_send_info_frame(hdmi, buffer, sizeof(buffer)); - return 0; -} - static int mtk_hdmi_setup_audio_infoframe(struct mtk_hdmi *hdmi) { struct hdmi_audio_infoframe frame; @@ -1027,19 +832,16 @@ static int mtk_hdmi_setup_vendor_specific_infoframe(= struct mtk_hdmi *hdmi, return 0; } =20 -static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi) +void mtk_hdmi_output_init_mt8183(struct mtk_hdmi *hdmi) { struct hdmi_audio_param *aud_param =3D &hdmi->aud_param; =20 - hdmi->csp =3D HDMI_COLORSPACE_RGB; aud_param->aud_codec =3D HDMI_AUDIO_CODING_TYPE_PCM; aud_param->aud_sampe_size =3D HDMI_AUDIO_SAMPLE_SIZE_16; aud_param->aud_input_type =3D HDMI_AUD_INPUT_I2S; aud_param->aud_i2s_fmt =3D HDMI_I2S_MODE_I2S_24BIT; aud_param->aud_mclk =3D HDMI_AUD_MCLK_128FS; aud_param->aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_2_0; - - return 0; } =20 static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi) @@ -1096,49 +898,28 @@ static int mtk_hdmi_output_set_display_mode(struct m= tk_hdmi *hdmi, return 0; } =20 -static const char * const mtk_hdmi_clk_names[MTK_HDMI_CLK_COUNT] =3D { - [MTK_HDMI_CLK_HDMI_PIXEL] =3D "pixel", - [MTK_HDMI_CLK_HDMI_PLL] =3D "pll", - [MTK_HDMI_CLK_AUD_BCLK] =3D "bclk", - [MTK_HDMI_CLK_AUD_SPDIF] =3D "spdif", -}; - -static int mtk_hdmi_get_all_clk(struct mtk_hdmi *hdmi, - struct device_node *np) -{ - int i; - - for (i =3D 0; i < ARRAY_SIZE(mtk_hdmi_clk_names); i++) { - hdmi->clk[i] =3D of_clk_get_by_name(np, - mtk_hdmi_clk_names[i]); - if (IS_ERR(hdmi->clk[i])) - return PTR_ERR(hdmi->clk[i]); - } - return 0; -} - -static int mtk_hdmi_clk_enable_audio(struct mtk_hdmi *hdmi) +int mtk_hdmi_clk_enable_audio_mt8183(struct mtk_hdmi *hdmi) { int ret; =20 - ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_AUD_BCLK]); + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV1_CLK_AUD_BCLK]); if (ret) return ret; =20 - ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_AUD_SPDIF]); + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV1_CLK_AUD_SPDIF]); if (ret) goto err; =20 return 0; err: - clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_BCLK]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV1_CLK_AUD_BCLK]); return ret; } =20 -static void mtk_hdmi_clk_disable_audio(struct mtk_hdmi *hdmi) +void mtk_hdmi_clk_disable_audio_mt8183(struct mtk_hdmi *hdmi) { - clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_BCLK]); - clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_AUD_SPDIF]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV1_CLK_AUD_BCLK]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV1_CLK_AUD_SPDIF]); } =20 static enum drm_connector_status @@ -1224,21 +1005,6 @@ static enum drm_connector_status mtk_hdmi_bridge_det= ect(struct drm_bridge *bridg return mtk_hdmi_detect(hdmi); } =20 -static struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) -{ - struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); - struct edid *edid; - - if (!hdmi->ddc_adpt) - return NULL; - edid =3D drm_get_edid(connector, hdmi->ddc_adpt); - if (!edid) - return NULL; - hdmi->dvi_mode =3D !drm_detect_monitor_audio(edid); - return edid; -} - static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -1263,13 +1029,6 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge = *bridge, return 0; } =20 -static bool mtk_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void mtk_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { @@ -1279,8 +1038,8 @@ static void mtk_hdmi_bridge_atomic_disable(struct drm= _bridge *bridge, return; =20 phy_power_off(hdmi->phy); - clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]); - clk_disable_unprepare(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PIXEL]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PLL]); =20 hdmi->curr_conn =3D NULL; =20 @@ -1301,28 +1060,6 @@ static void mtk_hdmi_bridge_atomic_post_disable(stru= ct drm_bridge *bridge, hdmi->powered =3D false; } =20 -static void mtk_hdmi_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) -{ - struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); - - dev_dbg(hdmi->dev, "cur info: name:%s, hdisplay:%d\n", - adjusted_mode->name, adjusted_mode->hdisplay); - dev_dbg(hdmi->dev, "hsync_start:%d,hsync_end:%d, htotal:%d", - adjusted_mode->hsync_start, adjusted_mode->hsync_end, - adjusted_mode->htotal); - dev_dbg(hdmi->dev, "hskew:%d, vdisplay:%d\n", - adjusted_mode->hskew, adjusted_mode->vdisplay); - dev_dbg(hdmi->dev, "vsync_start:%d, vsync_end:%d, vtotal:%d", - adjusted_mode->vsync_start, adjusted_mode->vsync_end, - adjusted_mode->vtotal); - dev_dbg(hdmi->dev, "vscan:%d, flag:%d\n", - adjusted_mode->vscan, adjusted_mode->flags); - - drm_mode_copy(&hdmi->mode, adjusted_mode); -} - static void mtk_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_state) { @@ -1334,36 +1071,32 @@ static void mtk_hdmi_bridge_atomic_pre_enable(struc= t drm_bridge *bridge, hdmi->powered =3D true; } =20 -static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi, - struct drm_display_mode *mode) -{ - mtk_hdmi_setup_audio_infoframe(hdmi); - mtk_hdmi_setup_avi_infoframe(hdmi, mode); - mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI"); - if (mode->flags & DRM_MODE_FLAG_3D_MASK) - mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode); -} - static void mtk_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_state) { struct drm_atomic_state *state =3D old_state->base.state; struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + u8 buffer_spd[HDMI_INFOFRAME_SIZE(SPD)]; + u8 buffer_avi[HDMI_INFOFRAME_SIZE(AVI)]; =20 /* Retrieve the connector through the atomic state. */ hdmi->curr_conn =3D drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); =20 mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode); - clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]); - clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]); + clk_prepare_enable(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PLL]); + clk_prepare_enable(hdmi->clk[MTK_HDMIV1_CLK_HDMI_PIXEL]); phy_power_on(hdmi->phy); - mtk_hdmi_send_infoframe(hdmi, &hdmi->mode); + mtk_hdmi_setup_audio_infoframe(hdmi); + mtk_hdmi_send_infoframe(hdmi, buffer_spd, sizeof(buffer_spd), + buffer_avi, sizeof(buffer_avi), &hdmi->mode); + if (hdmi->mode.flags & DRM_MODE_FLAG_3D_MASK) + mtk_hdmi_setup_vendor_specific_infoframe(hdmi, &hdmi->mode); =20 hdmi->enabled =3D true; } =20 -static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs =3D { +const struct drm_bridge_funcs mtk_mt8183_hdmi_bridge_funcs =3D { .mode_valid =3D mtk_hdmi_bridge_mode_valid, .atomic_duplicate_state =3D drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, @@ -1379,105 +1112,6 @@ static const struct drm_bridge_funcs mtk_hdmi_bridg= e_funcs =3D { .get_edid =3D mtk_hdmi_bridge_get_edid, }; =20 -static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, - struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - struct device_node *np =3D dev->of_node; - struct device_node *cec_np, *remote, *i2c_np; - struct platform_device *cec_pdev; - struct regmap *regmap; - int ret; - - ret =3D mtk_hdmi_get_all_clk(hdmi, np); - if (ret) { - if (ret !=3D -EPROBE_DEFER) - dev_err(dev, "Failed to get clocks: %d\n", ret); - - return ret; - } - - /* The CEC module handles HDMI hotplug detection */ - cec_np =3D of_get_compatible_child(np->parent, "mediatek,mt8173-cec"); - if (!cec_np) { - dev_err(dev, "Failed to find CEC node\n"); - return -EINVAL; - } - - cec_pdev =3D of_find_device_by_node(cec_np); - if (!cec_pdev) { - dev_err(hdmi->dev, "Waiting for CEC device %pOF\n", - cec_np); - of_node_put(cec_np); - return -EPROBE_DEFER; - } - of_node_put(cec_np); - hdmi->cec_dev =3D &cec_pdev->dev; - - /* - * The mediatek,syscon-hdmi property contains a phandle link to the - * MMSYS_CONFIG device and the register offset of the HDMI_SYS_CFG - * registers it contains. - */ - regmap =3D syscon_regmap_lookup_by_phandle(np, "mediatek,syscon-hdmi"); - ret =3D of_property_read_u32_index(np, "mediatek,syscon-hdmi", 1, - &hdmi->sys_offset); - if (IS_ERR(regmap)) - ret =3D PTR_ERR(regmap); - if (ret) { - dev_err(dev, - "Failed to get system configuration registers: %d\n", - ret); - goto put_device; - } - hdmi->sys_regmap =3D regmap; - - hdmi->regs =3D device_node_to_regmap(dev->of_node); - if (IS_ERR(hdmi->regs)) { - ret =3D PTR_ERR(hdmi->regs); - goto put_device; - } - - remote =3D of_graph_get_remote_node(np, 1, 0); - if (!remote) { - ret =3D -EINVAL; - goto put_device; - } - - if (!of_device_is_compatible(remote, "hdmi-connector")) { - hdmi->next_bridge =3D of_drm_find_bridge(remote); - if (!hdmi->next_bridge) { - dev_err(dev, "Waiting for external bridge\n"); - of_node_put(remote); - ret =3D -EPROBE_DEFER; - goto put_device; - } - } - - i2c_np =3D of_parse_phandle(remote, "ddc-i2c-bus", 0); - if (!i2c_np) { - dev_err(dev, "Failed to find ddc-i2c-bus node in %pOF\n", - remote); - of_node_put(remote); - ret =3D -EINVAL; - goto put_device; - } - of_node_put(remote); - - hdmi->ddc_adpt =3D of_find_i2c_adapter_by_node(i2c_np); - of_node_put(i2c_np); - if (!hdmi->ddc_adpt) { - dev_err(dev, "Failed to get ddc i2c adapter by node\n"); - ret =3D -EINVAL; - goto put_device; - } - - return 0; -put_device: - put_device(hdmi->cec_dev); - return ret; -} - /* * HDMI audio codec callbacks */ @@ -1623,175 +1257,9 @@ static const struct hdmi_codec_ops mtk_hdmi_audio_c= odec_ops =3D { .no_capture_mute =3D 1, }; =20 -static int mtk_hdmi_register_audio_driver(struct device *dev) +void mtk_hdmi_set_codec_pdata_mt8183(struct hdmi_codec_pdata *codec_data) { - struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); - struct hdmi_codec_pdata codec_data =3D { - .ops =3D &mtk_hdmi_audio_codec_ops, - .max_i2s_channels =3D 2, - .i2s =3D 1, - .data =3D hdmi, - }; - struct platform_device *pdev; - - pdev =3D platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, - PLATFORM_DEVID_AUTO, &codec_data, - sizeof(codec_data)); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME); - return 0; + codec_data->ops =3D &mtk_hdmi_audio_codec_ops; + codec_data->max_i2s_channels =3D 2; + codec_data->i2s =3D 1; } - -static int mtk_drm_hdmi_probe(struct platform_device *pdev) -{ - struct mtk_hdmi *hdmi; - struct device *dev =3D &pdev->dev; - int ret; - - hdmi =3D devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; - - hdmi->dev =3D dev; - hdmi->conf =3D of_device_get_match_data(dev); - - ret =3D mtk_hdmi_dt_parse_pdata(hdmi, pdev); - if (ret) - return ret; - - hdmi->phy =3D devm_phy_get(dev, "hdmi"); - if (IS_ERR(hdmi->phy)) { - ret =3D PTR_ERR(hdmi->phy); - dev_err(dev, "Failed to get HDMI PHY: %d\n", ret); - return ret; - } - - mutex_init(&hdmi->update_plugged_status_lock); - platform_set_drvdata(pdev, hdmi); - - ret =3D mtk_hdmi_output_init(hdmi); - if (ret) { - dev_err(dev, "Failed to initialize hdmi output\n"); - return ret; - } - - ret =3D mtk_hdmi_register_audio_driver(dev); - if (ret) { - dev_err(dev, "Failed to register audio driver: %d\n", ret); - return ret; - } - - hdmi->bridge.funcs =3D &mtk_hdmi_bridge_funcs; - hdmi->bridge.of_node =3D pdev->dev.of_node; - hdmi->bridge.ops =3D DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID - | DRM_BRIDGE_OP_HPD; - hdmi->bridge.type =3D DRM_MODE_CONNECTOR_HDMIA; - drm_bridge_add(&hdmi->bridge); - - ret =3D mtk_hdmi_clk_enable_audio(hdmi); - if (ret) { - dev_err(dev, "Failed to enable audio clocks: %d\n", ret); - goto err_bridge_remove; - } - - return 0; - -err_bridge_remove: - drm_bridge_remove(&hdmi->bridge); - return ret; -} - -static int mtk_drm_hdmi_remove(struct platform_device *pdev) -{ - struct mtk_hdmi *hdmi =3D platform_get_drvdata(pdev); - - drm_bridge_remove(&hdmi->bridge); - mtk_hdmi_clk_disable_audio(hdmi); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int mtk_hdmi_suspend(struct device *dev) -{ - struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); - - mtk_hdmi_clk_disable_audio(hdmi); - - return 0; -} - -static int mtk_hdmi_resume(struct device *dev) -{ - struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); - int ret =3D 0; - - ret =3D mtk_hdmi_clk_enable_audio(hdmi); - if (ret) { - dev_err(dev, "hdmi resume failed!\n"); - return ret; - } - - return 0; -} -#endif -static SIMPLE_DEV_PM_OPS(mtk_hdmi_pm_ops, - mtk_hdmi_suspend, mtk_hdmi_resume); - -static const struct mtk_hdmi_conf mtk_hdmi_conf_mt2701 =3D { - .tz_disabled =3D true, -}; - -static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8167 =3D { - .max_mode_clock =3D 148500, - .cea_modes_only =3D true, -}; - -static const struct of_device_id mtk_drm_hdmi_of_ids[] =3D { - { .compatible =3D "mediatek,mt2701-hdmi", - .data =3D &mtk_hdmi_conf_mt2701, - }, - { .compatible =3D "mediatek,mt8167-hdmi", - .data =3D &mtk_hdmi_conf_mt8167, - }, - { .compatible =3D "mediatek,mt8173-hdmi", - }, - {} -}; -MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_of_ids); - -static struct platform_driver mtk_hdmi_driver =3D { - .probe =3D mtk_drm_hdmi_probe, - .remove =3D mtk_drm_hdmi_remove, - .driver =3D { - .name =3D "mediatek-drm-hdmi", - .of_match_table =3D mtk_drm_hdmi_of_ids, - .pm =3D &mtk_hdmi_pm_ops, - }, -}; - -static struct platform_driver * const mtk_hdmi_drivers[] =3D { - &mtk_hdmi_ddc_driver, - &mtk_cec_driver, - &mtk_hdmi_driver, -}; - -static int __init mtk_hdmitx_init(void) -{ - return platform_register_drivers(mtk_hdmi_drivers, - ARRAY_SIZE(mtk_hdmi_drivers)); -} - -static void __exit mtk_hdmitx_exit(void) -{ - platform_unregister_drivers(mtk_hdmi_drivers, - ARRAY_SIZE(mtk_hdmi_drivers)); -} - -module_init(mtk_hdmitx_init); -module_exit(mtk_hdmitx_exit); - -MODULE_AUTHOR("Jie Qiu "); -MODULE_DESCRIPTION("MediaTek HDMI Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek= /mtk_hdmi.h index 472bf141c92b..3d4cd0c19150 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h @@ -6,9 +6,27 @@ #ifndef _MTK_HDMI_CTRL_H #define _MTK_HDMI_CTRL_H =20 +#include + +struct mtk_hdmi; struct platform_driver; =20 extern struct platform_driver mtk_cec_driver; extern struct platform_driver mtk_hdmi_ddc_driver; +extern const struct drm_bridge_funcs mtk_mt8183_hdmi_bridge_funcs; + +void mtk_hdmi_output_init_mt8183(struct mtk_hdmi *hdmi); +void mtk_hdmi_clk_disable_audio_mt8183(struct mtk_hdmi *hdmi); +int mtk_hdmi_clk_enable_audio_mt8183(struct mtk_hdmi *hdmi); +void mtk_hdmi_set_codec_pdata_mt8183(struct hdmi_codec_pdata *codec_data); + +enum mtk_hdmi_clk_id_mt8183 { + MTK_HDMIV1_CLK_HDMI_PIXEL, + MTK_HDMIV1_CLK_HDMI_PLL, + MTK_HDMIV1_CLK_AUD_BCLK, + MTK_HDMIV1_CLK_AUD_SPDIF, + MTK_HDMIV1_CLK_COUNT, +}; =20 +extern const char * const mtk_hdmi_clk_names_v1[MTK_HDMIV1_CLK_COUNT]; #endif /* _MTK_HDMI_CTRL_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.c new file mode 100644 index 000000000000..ead0c30f55b7 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + * Author: Jie Qiu + */ +#include "mtk_hdmi_common.h" + +struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b) +{ + return container_of(b, struct mtk_hdmi, bridge); +} + +int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, size_t= bufsz, + const char *vendor, const char *product) +{ + struct hdmi_spd_infoframe frame; + ssize_t err; + + err =3D hdmi_spd_infoframe_init(&frame, vendor, product); + if (err < 0) { + dev_err(hdmi->dev, "Failed to initialize SPD infoframe: %zd\n", + err); + return err; + } + + err =3D hdmi_spd_infoframe_pack(&frame, buffer, bufsz); + if (err < 0) { + dev_err(hdmi->dev, "Failed to pack SDP infoframe: %zd\n", err); + return err; + } + + return 0; +} + +int mtk_hdmi_get_all_clk(struct mtk_hdmi *hdmi, struct device_node *np, + const char *const *mtk_hdmi_clk_names, size_t num_clocks) +{ + int i; + + for (i =3D 0; i < num_clocks; i++) { + hdmi->clk[i] =3D of_clk_get_by_name(np, mtk_hdmi_clk_names[i]); + + if (IS_ERR(hdmi->clk[i])) + return PTR_ERR(hdmi->clk[i]); + } + + return 0; +} + +struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + struct edid *edid; + + if (!hdmi->ddc_adpt) + return NULL; + edid =3D drm_get_edid(connector, hdmi->ddc_adpt); + if (!edid) + return NULL; + return edid; +} + +bool mtk_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +void mtk_hdmi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + + drm_mode_copy(&hdmi->mode, adjusted_mode); +} + +int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, size_t= bufsz, + struct drm_display_mode *mode) +{ + struct hdmi_avi_infoframe frame; + ssize_t err; + + err =3D drm_hdmi_avi_infoframe_from_display_mode(&frame, hdmi->curr_conn, + mode); + + if (err < 0) { + dev_err(hdmi->dev, + "Failed to get AVI infoframe from mode: %zd\n", err); + return err; + } + + err =3D hdmi_avi_infoframe_pack(&frame, buffer, bufsz); + + if (err < 0) { + dev_err(hdmi->dev, "Failed to pack AVI infoframe: %zd\n", err); + return err; + } + + return 0; +} + +void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi, u8 *buffer_spd, size_t= bufsz_spd, + u8 *buffer_avi, size_t bufsz_avi, struct drm_display_mode *mode) +{ + mtk_hdmi_setup_avi_infoframe(hdmi, buffer_avi, bufsz_avi, mode); + mtk_hdmi_setup_spd_infoframe(hdmi, buffer_spd, bufsz_spd, "mediatek", "On= -chip HDMI"); +} + +int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device = *pdev, + const char *const *clk_names, size_t num_clocks) +{ + struct device *dev =3D &pdev->dev; + struct device_node *np =3D dev->of_node; + struct device_node *cec_np, *remote, *i2c_np; + struct platform_device *cec_pdev; + struct regmap *regmap; + struct resource *mem; + int ret; + + ret =3D mtk_hdmi_get_all_clk(hdmi, np, clk_names, num_clocks); + if (ret) { + dev_err(dev, "Failed to get all clks\n"); + return ret; + } + + /* The CEC module handles HDMI hotplug detection */ + cec_np =3D of_get_compatible_child(np->parent, "mediatek,mt8173-cec"); + if (!cec_np) { + dev_err(dev, "Failed to find CEC node\n"); + return -EINVAL; + } + + cec_pdev =3D of_find_device_by_node(cec_np); + if (!cec_pdev) { + dev_err(hdmi->dev, "Waiting for CEC device %pOF\n", cec_np); + of_node_put(cec_np); + return -EPROBE_DEFER; + } + of_node_put(cec_np); + hdmi->cec_dev =3D &cec_pdev->dev; + /* + * The mediatek,syscon-hdmi property contains a phandle link to the + * MMSYS_CONFIG device and the register offset of the HDMI_SYS_CFG + * registers it contains. + */ + regmap =3D syscon_regmap_lookup_by_phandle(np, "mediatek,syscon-hdmi"); + ret =3D of_property_read_u32_index(np, "mediatek,syscon-hdmi", 1, &hdmi->= sys_offset); + if (IS_ERR(regmap)) + ret =3D PTR_ERR(regmap); + if (ret) { + dev_err(dev, "Failed to get system configuration registers: %d\n", ret); + goto put_device; + } + hdmi->sys_regmap =3D regmap; + + mem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + ret =3D -ENOMEM; + goto put_device; + } + + hdmi->regs =3D device_node_to_regmap(dev->of_node); + if (IS_ERR(hdmi->regs)) { + ret =3D PTR_ERR(hdmi->regs); + goto put_device; + } + + remote =3D of_graph_get_remote_node(np, 1, 0); + if (!remote) { + ret =3D -EINVAL; + goto put_device; + } + + if (!of_device_is_compatible(remote, "hdmi-connector")) { + hdmi->next_bridge =3D of_drm_find_bridge(remote); + if (!hdmi->next_bridge) { + dev_err(dev, "Waiting for external bridge\n"); + of_node_put(remote); + ret =3D -EPROBE_DEFER; + goto put_device; + } + } + + i2c_np =3D of_parse_phandle(remote, "ddc-i2c-bus", 0); + if (!i2c_np) { + of_node_put(pdev->dev.of_node); + dev_err(dev, "Failed to find ddc-i2c-bus"); + ret =3D -EINVAL; + goto put_device; + } + + hdmi->ddc_adpt =3D of_find_i2c_adapter_by_node(i2c_np); + of_node_put(i2c_np); + if (!hdmi->ddc_adpt) { + dev_err(dev, "Failed to get ddc i2c adapter by node"); + ret =3D -EPROBE_DEFER; + goto put_device; + } + + return 0; +put_device: + put_device(hdmi->cec_dev); + return ret; +} + +static int mtk_hdmi_register_audio_driver(struct device *dev) +{ + struct platform_device *pdev; + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + struct hdmi_codec_pdata codec_data =3D { + .data =3D hdmi, + }; + + if (hdmi->conf->mtk_hdmi_set_codec_pdata) + hdmi->conf->mtk_hdmi_set_codec_pdata(&codec_data); + + pdev =3D platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, &codec_data, + sizeof(codec_data)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME); + return 0; +} + +int mtk_drm_hdmi_probe(struct platform_device *pdev) +{ + struct mtk_hdmi *hdmi; + struct device *dev =3D &pdev->dev; + int ret; + + hdmi =3D devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->dev =3D dev; + hdmi->conf =3D of_device_get_match_data(dev); + + hdmi->clk =3D devm_kcalloc(dev, hdmi->conf->num_clocks, sizeof(struct clk= *), + GFP_KERNEL); + + hdmi->phy =3D devm_phy_get(dev, "hdmi"); + if (IS_ERR(hdmi->phy)) { + ret =3D PTR_ERR(hdmi->phy); + dev_err(dev, "Failed to get HDMI PHY: %d\n", ret); + return ret; + } + + ret =3D mtk_hdmi_dt_parse_pdata(hdmi, pdev, hdmi->conf->mtk_hdmi_clock_na= mes, + hdmi->conf->num_clocks); + + if (ret) + return ret; + + platform_set_drvdata(pdev, hdmi); + + if (hdmi->conf->mtk_hdmi_output_init) + hdmi->conf->mtk_hdmi_output_init(hdmi); + + hdmi->bridge.funcs =3D hdmi->conf->bridge_funcs; + + hdmi->bridge.ops =3D DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRID= GE_OP_HPD; + hdmi->bridge.type =3D DRM_MODE_CONNECTOR_HDMIA; + hdmi->bridge.of_node =3D pdev->dev.of_node; + hdmi->bridge.ddc =3D hdmi->ddc_adpt; + drm_bridge_add(&hdmi->bridge); + + ret =3D mtk_hdmi_register_audio_driver(dev); + + if (ret) + return ret; + + return 0; +} + +int mtk_drm_hdmi_remove(struct platform_device *pdev) +{ + struct mtk_hdmi *hdmi =3D platform_get_drvdata(pdev); + + drm_bridge_remove(&hdmi->bridge); + + if (hdmi->conf->mtk_hdmi_clk_disable) + hdmi->conf->mtk_hdmi_clk_disable(hdmi); + + i2c_put_adapter(hdmi->ddc_adpt); + + return 0; +} + +static const struct mtk_hdmi_conf mtk_hdmi_conf_mt2701 =3D { + .tz_disabled =3D true, + .bridge_funcs =3D &mtk_mt8183_hdmi_bridge_funcs, + .mtk_hdmi_output_init =3D mtk_hdmi_output_init_mt8183, + .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_audio_mt8183, + .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_audio_mt8183, + .mtk_hdmi_set_codec_pdata =3D mtk_hdmi_set_codec_pdata_mt8183, + .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v1, + .num_clocks =3D MTK_HDMIV1_CLK_COUNT, +}; + +static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8167 =3D { + .max_mode_clock =3D 148500, + .cea_modes_only =3D true, + .bridge_funcs =3D &mtk_mt8183_hdmi_bridge_funcs, + .mtk_hdmi_output_init =3D mtk_hdmi_output_init_mt8183, + .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_audio_mt8183, + .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_audio_mt8183, + .mtk_hdmi_set_codec_pdata =3D mtk_hdmi_set_codec_pdata_mt8183, + .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v1, + .num_clocks =3D MTK_HDMIV1_CLK_COUNT, +}; + +static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8173 =3D { + .bridge_funcs =3D &mtk_mt8183_hdmi_bridge_funcs, + .mtk_hdmi_output_init =3D mtk_hdmi_output_init_mt8183, + .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_audio_mt8183, + .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_audio_mt8183, + .mtk_hdmi_set_codec_pdata =3D mtk_hdmi_set_codec_pdata_mt8183, + .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v1, + .num_clocks =3D MTK_HDMIV1_CLK_COUNT, +}; + +static const struct of_device_id mtk_drm_hdmi_of_ids[] =3D { + { .compatible =3D "mediatek,mt2701-hdmi", + .data =3D &mtk_hdmi_conf_mt2701, + }, + { .compatible =3D "mediatek,mt8167-hdmi", + .data =3D &mtk_hdmi_conf_mt8167, + }, + { .compatible =3D "mediatek,mt8173-hdmi", + .data =3D &mtk_hdmi_conf_mt8173, + }, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_of_ids); + +#ifdef CONFIG_PM_SLEEP +static __maybe_unused int mtk_hdmi_suspend(struct device *dev) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (hdmi->conf->mtk_hdmi_clk_disable) + hdmi->conf->mtk_hdmi_clk_disable(hdmi); + + return 0; +} + +static __maybe_unused int mtk_hdmi_resume(struct device *dev) +{ + int ret; + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + dev_dbg(dev, "hdmi resume success!\n"); + + if (hdmi->conf->mtk_hdmi_clk_enable) { + ret =3D hdmi->conf->mtk_hdmi_clk_enable(hdmi); + if (ret) + dev_err(dev, "hdmi resume failed!\n"); + } + + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(mtk_hdmi_pm_ops, + mtk_hdmi_suspend, mtk_hdmi_resume); + +static struct platform_driver mtk_hdmi_driver =3D { + .probe =3D mtk_drm_hdmi_probe, + .remove =3D mtk_drm_hdmi_remove, + .driver =3D { + .name =3D "mediatek-drm-hdmi", + .of_match_table =3D mtk_drm_hdmi_of_ids, + .pm =3D &mtk_hdmi_pm_ops, + }, +}; + +static struct platform_driver * const mtk_hdmi_drivers[] =3D { + &mtk_hdmi_ddc_driver, + &mtk_cec_driver, + &mtk_hdmi_driver, +}; + +static int __init mtk_hdmitx_init(void) +{ + return platform_register_drivers(mtk_hdmi_drivers, + ARRAY_SIZE(mtk_hdmi_drivers)); +} + +static void __exit mtk_hdmitx_exit(void) +{ + platform_unregister_drivers(mtk_hdmi_drivers, + ARRAY_SIZE(mtk_hdmi_drivers)); +} + +module_init(mtk_hdmitx_init); +module_exit(mtk_hdmitx_exit); + +MODULE_AUTHOR("Jie Qiu "); +MODULE_AUTHOR("Can Zeng "); +MODULE_DESCRIPTION("MediaTek HDMI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.h new file mode 100644 index 000000000000..6e4633981018 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + */ + +#ifndef _MTK_HDMI_COMMON_H +#define _MTK_HDMI_COMMON_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mtk_cec.h" +#include "mtk_hdmi.h" + +struct mtk_hdmi_conf { + bool tz_disabled; + bool cea_modes_only; + unsigned long max_mode_clock; + const struct drm_bridge_funcs *bridge_funcs; + void (*mtk_hdmi_output_init)(struct mtk_hdmi *hdmi); + void (*mtk_hdmi_clk_disable)(struct mtk_hdmi *hdmi); + int (*mtk_hdmi_clk_enable)(struct mtk_hdmi *hdmi); + void (*mtk_hdmi_set_codec_pdata)(struct hdmi_codec_pdata *codec_data); + const char *const *mtk_hdmi_clock_names; + int num_clocks; +}; + +enum hdmi_color_depth { HDMI_8_BIT, HDMI_10_BIT, HDMI_12_BIT, HDMI_16_BIT = }; + +enum hdmi_aud_input_type { + HDMI_AUD_INPUT_I2S =3D 0, + HDMI_AUD_INPUT_SPDIF, +}; + +enum hdmi_aud_i2s_fmt { + HDMI_I2S_MODE_RJT_24BIT =3D 0, + HDMI_I2S_MODE_RJT_16BIT, + HDMI_I2S_MODE_LJT_24BIT, + HDMI_I2S_MODE_LJT_16BIT, + HDMI_I2S_MODE_I2S_24BIT, + HDMI_I2S_MODE_I2S_16BIT +}; + +enum hdmi_aud_mclk { + HDMI_AUD_MCLK_128FS, + HDMI_AUD_MCLK_192FS, + HDMI_AUD_MCLK_256FS, + HDMI_AUD_MCLK_384FS, + HDMI_AUD_MCLK_512FS, + HDMI_AUD_MCLK_768FS, + HDMI_AUD_MCLK_1152FS, +}; + +enum hdmi_aud_channel_type { + HDMI_AUD_CHAN_TYPE_1_0 =3D 0, + HDMI_AUD_CHAN_TYPE_1_1, + HDMI_AUD_CHAN_TYPE_2_0, + HDMI_AUD_CHAN_TYPE_2_1, + HDMI_AUD_CHAN_TYPE_3_0, + HDMI_AUD_CHAN_TYPE_3_1, + HDMI_AUD_CHAN_TYPE_4_0, + HDMI_AUD_CHAN_TYPE_4_1, + HDMI_AUD_CHAN_TYPE_5_0, + HDMI_AUD_CHAN_TYPE_5_1, + HDMI_AUD_CHAN_TYPE_6_0, + HDMI_AUD_CHAN_TYPE_6_1, + HDMI_AUD_CHAN_TYPE_7_0, + HDMI_AUD_CHAN_TYPE_7_1, + HDMI_AUD_CHAN_TYPE_3_0_LRS, + HDMI_AUD_CHAN_TYPE_3_1_LRS, + HDMI_AUD_CHAN_TYPE_4_0_CLRS, + HDMI_AUD_CHAN_TYPE_4_1_CLRS, + HDMI_AUD_CHAN_TYPE_6_1_CS, + HDMI_AUD_CHAN_TYPE_6_1_CH, + HDMI_AUD_CHAN_TYPE_6_1_OH, + HDMI_AUD_CHAN_TYPE_6_1_CHR, + HDMI_AUD_CHAN_TYPE_7_1_LH_RH, + HDMI_AUD_CHAN_TYPE_7_1_LSR_RSR, + HDMI_AUD_CHAN_TYPE_7_1_LC_RC, + HDMI_AUD_CHAN_TYPE_7_1_LW_RW, + HDMI_AUD_CHAN_TYPE_7_1_LSD_RSD, + HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS, + HDMI_AUD_CHAN_TYPE_7_1_LHS_RHS, + HDMI_AUD_CHAN_TYPE_7_1_CS_CH, + HDMI_AUD_CHAN_TYPE_7_1_CS_OH, + HDMI_AUD_CHAN_TYPE_7_1_CS_CHR, + HDMI_AUD_CHAN_TYPE_7_1_CH_OH, + HDMI_AUD_CHAN_TYPE_7_1_CH_CHR, + HDMI_AUD_CHAN_TYPE_7_1_OH_CHR, + HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS_LSR_RSR, + HDMI_AUD_CHAN_TYPE_6_0_CS, + HDMI_AUD_CHAN_TYPE_6_0_CH, + HDMI_AUD_CHAN_TYPE_6_0_OH, + HDMI_AUD_CHAN_TYPE_6_0_CHR, + HDMI_AUD_CHAN_TYPE_7_0_LH_RH, + HDMI_AUD_CHAN_TYPE_7_0_LSR_RSR, + HDMI_AUD_CHAN_TYPE_7_0_LC_RC, + HDMI_AUD_CHAN_TYPE_7_0_LW_RW, + HDMI_AUD_CHAN_TYPE_7_0_LSD_RSD, + HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS, + HDMI_AUD_CHAN_TYPE_7_0_LHS_RHS, + HDMI_AUD_CHAN_TYPE_7_0_CS_CH, + HDMI_AUD_CHAN_TYPE_7_0_CS_OH, + HDMI_AUD_CHAN_TYPE_7_0_CS_CHR, + HDMI_AUD_CHAN_TYPE_7_0_CH_OH, + HDMI_AUD_CHAN_TYPE_7_0_CH_CHR, + HDMI_AUD_CHAN_TYPE_7_0_OH_CHR, + HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS_LSR_RSR, + HDMI_AUD_CHAN_TYPE_8_0_LH_RH_CS, + HDMI_AUD_CHAN_TYPE_UNKNOWN =3D 0xFF +}; + +enum hdmi_aud_channel_swap_type { + HDMI_AUD_SWAP_LR, + HDMI_AUD_SWAP_LFE_CC, + HDMI_AUD_SWAP_LSRS, + HDMI_AUD_SWAP_RLS_RRS, + HDMI_AUD_SWAP_LR_STATUS, +}; + +enum hdmi_hpd_state { + HDMI_PLUG_OUT =3D 0, + HDMI_PLUG_IN_AND_SINK_POWER_ON, + HDMI_PLUG_IN_ONLY, +}; + +struct hdmi_audio_param { + enum hdmi_audio_coding_type aud_codec; + enum hdmi_audio_sample_size aud_sampe_size; + enum hdmi_aud_input_type aud_input_type; + enum hdmi_aud_i2s_fmt aud_i2s_fmt; + enum hdmi_aud_mclk aud_mclk; + enum hdmi_aud_channel_type aud_input_chan_type; + struct hdmi_codec_params codec_params; +}; + +struct mtk_hdmi { + struct drm_bridge bridge; + struct device *dev; + const struct mtk_hdmi_conf *conf; + struct phy *phy; + struct i2c_adapter *ddc_adpt; + struct clk **clk; + struct drm_display_mode mode; + bool dvi_mode; + struct regmap *sys_regmap; + unsigned int sys_offset; + struct regmap *regs; + + bool powered; + bool enabled; + unsigned int hdmi_irq; + enum hdmi_hpd_state hpd; + + bool hdmi_enabled; + bool power_clk_enabled; + bool irq_registered; + + /* Audio */ + struct hdmi_audio_param aud_param; + bool audio_enable; + + struct drm_connector *curr_conn;/* current connector (only valid when 'en= abled') */ + struct mutex update_plugged_status_lock; + struct device *cec_dev; + struct device *codec_dev; + hdmi_codec_plugged_cb plugged_cb; + struct drm_bridge *next_bridge; +}; + +struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b); +int mtk_hdmi_setup_spd_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, size_t= bufsz, + const char *vendor, const char *product); +void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi, u8 *buffer_spd, size_t= bufsz_spd, + u8 *buffer_avi, size_t bufsz_avi, struct drm_display_mode *mode); +int mtk_hdmi_get_all_clk(struct mtk_hdmi *hdmi, struct device_node *np, + const char *const *clk_names, size_t num_clocks); +struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector); +bool mtk_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void mtk_hdmi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); +int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, + struct platform_device *pdev, const char *const *clk_names, size_t = num_clocks); +int mtk_drm_hdmi_probe(struct platform_device *pdev); +int mtk_drm_hdmi_remove(struct platform_device *pdev); + +#endif //_MTK_HDMI_COMMON_H --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82AF4C7EE23 for ; Mon, 29 May 2023 14:37:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230016AbjE2Og7 (ORCPT ); Mon, 29 May 2023 10:36:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229884AbjE2Ogq (ORCPT ); Mon, 29 May 2023 10:36:46 -0400 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0554CBE for ; Mon, 29 May 2023 07:36:44 -0700 (PDT) Received: by mail-ed1-x52d.google.com with SMTP id 4fb4d7f45d1cf-5149c76f4dbso2253205a12.1 for ; Mon, 29 May 2023 07:36:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371003; x=1687963003; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=c2Sh4+A1b+81wZLAVdTRbrmRS09i1jRPbv5H6IWS80Q=; b=hiSqot5Z0TVVzkwYkmdjRaFYGpVkqZ/2l7Z8d2ugq5qKwMiONQBL1+GBaWbf/yIP7z CUE1CBJ5ZqXFY9WXRrUezsKC9Wwr8XoT2GKDadeS36vWTMSqxPY4v4SEjYGwJry/LaVq /o/qOzl/CNrpF9Or/4l+K6JF4xQQu/hUD3RvCC9UB/2uJ9LOCiZf6xO7Gn4v1hweuYrb kRI31ThOkvK8k/B7vfN1rk58gZ+tR0XvafgFGcBCa6m61qLXsXYrYOPFkxnxOZ7IiIE8 tzUUttynUa0Iqjps+GkZo9CoNZ1Y6KAVVMmAkQ9oB5EyCrBJgYl0n/WOL3A0GatmdRxm zVJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371003; x=1687963003; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=c2Sh4+A1b+81wZLAVdTRbrmRS09i1jRPbv5H6IWS80Q=; b=QlfY1pPgX7weBO00NqjDkBTL9I2xXW9OM949F6NxJEoxBoUVoIf7rLCh7kg2y2vzL/ /bIuwq3pExTQxhVTQjoLOKuoFytq+q6MS9PZ06yeBwWRSlbg/KfgaR2W8YwXquZ2ApQi 8KslG16FNlKz7R25armsbXjciVLWCCS0Sapd9t46R0Vzy+PRoC4u+UlCdWlA7Lh5wXZx qsBi0hezFYEKxs2QtuRXKy0D8TIWZfgWDs5LhfyylrSUXpSgrxpic8NsILXod6Z6DXrZ 1sgDxvgWu2xiu36EywQwNPZ+yzUUwAfbPUiOrpad3awg0li/JRlwtDrNi5vOu8mres0I YCSQ== X-Gm-Message-State: AC+VfDztr6oIcr1K830QCta0D8tVitH8UGsObWW7mBpBiSBZEKaPwK5F TbAP/5rLa5YuU25KGLTvJ0FS9g== X-Google-Smtp-Source: ACHHUZ5waXscvjoYNWcuy+rA2rbzsNFah4xpic6XPGtTh3EC757yb2ISi5VAAB9m/SKenAeW2NEWag== X-Received: by 2002:a17:907:c1a:b0:973:84af:66e5 with SMTP id ga26-20020a1709070c1a00b0097384af66e5mr11058579ejc.40.1685371003383; Mon, 29 May 2023 07:36:43 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:42 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:01 +0200 Subject: [PATCH v4 4/8] drm/mediatek: hdmi: make the cec dev optional MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-4-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Make cec device optional in order to support newer versions of the hdmi IP which doesn't require it Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 8 +++-- drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 52 +++++++++++++++++++-------= ---- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek= /mtk_hdmi.c index 41a7593887fb..4c382aeb94c9 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -925,10 +925,11 @@ void mtk_hdmi_clk_disable_audio_mt8183(struct mtk_hdm= i *hdmi) static enum drm_connector_status mtk_hdmi_update_plugged_status(struct mtk_hdmi *hdmi) { - bool connected; + bool connected =3D true; =20 mutex_lock(&hdmi->update_plugged_status_lock); - connected =3D mtk_cec_hpd_high(hdmi->cec_dev); + if (hdmi->cec_dev) + connected =3D mtk_cec_hpd_high(hdmi->cec_dev); if (hdmi->plugged_cb && hdmi->codec_dev) hdmi->plugged_cb(hdmi->codec_dev, connected); mutex_unlock(&hdmi->update_plugged_status_lock); @@ -1024,7 +1025,8 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *= bridge, return ret; } =20 - mtk_cec_set_hpd_event(hdmi->cec_dev, mtk_hdmi_hpd_event, hdmi->dev); + if (hdmi->cec_dev) + mtk_cec_set_hpd_event(hdmi->cec_dev, mtk_hdmi_hpd_event, hdmi->dev); =20 return 0; } diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.c index ead0c30f55b7..d7f3d29138d8 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -110,28 +110,18 @@ void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi, u= 8 *buffer_spd, size_t bufsz mtk_hdmi_setup_spd_infoframe(hdmi, buffer_spd, bufsz_spd, "mediatek", "On= -chip HDMI"); } =20 -int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device = *pdev, - const char *const *clk_names, size_t num_clocks) +static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev,= struct device_node *np) { - struct device *dev =3D &pdev->dev; - struct device_node *np =3D dev->of_node; - struct device_node *cec_np, *remote, *i2c_np; + int ret; + struct device_node *cec_np; struct platform_device *cec_pdev; struct regmap *regmap; - struct resource *mem; - int ret; - - ret =3D mtk_hdmi_get_all_clk(hdmi, np, clk_names, num_clocks); - if (ret) { - dev_err(dev, "Failed to get all clks\n"); - return ret; - } =20 /* The CEC module handles HDMI hotplug detection */ cec_np =3D of_get_compatible_child(np->parent, "mediatek,mt8173-cec"); if (!cec_np) { dev_err(dev, "Failed to find CEC node\n"); - return -EINVAL; + return -ENOTSUPP; } =20 cec_pdev =3D of_find_device_by_node(cec_np); @@ -141,7 +131,6 @@ int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, stru= ct platform_device *pdev, return -EPROBE_DEFER; } of_node_put(cec_np); - hdmi->cec_dev =3D &cec_pdev->dev; /* * The mediatek,syscon-hdmi property contains a phandle link to the * MMSYS_CONFIG device and the register offset of the HDMI_SYS_CFG @@ -150,12 +139,39 @@ int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, st= ruct platform_device *pdev, regmap =3D syscon_regmap_lookup_by_phandle(np, "mediatek,syscon-hdmi"); ret =3D of_property_read_u32_index(np, "mediatek,syscon-hdmi", 1, &hdmi->= sys_offset); if (IS_ERR(regmap)) - ret =3D PTR_ERR(regmap); + return PTR_ERR(regmap); if (ret) { - dev_err(dev, "Failed to get system configuration registers: %d\n", ret); - goto put_device; + dev_err(dev, + "Failed to get system configuration registers: %d\n", ret); + return ret; } + hdmi->sys_regmap =3D regmap; + hdmi->cec_dev =3D &cec_pdev->dev; + + return 0; +} + +int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, struct platform_device = *pdev, + const char *const *clk_names, size_t num_clocks) +{ + struct device *dev =3D &pdev->dev; + struct device_node *np =3D dev->of_node; + struct device_node *remote, *i2c_np; + struct resource *mem; + int ret; + + ret =3D mtk_hdmi_get_all_clk(hdmi, np, clk_names, num_clocks); + if (ret) { + dev_err(dev, "Failed to get all clks\n"); + return ret; + } + + ret =3D mtk_hdmi_get_cec_dev(hdmi, dev, np); + if (ret =3D=3D -ENOTSUPP) + dev_info(dev, "No CEC node found, continuing without"); + else if(ret) + goto put_device; =20 mem =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74B6DC7EE23 for ; Mon, 29 May 2023 14:37:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230244AbjE2OhX (ORCPT ); Mon, 29 May 2023 10:37:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38578 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229981AbjE2Ogy (ORCPT ); Mon, 29 May 2023 10:36:54 -0400 Received: from mail-ej1-x634.google.com (mail-ej1-x634.google.com [IPv6:2a00:1450:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE5F0D8 for ; Mon, 29 May 2023 07:36:46 -0700 (PDT) Received: by mail-ej1-x634.google.com with SMTP id a640c23a62f3a-96f8d485ef3so524918766b.0 for ; Mon, 29 May 2023 07:36:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371005; x=1687963005; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=hoz29iQzbmqSH9FV21Yd3fKmX3zIbwdSxRPnx4zdKWc=; b=2r2Tz0ll4Fett0BLP4WbT8OyeDcRUfVM19AB8hqjoP0qsifTiJmvJqoArrPJnehVw6 KqZCljupQjoGQbefAj4rEP77mifDcaUFkU794QF5D78+Wt8zRdiKmuOsP3ftNepBg+6g adqfVbfbUn3Ok3I5vUtQEvvPX6azl1AB861h3byZnXsuMvmmi7mm/YA+SuvZDvhEz4sX KzHX4ztMFqnGvcJXsDYi8/EMQVaU9Er7K+i+MHQGQAEUkpF+1rf2WkbM4sFFH6wPT5SG qJ8P7/WwcGtJVQd2bgM/HiNy7pZ7HrPsrjpTM1QtAqFBxuQaspPhQqrvksmaKnhor2Ts BjWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371005; x=1687963005; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hoz29iQzbmqSH9FV21Yd3fKmX3zIbwdSxRPnx4zdKWc=; b=Z2JtzLAFZ9efh6B9Kl+PpB9EEas1k+uA0/KSK5VMx/SnYuzlMZqCPF4o2YFPzpbCdR VszE+gKryrifNSNxboqTPLweMl55QH282wVcftxU4NE9yAX4HwzMYsb9BQHadMma+rHd JExlyX9smk+cbGunmANEfloQw7kpzj7ebpw2AP4Kr9WAJ3Ak2IPOZ+A1lqo0bBYHT822 7DnHplrAa9UUMOBHPHuOulizVatnVZQIEIHMZnryPmt23OEi0prx6Ng2exsfMFtl2ioL AHkHBx0vjoXR0tGV7m+haYQZqkaEDwLbE6MhwrJrO3PGP1ctH5WgmMBC6hlWFu8lxMgz Fqyw== X-Gm-Message-State: AC+VfDz4GMmKXEjbk5u4hZJvOcCAdiUrZ8/cYOBh1ss5egDgrErJ9tSb hotZ5ziPH1H+EiNyBkwra+2+dQ== X-Google-Smtp-Source: ACHHUZ4jHs7unZGYRdVucEPdwhG89w25xE3fmgjIBoSAZmGrSxmBxii+ELrB86BZpmQNm4qG/XWysA== X-Received: by 2002:a17:907:934b:b0:96a:ad45:fd51 with SMTP id bv11-20020a170907934b00b0096aad45fd51mr9566539ejc.27.1685371005136; Mon, 29 May 2023 07:36:45 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:44 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:02 +0200 Subject: [PATCH v4 5/8] drm/mediatek: hdmi: add v2 support MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-5-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Adds hdmi and hdmi-ddc support for v2 IP. Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/Kconfig | 2 + drivers/gpu/drm/mediatek/Makefile | 2 + drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 13 + drivers/gpu/drm/mediatek/mtk_hdmi_common.h | 1 + drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 362 +++++++++ drivers/gpu/drm/mediatek/mtk_hdmi_regs_v2.h | 276 +++++++ drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 1105 +++++++++++++++++++++++= ++++ drivers/gpu/drm/mediatek/mtk_hdmi_v2.h | 30 + 8 files changed, 1791 insertions(+) diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kc= onfig index b451dee64d34..242992cd1439 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -34,5 +34,7 @@ config DRM_MEDIATEK_HDMI depends on DRM_MEDIATEK select SND_SOC_HDMI_CODEC if SND_SOC select PHY_MTK_HDMI + select DRM_DISPLAY_HDMI_HELPER + select DRM_DISPLAY_HELPER help DRM/KMS HDMI driver for Mediatek SoCs diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/M= akefile index 79bbaa58893e..bb60856b629e 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -24,6 +24,8 @@ mediatek-drm-hdmi-objs :=3D mtk_cec.o \ mtk_hdmi.o \ mtk_hdmi_common.o \ mtk_hdmi_ddc.o \ + mtk_hdmi_ddc_v2.o \ + mtk_hdmi_v2.o \ =20 obj-$(CONFIG_DRM_MEDIATEK_HDMI) +=3D mediatek-drm-hdmi.o =20 diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.c index d7f3d29138d8..97a00102a970 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -341,6 +341,15 @@ static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8173= =3D { .num_clocks =3D MTK_HDMIV1_CLK_COUNT, }; =20 +static const struct mtk_hdmi_conf mtk_hdmi_conf_v2 =3D { + .bridge_funcs =3D &mtk_v2_hdmi_bridge_funcs, + .mtk_hdmi_output_init =3D mtk_hdmi_output_init_v2, + .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_v2, + .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_v2, + .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v2, + .num_clocks =3D MTK_HDMIV2_CLK_COUNT, +}; + static const struct of_device_id mtk_drm_hdmi_of_ids[] =3D { { .compatible =3D "mediatek,mt2701-hdmi", .data =3D &mtk_hdmi_conf_mt2701, @@ -351,6 +360,9 @@ static const struct of_device_id mtk_drm_hdmi_of_ids[] = =3D { { .compatible =3D "mediatek,mt8173-hdmi", .data =3D &mtk_hdmi_conf_mt8173, }, + { .compatible =3D "mediatek,mt8195-hdmi", + .data =3D &mtk_hdmi_conf_v2, + }, {} }; MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_of_ids); @@ -399,6 +411,7 @@ static struct platform_driver mtk_hdmi_driver =3D { static struct platform_driver * const mtk_hdmi_drivers[] =3D { &mtk_hdmi_ddc_driver, &mtk_cec_driver, + &mtk_hdmi_ddc_v2_driver, &mtk_hdmi_driver, }; =20 diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.h index 6e4633981018..86de8942727d 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h @@ -27,6 +27,7 @@ =20 #include "mtk_cec.h" #include "mtk_hdmi.h" +#include "mtk_hdmi_v2.h" =20 struct mtk_hdmi_conf { bool tz_disabled; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_ddc_v2.c new file mode 100644 index 000000000000..c9e8424109f0 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2021 BayLibre, SAS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mtk_hdmi_regs_v2.h" +#include "mtk_hdmi_v2.h" + +#define EDID_ID 0x50 +#define DDC2_CLOK 572 /* BIM=3D208M/(v*4) =3D 90Khz */ +#define DDC2_CLOK_EDID 832 /* BIM=3D208M/(v*4) =3D 62.5Khz */ + +struct mtk_hdmi_ddc { + struct device *dev; + /* Serialize read/write operations */ + struct mutex mtx; + struct i2c_adapter adap; + struct clk *clk; + void __iomem *regs; +}; + +enum sif_bit_t_hdmi { + SIF_8_BIT_HDMI, /* /< [8 bits data address.] */ + SIF_16_BIT_HDMI, /* /< [16 bits data address.] */ +}; + +static void hdmi_ddc_request(struct mtk_hdmi_ddc *ddc) +{ + regmap_update_bits(ddc->regs, HDCP2X_POL_CTRL, HDCP2X_DIS_POLL_EN, + HDCP2X_DIS_POLL_EN); +} + +static void mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, unsigned int addr_id, + unsigned int offset_id, unsigned char wr_data) +{ + u32 val; + + regmap_read(ddc->regs, HDCP2X_DDCM_STATUS, &val); + + if (val & DDC_I2C_BUS_LOW) { + regmap_update_bits(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, CLOCK_SCL), = DDC_CMD); + usleep_range(250, 300); + } + regmap_update_bits(ddc->regs, HPD_DDC_CTRL, FIELD_PREP(DDC_DELAY_CNT, DDC= 2_CLOK), DDC_DELAY_CNT); + regmap_write(ddc->regs, SI2C_CTRL, FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ)); + regmap_update_bits(ddc->regs, SI2C_CTRL, FIELD_PREP(SI2C_WDATA, wr_data),= SI2C_WDATA); + regmap_update_bits(ddc->regs, SI2C_CTRL, SI2C_WR, SI2C_WR); + + regmap_write(ddc->regs, DDC_CTRL, + FIELD_PREP(DDC_CMD, SEQ_WRITE_REQ_ACK) | + FIELD_PREP(DDC_DIN_CNT, 1) | + FIELD_PREP(DDC_OFFSET, offset_id) | + (addr_id << 1)); + + usleep_range(1000, 1250); + regmap_read(ddc->regs, HDCP2X_DDCM_STATUS, &val); + + if (val & DDC_I2C_BUS_LOW) { + regmap_update_bits(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, CLOCK_SCL), = DDC_CMD); + usleep_range(250, 300); + } +} + +static unsigned char +ddcm_read_hdmi(struct mtk_hdmi_ddc *ddc, + unsigned int u4_clk_div, unsigned char uc_dev, unsigned int u4_add= r, + enum sif_bit_t_hdmi uc_addr_type, unsigned char *puc_value, + unsigned int u4_count) +{ + u32 val; + unsigned int i, temp_length, loop_counter, uc_read_count, uc_idx =3D 0; + + if (!puc_value || !u4_count || !u4_clk_div) + return 0; + + uc_idx =3D 0; + regmap_read(ddc->regs, HDCP2X_DDCM_STATUS, &val); + if (val & DDC_I2C_BUS_LOW) { + regmap_update_bits(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, CLOCK_SCL), = DDC_CMD); + usleep_range(250, 300); + } + + regmap_update_bits(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, CLEAR_FIFO), = DDC_CMD); + + if (u4_count >=3D 16) { + temp_length =3D 16; + loop_counter =3D + u4_count / 16 + (u4_count % 16 =3D=3D 0); + } else { + temp_length =3D u4_count; + loop_counter =3D 1; + } + if (uc_dev >=3D EDID_ID) { + if (u4_clk_div < DDC2_CLOK_EDID) + u4_clk_div =3D DDC2_CLOK_EDID; + } + regmap_update_bits(ddc->regs, HPD_DDC_CTRL, FIELD_PREP(DDC_DELAY_CNT, u4_= clk_div), DDC_DELAY_CNT); + for (i =3D 0; i < loop_counter; i++) { + if (i =3D=3D (loop_counter - 1) && i !=3D 0 && + u4_count % 16) + temp_length =3D u4_count % 16; + if (uc_dev > EDID_ID) { + regmap_update_bits(ddc->regs, SCDC_CTRL, FIELD_PREP(DDC_SEGMENT, uc_dev= - EDID_ID), DDC_SEGMENT); + regmap_write(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, ENH_READ_NO_ACK) | + FIELD_PREP(DDC_DIN_CNT, temp_length) | + FIELD_PREP(DDC_OFFSET, u4_addr + i * temp_length) | + (EDID_ID << 1)); + } else { + regmap_write(ddc->regs, DDC_CTRL, FIELD_PREP(DDC_CMD, SEQ_READ_NO_ACK) | + FIELD_PREP(DDC_DIN_CNT, temp_length) | + FIELD_PREP(DDC_OFFSET, u4_addr + i * 16) | + (uc_dev << 1)); + } + usleep_range(5000, 5500); + if (regmap_read_poll_timeout(ddc->regs, HPD_DDC_STATUS, val, + !(val & DDC_I2C_IN_PROG), 2000, temp_length + 5)) { + dev_err(ddc->dev, "time out waiting for DDC I2C\n"); + return 0; + } + regmap_read(ddc->regs, HDCP2X_DDCM_STATUS, &val); + if ((val & (DDC_I2C_NO_ACK | DDC_I2C_BUS_LOW))) { + regmap_read(ddc->regs, HDCP2X_DDCM_STATUS, &val); + if (val & DDC_I2C_BUS_LOW) { + regmap_update_bits(ddc->regs, DDC_CTRL, + FIELD_PREP(DDC_CMD, CLOCK_SCL), DDC_CMD); + usleep_range(250, 300); + } + return 0; + } + for (uc_idx =3D 0; uc_idx < temp_length; uc_idx++) { + regmap_write(ddc->regs, SI2C_CTRL, + FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) | SI2C_RD); + regmap_write(ddc->regs, SI2C_CTRL, + FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) | SI2C_CONFIRM_READ); + regmap_read(ddc->regs, HPD_DDC_STATUS, &val); + puc_value[i * 16 + uc_idx] =3D FIELD_GET(DDC_DATA_OUT, val); + /* + * when reading edid, if hdmi module been reset, + * ddc will fail and it's speed will be set to 400. + */ + regmap_read(ddc->regs, HPD_DDC_CTRL, &val); + if (((val >> 16) & 0xFFFF) < DDC2_CLOK) + return 0; + + uc_read_count =3D i * 16 + uc_idx + 1; + } + } + return uc_read_count; +} + +static unsigned char vddc_read(struct mtk_hdmi_ddc *ddc, unsigned int u4_c= lk_div, + unsigned char uc_dev, unsigned int u4_addr, + enum sif_bit_t_hdmi uc_addr_type, + unsigned char *puc_value, unsigned int u4_count) +{ + unsigned int u4_read_count =3D 0; + unsigned char uc_return_value =3D 0; + + if (!puc_value || !u4_count || !u4_clk_div || + uc_addr_type > SIF_16_BIT_HDMI || + (uc_addr_type =3D=3D SIF_8_BIT_HDMI && u4_addr > 255) || + (uc_addr_type =3D=3D SIF_16_BIT_HDMI && u4_addr > 65535)) { + return 0; + } + + if (uc_addr_type =3D=3D SIF_8_BIT_HDMI) + u4_read_count =3D 255 - u4_addr + 1; + else if (uc_addr_type =3D=3D SIF_16_BIT_HDMI) + u4_read_count =3D 65535 - u4_addr + 1; + + u4_read_count =3D (u4_read_count > u4_count) ? u4_count : u4_read_count; + uc_return_value =3D ddcm_read_hdmi(ddc, u4_clk_div, uc_dev, u4_addr, + uc_addr_type, puc_value, u4_read_count); + return uc_return_value; +} + +static bool fg_ddc_data_read(struct mtk_hdmi_ddc *ddc, + unsigned char b_dev, + unsigned char b_data_addr, + unsigned char b_data_count, + unsigned char *pr_data) +{ + int ret; + + mutex_lock(&ddc->mtx); + + hdmi_ddc_request(ddc); + ret =3D vddc_read(ddc, DDC2_CLOK, b_dev, b_data_addr, SIF_8_BIT_HDMI, + pr_data, b_data_count); + mutex_unlock(&ddc->mtx); + + return ret =3D=3D b_data_count; +} + +static void fg_ddc_data_write(struct mtk_hdmi_ddc *ddc, + unsigned char b_dev, + unsigned char b_data_addr, + unsigned char b_data_count, + unsigned char *pr_data) +{ + unsigned int i; + + mutex_lock(&ddc->mtx); + + hdmi_ddc_request(ddc); + for (i =3D 0; i < b_data_count; i++) + mtk_ddc_wr_one(ddc, b_dev, b_data_addr + i, *(pr_data + i)); + + mutex_unlock(&ddc->mtx); +} + +static int mtk_hdmi_ddc_xfer(struct i2c_adapter *adapter, struct i2c_msg *= msgs, + int num) +{ + struct mtk_hdmi_ddc *ddc =3D adapter->algo_data; + struct device *dev =3D adapter->dev.parent; + bool ret; + int i; + unsigned char offset; + + if (!ddc) + return -EINVAL; + + for (i =3D 0; i < num; i++) { + struct i2c_msg *msg =3D &msgs[i]; + + if (msg->flags & I2C_M_RD) { + /* The underlying DDC hardware always issue a write request + * that assigns the read offset as part of the read operation. + * Therefore we need to use the offset value assigned + * in the previous write request from the drm_edid.c + */ + ret =3D fg_ddc_data_read(ddc, msg->addr, + offset, /* determined by previous write requests */ + (msg->len), &msg->buf[0]); + if (!ret) { + dev_err(dev, "ddc read failed : %d\n", ret); + return ret; + } + } else { + fg_ddc_data_write(ddc, msg->addr, msg->buf[0], + (msg->len - 1), &msg->buf[1]); + + /* we store the offset value requested by drm_edid framework + * to use in subsequent read requests. + */ + if (DDC_ADDR =3D=3D msg->addr && 1 =3D=3D msg->len) + offset =3D msg->buf[0]; + } + } + + return i; +} + +static u32 mtk_hdmi_ddc_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm mtk_hdmi_ddc_algorithm =3D { + .master_xfer =3D mtk_hdmi_ddc_xfer, + .functionality =3D mtk_hdmi_ddc_func, +}; + +static int mtk_hdmi_ddc_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct device_node *hdmi; + struct mtk_hdmi_ddc *ddc; + int ret; + + ddc =3D devm_kzalloc(dev, sizeof(struct mtk_hdmi_ddc), GFP_KERNEL); + if (!ddc) + return -ENOMEM; + + ddc->dev =3D dev; + hdmi =3D of_parse_phandle(dev->of_node, "mediatek,hdmi", 0); + if (IS_ERR_OR_NULL(hdmi)) + return dev_err_probe(dev, -ENODEV, "mediatek hdmi not found"); + + ddc->regs =3D device_node_to_regmap(hdmi); + of_node_put(hdmi); + if (IS_ERR(ddc->regs)) + return dev_err_probe(dev, PTR_ERR(ddc->regs), "Unable to get hdmi syscon= "); + + ddc->clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(ddc->clk)) + return dev_err_probe(dev, PTR_ERR(ddc->clk), "get ddc_clk failed: %p ,\n= ", ddc->clk); + + mutex_init(&ddc->mtx); + + strscpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); + ddc->adap.owner =3D THIS_MODULE; + ddc->adap.class =3D I2C_CLASS_DDC; + ddc->adap.algo =3D &mtk_hdmi_ddc_algorithm; + ddc->adap.retries =3D 3; + ddc->adap.dev.of_node =3D dev->of_node; + ddc->adap.algo_data =3D ddc; + ddc->adap.dev.parent =3D &pdev->dev; + + ret =3D devm_i2c_add_adapter(dev, &ddc->adap); + if (ret < 0) { + clk_disable_unprepare(ddc->clk); + return dev_err_probe(dev, ret, "failed to add bus to i2c core\n"); + } + + platform_set_drvdata(pdev, ddc); + return 0; +} + +static int mtk_hdmi_ddc_remove(struct platform_device *pdev) +{ + struct mtk_hdmi_ddc *ddc =3D platform_get_drvdata(pdev); + + mutex_destroy(&ddc->mtx); + clk_disable_unprepare(ddc->clk); + + return 0; +} + +static const struct of_device_id mtk_hdmi_ddc_match[] =3D { + { + .compatible =3D "mediatek,mt8195-hdmi-ddc", + }, + {}, +}; + +struct platform_driver mtk_hdmi_ddc_v2_driver =3D { + .probe =3D mtk_hdmi_ddc_probe, + .remove =3D mtk_hdmi_ddc_remove, + .driver =3D { + .name =3D "mediatek-hdmi-mt8195-ddc", + .of_match_table =3D mtk_hdmi_ddc_match, + }, +}; + +MODULE_AUTHOR("Can Zeng "); +MODULE_DESCRIPTION("MediaTek HDMI DDC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_regs_v2.h b/drivers/gpu/drm/= mediatek/mtk_hdmi_regs_v2.h new file mode 100644 index 000000000000..7cce175e6b27 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_regs_v2.h @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2021 BayLibre, SAS + */ + +#ifndef _MTK_HDMI_REGS_H +#define _MTK_HDMI_REGS_H + +#define AIP_CTRL BIT(10) +#define AIP_CTS_SVAL 0x408 +#define AIP_I2S_CHST0 0x414 +#define AIP_I2S_CHST1 0x418 +#define AIP_I2S_CTRL 0x410 +#define AIP_N_VAL 0x404 +#define AIP_SPDIF_CTRL 0x40C +#define AIP_TPI_CTRL 0x428 +#define AIP_TXCTRL 0x424 + +#define AUD_DIS (0x0) +#define AUD_DIS_WR (0x0) +#define AUD_EN BIT(2) +#define AUD_EN_WR BIT(18) +#define AUD_ERR_THRESH GENMASK(29, 24) +#define AUD_IN_EN BIT(8) +#define AUD_MUTE_DIS (0x0) +#define AUD_MUTE_FIFO_EN BIT(5) +#define AUD_PACKET_DROP BIT(6) +#define AUD_RPT_DIS (0x0) +#define AUD_RPT_EN BIT(2) +#define AUD_SEL_OWRT BIT(9) + +#define AVI_DIS (0) +#define AVI_DIS_WR (0) +#define AVI_EN (0x1) +#define AVI_EN_WR BIT(16) +#define AVI_HEADER GENMASK(23, 0) +#define AVI_PKT00 GENMASK(31, 0) +#define AVI_PKT01 GENMASK(23, 0) +#define AVI_PKT02 GENMASK(31, 0) +#define AVI_PKT03 GENMASK(23, 0) +#define AVI_PKT04 GENMASK(31, 0) +#define AVI_PKT05 GENMASK(23, 0) +#define AVI_RPT_DIS (0x0) +#define AVI_RPT_EN (0x1) + +#define C422_C420_CONFIG_BYPASS BIT(5) +#define C422_C420_CONFIG_ENABLE BIT(4) +#define C422_C420_CONFIG_OUT_CB_OR_CR BIT(6) +#define C444_C422_CONFIG_ENABLE (0x1) + +#define CBIT_ORDER_SAME BIT(13) + +#define CLEAR_FIFO 0x9 + +#define CLOCK_SCL 0xA + +#define CP_CLR_MUTE_EN BIT(1) +#define CP_EN BIT(5) +#define CP_EN_WR BIT(21) +#define CP_RPT_EN BIT(5) +#define CP_SET_MUTE_DIS (0) +#define CP_SET_MUTE_EN (1) + +#define CTS_CAL_N4 BIT(23) +#define CTS_REQ_EN BIT(1) +#define CTS_SW_SEL (1) + +#define C_SD0 (0x0) +#define C_SD1 BIT(4) +#define C_SD2 BIT(9) +#define C_SD3 GENMASK(14, 12) +#define C_SD4 BIT(19) +#define C_SD5 (0x5 << 20) +#define C_SD6 GENMASK(26, 25) +#define C_SD7 GENMASK(30, 28) + +#define DATA_DIR_LSB BIT(9) +#define DATA_DIR_MSB (0) + +#define DDC_CMD GENMASK(31, 28) +#define DDC_CTRL 0xC10 +#define DDC_DATA_OUT GENMASK(23, 16) +#define DDC_DELAY_CNT GENMASK(31, 16) +#define DDC_DIN_CNT GENMASK(25, 16) +#define DDC_I2C_BUS_LOW BIT(11) +#define DDC_I2C_IN_PROG BIT(13) +#define DDC_I2C_NO_ACK BIT(10) +#define DDC_OFFSET GENMASK(15, 8) +#define DDC_SEGMENT GENMASK(15, 8) + +#define DEEPCOLOR_MODE_8BIT (0) +#define DEEPCOLOR_MODE_MASKBIT GENMASK(10, 8) +#define DEEPCOLOR_PAT_EN BIT(12) +#define DEEP_COLOR_ADD BIT(4) + +#define DOWNSAMPLE 0x2 + +#define DSD_EN BIT(15) +#define DSD_MUTE_DATA BIT(7) + +#define ENH_READ_NO_ACK 0x4 + +#define FIFO0_MAP GENMASK(1, 0) +#define FIFO1_MAP GENMASK(3, 2) +#define FIFO2_MAP GENMASK(5, 4) +#define FIFO3_MAP GENMASK(7, 6) + +#define FS_OVERRIDE_WRITE BIT(1) +#define FS_UNOVERRIDE (0) + +#define HBRA_ON BIT(14) + +#define HBR_FROM_SPDIF BIT(20) + +#define HDCP1X_CTRL 0xCD0 +#define HDCP1X_ENC_EN BIT(6) +#define HDCP2X_CTRL_0 0xC20 +#define HDCP2X_DDCM_STATUS 0xC68 +#define HDCP2X_DIS_POLL_EN BIT(16) +#define HDCP2X_EN (0x1) +#define HDCP2X_ENCRYPT_EN BIT(7) +#define HDCP2X_HPD_OVR BIT(10) +#define HDCP2X_HPD_SW BIT(11) +#define HDCP2X_POL_CTRL 0xC54 +#define HDCP2X_RX_REAUTH_REQ_DDCM_INT_UNMASK BIT(25) +#define HDCP_TOP_CTRL 0xC00 + +#define HDMI2_ON BIT(2) + +#define HDMITX_CONFIG 0x900 +#define HDMITX_SW_HPD BIT(29) +#define HDMITX_SW_RSTB BIT(31) + +#define HDMI_MODE_DVI (0) +#define HDMI_MODE_HDMI BIT(3) + +#define HDMI_YUV420_MODE BIT(10) + +#define HPD_DDC_CTRL 0xC08 +#define HPD_DDC_STATUS 0xC60 + +#define HPD_PIN_STA BIT(4) + +#define HTPLG_F_INT_STA BIT(1) +#define HTPLG_R_INT_STA BIT(0) + +#define I2S2DSD_EN BIT(30) +#define I2S_1ST_BIT_NOSHIFT BIT(8) +#define I2S_EN GENMASK(19, 16) + +#define JUSTIFY_RIGHT BIT(10) + +#define LAYOUT BIT(18) +#define LAYOUT0 0 +#define LAYOUT1 BIT(4) + +#define LFE_CC_SWAP BIT(1) + +#define MAP_SD0 0x0 +#define MAP_SD1 0x1 +#define MAP_SD2 0x2 +#define MAP_SD3 0x3 + +#define MAX_1UI_WRITE GENMASK(15, 8) +#define MAX_2UI_WRITE GENMASK(23, 16) + +#define MCLK_128FS 0x0 +#define MCLK_256FS 0x1 +#define MCLK_384FS 0x2 +#define MCLK_512FS 0x3 +#define MCLK_768FS 0x4 +#define MCLK_CTSGEN_SEL 0 +#define MCLK_EN BIT(2) +#define NO_MCLK_CTSGEN_SEL BIT(3) + +#define NULL_PKT_EN BIT(2) +#define NULL_PKT_VSYNC_HIGH_EN BIT(3) + +#define OUTPUT_FORMAT_DEMUX_420_ENABLE BIT(10) + +#define PORD_F_INT_STA BIT(3) +#define PORD_PIN_STA BIT(5) +#define PORD_R_INT_STA BIT(2) + +#define REG_VMUTE_EN BIT(16) +#define RST4AUDIO BIT(0) +#define RST4AUDIO_ACR BIT(2) +#define RST4AUDIO_FIFO BIT(1) + +#define SCDC_CTRL 0xC18 + +#define SCK_EDGE_RISE BIT(14) + +#define SCR_ON BIT(4) + +#define SEQ_READ_NO_ACK 0x2 +#define SEQ_WRITE_REQ_ACK 0x7 + +#define SI2C_ADDR GENMASK(23, 16) +#define SI2C_ADDR_READ (0xF4) +#define SI2C_CONFIRM_READ BIT(2) +#define SI2C_CTRL 0xCAC +#define SI2C_RD BIT(1) +#define SI2C_WDATA GENMASK(15, 8) +#define SI2C_WR BIT(0) + +#define SPDIF_EN BIT(13) +#define SPDIF_HEADER GENMASK(23, 0) +#define SPDIF_INTERNAL_MODULE BIT(24) +#define SPDIF_PKT00 GENMASK(31, 0) +#define SPDIF_PKT01 GENMASK(23, 0) +#define SPDIF_PKT02 GENMASK(31, 0) +#define SPDIF_PKT03 GENMASK(23, 0) +#define SPDIF_PKT04 GENMASK(31, 0) +#define SPDIF_PKT05 GENMASK(23, 0) +#define SPDIF_PKT06 GENMASK(31, 0) +#define SPDIF_PKT07 GENMASK(23, 0) + +#define SPD_DIS 0 +#define SPD_DIS_WR 0 +#define SPD_EN BIT(1) +#define SPD_EN_WR BIT(17) +#define SPD_RPT_DIS 0 +#define SPD_RPT_EN BIT(1) + +#define TOP_AIF_HEADER 0x040 +#define TOP_AIF_PKT00 0x044 +#define TOP_AIF_PKT01 0x048 +#define TOP_AIF_PKT02 0x04C +#define TOP_AIF_PKT03 0x050 +#define TOP_AUD_MAP 0x00C +#define TOP_AVI_HEADER 0x024 +#define TOP_AVI_PKT00 0x028 +#define TOP_AVI_PKT01 0x02C +#define TOP_AVI_PKT02 0x030 +#define TOP_AVI_PKT03 0x034 +#define TOP_AVI_PKT04 0x038 +#define TOP_AVI_PKT05 0x03C +#define TOP_CFG00 0x000 +#define TOP_CFG01 0x004 +#define TOP_INFO_EN 0x01C +#define TOP_INFO_RPT 0x020 +#define TOP_INT_CLR00 0x1B8 +#define TOP_INT_CLR01 0x1BC +#define TOP_INT_MASK00 0x1B0 +#define TOP_INT_MASK01 0x1B4 +#define TOP_INT_STA00 0x1A8 +#define TOP_MISC_CTLR 0x1A4 +#define TOP_SPDIF_HEADER 0x054 +#define TOP_SPDIF_PKT00 0x058 +#define TOP_SPDIF_PKT01 0x05C +#define TOP_SPDIF_PKT02 0x060 +#define TOP_SPDIF_PKT03 0x064 +#define TOP_SPDIF_PKT04 0x068 +#define TOP_SPDIF_PKT05 0x06C +#define TOP_SPDIF_PKT06 0x070 +#define TOP_SPDIF_PKT07 0x074 +#define TOP_VMUTE_CFG1 0x1C8 + +#define TPI_AUDIO_LOOKUP_DIS 0 +#define TPI_AUDIO_LOOKUP_EN BIT(2) + +#define VBIT_COM BIT(12) +#define VBIT_PCM 0 + +#define VID_DOWNSAMPLE_CONFIG 0x8F0 +#define VID_OUT_FORMAT 0x8FC + +#define WR_1UI_LOCK BIT(0) +#define WR_1UI_UNLOCK 0 +#define WR_2UI_LOCK BIT(2) +#define WR_2UI_UNLOCK 0 +#define WS_HIGH BIT(11) + +#endif /* _MTK_HDMI_REGS_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.c new file mode 100644 index 000000000000..98b1d50ecd72 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c @@ -0,0 +1,1105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mtk_drm_crtc.h" +#include "mtk_hdmi_common.h" +#include "mtk_hdmi_regs_v2.h" +#include "mtk_hdmi_v2.h" + +#define RGB444_8bit BIT(0) +#define RGB444_10bit BIT(1) +#define RGB444_12bit BIT(2) +#define RGB444_16bit BIT(3) + +#define YCBCR444_8bit BIT(4) +#define YCBCR444_10bit BIT(5) +#define YCBCR444_12bit BIT(6) +#define YCBCR444_16bit BIT(7) + +#define YCBCR422_8bit_NO_SUPPORT BIT(8) +#define YCBCR422_10bit_NO_SUPPORT BIT(9) +#define YCBCR422_12bit BIT(10) +#define YCBCR422_16bit_NO_SUPPORT BIT(11) + +#define YCBCR420_8bit BIT(12) +#define YCBCR420_10bit BIT(13) +#define YCBCR420_12bit BIT(14) +#define YCBCR420_16bit BIT(15) + +#define BYTES_TO_UINT32(msb, b1, b2, lsb) = \ + ((((msb) & 0xff) << 24) + (((b1) & 0xff) << 16) + (((b2) & 0xff) << 8) + = \ + (((lsb) & 0xff))) + +const char *const mtk_hdmi_clk_names_v2[MTK_HDMIV2_CLK_COUNT] =3D { + [MTK_HDMIV2_CLK_HDMI_APB_SEL] =3D "hdmi_apb_sel", + [MTK_HDMIV2_HDCP_SEL] =3D "hdcp_sel", + [MTK_HDMIV2_HDCP_24M_SEL] =3D "hdcp24_sel", + [MTK_HDMIV2_VPP_SPLIT_HDMI] =3D "split_hdmi", +}; + +static inline void mtk_hdmi_clr_all_int_status(struct mtk_hdmi *hdmi) +{ + /*clear all tx irq*/ + regmap_write(hdmi->regs, TOP_INT_CLR00, 0xffffffff); + regmap_write(hdmi->regs, TOP_INT_CLR00, 0x00000000); + regmap_write(hdmi->regs, TOP_INT_CLR01, 0xffffffff); + regmap_write(hdmi->regs, TOP_INT_CLR01, 0x00000000); +} + +static inline void mtk_hdmi_disable_all_int(struct mtk_hdmi *hdmi) +{ + /*disable all tx irq*/ + regmap_write(hdmi->regs, TOP_INT_MASK00, 0); + regmap_write(hdmi->regs, TOP_INT_MASK01, 0); +} + +static inline void mtk_hdmi_en_hdcp_reauth_int(struct mtk_hdmi *hdmi, + bool enable) +{ + u32 val =3D 0; + if (enable) + val =3D HDCP2X_RX_REAUTH_REQ_DDCM_INT_UNMASK; + + regmap_update_bits(hdmi->regs, TOP_INT_MASK00, HDCP2X_RX_REAUTH_REQ_DDCM_= INT_UNMASK, val); +} + +static inline void mtk_hdmi_enable_hpd_pord_irq(struct mtk_hdmi *hdmi, + bool enable) +{ + u32 val =3D 0; + if (enable) + val =3D 0xf; + + regmap_update_bits(hdmi->regs, TOP_INT_MASK00, 0xf, val); +} + +static inline void mtk_hdmi_clr_htplg_pord_irq(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, TOP_INT_CLR00, 0xf, 0xf); + regmap_update_bits(hdmi->regs, TOP_INT_CLR00, 0xf, 0); +} + +static inline void mtk_hdmi_set_sw_hpd(struct mtk_hdmi *hdmi, bool high) +{ + u32 val =3D 0; + if (high) + val =3D HDMITX_SW_HPD; + + regmap_update_bits(hdmi->regs, HDMITX_CONFIG, HDMITX_SW_HPD, val); +} + +static inline void mtk_hdmi_force_hdcp_hpd(struct mtk_hdmi *hdmi) +{ + /* force HDCP HPD to 1*/ + regmap_update_bits(hdmi->regs, HDCP2X_CTRL_0, HDCP2X_HPD_OVR, HDCP2X_HPD_= OVR); + regmap_update_bits(hdmi->regs, HDCP2X_CTRL_0, HDCP2X_HPD_SW, HDCP2X_HPD_S= W); +} + +static void mtk_hdmi_disable_hdcp_encrypt(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, HDCP2X_CTRL_0, HDCP2X_ENCRYPT_EN, 0); + regmap_update_bits(hdmi->regs, HDCP1X_CTRL, HDCP1X_ENC_EN, 0); +} + +static inline void mtk_hdmi_enable_scrambling(struct mtk_hdmi *hdmi, + bool enable) +{ + usleep_range(100, 150); + + u32 val =3D 0; + if (enable) + val =3D SCR_ON | HDMI2_ON; + + regmap_update_bits(hdmi->regs, TOP_CFG00, SCR_ON | HDMI2_ON, val); + + drm_scdc_set_scrambling(hdmi->curr_conn, enable); + drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, enable); +} + +static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) +{ + u32 val =3D 0; + if (black) + val =3D REG_VMUTE_EN; + + regmap_update_bits(hdmi->regs, TOP_VMUTE_CFG1, REG_VMUTE_EN, val); +} + +static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, HDMITX_CONFIG, HDMITX_SW_RSTB, 0); + udelay(5); + regmap_update_bits(hdmi->regs, HDMITX_CONFIG, HDMITX_SW_RSTB, HDMITX_SW_R= STB); +} + +static void mtk_hdmi_enable_hdmi_mode(struct mtk_hdmi *hdmi, bool enable) +{ + u32 val =3D HDMI_MODE_DVI; + if (enable) + val =3D HDMI_MODE_HDMI; + + regmap_update_bits(hdmi->regs, TOP_CFG00, HDMI_MODE_HDMI, val); +} + +static void mtk_hdmi_hw_audio_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, + u8 len) +{ + enum hdmi_infoframe_type frame_type; + u8 frame_ver; + u8 frame_len; + u8 checksum; + + frame_type =3D buffer[0]; + frame_ver =3D buffer[1]; + frame_len =3D buffer[2]; + checksum =3D buffer[3]; + + regmap_update_bits(hdmi->regs, TOP_INFO_EN, AUD_EN_WR | AUD_EN, AUD_DIS_W= R | AUD_DIS); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN, AUD_RPT_DIS); + + regmap_write(hdmi->regs, TOP_AIF_HEADER, + BYTES_TO_UINT32(0, frame_len, frame_ver, frame_type)); + regmap_write(hdmi->regs, TOP_AIF_PKT00, + BYTES_TO_UINT32(buffer[6], buffer[5], buffer[4], + buffer[3])); + regmap_write(hdmi->regs, TOP_AIF_PKT01, + BYTES_TO_UINT32(0, 0, buffer[8], buffer[7])); + regmap_write(hdmi->regs, TOP_AIF_PKT02, 0); + regmap_write(hdmi->regs, TOP_AIF_PKT03, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN, AUD_RPT_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, AUD_EN_WR | AUD_EN, AUD_EN_WR= | AUD_EN); +} + +static void mtk_hdmi_hw_avi_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, u= 8 len) +{ + regmap_update_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN, AVI_DIS_W= R | AVI_DIS); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN, AVI_RPT_DIS); + + regmap_write(hdmi->regs, TOP_AVI_HEADER, + BYTES_TO_UINT32(0, buffer[2], buffer[1], buffer[0])); + + regmap_write(hdmi->regs, TOP_AVI_PKT00, + BYTES_TO_UINT32(buffer[6], buffer[5], buffer[4], + buffer[3])); + + regmap_write(hdmi->regs, TOP_AVI_PKT01, + BYTES_TO_UINT32(0, buffer[9], buffer[8], buffer[7])); + + regmap_write(hdmi->regs, TOP_AVI_PKT02, + BYTES_TO_UINT32(buffer[13], buffer[12], buffer[11], + buffer[10])); + + regmap_write(hdmi->regs, TOP_AVI_PKT03, + BYTES_TO_UINT32(0, buffer[16], buffer[15], buffer[14])); + + regmap_write(hdmi->regs, TOP_AVI_PKT04, 0); + regmap_write(hdmi->regs, TOP_AVI_PKT05, 0); + + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN, AVI_RPT_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN, AVI_EN_WR= | AVI_EN); +} + +static void mtk_hdmi_hw_spd_infoframe(struct mtk_hdmi *hdmi, u8 *buffer, u= 8 len) +{ + regmap_update_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN, SPD_DIS_W= R | SPD_DIS); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN, SPD_RPT_DIS); + + regmap_write(hdmi->regs, TOP_SPDIF_HEADER, + BYTES_TO_UINT32(0, buffer[2], buffer[1], buffer[0])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT00, + BYTES_TO_UINT32(buffer[6], buffer[5], buffer[4], buffer[3])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT01, + BYTES_TO_UINT32(0, buffer[9], buffer[8], buffer[7])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT02, + BYTES_TO_UINT32(buffer[13], buffer[12], buffer[11], buffer[10])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT03, + BYTES_TO_UINT32(0, buffer[16], buffer[15], buffer[14])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT04, + BYTES_TO_UINT32(buffer[20], buffer[19], buffer[18], buffer[17])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT05, + BYTES_TO_UINT32(0, buffer[23], buffer[22], buffer[21])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT06, + BYTES_TO_UINT32(buffer[27], buffer[26], buffer[25], buffer[24])); + + regmap_write(hdmi->regs, TOP_SPDIF_PKT07, + BYTES_TO_UINT32(0, 0, 0, buffer[28])); + + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN, SPD_RPT_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN, SPD_EN_WR= | SPD_EN); +} + +static int mtk_hdmi_setup_audio_infoframe(struct mtk_hdmi *hdmi) +{ + struct hdmi_codec_params *params =3D &hdmi->aud_param.codec_params; + struct hdmi_audio_infoframe frame; + u8 buffer[14]; + ssize_t err; + + memcpy(&frame, ¶ms->cea, sizeof(struct hdmi_audio_infoframe)); + + err =3D hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (err < 0) + return err; + + mtk_hdmi_hw_audio_infoframe(hdmi, buffer, sizeof(buffer)); + return 0; +} + +static void mtk_hdmi_hw_send_aud_packet(struct mtk_hdmi *hdmi, bool enable) +{ + if (enable) + regmap_update_bits(hdmi->regs, AIP_TXCTRL, AUD_PACKET_DROP, 0); + else + regmap_update_bits(hdmi->regs, AIP_TXCTRL, AUD_PACKET_DROP, AUD_PACKET_D= ROP); +} + +static inline void mtk_hdmi_hw_send_av_mute(struct mtk_hdmi *hdmi) +{ + /*GCP packet */ + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN, 0); + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_EN, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR, 0); + + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN, 0); + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_EN, CP_SET_MUTE_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN, CP_RPT_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR, CP_EN | CP_= EN_WR); +} + +static inline void mtk_hdmi_hw_send_av_unmute(struct mtk_hdmi *hdmi) +{ + /*GCP packet */ + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN, 0); + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_EN, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR, 0); + + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN, CP_CLR_MUTE_EN); + regmap_update_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_DIS, 0); + regmap_update_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN, CP_RPT_EN); + regmap_update_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR, CP_EN | CP_= EN_WR); +} + +static void mtk_hdmi_hw_ncts_enable(struct mtk_hdmi *hdmi, bool enable) +{ + unsigned int data; + + regmap_read(hdmi->regs, AIP_CTRL, &data); + + if (enable) + data |=3D CTS_SW_SEL; + else + data &=3D ~CTS_SW_SEL; + + regmap_write(hdmi->regs, AIP_CTRL, data); +} + +static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi, + u8 *channel_status) +{ + /* actually, only the first 5 or 7 bytes of Channel Status + * contain useful information + */ + regmap_write(hdmi->regs, AIP_I2S_CHST0, + BYTES_TO_UINT32(channel_status[3], channel_status[2], + channel_status[1], channel_status[0])); + regmap_write(hdmi->regs, AIP_I2S_CHST1, + BYTES_TO_UINT32(0, channel_status[6], channel_status[5], + channel_status[4])); +} + +struct hdmi_acr_n { + unsigned int clock; + unsigned int n[3]; +}; + +/* Recommended N values from HDMI specification, tables 7-1 to 7-3 */ +static const struct hdmi_acr_n hdmi_rec_n_table[] =3D { + /* Clock, N: 32kHz 44.1kHz 48kHz */ + { 25175, { 4576, 7007, 6864 } }, + { 74176, { 11648, 17836, 11648 } }, + { 148352, { 11648, 8918, 5824 } }, + { 296703, { 5824, 4459, 5824 } }, + { 297000, { 3072, 4704, 5120 } }, + { 0, { 4096, 6272, 6144 } }, /* all other TMDS clocks */ +}; + +/** + * hdmi_recommended_n() - Return N value recommended by HDMI specification + * @freq: audio sample rate in Hz + * @clock: rounded TMDS clock in kHz + */ +static int hdmi_recommended_n(unsigned int freq, unsigned int clock) +{ + const struct hdmi_acr_n *recommended; + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(hdmi_rec_n_table) - 1; i++) { + if (clock =3D=3D hdmi_rec_n_table[i].clock) + break; + } + + if (i =3D=3D ARRAY_SIZE(hdmi_rec_n_table)) + return -EINVAL; + + recommended =3D hdmi_rec_n_table + i; + + switch (freq) { + case 32000: + return recommended->n[0]; + case 44100: + return recommended->n[1]; + case 48000: + return recommended->n[2]; + case 88200: + return recommended->n[1] * 2; + case 96000: + return recommended->n[2] * 2; + case 176400: + return recommended->n[1] * 4; + case 192000: + return recommended->n[2] * 4; + default: + return (128 * freq) / 1000; + } +} + +static unsigned int hdmi_mode_clock_to_hz(unsigned int clock) +{ + switch (clock) { + case 25175: + return 25174825; /* 25.2/1.001 MHz */ + case 74176: + return 74175824; /* 74.25/1.001 MHz */ + case 148352: + return 148351648; /* 148.5/1.001 MHz */ + case 296703: + return 296703297; /* 297/1.001 MHz */ + default: + return clock * 1000; + } +} + +static unsigned int hdmi_expected_cts(unsigned int audio_sample_rate, + unsigned int tmds_clock, unsigned int n) +{ + return DIV_ROUND_CLOSEST_ULL((u64)hdmi_mode_clock_to_hz(tmds_clock) * n, + 128 * audio_sample_rate); +} + +static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, + unsigned int sample_rate, + unsigned int clock) +{ + unsigned int ncts; + int n; + + n =3D hdmi_recommended_n(sample_rate, clock); + + if (n =3D=3D -EINVAL) { + DRM_ERROR("Invalid sample rate: %u\n", sample_rate); + return; + } + + ncts =3D hdmi_expected_cts(sample_rate, clock, n); + regmap_write(hdmi->regs, AIP_N_VAL, n); + regmap_write(hdmi->regs, AIP_CTS_SVAL, ncts); +} + +static void mtk_hdmi_aud_enable_packet(struct mtk_hdmi *hdmi, bool enable) +{ + mtk_hdmi_hw_send_aud_packet(hdmi, enable); +} + +static void mtk_hdmi_aud_on_off_hw_ncts(struct mtk_hdmi *hdmi, bool on) +{ + mtk_hdmi_hw_ncts_enable(hdmi, on); +} + +static void mtk_hdmi_audio_dsd_config(struct mtk_hdmi *hdmi, + unsigned char chnum, bool dsd_bypass) +{ + regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN | DSD_EN | HBRA_ON, DSD= _EN); + regmap_update_bits(hdmi->regs, AIP_TXCTRL, DSD_MUTE_DATA, DSD_MUTE_DATA); + if (dsd_bypass) + regmap_write(hdmi->regs, TOP_AUD_MAP, 0x75316420); + else + regmap_write(hdmi->regs, TOP_AUD_MAP, 0x04230150); + + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, I2S2DSD_EN, 0); +} + +static inline void mtk_hdmi_hw_i2s_fifo_map(struct mtk_hdmi *hdmi, + unsigned int fifo_mapping) +{ + regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, FIFO3_MAP | FIFO2_MAP | FIFO= 1_MAP | FIFO0_MAP, fifo_mapping); +} + +static inline void mtk_hdmi_hw_i2s_ch_number(struct mtk_hdmi *hdmi, + unsigned int chnum) +{ + regmap_update_bits(hdmi->regs, AIP_CTRL, I2S_EN, FIELD_PREP(I2S_EN, chnum= )); +} + +static void mtk_hdmi_hw_i2s_ch_mapping(struct mtk_hdmi *hdmi, + unsigned char chnum, + unsigned char mapping) +{ + unsigned int bdata; + + switch (chnum) { + case 2: + bdata =3D 0x1; + break; + case 3: + bdata =3D 0x3; + break; + case 6: + if (mapping =3D=3D 0x0E) { + bdata =3D 0xf; + break; + } + fallthrough; + case 5: + bdata =3D 0x7; + break; + case 7: + case 8: + bdata =3D 0xf; + break; + default: + bdata =3D 0x1; + } + + mtk_hdmi_hw_i2s_fifo_map(hdmi, (MAP_SD3 << 6) | (MAP_SD2 << 4) | + (MAP_SD1 << 2) | (MAP_SD0 << 0)); + mtk_hdmi_hw_i2s_ch_number(hdmi, bdata); + + if (chnum =3D=3D 2) + regmap_update_bits(hdmi->regs, AIP_TXCTRL, LAYOUT1, LAYOUT0); + else + regmap_update_bits(hdmi->regs, AIP_TXCTRL, LAYOUT1, LAYOUT1); +} + +static void mtk_hdmi_i2s_data_fmt(struct mtk_hdmi *hdmi, unsigned char fmt) +{ + unsigned int u4Data; + + regmap_read(hdmi->regs, AIP_I2S_CTRL, &u4Data); + u4Data &=3D ~(WS_HIGH | I2S_1ST_BIT_NOSHIFT | JUSTIFY_RIGHT); + + switch (fmt) { + case HDMI_I2S_MODE_RJT_24BIT: + case HDMI_I2S_MODE_RJT_16BIT: + u4Data |=3D (WS_HIGH | I2S_1ST_BIT_NOSHIFT | JUSTIFY_RIGHT); + u4Data |=3D (WS_HIGH | I2S_1ST_BIT_NOSHIFT | JUSTIFY_RIGHT); + break; + + case HDMI_I2S_MODE_LJT_24BIT: + case HDMI_I2S_MODE_LJT_16BIT: + u4Data |=3D (WS_HIGH | I2S_1ST_BIT_NOSHIFT); + u4Data |=3D (WS_HIGH | I2S_1ST_BIT_NOSHIFT); + break; + + case HDMI_I2S_MODE_I2S_24BIT: + case HDMI_I2S_MODE_I2S_16BIT: + default: + break; + } + regmap_write(hdmi->regs, AIP_I2S_CTRL, u4Data); +} + +static inline void mtk_hdmi_i2s_sck_edge(struct mtk_hdmi *hdmi, + unsigned int edge) +{ + regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, SCK_EDGE_RISE, edge); +} + +static inline void mtk_hdmi_i2s_cbit_order(struct mtk_hdmi *hdmi, + unsigned int cbit) +{ + regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, CBIT_ORDER_SAME, cbit); +} + +static inline void mtk_hdmi_i2s_vbit(struct mtk_hdmi *hdmi, unsigned int v= bit) +{ + regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, VBIT_COM, vbit); +} + +static inline void mtk_hdmi_i2s_data_direction(struct mtk_hdmi *hdmi, + unsigned int data_dir) +{ + regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, DATA_DIR_LSB, data_dir); +} + +static inline void mtk_hdmi_hw_audio_type(struct mtk_hdmi *hdmi, + unsigned int spdif_i2s) +{ + regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN, FIELD_PREP(SPDIF_EN, s= pdif_i2s)); +} + +static unsigned char mtk_hdmi_get_i2s_ch_mapping(struct mtk_hdmi *hdmi, + unsigned char channel_type) +{ + unsigned char channelmap =3D 0x00; + + switch (channel_type) { + case HDMI_AUD_CHAN_TYPE_1_1: + case HDMI_AUD_CHAN_TYPE_2_1: + channelmap =3D 0x01; + break; + + case HDMI_AUD_CHAN_TYPE_3_0: + channelmap =3D 0x02; + break; + + case HDMI_AUD_CHAN_TYPE_3_1: + channelmap =3D 0x03; + break; + + case HDMI_AUD_CHAN_TYPE_3_0_LRS: + case HDMI_AUD_CHAN_TYPE_4_0: + channelmap =3D 0x08; + break; + + case HDMI_AUD_CHAN_TYPE_5_1: + channelmap =3D 0x0B; + break; + + case HDMI_AUD_CHAN_TYPE_4_1_CLRS: + case HDMI_AUD_CHAN_TYPE_6_0: + case HDMI_AUD_CHAN_TYPE_6_0_CS: + case HDMI_AUD_CHAN_TYPE_6_0_CH: + case HDMI_AUD_CHAN_TYPE_6_0_OH: + case HDMI_AUD_CHAN_TYPE_6_0_CHR: + channelmap =3D 0x0E; + break; + + case HDMI_AUD_CHAN_TYPE_1_0: + case HDMI_AUD_CHAN_TYPE_2_0: + case HDMI_AUD_CHAN_TYPE_3_1_LRS: + case HDMI_AUD_CHAN_TYPE_4_1: + case HDMI_AUD_CHAN_TYPE_5_0: + case HDMI_AUD_CHAN_TYPE_4_0_CLRS: + case HDMI_AUD_CHAN_TYPE_6_1: + case HDMI_AUD_CHAN_TYPE_6_1_CS: + case HDMI_AUD_CHAN_TYPE_6_1_CH: + case HDMI_AUD_CHAN_TYPE_6_1_OH: + case HDMI_AUD_CHAN_TYPE_6_1_CHR: + case HDMI_AUD_CHAN_TYPE_7_0: + case HDMI_AUD_CHAN_TYPE_7_0_LH_RH: + case HDMI_AUD_CHAN_TYPE_7_0_LSR_RSR: + case HDMI_AUD_CHAN_TYPE_7_0_LC_RC: + case HDMI_AUD_CHAN_TYPE_7_0_LW_RW: + case HDMI_AUD_CHAN_TYPE_7_0_LSD_RSD: + case HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS: + case HDMI_AUD_CHAN_TYPE_7_0_LHS_RHS: + case HDMI_AUD_CHAN_TYPE_7_0_CS_CH: + case HDMI_AUD_CHAN_TYPE_7_0_CS_OH: + case HDMI_AUD_CHAN_TYPE_7_0_CS_CHR: + case HDMI_AUD_CHAN_TYPE_7_0_CH_OH: + case HDMI_AUD_CHAN_TYPE_7_0_CH_CHR: + case HDMI_AUD_CHAN_TYPE_7_0_OH_CHR: + case HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS_LSR_RSR: + case HDMI_AUD_CHAN_TYPE_8_0_LH_RH_CS: + case HDMI_AUD_CHAN_TYPE_7_1: + case HDMI_AUD_CHAN_TYPE_7_1_LH_RH: + case HDMI_AUD_CHAN_TYPE_7_1_LSR_RSR: + case HDMI_AUD_CHAN_TYPE_7_1_LC_RC: + case HDMI_AUD_CHAN_TYPE_7_1_LW_RW: + case HDMI_AUD_CHAN_TYPE_7_1_LSD_RSD: + case HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS: + case HDMI_AUD_CHAN_TYPE_7_1_LHS_RHS: + case HDMI_AUD_CHAN_TYPE_7_1_CS_CH: + case HDMI_AUD_CHAN_TYPE_7_1_CS_OH: + case HDMI_AUD_CHAN_TYPE_7_1_CS_CHR: + case HDMI_AUD_CHAN_TYPE_7_1_CH_OH: + case HDMI_AUD_CHAN_TYPE_7_1_CH_CHR: + case HDMI_AUD_CHAN_TYPE_7_1_OH_CHR: + case HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS_LSR_RSR: + channelmap =3D 0x00; + break; + } + + return channelmap; +} + +static inline void mtk_hdmi_hw_i2s_ch_swap(struct mtk_hdmi *hdmi, + unsigned char swapbit) +{ + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, 0x0F << 20, swapbit << 20); +} + +static void mtk_hdmi_hbr_config(struct mtk_hdmi *hdmi, bool dsd_bypass) +{ + if (dsd_bypass) { + regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN | DSD_EN | HBRA_ON, HB= RA_ON); + regmap_update_bits(hdmi->regs, AIP_CTRL, I2S_EN, I2S_EN); + } else { + regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN | DSD_EN | HBRA_ON, SP= DIF_EN); + regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_INTERNAL_MODULE, SPDIF_IN= TERNAL_MODULE); + regmap_update_bits(hdmi->regs, AIP_CTRL, HBR_FROM_SPDIF, HBR_FROM_SPDIF); + regmap_update_bits(hdmi->regs, AIP_CTRL, CTS_CAL_N4, CTS_CAL_N4); + } +} + +static inline void mtk_hdmi_hw_spdif_config(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, WR_1UI_LOCK, WR_1UI_UNLOCK= ); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, FS_OVERRIDE_WRITE, FS_UNOV= ERRIDE); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, WR_2UI_LOCK, WR_2UI_UNLOCK= ); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_1UI_WRITE, FIELD_PREP(= MAX_1UI_WRITE, 0x4)); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_2UI_WRITE, FIELD_PREP(= MAX_2UI_WRITE, 0x9)); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, AUD_ERR_THRESH, FIELD_PREP= (AUD_ERR_THRESH, 0x4)); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, I2S2DSD_EN, I2S2DSD_EN); +} + +static void mtk_hdmi_aud_set_input(struct mtk_hdmi *hdmi) +{ + unsigned char ChMapping; + + regmap_write(hdmi->regs, TOP_AUD_MAP, + C_SD7 + C_SD6 + C_SD5 + C_SD4 + C_SD3 + C_SD2 + C_SD1 + + C_SD0); + regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, 0x0F << 20, 0); + regmap_update_bits(hdmi->regs, AIP_CTRL, + SPDIF_EN | DSD_EN | HBRA_ON | CTS_CAL_N4 | + HBR_FROM_SPDIF | SPDIF_INTERNAL_MODULE, 0); + regmap_update_bits(hdmi->regs, AIP_TXCTRL, DSD_MUTE_DATA | LAYOUT1, 0); + + if (hdmi->aud_param.aud_input_type =3D=3D HDMI_AUD_INPUT_I2S) { + if (hdmi->aud_param.aud_codec =3D=3D HDMI_AUDIO_CODING_TYPE_DSD) { + mtk_hdmi_audio_dsd_config(hdmi, hdmi->aud_param.codec_params.channels, = 0); + mtk_hdmi_hw_i2s_ch_mapping(hdmi, hdmi->aud_param.codec_params.channels,= 1); + } else { + mtk_hdmi_i2s_data_fmt(hdmi, hdmi->aud_param.aud_i2s_fmt); + mtk_hdmi_i2s_sck_edge(hdmi, SCK_EDGE_RISE); + mtk_hdmi_i2s_cbit_order(hdmi, CBIT_ORDER_SAME); + mtk_hdmi_i2s_vbit(hdmi, VBIT_PCM); + mtk_hdmi_i2s_data_direction(hdmi, DATA_DIR_MSB); + mtk_hdmi_hw_audio_type(hdmi, HDMI_AUD_INPUT_I2S); + ChMapping =3D mtk_hdmi_get_i2s_ch_mapping(hdmi, hdmi->aud_param.aud_inp= ut_chan_type); + mtk_hdmi_hw_i2s_ch_mapping(hdmi, hdmi->aud_param.codec_params.channels,= ChMapping); + mtk_hdmi_hw_i2s_ch_swap(hdmi, LFE_CC_SWAP); + } + } else { + if (hdmi->aud_param.aud_input_type =3D=3D HDMI_AUD_INPUT_SPDIF && + (hdmi->aud_param.aud_codec =3D=3D + HDMI_AUDIO_CODING_TYPE_DTS_HD || + hdmi->aud_param.aud_codec =3D=3D + HDMI_AUDIO_CODING_TYPE_MLP) && + hdmi->aud_param.codec_params.sample_rate =3D=3D 768000) { + mtk_hdmi_hbr_config(hdmi, false); + } else { + mtk_hdmi_hw_spdif_config(hdmi); + mtk_hdmi_hw_i2s_ch_mapping(hdmi, 2, 0); + } + } +} + +static void mtk_hdmi_aud_set_sw_ncts(struct mtk_hdmi *hdmi, + struct drm_display_mode *display_mode) +{ + unsigned int sample_rate =3D hdmi->aud_param.codec_params.sample_rate; + + mtk_hdmi_aud_on_off_hw_ncts(hdmi, false); + + mtk_hdmi_hw_aud_set_ncts(hdmi, sample_rate, display_mode->clock); +} + +static inline void mtk_hdmi_hw_audio_input_enable(struct mtk_hdmi *hdmi, + unsigned int enable) +{ + if (enable) + regmap_update_bits(hdmi->regs, AIP_CTRL, AUD_IN_EN, AUD_IN_EN); + else + regmap_update_bits(hdmi->regs, AIP_CTRL, AUD_IN_EN, 0); +} + +static void mtk_hdmi_aip_ctrl_init(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, AIP_CTRL, AUD_SEL_OWRT | NO_MCLK_CTSGEN_SE= L | MCLK_EN | CTS_REQ_EN, AUD_SEL_OWRT | NO_MCLK_CTSGEN_SEL | CTS_REQ_EN); + regmap_update_bits(hdmi->regs, AIP_TPI_CTRL, TPI_AUDIO_LOOKUP_EN, TPI_AUD= IO_LOOKUP_DIS); +} + +static void mtk_hdmi_audio_reset(struct mtk_hdmi *hdmi, bool rst) +{ + if (rst) + regmap_update_bits(hdmi->regs, AIP_TXCTRL, RST4AUDIO | RST4AUDIO_FIFO | = RST4AUDIO_ACR, RST4AUDIO | RST4AUDIO_FIFO | RST4AUDIO_ACR); + else + regmap_update_bits(hdmi->regs, AIP_TXCTRL, RST4AUDIO | RST4AUDIO_FIFO | = RST4AUDIO_ACR, 0); +} + +static void mtk_hdmi_aud_output_config(struct mtk_hdmi *hdmi, + struct drm_display_mode *display_mode) +{ + mtk_hdmi_aud_enable_packet(hdmi, false); + mtk_hdmi_audio_reset(hdmi, true); + mtk_hdmi_aip_ctrl_init(hdmi); + mtk_hdmi_aud_set_input(hdmi); + mtk_hdmi_hw_aud_set_channel_status(hdmi, hdmi->aud_param.codec_params.iec= .status); + mtk_hdmi_setup_audio_infoframe(hdmi); + mtk_hdmi_hw_audio_input_enable(hdmi, true); + mtk_hdmi_audio_reset(hdmi, false); + mtk_hdmi_aud_set_sw_ncts(hdmi, display_mode); + usleep_range(25, 50); + mtk_hdmi_aud_on_off_hw_ncts(hdmi, true); + mtk_hdmi_aud_enable_packet(hdmi, true); +} + +void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi) +{ + struct hdmi_audio_param *aud_param =3D &hdmi->aud_param; + + aud_param->aud_codec =3D HDMI_AUDIO_CODING_TYPE_PCM; + aud_param->aud_sampe_size =3D HDMI_AUDIO_SAMPLE_SIZE_16; + aud_param->aud_input_type =3D HDMI_AUD_INPUT_I2S; + aud_param->aud_i2s_fmt =3D HDMI_I2S_MODE_I2S_24BIT; + aud_param->aud_mclk =3D HDMI_AUD_MCLK_128FS; + aud_param->aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_2_0; + + hdmi->hpd =3D HDMI_PLUG_OUT; +} + +static void mtk_hdmi_change_video_resolution(struct mtk_hdmi *hdmi) +{ + mtk_hdmi_hw_reset(hdmi); + mtk_hdmi_set_sw_hpd(hdmi, true); + usleep_range(2, 5); + + regmap_write(hdmi->regs, HDCP_TOP_CTRL, 0x0); + mtk_hdmi_en_hdcp_reauth_int(hdmi, true); + mtk_hdmi_enable_hpd_pord_irq(hdmi, true); + mtk_hdmi_force_hdcp_hpd(hdmi); + + regmap_update_bits(hdmi->regs, TOP_CFG00, DEEPCOLOR_MODE_MASKBIT, DEEPCOL= OR_MODE_8BIT); + regmap_update_bits(hdmi->regs, TOP_CFG00, DEEPCOLOR_PAT_EN, 0); + regmap_update_bits(hdmi->regs, TOP_MISC_CTLR, DEEP_COLOR_ADD, 0); + mtk_hdmi_enable_hdmi_mode(hdmi, !hdmi->dvi_mode); + + usleep_range(5, 10); + mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_hw_send_av_unmute(hdmi); + + regmap_update_bits(hdmi->regs, TOP_CFG01, NULL_PKT_VSYNC_HIGH_EN | NULL_P= KT_EN, NULL_PKT_VSYNC_HIGH_EN); + + /* enable scrambling if tmds clock is over 340Mhz */ + mtk_hdmi_enable_scrambling(hdmi, hdmi->mode.clock >=3D 340 * KILO); + + regmap_update_bits(hdmi->regs, HDMITX_CONFIG, HDMI_YUV420_MODE | HDMITX_S= W_HPD, 0 | HDMITX_SW_HPD); + regmap_update_bits(hdmi->regs, VID_DOWNSAMPLE_CONFIG, C444_C422_CONFIG_EN= ABLE, 0); + regmap_update_bits(hdmi->regs, VID_DOWNSAMPLE_CONFIG, C422_C420_CONFIG_EN= ABLE, 0); + regmap_update_bits(hdmi->regs, VID_DOWNSAMPLE_CONFIG, C422_C420_CONFIG_BY= PASS, C422_C420_CONFIG_BYPASS); + regmap_update_bits(hdmi->regs, VID_DOWNSAMPLE_CONFIG, C422_C420_CONFIG_OU= T_CB_OR_CR, 0); + regmap_update_bits(hdmi->regs, VID_OUT_FORMAT, OUTPUT_FORMAT_DEMUX_420_EN= ABLE, 0); +} + +static void mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi, + struct drm_display_mode *mode) +{ + int ret; + union phy_configure_opts opts =3D { + .dp =3D { .link_rate =3D hdmi->mode.clock * KILO} + }; + + ret =3D phy_configure(hdmi->phy, &opts); + if (ret) + dev_err(hdmi->dev, "Setting clock=3D%d failed: %d", mode->clock, ret); + + mtk_hdmi_change_video_resolution(hdmi); + mtk_hdmi_aud_output_config(hdmi, mode); +} + +int mtk_hdmi_clk_enable_v2(struct mtk_hdmi *hdmi) +{ + int ret; + + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV2_HDCP_SEL]); + if (ret) + return ret; + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV2_HDCP_24M_SEL]); + if (ret) + return ret; + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV2_CLK_HDMI_APB_SEL]); + if (ret) + return ret; + ret =3D clk_prepare_enable(hdmi->clk[MTK_HDMIV2_VPP_SPLIT_HDMI]); + + return ret; +} + +void mtk_hdmi_clk_disable_v2(struct mtk_hdmi *hdmi) +{ + clk_disable_unprepare(hdmi->clk[MTK_HDMIV2_HDCP_SEL]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV2_HDCP_24M_SEL]); + clk_disable_unprepare(hdmi->clk[MTK_HDMIV2_VPP_SPLIT_HDMI]); +} + +static void mtk_hdmi_hpd_event(enum hdmi_hpd_state hpd, struct device *dev) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev) + drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev); +} + +static enum hdmi_hpd_state mtk_hdmi_hpd_pord_status(struct mtk_hdmi *hdmi) +{ + + u32 hpd_status, pin_sta, pord_pin_sta; + + regmap_read(hdmi->regs, HPD_DDC_STATUS, &hpd_status); + pin_sta =3D FIELD_GET(HPD_PIN_STA, hpd_status); + pord_pin_sta =3D FIELD_GET(PORD_PIN_STA, hpd_status); + + if (pin_sta && pord_pin_sta) + return HDMI_PLUG_IN_AND_SINK_POWER_ON; + else if (pord_pin_sta) + return HDMI_PLUG_IN_ONLY; + else + return HDMI_PLUG_OUT; +} + +static irqreturn_t mtk_hdmi_isr(int irq, void *arg) +{ + struct mtk_hdmi *hdmi =3D arg; + unsigned int int_status; + int ret =3D IRQ_HANDLED; + + regmap_read(hdmi->regs, TOP_INT_STA00, &int_status); + + /* handle hpd interrupt */ + if (int_status & (PORD_F_INT_STA | PORD_R_INT_STA | HTPLG_F_INT_STA | + HTPLG_R_INT_STA)) { + mtk_hdmi_enable_hpd_pord_irq(hdmi, false); + mtk_hdmi_clr_htplg_pord_irq(hdmi); + ret =3D IRQ_WAKE_THREAD; + } + + /*clear all tx irq*/ + mtk_hdmi_clr_all_int_status(hdmi); + + return ret; +} + +static irqreturn_t mtk_hdmi_hpd_work_handle(int irq, void *arg) +{ + struct mtk_hdmi *hdmi =3D arg; + enum hdmi_hpd_state hpd; + + /* Debounce HDMI monitor HPD status. + * 30ms is the result of empirical testing */ + msleep(30); + + hpd =3D mtk_hdmi_hpd_pord_status(hdmi); + if (hpd !=3D hdmi->hpd) { + hdmi->hpd =3D hpd; + mtk_hdmi_hpd_event(hpd, hdmi->dev); + } + + mtk_hdmi_enable_hpd_pord_irq(hdmi, true); + return IRQ_HANDLED; +} + +static int mtk_hdmi_enable_disable(struct mtk_hdmi *hdmi, bool enable) +{ + int ret; + + if (enable && !hdmi->hdmi_enabled) { + if (!hdmi->power_clk_enabled) { + /* power domain on */ + ret =3D pm_runtime_get_sync(hdmi->dev); + + /* clk on */ + mtk_hdmi_clk_enable_v2(hdmi); + hdmi->power_clk_enabled =3D true; + } + + if (!hdmi->irq_registered) { + /* disable all tx interrupts */ + mtk_hdmi_disable_all_int(hdmi); + /* request irq */ + hdmi->hdmi_irq =3D + irq_of_parse_and_map(hdmi->dev->of_node, 0); + ret =3D request_threaded_irq(hdmi->hdmi_irq, mtk_hdmi_isr, + mtk_hdmi_hpd_work_handle, + IRQF_TRIGGER_HIGH, "hdmiirq", + hdmi); + hdmi->irq_registered =3D true; + /* enable hpd interrupt */ + mtk_hdmi_set_sw_hpd(hdmi, true); + mtk_hdmi_enable_hpd_pord_irq(hdmi, true); + } + + } else if (!enable && hdmi->hdmi_enabled) { + if (hdmi->irq_registered) { + /* free irq */ + free_irq(hdmi->hdmi_irq, NULL); + hdmi->irq_registered =3D false; + } + + if (hdmi->power_clk_enabled) { + /* clk disable */ + mtk_hdmi_clk_disable_v2(hdmi); + /* power domain off */ + ret =3D pm_runtime_put_sync(hdmi->dev); + hdmi->power_clk_enabled =3D false; + } + } + + hdmi->hdmi_enabled =3D enable; + + return 0; +} + +/* + * Bridge callbacks + */ + +static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + int ret; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + DRM_ERROR("The flag DRM_BRIDGE_ATTACH_NO_CONNECTOR must be supplied\n"); + return -EINVAL; + } + if (hdmi->next_bridge) { + ret =3D drm_bridge_attach(bridge->encoder, hdmi->next_bridge, bridge, fl= ags); + if (ret) + return ret; + } + + pm_runtime_enable(hdmi->dev); + mtk_hdmi_enable_disable(hdmi, true); + + return 0; +} + +static void mtk_hdmi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + + if (!hdmi->enabled) + return; + + mtk_hdmi_hw_send_av_mute(hdmi); + usleep_range(50000, 50050); + mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_disable_hdcp_encrypt(hdmi); + usleep_range(50000, 50050); + + phy_power_off(hdmi->phy); + + hdmi->enabled =3D false; +} + +static void mtk_hdmi_bridge_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + + if (!hdmi->powered) + return; + + phy_power_off(hdmi->phy); + + hdmi->powered =3D false; +} + +static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + struct drm_atomic_state *state =3D old_state->base.state; + union phy_configure_opts opts =3D { + .dp =3D { .link_rate =3D hdmi->mode.clock * KILO} + }; + + /* Retrieve the connector through the atomic state. */ + hdmi->curr_conn =3D drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + + mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode); + /* configuring phy clock link with appropriate rate */ + phy_configure(hdmi->phy, &opts); + phy_power_on(hdmi->phy); + hdmi->powered =3D true; +} + +static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + u8 buffer_spd[HDMI_INFOFRAME_SIZE(SPD)]; + u8 buffer_avi[HDMI_INFOFRAME_SIZE(AVI)]; + + phy_power_on(hdmi->phy); + mtk_hdmi_send_infoframe(hdmi, buffer_spd, sizeof(buffer_spd), + buffer_avi, sizeof(buffer_avi), &hdmi->mode); + mtk_hdmi_hw_spd_infoframe(hdmi, buffer_spd, sizeof(buffer_spd)); + mtk_hdmi_hw_avi_infoframe(hdmi, buffer_avi, sizeof(buffer_avi)); + + mtk_hdmi_hw_vid_black(hdmi, false); + + hdmi->enabled =3D true; +} + +static enum drm_connector_status mtk_hdmi_bridge_detect(struct drm_bridge = *bridge) +{ + struct mtk_hdmi *hdmi =3D hdmi_ctx_from_bridge(bridge); + + return (hdmi->hpd !=3D HDMI_PLUG_OUT) ? connector_status_connected : + connector_status_disconnected; +} + +const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs =3D { + .attach =3D mtk_hdmi_bridge_attach, + .atomic_duplicate_state =3D drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, + .atomic_reset =3D drm_atomic_helper_bridge_reset, + .mode_fixup =3D mtk_hdmi_bridge_mode_fixup, + .atomic_disable =3D mtk_hdmi_bridge_disable, + .atomic_post_disable =3D mtk_hdmi_bridge_post_disable, + .mode_set =3D mtk_hdmi_bridge_mode_set, + .atomic_pre_enable =3D mtk_hdmi_bridge_pre_enable, + .atomic_enable =3D mtk_hdmi_bridge_enable, + .get_edid =3D mtk_hdmi_bridge_get_edid, + .detect =3D mtk_hdmi_bridge_detect, +}; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.h new file mode 100644 index 000000000000..15d06d82eb8e --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + */ + +#ifndef _MTK_HDMI_V2_CTRL_H +#define _MTK_HDMI_V2_CTRL_H + +#include +#include + +struct mtk_hdmi; + +extern struct platform_driver mtk_hdmi_ddc_v2_driver; +extern const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs; +void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi); +int mtk_hdmi_clk_enable_v2(struct mtk_hdmi *hdmi); +void mtk_hdmi_clk_disable_v2(struct mtk_hdmi *hdmi); + +enum mtk_hdmi_clk_id_v2 { + MTK_HDMIV2_HDCP_SEL, + MTK_HDMIV2_HDCP_24M_SEL, + MTK_HDMIV2_VPP_SPLIT_HDMI, + MTK_HDMIV2_CLK_HDMI_APB_SEL, + MTK_HDMIV2_CLK_COUNT, +}; + +extern const char *const mtk_hdmi_clk_names_v2[MTK_HDMIV2_CLK_COUNT]; +#endif /* _MTK_HDMI_V2_CTRL_H */ --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3F4D4C7EE29 for ; Mon, 29 May 2023 14:37:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230047AbjE2OhR (ORCPT ); Mon, 29 May 2023 10:37:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229959AbjE2Ogw (ORCPT ); Mon, 29 May 2023 10:36:52 -0400 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8B3B5ED for ; Mon, 29 May 2023 07:36:48 -0700 (PDT) Received: by mail-ed1-x535.google.com with SMTP id 4fb4d7f45d1cf-5149bdb59daso1945678a12.2 for ; Mon, 29 May 2023 07:36:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371007; x=1687963007; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=y4Hg6vOJoPW8zpUD2u/XK34qVTid08A4C83SJzFRpwQ=; b=BcV/WNL2KjNRE3wehRbfjoSLyK1iGIHZWjKGa2M2/36fXqOioYuZudjwten0cg/3D6 vo5Gm25HDz1jpUZ0da5rWtQQLNbbEgrUUKKE380/rX4ukPx+Ck/VEVgsloa9aSM+mHpr XdQbFj8AADwS+nJs3jJ+gHVe+LgBNAJUQxItcWaOloF7AlLaZvKzkS3WhxhUa5ZEa/EF LqesKFZdNMOVcyI4v+tUa2uCoYgMEUp8hrr2QhNF9ewVm+RaGqArMLhgElvI9jpeKnbA JXe6ZB/cTEpTBteRYTOXeEXNkCtFU/un8XJ6gXXNhSsrEXO5UKPJYnM7KBE8uj9aGJkR RDwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371007; x=1687963007; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=y4Hg6vOJoPW8zpUD2u/XK34qVTid08A4C83SJzFRpwQ=; b=gvNwNl/iFn0nTwCzTxpM+uHfrR3wzlmWodKuH1XUwDXmlWuZ//XM4/ak36S+ISd2ua r5DqLY+jPTtqjHP/6+DPYpBO/kl1euxWUeLyI0v1SnNVXN1TJm9CobbhE2ks4U44HQsO EifwGXjJhWbcDSKXKCdlhqOYuvhti9R4nCx99HcrRvppw3H152K4YYA62xhdD9Eb3hi1 DHmjcg/JE7iDzvnwu9sc8OzNu+k5p0C6mlRbFwjt2kqX1XFO14V+NILWvHLiT14VSdf6 toTk8CHUVgDrlPSVjWCVpW2h1ps9oKYheS47bTIsiCPEQFi2MT7Cgn08QBBvS0i8hmdt V2nA== X-Gm-Message-State: AC+VfDx2CKhyVaQQcuStSJ+Xfzo3TXYhQtofHHtsOH5fv0fJk1wsRevb c4ybKJ2v+PVznubVyAThCGDk9Q== X-Google-Smtp-Source: ACHHUZ6GMwLwJZl/5hLoTYz4EyOEyKto+m7fsJGEyNBrdLSncOznqGbSpe3xwIsU4LQ+a2XSx8ArPA== X-Received: by 2002:a17:907:7244:b0:973:cc48:f19d with SMTP id ds4-20020a170907724400b00973cc48f19dmr11762300ejc.52.1685371006780; Mon, 29 May 2023 07:36:46 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:46 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:03 +0200 Subject: [PATCH v4 6/8] drm/mediatek: hdmi: v2: add audio support MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-6-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add HDMI audio support for v2 Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 1 + drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 198 +++++++++++++++++++++++++= ++++ drivers/gpu/drm/mediatek/mtk_hdmi_v2.h | 4 +- 3 files changed, 202 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.c index 97a00102a970..9ed86834ca85 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -346,6 +346,7 @@ static const struct mtk_hdmi_conf mtk_hdmi_conf_v2 =3D { .mtk_hdmi_output_init =3D mtk_hdmi_output_init_v2, .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_v2, .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_v2, + .mtk_hdmi_set_codec_pdata =3D mtk_hdmi_set_codec_pdata_v2, .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v2, .num_clocks =3D MTK_HDMIV2_CLK_COUNT, }; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.c index 98b1d50ecd72..0e41dfb36db4 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c @@ -150,6 +150,24 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdm= i, bool black) regmap_update_bits(hdmi->regs, TOP_VMUTE_CFG1, REG_VMUTE_EN, val); } =20 +static void mtk_hdmi_hw_aud_mute(struct mtk_hdmi *hdmi) +{ + u32 aip, val; + + regmap_read(hdmi->regs, AIP_CTRL, &aip); + + val =3D FIELD_PREP(AUD_MUTE_FIFO_EN, 1); + if (aip & DSD_EN) + val |=3D FIELD_PREP(DSD_MUTE_DATA, 1); + + regmap_update_bits(hdmi->regs, AIP_TXCTRL, val, val); +} + +static void mtk_hdmi_hw_aud_unmute(struct mtk_hdmi *hdmi) +{ + regmap_update_bits(hdmi->regs, AIP_TXCTRL, AUD_MUTE_FIFO_EN, AUD_MUTE_DIS= ); +} + static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi) { regmap_update_bits(hdmi->regs, HDMITX_CONFIG, HDMITX_SW_RSTB, 0); @@ -766,6 +784,7 @@ static void mtk_hdmi_audio_reset(struct mtk_hdmi *hdmi,= bool rst) static void mtk_hdmi_aud_output_config(struct mtk_hdmi *hdmi, struct drm_display_mode *display_mode) { + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_aud_enable_packet(hdmi, false); mtk_hdmi_audio_reset(hdmi, true); mtk_hdmi_aip_ctrl_init(hdmi); @@ -778,6 +797,7 @@ static void mtk_hdmi_aud_output_config(struct mtk_hdmi = *hdmi, usleep_range(25, 50); mtk_hdmi_aud_on_off_hw_ncts(hdmi, true); mtk_hdmi_aud_enable_packet(hdmi, true); + mtk_hdmi_hw_aud_unmute(hdmi); } =20 void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi) @@ -794,6 +814,16 @@ void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi) hdmi->hpd =3D HDMI_PLUG_OUT; } =20 +static void mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi, + struct hdmi_audio_param *param) +{ + if (!hdmi->audio_enable) + return; + + memcpy(&hdmi->aud_param, param, sizeof(*param)); + mtk_hdmi_aud_output_config(hdmi, &hdmi->mode); +} + static void mtk_hdmi_change_video_resolution(struct mtk_hdmi *hdmi) { mtk_hdmi_hw_reset(hdmi); @@ -812,6 +842,7 @@ static void mtk_hdmi_change_video_resolution(struct mtk= _hdmi *hdmi) =20 usleep_range(5, 10); mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_hw_send_av_unmute(hdmi); =20 regmap_update_bits(hdmi->regs, TOP_CFG01, NULL_PKT_VSYNC_HIGH_EN | NULL_P= KT_EN, NULL_PKT_VSYNC_HIGH_EN); @@ -1022,6 +1053,7 @@ static void mtk_hdmi_bridge_disable(struct drm_bridge= *bridge, mtk_hdmi_hw_send_av_mute(hdmi); usleep_range(50000, 50050); mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_disable_hdcp_encrypt(hdmi); usleep_range(50000, 50050); =20 @@ -1030,6 +1062,14 @@ static void mtk_hdmi_bridge_disable(struct drm_bridg= e *bridge, hdmi->enabled =3D false; } =20 +static void mtk_hdmi_handle_plugged_change(struct mtk_hdmi *hdmi, bool plu= gged) +{ + mutex_lock(&hdmi->update_plugged_status_lock); + if (hdmi->plugged_cb && hdmi->codec_dev) + hdmi->plugged_cb(hdmi->codec_dev, plugged); + mutex_unlock(&hdmi->update_plugged_status_lock); +} + static void mtk_hdmi_bridge_post_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_state) { @@ -1041,6 +1081,9 @@ static void mtk_hdmi_bridge_post_disable(struct drm_b= ridge *bridge, phy_power_off(hdmi->phy); =20 hdmi->powered =3D false; + + /* signal the disconnect event to audio codec */ + mtk_hdmi_handle_plugged_change(hdmi, false); } =20 static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge, @@ -1077,6 +1120,10 @@ static void mtk_hdmi_bridge_enable(struct drm_bridge= *bridge, mtk_hdmi_hw_avi_infoframe(hdmi, buffer_avi, sizeof(buffer_avi)); =20 mtk_hdmi_hw_vid_black(hdmi, false); + mtk_hdmi_hw_aud_unmute(hdmi); + + /* signal the connect event to audio codec */ + mtk_hdmi_handle_plugged_change(hdmi, true); =20 hdmi->enabled =3D true; } @@ -1103,3 +1150,154 @@ const struct drm_bridge_funcs mtk_v2_hdmi_bridge_fu= ncs =3D { .get_edid =3D mtk_hdmi_bridge_get_edid, .detect =3D mtk_hdmi_bridge_detect, }; + +static void mtk_hdmi_set_plugged_cb(struct mtk_hdmi *hdmi, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + bool plugged; + + mutex_lock(&hdmi->update_plugged_status_lock); + hdmi->plugged_cb =3D fn; + hdmi->codec_dev =3D codec_dev; + plugged =3D (hdmi->hpd =3D=3D HDMI_PLUG_IN_AND_SINK_POWER_ON); + mutex_unlock(&hdmi->update_plugged_status_lock); + + mtk_hdmi_handle_plugged_change(hdmi, plugged); +} + +/* + * HDMI audio codec callbacks + */ +static int mtk_hdmi_audio_hook_plugged_cb(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (!hdmi) + return -ENODEV; + + mtk_hdmi_set_plugged_cb(hdmi, fn, codec_dev); + return 0; +} + +static int mtk_hdmi_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + struct hdmi_audio_param hdmi_params; + unsigned int chan =3D params->cea.channels; + + if (!hdmi->bridge.encoder) + return -ENODEV; + + switch (chan) { + case 2: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_2_0; + break; + case 4: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_4_0; + break; + case 6: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_5_1; + break; + case 8: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_7_1; + break; + default: + return -EINVAL; + } + + switch (params->sample_rate) { + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + case 176400: + case 192000: + break; + default: + return -EINVAL; + } + + switch (daifmt->fmt) { + case HDMI_I2S: + hdmi_params.aud_codec =3D HDMI_AUDIO_CODING_TYPE_PCM; + hdmi_params.aud_sampe_size =3D HDMI_AUDIO_SAMPLE_SIZE_16; + hdmi_params.aud_input_type =3D HDMI_AUD_INPUT_I2S; + hdmi_params.aud_i2s_fmt =3D HDMI_I2S_MODE_I2S_24BIT; + hdmi_params.aud_mclk =3D HDMI_AUD_MCLK_128FS; + break; + default: + return -EINVAL; + } + + memcpy(&hdmi_params.codec_params, params, + sizeof(hdmi_params.codec_params)); + + mtk_hdmi_audio_set_param(hdmi, &hdmi_params); + + return 0; +} + +static int mtk_hdmi_audio_startup(struct device *dev, void *data) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + mtk_hdmi_aud_enable_packet(hdmi, true); + hdmi->audio_enable =3D true; + + return 0; +} + +static void mtk_hdmi_audio_shutdown(struct device *dev, void *data) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + mtk_hdmi_aud_enable_packet(hdmi, false); + hdmi->audio_enable =3D false; +} + +static int mtk_hdmi_audio_mute(struct device *dev, void *data, bool enable, + int direction) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (enable) + mtk_hdmi_hw_aud_mute(hdmi); + else + mtk_hdmi_hw_aud_unmute(hdmi); + + return 0; +} + +static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t = *buf, + size_t len) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (hdmi->enabled) + memcpy(buf, hdmi->curr_conn->eld, min(sizeof(hdmi->curr_conn->eld), len)= ); + else + memset(buf, 0, len); + return 0; +} + +static const struct hdmi_codec_ops mtk_hdmi_audio_codec_ops =3D { + .hw_params =3D mtk_hdmi_audio_hw_params, + .audio_startup =3D mtk_hdmi_audio_startup, + .audio_shutdown =3D mtk_hdmi_audio_shutdown, + .mute_stream =3D mtk_hdmi_audio_mute, + .get_eld =3D mtk_hdmi_audio_get_eld, + .hook_plugged_cb =3D mtk_hdmi_audio_hook_plugged_cb, +}; + +void mtk_hdmi_set_codec_pdata_v2(struct hdmi_codec_pdata *codec_data) +{ + codec_data->ops =3D &mtk_hdmi_audio_codec_ops; + codec_data->max_i2s_channels =3D 2; + codec_data->i2s =3D 1; +} diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.h index 15d06d82eb8e..6b195a9c6cc8 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h @@ -7,8 +7,9 @@ #ifndef _MTK_HDMI_V2_CTRL_H #define _MTK_HDMI_V2_CTRL_H =20 -#include #include +#include +#include =20 struct mtk_hdmi; =20 @@ -17,6 +18,7 @@ extern const struct drm_bridge_funcs mtk_v2_hdmi_bridge_f= uncs; void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi); int mtk_hdmi_clk_enable_v2(struct mtk_hdmi *hdmi); void mtk_hdmi_clk_disable_v2(struct mtk_hdmi *hdmi); +void mtk_hdmi_set_codec_pdata_v2(struct hdmi_codec_pdata *codec_data); =20 enum mtk_hdmi_clk_id_v2 { MTK_HDMIV2_HDCP_SEL, --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5E78C7EE23 for ; Mon, 29 May 2023 14:37:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230080AbjE2OhT (ORCPT ); Mon, 29 May 2023 10:37:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38574 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229974AbjE2Ogx (ORCPT ); Mon, 29 May 2023 10:36:53 -0400 Received: from mail-ed1-x533.google.com (mail-ed1-x533.google.com [IPv6:2a00:1450:4864:20::533]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0B6E4F4 for ; Mon, 29 May 2023 07:36:49 -0700 (PDT) Received: by mail-ed1-x533.google.com with SMTP id 4fb4d7f45d1cf-5149c76f4dbso2253368a12.1 for ; Mon, 29 May 2023 07:36:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371008; x=1687963008; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=telyeAKdwo8lnoUKAmP+74qLgfYo7FAmVRnOD3rnVlA=; b=3QfEh8YT8VlS0OUoEUSTFqi+WztJAYkk4PhkEglwIH04qFEanNcPwOOPmCHJ/1lDt/ yVqGExXRre1c1nr96wxJP7QnC4JprkZWqeQ/BtThg4TKlroQmiOxv+A+O6yueYTaQWhz 7sLhSdW9avkV3hB82XpYzgZLK7b8O6gmYyEgU92a/RfFuwlymQgoluWFq2jBEGvGBisj kTOHOhRtav6y4SNBrQweLvEkORs3EZBvdATLVMBHuHW+iMoPqDWSR19jxiIPjeK9uNCk O4a0rhlExDisIvCEYiVQmeypKwJ1F2bvaABfy3THAitdx3yRpCG7r+rDD+MYgZCbfqIq fwkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371008; x=1687963008; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=telyeAKdwo8lnoUKAmP+74qLgfYo7FAmVRnOD3rnVlA=; b=hfKAGqHFCGO4nvqVHHIcQNU8ScV68wOS+kUVzXxsbWUzIW7WIcQTz5NU8kWONQZyXo gJGlkJs9BJEKhn9zlsoSt38i5JeAQNkd2eaSudAE0AuaP1xq4ajIQYoeZTgiizzN1JVz P5iTMLUln+lKhwR8aF87DdHEGkpHlIgnZcU+vwJyW2kklM9Jy7JDMAVwDiionOUdJLpv 43wsa76sCz1lKPYwLre5iNoQOZfSO+SGNDlE51Z1B04z9BdcYOssy4kIeiJ7q0H0OaB/ JLSzOjyir0qOcZhghj4MzcK6dgPAjcJJTgOH6Qj1m2+LjjuLcKGIdxRrWb8vAEb7G/ha iU2w== X-Gm-Message-State: AC+VfDxqe2c9s/dBxG4zwAd1EPCP0C7ZzOzpwvF/h2IPtgrLbeMDmero EF9pUCyqCGZ57Hjh3b7T89987w== X-Google-Smtp-Source: ACHHUZ4QgZFbnnhdPEGrQaTJdIUZ1I3VKBbk9dR2dNCddcnlogHxJeDuEb3qF8lU0zYWvc3pVjZAYA== X-Received: by 2002:a17:907:7f0b:b0:96f:e080:4f56 with SMTP id qf11-20020a1709077f0b00b0096fe0804f56mr10191410ejc.31.1685371008553; Mon, 29 May 2023 07:36:48 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:48 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:04 +0200 Subject: [PATCH v4 7/8] dt-bindings: display: mediatek: dpi: Add compatible for MediaTek MT8195 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-7-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add dt-binding documentation of dpi for MediaTek MT8195 SoC. Acked-by: Krzysztof Kozlowski Signed-off-by: Guillaume Ranquet --- Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dp= i.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.ya= ml index d976380801e3..cabe4031729a 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml @@ -25,6 +25,7 @@ properties: - mediatek,mt8186-dpi - mediatek,mt8188-dp-intf - mediatek,mt8192-dpi + - mediatek,mt8195-dpi - mediatek,mt8195-dp-intf =20 reg: --=20 2.40.0 From nobody Fri Sep 20 19:19:57 2024 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8F06C77B7E for ; Mon, 29 May 2023 14:37:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230261AbjE2OhZ (ORCPT ); Mon, 29 May 2023 10:37:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230042AbjE2OhL (ORCPT ); Mon, 29 May 2023 10:37:11 -0400 Received: from mail-ej1-x634.google.com (mail-ej1-x634.google.com [IPv6:2a00:1450:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85032100 for ; Mon, 29 May 2023 07:36:52 -0700 (PDT) Received: by mail-ej1-x634.google.com with SMTP id a640c23a62f3a-97392066d04so502477066b.3 for ; Mon, 29 May 2023 07:36:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1685371010; x=1687963010; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=DtIowCWArhNAKDJ21t/Gz3FuvkA8KEPefFaFjHCeQr4=; b=pCTcRPHfX3X1QhvHwCBNVTgzfn/Qm28cgRWSmlzGAohNnkVN4gHRNa/q16pJEcvXt1 /APenx4ADuC8k13hFw2PBKaCGpcgNcI/Wm2A3tnb2ElOQIN30A2r3Pc53PRSkb1jZDJR x5S2w6uSizNScE+h8CbPJxfbCLKHyrVTlHoUwiuwEqna9V4iwK9zxQcqOwdh6ACNuuxb YEwOiYh/EosOeCa1PIdL+Fo/4FOAe8VYrg7mGRK9/G3PC/25h7GnTFW0xrECMTtn3Wzv HumEx6HtlqHcbYLNMVSdzc/wWFd/y5upyJFYNQvrpekQp8iQbhSQvEEtv8HChwIWgkOJ nvew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685371010; x=1687963010; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DtIowCWArhNAKDJ21t/Gz3FuvkA8KEPefFaFjHCeQr4=; b=H8NfWgCCiLMyCZ3Kh5l4eg8yMsTNrNT5mmVhFu5bsHsFFZEyzWx20kYYnpVumA1PCO GEln95Yykt1dmH/jSPu85U7c1NF8azx4LEELc0hWd8MY7hAB1B34SqHaJTCRM4fguc2b fE3L6/QLrZMp2qF5bzlfAoNOW6wYY8MQOPyB7hqqMwGPAHTHlQ6yCQOS4XZtUUX0wSC7 JTVZm3mph0PAp0EfU6m48zACQInYpU5j9kYOn5i4sT/dpd+8X/BhuWnHYZNK0JfR2X4A wjkxmOQMLPYbud8Kwy97571G++WFazc5BnyrCzms7AjxrkhO46Edr+Zc4G2NKBcb8uq2 J6vw== X-Gm-Message-State: AC+VfDwVIiKrlRqHXWYSHgLC4dkvOkvtW2vAF2SiPYE9MXdHpjYto8Bl QiOMBfrP52uOEQiF5xaqffMdTQ== X-Google-Smtp-Source: ACHHUZ6ZdgKp3qcctbdXffjSB1OljMNkHMX5k/OVK97KqbCMJGQbzQJgmnum9XhXzvedFA0un68qVg== X-Received: by 2002:a17:907:c09:b0:971:eb29:a086 with SMTP id ga9-20020a1709070c0900b00971eb29a086mr13291571ejc.75.1685371010136; Mon, 29 May 2023 07:36:50 -0700 (PDT) Received: from [127.0.0.1] (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id le8-20020a170907170800b0096f803afbe3sm5993654ejc.66.2023.05.29.07.36.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 May 2023 07:36:49 -0700 (PDT) From: Guillaume Ranquet Date: Mon, 29 May 2023 16:31:05 +0200 Subject: [PATCH v4 8/8] drm/mediatek: dpi: Add mt8195 hdmi to DPI driver MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v4-8-687f09a06dd9@baylibre.com> References: <20220919-v4-0-687f09a06dd9@baylibre.com> In-Reply-To: <20220919-v4-0-687f09a06dd9@baylibre.com> To: Chunfeng Yun , Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Krzysztof Kozlowski , Matthias Brugger , Chun-Kuang Hu , Philipp Zabel , David Airlie , Daniel Vetter , CK Hu , Jitao shi Cc: linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Krzysztof Kozlowski , AngeloGioacchino Del Regno , mac.shen@mediatek.com, stuart.lee@mediatek.com, Guillaume Ranquet X-Mailer: b4 0.13-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add the DPI1 hdmi path support in mtk dpi driver Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/mtk_dpi.c | 121 ++++++++++++++++++++++++++++= ++-- drivers/gpu/drm/mediatek/mtk_dpi_regs.h | 5 ++ 2 files changed, 119 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/= mtk_dpi.c index 948a53f1f4b3..b83a38e8bd60 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -9,12 +9,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include =20 #include