xref: /openbmc/linux/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
111696c5eSBiju Das // SPDX-License-Identifier: GPL-2.0
211696c5eSBiju Das /*
311696c5eSBiju Das  * R-Car LVDS Encoder
411696c5eSBiju Das  *
511696c5eSBiju Das  * Copyright (C) 2013-2018 Renesas Electronics Corporation
611696c5eSBiju Das  *
711696c5eSBiju Das  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
811696c5eSBiju Das  */
911696c5eSBiju Das 
1011696c5eSBiju Das #include <linux/clk.h>
1111696c5eSBiju Das #include <linux/delay.h>
1211696c5eSBiju Das #include <linux/io.h>
1311696c5eSBiju Das #include <linux/media-bus-format.h>
1411696c5eSBiju Das #include <linux/module.h>
1511696c5eSBiju Das #include <linux/of.h>
1611696c5eSBiju Das #include <linux/of_device.h>
1711696c5eSBiju Das #include <linux/of_graph.h>
1811696c5eSBiju Das #include <linux/platform_device.h>
1911696c5eSBiju Das #include <linux/pm_runtime.h>
2011696c5eSBiju Das #include <linux/reset.h>
2111696c5eSBiju Das #include <linux/slab.h>
2211696c5eSBiju Das #include <linux/sys_soc.h>
2311696c5eSBiju Das 
2411696c5eSBiju Das #include <drm/drm_atomic.h>
2511696c5eSBiju Das #include <drm/drm_atomic_helper.h>
2611696c5eSBiju Das #include <drm/drm_bridge.h>
2711696c5eSBiju Das #include <drm/drm_of.h>
2811696c5eSBiju Das #include <drm/drm_panel.h>
2911696c5eSBiju Das #include <drm/drm_print.h>
3011696c5eSBiju Das #include <drm/drm_probe_helper.h>
3111696c5eSBiju Das 
3211696c5eSBiju Das #include "rcar_lvds.h"
3311696c5eSBiju Das #include "rcar_lvds_regs.h"
3411696c5eSBiju Das 
3511696c5eSBiju Das struct rcar_lvds;
3611696c5eSBiju Das 
3711696c5eSBiju Das /* Keep in sync with the LVDCR0.LVMD hardware register values. */
3811696c5eSBiju Das enum rcar_lvds_mode {
3911696c5eSBiju Das 	RCAR_LVDS_MODE_JEIDA = 0,
4011696c5eSBiju Das 	RCAR_LVDS_MODE_MIRROR = 1,
4111696c5eSBiju Das 	RCAR_LVDS_MODE_VESA = 4,
4211696c5eSBiju Das };
4311696c5eSBiju Das 
4411696c5eSBiju Das enum rcar_lvds_link_type {
4511696c5eSBiju Das 	RCAR_LVDS_SINGLE_LINK = 0,
4611696c5eSBiju Das 	RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 1,
4711696c5eSBiju Das 	RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 2,
4811696c5eSBiju Das };
4911696c5eSBiju Das 
5011696c5eSBiju Das #define RCAR_LVDS_QUIRK_LANES		BIT(0)	/* LVDS lanes 1 and 3 inverted */
5111696c5eSBiju Das #define RCAR_LVDS_QUIRK_GEN3_LVEN	BIT(1)	/* LVEN bit needs to be set on R8A77970/R8A7799x */
5211696c5eSBiju Das #define RCAR_LVDS_QUIRK_PWD		BIT(2)	/* PWD bit available (all of Gen3 but E3) */
5311696c5eSBiju Das #define RCAR_LVDS_QUIRK_EXT_PLL		BIT(3)	/* Has extended PLL */
5411696c5eSBiju Das #define RCAR_LVDS_QUIRK_DUAL_LINK	BIT(4)	/* Supports dual-link operation */
5511696c5eSBiju Das 
5611696c5eSBiju Das struct rcar_lvds_device_info {
5711696c5eSBiju Das 	unsigned int gen;
5811696c5eSBiju Das 	unsigned int quirks;
5911696c5eSBiju Das 	void (*pll_setup)(struct rcar_lvds *lvds, unsigned int freq);
6011696c5eSBiju Das };
6111696c5eSBiju Das 
6211696c5eSBiju Das struct rcar_lvds {
6311696c5eSBiju Das 	struct device *dev;
6411696c5eSBiju Das 	const struct rcar_lvds_device_info *info;
6511696c5eSBiju Das 	struct reset_control *rstc;
6611696c5eSBiju Das 
6711696c5eSBiju Das 	struct drm_bridge bridge;
6811696c5eSBiju Das 
6911696c5eSBiju Das 	struct drm_bridge *next_bridge;
7011696c5eSBiju Das 	struct drm_panel *panel;
7111696c5eSBiju Das 
7211696c5eSBiju Das 	void __iomem *mmio;
7311696c5eSBiju Das 	struct {
7411696c5eSBiju Das 		struct clk *mod;		/* CPG module clock */
7511696c5eSBiju Das 		struct clk *extal;		/* External clock */
7611696c5eSBiju Das 		struct clk *dotclkin[2];	/* External DU clocks */
7711696c5eSBiju Das 	} clocks;
7811696c5eSBiju Das 
7911696c5eSBiju Das 	struct drm_bridge *companion;
8011696c5eSBiju Das 	enum rcar_lvds_link_type link_type;
8111696c5eSBiju Das };
8211696c5eSBiju Das 
8311696c5eSBiju Das #define bridge_to_rcar_lvds(b) \
8411696c5eSBiju Das 	container_of(b, struct rcar_lvds, bridge)
8511696c5eSBiju Das 
rcar_lvds_read(struct rcar_lvds * lvds,u32 reg)8611696c5eSBiju Das static u32 rcar_lvds_read(struct rcar_lvds *lvds, u32 reg)
8711696c5eSBiju Das {
8811696c5eSBiju Das 	return ioread32(lvds->mmio + reg);
8911696c5eSBiju Das }
9011696c5eSBiju Das 
rcar_lvds_write(struct rcar_lvds * lvds,u32 reg,u32 data)9111696c5eSBiju Das static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
9211696c5eSBiju Das {
9311696c5eSBiju Das 	iowrite32(data, lvds->mmio + reg);
9411696c5eSBiju Das }
9511696c5eSBiju Das 
9611696c5eSBiju Das /* -----------------------------------------------------------------------------
9711696c5eSBiju Das  * PLL Setup
9811696c5eSBiju Das  */
9911696c5eSBiju Das 
rcar_lvds_pll_setup_gen2(struct rcar_lvds * lvds,unsigned int freq)10011696c5eSBiju Das static void rcar_lvds_pll_setup_gen2(struct rcar_lvds *lvds, unsigned int freq)
10111696c5eSBiju Das {
10211696c5eSBiju Das 	u32 val;
10311696c5eSBiju Das 
10411696c5eSBiju Das 	if (freq < 39000000)
10511696c5eSBiju Das 		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
10611696c5eSBiju Das 	else if (freq < 61000000)
10711696c5eSBiju Das 		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
10811696c5eSBiju Das 	else if (freq < 121000000)
10911696c5eSBiju Das 		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
11011696c5eSBiju Das 	else
11111696c5eSBiju Das 		val = LVDPLLCR_PLLDLYCNT_150M;
11211696c5eSBiju Das 
11311696c5eSBiju Das 	rcar_lvds_write(lvds, LVDPLLCR, val);
11411696c5eSBiju Das }
11511696c5eSBiju Das 
rcar_lvds_pll_setup_gen3(struct rcar_lvds * lvds,unsigned int freq)11611696c5eSBiju Das static void rcar_lvds_pll_setup_gen3(struct rcar_lvds *lvds, unsigned int freq)
11711696c5eSBiju Das {
11811696c5eSBiju Das 	u32 val;
11911696c5eSBiju Das 
12011696c5eSBiju Das 	if (freq < 42000000)
12111696c5eSBiju Das 		val = LVDPLLCR_PLLDIVCNT_42M;
12211696c5eSBiju Das 	else if (freq < 85000000)
12311696c5eSBiju Das 		val = LVDPLLCR_PLLDIVCNT_85M;
12411696c5eSBiju Das 	else if (freq < 128000000)
12511696c5eSBiju Das 		val = LVDPLLCR_PLLDIVCNT_128M;
12611696c5eSBiju Das 	else
12711696c5eSBiju Das 		val = LVDPLLCR_PLLDIVCNT_148M;
12811696c5eSBiju Das 
12911696c5eSBiju Das 	rcar_lvds_write(lvds, LVDPLLCR, val);
13011696c5eSBiju Das }
13111696c5eSBiju Das 
13211696c5eSBiju Das struct pll_info {
13311696c5eSBiju Das 	unsigned long diff;
13411696c5eSBiju Das 	unsigned int pll_m;
13511696c5eSBiju Das 	unsigned int pll_n;
13611696c5eSBiju Das 	unsigned int pll_e;
13711696c5eSBiju Das 	unsigned int div;
13811696c5eSBiju Das 	u32 clksel;
13911696c5eSBiju Das };
14011696c5eSBiju Das 
rcar_lvds_d3_e3_pll_calc(struct rcar_lvds * lvds,struct clk * clk,unsigned long target,struct pll_info * pll,u32 clksel,bool dot_clock_only)14111696c5eSBiju Das static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
14211696c5eSBiju Das 				     unsigned long target, struct pll_info *pll,
14311696c5eSBiju Das 				     u32 clksel, bool dot_clock_only)
14411696c5eSBiju Das {
14511696c5eSBiju Das 	unsigned int div7 = dot_clock_only ? 1 : 7;
14611696c5eSBiju Das 	unsigned long output;
14711696c5eSBiju Das 	unsigned long fin;
14811696c5eSBiju Das 	unsigned int m_min;
14911696c5eSBiju Das 	unsigned int m_max;
15011696c5eSBiju Das 	unsigned int m;
15111696c5eSBiju Das 	int error;
15211696c5eSBiju Das 
15311696c5eSBiju Das 	if (!clk)
15411696c5eSBiju Das 		return;
15511696c5eSBiju Das 
15611696c5eSBiju Das 	/*
15711696c5eSBiju Das 	 * The LVDS PLL is made of a pre-divider and a multiplier (strangely
15811696c5eSBiju Das 	 * enough called M and N respectively), followed by a post-divider E.
15911696c5eSBiju Das 	 *
16011696c5eSBiju Das 	 *         ,-----.         ,-----.     ,-----.         ,-----.
16111696c5eSBiju Das 	 * Fin --> | 1/M | -Fpdf-> | PFD | --> | VCO | -Fvco-> | 1/E | --> Fout
16211696c5eSBiju Das 	 *         `-----'     ,-> |     |     `-----'   |     `-----'
16311696c5eSBiju Das 	 *                     |   `-----'               |
16411696c5eSBiju Das 	 *                     |         ,-----.         |
16511696c5eSBiju Das 	 *                     `-------- | 1/N | <-------'
16611696c5eSBiju Das 	 *                               `-----'
16711696c5eSBiju Das 	 *
16811696c5eSBiju Das 	 * The clock output by the PLL is then further divided by a programmable
16911696c5eSBiju Das 	 * divider DIV to achieve the desired target frequency. Finally, an
17011696c5eSBiju Das 	 * optional fixed /7 divider is used to convert the bit clock to a pixel
17111696c5eSBiju Das 	 * clock (as LVDS transmits 7 bits per lane per clock sample).
17211696c5eSBiju Das 	 *
17311696c5eSBiju Das 	 *          ,-------.     ,-----.     |\
17411696c5eSBiju Das 	 * Fout --> | 1/DIV | --> | 1/7 | --> | |
17511696c5eSBiju Das 	 *          `-------'  |  `-----'     | | --> dot clock
17611696c5eSBiju Das 	 *                     `------------> | |
17711696c5eSBiju Das 	 *                                    |/
17811696c5eSBiju Das 	 *
17911696c5eSBiju Das 	 * The /7 divider is optional, it is enabled when the LVDS PLL is used
18011696c5eSBiju Das 	 * to drive the LVDS encoder, and disabled when  used to generate a dot
18111696c5eSBiju Das 	 * clock for the DU RGB output, without using the LVDS encoder.
18211696c5eSBiju Das 	 *
18311696c5eSBiju Das 	 * The PLL allowed input frequency range is 12 MHz to 192 MHz.
18411696c5eSBiju Das 	 */
18511696c5eSBiju Das 
18611696c5eSBiju Das 	fin = clk_get_rate(clk);
18711696c5eSBiju Das 	if (fin < 12000000 || fin > 192000000)
18811696c5eSBiju Das 		return;
18911696c5eSBiju Das 
19011696c5eSBiju Das 	/*
19111696c5eSBiju Das 	 * The comparison frequency range is 12 MHz to 24 MHz, which limits the
19211696c5eSBiju Das 	 * allowed values for the pre-divider M (normal range 1-8).
19311696c5eSBiju Das 	 *
19411696c5eSBiju Das 	 * Fpfd = Fin / M
19511696c5eSBiju Das 	 */
19611696c5eSBiju Das 	m_min = max_t(unsigned int, 1, DIV_ROUND_UP(fin, 24000000));
19711696c5eSBiju Das 	m_max = min_t(unsigned int, 8, fin / 12000000);
19811696c5eSBiju Das 
19911696c5eSBiju Das 	for (m = m_min; m <= m_max; ++m) {
20011696c5eSBiju Das 		unsigned long fpfd;
20111696c5eSBiju Das 		unsigned int n_min;
20211696c5eSBiju Das 		unsigned int n_max;
20311696c5eSBiju Das 		unsigned int n;
20411696c5eSBiju Das 
20511696c5eSBiju Das 		/*
20611696c5eSBiju Das 		 * The VCO operating range is 900 Mhz to 1800 MHz, which limits
20711696c5eSBiju Das 		 * the allowed values for the multiplier N (normal range
20811696c5eSBiju Das 		 * 60-120).
20911696c5eSBiju Das 		 *
21011696c5eSBiju Das 		 * Fvco = Fin * N / M
21111696c5eSBiju Das 		 */
21211696c5eSBiju Das 		fpfd = fin / m;
21311696c5eSBiju Das 		n_min = max_t(unsigned int, 60, DIV_ROUND_UP(900000000, fpfd));
21411696c5eSBiju Das 		n_max = min_t(unsigned int, 120, 1800000000 / fpfd);
21511696c5eSBiju Das 
21611696c5eSBiju Das 		for (n = n_min; n < n_max; ++n) {
21711696c5eSBiju Das 			unsigned long fvco;
21811696c5eSBiju Das 			unsigned int e_min;
21911696c5eSBiju Das 			unsigned int e;
22011696c5eSBiju Das 
22111696c5eSBiju Das 			/*
22211696c5eSBiju Das 			 * The output frequency is limited to 1039.5 MHz,
22311696c5eSBiju Das 			 * limiting again the allowed values for the
22411696c5eSBiju Das 			 * post-divider E (normal value 1, 2 or 4).
22511696c5eSBiju Das 			 *
22611696c5eSBiju Das 			 * Fout = Fvco / E
22711696c5eSBiju Das 			 */
22811696c5eSBiju Das 			fvco = fpfd * n;
22911696c5eSBiju Das 			e_min = fvco > 1039500000 ? 1 : 0;
23011696c5eSBiju Das 
23111696c5eSBiju Das 			for (e = e_min; e < 3; ++e) {
23211696c5eSBiju Das 				unsigned long fout;
23311696c5eSBiju Das 				unsigned long diff;
23411696c5eSBiju Das 				unsigned int div;
23511696c5eSBiju Das 
23611696c5eSBiju Das 				/*
23711696c5eSBiju Das 				 * Finally we have a programable divider after
23811696c5eSBiju Das 				 * the PLL, followed by a an optional fixed /7
23911696c5eSBiju Das 				 * divider.
24011696c5eSBiju Das 				 */
24111696c5eSBiju Das 				fout = fvco / (1 << e) / div7;
24211696c5eSBiju Das 				div = max(1UL, DIV_ROUND_CLOSEST(fout, target));
24311696c5eSBiju Das 				diff = abs(fout / div - target);
24411696c5eSBiju Das 
24511696c5eSBiju Das 				if (diff < pll->diff) {
24611696c5eSBiju Das 					pll->diff = diff;
24711696c5eSBiju Das 					pll->pll_m = m;
24811696c5eSBiju Das 					pll->pll_n = n;
24911696c5eSBiju Das 					pll->pll_e = e;
25011696c5eSBiju Das 					pll->div = div;
25111696c5eSBiju Das 					pll->clksel = clksel;
25211696c5eSBiju Das 
25311696c5eSBiju Das 					if (diff == 0)
25411696c5eSBiju Das 						goto done;
25511696c5eSBiju Das 				}
25611696c5eSBiju Das 			}
25711696c5eSBiju Das 		}
25811696c5eSBiju Das 	}
25911696c5eSBiju Das 
26011696c5eSBiju Das done:
26111696c5eSBiju Das 	output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
26211696c5eSBiju Das 	       / div7 / pll->div;
26311696c5eSBiju Das 	error = (long)(output - target) * 10000 / (long)target;
26411696c5eSBiju Das 
26511696c5eSBiju Das 	dev_dbg(lvds->dev,
26611696c5eSBiju Das 		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/E/DIV %u/%u/%u/%u\n",
26711696c5eSBiju Das 		clk, fin, output, target, error / 100,
26811696c5eSBiju Das 		error < 0 ? -error % 100 : error % 100,
26911696c5eSBiju Das 		pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
27011696c5eSBiju Das }
27111696c5eSBiju Das 
rcar_lvds_pll_setup_d3_e3(struct rcar_lvds * lvds,unsigned int freq,bool dot_clock_only)27211696c5eSBiju Das static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds,
27311696c5eSBiju Das 				      unsigned int freq, bool dot_clock_only)
27411696c5eSBiju Das {
27511696c5eSBiju Das 	struct pll_info pll = { .diff = (unsigned long)-1 };
27611696c5eSBiju Das 	u32 lvdpllcr;
27711696c5eSBiju Das 
27811696c5eSBiju Das 	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
27911696c5eSBiju Das 				 LVDPLLCR_CKSEL_DU_DOTCLKIN(0), dot_clock_only);
28011696c5eSBiju Das 	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
28111696c5eSBiju Das 				 LVDPLLCR_CKSEL_DU_DOTCLKIN(1), dot_clock_only);
28211696c5eSBiju Das 	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
28311696c5eSBiju Das 				 LVDPLLCR_CKSEL_EXTAL, dot_clock_only);
28411696c5eSBiju Das 
28511696c5eSBiju Das 	lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
28611696c5eSBiju Das 		 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);
28711696c5eSBiju Das 
28811696c5eSBiju Das 	if (pll.pll_e > 0)
28911696c5eSBiju Das 		lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
29011696c5eSBiju Das 			 |  LVDPLLCR_PLLE(pll.pll_e - 1);
29111696c5eSBiju Das 
29211696c5eSBiju Das 	if (dot_clock_only)
29311696c5eSBiju Das 		lvdpllcr |= LVDPLLCR_OCKSEL;
29411696c5eSBiju Das 
29511696c5eSBiju Das 	rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
29611696c5eSBiju Das 
29711696c5eSBiju Das 	if (pll.div > 1)
29811696c5eSBiju Das 		/*
29911696c5eSBiju Das 		 * The DIVRESET bit is a misnomer, setting it to 1 deasserts the
30011696c5eSBiju Das 		 * divisor reset.
30111696c5eSBiju Das 		 */
30211696c5eSBiju Das 		rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL |
30311696c5eSBiju Das 				LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1));
30411696c5eSBiju Das 	else
30511696c5eSBiju Das 		rcar_lvds_write(lvds, LVDDIV, 0);
30611696c5eSBiju Das }
30711696c5eSBiju Das 
30811696c5eSBiju Das /* -----------------------------------------------------------------------------
30911696c5eSBiju Das  * Enable/disable
31011696c5eSBiju Das  */
31111696c5eSBiju Das 
rcar_lvds_get_lvds_mode(struct rcar_lvds * lvds,const struct drm_connector * connector)31211696c5eSBiju Das static enum rcar_lvds_mode rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds,
31311696c5eSBiju Das 					const struct drm_connector *connector)
31411696c5eSBiju Das {
31511696c5eSBiju Das 	const struct drm_display_info *info;
31611696c5eSBiju Das 	enum rcar_lvds_mode mode;
31711696c5eSBiju Das 
31811696c5eSBiju Das 	/*
31911696c5eSBiju Das 	 * There is no API yet to retrieve LVDS mode from a bridge, only panels
32011696c5eSBiju Das 	 * are supported.
32111696c5eSBiju Das 	 */
32211696c5eSBiju Das 	if (!lvds->panel)
32311696c5eSBiju Das 		return RCAR_LVDS_MODE_JEIDA;
32411696c5eSBiju Das 
32511696c5eSBiju Das 	info = &connector->display_info;
32611696c5eSBiju Das 	if (!info->num_bus_formats || !info->bus_formats) {
32711696c5eSBiju Das 		dev_warn(lvds->dev,
32811696c5eSBiju Das 			 "no LVDS bus format reported, using JEIDA\n");
32911696c5eSBiju Das 		return RCAR_LVDS_MODE_JEIDA;
33011696c5eSBiju Das 	}
33111696c5eSBiju Das 
33211696c5eSBiju Das 	switch (info->bus_formats[0]) {
33311696c5eSBiju Das 	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
33411696c5eSBiju Das 	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
33511696c5eSBiju Das 		mode = RCAR_LVDS_MODE_JEIDA;
33611696c5eSBiju Das 		break;
33711696c5eSBiju Das 	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
33811696c5eSBiju Das 		mode = RCAR_LVDS_MODE_VESA;
33911696c5eSBiju Das 		break;
34011696c5eSBiju Das 	default:
34111696c5eSBiju Das 		dev_warn(lvds->dev,
34211696c5eSBiju Das 			 "unsupported LVDS bus format 0x%04x, using JEIDA\n",
34311696c5eSBiju Das 			 info->bus_formats[0]);
34411696c5eSBiju Das 		return RCAR_LVDS_MODE_JEIDA;
34511696c5eSBiju Das 	}
34611696c5eSBiju Das 
34711696c5eSBiju Das 	if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
34811696c5eSBiju Das 		mode |= RCAR_LVDS_MODE_MIRROR;
34911696c5eSBiju Das 
35011696c5eSBiju Das 	return mode;
35111696c5eSBiju Das }
35211696c5eSBiju Das 
rcar_lvds_enable(struct drm_bridge * bridge,struct drm_atomic_state * state,struct drm_crtc * crtc,struct drm_connector * connector)35311696c5eSBiju Das static void rcar_lvds_enable(struct drm_bridge *bridge,
35411696c5eSBiju Das 			     struct drm_atomic_state *state,
35511696c5eSBiju Das 			     struct drm_crtc *crtc,
35611696c5eSBiju Das 			     struct drm_connector *connector)
35711696c5eSBiju Das {
35811696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
35911696c5eSBiju Das 	u32 lvdhcr;
36011696c5eSBiju Das 	u32 lvdcr0;
36111696c5eSBiju Das 	int ret;
36211696c5eSBiju Das 
36311696c5eSBiju Das 	ret = pm_runtime_resume_and_get(lvds->dev);
36411696c5eSBiju Das 	if (ret)
36511696c5eSBiju Das 		return;
36611696c5eSBiju Das 
36711696c5eSBiju Das 	/* Enable the companion LVDS encoder in dual-link mode. */
36811696c5eSBiju Das 	if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
36911696c5eSBiju Das 		rcar_lvds_enable(lvds->companion, state, crtc, connector);
37011696c5eSBiju Das 
37111696c5eSBiju Das 	/*
37211696c5eSBiju Das 	 * Hardcode the channels and control signals routing for now.
37311696c5eSBiju Das 	 *
37411696c5eSBiju Das 	 * HSYNC -> CTRL0
37511696c5eSBiju Das 	 * VSYNC -> CTRL1
37611696c5eSBiju Das 	 * DISP  -> CTRL2
37711696c5eSBiju Das 	 * 0     -> CTRL3
37811696c5eSBiju Das 	 */
37911696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
38011696c5eSBiju Das 			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
38111696c5eSBiju Das 			LVDCTRCR_CTR0SEL_HSYNC);
38211696c5eSBiju Das 
38311696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES)
38411696c5eSBiju Das 		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
38511696c5eSBiju Das 		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
38611696c5eSBiju Das 	else
38711696c5eSBiju Das 		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
38811696c5eSBiju Das 		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
38911696c5eSBiju Das 
39011696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
39111696c5eSBiju Das 
39211696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) {
39311696c5eSBiju Das 		u32 lvdstripe = 0;
39411696c5eSBiju Das 
39511696c5eSBiju Das 		if (lvds->link_type != RCAR_LVDS_SINGLE_LINK) {
39611696c5eSBiju Das 			/*
39711696c5eSBiju Das 			 * By default we generate even pixels from the primary
39811696c5eSBiju Das 			 * encoder and odd pixels from the companion encoder.
39911696c5eSBiju Das 			 * Swap pixels around if the sink requires odd pixels
40011696c5eSBiju Das 			 * from the primary encoder and even pixels from the
40111696c5eSBiju Das 			 * companion encoder.
40211696c5eSBiju Das 			 */
40311696c5eSBiju Das 			bool swap_pixels = lvds->link_type ==
40411696c5eSBiju Das 				RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
40511696c5eSBiju Das 
40611696c5eSBiju Das 			/*
40711696c5eSBiju Das 			 * Configure vertical stripe since we are dealing with
40811696c5eSBiju Das 			 * an LVDS dual-link connection.
40911696c5eSBiju Das 			 *
41011696c5eSBiju Das 			 * ST_SWAP is reserved for the companion encoder, only
41111696c5eSBiju Das 			 * set it in the primary encoder.
41211696c5eSBiju Das 			 */
41311696c5eSBiju Das 			lvdstripe = LVDSTRIPE_ST_ON
41411696c5eSBiju Das 				  | (lvds->companion && swap_pixels ?
41511696c5eSBiju Das 				     LVDSTRIPE_ST_SWAP : 0);
41611696c5eSBiju Das 		}
41711696c5eSBiju Das 		rcar_lvds_write(lvds, LVDSTRIPE, lvdstripe);
41811696c5eSBiju Das 	}
41911696c5eSBiju Das 
42011696c5eSBiju Das 	/*
42111696c5eSBiju Das 	 * PLL clock configuration on all instances but the companion in
42211696c5eSBiju Das 	 * dual-link mode.
42311696c5eSBiju Das 	 *
42411696c5eSBiju Das 	 * The extended PLL has been turned on by an explicit call to
42511696c5eSBiju Das 	 * rcar_lvds_pclk_enable() from the DU driver.
42611696c5eSBiju Das 	 */
42711696c5eSBiju Das 	if ((lvds->link_type == RCAR_LVDS_SINGLE_LINK || lvds->companion) &&
42811696c5eSBiju Das 	    !(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
42911696c5eSBiju Das 		const struct drm_crtc_state *crtc_state =
43011696c5eSBiju Das 			drm_atomic_get_new_crtc_state(state, crtc);
43111696c5eSBiju Das 		const struct drm_display_mode *mode =
43211696c5eSBiju Das 			&crtc_state->adjusted_mode;
43311696c5eSBiju Das 
43411696c5eSBiju Das 		lvds->info->pll_setup(lvds, mode->clock * 1000);
43511696c5eSBiju Das 	}
43611696c5eSBiju Das 
43711696c5eSBiju Das 	/* Set the LVDS mode and select the input. */
43811696c5eSBiju Das 	lvdcr0 = rcar_lvds_get_lvds_mode(lvds, connector) << LVDCR0_LVMD_SHIFT;
43911696c5eSBiju Das 
44011696c5eSBiju Das 	if (lvds->bridge.encoder) {
44111696c5eSBiju Das 		if (drm_crtc_index(crtc) == 2)
44211696c5eSBiju Das 			lvdcr0 |= LVDCR0_DUSEL;
44311696c5eSBiju Das 	}
44411696c5eSBiju Das 
44511696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
44611696c5eSBiju Das 
44711696c5eSBiju Das 	/* Turn all the channels on. */
44811696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR1,
44911696c5eSBiju Das 			LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
45011696c5eSBiju Das 			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
45111696c5eSBiju Das 
45211696c5eSBiju Das 	if (lvds->info->gen < 3) {
45311696c5eSBiju Das 		/* Enable LVDS operation and turn the bias circuitry on. */
45411696c5eSBiju Das 		lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN;
45511696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
45611696c5eSBiju Das 	}
45711696c5eSBiju Das 
45811696c5eSBiju Das 	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
45911696c5eSBiju Das 		/*
46011696c5eSBiju Das 		 * Turn the PLL on (simple PLL only, extended PLL is fully
46111696c5eSBiju Das 		 * controlled through LVDPLLCR).
46211696c5eSBiju Das 		 */
46311696c5eSBiju Das 		lvdcr0 |= LVDCR0_PLLON;
46411696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
46511696c5eSBiju Das 	}
46611696c5eSBiju Das 
46711696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
46811696c5eSBiju Das 		/* Set LVDS normal mode. */
46911696c5eSBiju Das 		lvdcr0 |= LVDCR0_PWD;
47011696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
47111696c5eSBiju Das 	}
47211696c5eSBiju Das 
47311696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
47411696c5eSBiju Das 		/*
47511696c5eSBiju Das 		 * Turn on the LVDS PHY. On D3, the LVEN and LVRES bit must be
47611696c5eSBiju Das 		 * set at the same time, so don't write the register yet.
47711696c5eSBiju Das 		 */
47811696c5eSBiju Das 		lvdcr0 |= LVDCR0_LVEN;
47911696c5eSBiju Das 		if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_PWD))
48011696c5eSBiju Das 			rcar_lvds_write(lvds, LVDCR0, lvdcr0);
48111696c5eSBiju Das 	}
48211696c5eSBiju Das 
48311696c5eSBiju Das 	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
48411696c5eSBiju Das 		/* Wait for the PLL startup delay (simple PLL only). */
48511696c5eSBiju Das 		usleep_range(100, 150);
48611696c5eSBiju Das 	}
48711696c5eSBiju Das 
48811696c5eSBiju Das 	/* Turn the output on. */
48911696c5eSBiju Das 	lvdcr0 |= LVDCR0_LVRES;
49011696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
49111696c5eSBiju Das }
49211696c5eSBiju Das 
rcar_lvds_disable(struct drm_bridge * bridge)49311696c5eSBiju Das static void rcar_lvds_disable(struct drm_bridge *bridge)
49411696c5eSBiju Das {
49511696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
49611696c5eSBiju Das 	u32 lvdcr0;
49711696c5eSBiju Das 
49811696c5eSBiju Das 	/*
49911696c5eSBiju Das 	 * Clear the LVDCR0 bits in the order specified by the hardware
50011696c5eSBiju Das 	 * documentation, ending with a write of 0 to the full register to
50111696c5eSBiju Das 	 * clear all remaining bits.
50211696c5eSBiju Das 	 */
50311696c5eSBiju Das 	lvdcr0 = rcar_lvds_read(lvds, LVDCR0);
50411696c5eSBiju Das 
50511696c5eSBiju Das 	lvdcr0 &= ~LVDCR0_LVRES;
50611696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
50711696c5eSBiju Das 
50811696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
50911696c5eSBiju Das 		lvdcr0 &= ~LVDCR0_LVEN;
51011696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
51111696c5eSBiju Das 	}
51211696c5eSBiju Das 
51311696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
51411696c5eSBiju Das 		lvdcr0 &= ~LVDCR0_PWD;
51511696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
51611696c5eSBiju Das 	}
51711696c5eSBiju Das 
51811696c5eSBiju Das 	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
51911696c5eSBiju Das 		lvdcr0 &= ~LVDCR0_PLLON;
52011696c5eSBiju Das 		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
52111696c5eSBiju Das 	}
52211696c5eSBiju Das 
52311696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR0, 0);
52411696c5eSBiju Das 	rcar_lvds_write(lvds, LVDCR1, 0);
52511696c5eSBiju Das 
52611696c5eSBiju Das 	/* The extended PLL is turned off in rcar_lvds_pclk_disable(). */
52711696c5eSBiju Das 	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))
52811696c5eSBiju Das 		rcar_lvds_write(lvds, LVDPLLCR, 0);
52911696c5eSBiju Das 
53011696c5eSBiju Das 	/* Disable the companion LVDS encoder in dual-link mode. */
53111696c5eSBiju Das 	if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
53211696c5eSBiju Das 		rcar_lvds_disable(lvds->companion);
53311696c5eSBiju Das 
53411696c5eSBiju Das 	pm_runtime_put_sync(lvds->dev);
53511696c5eSBiju Das }
53611696c5eSBiju Das 
53711696c5eSBiju Das /* -----------------------------------------------------------------------------
53811696c5eSBiju Das  * Clock - D3/E3 only
53911696c5eSBiju Das  */
54011696c5eSBiju Das 
rcar_lvds_pclk_enable(struct drm_bridge * bridge,unsigned long freq,bool dot_clk_only)54111696c5eSBiju Das int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq,
54211696c5eSBiju Das 			  bool dot_clk_only)
54311696c5eSBiju Das {
54411696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
54511696c5eSBiju Das 	int ret;
54611696c5eSBiju Das 
54711696c5eSBiju Das 	if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
54811696c5eSBiju Das 		return -ENODEV;
54911696c5eSBiju Das 
55011696c5eSBiju Das 	dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
55111696c5eSBiju Das 
55211696c5eSBiju Das 	ret = pm_runtime_resume_and_get(lvds->dev);
55311696c5eSBiju Das 	if (ret)
55411696c5eSBiju Das 		return ret;
55511696c5eSBiju Das 
55611696c5eSBiju Das 	rcar_lvds_pll_setup_d3_e3(lvds, freq, dot_clk_only);
55711696c5eSBiju Das 
55811696c5eSBiju Das 	return 0;
55911696c5eSBiju Das }
56011696c5eSBiju Das EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable);
56111696c5eSBiju Das 
rcar_lvds_pclk_disable(struct drm_bridge * bridge,bool dot_clk_only)56211696c5eSBiju Das void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only)
56311696c5eSBiju Das {
56411696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
56511696c5eSBiju Das 
56611696c5eSBiju Das 	if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
56711696c5eSBiju Das 		return;
56811696c5eSBiju Das 
56911696c5eSBiju Das 	dev_dbg(lvds->dev, "disabling LVDS PLL\n");
57011696c5eSBiju Das 
57111696c5eSBiju Das 	if (!dot_clk_only)
57211696c5eSBiju Das 		rcar_lvds_disable(bridge);
57311696c5eSBiju Das 
57411696c5eSBiju Das 	rcar_lvds_write(lvds, LVDPLLCR, 0);
57511696c5eSBiju Das 
57611696c5eSBiju Das 	pm_runtime_put_sync(lvds->dev);
57711696c5eSBiju Das }
57811696c5eSBiju Das EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable);
57911696c5eSBiju Das 
58011696c5eSBiju Das /* -----------------------------------------------------------------------------
58111696c5eSBiju Das  * Bridge
58211696c5eSBiju Das  */
58311696c5eSBiju Das 
rcar_lvds_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)58411696c5eSBiju Das static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
58511696c5eSBiju Das 				    struct drm_bridge_state *old_bridge_state)
58611696c5eSBiju Das {
58711696c5eSBiju Das 	struct drm_atomic_state *state = old_bridge_state->base.state;
58811696c5eSBiju Das 	struct drm_connector *connector;
58911696c5eSBiju Das 	struct drm_crtc *crtc;
59011696c5eSBiju Das 
59111696c5eSBiju Das 	connector = drm_atomic_get_new_connector_for_encoder(state,
59211696c5eSBiju Das 							     bridge->encoder);
59311696c5eSBiju Das 	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
59411696c5eSBiju Das 
59511696c5eSBiju Das 	rcar_lvds_enable(bridge, state, crtc, connector);
59611696c5eSBiju Das }
59711696c5eSBiju Das 
rcar_lvds_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)59811696c5eSBiju Das static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
59911696c5eSBiju Das 				     struct drm_bridge_state *old_bridge_state)
60011696c5eSBiju Das {
60111696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
60211696c5eSBiju Das 
60311696c5eSBiju Das 	/*
60411696c5eSBiju Das 	 * For D3 and E3, disabling the LVDS encoder before the DU would stall
60511696c5eSBiju Das 	 * the DU, causing a vblank wait timeout when stopping the DU. This has
60611696c5eSBiju Das 	 * been traced to clearing the LVEN bit, but the exact reason is
60711696c5eSBiju Das 	 * unknown. Keep the encoder enabled, it will be disabled by an explicit
60811696c5eSBiju Das 	 * call to rcar_lvds_pclk_disable() from the DU driver.
60911696c5eSBiju Das 	 *
61011696c5eSBiju Das 	 * We could clear the LVRES bit already to disable the LVDS output, but
61111696c5eSBiju Das 	 * that's likely pointless.
61211696c5eSBiju Das 	 */
61311696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)
61411696c5eSBiju Das 		return;
61511696c5eSBiju Das 
61611696c5eSBiju Das 	rcar_lvds_disable(bridge);
61711696c5eSBiju Das }
61811696c5eSBiju Das 
rcar_lvds_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)61911696c5eSBiju Das static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
62011696c5eSBiju Das 				 const struct drm_display_mode *mode,
62111696c5eSBiju Das 				 struct drm_display_mode *adjusted_mode)
62211696c5eSBiju Das {
62311696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
62411696c5eSBiju Das 	int min_freq;
62511696c5eSBiju Das 
62611696c5eSBiju Das 	/*
62711696c5eSBiju Das 	 * The internal LVDS encoder has a restricted clock frequency operating
62811696c5eSBiju Das 	 * range, from 5MHz to 148.5MHz on D3 and E3, and from 31MHz to
62911696c5eSBiju Das 	 * 148.5MHz on all other platforms. Clamp the clock accordingly.
63011696c5eSBiju Das 	 */
63111696c5eSBiju Das 	min_freq = lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL ? 5000 : 31000;
63211696c5eSBiju Das 	adjusted_mode->clock = clamp(adjusted_mode->clock, min_freq, 148500);
63311696c5eSBiju Das 
63411696c5eSBiju Das 	return true;
63511696c5eSBiju Das }
63611696c5eSBiju Das 
rcar_lvds_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)63711696c5eSBiju Das static int rcar_lvds_attach(struct drm_bridge *bridge,
63811696c5eSBiju Das 			    enum drm_bridge_attach_flags flags)
63911696c5eSBiju Das {
64011696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
64111696c5eSBiju Das 
64211696c5eSBiju Das 	if (!lvds->next_bridge)
64311696c5eSBiju Das 		return 0;
64411696c5eSBiju Das 
64511696c5eSBiju Das 	return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge,
64611696c5eSBiju Das 				 flags);
64711696c5eSBiju Das }
64811696c5eSBiju Das 
64911696c5eSBiju Das static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
65011696c5eSBiju Das 	.attach = rcar_lvds_attach,
65111696c5eSBiju Das 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
65211696c5eSBiju Das 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
65311696c5eSBiju Das 	.atomic_reset = drm_atomic_helper_bridge_reset,
65411696c5eSBiju Das 	.atomic_enable = rcar_lvds_atomic_enable,
65511696c5eSBiju Das 	.atomic_disable = rcar_lvds_atomic_disable,
65611696c5eSBiju Das 	.mode_fixup = rcar_lvds_mode_fixup,
65711696c5eSBiju Das };
65811696c5eSBiju Das 
rcar_lvds_dual_link(struct drm_bridge * bridge)65911696c5eSBiju Das bool rcar_lvds_dual_link(struct drm_bridge *bridge)
66011696c5eSBiju Das {
66111696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
66211696c5eSBiju Das 
66311696c5eSBiju Das 	return lvds->link_type != RCAR_LVDS_SINGLE_LINK;
66411696c5eSBiju Das }
66511696c5eSBiju Das EXPORT_SYMBOL_GPL(rcar_lvds_dual_link);
66611696c5eSBiju Das 
rcar_lvds_is_connected(struct drm_bridge * bridge)66711696c5eSBiju Das bool rcar_lvds_is_connected(struct drm_bridge *bridge)
66811696c5eSBiju Das {
66911696c5eSBiju Das 	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
67011696c5eSBiju Das 
67111696c5eSBiju Das 	return lvds->next_bridge != NULL;
67211696c5eSBiju Das }
67311696c5eSBiju Das EXPORT_SYMBOL_GPL(rcar_lvds_is_connected);
67411696c5eSBiju Das 
67511696c5eSBiju Das /* -----------------------------------------------------------------------------
67611696c5eSBiju Das  * Probe & Remove
67711696c5eSBiju Das  */
67811696c5eSBiju Das 
rcar_lvds_parse_dt_companion(struct rcar_lvds * lvds)67911696c5eSBiju Das static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds)
68011696c5eSBiju Das {
68111696c5eSBiju Das 	const struct of_device_id *match;
68211696c5eSBiju Das 	struct device_node *companion;
68311696c5eSBiju Das 	struct device_node *port0, *port1;
68411696c5eSBiju Das 	struct rcar_lvds *companion_lvds;
68511696c5eSBiju Das 	struct device *dev = lvds->dev;
68611696c5eSBiju Das 	int dual_link;
68711696c5eSBiju Das 	int ret = 0;
68811696c5eSBiju Das 
68911696c5eSBiju Das 	/* Locate the companion LVDS encoder for dual-link operation, if any. */
69011696c5eSBiju Das 	companion = of_parse_phandle(dev->of_node, "renesas,companion", 0);
69111696c5eSBiju Das 	if (!companion)
69211696c5eSBiju Das 		return 0;
69311696c5eSBiju Das 
69411696c5eSBiju Das 	/*
69511696c5eSBiju Das 	 * Sanity check: the companion encoder must have the same compatible
69611696c5eSBiju Das 	 * string.
69711696c5eSBiju Das 	 */
69811696c5eSBiju Das 	match = of_match_device(dev->driver->of_match_table, dev);
69911696c5eSBiju Das 	if (!of_device_is_compatible(companion, match->compatible)) {
70011696c5eSBiju Das 		dev_err(dev, "Companion LVDS encoder is invalid\n");
70111696c5eSBiju Das 		ret = -ENXIO;
70211696c5eSBiju Das 		goto done;
70311696c5eSBiju Das 	}
70411696c5eSBiju Das 
70511696c5eSBiju Das 	/*
70611696c5eSBiju Das 	 * We need to work out if the sink is expecting us to function in
70711696c5eSBiju Das 	 * dual-link mode. We do this by looking at the DT port nodes we are
70811696c5eSBiju Das 	 * connected to, if they are marked as expecting even pixels and
70911696c5eSBiju Das 	 * odd pixels than we need to enable vertical stripe output.
71011696c5eSBiju Das 	 */
71111696c5eSBiju Das 	port0 = of_graph_get_port_by_id(dev->of_node, 1);
71211696c5eSBiju Das 	port1 = of_graph_get_port_by_id(companion, 1);
71311696c5eSBiju Das 	dual_link = drm_of_lvds_get_dual_link_pixel_order(port0, port1);
71411696c5eSBiju Das 	of_node_put(port0);
71511696c5eSBiju Das 	of_node_put(port1);
71611696c5eSBiju Das 
71711696c5eSBiju Das 	switch (dual_link) {
71811696c5eSBiju Das 	case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
71911696c5eSBiju Das 		lvds->link_type = RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
72011696c5eSBiju Das 		break;
72111696c5eSBiju Das 	case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
72211696c5eSBiju Das 		lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
72311696c5eSBiju Das 		break;
72411696c5eSBiju Das 	default:
72511696c5eSBiju Das 		/*
72611696c5eSBiju Das 		 * Early dual-link bridge specific implementations populate the
72711696c5eSBiju Das 		 * timings field of drm_bridge. If the flag is set, we assume
72811696c5eSBiju Das 		 * that we are expected to generate even pixels from the primary
72911696c5eSBiju Das 		 * encoder, and odd pixels from the companion encoder.
73011696c5eSBiju Das 		 */
73111696c5eSBiju Das 		if (lvds->next_bridge->timings &&
73211696c5eSBiju Das 		    lvds->next_bridge->timings->dual_link)
73311696c5eSBiju Das 			lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
73411696c5eSBiju Das 		else
73511696c5eSBiju Das 			lvds->link_type = RCAR_LVDS_SINGLE_LINK;
73611696c5eSBiju Das 	}
73711696c5eSBiju Das 
73811696c5eSBiju Das 	if (lvds->link_type == RCAR_LVDS_SINGLE_LINK) {
73911696c5eSBiju Das 		dev_dbg(dev, "Single-link configuration detected\n");
74011696c5eSBiju Das 		goto done;
74111696c5eSBiju Das 	}
74211696c5eSBiju Das 
74311696c5eSBiju Das 	lvds->companion = of_drm_find_bridge(companion);
74411696c5eSBiju Das 	if (!lvds->companion) {
74511696c5eSBiju Das 		ret = -EPROBE_DEFER;
74611696c5eSBiju Das 		goto done;
74711696c5eSBiju Das 	}
74811696c5eSBiju Das 
74911696c5eSBiju Das 	dev_dbg(dev,
75011696c5eSBiju Das 		"Dual-link configuration detected (companion encoder %pOF)\n",
75111696c5eSBiju Das 		companion);
75211696c5eSBiju Das 
75311696c5eSBiju Das 	if (lvds->link_type == RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
75411696c5eSBiju Das 		dev_dbg(dev, "Data swapping required\n");
75511696c5eSBiju Das 
75611696c5eSBiju Das 	/*
75711696c5eSBiju Das 	 * FIXME: We should not be messing with the companion encoder private
75811696c5eSBiju Das 	 * data from the primary encoder, we should rather let the companion
75911696c5eSBiju Das 	 * encoder work things out on its own. However, the companion encoder
76011696c5eSBiju Das 	 * doesn't hold a reference to the primary encoder, and
76111696c5eSBiju Das 	 * drm_of_lvds_get_dual_link_pixel_order needs to be given references
76211696c5eSBiju Das 	 * to the output ports of both encoders, therefore leave it like this
76311696c5eSBiju Das 	 * for the time being.
76411696c5eSBiju Das 	 */
76511696c5eSBiju Das 	companion_lvds = bridge_to_rcar_lvds(lvds->companion);
76611696c5eSBiju Das 	companion_lvds->link_type = lvds->link_type;
76711696c5eSBiju Das 
76811696c5eSBiju Das done:
76911696c5eSBiju Das 	of_node_put(companion);
77011696c5eSBiju Das 
77111696c5eSBiju Das 	return ret;
77211696c5eSBiju Das }
77311696c5eSBiju Das 
rcar_lvds_parse_dt(struct rcar_lvds * lvds)77411696c5eSBiju Das static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
77511696c5eSBiju Das {
77611696c5eSBiju Das 	int ret;
77711696c5eSBiju Das 
77811696c5eSBiju Das 	ret = drm_of_find_panel_or_bridge(lvds->dev->of_node, 1, 0,
77911696c5eSBiju Das 					  &lvds->panel, &lvds->next_bridge);
78011696c5eSBiju Das 	if (ret)
78111696c5eSBiju Das 		goto done;
78211696c5eSBiju Das 
78311696c5eSBiju Das 	if (lvds->panel) {
78411696c5eSBiju Das 		lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev,
78511696c5eSBiju Das 							      lvds->panel);
78611696c5eSBiju Das 		if (IS_ERR_OR_NULL(lvds->next_bridge)) {
78711696c5eSBiju Das 			ret = -EINVAL;
78811696c5eSBiju Das 			goto done;
78911696c5eSBiju Das 		}
79011696c5eSBiju Das 	}
79111696c5eSBiju Das 
79211696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK)
79311696c5eSBiju Das 		ret = rcar_lvds_parse_dt_companion(lvds);
79411696c5eSBiju Das 
79511696c5eSBiju Das done:
79611696c5eSBiju Das 	/*
79711696c5eSBiju Das 	 * On D3/E3 the LVDS encoder provides a clock to the DU, which can be
79811696c5eSBiju Das 	 * used for the DPAD output even when the LVDS output is not connected.
79911696c5eSBiju Das 	 * Don't fail probe in that case as the DU will need the bridge to
80011696c5eSBiju Das 	 * control the clock.
80111696c5eSBiju Das 	 */
80211696c5eSBiju Das 	if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)
80311696c5eSBiju Das 		return ret == -ENODEV ? 0 : ret;
80411696c5eSBiju Das 
80511696c5eSBiju Das 	return ret;
80611696c5eSBiju Das }
80711696c5eSBiju Das 
rcar_lvds_get_clock(struct rcar_lvds * lvds,const char * name,bool optional)80811696c5eSBiju Das static struct clk *rcar_lvds_get_clock(struct rcar_lvds *lvds, const char *name,
80911696c5eSBiju Das 				       bool optional)
81011696c5eSBiju Das {
81111696c5eSBiju Das 	struct clk *clk;
81211696c5eSBiju Das 
81311696c5eSBiju Das 	clk = devm_clk_get(lvds->dev, name);
81411696c5eSBiju Das 	if (!IS_ERR(clk))
81511696c5eSBiju Das 		return clk;
81611696c5eSBiju Das 
81711696c5eSBiju Das 	if (PTR_ERR(clk) == -ENOENT && optional)
81811696c5eSBiju Das 		return NULL;
81911696c5eSBiju Das 
82011696c5eSBiju Das 	dev_err_probe(lvds->dev, PTR_ERR(clk), "failed to get %s clock\n",
82111696c5eSBiju Das 		      name ? name : "module");
82211696c5eSBiju Das 
82311696c5eSBiju Das 	return clk;
82411696c5eSBiju Das }
82511696c5eSBiju Das 
rcar_lvds_get_clocks(struct rcar_lvds * lvds)82611696c5eSBiju Das static int rcar_lvds_get_clocks(struct rcar_lvds *lvds)
82711696c5eSBiju Das {
82811696c5eSBiju Das 	lvds->clocks.mod = rcar_lvds_get_clock(lvds, NULL, false);
82911696c5eSBiju Das 	if (IS_ERR(lvds->clocks.mod))
83011696c5eSBiju Das 		return PTR_ERR(lvds->clocks.mod);
83111696c5eSBiju Das 
83211696c5eSBiju Das 	/*
83311696c5eSBiju Das 	 * LVDS encoders without an extended PLL have no external clock inputs.
83411696c5eSBiju Das 	 */
83511696c5eSBiju Das 	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))
83611696c5eSBiju Das 		return 0;
83711696c5eSBiju Das 
83811696c5eSBiju Das 	lvds->clocks.extal = rcar_lvds_get_clock(lvds, "extal", true);
83911696c5eSBiju Das 	if (IS_ERR(lvds->clocks.extal))
84011696c5eSBiju Das 		return PTR_ERR(lvds->clocks.extal);
84111696c5eSBiju Das 
84211696c5eSBiju Das 	lvds->clocks.dotclkin[0] = rcar_lvds_get_clock(lvds, "dclkin.0", true);
84311696c5eSBiju Das 	if (IS_ERR(lvds->clocks.dotclkin[0]))
84411696c5eSBiju Das 		return PTR_ERR(lvds->clocks.dotclkin[0]);
84511696c5eSBiju Das 
84611696c5eSBiju Das 	lvds->clocks.dotclkin[1] = rcar_lvds_get_clock(lvds, "dclkin.1", true);
84711696c5eSBiju Das 	if (IS_ERR(lvds->clocks.dotclkin[1]))
84811696c5eSBiju Das 		return PTR_ERR(lvds->clocks.dotclkin[1]);
84911696c5eSBiju Das 
85011696c5eSBiju Das 	/* At least one input to the PLL must be available. */
85111696c5eSBiju Das 	if (!lvds->clocks.extal && !lvds->clocks.dotclkin[0] &&
85211696c5eSBiju Das 	    !lvds->clocks.dotclkin[1]) {
85311696c5eSBiju Das 		dev_err(lvds->dev,
85411696c5eSBiju Das 			"no input clock (extal, dclkin.0 or dclkin.1)\n");
85511696c5eSBiju Das 		return -EINVAL;
85611696c5eSBiju Das 	}
85711696c5eSBiju Das 
85811696c5eSBiju Das 	return 0;
85911696c5eSBiju Das }
86011696c5eSBiju Das 
86111696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_r8a7790es1_info = {
86211696c5eSBiju Das 	.gen = 2,
86311696c5eSBiju Das 	.quirks = RCAR_LVDS_QUIRK_LANES,
86411696c5eSBiju Das 	.pll_setup = rcar_lvds_pll_setup_gen2,
86511696c5eSBiju Das };
86611696c5eSBiju Das 
86711696c5eSBiju Das static const struct soc_device_attribute lvds_quirk_matches[] = {
86811696c5eSBiju Das 	{
86911696c5eSBiju Das 		.soc_id = "r8a7790", .revision = "ES1.*",
87011696c5eSBiju Das 		.data = &rcar_lvds_r8a7790es1_info,
87111696c5eSBiju Das 	},
87211696c5eSBiju Das 	{ /* sentinel */ }
87311696c5eSBiju Das };
87411696c5eSBiju Das 
rcar_lvds_probe(struct platform_device * pdev)87511696c5eSBiju Das static int rcar_lvds_probe(struct platform_device *pdev)
87611696c5eSBiju Das {
87711696c5eSBiju Das 	const struct soc_device_attribute *attr;
87811696c5eSBiju Das 	struct rcar_lvds *lvds;
87911696c5eSBiju Das 	int ret;
88011696c5eSBiju Das 
88111696c5eSBiju Das 	lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
88211696c5eSBiju Das 	if (lvds == NULL)
88311696c5eSBiju Das 		return -ENOMEM;
88411696c5eSBiju Das 
88511696c5eSBiju Das 	platform_set_drvdata(pdev, lvds);
88611696c5eSBiju Das 
88711696c5eSBiju Das 	lvds->dev = &pdev->dev;
88811696c5eSBiju Das 	lvds->info = of_device_get_match_data(&pdev->dev);
88911696c5eSBiju Das 
89011696c5eSBiju Das 	attr = soc_device_match(lvds_quirk_matches);
89111696c5eSBiju Das 	if (attr)
89211696c5eSBiju Das 		lvds->info = attr->data;
89311696c5eSBiju Das 
89411696c5eSBiju Das 	ret = rcar_lvds_parse_dt(lvds);
89511696c5eSBiju Das 	if (ret < 0)
89611696c5eSBiju Das 		return ret;
89711696c5eSBiju Das 
89811696c5eSBiju Das 	lvds->bridge.funcs = &rcar_lvds_bridge_ops;
89911696c5eSBiju Das 	lvds->bridge.of_node = pdev->dev.of_node;
90011696c5eSBiju Das 
90111696c5eSBiju Das 	lvds->mmio = devm_platform_ioremap_resource(pdev, 0);
90211696c5eSBiju Das 	if (IS_ERR(lvds->mmio))
90311696c5eSBiju Das 		return PTR_ERR(lvds->mmio);
90411696c5eSBiju Das 
90511696c5eSBiju Das 	ret = rcar_lvds_get_clocks(lvds);
90611696c5eSBiju Das 	if (ret < 0)
90711696c5eSBiju Das 		return ret;
90811696c5eSBiju Das 
90911696c5eSBiju Das 	lvds->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
91011696c5eSBiju Das 	if (IS_ERR(lvds->rstc))
91111696c5eSBiju Das 		return dev_err_probe(&pdev->dev, PTR_ERR(lvds->rstc),
91211696c5eSBiju Das 				     "failed to get cpg reset\n");
91311696c5eSBiju Das 
91411696c5eSBiju Das 	pm_runtime_enable(&pdev->dev);
91511696c5eSBiju Das 
91611696c5eSBiju Das 	drm_bridge_add(&lvds->bridge);
91711696c5eSBiju Das 
91811696c5eSBiju Das 	return 0;
91911696c5eSBiju Das }
92011696c5eSBiju Das 
rcar_lvds_remove(struct platform_device * pdev)921*de8a334fSThomas Zimmermann static void rcar_lvds_remove(struct platform_device *pdev)
92211696c5eSBiju Das {
92311696c5eSBiju Das 	struct rcar_lvds *lvds = platform_get_drvdata(pdev);
92411696c5eSBiju Das 
92511696c5eSBiju Das 	drm_bridge_remove(&lvds->bridge);
92611696c5eSBiju Das 
92711696c5eSBiju Das 	pm_runtime_disable(&pdev->dev);
92811696c5eSBiju Das }
92911696c5eSBiju Das 
93011696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
93111696c5eSBiju Das 	.gen = 2,
93211696c5eSBiju Das 	.pll_setup = rcar_lvds_pll_setup_gen2,
93311696c5eSBiju Das };
93411696c5eSBiju Das 
93511696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
93611696c5eSBiju Das 	.gen = 3,
93711696c5eSBiju Das 	.quirks = RCAR_LVDS_QUIRK_PWD,
93811696c5eSBiju Das 	.pll_setup = rcar_lvds_pll_setup_gen3,
93911696c5eSBiju Das };
94011696c5eSBiju Das 
94111696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = {
94211696c5eSBiju Das 	.gen = 3,
94311696c5eSBiju Das 	.quirks = RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_GEN3_LVEN,
94411696c5eSBiju Das 	.pll_setup = rcar_lvds_pll_setup_gen2,
94511696c5eSBiju Das };
94611696c5eSBiju Das 
94711696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = {
94811696c5eSBiju Das 	.gen = 3,
94911696c5eSBiju Das 	.quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL
95011696c5eSBiju Das 		| RCAR_LVDS_QUIRK_DUAL_LINK,
95111696c5eSBiju Das };
95211696c5eSBiju Das 
95311696c5eSBiju Das static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = {
95411696c5eSBiju Das 	.gen = 3,
95511696c5eSBiju Das 	.quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD
95611696c5eSBiju Das 		| RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK,
95711696c5eSBiju Das };
95811696c5eSBiju Das 
95911696c5eSBiju Das static const struct of_device_id rcar_lvds_of_table[] = {
96011696c5eSBiju Das 	{ .compatible = "renesas,r8a7742-lvds", .data = &rcar_lvds_gen2_info },
96111696c5eSBiju Das 	{ .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info },
96211696c5eSBiju Das 	{ .compatible = "renesas,r8a7744-lvds", .data = &rcar_lvds_gen2_info },
96311696c5eSBiju Das 	{ .compatible = "renesas,r8a774a1-lvds", .data = &rcar_lvds_gen3_info },
96411696c5eSBiju Das 	{ .compatible = "renesas,r8a774b1-lvds", .data = &rcar_lvds_gen3_info },
96511696c5eSBiju Das 	{ .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info },
96611696c5eSBiju Das 	{ .compatible = "renesas,r8a774e1-lvds", .data = &rcar_lvds_gen3_info },
96711696c5eSBiju Das 	{ .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_gen2_info },
96811696c5eSBiju Das 	{ .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
96911696c5eSBiju Das 	{ .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
97011696c5eSBiju Das 	{ .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
97111696c5eSBiju Das 	{ .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
97211696c5eSBiju Das 	{ .compatible = "renesas,r8a77961-lvds", .data = &rcar_lvds_gen3_info },
97311696c5eSBiju Das 	{ .compatible = "renesas,r8a77965-lvds", .data = &rcar_lvds_gen3_info },
97411696c5eSBiju Das 	{ .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
97511696c5eSBiju Das 	{ .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info },
97611696c5eSBiju Das 	{ .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info },
97711696c5eSBiju Das 	{ .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_r8a77995_info },
97811696c5eSBiju Das 	{ }
97911696c5eSBiju Das };
98011696c5eSBiju Das 
98111696c5eSBiju Das MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
98211696c5eSBiju Das 
rcar_lvds_runtime_suspend(struct device * dev)98311696c5eSBiju Das static int rcar_lvds_runtime_suspend(struct device *dev)
98411696c5eSBiju Das {
98511696c5eSBiju Das 	struct rcar_lvds *lvds = dev_get_drvdata(dev);
98611696c5eSBiju Das 
98711696c5eSBiju Das 	clk_disable_unprepare(lvds->clocks.mod);
98811696c5eSBiju Das 
98911696c5eSBiju Das 	reset_control_assert(lvds->rstc);
99011696c5eSBiju Das 
99111696c5eSBiju Das 	return 0;
99211696c5eSBiju Das }
99311696c5eSBiju Das 
rcar_lvds_runtime_resume(struct device * dev)99411696c5eSBiju Das static int rcar_lvds_runtime_resume(struct device *dev)
99511696c5eSBiju Das {
99611696c5eSBiju Das 	struct rcar_lvds *lvds = dev_get_drvdata(dev);
99711696c5eSBiju Das 	int ret;
99811696c5eSBiju Das 
99911696c5eSBiju Das 	ret = reset_control_deassert(lvds->rstc);
100011696c5eSBiju Das 	if (ret)
100111696c5eSBiju Das 		return ret;
100211696c5eSBiju Das 
100311696c5eSBiju Das 	ret = clk_prepare_enable(lvds->clocks.mod);
100411696c5eSBiju Das 	if (ret < 0)
100511696c5eSBiju Das 		goto err_reset_assert;
100611696c5eSBiju Das 
100711696c5eSBiju Das 	return 0;
100811696c5eSBiju Das 
100911696c5eSBiju Das err_reset_assert:
101011696c5eSBiju Das 	reset_control_assert(lvds->rstc);
101111696c5eSBiju Das 
101211696c5eSBiju Das 	return ret;
101311696c5eSBiju Das }
101411696c5eSBiju Das 
101511696c5eSBiju Das static const struct dev_pm_ops rcar_lvds_pm_ops = {
101611696c5eSBiju Das 	SET_RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL)
101711696c5eSBiju Das };
101811696c5eSBiju Das 
101911696c5eSBiju Das static struct platform_driver rcar_lvds_platform_driver = {
102011696c5eSBiju Das 	.probe		= rcar_lvds_probe,
1021*de8a334fSThomas Zimmermann 	.remove_new	= rcar_lvds_remove,
102211696c5eSBiju Das 	.driver		= {
102311696c5eSBiju Das 		.name	= "rcar-lvds",
102411696c5eSBiju Das 		.pm	= &rcar_lvds_pm_ops,
102511696c5eSBiju Das 		.of_match_table = rcar_lvds_of_table,
102611696c5eSBiju Das 	},
102711696c5eSBiju Das };
102811696c5eSBiju Das 
102911696c5eSBiju Das module_platform_driver(rcar_lvds_platform_driver);
103011696c5eSBiju Das 
103111696c5eSBiju Das MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
103211696c5eSBiju Das MODULE_DESCRIPTION("Renesas R-Car LVDS Encoder Driver");
103311696c5eSBiju Das MODULE_LICENSE("GPL");
1034