Commit 43ccc783 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'mediatek-drm-next-5.14' of...

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

 into drm-next

Mediatek DRM Next for Linux 5.14

1. Add MT8167 HDMI support
2. Fix PM reference leak
3. Add MT8183 DPI dual edge support

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

From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210616150301.292-1-chunkuang.hu@kernel.org
parents 1bd8a7dc ec8747c5
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mediatek/mediatek,cec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Mediatek HDMI CEC Controller Device Tree Bindings

maintainers:
  - CK Hu <ck.hu@mediatek.com>
  - Jitao shi <jitao.shi@mediatek.com>

description: |
  The HDMI CEC controller handles hotplug detection and CEC communication.

properties:
  compatible:
    enum:
      - mediatek,mt7623-cec
      - mediatek,mt8167-cec
      - mediatek,mt8173-cec

  reg:
    maxItems: 1

  interrupts:
    maxItems: 1

  clocks:
    maxItems: 1

required:
  - compatible
  - reg
  - interrupts
  - clocks

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/mt8173-clk.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/interrupt-controller/irq.h>
    cec: cec@10013000 {
        compatible = "mediatek,mt8173-cec";
        reg = <0x10013000 0xbc>;
        interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>;
        clocks = <&infracfg CLK_INFRA_CEC>;
    };

...
+58 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mediatek/mediatek,hdmi-ddc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Mediatek HDMI DDC Device Tree Bindings

maintainers:
  - CK Hu <ck.hu@mediatek.com>
  - Jitao shi <jitao.shi@mediatek.com>

description: |
  The HDMI DDC i2c controller is used to interface with the HDMI DDC pins.

properties:
  compatible:
    enum:
      - mediatek,mt7623-hdmi-ddc
      - mediatek,mt8167-hdmi-ddc
      - mediatek,mt8173-hdmi-ddc

  reg:
    maxItems: 1

  interrupts:
    maxItems: 1

  clocks:
    maxItems: 1

  clock-names:
    items:
      - const: ddc-i2c

required:
  - compatible
  - reg
  - interrupts
  - clocks
  - clock-names

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/mt8173-clk.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/interrupt-controller/irq.h>
    hdmi_ddc0: i2c@11012000 {
        compatible = "mediatek,mt8173-hdmi-ddc";
        reg = <0x11012000 0x1c>;
        interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>;
        clocks = <&pericfg CLK_PERI_I2C5>;
        clock-names = "ddc-i2c";
    };

...
+0 −136
Original line number Diff line number Diff line
Mediatek HDMI Encoder
=====================

The Mediatek HDMI encoder can generate HDMI 1.4a or MHL 2.0 signals from
its parallel input.

Required properties:
- compatible: Should be "mediatek,<chip>-hdmi".
- the supported chips are mt2701, mt7623 and mt8173
- reg: Physical base address and length of the controller's registers
- interrupts: The interrupt signal from the function block.
- clocks: device clocks
  See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
- clock-names: must contain "pixel", "pll", "bclk", and "spdif".
- phys: phandle link to the HDMI PHY node.
  See Documentation/devicetree/bindings/phy/phy-bindings.txt for details.
- phy-names: must contain "hdmi"
- mediatek,syscon-hdmi: phandle link and register offset to the system
  configuration registers. For mt8173 this must be offset 0x900 into the
  MMSYS_CONFIG region: <&mmsys 0x900>.
- ports: A node containing input and output port nodes with endpoint
  definitions as documented in Documentation/devicetree/bindings/graph.txt.
- port@0: The input port in the ports node should be connected to a DPI output
  port.
- port@1: The output port in the ports node should be connected to the input
  port of a connector node that contains a ddc-i2c-bus property, or to the
  input port of an attached bridge chip, such as a SlimPort transmitter.

HDMI CEC
========

The HDMI CEC controller handles hotplug detection and CEC communication.

Required properties:
- compatible: Should be "mediatek,<chip>-cec"
- the supported chips are mt7623 and mt8173
- reg: Physical base address and length of the controller's registers
- interrupts: The interrupt signal from the function block.
- clocks: device clock

HDMI DDC
========

The HDMI DDC i2c controller is used to interface with the HDMI DDC pins.
The Mediatek's I2C controller is used to interface with I2C devices.

Required properties:
- compatible: Should be "mediatek,<chip>-hdmi-ddc"
- the supported chips are mt7623 and mt8173
- reg: Physical base address and length of the controller's registers
- clocks: device clock
- clock-names: Should be "ddc-i2c".

HDMI PHY
========
See phy/mediatek,hdmi-phy.yaml

Example:

cec: cec@10013000 {
	compatible = "mediatek,mt8173-cec";
	reg = <0 0x10013000 0 0xbc>;
	interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>;
	clocks = <&infracfg CLK_INFRA_CEC>;
};

hdmi_phy: hdmi-phy@10209100 {
	compatible = "mediatek,mt8173-hdmi-phy";
	reg = <0 0x10209100 0 0x24>;
	clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>;
	clock-names = "pll_ref";
	clock-output-names = "hdmitx_dig_cts";
	mediatek,ibias = <0xa>;
	mediatek,ibias_up = <0x1c>;
	#clock-cells = <0>;
	#phy-cells = <0>;
};

hdmi_ddc0: i2c@11012000 {
	compatible = "mediatek,mt8173-hdmi-ddc";
	reg = <0 0x11012000 0 0x1c>;
	interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>;
	clocks = <&pericfg CLK_PERI_I2C5>;
	clock-names = "ddc-i2c";
};

hdmi0: hdmi@14025000 {
	compatible = "mediatek,mt8173-hdmi";
	reg = <0 0x14025000 0 0x400>;
	interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>;
	clocks = <&mmsys CLK_MM_HDMI_PIXEL>,
		 <&mmsys CLK_MM_HDMI_PLLCK>,
		 <&mmsys CLK_MM_HDMI_AUDIO>,
		 <&mmsys CLK_MM_HDMI_SPDIF>;
	clock-names = "pixel", "pll", "bclk", "spdif";
	pinctrl-names = "default";
	pinctrl-0 = <&hdmi_pin>;
	phys = <&hdmi_phy>;
	phy-names = "hdmi";
	mediatek,syscon-hdmi = <&mmsys 0x900>;
	assigned-clocks = <&topckgen CLK_TOP_HDMI_SEL>;
	assigned-clock-parents = <&hdmi_phy>;

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;

			hdmi0_in: endpoint {
				remote-endpoint = <&dpi0_out>;
			};
		};

		port@1 {
			reg = <1>;

			hdmi0_out: endpoint {
				remote-endpoint = <&hdmi_con_in>;
			};
		};
	};
};

connector {
	compatible = "hdmi-connector";
	type = "a";
	ddc-i2c-bus = <&hdmiddc0>;

	port {
		hdmi_con_in: endpoint {
			remote-endpoint = <&hdmi0_out>;
		};
	};
};
+133 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mediatek/mediatek,hdmi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Mediatek HDMI Encoder Device Tree Bindings

maintainers:
  - CK Hu <ck.hu@mediatek.com>
  - Jitao shi <jitao.shi@mediatek.com>

description: |
  The Mediatek HDMI encoder can generate HDMI 1.4a or MHL 2.0 signals from
  its parallel input.

properties:
  compatible:
    enum:
      - mediatek,mt2701-hdmi
      - mediatek,mt7623-hdmi
      - mediatek,mt8167-hdmi
      - mediatek,mt8173-hdmi

  reg:
    maxItems: 1

  interrupts:
    maxItems: 1

  clocks:
    items:
      - description: Pixel Clock
      - description: HDMI PLL
      - description: Bit Clock
      - description: S/PDIF Clock

  clock-names:
    items:
      - const: pixel
      - const: pll
      - const: bclk
      - const: spdif

  phys:
    maxItems: 1

  phy-names:
    items:
      - const: hdmi

  mediatek,syscon-hdmi:
    $ref: '/schemas/types.yaml#/definitions/phandle-array'
    maxItems: 1
    description: |
      phandle link and register offset to the system configuration registers.

  ports:
    $ref: /schemas/graph.yaml#/properties/ports

    properties:
      port@0:
        $ref: /schemas/graph.yaml#/properties/port
        description: |
          Input port node. This port should be connected to a DPI output port.

      port@1:
        $ref: /schemas/graph.yaml#/properties/port
        description: |
          Output port node. This port should be connected to the input port of a connector
          node that contains a ddc-i2c-bus property, 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
  - phys
  - phy-names
  - mediatek,syscon-hdmi
  - ports

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/mt8173-clk.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/interrupt-controller/irq.h>
    hdmi0: hdmi@14025000 {
        compatible = "mediatek,mt8173-hdmi";
        reg = <0x14025000 0x400>;
        interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>;
        clocks = <&mmsys CLK_MM_HDMI_PIXEL>,
             <&mmsys CLK_MM_HDMI_PLLCK>,
             <&mmsys CLK_MM_HDMI_AUDIO>,
             <&mmsys CLK_MM_HDMI_SPDIF>;
        clock-names = "pixel", "pll", "bclk", "spdif";
        pinctrl-names = "default";
        pinctrl-0 = <&hdmi_pin>;
        phys = <&hdmi_phy>;
        phy-names = "hdmi";
        mediatek,syscon-hdmi = <&mmsys 0x900>;

        ports {
          #address-cells = <1>;
          #size-cells = <0>;

          port@0 {
            reg = <0>;

            hdmi0_in: endpoint {
              remote-endpoint = <&dpi0_out>;
            };
          };

          port@1 {
            reg = <1>;

            hdmi0_out: endpoint {
              remote-endpoint = <&hdmi_con_in>;
            };
          };
        };
    };

...
+123 −6
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct mtk_dpi {
	struct pinctrl *pinctrl;
	struct pinctrl_state *pins_gpio;
	struct pinctrl_state *pins_dpi;
	u32 output_fmt;
	int refcount;
};

@@ -122,6 +123,8 @@ struct mtk_dpi_conf {
	u32 reg_h_fre_con;
	u32 max_clock_khz;
	bool edge_sel_en;
	const u32 *output_fmts;
	u32 num_output_fmts;
};

static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -381,6 +384,20 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
	}
}

static void mtk_dpi_dual_edge(struct mtk_dpi *dpi)
{
	if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
	    (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) {
		mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE,
			     DDR_EN | DDR_4PHASE);
		mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING,
			     dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE ?
			     EDGE_SEL : 0, EDGE_SEL);
	} else {
		mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE, 0);
	}
}

static void mtk_dpi_power_off(struct mtk_dpi *dpi)
{
	if (WARN_ON(dpi->refcount == 0))
@@ -455,7 +472,13 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
	pll_rate = clk_get_rate(dpi->tvd_clk);

	vm.pixelclock = pll_rate / factor;
	if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
	    (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
		clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
	else
		clk_set_rate(dpi->pixel_clk, vm.pixelclock);


	vm.pixelclock = clk_get_rate(dpi->pixel_clk);

	dev_dbg(dpi->dev, "Got  PLL %lu Hz, pixel clock %lu Hz\n",
@@ -519,12 +542,87 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
	mtk_dpi_config_yc_map(dpi, dpi->yc_map);
	mtk_dpi_config_color_format(dpi, dpi->color_format);
	mtk_dpi_config_2n_h_fre(dpi);
	mtk_dpi_dual_edge(dpi);
	mtk_dpi_config_disable_edge(dpi);
	mtk_dpi_sw_reset(dpi, false);

	return 0;
}

static u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
						      struct drm_bridge_state *bridge_state,
						      struct drm_crtc_state *crtc_state,
						      struct drm_connector_state *conn_state,
						      unsigned int *num_output_fmts)
{
	struct mtk_dpi *dpi = bridge_to_dpi(bridge);
	u32 *output_fmts;

	*num_output_fmts = 0;

	if (!dpi->conf->output_fmts) {
		dev_err(dpi->dev, "output_fmts should not be null\n");
		return NULL;
	}

	output_fmts = kcalloc(dpi->conf->num_output_fmts, sizeof(*output_fmts),
			     GFP_KERNEL);
	if (!output_fmts)
		return NULL;

	*num_output_fmts = dpi->conf->num_output_fmts;

	memcpy(output_fmts, dpi->conf->output_fmts,
	       sizeof(*output_fmts) * dpi->conf->num_output_fmts);

	return output_fmts;
}

static u32 *mtk_dpi_bridge_atomic_get_input_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;

	*num_input_fmts = 0;

	input_fmts = kcalloc(1, sizeof(*input_fmts),
			     GFP_KERNEL);
	if (!input_fmts)
		return NULL;

	*num_input_fmts = 1;
	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;

	return input_fmts;
}

static int mtk_dpi_bridge_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 mtk_dpi *dpi = bridge->driver_private;
	unsigned int out_bus_format;

	out_bus_format = bridge_state->output_bus_cfg.format;

	dev_dbg(dpi->dev, "input format 0x%04x, output format 0x%04x\n",
		bridge_state->input_bus_cfg.format,
		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->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
	dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;

	return 0;
}

static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
				 enum drm_bridge_attach_flags flags)
{
@@ -577,6 +675,12 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
	.mode_valid = mtk_dpi_bridge_mode_valid,
	.disable = mtk_dpi_bridge_disable,
	.enable = mtk_dpi_bridge_enable,
	.atomic_check = mtk_dpi_bridge_atomic_check,
	.atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts,
	.atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts,
	.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,
};

void mtk_dpi_start(struct device *dev)
@@ -623,11 +727,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
	}
	drm_connector_attach_encoder(dpi->connector, &dpi->encoder);

	dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
	dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
	dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
	dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;

	return 0;

err_cleanup:
@@ -680,10 +779,21 @@ static unsigned int mt8183_calculate_factor(int clock)
		return 2;
}

static const u32 mt8173_output_fmts[] = {
	MEDIA_BUS_FMT_RGB888_1X24,
};

static const u32 mt8183_output_fmts[] = {
	MEDIA_BUS_FMT_RGB888_2X12_LE,
	MEDIA_BUS_FMT_RGB888_2X12_BE,
};

static const struct mtk_dpi_conf mt8173_conf = {
	.cal_factor = mt8173_calculate_factor,
	.reg_h_fre_con = 0xe0,
	.max_clock_khz = 300000,
	.output_fmts = mt8173_output_fmts,
	.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};

static const struct mtk_dpi_conf mt2701_conf = {
@@ -691,18 +801,24 @@ static const struct mtk_dpi_conf mt2701_conf = {
	.reg_h_fre_con = 0xb0,
	.edge_sel_en = true,
	.max_clock_khz = 150000,
	.output_fmts = mt8173_output_fmts,
	.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};

static const struct mtk_dpi_conf mt8183_conf = {
	.cal_factor = mt8183_calculate_factor,
	.reg_h_fre_con = 0xe0,
	.max_clock_khz = 100000,
	.output_fmts = mt8183_output_fmts,
	.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
};

static const struct mtk_dpi_conf mt8192_conf = {
	.cal_factor = mt8183_calculate_factor,
	.reg_h_fre_con = 0xe0,
	.max_clock_khz = 150000,
	.output_fmts = mt8173_output_fmts,
	.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};

static int mtk_dpi_probe(struct platform_device *pdev)
@@ -718,6 +834,7 @@ static int mtk_dpi_probe(struct platform_device *pdev)

	dpi->dev = dev;
	dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
	dpi->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;

	dpi->pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR(dpi->pinctrl)) {
Loading