18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com
48c2ecf20Sopenharmony_ci *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/device.h>
98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/media-bus-format.h>
138c2ecf20Sopenharmony_ci#include <linux/minmax.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/regmap.h>
168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
208c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h>
218c2ecf20Sopenharmony_ci#include <drm/drm_drv.h>
228c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h>
238c2ecf20Sopenharmony_ci#include <drm/drm_of.h>
248c2ecf20Sopenharmony_ci#include <drm/drm_panel.h>
258c2ecf20Sopenharmony_ci#include <video/mipi_display.h>
268c2ecf20Sopenharmony_ci#include <video/videomode.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Global (16-bit addressable) */
298c2ecf20Sopenharmony_ci#define TC358768_CHIPID			0x0000
308c2ecf20Sopenharmony_ci#define TC358768_SYSCTL			0x0002
318c2ecf20Sopenharmony_ci#define TC358768_CONFCTL		0x0004
328c2ecf20Sopenharmony_ci#define TC358768_VSDLY			0x0006
338c2ecf20Sopenharmony_ci#define TC358768_DATAFMT		0x0008
348c2ecf20Sopenharmony_ci#define TC358768_GPIOEN			0x000E
358c2ecf20Sopenharmony_ci#define TC358768_GPIODIR		0x0010
368c2ecf20Sopenharmony_ci#define TC358768_GPIOIN			0x0012
378c2ecf20Sopenharmony_ci#define TC358768_GPIOOUT		0x0014
388c2ecf20Sopenharmony_ci#define TC358768_PLLCTL0		0x0016
398c2ecf20Sopenharmony_ci#define TC358768_PLLCTL1		0x0018
408c2ecf20Sopenharmony_ci#define TC358768_CMDBYTE		0x0022
418c2ecf20Sopenharmony_ci#define TC358768_PP_MISC		0x0032
428c2ecf20Sopenharmony_ci#define TC358768_DSITX_DT		0x0050
438c2ecf20Sopenharmony_ci#define TC358768_FIFOSTATUS		0x00F8
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Debug (16-bit addressable) */
468c2ecf20Sopenharmony_ci#define TC358768_VBUFCTRL		0x00E0
478c2ecf20Sopenharmony_ci#define TC358768_DBG_WIDTH		0x00E2
488c2ecf20Sopenharmony_ci#define TC358768_DBG_VBLANK		0x00E4
498c2ecf20Sopenharmony_ci#define TC358768_DBG_DATA		0x00E8
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* TX PHY (32-bit addressable) */
528c2ecf20Sopenharmony_ci#define TC358768_CLW_DPHYCONTTX		0x0100
538c2ecf20Sopenharmony_ci#define TC358768_D0W_DPHYCONTTX		0x0104
548c2ecf20Sopenharmony_ci#define TC358768_D1W_DPHYCONTTX		0x0108
558c2ecf20Sopenharmony_ci#define TC358768_D2W_DPHYCONTTX		0x010C
568c2ecf20Sopenharmony_ci#define TC358768_D3W_DPHYCONTTX		0x0110
578c2ecf20Sopenharmony_ci#define TC358768_CLW_CNTRL		0x0140
588c2ecf20Sopenharmony_ci#define TC358768_D0W_CNTRL		0x0144
598c2ecf20Sopenharmony_ci#define TC358768_D1W_CNTRL		0x0148
608c2ecf20Sopenharmony_ci#define TC358768_D2W_CNTRL		0x014C
618c2ecf20Sopenharmony_ci#define TC358768_D3W_CNTRL		0x0150
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* TX PPI (32-bit addressable) */
648c2ecf20Sopenharmony_ci#define TC358768_STARTCNTRL		0x0204
658c2ecf20Sopenharmony_ci#define TC358768_DSITXSTATUS		0x0208
668c2ecf20Sopenharmony_ci#define TC358768_LINEINITCNT		0x0210
678c2ecf20Sopenharmony_ci#define TC358768_LPTXTIMECNT		0x0214
688c2ecf20Sopenharmony_ci#define TC358768_TCLK_HEADERCNT		0x0218
698c2ecf20Sopenharmony_ci#define TC358768_TCLK_TRAILCNT		0x021C
708c2ecf20Sopenharmony_ci#define TC358768_THS_HEADERCNT		0x0220
718c2ecf20Sopenharmony_ci#define TC358768_TWAKEUP		0x0224
728c2ecf20Sopenharmony_ci#define TC358768_TCLK_POSTCNT		0x0228
738c2ecf20Sopenharmony_ci#define TC358768_THS_TRAILCNT		0x022C
748c2ecf20Sopenharmony_ci#define TC358768_HSTXVREGCNT		0x0230
758c2ecf20Sopenharmony_ci#define TC358768_HSTXVREGEN		0x0234
768c2ecf20Sopenharmony_ci#define TC358768_TXOPTIONCNTRL		0x0238
778c2ecf20Sopenharmony_ci#define TC358768_BTACNTRL1		0x023C
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* TX CTRL (32-bit addressable) */
808c2ecf20Sopenharmony_ci#define TC358768_DSI_CONTROL		0x040C
818c2ecf20Sopenharmony_ci#define TC358768_DSI_STATUS		0x0410
828c2ecf20Sopenharmony_ci#define TC358768_DSI_INT		0x0414
838c2ecf20Sopenharmony_ci#define TC358768_DSI_INT_ENA		0x0418
848c2ecf20Sopenharmony_ci#define TC358768_DSICMD_RDFIFO		0x0430
858c2ecf20Sopenharmony_ci#define TC358768_DSI_ACKERR		0x0434
868c2ecf20Sopenharmony_ci#define TC358768_DSI_ACKERR_INTENA	0x0438
878c2ecf20Sopenharmony_ci#define TC358768_DSI_ACKERR_HALT	0x043c
888c2ecf20Sopenharmony_ci#define TC358768_DSI_RXERR		0x0440
898c2ecf20Sopenharmony_ci#define TC358768_DSI_RXERR_INTENA	0x0444
908c2ecf20Sopenharmony_ci#define TC358768_DSI_RXERR_HALT		0x0448
918c2ecf20Sopenharmony_ci#define TC358768_DSI_ERR		0x044C
928c2ecf20Sopenharmony_ci#define TC358768_DSI_ERR_INTENA		0x0450
938c2ecf20Sopenharmony_ci#define TC358768_DSI_ERR_HALT		0x0454
948c2ecf20Sopenharmony_ci#define TC358768_DSI_CONFW		0x0500
958c2ecf20Sopenharmony_ci#define TC358768_DSI_LPCMD		0x0500
968c2ecf20Sopenharmony_ci#define TC358768_DSI_RESET		0x0504
978c2ecf20Sopenharmony_ci#define TC358768_DSI_INT_CLR		0x050C
988c2ecf20Sopenharmony_ci#define TC358768_DSI_START		0x0518
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* DSITX CTRL (16-bit addressable) */
1018c2ecf20Sopenharmony_ci#define TC358768_DSICMD_TX		0x0600
1028c2ecf20Sopenharmony_ci#define TC358768_DSICMD_TYPE		0x0602
1038c2ecf20Sopenharmony_ci#define TC358768_DSICMD_WC		0x0604
1048c2ecf20Sopenharmony_ci#define TC358768_DSICMD_WD0		0x0610
1058c2ecf20Sopenharmony_ci#define TC358768_DSICMD_WD1		0x0612
1068c2ecf20Sopenharmony_ci#define TC358768_DSICMD_WD2		0x0614
1078c2ecf20Sopenharmony_ci#define TC358768_DSICMD_WD3		0x0616
1088c2ecf20Sopenharmony_ci#define TC358768_DSI_EVENT		0x0620
1098c2ecf20Sopenharmony_ci#define TC358768_DSI_VSW		0x0622
1108c2ecf20Sopenharmony_ci#define TC358768_DSI_VBPR		0x0624
1118c2ecf20Sopenharmony_ci#define TC358768_DSI_VACT		0x0626
1128c2ecf20Sopenharmony_ci#define TC358768_DSI_HSW		0x0628
1138c2ecf20Sopenharmony_ci#define TC358768_DSI_HBPR		0x062A
1148c2ecf20Sopenharmony_ci#define TC358768_DSI_HACT		0x062C
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/* TC358768_DSI_CONTROL (0x040C) register */
1178c2ecf20Sopenharmony_ci#define TC358768_DSI_CONTROL_DIS_MODE	BIT(15)
1188c2ecf20Sopenharmony_ci#define TC358768_DSI_CONTROL_TXMD	BIT(7)
1198c2ecf20Sopenharmony_ci#define TC358768_DSI_CONTROL_HSCKMD	BIT(5)
1208c2ecf20Sopenharmony_ci#define TC358768_DSI_CONTROL_EOTDIS	BIT(0)
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* TC358768_DSI_CONFW (0x0500) register */
1238c2ecf20Sopenharmony_ci#define TC358768_DSI_CONFW_MODE_SET	(5 << 29)
1248c2ecf20Sopenharmony_ci#define TC358768_DSI_CONFW_MODE_CLR	(6 << 29)
1258c2ecf20Sopenharmony_ci#define TC358768_DSI_CONFW_ADDR_DSI_CONTROL	(0x3 << 24)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic const char * const tc358768_supplies[] = {
1288c2ecf20Sopenharmony_ci	"vddc", "vddmipi", "vddio"
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct tc358768_dsi_output {
1328c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dev;
1338c2ecf20Sopenharmony_ci	struct drm_panel *panel;
1348c2ecf20Sopenharmony_ci	struct drm_bridge *bridge;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistruct tc358768_priv {
1388c2ecf20Sopenharmony_ci	struct device *dev;
1398c2ecf20Sopenharmony_ci	struct regmap *regmap;
1408c2ecf20Sopenharmony_ci	struct gpio_desc *reset_gpio;
1418c2ecf20Sopenharmony_ci	struct regulator_bulk_data supplies[ARRAY_SIZE(tc358768_supplies)];
1428c2ecf20Sopenharmony_ci	struct clk *refclk;
1438c2ecf20Sopenharmony_ci	int enabled;
1448c2ecf20Sopenharmony_ci	int error;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	struct mipi_dsi_host dsi_host;
1478c2ecf20Sopenharmony_ci	struct drm_bridge bridge;
1488c2ecf20Sopenharmony_ci	struct tc358768_dsi_output output;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	u32 pd_lines; /* number of Parallel Port Input Data Lines */
1518c2ecf20Sopenharmony_ci	u32 dsi_lanes; /* number of DSI Lanes */
1528c2ecf20Sopenharmony_ci	u32 dsi_bpp; /* number of Bits Per Pixel over DSI */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Parameters for PLL programming */
1558c2ecf20Sopenharmony_ci	u32 fbd;	/* PLL feedback divider */
1568c2ecf20Sopenharmony_ci	u32 prd;	/* PLL input divider */
1578c2ecf20Sopenharmony_ci	u32 frs;	/* PLL Freqency range for HSCK (post divider) */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	u32 dsiclk;	/* pll_clk / 2 */
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic inline struct tc358768_priv *dsi_host_to_tc358768(struct mipi_dsi_host
1638c2ecf20Sopenharmony_ci							 *host)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	return container_of(host, struct tc358768_priv, dsi_host);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic inline struct tc358768_priv *bridge_to_tc358768(struct drm_bridge
1698c2ecf20Sopenharmony_ci						       *bridge)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	return container_of(bridge, struct tc358768_priv, bridge);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int tc358768_clear_error(struct tc358768_priv *priv)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	int ret = priv->error;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	priv->error = 0;
1798c2ecf20Sopenharmony_ci	return ret;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void tc358768_write(struct tc358768_priv *priv, u32 reg, u32 val)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	/* work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
1858c2ecf20Sopenharmony_ci	int tmpval = val;
1868c2ecf20Sopenharmony_ci	size_t count = 2;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (priv->error)
1898c2ecf20Sopenharmony_ci		return;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* 16-bit register? */
1928c2ecf20Sopenharmony_ci	if (reg < 0x100 || reg >= 0x600)
1938c2ecf20Sopenharmony_ci		count = 1;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	priv->error = regmap_bulk_write(priv->regmap, reg, &tmpval, count);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void tc358768_read(struct tc358768_priv *priv, u32 reg, u32 *val)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	size_t count = 2;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (priv->error)
2038c2ecf20Sopenharmony_ci		return;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* 16-bit register? */
2068c2ecf20Sopenharmony_ci	if (reg < 0x100 || reg >= 0x600) {
2078c2ecf20Sopenharmony_ci		*val = 0;
2088c2ecf20Sopenharmony_ci		count = 1;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	priv->error = regmap_bulk_read(priv->regmap, reg, val, count);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic void tc358768_update_bits(struct tc358768_priv *priv, u32 reg, u32 mask,
2158c2ecf20Sopenharmony_ci				 u32 val)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	u32 tmp, orig;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	tc358768_read(priv, reg, &orig);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (priv->error)
2228c2ecf20Sopenharmony_ci		return;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	tmp = orig & ~mask;
2258c2ecf20Sopenharmony_ci	tmp |= val & mask;
2268c2ecf20Sopenharmony_ci	if (tmp != orig)
2278c2ecf20Sopenharmony_ci		tc358768_write(priv, reg, tmp);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int tc358768_sw_reset(struct tc358768_priv *priv)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	/* Assert Reset */
2338c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_SYSCTL, 1);
2348c2ecf20Sopenharmony_ci	/* Release Reset, Exit Sleep */
2358c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_SYSCTL, 0);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return tc358768_clear_error(priv);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic void tc358768_hw_enable(struct tc358768_priv *priv)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	int ret;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (priv->enabled)
2458c2ecf20Sopenharmony_ci		return;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
2488c2ecf20Sopenharmony_ci	if (ret < 0)
2498c2ecf20Sopenharmony_ci		dev_err(priv->dev, "error enabling regulators (%d)\n", ret);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (priv->reset_gpio)
2528c2ecf20Sopenharmony_ci		usleep_range(200, 300);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * The RESX is active low (GPIO_ACTIVE_LOW).
2568c2ecf20Sopenharmony_ci	 * DEASSERT (value = 0) the reset_gpio to enable the chip
2578c2ecf20Sopenharmony_ci	 */
2588c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(priv->reset_gpio, 0);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* wait for encoder clocks to stabilize */
2618c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	priv->enabled = true;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic void tc358768_hw_disable(struct tc358768_priv *priv)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	int ret;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!priv->enabled)
2718c2ecf20Sopenharmony_ci		return;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * The RESX is active low (GPIO_ACTIVE_LOW).
2758c2ecf20Sopenharmony_ci	 * ASSERT (value = 1) the reset_gpio to disable the chip
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(priv->reset_gpio, 1);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
2808c2ecf20Sopenharmony_ci				     priv->supplies);
2818c2ecf20Sopenharmony_ci	if (ret < 0)
2828c2ecf20Sopenharmony_ci		dev_err(priv->dev, "error disabling regulators (%d)\n", ret);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	priv->enabled = false;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic u32 tc358768_pll_to_pclk(struct tc358768_priv *priv, u32 pll_clk)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->dsi_bpp);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic u32 tc358768_pclk_to_pll(struct tc358768_priv *priv, u32 pclk)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	return (u32)div_u64((u64)pclk * priv->dsi_bpp, priv->dsi_lanes);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int tc358768_calc_pll(struct tc358768_priv *priv,
2988c2ecf20Sopenharmony_ci			     const struct drm_display_mode *mode,
2998c2ecf20Sopenharmony_ci			     bool verify_only)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	const u32 frs_limits[] = {
3028c2ecf20Sopenharmony_ci		1000000000,
3038c2ecf20Sopenharmony_ci		500000000,
3048c2ecf20Sopenharmony_ci		250000000,
3058c2ecf20Sopenharmony_ci		125000000,
3068c2ecf20Sopenharmony_ci		62500000
3078c2ecf20Sopenharmony_ci	};
3088c2ecf20Sopenharmony_ci	unsigned long refclk;
3098c2ecf20Sopenharmony_ci	u32 prd, target_pll, i, max_pll, min_pll;
3108c2ecf20Sopenharmony_ci	u32 frs, best_diff, best_pll, best_prd, best_fbd;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	target_pll = tc358768_pclk_to_pll(priv, mode->clock * 1000);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* pll_clk = RefClk * [(FBD + 1)/ (PRD + 1)] * [1 / (2^FRS)] */
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(frs_limits); i++)
3178c2ecf20Sopenharmony_ci		if (target_pll >= frs_limits[i])
3188c2ecf20Sopenharmony_ci			break;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(frs_limits) || i == 0)
3218c2ecf20Sopenharmony_ci		return -EINVAL;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	frs = i - 1;
3248c2ecf20Sopenharmony_ci	max_pll = frs_limits[i - 1];
3258c2ecf20Sopenharmony_ci	min_pll = frs_limits[i];
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	refclk = clk_get_rate(priv->refclk);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	best_diff = UINT_MAX;
3308c2ecf20Sopenharmony_ci	best_pll = 0;
3318c2ecf20Sopenharmony_ci	best_prd = 0;
3328c2ecf20Sopenharmony_ci	best_fbd = 0;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	for (prd = 0; prd < 16; ++prd) {
3358c2ecf20Sopenharmony_ci		u32 divisor = (prd + 1) * (1 << frs);
3368c2ecf20Sopenharmony_ci		u32 fbd;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		for (fbd = 0; fbd < 512; ++fbd) {
3398c2ecf20Sopenharmony_ci			u32 pll, diff, pll_in;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci			pll = (u32)div_u64((u64)refclk * (fbd + 1), divisor);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci			if (pll >= max_pll || pll < min_pll)
3448c2ecf20Sopenharmony_ci				continue;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci			pll_in = (u32)div_u64((u64)refclk, prd + 1);
3478c2ecf20Sopenharmony_ci			if (pll_in < 4000000)
3488c2ecf20Sopenharmony_ci				continue;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci			diff = max(pll, target_pll) - min(pll, target_pll);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci			if (diff < best_diff) {
3538c2ecf20Sopenharmony_ci				best_diff = diff;
3548c2ecf20Sopenharmony_ci				best_pll = pll;
3558c2ecf20Sopenharmony_ci				best_prd = prd;
3568c2ecf20Sopenharmony_ci				best_fbd = fbd;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci				if (best_diff == 0)
3598c2ecf20Sopenharmony_ci					goto found;
3608c2ecf20Sopenharmony_ci			}
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (best_diff == UINT_MAX) {
3658c2ecf20Sopenharmony_ci		dev_err(priv->dev, "could not find suitable PLL setup\n");
3668c2ecf20Sopenharmony_ci		return -EINVAL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cifound:
3708c2ecf20Sopenharmony_ci	if (verify_only)
3718c2ecf20Sopenharmony_ci		return 0;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	priv->fbd = best_fbd;
3748c2ecf20Sopenharmony_ci	priv->prd = best_prd;
3758c2ecf20Sopenharmony_ci	priv->frs = frs;
3768c2ecf20Sopenharmony_ci	priv->dsiclk = best_pll / 2;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return 0;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
3828c2ecf20Sopenharmony_ci				    struct mipi_dsi_device *dev)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = dsi_host_to_tc358768(host);
3858c2ecf20Sopenharmony_ci	struct drm_bridge *bridge;
3868c2ecf20Sopenharmony_ci	struct drm_panel *panel;
3878c2ecf20Sopenharmony_ci	struct device_node *ep;
3888c2ecf20Sopenharmony_ci	int ret;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (dev->lanes > 4) {
3918c2ecf20Sopenharmony_ci		dev_err(priv->dev, "unsupported number of data lanes(%u)\n",
3928c2ecf20Sopenharmony_ci			dev->lanes);
3938c2ecf20Sopenharmony_ci		return -EINVAL;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/*
3978c2ecf20Sopenharmony_ci	 * tc358768 supports both Video and Pulse mode, but the driver only
3988c2ecf20Sopenharmony_ci	 * implements Video (event) mode currently
3998c2ecf20Sopenharmony_ci	 */
4008c2ecf20Sopenharmony_ci	if (!(dev->mode_flags & MIPI_DSI_MODE_VIDEO)) {
4018c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Only MIPI_DSI_MODE_VIDEO is supported\n");
4028c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/*
4068c2ecf20Sopenharmony_ci	 * tc358768 supports RGB888, RGB666, RGB666_PACKED and RGB565, but only
4078c2ecf20Sopenharmony_ci	 * RGB888 is verified.
4088c2ecf20Sopenharmony_ci	 */
4098c2ecf20Sopenharmony_ci	if (dev->format != MIPI_DSI_FMT_RGB888) {
4108c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "Only MIPI_DSI_FMT_RGB888 tested!\n");
4118c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel,
4158c2ecf20Sopenharmony_ci					  &bridge);
4168c2ecf20Sopenharmony_ci	if (ret)
4178c2ecf20Sopenharmony_ci		return ret;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (panel) {
4208c2ecf20Sopenharmony_ci		bridge = drm_panel_bridge_add_typed(panel,
4218c2ecf20Sopenharmony_ci						    DRM_MODE_CONNECTOR_DSI);
4228c2ecf20Sopenharmony_ci		if (IS_ERR(bridge))
4238c2ecf20Sopenharmony_ci			return PTR_ERR(bridge);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	priv->output.dev = dev;
4278c2ecf20Sopenharmony_ci	priv->output.bridge = bridge;
4288c2ecf20Sopenharmony_ci	priv->output.panel = panel;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	priv->dsi_lanes = dev->lanes;
4318c2ecf20Sopenharmony_ci	priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* get input ep (port0/endpoint0) */
4348c2ecf20Sopenharmony_ci	ret = -EINVAL;
4358c2ecf20Sopenharmony_ci	ep = of_graph_get_endpoint_by_regs(host->dev->of_node, 0, 0);
4368c2ecf20Sopenharmony_ci	if (ep) {
4378c2ecf20Sopenharmony_ci		ret = of_property_read_u32(ep, "data-lines", &priv->pd_lines);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		of_node_put(ep);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (ret)
4438c2ecf20Sopenharmony_ci		priv->pd_lines = priv->dsi_bpp;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	drm_bridge_add(&priv->bridge);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int tc358768_dsi_host_detach(struct mipi_dsi_host *host,
4518c2ecf20Sopenharmony_ci				    struct mipi_dsi_device *dev)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = dsi_host_to_tc358768(host);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	drm_bridge_remove(&priv->bridge);
4568c2ecf20Sopenharmony_ci	if (priv->output.panel)
4578c2ecf20Sopenharmony_ci		drm_panel_bridge_remove(priv->output.bridge);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic ssize_t tc358768_dsi_host_transfer(struct mipi_dsi_host *host,
4638c2ecf20Sopenharmony_ci					  const struct mipi_dsi_msg *msg)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = dsi_host_to_tc358768(host);
4668c2ecf20Sopenharmony_ci	struct mipi_dsi_packet packet;
4678c2ecf20Sopenharmony_ci	int ret;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (!priv->enabled) {
4708c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Bridge is not enabled\n");
4718c2ecf20Sopenharmony_ci		return -ENODEV;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (msg->rx_len) {
4758c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "MIPI rx is not supported\n");
4768c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (msg->tx_len > 8) {
4808c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "Maximum 8 byte MIPI tx is supported\n");
4818c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	ret = mipi_dsi_create_packet(&packet, msg);
4858c2ecf20Sopenharmony_ci	if (ret)
4868c2ecf20Sopenharmony_ci		return ret;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (mipi_dsi_packet_format_is_short(msg->type)) {
4898c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_DSICMD_TYPE,
4908c2ecf20Sopenharmony_ci			       (0x10 << 8) | (packet.header[0] & 0x3f));
4918c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_DSICMD_WC, 0);
4928c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_DSICMD_WD0,
4938c2ecf20Sopenharmony_ci			       (packet.header[2] << 8) | packet.header[1]);
4948c2ecf20Sopenharmony_ci	} else {
4958c2ecf20Sopenharmony_ci		int i;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_DSICMD_TYPE,
4988c2ecf20Sopenharmony_ci			       (0x40 << 8) | (packet.header[0] & 0x3f));
4998c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_DSICMD_WC, packet.payload_length);
5008c2ecf20Sopenharmony_ci		for (i = 0; i < packet.payload_length; i += 2) {
5018c2ecf20Sopenharmony_ci			u16 val = packet.payload[i];
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci			if (i + 1 < packet.payload_length)
5048c2ecf20Sopenharmony_ci				val |= packet.payload[i + 1] << 8;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci			tc358768_write(priv, TC358768_DSICMD_WD0 + i, val);
5078c2ecf20Sopenharmony_ci		}
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* start transfer */
5118c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSICMD_TX, 1);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	ret = tc358768_clear_error(priv);
5148c2ecf20Sopenharmony_ci	if (ret)
5158c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "Software disable failed: %d\n", ret);
5168c2ecf20Sopenharmony_ci	else
5178c2ecf20Sopenharmony_ci		ret = packet.size;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return ret;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic const struct mipi_dsi_host_ops tc358768_dsi_host_ops = {
5238c2ecf20Sopenharmony_ci	.attach = tc358768_dsi_host_attach,
5248c2ecf20Sopenharmony_ci	.detach = tc358768_dsi_host_detach,
5258c2ecf20Sopenharmony_ci	.transfer = tc358768_dsi_host_transfer,
5268c2ecf20Sopenharmony_ci};
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic int tc358768_bridge_attach(struct drm_bridge *bridge,
5298c2ecf20Sopenharmony_ci				  enum drm_bridge_attach_flags flags)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) {
5348c2ecf20Sopenharmony_ci		dev_err(priv->dev, "needs atomic updates support\n");
5358c2ecf20Sopenharmony_ci		return -ENOTSUPP;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge,
5398c2ecf20Sopenharmony_ci				 flags);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic enum drm_mode_status
5438c2ecf20Sopenharmony_citc358768_bridge_mode_valid(struct drm_bridge *bridge,
5448c2ecf20Sopenharmony_ci			   const struct drm_display_info *info,
5458c2ecf20Sopenharmony_ci			   const struct drm_display_mode *mode)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (tc358768_calc_pll(priv, mode, true))
5508c2ecf20Sopenharmony_ci		return MODE_CLOCK_RANGE;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return MODE_OK;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic void tc358768_bridge_disable(struct drm_bridge *bridge)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
5588c2ecf20Sopenharmony_ci	int ret;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/* set FrmStop */
5618c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_PP_MISC, BIT(15), BIT(15));
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	/* wait at least for one frame */
5648c2ecf20Sopenharmony_ci	msleep(50);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	/* clear PP_en */
5678c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_CONFCTL, BIT(6), 0);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* set RstPtr */
5708c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_PP_MISC, BIT(14), BIT(14));
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	ret = tc358768_clear_error(priv);
5738c2ecf20Sopenharmony_ci	if (ret)
5748c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "Software disable failed: %d\n", ret);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic void tc358768_bridge_post_disable(struct drm_bridge *bridge)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	tc358768_hw_disable(priv);
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int tc358768_setup_pll(struct tc358768_priv *priv,
5858c2ecf20Sopenharmony_ci			      const struct drm_display_mode *mode)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	u32 fbd, prd, frs;
5888c2ecf20Sopenharmony_ci	int ret;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	ret = tc358768_calc_pll(priv, mode, false);
5918c2ecf20Sopenharmony_ci	if (ret) {
5928c2ecf20Sopenharmony_ci		dev_err(priv->dev, "PLL calculation failed: %d\n", ret);
5938c2ecf20Sopenharmony_ci		return ret;
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	fbd = priv->fbd;
5978c2ecf20Sopenharmony_ci	prd = priv->prd;
5988c2ecf20Sopenharmony_ci	frs = priv->frs;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "PLL: refclk %lu, fbd %u, prd %u, frs %u\n",
6018c2ecf20Sopenharmony_ci		clk_get_rate(priv->refclk), fbd, prd, frs);
6028c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "PLL: pll_clk: %u, DSIClk %u, DSIByteClk %u\n",
6038c2ecf20Sopenharmony_ci		priv->dsiclk * 2, priv->dsiclk, priv->dsiclk / 4);
6048c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "PLL: pclk %u (panel: %u)\n",
6058c2ecf20Sopenharmony_ci		tc358768_pll_to_pclk(priv, priv->dsiclk * 2),
6068c2ecf20Sopenharmony_ci		mode->clock * 1000);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	/* PRD[15:12] FBD[8:0] */
6098c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_PLLCTL0, (prd << 12) | fbd);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	/* FRS[11:10] LBWS[9:8] CKEN[4] RESETB[1] EN[0] */
6128c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_PLLCTL1,
6138c2ecf20Sopenharmony_ci		       (frs << 10) | (0x2 << 8) | BIT(1) | BIT(0));
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* wait for lock */
6168c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	/* FRS[11:10] LBWS[9:8] CKEN[4] PLL_CKEN[4] RESETB[1] EN[0] */
6198c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_PLLCTL1,
6208c2ecf20Sopenharmony_ci		       (frs << 10) | (0x2 << 8) | BIT(4) | BIT(1) | BIT(0));
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	return tc358768_clear_error(priv);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci#define TC358768_PRECISION	1000
6268c2ecf20Sopenharmony_cistatic u32 tc358768_ns_to_cnt(u32 ns, u32 period_nsk)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	return (ns * TC358768_PRECISION + period_nsk) / period_nsk;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic u32 tc358768_to_ns(u32 nsk)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	return (nsk / TC358768_PRECISION);
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
6398c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi_dev = priv->output.dev;
6408c2ecf20Sopenharmony_ci	unsigned long mode_flags = dsi_dev->mode_flags;
6418c2ecf20Sopenharmony_ci	u32 val, val2, lptxcnt, hact, data_type;
6428c2ecf20Sopenharmony_ci	s32 raw_val;
6438c2ecf20Sopenharmony_ci	const struct drm_display_mode *mode;
6448c2ecf20Sopenharmony_ci	u32 dsibclk_nsk, dsiclk_nsk, ui_nsk, phy_delay_nsk;
6458c2ecf20Sopenharmony_ci	u32 dsiclk, dsibclk;
6468c2ecf20Sopenharmony_ci	int ret, i;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
6498c2ecf20Sopenharmony_ci		dev_warn_once(priv->dev, "Non-continuous mode unimplemented, falling back to continuous\n");
6508c2ecf20Sopenharmony_ci		mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	tc358768_hw_enable(priv);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	ret = tc358768_sw_reset(priv);
6568c2ecf20Sopenharmony_ci	if (ret) {
6578c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Software reset failed: %d\n", ret);
6588c2ecf20Sopenharmony_ci		tc358768_hw_disable(priv);
6598c2ecf20Sopenharmony_ci		return;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	mode = &bridge->encoder->crtc->state->adjusted_mode;
6638c2ecf20Sopenharmony_ci	ret = tc358768_setup_pll(priv, mode);
6648c2ecf20Sopenharmony_ci	if (ret) {
6658c2ecf20Sopenharmony_ci		dev_err(priv->dev, "PLL setup failed: %d\n", ret);
6668c2ecf20Sopenharmony_ci		tc358768_hw_disable(priv);
6678c2ecf20Sopenharmony_ci		return;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	dsiclk = priv->dsiclk;
6718c2ecf20Sopenharmony_ci	dsibclk = dsiclk / 4;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	/* Data Format Control Register */
6748c2ecf20Sopenharmony_ci	val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */
6758c2ecf20Sopenharmony_ci	switch (dsi_dev->format) {
6768c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB888:
6778c2ecf20Sopenharmony_ci		val |= (0x3 << 4);
6788c2ecf20Sopenharmony_ci		hact = mode->hdisplay * 3;
6798c2ecf20Sopenharmony_ci		data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
6808c2ecf20Sopenharmony_ci		break;
6818c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666:
6828c2ecf20Sopenharmony_ci		val |= (0x4 << 4);
6838c2ecf20Sopenharmony_ci		hact = mode->hdisplay * 3;
6848c2ecf20Sopenharmony_ci		data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
6858c2ecf20Sopenharmony_ci		break;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666_PACKED:
6888c2ecf20Sopenharmony_ci		val |= (0x4 << 4) | BIT(3);
6898c2ecf20Sopenharmony_ci		hact = mode->hdisplay * 18 / 8;
6908c2ecf20Sopenharmony_ci		data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
6918c2ecf20Sopenharmony_ci		break;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB565:
6948c2ecf20Sopenharmony_ci		val |= (0x5 << 4);
6958c2ecf20Sopenharmony_ci		hact = mode->hdisplay * 2;
6968c2ecf20Sopenharmony_ci		data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
6978c2ecf20Sopenharmony_ci		break;
6988c2ecf20Sopenharmony_ci	default:
6998c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Invalid data format (%u)\n",
7008c2ecf20Sopenharmony_ci			dsi_dev->format);
7018c2ecf20Sopenharmony_ci		tc358768_hw_disable(priv);
7028c2ecf20Sopenharmony_ci		return;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/* VSDly[9:0] */
7068c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_VSDLY, 1);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DATAFMT, val);
7098c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSITX_DT, data_type);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	/* Enable D-PHY (HiZ->LP11) */
7128c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_CLW_CNTRL, 0x0000);
7138c2ecf20Sopenharmony_ci	/* Enable lanes */
7148c2ecf20Sopenharmony_ci	for (i = 0; i < dsi_dev->lanes; i++)
7158c2ecf20Sopenharmony_ci		tc358768_write(priv, TC358768_D0W_CNTRL + i * 4, 0x0000);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	/* DSI Timings */
7188c2ecf20Sopenharmony_ci	dsibclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION,
7198c2ecf20Sopenharmony_ci				  dsibclk);
7208c2ecf20Sopenharmony_ci	dsiclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, dsiclk);
7218c2ecf20Sopenharmony_ci	ui_nsk = dsiclk_nsk / 2;
7228c2ecf20Sopenharmony_ci	phy_delay_nsk = dsibclk_nsk + 2 * dsiclk_nsk;
7238c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "dsiclk_nsk: %u\n", dsiclk_nsk);
7248c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "ui_nsk: %u\n", ui_nsk);
7258c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "dsibclk_nsk: %u\n", dsibclk_nsk);
7268c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "phy_delay_nsk: %u\n", phy_delay_nsk);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	/* LP11 > 100us for D-PHY Rx Init */
7298c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(100 * 1000, dsibclk_nsk) - 1;
7308c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "LINEINITCNT: 0x%x\n", val);
7318c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_LINEINITCNT, val);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* LPTimeCnt > 50ns */
7348c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(50, dsibclk_nsk) - 1;
7358c2ecf20Sopenharmony_ci	lptxcnt = val;
7368c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "LPTXTIMECNT: 0x%x\n", val);
7378c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_LPTXTIMECNT, val);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	/* 38ns < TCLK_PREPARE < 95ns */
7408c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1;
7418c2ecf20Sopenharmony_ci	/* TCLK_PREPARE + TCLK_ZERO > 300ns */
7428c2ecf20Sopenharmony_ci	val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk),
7438c2ecf20Sopenharmony_ci				  dsibclk_nsk) - 2;
7448c2ecf20Sopenharmony_ci	val |= val2 << 8;
7458c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val);
7468c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_TCLK_HEADERCNT, val);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* TCLK_TRAIL > 60ns AND TEOT <= 105 ns + 12*UI */
7498c2ecf20Sopenharmony_ci	raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(2 * ui_nsk), dsibclk_nsk) - 5;
7508c2ecf20Sopenharmony_ci	val = clamp(raw_val, 0, 127);
7518c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\n", val);
7528c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_TCLK_TRAILCNT, val);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/* 40ns + 4*UI < THS_PREPARE < 85ns + 6*UI */
7558c2ecf20Sopenharmony_ci	val = 50 + tc358768_to_ns(4 * ui_nsk);
7568c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1;
7578c2ecf20Sopenharmony_ci	/* THS_PREPARE + THS_ZERO > 145ns + 10*UI */
7588c2ecf20Sopenharmony_ci	raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10;
7598c2ecf20Sopenharmony_ci	val2 = clamp(raw_val, 0, 127);
7608c2ecf20Sopenharmony_ci	val |= val2 << 8;
7618c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val);
7628c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_THS_HEADERCNT, val);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* TWAKEUP > 1ms in lptxcnt steps */
7658c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(1020000, dsibclk_nsk);
7668c2ecf20Sopenharmony_ci	val = val / (lptxcnt + 1) - 1;
7678c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "TWAKEUP: 0x%x\n", val);
7688c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_TWAKEUP, val);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	/* TCLK_POSTCNT > 60ns + 52*UI */
7718c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(60 + tc358768_to_ns(52 * ui_nsk),
7728c2ecf20Sopenharmony_ci				 dsibclk_nsk) - 3;
7738c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val);
7748c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_TCLK_POSTCNT, val);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* max(60ns + 4*UI, 8*UI) < THS_TRAILCNT < 105ns + 12*UI */
7778c2ecf20Sopenharmony_ci	raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(18 * ui_nsk),
7788c2ecf20Sopenharmony_ci				     dsibclk_nsk) - 4;
7798c2ecf20Sopenharmony_ci	val = clamp(raw_val, 0, 15);
7808c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val);
7818c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_THS_TRAILCNT, val);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	val = BIT(0);
7848c2ecf20Sopenharmony_ci	for (i = 0; i < dsi_dev->lanes; i++)
7858c2ecf20Sopenharmony_ci		val |= BIT(i + 1);
7868c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_HSTXVREGEN, val);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_TXOPTIONCNTRL,
7898c2ecf20Sopenharmony_ci		       (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0));
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	/* TXTAGOCNT[26:16] RXTASURECNT[10:0] */
7928c2ecf20Sopenharmony_ci	val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4);
7938c2ecf20Sopenharmony_ci	val = tc358768_ns_to_cnt(val, dsibclk_nsk) / 4 - 1;
7948c2ecf20Sopenharmony_ci	val2 = tc358768_ns_to_cnt(tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk),
7958c2ecf20Sopenharmony_ci				  dsibclk_nsk) - 2;
7968c2ecf20Sopenharmony_ci	val |= val2 << 16;
7978c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "BTACNTRL1: 0x%x\n", val);
7988c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_BTACNTRL1, val);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	/* START[0] */
8018c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_STARTCNTRL, 1);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	/* Set event mode */
8048c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_EVENT, 1);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	/* vsw (+ vbp) */
8078c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_VSW,
8088c2ecf20Sopenharmony_ci		       mode->vtotal - mode->vsync_start);
8098c2ecf20Sopenharmony_ci	/* vbp (not used in event mode) */
8108c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_VBPR, 0);
8118c2ecf20Sopenharmony_ci	/* vact */
8128c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_VACT, mode->vdisplay);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/* (hsw + hbp) * byteclk * ndl / pclk */
8158c2ecf20Sopenharmony_ci	val = (u32)div_u64((mode->htotal - mode->hsync_start) *
8168c2ecf20Sopenharmony_ci			   ((u64)priv->dsiclk / 4) * priv->dsi_lanes,
8178c2ecf20Sopenharmony_ci			   mode->clock * 1000);
8188c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_HSW, val);
8198c2ecf20Sopenharmony_ci	/* hbp (not used in event mode) */
8208c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_HBPR, 0);
8218c2ecf20Sopenharmony_ci	/* hact (bytes) */
8228c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_HACT, hact);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	/* VSYNC polarity */
8258c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_CONFCTL, BIT(5),
8268c2ecf20Sopenharmony_ci			     (mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIT(5) : 0);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/* HSYNC polarity */
8298c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_PP_MISC, BIT(0),
8308c2ecf20Sopenharmony_ci			     (mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIT(0) : 0);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	/* Start DSI Tx */
8338c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_START, 0x1);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/* Configure DSI_Control register */
8368c2ecf20Sopenharmony_ci	val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
8378c2ecf20Sopenharmony_ci	val |= TC358768_DSI_CONTROL_TXMD | TC358768_DSI_CONTROL_HSCKMD |
8388c2ecf20Sopenharmony_ci	       0x3 << 1 | TC358768_DSI_CONTROL_EOTDIS;
8398c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_CONFW, val);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
8428c2ecf20Sopenharmony_ci	val |= (dsi_dev->lanes - 1) << 1;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	val |= TC358768_DSI_CONTROL_TXMD;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
8478c2ecf20Sopenharmony_ci		val |= TC358768_DSI_CONTROL_HSCKMD;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (dsi_dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
8508c2ecf20Sopenharmony_ci		val |= TC358768_DSI_CONTROL_EOTDIS;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_CONFW, val);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
8558c2ecf20Sopenharmony_ci	val |= TC358768_DSI_CONTROL_DIS_MODE; /* DSI mode */
8568c2ecf20Sopenharmony_ci	tc358768_write(priv, TC358768_DSI_CONFW, val);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	ret = tc358768_clear_error(priv);
8598c2ecf20Sopenharmony_ci	if (ret) {
8608c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Bridge pre_enable failed: %d\n", ret);
8618c2ecf20Sopenharmony_ci		tc358768_bridge_disable(bridge);
8628c2ecf20Sopenharmony_ci		tc358768_bridge_post_disable(bridge);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic void tc358768_bridge_enable(struct drm_bridge *bridge)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
8698c2ecf20Sopenharmony_ci	int ret;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (!priv->enabled) {
8728c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Bridge is not enabled\n");
8738c2ecf20Sopenharmony_ci		return;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* clear FrmStop and RstPtr */
8778c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_PP_MISC, 0x3 << 14, 0);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* set PP_en */
8808c2ecf20Sopenharmony_ci	tc358768_update_bits(priv, TC358768_CONFCTL, BIT(6), BIT(6));
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	ret = tc358768_clear_error(priv);
8838c2ecf20Sopenharmony_ci	if (ret) {
8848c2ecf20Sopenharmony_ci		dev_err(priv->dev, "Bridge enable failed: %d\n", ret);
8858c2ecf20Sopenharmony_ci		tc358768_bridge_disable(bridge);
8868c2ecf20Sopenharmony_ci		tc358768_bridge_post_disable(bridge);
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci#define MAX_INPUT_SEL_FORMATS	1
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic u32 *
8938c2ecf20Sopenharmony_citc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
8948c2ecf20Sopenharmony_ci				   struct drm_bridge_state *bridge_state,
8958c2ecf20Sopenharmony_ci				   struct drm_crtc_state *crtc_state,
8968c2ecf20Sopenharmony_ci				   struct drm_connector_state *conn_state,
8978c2ecf20Sopenharmony_ci				   u32 output_fmt,
8988c2ecf20Sopenharmony_ci				   unsigned int *num_input_fmts)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = bridge_to_tc358768(bridge);
9018c2ecf20Sopenharmony_ci	u32 *input_fmts;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	*num_input_fmts = 0;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
9068c2ecf20Sopenharmony_ci			     GFP_KERNEL);
9078c2ecf20Sopenharmony_ci	if (!input_fmts)
9088c2ecf20Sopenharmony_ci		return NULL;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	switch (priv->pd_lines) {
9118c2ecf20Sopenharmony_ci	case 16:
9128c2ecf20Sopenharmony_ci		input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16;
9138c2ecf20Sopenharmony_ci		break;
9148c2ecf20Sopenharmony_ci	case 18:
9158c2ecf20Sopenharmony_ci		input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18;
9168c2ecf20Sopenharmony_ci		break;
9178c2ecf20Sopenharmony_ci	default:
9188c2ecf20Sopenharmony_ci	case 24:
9198c2ecf20Sopenharmony_ci		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci	};
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	*num_input_fmts = MAX_INPUT_SEL_FORMATS;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	return input_fmts;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs tc358768_bridge_funcs = {
9298c2ecf20Sopenharmony_ci	.attach = tc358768_bridge_attach,
9308c2ecf20Sopenharmony_ci	.mode_valid = tc358768_bridge_mode_valid,
9318c2ecf20Sopenharmony_ci	.pre_enable = tc358768_bridge_pre_enable,
9328c2ecf20Sopenharmony_ci	.enable = tc358768_bridge_enable,
9338c2ecf20Sopenharmony_ci	.disable = tc358768_bridge_disable,
9348c2ecf20Sopenharmony_ci	.post_disable = tc358768_bridge_post_disable,
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
9378c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
9388c2ecf20Sopenharmony_ci	.atomic_reset = drm_atomic_helper_bridge_reset,
9398c2ecf20Sopenharmony_ci	.atomic_get_input_bus_fmts = tc358768_atomic_get_input_bus_fmts,
9408c2ecf20Sopenharmony_ci};
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic const struct drm_bridge_timings default_tc358768_timings = {
9438c2ecf20Sopenharmony_ci	.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
9448c2ecf20Sopenharmony_ci		 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE
9458c2ecf20Sopenharmony_ci		 | DRM_BUS_FLAG_DE_HIGH,
9468c2ecf20Sopenharmony_ci};
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic bool tc358768_is_reserved_reg(unsigned int reg)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	switch (reg) {
9518c2ecf20Sopenharmony_ci	case 0x114 ... 0x13f:
9528c2ecf20Sopenharmony_ci	case 0x200:
9538c2ecf20Sopenharmony_ci	case 0x20c:
9548c2ecf20Sopenharmony_ci	case 0x400 ... 0x408:
9558c2ecf20Sopenharmony_ci	case 0x41c ... 0x42f:
9568c2ecf20Sopenharmony_ci		return true;
9578c2ecf20Sopenharmony_ci	default:
9588c2ecf20Sopenharmony_ci		return false;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_cistatic bool tc358768_writeable_reg(struct device *dev, unsigned int reg)
9638c2ecf20Sopenharmony_ci{
9648c2ecf20Sopenharmony_ci	if (tc358768_is_reserved_reg(reg))
9658c2ecf20Sopenharmony_ci		return false;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	switch (reg) {
9688c2ecf20Sopenharmony_ci	case TC358768_CHIPID:
9698c2ecf20Sopenharmony_ci	case TC358768_FIFOSTATUS:
9708c2ecf20Sopenharmony_ci	case TC358768_DSITXSTATUS ... (TC358768_DSITXSTATUS + 2):
9718c2ecf20Sopenharmony_ci	case TC358768_DSI_CONTROL ... (TC358768_DSI_INT_ENA + 2):
9728c2ecf20Sopenharmony_ci	case TC358768_DSICMD_RDFIFO ... (TC358768_DSI_ERR_HALT + 2):
9738c2ecf20Sopenharmony_ci		return false;
9748c2ecf20Sopenharmony_ci	default:
9758c2ecf20Sopenharmony_ci		return true;
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic bool tc358768_readable_reg(struct device *dev, unsigned int reg)
9808c2ecf20Sopenharmony_ci{
9818c2ecf20Sopenharmony_ci	if (tc358768_is_reserved_reg(reg))
9828c2ecf20Sopenharmony_ci		return false;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	switch (reg) {
9858c2ecf20Sopenharmony_ci	case TC358768_STARTCNTRL:
9868c2ecf20Sopenharmony_ci	case TC358768_DSI_CONFW ... (TC358768_DSI_CONFW + 2):
9878c2ecf20Sopenharmony_ci	case TC358768_DSI_INT_CLR ... (TC358768_DSI_INT_CLR + 2):
9888c2ecf20Sopenharmony_ci	case TC358768_DSI_START ... (TC358768_DSI_START + 2):
9898c2ecf20Sopenharmony_ci	case TC358768_DBG_DATA:
9908c2ecf20Sopenharmony_ci		return false;
9918c2ecf20Sopenharmony_ci	default:
9928c2ecf20Sopenharmony_ci		return true;
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_cistatic const struct regmap_config tc358768_regmap_config = {
9978c2ecf20Sopenharmony_ci	.name = "tc358768",
9988c2ecf20Sopenharmony_ci	.reg_bits = 16,
9998c2ecf20Sopenharmony_ci	.val_bits = 16,
10008c2ecf20Sopenharmony_ci	.max_register = TC358768_DSI_HACT,
10018c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_NONE,
10028c2ecf20Sopenharmony_ci	.writeable_reg = tc358768_writeable_reg,
10038c2ecf20Sopenharmony_ci	.readable_reg = tc358768_readable_reg,
10048c2ecf20Sopenharmony_ci	.reg_format_endian = REGMAP_ENDIAN_BIG,
10058c2ecf20Sopenharmony_ci	.val_format_endian = REGMAP_ENDIAN_BIG,
10068c2ecf20Sopenharmony_ci};
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic const struct i2c_device_id tc358768_i2c_ids[] = {
10098c2ecf20Sopenharmony_ci	{ "tc358768", 0 },
10108c2ecf20Sopenharmony_ci	{ "tc358778", 0 },
10118c2ecf20Sopenharmony_ci	{ }
10128c2ecf20Sopenharmony_ci};
10138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tc358768_i2c_ids);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cistatic const struct of_device_id tc358768_of_ids[] = {
10168c2ecf20Sopenharmony_ci	{ .compatible = "toshiba,tc358768", },
10178c2ecf20Sopenharmony_ci	{ .compatible = "toshiba,tc358778", },
10188c2ecf20Sopenharmony_ci	{ }
10198c2ecf20Sopenharmony_ci};
10208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tc358768_of_ids);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic int tc358768_get_regulators(struct tc358768_priv *priv)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	int i, ret;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->supplies); ++i)
10278c2ecf20Sopenharmony_ci		priv->supplies[i].supply = tc358768_supplies[i];
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	ret = devm_regulator_bulk_get(priv->dev, ARRAY_SIZE(priv->supplies),
10308c2ecf20Sopenharmony_ci				      priv->supplies);
10318c2ecf20Sopenharmony_ci	if (ret < 0)
10328c2ecf20Sopenharmony_ci		dev_err(priv->dev, "failed to get regulators: %d\n", ret);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	return ret;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int tc358768_i2c_probe(struct i2c_client *client,
10388c2ecf20Sopenharmony_ci			      const struct i2c_device_id *id)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	struct tc358768_priv *priv;
10418c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
10428c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
10438c2ecf20Sopenharmony_ci	int ret;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (!np)
10468c2ecf20Sopenharmony_ci		return -ENODEV;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
10498c2ecf20Sopenharmony_ci	if (!priv)
10508c2ecf20Sopenharmony_ci		return -ENOMEM;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, priv);
10538c2ecf20Sopenharmony_ci	priv->dev = dev;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	ret = tc358768_get_regulators(priv);
10568c2ecf20Sopenharmony_ci	if (ret)
10578c2ecf20Sopenharmony_ci		return ret;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	priv->refclk = devm_clk_get(dev, "refclk");
10608c2ecf20Sopenharmony_ci	if (IS_ERR(priv->refclk))
10618c2ecf20Sopenharmony_ci		return PTR_ERR(priv->refclk);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	/*
10648c2ecf20Sopenharmony_ci	 * RESX is low active, to disable tc358768 initially (keep in reset)
10658c2ecf20Sopenharmony_ci	 * the gpio line must be LOW. This is the ASSERTED state of
10668c2ecf20Sopenharmony_ci	 * GPIO_ACTIVE_LOW (GPIOD_OUT_HIGH == ASSERTED).
10678c2ecf20Sopenharmony_ci	 */
10688c2ecf20Sopenharmony_ci	priv->reset_gpio  = devm_gpiod_get_optional(dev, "reset",
10698c2ecf20Sopenharmony_ci						    GPIOD_OUT_HIGH);
10708c2ecf20Sopenharmony_ci	if (IS_ERR(priv->reset_gpio))
10718c2ecf20Sopenharmony_ci		return PTR_ERR(priv->reset_gpio);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	priv->regmap = devm_regmap_init_i2c(client, &tc358768_regmap_config);
10748c2ecf20Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
10758c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to init regmap\n");
10768c2ecf20Sopenharmony_ci		return PTR_ERR(priv->regmap);
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	priv->dsi_host.dev = dev;
10808c2ecf20Sopenharmony_ci	priv->dsi_host.ops = &tc358768_dsi_host_ops;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	priv->bridge.funcs = &tc358768_bridge_funcs;
10838c2ecf20Sopenharmony_ci	priv->bridge.timings = &default_tc358768_timings;
10848c2ecf20Sopenharmony_ci	priv->bridge.of_node = np;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, priv);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	return mipi_dsi_host_register(&priv->dsi_host);
10898c2ecf20Sopenharmony_ci}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_cistatic int tc358768_i2c_remove(struct i2c_client *client)
10928c2ecf20Sopenharmony_ci{
10938c2ecf20Sopenharmony_ci	struct tc358768_priv *priv = i2c_get_clientdata(client);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	mipi_dsi_host_unregister(&priv->dsi_host);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	return 0;
10988c2ecf20Sopenharmony_ci}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_cistatic struct i2c_driver tc358768_driver = {
11018c2ecf20Sopenharmony_ci	.driver = {
11028c2ecf20Sopenharmony_ci		.name = "tc358768",
11038c2ecf20Sopenharmony_ci		.of_match_table = tc358768_of_ids,
11048c2ecf20Sopenharmony_ci	},
11058c2ecf20Sopenharmony_ci	.id_table = tc358768_i2c_ids,
11068c2ecf20Sopenharmony_ci	.probe = tc358768_i2c_probe,
11078c2ecf20Sopenharmony_ci	.remove	= tc358768_i2c_remove,
11088c2ecf20Sopenharmony_ci};
11098c2ecf20Sopenharmony_cimodule_i2c_driver(tc358768_driver);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
11128c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TC358768AXBG/TC358778XBG DSI bridge");
11138c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1114