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