xref: /openbmc/linux/drivers/gpu/drm/renesas/rcar-du/rzg2l_mipi_dsi.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
111696c5eSBiju Das // SPDX-License-Identifier: GPL-2.0
211696c5eSBiju Das /*
311696c5eSBiju Das  * RZ/G2L MIPI DSI Encoder Driver
411696c5eSBiju Das  *
511696c5eSBiju Das  * Copyright (C) 2022 Renesas Electronics Corporation
611696c5eSBiju Das  */
711696c5eSBiju Das #include <linux/clk.h>
811696c5eSBiju Das #include <linux/delay.h>
911696c5eSBiju Das #include <linux/io.h>
1011696c5eSBiju Das #include <linux/iopoll.h>
1111696c5eSBiju Das #include <linux/module.h>
1211696c5eSBiju Das #include <linux/of.h>
1311696c5eSBiju Das #include <linux/of_graph.h>
1411696c5eSBiju Das #include <linux/platform_device.h>
1511696c5eSBiju Das #include <linux/pm_runtime.h>
1611696c5eSBiju Das #include <linux/reset.h>
1711696c5eSBiju Das #include <linux/slab.h>
1811696c5eSBiju Das 
1911696c5eSBiju Das #include <drm/drm_atomic.h>
2011696c5eSBiju Das #include <drm/drm_atomic_helper.h>
2111696c5eSBiju Das #include <drm/drm_bridge.h>
2211696c5eSBiju Das #include <drm/drm_mipi_dsi.h>
2311696c5eSBiju Das #include <drm/drm_of.h>
2411696c5eSBiju Das #include <drm/drm_panel.h>
2511696c5eSBiju Das #include <drm/drm_probe_helper.h>
2611696c5eSBiju Das 
2711696c5eSBiju Das #include "rzg2l_mipi_dsi_regs.h"
2811696c5eSBiju Das 
2911696c5eSBiju Das struct rzg2l_mipi_dsi {
3011696c5eSBiju Das 	struct device *dev;
3111696c5eSBiju Das 	void __iomem *mmio;
3211696c5eSBiju Das 
3311696c5eSBiju Das 	struct reset_control *rstc;
3411696c5eSBiju Das 	struct reset_control *arstc;
3511696c5eSBiju Das 	struct reset_control *prstc;
3611696c5eSBiju Das 
3711696c5eSBiju Das 	struct mipi_dsi_host host;
3811696c5eSBiju Das 	struct drm_bridge bridge;
3911696c5eSBiju Das 	struct drm_bridge *next_bridge;
4011696c5eSBiju Das 
4111696c5eSBiju Das 	struct clk *vclk;
4211696c5eSBiju Das 
4311696c5eSBiju Das 	enum mipi_dsi_pixel_format format;
4411696c5eSBiju Das 	unsigned int num_data_lanes;
4511696c5eSBiju Das 	unsigned int lanes;
4611696c5eSBiju Das 	unsigned long mode_flags;
4711696c5eSBiju Das };
4811696c5eSBiju Das 
4911696c5eSBiju Das static inline struct rzg2l_mipi_dsi *
bridge_to_rzg2l_mipi_dsi(struct drm_bridge * bridge)5011696c5eSBiju Das bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
5111696c5eSBiju Das {
5211696c5eSBiju Das 	return container_of(bridge, struct rzg2l_mipi_dsi, bridge);
5311696c5eSBiju Das }
5411696c5eSBiju Das 
5511696c5eSBiju Das static inline struct rzg2l_mipi_dsi *
host_to_rzg2l_mipi_dsi(struct mipi_dsi_host * host)5611696c5eSBiju Das host_to_rzg2l_mipi_dsi(struct mipi_dsi_host *host)
5711696c5eSBiju Das {
5811696c5eSBiju Das 	return container_of(host, struct rzg2l_mipi_dsi, host);
5911696c5eSBiju Das }
6011696c5eSBiju Das 
6111696c5eSBiju Das struct rzg2l_mipi_dsi_timings {
6211696c5eSBiju Das 	unsigned long hsfreq_max;
6311696c5eSBiju Das 	u32 t_init;
6411696c5eSBiju Das 	u32 tclk_prepare;
6511696c5eSBiju Das 	u32 ths_prepare;
6611696c5eSBiju Das 	u32 tclk_zero;
6711696c5eSBiju Das 	u32 tclk_pre;
6811696c5eSBiju Das 	u32 tclk_post;
6911696c5eSBiju Das 	u32 tclk_trail;
7011696c5eSBiju Das 	u32 ths_zero;
7111696c5eSBiju Das 	u32 ths_trail;
7211696c5eSBiju Das 	u32 ths_exit;
7311696c5eSBiju Das 	u32 tlpx;
7411696c5eSBiju Das };
7511696c5eSBiju Das 
7611696c5eSBiju Das static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
7711696c5eSBiju Das 	{
7811696c5eSBiju Das 		.hsfreq_max = 80000,
7911696c5eSBiju Das 		.t_init = 79801,
8011696c5eSBiju Das 		.tclk_prepare = 8,
8111696c5eSBiju Das 		.ths_prepare = 13,
8211696c5eSBiju Das 		.tclk_zero = 33,
8311696c5eSBiju Das 		.tclk_pre = 24,
8411696c5eSBiju Das 		.tclk_post = 94,
8511696c5eSBiju Das 		.tclk_trail = 10,
8611696c5eSBiju Das 		.ths_zero = 23,
8711696c5eSBiju Das 		.ths_trail = 17,
8811696c5eSBiju Das 		.ths_exit = 13,
8911696c5eSBiju Das 		.tlpx = 6,
9011696c5eSBiju Das 	},
9111696c5eSBiju Das 	{
9211696c5eSBiju Das 		.hsfreq_max = 125000,
9311696c5eSBiju Das 		.t_init = 79801,
9411696c5eSBiju Das 		.tclk_prepare = 8,
9511696c5eSBiju Das 		.ths_prepare = 12,
9611696c5eSBiju Das 		.tclk_zero = 33,
9711696c5eSBiju Das 		.tclk_pre = 15,
9811696c5eSBiju Das 		.tclk_post = 94,
9911696c5eSBiju Das 		.tclk_trail = 10,
10011696c5eSBiju Das 		.ths_zero = 23,
10111696c5eSBiju Das 		.ths_trail = 17,
10211696c5eSBiju Das 		.ths_exit = 13,
10311696c5eSBiju Das 		.tlpx = 6,
10411696c5eSBiju Das 	},
10511696c5eSBiju Das 	{
10611696c5eSBiju Das 		.hsfreq_max = 250000,
10711696c5eSBiju Das 		.t_init = 79801,
10811696c5eSBiju Das 		.tclk_prepare = 8,
10911696c5eSBiju Das 		.ths_prepare = 12,
11011696c5eSBiju Das 		.tclk_zero = 33,
11111696c5eSBiju Das 		.tclk_pre = 13,
11211696c5eSBiju Das 		.tclk_post = 94,
11311696c5eSBiju Das 		.tclk_trail = 10,
11411696c5eSBiju Das 		.ths_zero = 23,
11511696c5eSBiju Das 		.ths_trail = 16,
11611696c5eSBiju Das 		.ths_exit = 13,
11711696c5eSBiju Das 		.tlpx = 6,
11811696c5eSBiju Das 	},
11911696c5eSBiju Das 	{
12011696c5eSBiju Das 		.hsfreq_max = 360000,
12111696c5eSBiju Das 		.t_init = 79801,
12211696c5eSBiju Das 		.tclk_prepare = 8,
12311696c5eSBiju Das 		.ths_prepare = 10,
12411696c5eSBiju Das 		.tclk_zero = 33,
12511696c5eSBiju Das 		.tclk_pre = 4,
12611696c5eSBiju Das 		.tclk_post = 35,
12711696c5eSBiju Das 		.tclk_trail = 7,
12811696c5eSBiju Das 		.ths_zero = 16,
12911696c5eSBiju Das 		.ths_trail = 9,
13011696c5eSBiju Das 		.ths_exit = 13,
13111696c5eSBiju Das 		.tlpx = 6,
13211696c5eSBiju Das 	},
13311696c5eSBiju Das 	{
13411696c5eSBiju Das 		.hsfreq_max = 720000,
13511696c5eSBiju Das 		.t_init = 79801,
13611696c5eSBiju Das 		.tclk_prepare = 8,
13711696c5eSBiju Das 		.ths_prepare = 9,
13811696c5eSBiju Das 		.tclk_zero = 33,
13911696c5eSBiju Das 		.tclk_pre = 4,
14011696c5eSBiju Das 		.tclk_post = 35,
14111696c5eSBiju Das 		.tclk_trail = 7,
14211696c5eSBiju Das 		.ths_zero = 16,
14311696c5eSBiju Das 		.ths_trail = 9,
14411696c5eSBiju Das 		.ths_exit = 13,
14511696c5eSBiju Das 		.tlpx = 6,
14611696c5eSBiju Das 	},
14711696c5eSBiju Das 	{
14811696c5eSBiju Das 		.hsfreq_max = 1500000,
14911696c5eSBiju Das 		.t_init = 79801,
15011696c5eSBiju Das 		.tclk_prepare = 8,
15111696c5eSBiju Das 		.ths_prepare = 9,
15211696c5eSBiju Das 		.tclk_zero = 33,
15311696c5eSBiju Das 		.tclk_pre = 4,
15411696c5eSBiju Das 		.tclk_post = 35,
15511696c5eSBiju Das 		.tclk_trail = 7,
15611696c5eSBiju Das 		.ths_zero = 16,
15711696c5eSBiju Das 		.ths_trail = 9,
15811696c5eSBiju Das 		.ths_exit = 13,
15911696c5eSBiju Das 		.tlpx = 6,
16011696c5eSBiju Das 	},
16111696c5eSBiju Das };
16211696c5eSBiju Das 
rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi * dsi,u32 reg,u32 data)16311696c5eSBiju Das static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
16411696c5eSBiju Das {
16511696c5eSBiju Das 	iowrite32(data, dsi->mmio + reg);
16611696c5eSBiju Das }
16711696c5eSBiju Das 
rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi * dsi,u32 reg,u32 data)16811696c5eSBiju Das static void rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
16911696c5eSBiju Das {
17011696c5eSBiju Das 	iowrite32(data, dsi->mmio + LINK_REG_OFFSET + reg);
17111696c5eSBiju Das }
17211696c5eSBiju Das 
rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi * dsi,u32 reg)17311696c5eSBiju Das static u32 rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
17411696c5eSBiju Das {
17511696c5eSBiju Das 	return ioread32(dsi->mmio + reg);
17611696c5eSBiju Das }
17711696c5eSBiju Das 
rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi * dsi,u32 reg)17811696c5eSBiju Das static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
17911696c5eSBiju Das {
18011696c5eSBiju Das 	return ioread32(dsi->mmio + LINK_REG_OFFSET + reg);
18111696c5eSBiju Das }
18211696c5eSBiju Das 
18311696c5eSBiju Das /* -----------------------------------------------------------------------------
18411696c5eSBiju Das  * Hardware Setup
18511696c5eSBiju Das  */
18611696c5eSBiju Das 
rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi * dsi,unsigned long hsfreq)18711696c5eSBiju Das static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
18811696c5eSBiju Das 				    unsigned long hsfreq)
18911696c5eSBiju Das {
19011696c5eSBiju Das 	const struct rzg2l_mipi_dsi_timings *dphy_timings;
19111696c5eSBiju Das 	unsigned int i;
19211696c5eSBiju Das 	u32 dphyctrl0;
19311696c5eSBiju Das 	u32 dphytim0;
19411696c5eSBiju Das 	u32 dphytim1;
19511696c5eSBiju Das 	u32 dphytim2;
19611696c5eSBiju Das 	u32 dphytim3;
19711696c5eSBiju Das 	int ret;
19811696c5eSBiju Das 
19911696c5eSBiju Das 	/* All DSI global operation timings are set with recommended setting */
20011696c5eSBiju Das 	for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) {
20111696c5eSBiju Das 		dphy_timings = &rzg2l_mipi_dsi_global_timings[i];
20211696c5eSBiju Das 		if (hsfreq <= dphy_timings->hsfreq_max)
20311696c5eSBiju Das 			break;
20411696c5eSBiju Das 	}
20511696c5eSBiju Das 
20611696c5eSBiju Das 	/* Initializing DPHY before accessing LINK */
20711696c5eSBiju Das 	dphyctrl0 = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN |
20811696c5eSBiju Das 		    DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR;
20911696c5eSBiju Das 
21011696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
21111696c5eSBiju Das 	usleep_range(20, 30);
21211696c5eSBiju Das 
21311696c5eSBiju Das 	dphyctrl0 |= DSIDPHYCTRL0_EN_LDO1200;
21411696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
21511696c5eSBiju Das 	usleep_range(10, 20);
21611696c5eSBiju Das 
21711696c5eSBiju Das 	dphytim0 = DSIDPHYTIM0_TCLK_MISS(0) |
21811696c5eSBiju Das 		   DSIDPHYTIM0_T_INIT(dphy_timings->t_init);
21911696c5eSBiju Das 	dphytim1 = DSIDPHYTIM1_THS_PREPARE(dphy_timings->ths_prepare) |
22011696c5eSBiju Das 		   DSIDPHYTIM1_TCLK_PREPARE(dphy_timings->tclk_prepare) |
22111696c5eSBiju Das 		   DSIDPHYTIM1_THS_SETTLE(0) |
22211696c5eSBiju Das 		   DSIDPHYTIM1_TCLK_SETTLE(0);
22311696c5eSBiju Das 	dphytim2 = DSIDPHYTIM2_TCLK_TRAIL(dphy_timings->tclk_trail) |
22411696c5eSBiju Das 		   DSIDPHYTIM2_TCLK_POST(dphy_timings->tclk_post) |
22511696c5eSBiju Das 		   DSIDPHYTIM2_TCLK_PRE(dphy_timings->tclk_pre) |
22611696c5eSBiju Das 		   DSIDPHYTIM2_TCLK_ZERO(dphy_timings->tclk_zero);
22711696c5eSBiju Das 	dphytim3 = DSIDPHYTIM3_TLPX(dphy_timings->tlpx) |
22811696c5eSBiju Das 		   DSIDPHYTIM3_THS_EXIT(dphy_timings->ths_exit) |
22911696c5eSBiju Das 		   DSIDPHYTIM3_THS_TRAIL(dphy_timings->ths_trail) |
23011696c5eSBiju Das 		   DSIDPHYTIM3_THS_ZERO(dphy_timings->ths_zero);
23111696c5eSBiju Das 
23211696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM0, dphytim0);
23311696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM1, dphytim1);
23411696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM2, dphytim2);
23511696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYTIM3, dphytim3);
23611696c5eSBiju Das 
23711696c5eSBiju Das 	ret = reset_control_deassert(dsi->rstc);
23811696c5eSBiju Das 	if (ret < 0)
23911696c5eSBiju Das 		return ret;
24011696c5eSBiju Das 
24111696c5eSBiju Das 	udelay(1);
24211696c5eSBiju Das 
24311696c5eSBiju Das 	return 0;
24411696c5eSBiju Das }
24511696c5eSBiju Das 
rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi * dsi)24611696c5eSBiju Das static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
24711696c5eSBiju Das {
24811696c5eSBiju Das 	u32 dphyctrl0;
24911696c5eSBiju Das 
25011696c5eSBiju Das 	dphyctrl0 = rzg2l_mipi_dsi_phy_read(dsi, DSIDPHYCTRL0);
25111696c5eSBiju Das 
25211696c5eSBiju Das 	dphyctrl0 &= ~(DSIDPHYCTRL0_EN_LDO1200 | DSIDPHYCTRL0_EN_BGR);
25311696c5eSBiju Das 	rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
25411696c5eSBiju Das 
25511696c5eSBiju Das 	reset_control_assert(dsi->rstc);
25611696c5eSBiju Das }
25711696c5eSBiju Das 
rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi * dsi,const struct drm_display_mode * mode)25811696c5eSBiju Das static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
25911696c5eSBiju Das 				  const struct drm_display_mode *mode)
26011696c5eSBiju Das {
26111696c5eSBiju Das 	unsigned long hsfreq;
26211696c5eSBiju Das 	unsigned int bpp;
26311696c5eSBiju Das 	u32 txsetr;
26411696c5eSBiju Das 	u32 clstptsetr;
26511696c5eSBiju Das 	u32 lptrnstsetr;
26611696c5eSBiju Das 	u32 clkkpt;
26711696c5eSBiju Das 	u32 clkbfht;
26811696c5eSBiju Das 	u32 clkstpt;
26911696c5eSBiju Das 	u32 golpbkt;
27011696c5eSBiju Das 	int ret;
27111696c5eSBiju Das 
27211696c5eSBiju Das 	/*
27311696c5eSBiju Das 	 * Relationship between hsclk and vclk must follow
27411696c5eSBiju Das 	 * vclk * bpp = hsclk * 8 * lanes
27511696c5eSBiju Das 	 * where vclk: video clock (Hz)
27611696c5eSBiju Das 	 *       bpp: video pixel bit depth
27711696c5eSBiju Das 	 *       hsclk: DSI HS Byte clock frequency (Hz)
27811696c5eSBiju Das 	 *       lanes: number of data lanes
27911696c5eSBiju Das 	 *
28011696c5eSBiju Das 	 * hsclk(bit) = hsclk(byte) * 8
28111696c5eSBiju Das 	 */
28211696c5eSBiju Das 	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
28311696c5eSBiju Das 	hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes);
28411696c5eSBiju Das 
28511696c5eSBiju Das 	ret = pm_runtime_resume_and_get(dsi->dev);
28611696c5eSBiju Das 	if (ret < 0)
28711696c5eSBiju Das 		return ret;
28811696c5eSBiju Das 
28911696c5eSBiju Das 	clk_set_rate(dsi->vclk, mode->clock * 1000);
29011696c5eSBiju Das 
29111696c5eSBiju Das 	ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq);
29211696c5eSBiju Das 	if (ret < 0)
29311696c5eSBiju Das 		goto err_phy;
29411696c5eSBiju Das 
29511696c5eSBiju Das 	/* Enable Data lanes and Clock lanes */
29611696c5eSBiju Das 	txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN;
29711696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr);
29811696c5eSBiju Das 
29911696c5eSBiju Das 	/*
30011696c5eSBiju Das 	 * Global timings characteristic depends on high speed Clock Frequency
30111696c5eSBiju Das 	 * Currently MIPI DSI-IF just supports maximum FHD@60 with:
30211696c5eSBiju Das 	 * - videoclock = 148.5 (MHz)
30311696c5eSBiju Das 	 * - bpp: maximum 24bpp
30411696c5eSBiju Das 	 * - data lanes: maximum 4 lanes
30511696c5eSBiju Das 	 * Therefore maximum hsclk will be 891 Mbps.
30611696c5eSBiju Das 	 */
30711696c5eSBiju Das 	if (hsfreq > 445500) {
30811696c5eSBiju Das 		clkkpt = 12;
30911696c5eSBiju Das 		clkbfht = 15;
31011696c5eSBiju Das 		clkstpt = 48;
31111696c5eSBiju Das 		golpbkt = 75;
31211696c5eSBiju Das 	} else if (hsfreq > 250000) {
31311696c5eSBiju Das 		clkkpt = 7;
31411696c5eSBiju Das 		clkbfht = 8;
31511696c5eSBiju Das 		clkstpt = 27;
31611696c5eSBiju Das 		golpbkt = 40;
31711696c5eSBiju Das 	} else {
31811696c5eSBiju Das 		clkkpt = 8;
31911696c5eSBiju Das 		clkbfht = 6;
32011696c5eSBiju Das 		clkstpt = 24;
32111696c5eSBiju Das 		golpbkt = 29;
32211696c5eSBiju Das 	}
32311696c5eSBiju Das 
32411696c5eSBiju Das 	clstptsetr = CLSTPTSETR_CLKKPT(clkkpt) | CLSTPTSETR_CLKBFHT(clkbfht) |
32511696c5eSBiju Das 		     CLSTPTSETR_CLKSTPT(clkstpt);
32611696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, CLSTPTSETR, clstptsetr);
32711696c5eSBiju Das 
32811696c5eSBiju Das 	lptrnstsetr = LPTRNSTSETR_GOLPBKT(golpbkt);
32911696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, LPTRNSTSETR, lptrnstsetr);
33011696c5eSBiju Das 
33111696c5eSBiju Das 	return 0;
33211696c5eSBiju Das 
33311696c5eSBiju Das err_phy:
33411696c5eSBiju Das 	rzg2l_mipi_dsi_dphy_exit(dsi);
33511696c5eSBiju Das 	pm_runtime_put(dsi->dev);
33611696c5eSBiju Das 
33711696c5eSBiju Das 	return ret;
33811696c5eSBiju Das }
33911696c5eSBiju Das 
rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi * dsi)34011696c5eSBiju Das static void rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi *dsi)
34111696c5eSBiju Das {
34211696c5eSBiju Das 	rzg2l_mipi_dsi_dphy_exit(dsi);
34311696c5eSBiju Das 	pm_runtime_put(dsi->dev);
34411696c5eSBiju Das }
34511696c5eSBiju Das 
rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi * dsi,const struct drm_display_mode * mode)34611696c5eSBiju Das static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
34711696c5eSBiju Das 					      const struct drm_display_mode *mode)
34811696c5eSBiju Das {
34911696c5eSBiju Das 	u32 vich1ppsetr;
35011696c5eSBiju Das 	u32 vich1vssetr;
35111696c5eSBiju Das 	u32 vich1vpsetr;
35211696c5eSBiju Das 	u32 vich1hssetr;
35311696c5eSBiju Das 	u32 vich1hpsetr;
35411696c5eSBiju Das 	int dsi_format;
35511696c5eSBiju Das 	u32 delay[2];
35611696c5eSBiju Das 	u8 index;
35711696c5eSBiju Das 
35811696c5eSBiju Das 	/* Configuration for Pixel Packet */
35911696c5eSBiju Das 	dsi_format = mipi_dsi_pixel_format_to_bpp(dsi->format);
36011696c5eSBiju Das 	switch (dsi_format) {
36111696c5eSBiju Das 	case 24:
36211696c5eSBiju Das 		vich1ppsetr = VICH1PPSETR_DT_RGB24;
36311696c5eSBiju Das 		break;
36411696c5eSBiju Das 	case 18:
36511696c5eSBiju Das 		vich1ppsetr = VICH1PPSETR_DT_RGB18;
36611696c5eSBiju Das 		break;
36711696c5eSBiju Das 	}
36811696c5eSBiju Das 
36911696c5eSBiju Das 	if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) &&
37011696c5eSBiju Das 	    !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST))
37111696c5eSBiju Das 		vich1ppsetr |= VICH1PPSETR_TXESYNC_PULSE;
37211696c5eSBiju Das 
37311696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1PPSETR, vich1ppsetr);
37411696c5eSBiju Das 
37511696c5eSBiju Das 	/* Configuration for Video Parameters */
37611696c5eSBiju Das 	vich1vssetr = VICH1VSSETR_VACTIVE(mode->vdisplay) |
37711696c5eSBiju Das 		      VICH1VSSETR_VSA(mode->vsync_end - mode->vsync_start);
37811696c5eSBiju Das 	vich1vssetr |= (mode->flags & DRM_MODE_FLAG_PVSYNC) ?
37911696c5eSBiju Das 			VICH1VSSETR_VSPOL_HIGH : VICH1VSSETR_VSPOL_LOW;
38011696c5eSBiju Das 
38111696c5eSBiju Das 	vich1vpsetr = VICH1VPSETR_VFP(mode->vsync_start - mode->vdisplay) |
38211696c5eSBiju Das 		      VICH1VPSETR_VBP(mode->vtotal - mode->vsync_end);
38311696c5eSBiju Das 
38411696c5eSBiju Das 	vich1hssetr = VICH1HSSETR_HACTIVE(mode->hdisplay) |
38511696c5eSBiju Das 		      VICH1HSSETR_HSA(mode->hsync_end - mode->hsync_start);
38611696c5eSBiju Das 	vich1hssetr |= (mode->flags & DRM_MODE_FLAG_PHSYNC) ?
38711696c5eSBiju Das 			VICH1HSSETR_HSPOL_HIGH : VICH1HSSETR_HSPOL_LOW;
38811696c5eSBiju Das 
38911696c5eSBiju Das 	vich1hpsetr = VICH1HPSETR_HFP(mode->hsync_start - mode->hdisplay) |
39011696c5eSBiju Das 		      VICH1HPSETR_HBP(mode->htotal - mode->hsync_end);
39111696c5eSBiju Das 
39211696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1VSSETR, vich1vssetr);
39311696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1VPSETR, vich1vpsetr);
39411696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1HSSETR, vich1hssetr);
39511696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1HPSETR, vich1hpsetr);
39611696c5eSBiju Das 
39711696c5eSBiju Das 	/*
39811696c5eSBiju Das 	 * Configuration for Delay Value
39911696c5eSBiju Das 	 * Delay value based on 2 ranges of video clock.
40011696c5eSBiju Das 	 * 74.25MHz is videoclock of HD@60p or FHD@30p
40111696c5eSBiju Das 	 */
40211696c5eSBiju Das 	if (mode->clock > 74250) {
40311696c5eSBiju Das 		delay[0] = 231;
40411696c5eSBiju Das 		delay[1] = 216;
40511696c5eSBiju Das 	} else {
40611696c5eSBiju Das 		delay[0] = 220;
40711696c5eSBiju Das 		delay[1] = 212;
40811696c5eSBiju Das 	}
40911696c5eSBiju Das 
41011696c5eSBiju Das 	if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
41111696c5eSBiju Das 		index = 0;
41211696c5eSBiju Das 	else
41311696c5eSBiju Das 		index = 1;
41411696c5eSBiju Das 
41511696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1SET1R,
41611696c5eSBiju Das 				  VICH1SET1R_DLY(delay[index]));
41711696c5eSBiju Das }
41811696c5eSBiju Das 
rzg2l_mipi_dsi_start_hs_clock(struct rzg2l_mipi_dsi * dsi)41911696c5eSBiju Das static int rzg2l_mipi_dsi_start_hs_clock(struct rzg2l_mipi_dsi *dsi)
42011696c5eSBiju Das {
42111696c5eSBiju Das 	bool is_clk_cont;
42211696c5eSBiju Das 	u32 hsclksetr;
42311696c5eSBiju Das 	u32 status;
42411696c5eSBiju Das 	int ret;
42511696c5eSBiju Das 
42611696c5eSBiju Das 	is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS);
42711696c5eSBiju Das 
42811696c5eSBiju Das 	/* Start HS clock */
42911696c5eSBiju Das 	hsclksetr = HSCLKSETR_HSCLKRUN_HS | (is_clk_cont ?
43011696c5eSBiju Das 					     HSCLKSETR_HSCLKMODE_CONT :
43111696c5eSBiju Das 					     HSCLKSETR_HSCLKMODE_NON_CONT);
43211696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR, hsclksetr);
43311696c5eSBiju Das 
43411696c5eSBiju Das 	if (is_clk_cont) {
43511696c5eSBiju Das 		ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
43611696c5eSBiju Das 					status & PLSR_CLLP2HS,
43711696c5eSBiju Das 					2000, 20000, false, dsi, PLSR);
43811696c5eSBiju Das 		if (ret < 0) {
43911696c5eSBiju Das 			dev_err(dsi->dev, "failed to start HS clock\n");
44011696c5eSBiju Das 			return ret;
44111696c5eSBiju Das 		}
44211696c5eSBiju Das 	}
44311696c5eSBiju Das 
44411696c5eSBiju Das 	dev_dbg(dsi->dev, "Start High Speed Clock with %s clock mode",
44511696c5eSBiju Das 		is_clk_cont ? "continuous" : "non-continuous");
44611696c5eSBiju Das 
44711696c5eSBiju Das 	return 0;
44811696c5eSBiju Das }
44911696c5eSBiju Das 
rzg2l_mipi_dsi_stop_hs_clock(struct rzg2l_mipi_dsi * dsi)45011696c5eSBiju Das static int rzg2l_mipi_dsi_stop_hs_clock(struct rzg2l_mipi_dsi *dsi)
45111696c5eSBiju Das {
45211696c5eSBiju Das 	bool is_clk_cont;
45311696c5eSBiju Das 	u32 status;
45411696c5eSBiju Das 	int ret;
45511696c5eSBiju Das 
45611696c5eSBiju Das 	is_clk_cont = !(dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS);
45711696c5eSBiju Das 
45811696c5eSBiju Das 	/* Stop HS clock */
45911696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, HSCLKSETR,
46011696c5eSBiju Das 				  is_clk_cont ? HSCLKSETR_HSCLKMODE_CONT :
46111696c5eSBiju Das 				  HSCLKSETR_HSCLKMODE_NON_CONT);
46211696c5eSBiju Das 
46311696c5eSBiju Das 	if (is_clk_cont) {
46411696c5eSBiju Das 		ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
46511696c5eSBiju Das 					status & PLSR_CLHS2LP,
46611696c5eSBiju Das 					2000, 20000, false, dsi, PLSR);
46711696c5eSBiju Das 		if (ret < 0) {
46811696c5eSBiju Das 			dev_err(dsi->dev, "failed to stop HS clock\n");
46911696c5eSBiju Das 			return ret;
47011696c5eSBiju Das 		}
47111696c5eSBiju Das 	}
47211696c5eSBiju Das 
47311696c5eSBiju Das 	return 0;
47411696c5eSBiju Das }
47511696c5eSBiju Das 
rzg2l_mipi_dsi_start_video(struct rzg2l_mipi_dsi * dsi)47611696c5eSBiju Das static int rzg2l_mipi_dsi_start_video(struct rzg2l_mipi_dsi *dsi)
47711696c5eSBiju Das {
47811696c5eSBiju Das 	u32 vich1set0r;
47911696c5eSBiju Das 	u32 status;
48011696c5eSBiju Das 	int ret;
48111696c5eSBiju Das 
48211696c5eSBiju Das 	/* Configuration for Blanking sequence and start video input*/
48311696c5eSBiju Das 	vich1set0r = VICH1SET0R_HFPNOLP | VICH1SET0R_HBPNOLP |
48411696c5eSBiju Das 		     VICH1SET0R_HSANOLP | VICH1SET0R_VSTART;
48511696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, vich1set0r);
48611696c5eSBiju Das 
48711696c5eSBiju Das 	ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
48811696c5eSBiju Das 				status & VICH1SR_VIRDY,
48911696c5eSBiju Das 				2000, 20000, false, dsi, VICH1SR);
49011696c5eSBiju Das 	if (ret < 0)
49111696c5eSBiju Das 		dev_err(dsi->dev, "Failed to start video signal input\n");
49211696c5eSBiju Das 
49311696c5eSBiju Das 	return ret;
49411696c5eSBiju Das }
49511696c5eSBiju Das 
rzg2l_mipi_dsi_stop_video(struct rzg2l_mipi_dsi * dsi)49611696c5eSBiju Das static int rzg2l_mipi_dsi_stop_video(struct rzg2l_mipi_dsi *dsi)
49711696c5eSBiju Das {
49811696c5eSBiju Das 	u32 status;
49911696c5eSBiju Das 	int ret;
50011696c5eSBiju Das 
50111696c5eSBiju Das 	rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, VICH1SET0R_VSTPAFT);
50211696c5eSBiju Das 	ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
50311696c5eSBiju Das 				(status & VICH1SR_STOP) && (!(status & VICH1SR_RUNNING)),
50411696c5eSBiju Das 				2000, 20000, false, dsi, VICH1SR);
50511696c5eSBiju Das 	if (ret < 0)
50611696c5eSBiju Das 		goto err;
50711696c5eSBiju Das 
50811696c5eSBiju Das 	ret = read_poll_timeout(rzg2l_mipi_dsi_link_read, status,
50911696c5eSBiju Das 				!(status & LINKSR_HSBUSY),
51011696c5eSBiju Das 				2000, 20000, false, dsi, LINKSR);
51111696c5eSBiju Das 	if (ret < 0)
51211696c5eSBiju Das 		goto err;
51311696c5eSBiju Das 
51411696c5eSBiju Das 	return 0;
51511696c5eSBiju Das 
51611696c5eSBiju Das err:
51711696c5eSBiju Das 	dev_err(dsi->dev, "Failed to stop video signal input\n");
51811696c5eSBiju Das 	return ret;
51911696c5eSBiju Das }
52011696c5eSBiju Das 
52111696c5eSBiju Das /* -----------------------------------------------------------------------------
52211696c5eSBiju Das  * Bridge
52311696c5eSBiju Das  */
52411696c5eSBiju Das 
rzg2l_mipi_dsi_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)52511696c5eSBiju Das static int rzg2l_mipi_dsi_attach(struct drm_bridge *bridge,
52611696c5eSBiju Das 				 enum drm_bridge_attach_flags flags)
52711696c5eSBiju Das {
52811696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
52911696c5eSBiju Das 
53011696c5eSBiju Das 	return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge,
53111696c5eSBiju Das 				 flags);
53211696c5eSBiju Das }
53311696c5eSBiju Das 
rzg2l_mipi_dsi_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)53411696c5eSBiju Das static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
53511696c5eSBiju Das 					 struct drm_bridge_state *old_bridge_state)
53611696c5eSBiju Das {
53711696c5eSBiju Das 	struct drm_atomic_state *state = old_bridge_state->base.state;
53811696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
53911696c5eSBiju Das 	const struct drm_display_mode *mode;
54011696c5eSBiju Das 	struct drm_connector *connector;
54111696c5eSBiju Das 	struct drm_crtc *crtc;
54211696c5eSBiju Das 	int ret;
54311696c5eSBiju Das 
54411696c5eSBiju Das 	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
54511696c5eSBiju Das 	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
54611696c5eSBiju Das 	mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode;
54711696c5eSBiju Das 
54811696c5eSBiju Das 	ret = rzg2l_mipi_dsi_startup(dsi, mode);
54911696c5eSBiju Das 	if (ret < 0)
55011696c5eSBiju Das 		return;
55111696c5eSBiju Das 
55211696c5eSBiju Das 	rzg2l_mipi_dsi_set_display_timing(dsi, mode);
55311696c5eSBiju Das 
55411696c5eSBiju Das 	ret = rzg2l_mipi_dsi_start_hs_clock(dsi);
55511696c5eSBiju Das 	if (ret < 0)
55611696c5eSBiju Das 		goto err_stop;
55711696c5eSBiju Das 
55811696c5eSBiju Das 	ret = rzg2l_mipi_dsi_start_video(dsi);
55911696c5eSBiju Das 	if (ret < 0)
56011696c5eSBiju Das 		goto err_stop_clock;
56111696c5eSBiju Das 
56211696c5eSBiju Das 	return;
56311696c5eSBiju Das 
56411696c5eSBiju Das err_stop_clock:
56511696c5eSBiju Das 	rzg2l_mipi_dsi_stop_hs_clock(dsi);
56611696c5eSBiju Das err_stop:
56711696c5eSBiju Das 	rzg2l_mipi_dsi_stop(dsi);
56811696c5eSBiju Das }
56911696c5eSBiju Das 
rzg2l_mipi_dsi_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)57011696c5eSBiju Das static void rzg2l_mipi_dsi_atomic_disable(struct drm_bridge *bridge,
57111696c5eSBiju Das 					  struct drm_bridge_state *old_bridge_state)
57211696c5eSBiju Das {
57311696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
57411696c5eSBiju Das 
57511696c5eSBiju Das 	rzg2l_mipi_dsi_stop_video(dsi);
57611696c5eSBiju Das 	rzg2l_mipi_dsi_stop_hs_clock(dsi);
57711696c5eSBiju Das 	rzg2l_mipi_dsi_stop(dsi);
57811696c5eSBiju Das }
57911696c5eSBiju Das 
58011696c5eSBiju Das static enum drm_mode_status
rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)58111696c5eSBiju Das rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
58211696c5eSBiju Das 				 const struct drm_display_info *info,
58311696c5eSBiju Das 				 const struct drm_display_mode *mode)
58411696c5eSBiju Das {
58511696c5eSBiju Das 	if (mode->clock > 148500)
58611696c5eSBiju Das 		return MODE_CLOCK_HIGH;
58711696c5eSBiju Das 
58811696c5eSBiju Das 	return MODE_OK;
58911696c5eSBiju Das }
59011696c5eSBiju Das 
59111696c5eSBiju Das static const struct drm_bridge_funcs rzg2l_mipi_dsi_bridge_ops = {
59211696c5eSBiju Das 	.attach = rzg2l_mipi_dsi_attach,
59311696c5eSBiju Das 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
59411696c5eSBiju Das 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
59511696c5eSBiju Das 	.atomic_reset = drm_atomic_helper_bridge_reset,
59611696c5eSBiju Das 	.atomic_enable = rzg2l_mipi_dsi_atomic_enable,
59711696c5eSBiju Das 	.atomic_disable = rzg2l_mipi_dsi_atomic_disable,
59811696c5eSBiju Das 	.mode_valid = rzg2l_mipi_dsi_bridge_mode_valid,
59911696c5eSBiju Das };
60011696c5eSBiju Das 
60111696c5eSBiju Das /* -----------------------------------------------------------------------------
60211696c5eSBiju Das  * Host setting
60311696c5eSBiju Das  */
60411696c5eSBiju Das 
rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host * host,struct mipi_dsi_device * device)60511696c5eSBiju Das static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
60611696c5eSBiju Das 				      struct mipi_dsi_device *device)
60711696c5eSBiju Das {
60811696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
60911696c5eSBiju Das 	int ret;
61011696c5eSBiju Das 
61111696c5eSBiju Das 	if (device->lanes > dsi->num_data_lanes) {
61211696c5eSBiju Das 		dev_err(dsi->dev,
61311696c5eSBiju Das 			"Number of lines of device (%u) exceeds host (%u)\n",
61411696c5eSBiju Das 			device->lanes, dsi->num_data_lanes);
61511696c5eSBiju Das 		return -EINVAL;
61611696c5eSBiju Das 	}
61711696c5eSBiju Das 
61811696c5eSBiju Das 	switch (mipi_dsi_pixel_format_to_bpp(device->format)) {
61911696c5eSBiju Das 	case 24:
62011696c5eSBiju Das 	case 18:
62111696c5eSBiju Das 		break;
62211696c5eSBiju Das 	default:
62311696c5eSBiju Das 		dev_err(dsi->dev, "Unsupported format 0x%04x\n", device->format);
62411696c5eSBiju Das 		return -EINVAL;
62511696c5eSBiju Das 	}
62611696c5eSBiju Das 
62711696c5eSBiju Das 	dsi->lanes = device->lanes;
62811696c5eSBiju Das 	dsi->format = device->format;
62911696c5eSBiju Das 	dsi->mode_flags = device->mode_flags;
63011696c5eSBiju Das 
63111696c5eSBiju Das 	dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node,
63211696c5eSBiju Das 						  1, 0);
63311696c5eSBiju Das 	if (IS_ERR(dsi->next_bridge)) {
63411696c5eSBiju Das 		ret = PTR_ERR(dsi->next_bridge);
63511696c5eSBiju Das 		dev_err(dsi->dev, "failed to get next bridge: %d\n", ret);
63611696c5eSBiju Das 		return ret;
63711696c5eSBiju Das 	}
63811696c5eSBiju Das 
63911696c5eSBiju Das 	drm_bridge_add(&dsi->bridge);
64011696c5eSBiju Das 
64111696c5eSBiju Das 	return 0;
64211696c5eSBiju Das }
64311696c5eSBiju Das 
rzg2l_mipi_dsi_host_detach(struct mipi_dsi_host * host,struct mipi_dsi_device * device)64411696c5eSBiju Das static int rzg2l_mipi_dsi_host_detach(struct mipi_dsi_host *host,
64511696c5eSBiju Das 				      struct mipi_dsi_device *device)
64611696c5eSBiju Das {
64711696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
64811696c5eSBiju Das 
64911696c5eSBiju Das 	drm_bridge_remove(&dsi->bridge);
65011696c5eSBiju Das 
65111696c5eSBiju Das 	return 0;
65211696c5eSBiju Das }
65311696c5eSBiju Das 
65411696c5eSBiju Das static const struct mipi_dsi_host_ops rzg2l_mipi_dsi_host_ops = {
65511696c5eSBiju Das 	.attach = rzg2l_mipi_dsi_host_attach,
65611696c5eSBiju Das 	.detach = rzg2l_mipi_dsi_host_detach,
65711696c5eSBiju Das };
65811696c5eSBiju Das 
65911696c5eSBiju Das /* -----------------------------------------------------------------------------
66011696c5eSBiju Das  * Power Management
66111696c5eSBiju Das  */
66211696c5eSBiju Das 
rzg2l_mipi_pm_runtime_suspend(struct device * dev)66311696c5eSBiju Das static int __maybe_unused rzg2l_mipi_pm_runtime_suspend(struct device *dev)
66411696c5eSBiju Das {
66511696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev);
66611696c5eSBiju Das 
66711696c5eSBiju Das 	reset_control_assert(dsi->prstc);
66811696c5eSBiju Das 	reset_control_assert(dsi->arstc);
66911696c5eSBiju Das 
67011696c5eSBiju Das 	return 0;
67111696c5eSBiju Das }
67211696c5eSBiju Das 
rzg2l_mipi_pm_runtime_resume(struct device * dev)67311696c5eSBiju Das static int __maybe_unused rzg2l_mipi_pm_runtime_resume(struct device *dev)
67411696c5eSBiju Das {
67511696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = dev_get_drvdata(dev);
67611696c5eSBiju Das 	int ret;
67711696c5eSBiju Das 
67811696c5eSBiju Das 	ret = reset_control_deassert(dsi->arstc);
67911696c5eSBiju Das 	if (ret < 0)
68011696c5eSBiju Das 		return ret;
68111696c5eSBiju Das 
68211696c5eSBiju Das 	ret = reset_control_deassert(dsi->prstc);
68311696c5eSBiju Das 	if (ret < 0)
68411696c5eSBiju Das 		reset_control_assert(dsi->arstc);
68511696c5eSBiju Das 
68611696c5eSBiju Das 	return ret;
68711696c5eSBiju Das }
68811696c5eSBiju Das 
68911696c5eSBiju Das static const struct dev_pm_ops rzg2l_mipi_pm_ops = {
69011696c5eSBiju Das 	SET_RUNTIME_PM_OPS(rzg2l_mipi_pm_runtime_suspend, rzg2l_mipi_pm_runtime_resume, NULL)
69111696c5eSBiju Das };
69211696c5eSBiju Das 
69311696c5eSBiju Das /* -----------------------------------------------------------------------------
69411696c5eSBiju Das  * Probe & Remove
69511696c5eSBiju Das  */
69611696c5eSBiju Das 
rzg2l_mipi_dsi_probe(struct platform_device * pdev)69711696c5eSBiju Das static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
69811696c5eSBiju Das {
69911696c5eSBiju Das 	unsigned int num_data_lanes;
70011696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi;
70111696c5eSBiju Das 	u32 txsetr;
70211696c5eSBiju Das 	int ret;
70311696c5eSBiju Das 
70411696c5eSBiju Das 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
70511696c5eSBiju Das 	if (!dsi)
70611696c5eSBiju Das 		return -ENOMEM;
70711696c5eSBiju Das 
70811696c5eSBiju Das 	platform_set_drvdata(pdev, dsi);
70911696c5eSBiju Das 	dsi->dev = &pdev->dev;
71011696c5eSBiju Das 
71111696c5eSBiju Das 	ret = drm_of_get_data_lanes_count_ep(dsi->dev->of_node, 1, 0, 1, 4);
71211696c5eSBiju Das 	if (ret < 0)
71311696c5eSBiju Das 		return dev_err_probe(dsi->dev, ret,
71411696c5eSBiju Das 				     "missing or invalid data-lanes property\n");
71511696c5eSBiju Das 
71611696c5eSBiju Das 	num_data_lanes = ret;
71711696c5eSBiju Das 
71811696c5eSBiju Das 	dsi->mmio = devm_platform_ioremap_resource(pdev, 0);
71911696c5eSBiju Das 	if (IS_ERR(dsi->mmio))
72011696c5eSBiju Das 		return PTR_ERR(dsi->mmio);
72111696c5eSBiju Das 
72211696c5eSBiju Das 	dsi->vclk = devm_clk_get(dsi->dev, "vclk");
72311696c5eSBiju Das 	if (IS_ERR(dsi->vclk))
72411696c5eSBiju Das 		return PTR_ERR(dsi->vclk);
72511696c5eSBiju Das 
72611696c5eSBiju Das 	dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst");
72711696c5eSBiju Das 	if (IS_ERR(dsi->rstc))
72811696c5eSBiju Das 		return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
72911696c5eSBiju Das 				     "failed to get rst\n");
73011696c5eSBiju Das 
73111696c5eSBiju Das 	dsi->arstc = devm_reset_control_get_exclusive(dsi->dev, "arst");
73211696c5eSBiju Das 	if (IS_ERR(dsi->arstc))
73311696c5eSBiju Das 		return dev_err_probe(&pdev->dev, PTR_ERR(dsi->arstc),
73411696c5eSBiju Das 				     "failed to get arst\n");
73511696c5eSBiju Das 
73611696c5eSBiju Das 	dsi->prstc = devm_reset_control_get_exclusive(dsi->dev, "prst");
73711696c5eSBiju Das 	if (IS_ERR(dsi->prstc))
73811696c5eSBiju Das 		return dev_err_probe(dsi->dev, PTR_ERR(dsi->prstc),
73911696c5eSBiju Das 				     "failed to get prst\n");
74011696c5eSBiju Das 
74111696c5eSBiju Das 	platform_set_drvdata(pdev, dsi);
74211696c5eSBiju Das 
74311696c5eSBiju Das 	pm_runtime_enable(dsi->dev);
74411696c5eSBiju Das 
74511696c5eSBiju Das 	ret = pm_runtime_resume_and_get(dsi->dev);
74611696c5eSBiju Das 	if (ret < 0)
74711696c5eSBiju Das 		goto err_pm_disable;
74811696c5eSBiju Das 
74911696c5eSBiju Das 	/*
75011696c5eSBiju Das 	 * TXSETR register can be read only after DPHY init. But during probe
75111696c5eSBiju Das 	 * mode->clock and format are not available. So initialize DPHY with
75211696c5eSBiju Das 	 * timing parameters for 80Mbps.
75311696c5eSBiju Das 	 */
75411696c5eSBiju Das 	ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000);
75511696c5eSBiju Das 	if (ret < 0)
75611696c5eSBiju Das 		goto err_phy;
75711696c5eSBiju Das 
75811696c5eSBiju Das 	txsetr = rzg2l_mipi_dsi_link_read(dsi, TXSETR);
75911696c5eSBiju Das 	dsi->num_data_lanes = min(((txsetr >> 16) & 3) + 1, num_data_lanes);
76011696c5eSBiju Das 	rzg2l_mipi_dsi_dphy_exit(dsi);
76111696c5eSBiju Das 	pm_runtime_put(dsi->dev);
76211696c5eSBiju Das 
76311696c5eSBiju Das 	/* Initialize the DRM bridge. */
76411696c5eSBiju Das 	dsi->bridge.funcs = &rzg2l_mipi_dsi_bridge_ops;
76511696c5eSBiju Das 	dsi->bridge.of_node = dsi->dev->of_node;
76611696c5eSBiju Das 
76711696c5eSBiju Das 	/* Init host device */
76811696c5eSBiju Das 	dsi->host.dev = dsi->dev;
76911696c5eSBiju Das 	dsi->host.ops = &rzg2l_mipi_dsi_host_ops;
77011696c5eSBiju Das 	ret = mipi_dsi_host_register(&dsi->host);
77111696c5eSBiju Das 	if (ret < 0)
77211696c5eSBiju Das 		goto err_pm_disable;
77311696c5eSBiju Das 
77411696c5eSBiju Das 	return 0;
77511696c5eSBiju Das 
77611696c5eSBiju Das err_phy:
77711696c5eSBiju Das 	rzg2l_mipi_dsi_dphy_exit(dsi);
77811696c5eSBiju Das 	pm_runtime_put(dsi->dev);
77911696c5eSBiju Das err_pm_disable:
78011696c5eSBiju Das 	pm_runtime_disable(dsi->dev);
78111696c5eSBiju Das 	return ret;
78211696c5eSBiju Das }
78311696c5eSBiju Das 
rzg2l_mipi_dsi_remove(struct platform_device * pdev)784*de8a334fSThomas Zimmermann static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
78511696c5eSBiju Das {
78611696c5eSBiju Das 	struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev);
78711696c5eSBiju Das 
78811696c5eSBiju Das 	mipi_dsi_host_unregister(&dsi->host);
78911696c5eSBiju Das 	pm_runtime_disable(&pdev->dev);
79011696c5eSBiju Das }
79111696c5eSBiju Das 
79211696c5eSBiju Das static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
79311696c5eSBiju Das 	{ .compatible = "renesas,rzg2l-mipi-dsi" },
79411696c5eSBiju Das 	{ /* sentinel */ }
79511696c5eSBiju Das };
79611696c5eSBiju Das 
79711696c5eSBiju Das MODULE_DEVICE_TABLE(of, rzg2l_mipi_dsi_of_table);
79811696c5eSBiju Das 
79911696c5eSBiju Das static struct platform_driver rzg2l_mipi_dsi_platform_driver = {
80011696c5eSBiju Das 	.probe	= rzg2l_mipi_dsi_probe,
801*de8a334fSThomas Zimmermann 	.remove_new = rzg2l_mipi_dsi_remove,
80211696c5eSBiju Das 	.driver	= {
80311696c5eSBiju Das 		.name = "rzg2l-mipi-dsi",
80411696c5eSBiju Das 		.pm = &rzg2l_mipi_pm_ops,
80511696c5eSBiju Das 		.of_match_table = rzg2l_mipi_dsi_of_table,
80611696c5eSBiju Das 	},
80711696c5eSBiju Das };
80811696c5eSBiju Das 
80911696c5eSBiju Das module_platform_driver(rzg2l_mipi_dsi_platform_driver);
81011696c5eSBiju Das 
81111696c5eSBiju Das MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
81211696c5eSBiju Das MODULE_DESCRIPTION("Renesas RZ/G2L MIPI DSI Encoder Driver");
81311696c5eSBiju Das MODULE_LICENSE("GPL");
814