[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CABnWg9vqh2J6=Ku1bSTzAkJ=r1woRcYj7He=hecdZdefAvU4MA@mail.gmail.com>
Date: Fri, 8 Oct 2021 06:30:46 -0700
From: Guillaume Ranquet <granquet@...libre.com>
To: Chun-Kuang Hu <chunkuang.hu@...nel.org>
Cc: Philipp Zabel <p.zabel@...gutronix.de>,
David Airlie <airlied@...ux.ie>,
Daniel Vetter <daniel@...ll.ch>,
Matthias Brugger <matthias.bgg@...il.com>,
linux-kernel <linux-kernel@...r.kernel.org>,
DRI Development <dri-devel@...ts.freedesktop.org>,
"ARM/Mediatek SoC support" <linux-mediatek@...ts.infradead.org>,
Linux ARM <linux-arm-kernel@...ts.infradead.org>
Subject: Re: [PATCH v1 4/4] drm/mediatek: add mt8195 hdmi TX support
Quoting Guillaume Ranquet (2021-09-30 17:30:16)
> Hi Chun-Kuang.
>
> Thank you for your input.
> I have tried to find commonalities between the two drivers but I didn't
> find enough shared code to warrant that architecture.
> I'll have another look, especially now that I'm more familiar with the
> driver.
>
> Regarding 2, I have removed as much functionalities as I could from the
> original vendor tree (like hdcp, hdr, cec...) to keep only HDMI audio and
> video TX.
>
> There might be some more things to remove, but I'm no expert in the domain
> and I'm working without access to mediatek datasheets and documentation.
>
> Though, at this stage I could split the patch in two with video first and
> then audio.
>
> I will try to work something out for a V2.
>
> Thx,
> Guillaume.
>
> Quoting Chun-Kuang Hu (2021-09-30 15:36:42)
> > Hi, Guillaume:
> >
> > This is a big patch, and I'm not familiar with this driver, so the
> > review process would be long. So I tell you about how I review this
> > patch, and if you could process according to my way, the process would
> > be more short.
> >
> > 1. Find the common part of all hdmi driver.
> > Even though mt8195 hdmi has many difference with other mediatek soc
> > hdmi driver, I would like to find the common part and have just one
> > copy of the common part. I expect there would three file finally:
> >
> > mtk_hdmi.c (the common part)
> > mtk_hdmi_mt8173.c (each soc special part)
> > mtk_hdmi_mt8195.c (each soc special part)
> >
> > But this would be difficult in this stage, so you could temporarily
> > have these three file:
> >
> > mtk_hdmi_common.c (the common part)
> > mtk_hdmi.c (each soc special part)
> > mtk_hdmi_mt8195.c (each soc special part)
> >
> > When review is almost done, then change the file name as I wish.
> >
> > 2. The first patch has only basic function, separate advance function
> > to another patch.
> > When comparing mt8195 hdmi driver with other hdmi driver, if mt8195
> > hdmi driver has some function that other hdmi does not have, I would
> > think that function is advance function and should be separate to
> > another patch.
> >
> > If you follow this way, I think the review process would be short.
> > Because this patch is big, I would just review partial part each time.
> >
> > Regards,
> > Chun-Kuang.
> >
> >
> > Guillaume Ranquet <granquet@...libre.com> ��� 2021���9���29��� ������ ������5:47���������
> > >
> > > Add basic hdmi TX support for the mediatek mt8195 SoCs
> > >
> > > Signed-off-by: Guillaume Ranquet <granquet@...libre.com>
> > > ---
> > > drivers/gpu/drm/mediatek/Kconfig | 10 +
> > > drivers/gpu/drm/mediatek/Makefile | 4 +-
> > > drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c | 2293 +++++++++++++++++
> > > drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h | 128 +
> > > .../gpu/drm/mediatek/mtk_mt8195_hdmi_ddc.c | 530 ++++
> > > .../gpu/drm/mediatek/mtk_mt8195_hdmi_ddc.h | 20 +
> > > .../gpu/drm/mediatek/mtk_mt8195_hdmi_regs.h | 329 +++
> > > 7 files changed, 3313 insertions(+), 1 deletion(-)
> > > create mode 100644 drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
> > > create mode 100644 drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h
> > > create mode 100644 drivers/gpu/drm/mediatek/mtk_mt8195_hdmi_ddc.c
> > > create mode 100644 drivers/gpu/drm/mediatek/mtk_mt8195_hdmi_ddc.h
> > > create mode 100644 drivers/gpu/drm/mediatek/mtk_mt8195_hdmi_regs.h
> > >
> > > diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
> > > index 2976d21e9a34a..517d065f0511b 100644
> > > --- a/drivers/gpu/drm/mediatek/Kconfig
> > > +++ b/drivers/gpu/drm/mediatek/Kconfig
> > > @@ -28,3 +28,13 @@ config DRM_MEDIATEK_HDMI
> > > select PHY_MTK_HDMI
> > > help
> > > DRM/KMS HDMI driver for Mediatek SoCs
> > > +
> > > +config DRM_MEDIATEK_HDMI_MT8195_SUSPEND_LOW_POWER
> > > + tristate "DRM HDMI SUSPEND LOW POWER Support for Mediatek mt8195 SoCs"
> > > + depends on DRM_MEDIATEK_HDMI
> > > + help
> > > + DRM/KMS HDMI SUSPEND_LOW_POWER for Mediatek SoCs.
> > > + Choose this option if you want to disable/enable
> > > + clock and power domain when platform enter suspend,
> > > + and this config depends on DRM_MEDIATEK_HDMI.
> > > +
> > > diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
> > > index 29098d7c8307c..736f0816083d0 100644
> > > --- a/drivers/gpu/drm/mediatek/Makefile
> > > +++ b/drivers/gpu/drm/mediatek/Makefile
> > > @@ -18,6 +18,8 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
> > >
> > > mediatek-drm-hdmi-objs := mtk_cec.o \
> > > mtk_hdmi.o \
> > > - mtk_hdmi_ddc.o
> > > + mtk_hdmi_ddc.o \
> > > + mtk_mt8195_hdmi.o \
> > > + mtk_mt8195_hdmi_ddc.o \
> > >
> > > obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
> > > diff --git a/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c b/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
> > > new file mode 100644
> > > index 0000000000000..46c7c8af524ac
> > > --- /dev/null
> > >
Hi Chun-Kuang.
I have removed audio from mtk_mt8195_hdmi, which drops the line count
by approximately a thousand lines.
I couldn't find anything else to remove as _to me_, everything seems
relevant... but I'm no drm/hdmi expert.
I have also tried to find the commonalities between the mtk_hdmi
"legacy" driver and the mt8195 driver.
I have found around 200 lines of codes that could be shared between
the two drivers with some tweaks here and there.
I'm showing a rough draft of what the common code would be down below.
Do you think it's worth the effort to pursue that goal?
Thx,
Guillaume.
Note that it won't apply as I'm not providing the audio removal patch
and it is based on a 5.10 branch I'm testing on right now.
This is just for discussion. I'll rebase and rework things if you
think pursuing this idea is worth the effort.
commit 715b7f7c058f987a583033c885be491e756d9357
Author: Guillaume Ranquet <granquet@...libre.com>
Date: Fri Oct 8 11:25:55 2021 +0200
Draft: HDMI: find common stuff betweem legacy and mt8195
Signed-off-by: Guillaume Ranquet <granquet@...libre.com>
Change-Id: I8a2fb31ceecf467a560abc3201c97e66fb5e9602
diff --git a/drivers/gpu/drm/mediatek/Makefile
b/drivers/gpu/drm/mediatek/Makefile
index 87b3506981fd..477c0648643c 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
mediatek-drm-hdmi-objs := mtk_cec.o \
mtk_hdmi.o \
mtk_hdmi_ddc.o \
+ mtk_hdmi_common.o \
mtk_mt8195_hdmi.o \
mtk_mt8195_hdmi_ddc.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
new file mode 100644
index 000000000000..72ae33019415
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c
@@ -0,0 +1,265 @@
+#include "mtk_hdmi_common.h"
+
+struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b)
+{
+ return container_of(b, struct mtk_hdmi, bridge);
+}
+
+u32 mtk_hdmi_read(struct mtk_hdmi *hdmi, u32 offset)
+{
+ return readl(hdmi->regs + offset);
+}
+
+void mtk_hdmi_write(struct mtk_hdmi *hdmi, u32 offset, u32 val)
+{
+ writel(val, hdmi->regs + offset);
+}
+
+inline void mtk_hdmi_clear_bits(struct mtk_hdmi *hdmi, u32 offset,
+ u32 bits)
+{
+ void __iomem *reg = hdmi->regs + offset;
+ u32 tmp;
+
+ tmp = readl(reg);
+ tmp &= ~bits;
+ writel(tmp, reg);
+}
+
+inline void mtk_hdmi_set_bits(struct mtk_hdmi *hdmi, u32 offset,
+ u32 bits)
+{
+ void __iomem *reg = hdmi->regs + offset;
+ u32 tmp;
+
+ tmp = readl(reg);
+ tmp |= bits;
+ writel(tmp, reg);
+}
+
+void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 mask)
+{
+ void __iomem *reg = hdmi->regs + offset;
+ u32 tmp;
+
+ tmp = readl(reg);
+ tmp = (tmp & ~mask) | (val & mask);
+ writel(tmp, reg);
+}
+
+//TODO: ~common!
+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 = 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 = 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;
+}
+
+//TODO: common
+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 = 0; i < num_clocks; i++) {
+ hdmi->clk[i] = 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;
+}
+
+//TODO: common
+struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+ struct edid *edid;
+
+ if (!hdmi->ddc_adpt)
+ return NULL;
+ edid = drm_get_edid(connector, hdmi->ddc_adpt);
+ if (!edid)
+ return NULL;
+ return edid;
+}
+
+//TODO: common with mt8183
+bool mtk_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+//TODO: common
+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 = hdmi_ctx_from_bridge(bridge);
+
+ drm_mode_copy(&hdmi->mode, adjusted_mode);
+}
+
+//TODO: partly common
+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;
+ bool is_hdmi2x_sink = false;
+
+ if (hdmi->conn.display_info.hdmi.scdc.supported)
+ is_hdmi2x_sink =
+ true; //if support scdc, then the sink support HDMI2.0
+
+ err = drm_hdmi_avi_infoframe_from_display_mode(&frame, &hdmi->conn,
+ mode);
+
+ if (err < 0) {
+ dev_err(hdmi->dev,
+ "Failed to get AVI infoframe from mode: %zd\n", err);
+ return err;
+ }
+
+ frame.colorimetry = hdmi->colorimtery;
+ //no need, since we cannot support other extended colorimetry?
+ if (frame.colorimetry == HDMI_COLORIMETRY_EXTENDED)
+ frame.extended_colorimetry = hdmi->extended_colorimetry;
+
+ /* quantiation range:limited or full */
+ if (frame.colorspace == HDMI_COLORSPACE_RGB)
+ frame.quantization_range = hdmi->quantization_range;
+ else
+ frame.ycc_quantization_range = hdmi->ycc_quantization_range;
+ err = 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;
+}
+
+//TODO: partly common?
+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");
+}
+
+static struct mtk_hdmi_ddc *hdmi_ddc_ctx_from_mtk_hdmi(struct mtk_hdmi *hdmi)
+{
+ return container_of(hdmi->ddc_adpt, struct mtk_hdmi_ddc, adap);
+}
+
+//TODO: mostly common, can work
+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 = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *i2c_np;
+ struct resource *mem;
+ int ret;
+ struct mtk_hdmi_ddc *ddc;
+
+ ret = mtk_hdmi_get_all_clk(hdmi, np, clk_names, num_clocks);
+ if (ret) {
+ dev_err(dev, "Failed to get all clks\n");
+ return ret;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENOMEM;
+
+ hdmi->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
+
+ i2c_np = of_parse_phandle(pdev->dev.of_node, "ddc-i2c-bus", 0);
+ if (!i2c_np) {
+ of_node_put(pdev->dev.of_node);
+ dev_err(dev, "Failed to find ddc-i2c-bus \n");
+ return -EINVAL;
+ }
+
+ hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
+ if (!hdmi->ddc_adpt)
+ return -EPROBE_DEFER;
+
+ //TODO: rework this... this is ugly
+ ddc = hdmi_ddc_ctx_from_mtk_hdmi(hdmi);
+ ddc->regs = hdmi->regs;
+
+ return 0;
+}
+
+int mtk_drm_hdmi_probe(struct platform_device *pdev)
+{
+ struct mtk_hdmi *hdmi;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->dev = dev;
+
+ hdmi->phy = devm_phy_get(dev, "hdmi");
+ if (IS_ERR(hdmi->phy)) {
+ ret = PTR_ERR(hdmi->phy);
+ dev_err(dev, "Failed to get HDMI PHY: %d\n", ret);
+ return ret;
+ }
+
+ ret = mtk_hdmi_dt_parse_pdata(hdmi, pdev, mtk_hdmi_clk_names,
ARRAY_SIZE(mtk_hdmi_clk_names));
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ //TODO
+ mtk_hdmi_output_init(hdmi);
+
+ hdmi->bridge.funcs = &mtk_mt8195_hdmi_bridge_funcs;
+ hdmi->bridge.of_node = pdev->dev.of_node;
+ drm_bridge_add(&hdmi->bridge);
+
+ return 0;
+}
+
+int mtk_drm_hdmi_remove(struct platform_device *pdev)
+{
+ struct mtk_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&hdmi->bridge);
+// TODO:
+ mtk_hdmi_clk_disable(hdmi);
+ i2c_put_adapter(hdmi->ddc_adpt);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
new file mode 100644
index 000000000000..2e0b15d8abf4
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2021 BayLibre, SAS
+ */
+
+#ifndef _MTK_HDMI_COMMON_H
+#define _MTK_HDMI_COMMON_H
+#include <linux/hdmi.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/hdmi-codec.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/phy/phy.h>
+
+#include "mtk_mt8195_hdmi_ddc.h"
+
+enum hdmi_color_depth { HDMI_8_BIT, HDMI_10_BIT, HDMI_12_BIT, HDMI_16_BIT };
+
+enum mtk_hdmi_clk_id {
+ MTK_HDMI_CLK_UNIVPLL_D6D4,
+ MTK_HDMI_CLK_MSDCPLL_D2,
+ MTK_HDMI_CLK_HDMI_APB_SEL,
+ MTK_HDMI_UNIVPLL_D4D8,
+ MTK_HDIM_HDCP_SEL,
+ MTK_HDMI_HDCP_24M_SEL,
+ MTK_HDMI_VPP_SPLIT_HDMI,
+ MTK_HDMI_CLK_COUNT,
+};
+
+enum hdmi_hpd_state {
+ HDMI_PLUG_OUT = 0,
+ HDMI_PLUG_IN_AND_SINK_POWER_ON,
+ HDMI_PLUG_IN_ONLY,
+};
+
+struct mtk_hdmi {
+ struct drm_bridge bridge;
+ struct drm_connector conn;
+ struct device *dev;
+ struct phy *phy;
+ struct i2c_adapter *ddc_adpt;
+ struct clk *clk[MTK_HDMI_CLK_COUNT];
+ struct drm_display_mode mode;
+ bool dvi_mode;
+ void __iomem *regs;
+ spinlock_t property_lock;
+ struct drm_property *csp_depth_prop;
+ u64 support_csp_depth;
+ u64 set_csp_depth;
+ enum hdmi_colorspace csp;
+ enum hdmi_color_depth color_depth;
+ enum hdmi_colorimetry colorimtery;
+ enum hdmi_extended_colorimetry extended_colorimetry;
+ enum hdmi_quantization_range quantization_range;
+ enum hdmi_ycc_quantization_range ycc_quantization_range;
+
+ bool powered;
+ bool enabled;
+ unsigned int hdmi_irq;
+ enum hdmi_hpd_state hpd;
+
+ bool hdmi_enabled;
+ bool power_clk_enabled;
+ bool irq_registered;
+};
+
+struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b);
+u32 mtk_hdmi_read(struct mtk_hdmi *hdmi, u32 offset);
+void mtk_hdmi_write(struct mtk_hdmi *hdmi, u32 offset, u32 val);
+inline void mtk_hdmi_clear_bits(struct mtk_hdmi *hdmi, u32 offset,
+ u32 bits);
+inline void mtk_hdmi_set_bits(struct mtk_hdmi *hdmi, u32 offset,
+ u32 bits);
+void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 mask);
+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);
+
+//TODO: do better than this
+extern const struct drm_bridge_funcs mtk_mt8195_hdmi_bridge_funcs;
+extern const char *const mtk_hdmi_clk_names[MTK_HDMI_CLK_COUNT];
+extern void mtk_hdmi_output_init(struct mtk_hdmi *hdmi);
+extern void mtk_hdmi_clk_disable(struct mtk_hdmi *hdmi);
+#endif //_MTK_HDMI_COMMON_H
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
b/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
index f9bcef24c1d2..72840ef2b0a6 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.c
@@ -17,7 +17,6 @@
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
-#include <linux/phy/phy.h>
#include <linux/pm_wakeup.h>
#include <linux/timer.h>
@@ -28,15 +27,37 @@
#include <drm/drm_scdc_helper.h>
#include "mtk_drm_crtc.h"
-#include "mtk_mt8195_hdmi_ddc.h"
#include "mtk_mt8195_hdmi.h"
+#include "mtk_hdmi_common.h"
+#include "mtk_mt8195_hdmi_ddc.h"
#include "mtk_mt8195_hdmi_regs.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)))
-static const char *const mtk_hdmi_clk_names[MTK_HDMI_CLK_COUNT] = {
+const char *const mtk_hdmi_clk_names[MTK_HDMI_CLK_COUNT] = {
[MTK_HDMI_CLK_UNIVPLL_D6D4] = "univpll_d6_d4",
[MTK_HDMI_CLK_MSDCPLL_D2] = "msdcpll_d2",
[MTK_HDMI_CLK_HDMI_APB_SEL] = "hdmi_apb_sel",
@@ -46,63 +67,11 @@ static const char *const
mtk_hdmi_clk_names[MTK_HDMI_CLK_COUNT] = {
[MTK_HDMI_VPP_SPLIT_HDMI] = "split_hdmi",
};
-static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b)
-{
- return container_of(b, struct mtk_hdmi, bridge);
-}
-
static inline struct mtk_hdmi *hdmi_ctx_from_conn(struct drm_connector *c)
{
return container_of(c, struct mtk_hdmi, conn);
}
-static struct mtk_hdmi_ddc *hdmi_ddc_ctx_from_mtk_hdmi(struct mtk_hdmi *hdmi)
-{
- return container_of(hdmi->ddc_adpt, struct mtk_hdmi_ddc, adap);
-}
-
-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 inline void mtk_hdmi_clear_bits(struct mtk_hdmi *hdmi, u32 offset,
- u32 bits)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp &= ~bits;
- writel(tmp, reg);
-}
-
-static inline void mtk_hdmi_set_bits(struct mtk_hdmi *hdmi, u32 offset,
- u32 bits)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp |= bits;
- writel(tmp, reg);
-}
-
-static void mtk_hdmi_mask(struct mtk_hdmi *hdmi, u32 offset, u32 val, u32 mask)
-{
- void __iomem *reg = hdmi->regs + offset;
- u32 tmp;
-
- tmp = readl(reg);
- tmp = (tmp & ~mask) | (val & mask);
- writel(tmp, reg);
-}
-
static inline void mtk_hdmi_clr_all_int_status(struct mtk_hdmi *hdmi)
{
/*clear all tx irq*/
@@ -251,6 +220,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi
*hdmi, bool black)
mtk_hdmi_mask(hdmi, TOP_VMUTE_CFG1, 0, REG_VMUTE_EN);
}
+//TODO: not compatible
static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi)
{
mtk_hdmi_mask(hdmi, HDMITX_CONFIG, 0x0 << HDMITX_SW_RSTB_SHIFT,
@@ -276,6 +246,7 @@ static bool mtk_hdmi_sink_is_hdmi_device(struct
mtk_hdmi *hdmi)
return true;
}
+//TODO: not compatible
static void mtk_hdmi_set_deep_color(struct mtk_hdmi *hdmi, bool is_hdmi_sink)
{
unsigned int deep_color = 0;
@@ -345,6 +316,7 @@ static void mtk_hdmi_hw_avi_infoframe(struct
mtk_hdmi *hdmi, u8 *buffer, u8 len)
AVI_EN_WR | AVI_EN);
}
+//TODO: not common
static void mtk_hdmi_hw_spd_infoframe(struct mtk_hdmi *hdmi, u8
*buffer, u8 len)
{
mtk_hdmi_mask(hdmi, TOP_INFO_EN, SPD_DIS_WR | SPD_DIS,
@@ -387,6 +359,7 @@ static void mtk_hdmi_hw_spd_infoframe(struct
mtk_hdmi *hdmi, u8 *buffer, u8 len)
SPD_EN_WR | SPD_EN);
}
+//TODO: not compatible
static inline void mtk_hdmi_hw_send_av_mute(struct mtk_hdmi *hdmi)
{
/*GCP packet */
@@ -401,6 +374,7 @@ static inline void mtk_hdmi_hw_send_av_mute(struct
mtk_hdmi *hdmi)
mtk_hdmi_mask(hdmi, TOP_INFO_EN, CP_EN | CP_EN_WR, CP_EN | CP_EN_WR);
}
+//TODO: not compatible
static inline void mtk_hdmi_hw_send_av_unmute(struct mtk_hdmi *hdmi)
{
/*GCP packet */
@@ -415,73 +389,9 @@ static inline void
mtk_hdmi_hw_send_av_unmute(struct mtk_hdmi *hdmi)
mtk_hdmi_mask(hdmi, TOP_INFO_EN, CP_EN | CP_EN_WR, CP_EN | CP_EN_WR);
}
-static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- struct hdmi_avi_infoframe frame;
- u8 buffer[17];
- ssize_t err;
- bool is_hdmi2x_sink = false;
-
- if (hdmi->conn.display_info.hdmi.scdc.supported)
- is_hdmi2x_sink =
- true; //if support scdc, then the sink support HDMI2.0
-
- err = drm_hdmi_avi_infoframe_from_display_mode(&frame, &hdmi->conn,
- mode);
-
- if (err < 0) {
- dev_err(hdmi->dev,
- "Failed to get AVI infoframe from mode: %zd\n", err);
- return err;
- }
-
- frame.colorimetry = hdmi->colorimtery;
- //no need, since we cannot support other extended colorimetry?
- if (frame.colorimetry == HDMI_COLORIMETRY_EXTENDED)
- frame.extended_colorimetry = hdmi->extended_colorimetry;
-
- /* quantiation range:limited or full */
- if (frame.colorspace == HDMI_COLORSPACE_RGB)
- frame.quantization_range = hdmi->quantization_range;
- else
- frame.ycc_quantization_range = hdmi->ycc_quantization_range;
- err = 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_avi_infoframe(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[29];
- ssize_t err;
-
- err = 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 = 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_spd_infoframe(hdmi, buffer, sizeof(buffer));
- return 0;
-}
-
-static void mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
+//TODO: not common
+void mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
{
hdmi->hpd = HDMI_PLUG_OUT;
hdmi->set_csp_depth = RGB444_8bit;
@@ -538,26 +448,13 @@ static void
mtk_hdmi_change_video_resolution(struct mtk_hdmi *hdmi)
mtk_hdmi_yuv420_downsample(hdmi, false);
}
+//TODO: not common
static void mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
struct drm_display_mode *mode)
{
mtk_hdmi_change_video_resolution(hdmi);
}
-static int mtk_hdmi_get_all_clk(struct mtk_hdmi *hdmi, struct device_node *np)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mtk_hdmi_clk_names); i++) {
- hdmi->clk[i] = 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 void mtk_hdmi_clk_enable(struct mtk_hdmi *hdmi)
{
int i;
@@ -576,7 +473,7 @@ static void mtk_hdmi_clk_enable(struct mtk_hdmi *hdmi)
}
}
-static void mtk_hdmi_clk_disable(struct mtk_hdmi *hdmi)
+void mtk_hdmi_clk_disable(struct mtk_hdmi *hdmi)
{
int i;
@@ -844,8 +741,6 @@ static void mtk_hdmi_connetor_init_property(struct
drm_device *drm_dev,
if (!prop)
return;
- hdmi->hdmi_info_blob = prop;
- hdmi->hdmi_info_blob_ptr = NULL;
drm_object_attach_property(&conn->base, prop, 0);
}
@@ -953,6 +848,7 @@ static struct drm_encoder
*mtk_hdmi_conn_best_enc(struct drm_connector *conn)
return hdmi->bridge.encoder;
}
+//TODO: no connector in orig driver
static const struct drm_connector_funcs mtk_hdmi_connector_funcs = {
.detect = hdmi_conn_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -974,6 +870,7 @@ static const struct drm_connector_helper_funcs
mtk_hdmi_connector_helper_funcs =
* Bridge callbacks
*/
+//TODO: not common
static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@@ -1005,27 +902,8 @@ static int mtk_hdmi_bridge_attach(struct
drm_bridge *bridge,
return 0;
}
-static struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
-{
- struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
- struct edid *edid;
-
- if (!hdmi->ddc_adpt)
- return NULL;
- edid = drm_get_edid(connector, hdmi->ddc_adpt);
- if (!edid)
- return NULL;
- return edid;
-}
-
-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;
-}
+//TODO: not common
static void mtk_hdmi_bridge_disable(struct drm_bridge *bridge)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1042,6 +920,7 @@ static void mtk_hdmi_bridge_disable(struct
drm_bridge *bridge)
hdmi->enabled = false;
}
+//TODO: not common
static void mtk_hdmi_bridge_post_disable(struct drm_bridge *bridge)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1056,26 +935,12 @@ static void mtk_hdmi_bridge_post_disable(struct
drm_bridge *bridge)
mtk_hdmi_reset_colorspace_setting(hdmi);
}
-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 = hdmi_ctx_from_bridge(bridge);
-
- drm_mode_copy(&hdmi->mode, adjusted_mode);
-}
-
-static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
- mtk_hdmi_setup_avi_infoframe(hdmi, mode);
- mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
-}
-
+//TODO:not common
static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
+ u8 buffer_spd[HDMI_INFOFRAME_HEADER_SIZE + HDMI_SPD_INFOFRAME_SIZE];
+ u8 buffer_avi[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
union phy_configure_opts opts = {
.dp = { .link_rate = hdmi->mode.clock * 1000 }
};
@@ -1084,11 +949,14 @@ static void mtk_hdmi_bridge_pre_enable(struct
drm_bridge *bridge)
mtk_hdmi_output_set_display_mode(hdmi, &hdmi->mode);
phy_configure(hdmi->phy, &opts);
phy_power_on(hdmi->phy);
- mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
+ 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_avi));
+ mtk_hdmi_hw_avi_infoframe(hdmi, buffer_avi, sizeof(buffer_spd));
hdmi->powered = true;
}
+//TODO:not common
static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1099,7 +967,7 @@ static void mtk_hdmi_bridge_enable(struct
drm_bridge *bridge)
hdmi->enabled = true;
}
-static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs = {
+const struct drm_bridge_funcs mtk_mt8195_hdmi_bridge_funcs = {
.attach = mtk_hdmi_bridge_attach,
.mode_fixup = mtk_hdmi_bridge_mode_fixup,
.disable = mtk_hdmi_bridge_disable,
@@ -1110,88 +978,6 @@ static const struct drm_bridge_funcs
mtk_hdmi_bridge_funcs = {
.get_edid = mtk_hdmi_bridge_get_edid,
};
-static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
- struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct device_node *i2c_np;
- struct resource *mem;
- int ret;
- struct mtk_hdmi_ddc *ddc;
-
- ret = mtk_hdmi_get_all_clk(hdmi, np);
- if (ret)
- return ret;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENOMEM;
-
- hdmi->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
-
- i2c_np = of_parse_phandle(pdev->dev.of_node, "ddc-i2c-bus", 0);
- if (!i2c_np) {
- of_node_put(pdev->dev.of_node);
- return -EINVAL;
- }
-
- hdmi->ddc_adpt = of_find_i2c_adapter_by_node(i2c_np);
- if (!hdmi->ddc_adpt)
- return -EPROBE_DEFER;
-
- ddc = hdmi_ddc_ctx_from_mtk_hdmi(hdmi);
- ddc->regs = hdmi->regs;
-
- return 0;
-}
-
-static int mtk_drm_hdmi_probe(struct platform_device *pdev)
-{
- struct mtk_hdmi *hdmi;
- struct device *dev = &pdev->dev;
- int ret;
-
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
-
- hdmi->phy = devm_phy_get(dev, "hdmi");
- if (IS_ERR(hdmi->phy)) {
- ret = PTR_ERR(hdmi->phy);
- return ret;
- }
-
- ret = mtk_hdmi_dt_parse_pdata(hdmi, pdev);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, hdmi);
-
- mtk_hdmi_output_init(hdmi);
-
- hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
- hdmi->bridge.of_node = pdev->dev.of_node;
- drm_bridge_add(&hdmi->bridge);
-
- return 0;
-}
-
-static int mtk_drm_hdmi_remove(struct platform_device *pdev)
-{
- struct mtk_hdmi *hdmi = platform_get_drvdata(pdev);
-
- drm_bridge_remove(&hdmi->bridge);
- mtk_hdmi_clk_disable(hdmi);
- i2c_put_adapter(hdmi->ddc_adpt);
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static __maybe_unused int mtk_hdmi_suspend(struct device *dev)
{
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h
b/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h
index 5eaa1485cc0c..fbbfa6164292 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h
+++ b/drivers/gpu/drm/mediatek/mtk_mt8195_hdmi.h
@@ -9,97 +9,6 @@
#include <linux/hdmi.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_edid.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <sound/hdmi-codec.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-
-//#include "../../../phy/mediatek/phy-mtk-hdmi-mt8195.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)
-
-enum hdmi_color_depth { HDMI_8_BIT, HDMI_10_BIT, HDMI_12_BIT, HDMI_16_BIT };
-
-enum mtk_hdmi_clk_id {
- MTK_HDMI_CLK_UNIVPLL_D6D4,
- MTK_HDMI_CLK_MSDCPLL_D2,
- MTK_HDMI_CLK_HDMI_APB_SEL,
- MTK_HDMI_UNIVPLL_D4D8,
- MTK_HDIM_HDCP_SEL,
- MTK_HDMI_HDCP_24M_SEL,
- MTK_HDMI_VPP_SPLIT_HDMI,
- MTK_HDMI_CLK_COUNT,
-};
-
-enum hdmi_hpd_state {
- HDMI_PLUG_OUT = 0,
- HDMI_PLUG_IN_AND_SINK_POWER_ON,
- HDMI_PLUG_IN_ONLY,
-};
-
-struct mtk_hdmi {
- struct drm_bridge bridge;
- struct drm_connector conn;
- struct device *dev;
- struct phy *phy;
- struct cec_notifier *notifier;
- struct i2c_adapter *ddc_adpt;
- struct clk *clk[MTK_HDMI_CLK_COUNT];
- struct drm_display_mode mode;
- struct mtk_edid_params *edid_params;
- struct mtk_hdmi_sink_av_cap *sink_avcap;
- bool dvi_mode;
- u32 max_hdisplay;
- u32 max_vdisplay;
- void __iomem *regs;
- spinlock_t property_lock;
- struct drm_property *hdmi_info_blob;
- struct drm_property_blob *hdmi_info_blob_ptr;
- struct drm_property *csp_depth_prop;
- u64 support_csp_depth;
- u64 set_csp_depth;
- enum hdmi_colorspace csp;
- enum hdmi_color_depth color_depth;
- enum hdmi_colorimetry colorimtery;
- enum hdmi_extended_colorimetry extended_colorimetry;
- enum hdmi_quantization_range quantization_range;
- enum hdmi_ycc_quantization_range ycc_quantization_range;
-
- struct device *codec_dev;
- hdmi_codec_plugged_cb plugged_cb;
-
- bool powered;
- bool enabled;
- unsigned int hdmi_irq;
- enum hdmi_hpd_state hpd;
-
- bool hdmi_enabled;
- bool power_clk_enabled;
- bool irq_registered;
-};
#if defined(CONFIG_DRM_MEDIATEK_HDMI) ||
\
defined(CONFIG_DRM_MEDIATEK_HDMI_MODULE)
Powered by blists - more mailing lists