1
0

Merge tag 'mediatek-drm-next-20250515' of https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux into drm-next

Mediatek DRM Next - 20250515

1. Prepare for support MT8195/88 HDMIv2 and DDCv2
2. DPI: Cleanups and add support for more formats
3. Cleanups and sanitization
4. Replace custom compare_dev with component_compare_of

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Link: https://lore.kernel.org/r/20250514233647.15907-1-chunkuang.hu@kernel.org
This commit is contained in:
Dave Airlie
2025-05-16 07:29:33 +10:00
10 changed files with 498 additions and 292 deletions

View File

@@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8195-hdmi-ddc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek HDMI MT8195 series HDMI Display Data Channel (DDC)
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
- CK Hu <ck.hu@mediatek.com>
properties:
compatible:
oneOf:
- const: mediatek,mt8195-hdmi-ddc
- items:
- const: mediatek,mt8188-hdmi-ddc
- const: mediatek,mt8195-hdmi-ddc
clocks:
maxItems: 1
power-domains:
maxItems: 1
required:
- compatible
- clocks
additionalProperties: false
examples:
- |
hdmi {
hdmi_ddc: i2c {
compatible = "mediatek,mt8195-hdmi-ddc";
clocks = <&clk26m>;
};
};
...

View File

@@ -0,0 +1,151 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8195-hdmi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT8195 series HDMI-TX Encoder
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
- CK Hu <ck.hu@mediatek.com>
description:
The MediaTek HDMI-TX v2 encoder can generate HDMI format data based on
the HDMI Specification 2.0b.
properties:
compatible:
enum:
- mediatek,mt8188-hdmi-tx
- mediatek,mt8195-hdmi-tx
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: HDMI Peripheral Bus (APB) clock
- description: HDCP and HDMI_TOP clock
- description: HDCP, HDMI_TOP and HDMI Audio reference clock
- description: VPP HDMI Split clock
clock-names:
items:
- const: bus
- const: hdcp
- const: hdcp24m
- const: hdmi-split
i2c:
type: object
$ref: /schemas/display/mediatek/mediatek,mt8195-hdmi-ddc.yaml
unevaluatedProperties: false
description: HDMI DDC I2C controller
phys:
maxItems: 1
description: PHY providing clocking TMDS and pixel to controller
phy-names:
items:
- const: hdmi
power-domains:
maxItems: 1
'#sound-dai-cells':
const: 1
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description:
Input port, usually connected to the output port of a DPI
port@1:
$ref: /schemas/graph.yaml#/properties/port
description:
Output port that must be connected either to the input port of
a HDMI connector node containing a ddc-i2c-bus, or to the input
port of an attached bridge chip, such as a SlimPort transmitter.
required:
- port@0
- port@1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
- phys
- phy-names
- ports
allOf:
- $ref: /schemas/sound/dai-common.yaml#
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8195-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/mt8195-power.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
hdmi@1c300000 {
compatible = "mediatek,mt8195-hdmi-tx";
reg = <0 0x1c300000 0 0x1000>;
clocks = <&topckgen CLK_TOP_HDMI_APB>,
<&topckgen CLK_TOP_HDCP>,
<&topckgen CLK_TOP_HDCP_24M>,
<&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>;
clock-names = "bus", "hdcp", "hdcp24m", "hdmi-split";
interrupts = <GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH 0>;
phys = <&hdmi_phy>;
phy-names = "hdmi";
power-domains = <&spm MT8195_POWER_DOMAIN_HDMI_TX>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_pins>;
#sound-dai-cells = <1>;
hdmitx_ddc: i2c {
compatible = "mediatek,mt8195-hdmi-ddc";
clocks = <&clk26m>;
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
hdmi_in: endpoint {
remote-endpoint = <&dpi1_out>;
};
};
port@1 {
reg = <1>;
hdmi_out: endpoint {
remote-endpoint = <&hdmi_connector_in>;
};
};
};
};
};

View File

@@ -21,10 +21,8 @@ mediatek-drm-y := mtk_crtc.o \
obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
mediatek-drm-hdmi-objs := mtk_cec.o \
mtk_hdmi.o \
mtk_hdmi_ddc.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_cec.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_hdmi.o
obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mtk_hdmi_ddc.o
obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk_dp.o

View File

@@ -12,7 +12,6 @@
#include <linux/platform_device.h>
#include "mtk_cec.h"
#include "mtk_hdmi.h"
#include "mtk_drm_drv.h"
#define TR_CONFIG 0x00
@@ -102,6 +101,7 @@ void mtk_cec_set_hpd_event(struct device *dev,
cec->hpd_event = hpd_event;
spin_unlock_irqrestore(&cec->lock, flags);
}
EXPORT_SYMBOL_NS_GPL(mtk_cec_set_hpd_event, "DRM_MTK_HDMI_V1");
bool mtk_cec_hpd_high(struct device *dev)
{
@@ -112,6 +112,7 @@ bool mtk_cec_hpd_high(struct device *dev)
return (status & (HDMI_PORD | HDMI_HTPLG)) == (HDMI_PORD | HDMI_HTPLG);
}
EXPORT_SYMBOL_NS_GPL(mtk_cec_hpd_high, "DRM_MTK_HDMI_V1");
static void mtk_cec_htplg_irq_init(struct mtk_cec *cec)
{
@@ -247,3 +248,7 @@ struct platform_driver mtk_cec_driver = {
.of_match_table = mtk_cec_of_ids,
},
};
module_platform_driver(mtk_cec_driver);
MODULE_DESCRIPTION("MediaTek HDMI CEC Driver");
MODULE_LICENSE("GPL");

View File

@@ -492,11 +492,6 @@ static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids[] = {
{ /* sentinel */ }
};
static int compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}
static int ovl_adaptor_of_get_ddp_comp_type(struct device_node *node,
enum mtk_ovl_adaptor_comp_type *ctype)
{
@@ -567,7 +562,7 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
priv->ovl_adaptor_comp[id] = &comp_pdev->dev;
drm_of_component_match_add(dev, match, compare_of, node);
drm_of_component_match_add(dev, match, component_compare_of, node);
dev_dbg(dev, "Adding component match for %pOF\n", node);
}

View File

@@ -59,7 +59,8 @@ enum mtk_dpi_out_channel_swap {
enum mtk_dpi_out_color_format {
MTK_DPI_COLOR_FORMAT_RGB,
MTK_DPI_COLOR_FORMAT_YCBCR_422
MTK_DPI_COLOR_FORMAT_YCBCR_422,
MTK_DPI_COLOR_FORMAT_YCBCR_444
};
struct mtk_dpi {
@@ -450,9 +451,16 @@ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
enum mtk_dpi_out_color_format format)
{
mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
if (format == MTK_DPI_COLOR_FORMAT_YCBCR_422) {
switch (format) {
case MTK_DPI_COLOR_FORMAT_YCBCR_444:
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, true);
if (dpi->conf->swap_input_support)
mtk_dpi_config_swap_input(dpi, false);
break;
case MTK_DPI_COLOR_FORMAT_YCBCR_422:
mtk_dpi_config_yuv422_enable(dpi, true);
mtk_dpi_config_csc_enable(dpi, true);
@@ -463,11 +471,14 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
mtk_dpi_mask(dpi, DPI_MATRIX_SET, dpi->mode.hdisplay <= 720 ?
MATRIX_SEL_RGB_TO_BT601 : MATRIX_SEL_RGB_TO_JPEG,
INT_MATRIX_SEL_MASK);
} else {
break;
default:
case MTK_DPI_COLOR_FORMAT_RGB:
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, false);
if (dpi->conf->swap_input_support)
mtk_dpi_config_swap_input(dpi, false);
break;
}
}
@@ -734,6 +745,65 @@ static u32 *mtk_dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
static unsigned int mtk_dpi_bus_fmt_bit_num(unsigned int out_bus_format)
{
switch (out_bus_format) {
default:
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_BGR888_1X24:
case MEDIA_BUS_FMT_RGB888_2X12_LE:
case MEDIA_BUS_FMT_RGB888_2X12_BE:
case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_YUV8_1X24:
return MTK_DPI_OUT_BIT_NUM_8BITS;
case MEDIA_BUS_FMT_RGB101010_1X30:
case MEDIA_BUS_FMT_YUYV10_1X20:
case MEDIA_BUS_FMT_YUV10_1X30:
return MTK_DPI_OUT_BIT_NUM_10BITS;
case MEDIA_BUS_FMT_YUYV12_1X24:
return MTK_DPI_OUT_BIT_NUM_12BITS;
}
}
static unsigned int mtk_dpi_bus_fmt_channel_swap(unsigned int out_bus_format)
{
switch (out_bus_format) {
default:
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_RGB888_2X12_LE:
case MEDIA_BUS_FMT_RGB888_2X12_BE:
case MEDIA_BUS_FMT_RGB101010_1X30:
case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_YUYV10_1X20:
case MEDIA_BUS_FMT_YUYV12_1X24:
return MTK_DPI_OUT_CHANNEL_SWAP_RGB;
case MEDIA_BUS_FMT_BGR888_1X24:
case MEDIA_BUS_FMT_YUV8_1X24:
case MEDIA_BUS_FMT_YUV10_1X30:
return MTK_DPI_OUT_CHANNEL_SWAP_BGR;
}
}
static unsigned int mtk_dpi_bus_fmt_color_format(unsigned int out_bus_format)
{
switch (out_bus_format) {
default:
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_BGR888_1X24:
case MEDIA_BUS_FMT_RGB888_2X12_LE:
case MEDIA_BUS_FMT_RGB888_2X12_BE:
case MEDIA_BUS_FMT_RGB101010_1X30:
return MTK_DPI_COLOR_FORMAT_RGB;
case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_YUYV10_1X20:
case MEDIA_BUS_FMT_YUYV12_1X24:
return MTK_DPI_COLOR_FORMAT_YCBCR_422;
case MEDIA_BUS_FMT_YUV8_1X24:
case MEDIA_BUS_FMT_YUV10_1X30:
return MTK_DPI_COLOR_FORMAT_YCBCR_444;
}
}
static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
@@ -753,13 +823,10 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
bridge_state->output_bus_cfg.format);
dpi->output_fmt = out_bus_format;
dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
dpi->bit_num = mtk_dpi_bus_fmt_bit_num(out_bus_format);
dpi->channel_swap = mtk_dpi_bus_fmt_channel_swap(out_bus_format);
dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
dpi->color_format = MTK_DPI_COLOR_FORMAT_YCBCR_422;
else
dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
dpi->color_format = mtk_dpi_bus_fmt_color_format(out_bus_format);
return 0;
}
@@ -1027,9 +1094,29 @@ static const u32 mt8183_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_2X12_BE,
};
static const u32 mt8195_output_fmts[] = {
static const u32 mt8195_dpi_output_fmts[] = {
MEDIA_BUS_FMT_BGR888_1X24,
MEDIA_BUS_FMT_RGB888_1X24,
MEDIA_BUS_FMT_RGB888_2X12_LE,
MEDIA_BUS_FMT_RGB888_2X12_BE,
MEDIA_BUS_FMT_RGB101010_1X30,
MEDIA_BUS_FMT_YUYV8_1X16,
MEDIA_BUS_FMT_YUYV10_1X20,
MEDIA_BUS_FMT_YUYV12_1X24,
MEDIA_BUS_FMT_YUV8_1X24,
MEDIA_BUS_FMT_YUV10_1X30,
};
static const u32 mt8195_dp_intf_output_fmts[] = {
MEDIA_BUS_FMT_BGR888_1X24,
MEDIA_BUS_FMT_RGB888_1X24,
MEDIA_BUS_FMT_RGB888_2X12_LE,
MEDIA_BUS_FMT_RGB888_2X12_BE,
MEDIA_BUS_FMT_RGB101010_1X30,
MEDIA_BUS_FMT_YUYV8_1X16,
MEDIA_BUS_FMT_YUYV10_1X20,
MEDIA_BUS_FMT_YUV8_1X24,
MEDIA_BUS_FMT_YUV10_1X30,
};
static const struct mtk_dpi_factor dpi_factor_mt2701[] = {
@@ -1142,8 +1229,8 @@ static const struct mtk_dpi_conf mt8192_conf = {
static const struct mtk_dpi_conf mt8195_conf = {
.max_clock_khz = 594000,
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
.output_fmts = mt8195_dpi_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8195_dpi_output_fmts),
.pixels_per_iter = 1,
.is_ck_de_pol = true,
.swap_input_support = true,
@@ -1162,8 +1249,8 @@ static const struct mtk_dpi_conf mt8195_dpintf_conf = {
.dpi_factor = dpi_factor_mt8195_dp_intf,
.num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8195_dp_intf),
.max_clock_khz = 600000,
.output_fmts = mt8195_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
.output_fmts = mt8195_dp_intf_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8195_dp_intf_output_fmts),
.pixels_per_iter = 4,
.dimension_mask = DPINTF_HPW_MASK,
.hvsize_mask = DPINTF_HSIZE_MASK,

View File

@@ -470,7 +470,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
ret = drmm_mode_config_init(drm);
if (ret)
goto put_mutex_dev;
return ret;
drm->mode_config.min_width = 64;
drm->mode_config.min_height = 64;
@@ -488,8 +488,11 @@ static int mtk_drm_kms_init(struct drm_device *drm)
for (i = 0; i < private->data->mmsys_dev_num; i++) {
drm->dev_private = private->all_drm_private[i];
ret = component_bind_all(private->all_drm_private[i]->dev, drm);
if (ret)
goto put_mutex_dev;
if (ret) {
while (--i >= 0)
component_unbind_all(private->all_drm_private[i]->dev, drm);
return ret;
}
}
/*
@@ -582,9 +585,6 @@ static int mtk_drm_kms_init(struct drm_device *drm)
err_component_unbind:
for (i = 0; i < private->data->mmsys_dev_num; i++)
component_unbind_all(private->all_drm_private[i]->dev, drm);
put_mutex_dev:
for (i = 0; i < private->data->mmsys_dev_num; i++)
put_device(private->all_drm_private[i]->mutex_dev);
return ret;
}
@@ -655,8 +655,10 @@ static int mtk_drm_bind(struct device *dev)
return 0;
drm = drm_dev_alloc(&mtk_drm_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
if (IS_ERR(drm)) {
ret = PTR_ERR(drm);
goto err_put_dev;
}
private->drm_master = true;
drm->dev_private = private;
@@ -682,18 +684,31 @@ err_free:
drm_dev_put(drm);
for (i = 0; i < private->data->mmsys_dev_num; i++)
private->all_drm_private[i]->drm = NULL;
err_put_dev:
for (i = 0; i < private->data->mmsys_dev_num; i++) {
/* For device_find_child in mtk_drm_get_all_priv() */
put_device(private->all_drm_private[i]->dev);
}
put_device(private->mutex_dev);
return ret;
}
static void mtk_drm_unbind(struct device *dev)
{
struct mtk_drm_private *private = dev_get_drvdata(dev);
int i;
/* for multi mmsys dev, unregister drm dev in mmsys master */
if (private->drm_master) {
drm_dev_unregister(private->drm);
mtk_drm_kms_deinit(private->drm);
drm_dev_put(private->drm);
for (i = 0; i < private->data->mmsys_dev_num; i++) {
/* For device_find_child in mtk_drm_get_all_priv() */
put_device(private->all_drm_private[i]->dev);
}
put_device(private->mutex_dev);
}
private->mtk_drm_bound = false;
private->drm_master = false;

View File

@@ -31,7 +31,6 @@
#include <drm/drm_probe_helper.h>
#include "mtk_cec.h"
#include "mtk_hdmi.h"
#include "mtk_hdmi_regs.h"
#define NCTS_BYTES 7
@@ -165,7 +164,7 @@ struct mtk_hdmi {
bool dvi_mode;
struct regmap *sys_regmap;
unsigned int sys_offset;
void __iomem *regs;
struct regmap *regs;
struct platform_device *audio_pdev;
struct hdmi_audio_param aud_param;
bool audio_enable;
@@ -181,50 +180,10 @@ static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b)
return container_of(b, struct mtk_hdmi, bridge);
}
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 bits)
{
void __iomem *reg = hdmi->regs + offset;
u32 tmp;
tmp = readl(reg);
tmp &= ~bits;
writel(tmp, reg);
}
static 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 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);
}
static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
@@ -259,12 +218,12 @@ static void mtk_hdmi_hw_1p4_version_enable(struct mtk_hdmi *hdmi, bool enable)
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);
}
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);
}
static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi)
@@ -273,25 +232,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);
}
static void mtk_hdmi_hw_enable_notice(struct mtk_hdmi *hdmi, bool enable_notice)
{
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);
}
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);
}
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);
}
static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer,
@@ -337,22 +296,22 @@ static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *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);
mtk_hdmi_write(hdmi, GRL_IFM_PORT, checksum);
regmap_write(hdmi->regs, GRL_IFM_PORT, checksum);
for (i = 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]);
mtk_hdmi_set_bits(hdmi, ctrl_reg, ctrl_frame_en);
regmap_set_bits(hdmi->regs, ctrl_reg, ctrl_frame_en);
}
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);
}
static void mtk_hdmi_hw_config_sys(struct mtk_hdmi *hdmi)
@@ -373,44 +332,44 @@ static void mtk_hdmi_hw_set_deep_color_mode(struct mtk_hdmi *hdmi)
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);
}
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_UNMUTE_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_UNMUTE_SET,
CFG4_AV_UNMUTE_SET);
}
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);
}
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);
}
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);
if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
mode->clock == 74250 &&
mode->vdisplay == 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);
}
static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk_hdmi *hdmi,
@@ -438,7 +397,7 @@ static void mtk_hdmi_hw_aud_set_channel_swap(struct mtk_hdmi *hdmi,
swap_bit = 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);
}
static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi *hdmi,
@@ -459,7 +418,7 @@ static void mtk_hdmi_hw_aud_set_bit_num(struct mtk_hdmi *hdmi,
break;
}
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);
}
static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
@@ -467,7 +426,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
{
u32 val;
val = mtk_hdmi_read(hdmi, GRL_CFG0);
regmap_read(hdmi->regs, GRL_CFG0, &val);
val &= ~(CFG0_W_LENGTH_MASK | CFG0_I2S_MODE_MASK);
switch (i2s_fmt) {
@@ -491,7 +450,7 @@ static void mtk_hdmi_hw_aud_set_i2s_fmt(struct mtk_hdmi *hdmi,
val |= CFG0_I2S_MODE_I2S | CFG0_W_LENGTH_16BIT;
break;
}
mtk_hdmi_write(hdmi, GRL_CFG0, val);
regmap_write(hdmi->regs, GRL_CFG0, val);
}
static void mtk_hdmi_hw_audio_config(struct mtk_hdmi *hdmi, bool dst)
@@ -500,14 +459,14 @@ static void mtk_hdmi_hw_audio_config(struct mtk_hdmi *hdmi, bool dst)
u8 val;
/* 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);
if (dst)
val = DST_NORMAL_DOUBLE | SACD_DST;
else
val = 0;
mtk_hdmi_mask(hdmi, GRL_AUDIO_CFG, val, mask);
regmap_update_bits(hdmi->regs, GRL_AUDIO_CFG, mask, val);
}
static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct mtk_hdmi *hdmi,
@@ -548,10 +507,10 @@ static void mtk_hdmi_hw_aud_set_i2s_chan_num(struct mtk_hdmi *hdmi,
i2s_uv = I2S_UV_CH_EN(0);
}
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);
}
static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
@@ -559,7 +518,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
{
u32 val;
val = mtk_hdmi_read(hdmi, GRL_CFG1);
regmap_read(hdmi->regs, GRL_CFG1, &val);
if (input_type == HDMI_AUD_INPUT_I2S &&
(val & CFG1_SPDIF) == CFG1_SPDIF) {
val &= ~CFG1_SPDIF;
@@ -567,7 +526,7 @@ static void mtk_hdmi_hw_aud_set_input_type(struct mtk_hdmi *hdmi,
(val & CFG1_SPDIF) == 0) {
val |= CFG1_SPDIF;
}
mtk_hdmi_write(hdmi, GRL_CFG1, val);
regmap_write(hdmi->regs, GRL_CFG1, val);
}
static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi,
@@ -576,13 +535,13 @@ static void mtk_hdmi_hw_aud_set_channel_status(struct mtk_hdmi *hdmi,
int i;
for (i = 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);
}
}
@@ -590,13 +549,13 @@ static void mtk_hdmi_hw_aud_src_reenable(struct mtk_hdmi *hdmi)
{
u32 val;
val = mtk_hdmi_read(hdmi, GRL_MIX_CTRL);
regmap_read(hdmi->regs, GRL_MIX_CTRL, &val);
if (val & MIX_CTRL_SRC_EN) {
val &= ~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 |= MIX_CTRL_SRC_EN;
mtk_hdmi_write(hdmi, GRL_MIX_CTRL, val);
regmap_write(hdmi->regs, GRL_MIX_CTRL, val);
}
}
@@ -604,10 +563,10 @@ static void mtk_hdmi_hw_aud_src_disable(struct mtk_hdmi *hdmi)
{
u32 val;
val = mtk_hdmi_read(hdmi, GRL_MIX_CTRL);
regmap_read(hdmi->regs, GRL_MIX_CTRL, &val);
val &= ~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);
}
static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
@@ -615,7 +574,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
{
u32 val;
val = mtk_hdmi_read(hdmi, GRL_CFG5);
regmap_read(hdmi->regs, GRL_CFG5, &val);
val &= CFG5_CD_RATIO_MASK;
switch (mclk) {
@@ -638,7 +597,7 @@ static void mtk_hdmi_hw_aud_set_mclk(struct mtk_hdmi *hdmi,
val |= CFG5_FS256;
break;
}
mtk_hdmi_write(hdmi, GRL_CFG5, val);
regmap_write(hdmi->regs, GRL_CFG5, val);
}
struct hdmi_acr_n {
@@ -716,15 +675,22 @@ static unsigned int hdmi_expected_cts(unsigned int audio_sample_rate,
128 * audio_sample_rate);
}
static void mtk_hdmi_get_ncts(unsigned int sample_rate, unsigned int clock,
unsigned int *n, unsigned int *cts)
{
*n = hdmi_recommended_n(sample_rate, clock);
*cts = hdmi_expected_cts(sample_rate, clock, *n);
}
static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, unsigned int n,
unsigned int cts)
{
unsigned char val[NCTS_BYTES];
int i;
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));
val[0] = (cts >> 24) & 0xff;
@@ -737,7 +703,7 @@ static void do_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi, unsigned int n,
val[6] = n & 0xff;
for (i = 0; i < NCTS_BYTES; i++)
mtk_hdmi_write(hdmi, GRL_NCTS, val[i]);
regmap_write(hdmi->regs, GRL_NCTS, val[i]);
}
static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi,
@@ -746,14 +712,12 @@ static void mtk_hdmi_hw_aud_set_ncts(struct mtk_hdmi *hdmi,
{
unsigned int n, cts;
n = hdmi_recommended_n(sample_rate, clock);
cts = hdmi_expected_cts(sample_rate, clock, n);
mtk_hdmi_get_ncts(sample_rate, clock, &n, &cts);
dev_dbg(hdmi->dev, "%s: sample_rate=%u, clock=%d, cts=%u, n=%u\n",
__func__, sample_rate, clock, n, cts);
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_NCTS_SEL_64);
do_hdmi_hw_aud_set_ncts(hdmi, n, cts);
}
@@ -873,7 +837,7 @@ static void mtk_hdmi_aud_set_input(struct mtk_hdmi *hdmi)
bool dst;
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);
if (hdmi->aud_param.aud_input_type == HDMI_AUD_INPUT_SPDIF &&
hdmi->aud_param.aud_codec == HDMI_AUDIO_CODING_TYPE_DST) {
@@ -905,7 +869,7 @@ static int mtk_hdmi_aud_set_src(struct mtk_hdmi *hdmi,
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);
if (hdmi->aud_param.aud_input_type == HDMI_AUD_INPUT_I2S) {
switch (sample_rate) {
@@ -1061,20 +1025,6 @@ static int mtk_hdmi_setup_vendor_specific_infoframe(struct mtk_hdmi *hdmi,
return 0;
}
static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
{
struct hdmi_audio_param *aud_param = &hdmi->aud_param;
aud_param->aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
aud_param->aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
aud_param->aud_input_type = HDMI_AUD_INPUT_I2S;
aud_param->aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
aud_param->aud_mclk = HDMI_AUD_MCLK_128FS;
aud_param->aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
return 0;
}
static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
{
mtk_hdmi_hw_send_aud_packet(hdmi, true);
@@ -1087,20 +1037,6 @@ static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
hdmi->audio_enable = false;
}
static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
struct hdmi_audio_param *param)
{
if (!hdmi->audio_enable) {
dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
return -EINVAL;
}
dev_dbg(hdmi->dev, "codec:%d, input:%d, channel:%d, fs:%d\n",
param->aud_codec, param->aud_input_type,
param->aud_input_chan_type, param->codec_params.sample_rate);
memcpy(&hdmi->aud_param, param, sizeof(*param));
return mtk_hdmi_aud_output_config(hdmi, &hdmi->mode);
}
static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
struct drm_display_mode *mode)
{
@@ -1408,30 +1344,20 @@ static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs = {
.edid_read = mtk_hdmi_bridge_edid_read,
};
static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
struct platform_device *pdev)
static int mtk_hdmi_get_cec_dev(struct mtk_hdmi *hdmi, struct device *dev, struct device_node *np)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *cec_np, *remote, *i2c_np;
struct platform_device *cec_pdev;
struct regmap *regmap;
struct device_node *cec_np;
int ret;
ret = mtk_hdmi_get_all_clk(hdmi, np);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get clocks: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to get clocks\n");
/* The CEC module handles HDMI hotplug detection */
cec_np = of_get_compatible_child(np->parent, "mediatek,mt8173-cec");
if (!cec_np) {
dev_err(dev, "Failed to find CEC node\n");
return -EINVAL;
}
if (!cec_np)
return dev_err_probe(dev, -EINVAL, "Failed to find CEC node\n");
cec_pdev = of_find_device_by_node(cec_np);
if (!cec_pdev) {
@@ -1441,82 +1367,77 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
return -EPROBE_DEFER;
}
of_node_put(cec_np);
hdmi->cec_dev = &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 = syscon_regmap_lookup_by_phandle(np, "mediatek,syscon-hdmi");
ret = of_property_read_u32_index(np, "mediatek,syscon-hdmi", 1,
&hdmi->sys_offset);
if (IS_ERR(regmap))
ret = PTR_ERR(regmap);
if (ret) {
dev_err(dev,
"Failed to get system configuration registers: %d\n",
ret);
goto put_device;
}
hdmi->sys_regmap = regmap;
hdmi->sys_regmap = syscon_regmap_lookup_by_phandle_args(np, "mediatek,syscon-hdmi",
1, &hdmi->sys_offset);
if (IS_ERR(hdmi->sys_regmap))
return dev_err_probe(dev, PTR_ERR(hdmi->sys_regmap),
"Failed to get system configuration registers\n");
hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hdmi->regs)) {
ret = PTR_ERR(hdmi->regs);
goto put_device;
}
hdmi->cec_dev = &cec_pdev->dev;
return 0;
}
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 *remote, *i2c_np;
int ret;
ret = mtk_hdmi_get_all_clk(hdmi, np);
if (ret)
return dev_err_probe(dev, ret, "Failed to get clocks\n");
hdmi->regs = device_node_to_regmap(dev->of_node);
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
remote = of_graph_get_remote_node(np, 1, 0);
if (!remote) {
ret = -EINVAL;
goto put_device;
}
if (!remote)
return -EINVAL;
if (!of_device_is_compatible(remote, "hdmi-connector")) {
hdmi->next_bridge = of_drm_find_bridge(remote);
if (!hdmi->next_bridge) {
dev_err(dev, "Waiting for external bridge\n");
of_node_put(remote);
ret = -EPROBE_DEFER;
goto put_device;
return -EPROBE_DEFER;
}
}
i2c_np = 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 = -EINVAL;
goto put_device;
}
of_node_put(remote);
if (!i2c_np)
return dev_err_probe(dev, -EINVAL, "No ddc-i2c-bus in connector\n");
hdmi->ddc_adpt = 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 = -EINVAL;
goto put_device;
}
if (!hdmi->ddc_adpt)
return dev_err_probe(dev, -EINVAL, "Failed to get ddc i2c adapter by node\n");
ret = mtk_hdmi_get_cec_dev(hdmi, dev, np);
if (ret)
return ret;
return 0;
put_device:
put_device(hdmi->cec_dev);
return ret;
}
/*
* HDMI audio codec callbacks
*/
static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
static int mtk_hdmi_audio_params(struct mtk_hdmi *hdmi,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
struct hdmi_audio_param hdmi_params;
struct hdmi_audio_param aud_params = { 0 };
unsigned int chan = params->cea.channels;
dev_dbg(hdmi->dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
@@ -1527,16 +1448,16 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
switch (chan) {
case 2:
hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
break;
case 4:
hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_4_0;
aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_4_0;
break;
case 6:
hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_5_1;
aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_5_1;
break;
case 8:
hdmi_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_7_1;
aud_params.aud_input_chan_type = HDMI_AUD_CHAN_TYPE_7_1;
break;
default:
dev_err(hdmi->dev, "channel[%d] not supported!\n", chan);
@@ -1560,27 +1481,45 @@ static int mtk_hdmi_audio_hw_params(struct device *dev, void *data,
switch (daifmt->fmt) {
case HDMI_I2S:
hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
hdmi_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
hdmi_params.aud_input_type = HDMI_AUD_INPUT_I2S;
hdmi_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
hdmi_params.aud_mclk = HDMI_AUD_MCLK_128FS;
aud_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
aud_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
aud_params.aud_input_type = HDMI_AUD_INPUT_I2S;
aud_params.aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
aud_params.aud_mclk = HDMI_AUD_MCLK_128FS;
break;
case HDMI_SPDIF:
hdmi_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
hdmi_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
hdmi_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
aud_params.aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
aud_params.aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
aud_params.aud_input_type = HDMI_AUD_INPUT_SPDIF;
break;
default:
dev_err(hdmi->dev, "%s: Invalid DAI format %d\n", __func__,
daifmt->fmt);
return -EINVAL;
}
memcpy(&aud_params.codec_params, params, sizeof(aud_params.codec_params));
memcpy(&hdmi->aud_param, &aud_params, sizeof(aud_params));
memcpy(&hdmi_params.codec_params, params,
sizeof(hdmi_params.codec_params));
dev_dbg(hdmi->dev, "codec:%d, input:%d, channel:%d, fs:%d\n",
aud_params.aud_codec, aud_params.aud_input_type,
aud_params.aud_input_chan_type, aud_params.codec_params.sample_rate);
mtk_hdmi_audio_set_param(hdmi, &hdmi_params);
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 = dev_get_drvdata(dev);
if (!hdmi->audio_enable) {
dev_err(hdmi->dev, "hdmi audio is in disable state!\n");
return -EINVAL;
}
mtk_hdmi_audio_params(hdmi, daifmt, params);
mtk_hdmi_aud_output_config(hdmi, &hdmi->mode);
return 0;
}
@@ -1626,17 +1565,22 @@ static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
return 0;
}
static void mtk_hdmi_audio_set_plugged_cb(struct mtk_hdmi *hdmi, hdmi_codec_plugged_cb fn,
struct device *codec_dev)
{
mutex_lock(&hdmi->update_plugged_status_lock);
hdmi->plugged_cb = fn;
hdmi->codec_dev = codec_dev;
mutex_unlock(&hdmi->update_plugged_status_lock);
}
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 = data;
mutex_lock(&hdmi->update_plugged_status_lock);
hdmi->plugged_cb = fn;
hdmi->codec_dev = codec_dev;
mutex_unlock(&hdmi->update_plugged_status_lock);
mtk_hdmi_audio_set_plugged_cb(hdmi, fn, codec_dev);
mtk_hdmi_update_plugged_status(hdmi);
return 0;
@@ -1659,6 +1603,7 @@ static void mtk_hdmi_unregister_audio_driver(void *data)
static int mtk_hdmi_register_audio_driver(struct device *dev)
{
struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
struct hdmi_audio_param *aud_param = &hdmi->aud_param;
struct hdmi_codec_pdata codec_data = {
.ops = &mtk_hdmi_audio_codec_ops,
.max_i2s_channels = 2,
@@ -1668,6 +1613,13 @@ static int mtk_hdmi_register_audio_driver(struct device *dev)
};
int ret;
aud_param->aud_codec = HDMI_AUDIO_CODING_TYPE_PCM;
aud_param->aud_sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
aud_param->aud_input_type = HDMI_AUD_INPUT_I2S;
aud_param->aud_i2s_fmt = HDMI_I2S_MODE_I2S_24BIT;
aud_param->aud_mclk = HDMI_AUD_MCLK_128FS;
aud_param->aud_input_chan_type = HDMI_AUD_CHAN_TYPE_2_0;
hdmi->audio_pdev = platform_device_register_data(dev,
HDMI_CODEC_DRV_NAME,
PLATFORM_DEVID_AUTO,
@@ -1709,11 +1661,6 @@ static int mtk_hdmi_probe(struct platform_device *pdev)
mutex_init(&hdmi->update_plugged_status_lock);
platform_set_drvdata(pdev, hdmi);
ret = mtk_hdmi_output_init(hdmi);
if (ret)
return dev_err_probe(dev, ret,
"Failed to initialize hdmi output\n");
ret = mtk_hdmi_register_audio_driver(dev);
if (ret)
return dev_err_probe(dev, ret,
@@ -1790,28 +1737,9 @@ static struct platform_driver mtk_hdmi_driver = {
.pm = &mtk_hdmi_pm_ops,
},
};
static struct platform_driver * const mtk_hdmi_drivers[] = {
&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_platform_driver(mtk_hdmi_driver);
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek HDMI Driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("DRM_MTK_HDMI_V1");

View File

@@ -1,14 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: Jie Qiu <jie.qiu@mediatek.com>
*/
#ifndef _MTK_HDMI_CTRL_H
#define _MTK_HDMI_CTRL_H
struct platform_driver;
extern struct platform_driver mtk_cec_driver;
extern struct platform_driver mtk_hdmi_ddc_driver;
#endif /* _MTK_HDMI_CTRL_H */

View File

@@ -20,7 +20,6 @@
#include <linux/of_platform.h>
#include "mtk_drm_drv.h"
#include "mtk_hdmi.h"
#define SIF1_CLOK (288)
#define DDC_DDCMCTL0 (0x0)
@@ -337,6 +336,7 @@ struct platform_driver mtk_hdmi_ddc_driver = {
.of_match_table = mtk_hdmi_ddc_match,
},
};
module_platform_driver(mtk_hdmi_ddc_driver);
MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek HDMI DDC Driver");