Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp353015pxb; Fri, 15 Oct 2021 06:52:31 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyTPN4oHpyGQDOKfDlE+yCicMXWDKJuJhm4dnKXVNlXes9hxRA1UPHDuJ7N1R+kS6bcZMe7 X-Received: by 2002:a62:7b43:0:b0:44c:6d72:ac4d with SMTP id w64-20020a627b43000000b0044c6d72ac4dmr11518925pfc.73.1634305951140; Fri, 15 Oct 2021 06:52:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1634305951; cv=none; d=google.com; s=arc-20160816; b=mWuWVmbzbDEFbTGqB4NlAn4/GM6a7zTZgb/jZRkLmRRCNQjBYUdr9SEMkUOEdhKWRI qZp8oTh4jHGWmhXAD6RJTLdWt8JpHhTZ7i5YHErMzmDwIaFXk2Qi57dBWHZrWVQgE1Uk BXPxolSOqLC/smaWHfcOHUapfGY1UecrBwAABc+vgPYGQuZHLrYFuoo/QhyPEu+XSu/O jZkPCYzMpZACjKxB9108boB5uSuRD7ZAnjY6I2HMGlbpNgPavVN+cZZzzXMbtKP9I47Y 1E1CSliyzDOKIVc36FTa5kxrlDmml6Ia1IzCU1vKO/BCJh7qFr8ex8ozhJhazL2KyqLx 01aw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:organization :from:references:cc:to:subject:dkim-signature; bh=CuHilB1FzICLnPc+us8vYOQQ1ydpijQ4gELdefxB4+o=; b=UTkeDkQTDEXbdk5LCmF2KYaO2xLMfQzpExlytlnEWCACZFjmG/mcugXe4V+OJeaUam wwMR8RnUsweFyKX0g/i67z5tnHxT67ZfAl2VGWgqpTyiwLmv+Vs//lhtD7Xj0l5CEcZh yykJq5Cl4JjpuTLsjASGqj8703sCQ+5xLmAb12kn4EuXVzmh6biF/N8x6TipdbFrAPDx 2T1bvZPnU/HqSkrCo6fvefuHJtYh0X0UeFgnoAlprX61Wp9rIhn7mx/zJ4aXmEHg2jAE u2ee+atME5lM4Nb0kzOx54lVx5uf8DoWhv25bNpp2eswlw4WwHY2grRt2DqE/9Ch7uvV 9a4Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20210112.gappssmtp.com header.s=20210112 header.b="JJOlom/p"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id g9si6997869pjk.70.2021.10.15.06.52.18; Fri, 15 Oct 2021 06:52:31 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20210112.gappssmtp.com header.s=20210112 header.b="JJOlom/p"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231232AbhJOH5O (ORCPT + 99 others); Fri, 15 Oct 2021 03:57:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236374AbhJOH5N (ORCPT ); Fri, 15 Oct 2021 03:57:13 -0400 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E6E95C061570 for ; Fri, 15 Oct 2021 00:55:06 -0700 (PDT) Received: by mail-wm1-x331.google.com with SMTP id j10-20020a1c230a000000b0030d523b6693so2099086wmj.2 for ; Fri, 15 Oct 2021 00:55:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20210112.gappssmtp.com; s=20210112; h=subject:to:cc:references:from:organization:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=CuHilB1FzICLnPc+us8vYOQQ1ydpijQ4gELdefxB4+o=; b=JJOlom/p9oiem9AdkHcFmoW5n6Hv45wgVKqD+iI+eSJ+jVju6YUMZdmERkDcw1tN7c BN4i0gFRt990CI26aMBqgotXO5lR4wNCYRukWd6W6ptMwa5TPrU6ro8F3iNX0/y+OHVQ aJvPcqGShgrtnW+3MKpEe7JhUst47YiX7uhBeJzZbDQf5i3fQ1iPycddH4TkbAm2+n/V UZNrzdzfSziebRnZ7fxSWHAsiy/jI+oHCgfBP9mm5lToK1mZZ2pnc7s0nS2PMXRyhuG4 VDIFm8KKyoLV/LJXGImLGkJZcEJ4K9B9gzxrj30wLZvIqcUM3YUZ+AqXY++tlxa3uu1P AIKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:to:cc:references:from:organization :message-id:date:user-agent:mime-version:in-reply-to :content-language:content-transfer-encoding; bh=CuHilB1FzICLnPc+us8vYOQQ1ydpijQ4gELdefxB4+o=; b=o2tWZ+FIhPt/SGV3Id/9E9gQ5HvYf6tWugWOECzks4+B/bH16cUf1wACoOZI25JXMn +kr+t5rmZYed6OSk6NpjhzfIy87aRUm0NGnl7CvUcvS0EjtWRspcliyJTWJYFJaCXwRz FE3ow0DwbSZMxPfmblpa8D5+1R7NhbvJX5HOpHGLIYhOj68n4vE6T3AWAptCMnCN+n01 72zPosIwi936k8D42xJqL4crRsZRCKX2HZgmwaDCHvSOPzvDAzIGL0oIlJSK78fsJOs4 uqHwr+xCF+lq2nv0EbHzxZF4SDhAnbicTUOtN7Sjzzmbhcovl5aASJ1dZ/uE0YkRrrdV XkOA== X-Gm-Message-State: AOAM532Jz6sVXrCqiFTb9zvQnUd2LtOORFdG6BM/mZYYFIgqpSg5tG2N 0NpdA3cqsT/zD5DxSn0k3GCkmwptQEAeAg== X-Received: by 2002:a05:600c:21cc:: with SMTP id x12mr16193227wmj.8.1634284504626; Fri, 15 Oct 2021 00:55:04 -0700 (PDT) Received: from ?IPv6:2001:861:44c0:66c0:f6e3:13bd:45ae:5eeb? ([2001:861:44c0:66c0:f6e3:13bd:45ae:5eeb]) by smtp.gmail.com with ESMTPSA id j206sm7194574wmj.23.2021.10.15.00.55.03 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 15 Oct 2021 00:55:04 -0700 (PDT) Subject: Re: [PATCH 3/7] drm/meson: split out encoder from meson_dw_hdmi To: Sam Ravnborg Cc: daniel@ffwll.ch, Laurent.pinchart@ideasonboard.com, martin.blumenstingl@googlemail.com, dri-devel@lists.freedesktop.org, linux-amlogic@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org References: <20211014152606.2289528-1-narmstrong@baylibre.com> <20211014152606.2289528-4-narmstrong@baylibre.com> From: Neil Armstrong Organization: Baylibre Message-ID: Date: Fri, 15 Oct 2021 09:55:03 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, On 14/10/2021 20:07, Sam Ravnborg wrote: > Hi Neil, > > I did not verify all the code movements - but it looked correct from a > quick glance. > A few comments below, especially the use of mode_set() should be > addressed as it is deprecated. I was not sure about mode_set, will move to atomic_enable and address all the other comments, Thanks, Neil > > Sam > > On Thu, Oct 14, 2021 at 05:26:02PM +0200, Neil Armstrong wrote: >> This moves all the non-DW-HDMI code where it should be: >> an encoder in the drm/meson core driver. >> >> The bridge functions are copied as-is, the encoder init uses the >> simple kms helper and for now the bridge attach flags is 0. >> >> The meson dw-hdmi glue is slighly fixed to live without the >> encoder in the same driver. >> >> Signed-off-by: Neil Armstrong >> --- >> drivers/gpu/drm/meson/Makefile | 1 + >> drivers/gpu/drm/meson/meson_drv.c | 5 + >> drivers/gpu/drm/meson/meson_dw_hdmi.c | 341 ++----------------- >> drivers/gpu/drm/meson/meson_encoder_hdmi.c | 359 +++++++++++++++++++++ >> drivers/gpu/drm/meson/meson_encoder_hdmi.h | 12 + >> 5 files changed, 396 insertions(+), 322 deletions(-) >> create mode 100644 drivers/gpu/drm/meson/meson_encoder_hdmi.c >> create mode 100644 drivers/gpu/drm/meson/meson_encoder_hdmi.h >> >> diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile >> index 28a519cdf66b..523fce45f16b 100644 >> --- a/drivers/gpu/drm/meson/Makefile >> +++ b/drivers/gpu/drm/meson/Makefile >> @@ -2,6 +2,7 @@ >> meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o >> meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o >> meson-drm-y += meson_rdma.o meson_osd_afbcd.o >> +meson-drm-y += meson_encoder_hdmi.o >> >> obj-$(CONFIG_DRM_MESON) += meson-drm.o >> obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o >> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c >> index b53606d8825f..0a28a8e29d63 100644 >> --- a/drivers/gpu/drm/meson/meson_drv.c >> +++ b/drivers/gpu/drm/meson/meson_drv.c >> @@ -32,6 +32,7 @@ >> #include "meson_osd_afbcd.h" >> #include "meson_registers.h" >> #include "meson_venc_cvbs.h" >> +#include "meson_encoder_hdmi.h" >> #include "meson_viu.h" >> #include "meson_vpp.h" >> #include "meson_rdma.h" >> @@ -319,6 +320,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) >> } >> } >> >> + ret = meson_encoder_hdmi_init(priv); >> + if (ret) >> + goto free_drm; >> + >> ret = meson_plane_create(priv); >> if (ret) >> goto free_drm; >> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c >> index 2ed87cfdd735..c2480b3335ac 100644 >> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c >> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c >> @@ -22,14 +22,11 @@ >> #include >> #include >> >> -#include >> #include >> >> #include "meson_drv.h" >> #include "meson_dw_hdmi.h" >> #include "meson_registers.h" >> -#include "meson_vclk.h" >> -#include "meson_venc.h" >> >> #define DRIVER_NAME "meson-dw-hdmi" >> #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" >> @@ -135,8 +132,6 @@ struct meson_dw_hdmi_data { >> }; >> >> struct meson_dw_hdmi { >> - struct drm_encoder encoder; >> - struct drm_bridge bridge; >> struct dw_hdmi_plat_data dw_plat_data; >> struct meson_drm *priv; >> struct device *dev; >> @@ -148,12 +143,8 @@ struct meson_dw_hdmi { >> struct regulator *hdmi_supply; >> u32 irq_stat; >> struct dw_hdmi *hdmi; >> - unsigned long output_bus_fmt; >> + struct drm_bridge *bridge; >> }; >> -#define encoder_to_meson_dw_hdmi(x) \ >> - container_of(x, struct meson_dw_hdmi, encoder) >> -#define bridge_to_meson_dw_hdmi(x) \ >> - container_of(x, struct meson_dw_hdmi, bridge) >> >> static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, >> const char *compat) >> @@ -295,14 +286,14 @@ static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, >> >> /* Setup PHY bandwidth modes */ >> static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, >> - const struct drm_display_mode *mode) >> + const struct drm_display_mode *mode, >> + bool mode_is_420) >> { >> struct meson_drm *priv = dw_hdmi->priv; >> unsigned int pixel_clock = mode->clock; >> >> /* For 420, pixel clock is half unlike venc clock */ >> - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> - pixel_clock /= 2; >> + if (mode_is_420) pixel_clock /= 2; >> >> if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || >> dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { >> @@ -374,68 +365,25 @@ static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi) >> mdelay(2); >> } >> >> -static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, >> - const struct drm_display_mode *mode) >> -{ >> - struct meson_drm *priv = dw_hdmi->priv; >> - int vic = drm_match_cea_mode(mode); >> - unsigned int phy_freq; >> - unsigned int vclk_freq; >> - unsigned int venc_freq; >> - unsigned int hdmi_freq; >> - >> - vclk_freq = mode->clock; >> - >> - /* For 420, pixel clock is half unlike venc clock */ >> - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> - vclk_freq /= 2; >> - >> - /* TMDS clock is pixel_clock * 10 */ >> - phy_freq = vclk_freq * 10; >> - >> - if (!vic) { >> - meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, >> - vclk_freq, vclk_freq, vclk_freq, false); >> - return; >> - } >> - >> - /* 480i/576i needs global pixel doubling */ >> - if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> - vclk_freq *= 2; >> - >> - venc_freq = vclk_freq; >> - hdmi_freq = vclk_freq; >> - >> - /* VENC double pixels for 1080i, 720p and YUV420 modes */ >> - if (meson_venc_hdmi_venc_repeat(vic) || >> - dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> - venc_freq *= 2; >> - >> - vclk_freq = max(venc_freq, hdmi_freq); >> - >> - if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> - venc_freq /= 2; >> - >> - DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n", >> - phy_freq, vclk_freq, venc_freq, hdmi_freq, >> - priv->venc.hdmi_use_enci); >> - >> - meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, >> - venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); >> -} >> - >> static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, >> const struct drm_display_info *display, >> const struct drm_display_mode *mode) >> { >> struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; >> + bool is_hdmi2_sink = display->hdmi.scdc.supported; >> struct meson_drm *priv = dw_hdmi->priv; >> unsigned int wr_clk = >> readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); >> + bool mode_is_420 = false; >> >> DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name, >> mode->clock > 340000 ? 40 : 10); >> >> + if (drm_mode_is_420_only(display, mode) || >> + (!is_hdmi2_sink && >> + drm_mode_is_420_also(display, mode))) >> + mode_is_420 = true; >> + >> /* Enable clocks */ >> regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); >> >> @@ -457,8 +405,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, >> dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); >> >> /* TMDS pattern setup */ >> - if (mode->clock > 340000 && >> - dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_YUV8_1X24) { >> + if (mode->clock > 340000 && !mode_is_420) { >> dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, >> 0); >> dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, >> @@ -476,7 +423,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, >> dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); >> >> /* Setup PHY parameters */ >> - meson_hdmi_phy_setup_mode(dw_hdmi, mode); >> + meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); >> >> /* Setup PHY */ >> regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, >> @@ -622,214 +569,15 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) >> dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected, >> hpd_connected); >> >> - drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); >> + drm_helper_hpd_irq_event(dw_hdmi->bridge->dev); >> + drm_bridge_hpd_notify(dw_hdmi->bridge, >> + hpd_connected ? connector_status_connected >> + : connector_status_disconnected); >> } >> >> return IRQ_HANDLED; >> } >> >> -static enum drm_mode_status >> -dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, >> - const struct drm_display_info *display_info, >> - const struct drm_display_mode *mode) >> -{ >> - struct meson_dw_hdmi *dw_hdmi = data; >> - struct meson_drm *priv = dw_hdmi->priv; >> - bool is_hdmi2_sink = display_info->hdmi.scdc.supported; >> - unsigned int phy_freq; >> - unsigned int vclk_freq; >> - unsigned int venc_freq; >> - unsigned int hdmi_freq; >> - int vic = drm_match_cea_mode(mode); >> - enum drm_mode_status status; >> - >> - DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); >> - >> - /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ >> - if (display_info->max_tmds_clock && >> - mode->clock > display_info->max_tmds_clock && >> - !drm_mode_is_420_only(display_info, mode) && >> - !drm_mode_is_420_also(display_info, mode)) >> - return MODE_BAD; >> - >> - /* Check against non-VIC supported modes */ >> - if (!vic) { >> - status = meson_venc_hdmi_supported_mode(mode); >> - if (status != MODE_OK) >> - return status; >> - >> - return meson_vclk_dmt_supported_freq(priv, mode->clock); >> - /* Check against supported VIC modes */ >> - } else if (!meson_venc_hdmi_supported_vic(vic)) >> - return MODE_BAD; >> - >> - vclk_freq = mode->clock; >> - >> - /* For 420, pixel clock is half unlike venc clock */ >> - if (drm_mode_is_420_only(display_info, mode) || >> - (!is_hdmi2_sink && >> - drm_mode_is_420_also(display_info, mode))) >> - vclk_freq /= 2; >> - >> - /* TMDS clock is pixel_clock * 10 */ >> - phy_freq = vclk_freq * 10; >> - >> - /* 480i/576i needs global pixel doubling */ >> - if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> - vclk_freq *= 2; >> - >> - venc_freq = vclk_freq; >> - hdmi_freq = vclk_freq; >> - >> - /* VENC double pixels for 1080i, 720p and YUV420 modes */ >> - if (meson_venc_hdmi_venc_repeat(vic) || >> - drm_mode_is_420_only(display_info, mode) || >> - (!is_hdmi2_sink && >> - drm_mode_is_420_also(display_info, mode))) >> - venc_freq *= 2; >> - >> - vclk_freq = max(venc_freq, hdmi_freq); >> - >> - if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> - venc_freq /= 2; >> - >> - dev_dbg(dw_hdmi->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", >> - __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); >> - >> - return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); >> -} >> - >> -/* Encoder */ >> - >> -static const u32 meson_dw_hdmi_out_bus_fmts[] = { >> - MEDIA_BUS_FMT_YUV8_1X24, >> - MEDIA_BUS_FMT_UYYVYY8_0_5X24, >> -}; >> - >> -static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder) >> -{ >> - drm_encoder_cleanup(encoder); >> -} >> - >> -static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = { >> - .destroy = meson_venc_hdmi_encoder_destroy, >> -}; >> - >> -static u32 * >> -meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge, >> - struct drm_bridge_state *bridge_state, >> - struct drm_crtc_state *crtc_state, >> - struct drm_connector_state *conn_state, >> - u32 output_fmt, >> - unsigned int *num_input_fmts) >> -{ >> - u32 *input_fmts = NULL; >> - int i; >> - >> - *num_input_fmts = 0; >> - >> - for (i = 0 ; i < ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts) ; ++i) { >> - if (output_fmt == meson_dw_hdmi_out_bus_fmts[i]) { >> - *num_input_fmts = 1; >> - input_fmts = kcalloc(*num_input_fmts, >> - sizeof(*input_fmts), >> - GFP_KERNEL); >> - if (!input_fmts) >> - return NULL; >> - >> - input_fmts[0] = output_fmt; >> - >> - break; >> - } >> - } >> - >> - return input_fmts; >> -} >> - >> -static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge, >> - struct drm_bridge_state *bridge_state, >> - struct drm_crtc_state *crtc_state, >> - struct drm_connector_state *conn_state) >> -{ >> - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); >> - >> - dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format; >> - >> - DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt); >> - >> - return 0; >> -} >> - >> -static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge) >> -{ >> - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); >> - struct meson_drm *priv = dw_hdmi->priv; >> - >> - DRM_DEBUG_DRIVER("\n"); >> - >> - writel_bits_relaxed(0x3, 0, >> - priv->io_base + _REG(VPU_HDMI_SETTING)); >> - >> - writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); >> - writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); >> -} >> - >> -static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge) >> -{ >> - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); >> - struct meson_drm *priv = dw_hdmi->priv; >> - >> - DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); >> - >> - if (priv->venc.hdmi_use_enci) >> - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); >> - else >> - writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); >> -} >> - >> -static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge, >> - const struct drm_display_mode *mode, >> - const struct drm_display_mode *adjusted_mode) >> -{ >> - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); >> - struct meson_drm *priv = dw_hdmi->priv; >> - int vic = drm_match_cea_mode(mode); >> - unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR; >> - bool yuv420_mode = false; >> - >> - DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); >> - >> - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { >> - ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; >> - yuv420_mode = true; >> - } >> - >> - /* VENC + VENC-DVI Mode setup */ >> - meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); >> - >> - /* VCLK Set clock */ >> - dw_hdmi_set_vclk(dw_hdmi, mode); >> - >> - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> - /* Setup YUV420 to HDMI-TX, no 10bit diphering */ >> - writel_relaxed(2 | (2 << 2), >> - priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); >> - else >> - /* Setup YUV444 to HDMI-TX, no 10bit diphering */ >> - writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); >> -} >> - >> -static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = { >> - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, >> - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, >> - .atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts, >> - .atomic_reset = drm_atomic_helper_bridge_reset, >> - .atomic_check = meson_venc_hdmi_encoder_atomic_check, >> - .enable = meson_venc_hdmi_encoder_enable, >> - .disable = meson_venc_hdmi_encoder_disable, >> - .mode_set = meson_venc_hdmi_encoder_mode_set, >> -}; >> - >> /* DW HDMI Regmap */ >> >> static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, >> @@ -876,28 +624,6 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { >> .dwc_write = dw_hdmi_g12a_dwc_write, >> }; >> >> -static bool meson_hdmi_connector_is_available(struct device *dev) >> -{ >> - struct device_node *ep, *remote; >> - >> - /* HDMI Connector is on the second port, first endpoint */ >> - ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0); >> - if (!ep) >> - return false; >> - >> - /* If the endpoint node exists, consider it enabled */ >> - remote = of_graph_get_remote_port(ep); >> - if (remote) { >> - of_node_put(ep); >> - return true; >> - } >> - >> - of_node_put(ep); >> - of_node_put(remote); >> - >> - return false; >> -} >> - >> static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) >> { >> struct meson_drm *priv = meson_dw_hdmi->priv; >> @@ -976,19 +702,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, >> struct drm_device *drm = data; >> struct meson_drm *priv = drm->dev_private; >> struct dw_hdmi_plat_data *dw_plat_data; >> - struct drm_bridge *next_bridge; >> - struct drm_encoder *encoder; >> struct resource *res; >> int irq; >> int ret; >> >> DRM_DEBUG_DRIVER("\n"); >> >> - if (!meson_hdmi_connector_is_available(dev)) { >> - dev_info(drm->dev, "HDMI Output connector not available\n"); >> - return -ENODEV; >> - } >> - >> match = of_device_get_match_data(&pdev->dev); >> if (!match) { >> dev_err(&pdev->dev, "failed to get match data\n"); >> @@ -1004,7 +723,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, >> meson_dw_hdmi->dev = dev; >> meson_dw_hdmi->data = match; >> dw_plat_data = &meson_dw_hdmi->dw_plat_data; >> - encoder = &meson_dw_hdmi->encoder; >> >> meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi"); >> if (IS_ERR(meson_dw_hdmi->hdmi_supply)) { >> @@ -1076,28 +794,11 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, >> return ret; >> } >> >> - /* Encoder */ >> - >> - ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, >> - DRM_MODE_ENCODER_TMDS, "meson_hdmi"); >> - if (ret) { >> - dev_err(priv->dev, "Failed to init HDMI encoder\n"); >> - return ret; >> - } >> - >> - meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs; >> - drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL, 0); >> - >> - encoder->possible_crtcs = BIT(0); >> - >> meson_dw_hdmi_init(meson_dw_hdmi); >> >> - DRM_DEBUG_DRIVER("encoder initialized\n"); >> - >> /* Bridge / Connector */ >> >> dw_plat_data->priv_data = meson_dw_hdmi; >> - dw_plat_data->mode_valid = dw_hdmi_mode_valid; >> dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; >> dw_plat_data->phy_name = "meson_dw_hdmi_phy"; >> dw_plat_data->phy_data = meson_dw_hdmi; >> @@ -1112,15 +813,11 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, >> >> platform_set_drvdata(pdev, meson_dw_hdmi); >> >> - meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, >> - &meson_dw_hdmi->dw_plat_data); >> + meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data); >> if (IS_ERR(meson_dw_hdmi->hdmi)) >> return PTR_ERR(meson_dw_hdmi->hdmi); >> >> - next_bridge = of_drm_find_bridge(pdev->dev.of_node); >> - if (next_bridge) >> - drm_bridge_attach(encoder, next_bridge, >> - &meson_dw_hdmi->bridge, 0); >> + meson_dw_hdmi->bridge = of_drm_find_bridge(pdev->dev.of_node); >> >> DRM_DEBUG_DRIVER("HDMI controller initialized\n"); >> >> diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c >> new file mode 100644 >> index 000000000000..c775a1ab5b1e >> --- /dev/null >> +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c >> @@ -0,0 +1,359 @@ >> +// SPDX-License-Identifier: GPL-2.0-or-later >> +/* >> + * Copyright (C) 2016 BayLibre, SAS >> + * Author: Neil Armstrong >> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include > alphabetic order. >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> + >> +#include "meson_drv.h" >> +#include "meson_registers.h" >> +#include "meson_vclk.h" >> +#include "meson_venc.h" >> + >> +struct meson_encoder_hdmi { >> + struct drm_encoder encoder; >> + struct drm_bridge bridge; >> + struct drm_bridge *next_bridge; >> + struct meson_drm *priv; >> + unsigned long output_bus_fmt; >> +}; >> + >> +#define bridge_to_meson_encoder_hdmi(x) \ >> + container_of(x, struct meson_encoder_hdmi, bridge) >> + >> +static int meson_encoder_hdmi_attach(struct drm_bridge *bridge, >> + enum drm_bridge_attach_flags flags) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + >> + return drm_bridge_attach(bridge->encoder, encoder_hdmi->next_bridge, >> + &encoder_hdmi->bridge, flags); >> +} >> + >> +static void meson_encoder_hdmi_enable(struct drm_bridge *bridge) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + struct meson_drm *priv = encoder_hdmi->priv; >> + >> + DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); > Bridge drivers mainly uses dev_xxx logging. > New drivers do not use the deprecated DRM_ logging. > > This goes for all logging in this file. > Remember to drop include of drm_print.h > > >> + >> + if (priv->venc.hdmi_use_enci) >> + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); >> + else >> + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); >> +} >> + >> +static void meson_encoder_hdmi_disable(struct drm_bridge *bridge) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + struct meson_drm *priv = encoder_hdmi->priv; >> + >> + DRM_DEBUG_DRIVER("\n"); >> + >> + writel_bits_relaxed(0x3, 0, >> + priv->io_base + _REG(VPU_HDMI_SETTING)); >> + >> + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); >> + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); >> +} >> + >> +static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder_hdmi, >> + const struct drm_display_mode *mode) >> +{ >> + struct meson_drm *priv = encoder_hdmi->priv; >> + int vic = drm_match_cea_mode(mode); >> + unsigned int phy_freq; >> + unsigned int vclk_freq; >> + unsigned int venc_freq; >> + unsigned int hdmi_freq; >> + >> + vclk_freq = mode->clock; >> + >> + /* For 420, pixel clock is half unlike venc clock */ >> + if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> + vclk_freq /= 2; >> + >> + /* TMDS clock is pixel_clock * 10 */ >> + phy_freq = vclk_freq * 10; >> + >> + if (!vic) { >> + meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, >> + vclk_freq, vclk_freq, vclk_freq, false); >> + return; >> + } >> + >> + /* 480i/576i needs global pixel doubling */ >> + if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> + vclk_freq *= 2; >> + >> + venc_freq = vclk_freq; >> + hdmi_freq = vclk_freq; >> + >> + /* VENC double pixels for 1080i, 720p and YUV420 modes */ >> + if (meson_venc_hdmi_venc_repeat(vic) || >> + encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> + venc_freq *= 2; >> + >> + vclk_freq = max(venc_freq, hdmi_freq); >> + >> + if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> + venc_freq /= 2; >> + >> + DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n", >> + phy_freq, vclk_freq, venc_freq, hdmi_freq, >> + priv->venc.hdmi_use_enci); >> + >> + meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, >> + venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); >> +} >> + >> +static enum drm_mode_status meson_encoder_hdmi_mode_valid(struct drm_bridge *bridge, >> + const struct drm_display_info *display_info, >> + const struct drm_display_mode *mode) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + struct meson_drm *priv = encoder_hdmi->priv; >> + bool is_hdmi2_sink = display_info->hdmi.scdc.supported; >> + unsigned int phy_freq; >> + unsigned int vclk_freq; >> + unsigned int venc_freq; >> + unsigned int hdmi_freq; >> + int vic = drm_match_cea_mode(mode); >> + enum drm_mode_status status; >> + >> + DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); >> + >> + /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ >> + if (display_info->max_tmds_clock && >> + mode->clock > display_info->max_tmds_clock && >> + !drm_mode_is_420_only(display_info, mode) && >> + !drm_mode_is_420_also(display_info, mode)) >> + return MODE_BAD; >> + >> + /* Check against non-VIC supported modes */ >> + if (!vic) { >> + status = meson_venc_hdmi_supported_mode(mode); >> + if (status != MODE_OK) >> + return status; >> + >> + return meson_vclk_dmt_supported_freq(priv, mode->clock); >> + /* Check against supported VIC modes */ >> + } else if (!meson_venc_hdmi_supported_vic(vic)) >> + return MODE_BAD; >> + >> + vclk_freq = mode->clock; >> + >> + /* For 420, pixel clock is half unlike venc clock */ >> + if (drm_mode_is_420_only(display_info, mode) || >> + (!is_hdmi2_sink && >> + drm_mode_is_420_also(display_info, mode))) >> + vclk_freq /= 2; >> + >> + /* TMDS clock is pixel_clock * 10 */ >> + phy_freq = vclk_freq * 10; >> + >> + /* 480i/576i needs global pixel doubling */ >> + if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> + vclk_freq *= 2; >> + >> + venc_freq = vclk_freq; >> + hdmi_freq = vclk_freq; >> + >> + /* VENC double pixels for 1080i, 720p and YUV420 modes */ >> + if (meson_venc_hdmi_venc_repeat(vic) || >> + drm_mode_is_420_only(display_info, mode) || >> + (!is_hdmi2_sink && >> + drm_mode_is_420_also(display_info, mode))) >> + venc_freq *= 2; >> + >> + vclk_freq = max(venc_freq, hdmi_freq); >> + >> + if (mode->flags & DRM_MODE_FLAG_DBLCLK) >> + venc_freq /= 2; >> + >> + dev_dbg(priv->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", >> + __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); >> + >> + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); >> +} >> + >> +static void meson_encoder_hdmi_mode_set(struct drm_bridge *bridge, >> + const struct drm_display_mode *mode, >> + const struct drm_display_mode *adjusted_mode) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + struct meson_drm *priv = encoder_hdmi->priv; >> + int vic = drm_match_cea_mode(mode); >> + unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR; >> + bool yuv420_mode = false; >> + >> + DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); >> + >> + if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { >> + ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; >> + yuv420_mode = true; >> + } >> + >> + /* VENC + VENC-DVI Mode setup */ >> + meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); >> + >> + /* VCLK Set clock */ >> + meson_encoder_hdmi_set_vclk(encoder_hdmi, mode); >> + >> + if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) >> + /* Setup YUV420 to HDMI-TX, no 10bit diphering */ >> + writel_relaxed(2 | (2 << 2), >> + priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); >> + else >> + /* Setup YUV444 to HDMI-TX, no 10bit diphering */ >> + writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); >> +} >> + >> +static const u32 meson_encoder_hdmi_out_bus_fmts[] = { >> + MEDIA_BUS_FMT_YUV8_1X24, >> + MEDIA_BUS_FMT_UYYVYY8_0_5X24, >> +}; >> + >> +static u32 * >> +meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge, >> + struct drm_bridge_state *bridge_state, >> + struct drm_crtc_state *crtc_state, >> + struct drm_connector_state *conn_state, >> + u32 output_fmt, >> + unsigned int *num_input_fmts) >> +{ >> + u32 *input_fmts = NULL; >> + int i; >> + >> + *num_input_fmts = 0; >> + >> + for (i = 0 ; i < ARRAY_SIZE(meson_encoder_hdmi_out_bus_fmts) ; ++i) { >> + if (output_fmt == meson_encoder_hdmi_out_bus_fmts[i]) { >> + *num_input_fmts = 1; >> + input_fmts = kcalloc(*num_input_fmts, >> + sizeof(*input_fmts), >> + GFP_KERNEL); > In code similar to this in a previous patch kmalloc() was used. > Both are OK, I just noticed that the code differs. > >> + if (!input_fmts) >> + return NULL; >> + >> + input_fmts[0] = output_fmt; >> + >> + break; >> + } >> + } >> + >> + return input_fmts; >> +} >> + >> +static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge, >> + struct drm_bridge_state *bridge_state, >> + struct drm_crtc_state *crtc_state, >> + struct drm_connector_state *conn_state) >> +{ >> + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); >> + struct drm_connector_state *old_conn_state = >> + drm_atomic_get_old_connector_state(conn_state->state, conn_state->connector); >> + >> + encoder_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format; >> + >> + DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", encoder_hdmi->output_bus_fmt); >> + >> + if (!drm_connector_atomic_hdr_metadata_equal(old_conn_state, conn_state)) >> + crtc_state->mode_changed = true; >> + >> + return 0; >> +} >> + >> +static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = { >> + .attach = meson_encoder_hdmi_attach, >> + .enable = meson_encoder_hdmi_enable, >> + .disable = meson_encoder_hdmi_disable, >> + .mode_valid = meson_encoder_hdmi_mode_valid, >> + .mode_set = meson_encoder_hdmi_mode_set, > Use of mode_set is deprecated, new drivers shall set their mode in the > atomic_enable operation. >> + .atomic_get_input_bus_fmts = meson_encoder_hdmi_get_inp_bus_fmts, >> + .atomic_check = meson_encoder_hdmi_atomic_check, >> + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, >> + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, >> + .atomic_reset = drm_atomic_helper_bridge_reset, >> +}; >> + >> +int meson_encoder_hdmi_init(struct meson_drm *priv) >> +{ >> + struct meson_encoder_hdmi *meson_encoder_hdmi; >> + struct device_node *remote; >> + int ret; >> + >> + DRM_DEBUG_DRIVER("\n"); >> + >> + meson_encoder_hdmi = devm_kzalloc(priv->dev, sizeof(*meson_encoder_hdmi), GFP_KERNEL); >> + if (!meson_encoder_hdmi) >> + return -ENOMEM; >> + >> + /* HDMI Transceiver Bridge */ >> + remote = of_graph_get_remote_node(priv->dev->of_node, 1, 0); >> + if (!remote) { >> + dev_err(priv->dev, "HDMI transceiver device is disabled"); >> + return 0; >> + } >> + >> + meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote); >> + if (!meson_encoder_hdmi->next_bridge) { >> + dev_err(priv->dev, "Failed to find HDMI transceiver bridge\n"); >> + return -EPROBE_DEFER; >> + } >> + >> + /* HDMI Encoder Bridge */ >> + meson_encoder_hdmi->bridge.funcs = &meson_encoder_hdmi_bridge_funcs; >> + meson_encoder_hdmi->bridge.of_node = priv->dev->of_node; >> + meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; >> + >> + drm_bridge_add(&meson_encoder_hdmi->bridge); >> + >> + meson_encoder_hdmi->priv = priv; >> + >> + /* Encoder */ >> + ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder, >> + DRM_MODE_ENCODER_TMDS); >> + if (ret) { >> + dev_err(priv->dev, "Failed to init HDMI encoder: %d\n", ret); >> + return ret; >> + } >> + >> + meson_encoder_hdmi->encoder.possible_crtcs = BIT(0); >> + >> + /* Attach HDMI Encoder Bridge to Encoder */ >> + ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL, 0); >> + if (ret) { >> + dev_err(priv->dev, "Failed to attach bridge: %d\n", ret); >> + return ret; >> + } >> + >> + /* >> + * We should have now in place: >> + * encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[dw-hdmi connector] >> + */ >> + >> + DRM_DEBUG_DRIVER("HDMI encoder initialized\n"); >> + >> + return 0; >> +} >> diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.h b/drivers/gpu/drm/meson/meson_encoder_hdmi.h >> new file mode 100644 >> index 000000000000..ed19494f0956 >> --- /dev/null >> +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.h >> @@ -0,0 +1,12 @@ >> +/* SPDX-License-Identifier: GPL-2.0-or-later */ >> +/* >> + * Copyright (C) 2021 BayLibre, SAS >> + * Author: Neil Armstrong >> + */ >> + >> +#ifndef __MESON_ENCODER_HDMI_H >> +#define __MESON_ENCODER_HDMI_H >> + >> +int meson_encoder_hdmi_init(struct meson_drm *priv); >> + >> +#endif /* __MESON_ENCODER_HDMI_H */ >> -- >> 2.25.1