1234353Sdim// SPDX-License-Identifier: GPL-2.0+ 2193323Sed/* 3193323Sed * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd 4193323Sed * Copyright (C) STMicroelectronics SA 2017 5193323Sed * 6193323Sed * Modified by Philippe Cornu <philippe.cornu@st.com> 7193323Sed * This generic Synopsys DesignWare MIPI DSI host driver is based on the 8193323Sed * Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs. 9193323Sed */ 10193323Sed 11193323Sed#include <linux/clk.h> 12193323Sed#include <linux/component.h> 13193323Sed#include <linux/debugfs.h> 14218893Sdim#include <linux/iopoll.h> 15218893Sdim#include <linux/math64.h> 16218893Sdim#include <linux/media-bus-format.h> 17218893Sdim#include <linux/module.h> 18218893Sdim#include <linux/platform_device.h> 19193323Sed#include <linux/pm_runtime.h> 20218893Sdim#include <linux/reset.h> 21218893Sdim 22218893Sdim#include <video/mipi_display.h> 23218893Sdim 24218893Sdim#include <drm/bridge/dw_mipi_dsi.h> 25218893Sdim#include <drm/drm_atomic_helper.h> 26218893Sdim#include <drm/drm_bridge.h> 27218893Sdim#include <drm/drm_connector.h> 28193323Sed#include <drm/drm_crtc.h> 29218893Sdim#include <drm/drm_mipi_dsi.h> 30193323Sed#include <drm/drm_modes.h> 31198892Srdivacky#include <drm/drm_of.h> 32198892Srdivacky#include <drm/drm_print.h> 33198892Srdivacky 34226633Sdim#define HWVER_131 0x31333100 /* IP version 1.31 */ 35226633Sdim 36226633Sdim#define DSI_VERSION 0x00 37226633Sdim#define VERSION GENMASK(31, 8) 38226633Sdim 39226633Sdim#define DSI_PWR_UP 0x04 40198892Srdivacky#define RESET 0 41198892Srdivacky#define POWERUP BIT(0) 42226633Sdim 43226633Sdim#define DSI_CLKMGR_CFG 0x08 44226633Sdim#define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) 45226633Sdim#define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) 46226633Sdim 47226633Sdim#define DSI_DPI_VCID 0x0c 48226633Sdim#define DPI_VCID(vcid) ((vcid) & 0x3) 49226633Sdim 50198892Srdivacky#define DSI_DPI_COLOR_CODING 0x10 51198892Srdivacky#define LOOSELY18_EN BIT(8) 52198892Srdivacky#define DPI_COLOR_CODING_16BIT_1 0x0 53198892Srdivacky#define DPI_COLOR_CODING_16BIT_2 0x1 54226633Sdim#define DPI_COLOR_CODING_16BIT_3 0x2 55226633Sdim#define DPI_COLOR_CODING_18BIT_1 0x3 56226633Sdim#define DPI_COLOR_CODING_18BIT_2 0x4 57226633Sdim#define DPI_COLOR_CODING_24BIT 0x5 58226633Sdim 59226633Sdim#define DSI_DPI_CFG_POL 0x14 60226633Sdim#define COLORM_ACTIVE_LOW BIT(4) 61226633Sdim#define SHUTD_ACTIVE_LOW BIT(3) 62198892Srdivacky#define HSYNC_ACTIVE_LOW BIT(2) 63198892Srdivacky#define VSYNC_ACTIVE_LOW BIT(1) 64239462Sdim#define DATAEN_ACTIVE_LOW BIT(0) 65239462Sdim 66239462Sdim#define DSI_DPI_LP_CMD_TIM 0x18 67239462Sdim#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) 68239462Sdim#define INVACT_LPCMD_TIME(p) ((p) & 0xff) 69239462Sdim 70239462Sdim#define DSI_DBI_VCID 0x1c 71239462Sdim#define DSI_DBI_CFG 0x20 72239462Sdim#define DSI_DBI_PARTITIONING_EN 0x24 73234353Sdim#define DSI_DBI_CMDSIZE 0x28 74234353Sdim 75234353Sdim#define DSI_PCKHDL_CFG 0x2c 76234353Sdim#define CRC_RX_EN BIT(4) 77234353Sdim#define ECC_RX_EN BIT(3) 78234353Sdim#define BTA_EN BIT(2) 79234353Sdim#define EOTP_RX_EN BIT(1) 80234353Sdim#define EOTP_TX_EN BIT(0) 81234353Sdim 82234353Sdim#define DSI_GEN_VCID 0x30 83198892Srdivacky 84234353Sdim#define DSI_MODE_CFG 0x34 85234353Sdim#define ENABLE_VIDEO_MODE 0 86234353Sdim#define ENABLE_CMD_MODE BIT(0) 87234353Sdim 88234353Sdim#define DSI_VID_MODE_CFG 0x38 89234353Sdim#define ENABLE_LOW_POWER (0x3f << 8) 90198892Srdivacky#define ENABLE_LOW_POWER_MASK (0x3f << 8) 91193323Sed#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 92193323Sed#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 93193323Sed#define VID_MODE_TYPE_BURST 0x2 94204642Srdivacky#define VID_MODE_TYPE_MASK 0x3 95193323Sed#define ENABLE_LOW_POWER_CMD BIT(15) 96218893Sdim#define VID_MODE_VPG_ENABLE BIT(16) 97234353Sdim#define VID_MODE_VPG_MODE BIT(20) 98239462Sdim#define VID_MODE_VPG_HORIZONTAL BIT(24) 99193323Sed 100218893Sdim#define DSI_VID_PKT_SIZE 0x3c 101234353Sdim#define VID_PKT_SIZE(p) ((p) & 0x3fff) 102218893Sdim 103218893Sdim#define DSI_VID_NUM_CHUNKS 0x40 104218893Sdim#define VID_NUM_CHUNKS(c) ((c) & 0x1fff) 105218893Sdim 106218893Sdim#define DSI_VID_NULL_SIZE 0x44 107193323Sed#define VID_NULL_SIZE(b) ((b) & 0x1fff) 108218893Sdim 109193323Sed#define DSI_VID_HSA_TIME 0x48 110218893Sdim#define DSI_VID_HBP_TIME 0x4c 111234353Sdim#define DSI_VID_HLINE_TIME 0x50 112239462Sdim#define DSI_VID_VSA_LINES 0x54 113218893Sdim#define DSI_VID_VBP_LINES 0x58 114218893Sdim#define DSI_VID_VFP_LINES 0x5c 115234353Sdim#define DSI_VID_VACTIVE_LINES 0x60 116218893Sdim#define DSI_EDPI_CMD_SIZE 0x64 117218893Sdim 118218893Sdim#define DSI_CMD_MODE_CFG 0x68 119218893Sdim#define MAX_RD_PKT_SIZE_LP BIT(24) 120218893Sdim#define DCS_LW_TX_LP BIT(19) 121218893Sdim#define DCS_SR_0P_TX_LP BIT(18) 122193323Sed#define DCS_SW_1P_TX_LP BIT(17) 123193323Sed#define DCS_SW_0P_TX_LP BIT(16) 124193323Sed#define GEN_LW_TX_LP BIT(14) 125193323Sed#define GEN_SR_2P_TX_LP BIT(13) 126218893Sdim#define GEN_SR_1P_TX_LP BIT(12) 127218893Sdim#define GEN_SR_0P_TX_LP BIT(11) 128218893Sdim#define GEN_SW_2P_TX_LP BIT(10) 129218893Sdim#define GEN_SW_1P_TX_LP BIT(9) 130218893Sdim#define GEN_SW_0P_TX_LP BIT(8) 131218893Sdim#define ACK_RQST_EN BIT(1) 132218893Sdim#define TEAR_FX_EN BIT(0) 133218893Sdim 134218893Sdim#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ 135218893Sdim DCS_LW_TX_LP | \ 136218893Sdim DCS_SR_0P_TX_LP | \ 137218893Sdim DCS_SW_1P_TX_LP | \ 138224145Sdim DCS_SW_0P_TX_LP | \ 139224145Sdim GEN_LW_TX_LP | \ 140218893Sdim GEN_SR_2P_TX_LP | \ 141218893Sdim GEN_SR_1P_TX_LP | \ 142218893Sdim GEN_SR_0P_TX_LP | \ 143218893Sdim GEN_SW_2P_TX_LP | \ 144218893Sdim GEN_SW_1P_TX_LP | \ 145218893Sdim GEN_SW_0P_TX_LP) 146218893Sdim 147224145Sdim#define DSI_GEN_HDR 0x6c 148224145Sdim#define DSI_GEN_PLD_DATA 0x70 149218893Sdim 150218893Sdim#define DSI_CMD_PKT_STATUS 0x74 151218893Sdim#define GEN_RD_CMD_BUSY BIT(6) 152218893Sdim#define GEN_PLD_R_FULL BIT(5) 153218893Sdim#define GEN_PLD_R_EMPTY BIT(4) 154218893Sdim#define GEN_PLD_W_FULL BIT(3) 155193323Sed#define GEN_PLD_W_EMPTY BIT(2) 156218893Sdim#define GEN_CMD_FULL BIT(1) 157218893Sdim#define GEN_CMD_EMPTY BIT(0) 158218893Sdim 159218893Sdim#define DSI_TO_CNT_CFG 0x78 160218893Sdim#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) 161218893Sdim#define LPRX_TO_CNT(p) ((p) & 0xffff) 162218893Sdim 163218893Sdim#define DSI_HS_RD_TO_CNT 0x7c 164205218Srdivacky#define DSI_LP_RD_TO_CNT 0x80 165218893Sdim#define DSI_HS_WR_TO_CNT 0x84 166218893Sdim#define DSI_LP_WR_TO_CNT 0x88 167218893Sdim#define DSI_BTA_TO_CNT 0x8c 168218893Sdim 169218893Sdim#define DSI_LPCLK_CTRL 0x94 170224145Sdim#define AUTO_CLKLANE_CTRL BIT(1) 171224145Sdim#define PHY_TXREQUESTCLKHS BIT(0) 172218893Sdim 173218893Sdim#define DSI_PHY_TMR_LPCLK_CFG 0x98 174218893Sdim#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) 175218893Sdim#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) 176218893Sdim 177205218Srdivacky#define DSI_PHY_TMR_CFG 0x9c 178218893Sdim#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) 179218893Sdim#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) 180218893Sdim#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) 181218893Sdim#define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) 182218893Sdim#define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) 183224145Sdim 184224145Sdim#define DSI_PHY_RSTZ 0xa0 185218893Sdim#define PHY_DISFORCEPLL 0 186218893Sdim#define PHY_ENFORCEPLL BIT(3) 187218893Sdim#define PHY_DISABLECLK 0 188218893Sdim#define PHY_ENABLECLK BIT(2) 189218893Sdim#define PHY_RSTZ 0 190193323Sed#define PHY_UNRSTZ BIT(1) 191218893Sdim#define PHY_SHUTDOWNZ 0 192218893Sdim#define PHY_UNSHUTDOWNZ BIT(0) 193218893Sdim 194218893Sdim#define DSI_PHY_IF_CFG 0xa4 195193323Sed#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) 196205218Srdivacky#define N_LANES(n) (((n) - 1) & 0x3) 197218893Sdim 198205218Srdivacky#define DSI_PHY_ULPS_CTRL 0xa8 199218893Sdim#define DSI_PHY_TX_TRIGGERS 0xac 200218893Sdim 201193323Sed#define DSI_PHY_STATUS 0xb0 202218893Sdim#define PHY_STOP_STATE_CLK_LANE BIT(2) 203218893Sdim#define PHY_LOCK BIT(0) 204218893Sdim 205218893Sdim#define DSI_PHY_TST_CTRL0 0xb4 206218893Sdim#define PHY_TESTCLK BIT(1) 207218893Sdim#define PHY_UNTESTCLK 0 208218893Sdim#define PHY_TESTCLR BIT(0) 209218893Sdim#define PHY_UNTESTCLR 0 210224145Sdim 211224145Sdim#define DSI_PHY_TST_CTRL1 0xb8 212224145Sdim#define PHY_TESTEN BIT(16) 213224145Sdim#define PHY_UNTESTEN 0 214224145Sdim#define PHY_TESTDOUT(n) (((n) & 0xff) << 8) 215224145Sdim#define PHY_TESTDIN(n) ((n) & 0xff) 216224145Sdim 217224145Sdim#define DSI_INT_ST0 0xbc 218234353Sdim#define DSI_INT_ST1 0xc0 219234353Sdim#define DSI_INT_MSK0 0xc4 220234353Sdim#define DSI_INT_MSK1 0xc8 221234353Sdim 222234353Sdim#define DSI_PHY_TMR_RD_CFG 0xf4 223234353Sdim#define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) 224234353Sdim 225234353Sdim#define PHY_STATUS_TIMEOUT_US 10000 226224145Sdim#define CMD_PKT_STATUS_TIMEOUT_US 20000 227263508Sdim 228263508Sdim#ifdef CONFIG_DEBUG_FS 229263508Sdim#define VPG_DEFS(name, dsi) \ 230263508Sdim ((void __force *)&((*dsi).vpg_defs.name)) 231263508Sdim 232263508Sdim#define REGISTER(name, mask, dsi) \ 233263508Sdim { #name, VPG_DEFS(name, dsi), mask, dsi } 234263508Sdim 235263508Sdimstruct debugfs_entries { 236263508Sdim const char *name; 237263508Sdim bool *reg; 238263508Sdim u32 mask; 239263508Sdim struct dw_mipi_dsi *dsi; 240263508Sdim}; 241263508Sdim#endif /* CONFIG_DEBUG_FS */ 242263508Sdim 243263508Sdimstruct dw_mipi_dsi { 244263508Sdim struct drm_bridge bridge; 245263508Sdim struct mipi_dsi_host dsi_host; 246263508Sdim struct drm_bridge *panel_bridge; 247263508Sdim struct device *dev; 248263508Sdim void __iomem *base; 249263508Sdim 250263508Sdim struct clk *pclk; 251263508Sdim 252263508Sdim unsigned int lane_mbps; /* per lane */ 253263508Sdim u32 channel; 254193323Sed u32 lanes; 255263508Sdim u32 format; 256263508Sdim unsigned long mode_flags; 257263508Sdim 258193323Sed#ifdef CONFIG_DEBUG_FS 259193323Sed struct dentry *debugfs; 260193323Sed struct debugfs_entries *debugfs_vpg; 261193323Sed struct { 262239462Sdim bool vpg; 263218893Sdim bool vpg_horizontal; 264218893Sdim bool vpg_ber_pattern; 265218893Sdim } vpg_defs; 266218893Sdim#endif /* CONFIG_DEBUG_FS */ 267193323Sed 268239462Sdim struct dw_mipi_dsi *master; /* dual-dsi master ptr */ 269218893Sdim struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */ 270218893Sdim 271218893Sdim struct drm_display_mode mode; 272218893Sdim const struct dw_mipi_dsi_plat_data *plat_data; 273219077Sdim}; 274219077Sdim 275219077Sdim/* 276218893Sdim * Check if either a link to a master or slave is present 277193323Sed */ 278239462Sdimstatic inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi) 279218893Sdim{ 280218893Sdim return dsi->slave || dsi->master; 281218893Sdim} 282218893Sdim 283193323Sed/* 284239462Sdim * The controller should generate 2 frames before 285218893Sdim * preparing the peripheral. 286218893Sdim */ 287218893Sdimstatic void dw_mipi_dsi_wait_for_two_frames(const struct drm_display_mode *mode) 288218893Sdim{ 289219077Sdim int refresh, two_frames; 290219077Sdim 291219077Sdim refresh = drm_mode_vrefresh(mode); 292198090Srdivacky two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; 293193323Sed msleep(two_frames); 294239462Sdim} 295218893Sdim 296218893Sdimstatic inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host) 297218893Sdim{ 298218893Sdim return container_of(host, struct dw_mipi_dsi, dsi_host); 299193323Sed} 300239462Sdim 301218893Sdimstatic inline struct dw_mipi_dsi *bridge_to_dsi(struct drm_bridge *bridge) 302218893Sdim{ 303218893Sdim return container_of(bridge, struct dw_mipi_dsi, bridge); 304218893Sdim} 305193323Sed 306239462Sdimstatic inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) 307218893Sdim{ 308218893Sdim writel(val, dsi->base + reg); 309218893Sdim} 310218893Sdim 311193323Sedstatic inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) 312239462Sdim{ 313218893Sdim return readl(dsi->base + reg); 314218893Sdim} 315218893Sdim 316218893Sdimstatic int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, 317219077Sdim struct mipi_dsi_device *device) 318219077Sdim{ 319219077Sdim struct dw_mipi_dsi *dsi = host_to_dsi(host); 320218893Sdim const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; 321199481Srdivacky struct drm_bridge *bridge; 322218893Sdim int ret; 323218893Sdim 324218893Sdim if (device->lanes > dsi->plat_data->max_data_lanes) { 325218893Sdim dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", 326193323Sed device->lanes); 327218893Sdim return -EINVAL; 328218893Sdim } 329218893Sdim 330218893Sdim dsi->lanes = device->lanes; 331219077Sdim dsi->channel = device->channel; 332219077Sdim dsi->format = device->format; 333219077Sdim dsi->mode_flags = device->mode_flags; 334218893Sdim 335193323Sed bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0); 336263508Sdim if (IS_ERR(bridge)) 337263508Sdim return PTR_ERR(bridge); 338263508Sdim 339263508Sdim bridge->pre_enable_prev_first = true; 340263508Sdim dsi->panel_bridge = bridge; 341263508Sdim 342263508Sdim drm_bridge_add(&dsi->bridge); 343263508Sdim 344263508Sdim if (pdata->host_ops && pdata->host_ops->attach) { 345263508Sdim ret = pdata->host_ops->attach(pdata->priv_data, device); 346263508Sdim if (ret < 0) 347263508Sdim return ret; 348263508Sdim } 349263508Sdim 350263508Sdim return 0; 351263508Sdim} 352263508Sdim 353263508Sdimstatic int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, 354263508Sdim struct mipi_dsi_device *device) 355263508Sdim{ 356263508Sdim struct dw_mipi_dsi *dsi = host_to_dsi(host); 357263508Sdim const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; 358263508Sdim int ret; 359263508Sdim 360263508Sdim if (pdata->host_ops && pdata->host_ops->detach) { 361263508Sdim ret = pdata->host_ops->detach(pdata->priv_data, device); 362263508Sdim if (ret < 0) 363263508Sdim return ret; 364263508Sdim } 365263508Sdim 366263508Sdim drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); 367263508Sdim 368263508Sdim drm_bridge_remove(&dsi->bridge); 369263508Sdim 370263508Sdim return 0; 371263508Sdim} 372263508Sdim 373263508Sdimstatic void dw_mipi_message_config(struct dw_mipi_dsi *dsi, 374263508Sdim const struct mipi_dsi_msg *msg) 375263508Sdim{ 376263508Sdim bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; 377263508Sdim u32 val = 0; 378193323Sed 379204961Srdivacky /* 380263508Sdim * TODO dw drv improvements 381263508Sdim * largest packet sizes during hfp or during vsa/vpb/vfp 382193323Sed * should be computed according to byte lane, lane number and only 383199481Srdivacky * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS) 384193323Sed */ 385218893Sdim dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(16) 386234353Sdim | INVACT_LPCMD_TIME(4)); 387218893Sdim 388218893Sdim if (msg->flags & MIPI_DSI_MSG_REQ_ACK) 389218893Sdim val |= ACK_RQST_EN; 390218893Sdim if (lpm) 391193323Sed val |= CMD_MODE_ALL_LP; 392218893Sdim 393218893Sdim dsi_write(dsi, DSI_CMD_MODE_CFG, val); 394218893Sdim 395218893Sdim val = dsi_read(dsi, DSI_VID_MODE_CFG); 396219077Sdim if (lpm) 397219077Sdim val |= ENABLE_LOW_POWER_CMD; 398219077Sdim else 399218893Sdim val &= ~ENABLE_LOW_POWER_CMD; 400193323Sed dsi_write(dsi, DSI_VID_MODE_CFG, val); 401218893Sdim} 402218893Sdim 403218893Sdimstatic int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) 404218893Sdim{ 405218893Sdim int ret; 406193323Sed u32 val, mask; 407218893Sdim 408218893Sdim ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, 409218893Sdim val, !(val & GEN_CMD_FULL), 1000, 410218893Sdim CMD_PKT_STATUS_TIMEOUT_US); 411219077Sdim if (ret) { 412219077Sdim dev_err(dsi->dev, "failed to get available command FIFO\n"); 413219077Sdim return ret; 414218893Sdim } 415234353Sdim 416218893Sdim dsi_write(dsi, DSI_GEN_HDR, hdr_val); 417193323Sed 418193323Sed mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; 419193323Sed ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, 420193323Sed val, (val & mask) == mask, 421218893Sdim 1000, CMD_PKT_STATUS_TIMEOUT_US); 422218893Sdim if (ret) { 423218893Sdim dev_err(dsi->dev, "failed to write command FIFO\n"); 424218893Sdim return ret; 425193323Sed } 426218893Sdim 427218893Sdim return 0; 428218893Sdim} 429218893Sdim 430219077Sdimstatic int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, 431219077Sdim const struct mipi_dsi_packet *packet) 432219077Sdim{ 433218893Sdim const u8 *tx_buf = packet->payload; 434193323Sed int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; 435234353Sdim __le32 word; 436218893Sdim u32 val; 437218893Sdim 438218893Sdim while (len) { 439218893Sdim if (len < pld_data_bytes) { 440218893Sdim word = 0; 441218893Sdim memcpy(&word, tx_buf, len); 442218893Sdim dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); 443193323Sed len = 0; 444218893Sdim } else { 445218893Sdim memcpy(&word, tx_buf, pld_data_bytes); 446218893Sdim dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); 447218893Sdim tx_buf += pld_data_bytes; 448218893Sdim len -= pld_data_bytes; 449218893Sdim } 450203954Srdivacky 451219077Sdim ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, 452219077Sdim val, !(val & GEN_PLD_W_FULL), 1000, 453219077Sdim CMD_PKT_STATUS_TIMEOUT_US); 454218893Sdim if (ret) { 455203954Srdivacky dev_err(dsi->dev, 456218893Sdim "failed to get available write payload FIFO\n"); 457218893Sdim return ret; 458218893Sdim } 459218893Sdim } 460218893Sdim 461218893Sdim word = 0; 462218893Sdim memcpy(&word, packet->header, sizeof(packet->header)); 463198090Srdivacky return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); 464193323Sed} 465218893Sdim 466218893Sdimstatic int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, 467218893Sdim const struct mipi_dsi_msg *msg) 468218893Sdim{ 469218893Sdim int i, j, ret, len = msg->rx_len; 470218893Sdim u8 *buf = msg->rx_buf; 471193323Sed u32 val; 472219077Sdim 473219077Sdim /* Wait end of the read operation */ 474219077Sdim ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, 475218893Sdim val, !(val & GEN_RD_CMD_BUSY), 476234353Sdim 1000, CMD_PKT_STATUS_TIMEOUT_US); 477218893Sdim if (ret) { 478218893Sdim dev_err(dsi->dev, "Timeout during read operation\n"); 479218893Sdim return ret; 480218893Sdim } 481218893Sdim 482218893Sdim for (i = 0; i < len; i += 4) { 483218893Sdim /* Read fifo must not be empty before all bytes are read */ 484218893Sdim ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, 485218893Sdim val, !(val & GEN_PLD_R_EMPTY), 486218893Sdim 1000, CMD_PKT_STATUS_TIMEOUT_US); 487218893Sdim if (ret) { 488218893Sdim dev_err(dsi->dev, "Read payload FIFO is empty\n"); 489218893Sdim return ret; 490218893Sdim } 491218893Sdim 492218893Sdim val = dsi_read(dsi, DSI_GEN_PLD_DATA); 493193323Sed for (j = 0; j < 4 && j + i < len; j++) 494218893Sdim buf[i + j] = val >> (8 * j); 495218893Sdim } 496218893Sdim 497218893Sdim return ret; 498218893Sdim} 499218893Sdim 500218893Sdimstatic ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, 501218893Sdim const struct mipi_dsi_msg *msg) 502218893Sdim{ 503218893Sdim struct dw_mipi_dsi *dsi = host_to_dsi(host); 504218893Sdim struct mipi_dsi_packet packet; 505218893Sdim int ret, nb_bytes; 506218893Sdim 507193323Sed ret = mipi_dsi_create_packet(&packet, msg); 508193323Sed if (ret) { 509193323Sed dev_err(dsi->dev, "failed to create packet: %d\n", ret); 510203954Srdivacky return ret; 511203954Srdivacky } 512263508Sdim 513263508Sdim dw_mipi_message_config(dsi, msg); 514193323Sed if (dsi->slave) 515193323Sed dw_mipi_message_config(dsi->slave, msg); 516263508Sdim 517203954Srdivacky ret = dw_mipi_dsi_write(dsi, &packet); 518218893Sdim if (ret) 519239462Sdim return ret; 520226633Sdim if (dsi->slave) { 521205407Srdivacky ret = dw_mipi_dsi_write(dsi->slave, &packet); 522203954Srdivacky if (ret) 523239462Sdim return ret; 524239462Sdim } 525239462Sdim 526239462Sdim if (msg->rx_buf && msg->rx_len) { 527243830Sdim ret = dw_mipi_dsi_read(dsi, msg); 528243830Sdim if (ret) 529205407Srdivacky return ret; 530243830Sdim nb_bytes = msg->rx_len; 531243830Sdim } else { 532205407Srdivacky nb_bytes = packet.size; 533239462Sdim } 534226633Sdim 535203954Srdivacky return nb_bytes; 536203954Srdivacky} 537239462Sdim 538226633Sdimstatic const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { 539203954Srdivacky .attach = dw_mipi_dsi_host_attach, 540203954Srdivacky .detach = dw_mipi_dsi_host_detach, 541263508Sdim .transfer = dw_mipi_dsi_host_transfer, 542263508Sdim}; 543263508Sdim 544263508Sdimstatic u32 * 545263508Sdimdw_mipi_dsi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 546263508Sdim struct drm_bridge_state *bridge_state, 547263508Sdim struct drm_crtc_state *crtc_state, 548263508Sdim struct drm_connector_state *conn_state, 549263508Sdim u32 output_fmt, 550263508Sdim unsigned int *num_input_fmts) 551263508Sdim{ 552263508Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 553263508Sdim const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; 554263508Sdim u32 *input_fmts; 555263508Sdim 556263508Sdim if (pdata->get_input_bus_fmts) 557263508Sdim return pdata->get_input_bus_fmts(pdata->priv_data, 558263508Sdim bridge, bridge_state, 559263508Sdim crtc_state, conn_state, 560263508Sdim output_fmt, num_input_fmts); 561263508Sdim 562263508Sdim /* Fall back to MEDIA_BUS_FMT_FIXED as the only input format. */ 563263508Sdim input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); 564263508Sdim if (!input_fmts) 565263508Sdim return NULL; 566263508Sdim input_fmts[0] = MEDIA_BUS_FMT_FIXED; 567263508Sdim *num_input_fmts = 1; 568263508Sdim 569263508Sdim return input_fmts; 570263508Sdim} 571263508Sdim 572263508Sdimstatic int dw_mipi_dsi_bridge_atomic_check(struct drm_bridge *bridge, 573263508Sdim struct drm_bridge_state *bridge_state, 574263508Sdim struct drm_crtc_state *crtc_state, 575263508Sdim struct drm_connector_state *conn_state) 576263508Sdim{ 577263508Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 578263508Sdim const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; 579263508Sdim bool ret; 580263508Sdim 581263508Sdim bridge_state->input_bus_cfg.flags = 582263508Sdim DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; 583263508Sdim 584263508Sdim if (pdata->mode_fixup) { 585263508Sdim ret = pdata->mode_fixup(pdata->priv_data, &crtc_state->mode, 586263508Sdim &crtc_state->adjusted_mode); 587263508Sdim if (!ret) { 588263508Sdim DRM_DEBUG_DRIVER("failed to fixup mode " DRM_MODE_FMT "\n", 589263508Sdim DRM_MODE_ARG(&crtc_state->mode)); 590263508Sdim return -EINVAL; 591263508Sdim } 592263508Sdim } 593263508Sdim 594263508Sdim return 0; 595263508Sdim} 596263508Sdim 597263508Sdimstatic void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) 598263508Sdim{ 599263508Sdim u32 val; 600263508Sdim 601263508Sdim /* 602263508Sdim * TODO dw drv improvements 603263508Sdim * enabling low power is panel-dependent, we should use the 604263508Sdim * panel configuration here... 605263508Sdim */ 606263508Sdim val = ENABLE_LOW_POWER; 607263508Sdim 608263508Sdim if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) 609263508Sdim val |= VID_MODE_TYPE_BURST; 610263508Sdim else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 611263508Sdim val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; 612263508Sdim else 613263508Sdim val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; 614263508Sdim 615263508Sdim#ifdef CONFIG_DEBUG_FS 616263508Sdim if (dsi->vpg_defs.vpg) { 617263508Sdim val |= VID_MODE_VPG_ENABLE; 618263508Sdim val |= dsi->vpg_defs.vpg_horizontal ? 619263508Sdim VID_MODE_VPG_HORIZONTAL : 0; 620263508Sdim val |= dsi->vpg_defs.vpg_ber_pattern ? VID_MODE_VPG_MODE : 0; 621263508Sdim } 622263508Sdim#endif /* CONFIG_DEBUG_FS */ 623263508Sdim 624263508Sdim dsi_write(dsi, DSI_VID_MODE_CFG, val); 625263508Sdim} 626263508Sdim 627263508Sdimstatic void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, 628263508Sdim unsigned long mode_flags) 629263508Sdim{ 630263508Sdim u32 val; 631263508Sdim 632263508Sdim dsi_write(dsi, DSI_PWR_UP, RESET); 633263508Sdim 634263508Sdim if (mode_flags & MIPI_DSI_MODE_VIDEO) { 635263508Sdim dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); 636263508Sdim dw_mipi_dsi_video_mode_config(dsi); 637263508Sdim } else { 638263508Sdim dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); 639263508Sdim } 640263508Sdim 641263508Sdim val = PHY_TXREQUESTCLKHS; 642263508Sdim if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) 643263508Sdim val |= AUTO_CLKLANE_CTRL; 644263508Sdim dsi_write(dsi, DSI_LPCLK_CTRL, val); 645263508Sdim 646218893Sdim dsi_write(dsi, DSI_PWR_UP, POWERUP); 647218893Sdim} 648218893Sdim 649218893Sdimstatic void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi) 650193323Sed{ 651218893Sdim dsi_write(dsi, DSI_PWR_UP, RESET); 652218893Sdim dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ); 653218893Sdim} 654218893Sdim 655219077Sdimstatic void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) 656219077Sdim{ 657219077Sdim const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; 658218893Sdim unsigned int esc_rate; /* in MHz */ 659193323Sed u32 esc_clk_division; 660263508Sdim int ret; 661263508Sdim 662263508Sdim /* 663263508Sdim * The maximum permitted escape clock is 20MHz and it is derived from 664263508Sdim * lanebyteclk, which is running at "lane_mbps / 8". 665263508Sdim */ 666263508Sdim if (phy_ops->get_esc_clk_rate) { 667263508Sdim ret = phy_ops->get_esc_clk_rate(dsi->plat_data->priv_data, 668263508Sdim &esc_rate); 669263508Sdim if (ret) 670263508Sdim DRM_DEBUG_DRIVER("Phy get_esc_clk_rate() failed\n"); 671263508Sdim } else 672263508Sdim esc_rate = 20; /* Default to 20MHz */ 673263508Sdim 674263508Sdim /* 675263508Sdim * We want : 676263508Sdim * (lane_mbps >> 3) / esc_clk_division < X 677263508Sdim * which is: 678263508Sdim * (lane_mbps >> 3) / X > esc_clk_division 679263508Sdim */ 680263508Sdim esc_clk_division = (dsi->lane_mbps >> 3) / esc_rate + 1; 681263508Sdim 682263508Sdim dsi_write(dsi, DSI_PWR_UP, RESET); 683263508Sdim 684263508Sdim /* 685263508Sdim * TODO dw drv improvements 686263508Sdim * timeout clock division should be computed with the 687263508Sdim * high speed transmission counter timeout and byte lane... 688263508Sdim */ 689263508Sdim dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(0) | 690263508Sdim TX_ESC_CLK_DIVISION(esc_clk_division)); 691263508Sdim} 692263508Sdim 693263508Sdimstatic void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, 694263508Sdim const struct drm_display_mode *mode) 695263508Sdim{ 696263508Sdim u32 val = 0, color = 0; 697263508Sdim 698263508Sdim switch (dsi->format) { 699263508Sdim case MIPI_DSI_FMT_RGB888: 700263508Sdim color = DPI_COLOR_CODING_24BIT; 701263508Sdim break; 702263508Sdim case MIPI_DSI_FMT_RGB666: 703263508Sdim color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; 704263508Sdim break; 705263508Sdim case MIPI_DSI_FMT_RGB666_PACKED: 706263508Sdim color = DPI_COLOR_CODING_18BIT_1; 707263508Sdim break; 708263508Sdim case MIPI_DSI_FMT_RGB565: 709263508Sdim color = DPI_COLOR_CODING_16BIT_1; 710263508Sdim break; 711263508Sdim } 712263508Sdim 713263508Sdim if (mode->flags & DRM_MODE_FLAG_NVSYNC) 714263508Sdim val |= VSYNC_ACTIVE_LOW; 715263508Sdim if (mode->flags & DRM_MODE_FLAG_NHSYNC) 716263508Sdim val |= HSYNC_ACTIVE_LOW; 717218893Sdim 718218893Sdim dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); 719218893Sdim dsi_write(dsi, DSI_DPI_COLOR_CODING, color); 720218893Sdim dsi_write(dsi, DSI_DPI_CFG_POL, val); 721193323Sed} 722218893Sdim 723218893Sdimstatic void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) 724218893Sdim{ 725218893Sdim dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); 726193323Sed} 727218893Sdim 728218893Sdimstatic void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, 729218893Sdim const struct drm_display_mode *mode) 730218893Sdim{ 731193323Sed /* 732218893Sdim * TODO dw drv improvements 733218893Sdim * only burst mode is supported here. For non-burst video modes, 734218893Sdim * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC & 735218893Sdim * DSI_VNPCR.NPSIZE... especially because this driver supports 736193323Sed * non-burst video modes, see dw_mipi_dsi_video_mode_config()... 737193323Sed */ 738193323Sed 739193323Sed dsi_write(dsi, DSI_VID_PKT_SIZE, 740193323Sed dw_mipi_is_dual_mode(dsi) ? 741218893Sdim VID_PKT_SIZE(mode->hdisplay / 2) : 742218893Sdim VID_PKT_SIZE(mode->hdisplay)); 743218893Sdim} 744218893Sdim 745218893Sdimstatic void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) 746218893Sdim{ 747218893Sdim /* 748193323Sed * TODO dw drv improvements 749218893Sdim * compute high speed transmission counter timeout according 750218893Sdim * to the timeout clock division (TO_CLK_DIVISION) and byte lane... 751218893Sdim */ 752218893Sdim dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(0) | LPRX_TO_CNT(0)); 753193323Sed /* 754218893Sdim * TODO dw drv improvements 755218893Sdim * the Bus-Turn-Around Timeout Counter should be computed 756221345Sdim * according to byte lane... 757221345Sdim */ 758221345Sdim dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); 759221345Sdim dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); 760218893Sdim} 761218893Sdim 762243830Sdimstatic const u32 minimum_lbccs[] = {10, 5, 4, 3}; 763218893Sdim 764218893Sdimstatic inline u32 dw_mipi_dsi_get_minimum_lbcc(struct dw_mipi_dsi *dsi) 765218893Sdim{ 766243830Sdim return minimum_lbccs[dsi->lanes - 1]; 767243830Sdim} 768218893Sdim 769218893Sdim/* Get lane byte clock cycles. */ 770218893Sdimstatic u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, 771218893Sdim const struct drm_display_mode *mode, 772218893Sdim u32 hcomponent) 773218893Sdim{ 774218893Sdim u32 frac, lbcc, minimum_lbcc; 775218893Sdim int bpp; 776218893Sdim 777218893Sdim if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { 778218893Sdim /* lbcc based on lane_mbps */ 779221345Sdim lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; 780221345Sdim } else { 781221345Sdim /* lbcc based on pixel clock rate */ 782221345Sdim bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); 783218893Sdim if (bpp < 0) { 784218893Sdim dev_err(dsi->dev, "failed to get bpp\n"); 785208599Srdivacky return 0; 786199481Srdivacky } 787218893Sdim 788218893Sdim lbcc = div_u64((u64)hcomponent * mode->clock * bpp, dsi->lanes * 8); 789203954Srdivacky } 790218893Sdim 791218893Sdim frac = lbcc % mode->clock; 792218893Sdim lbcc = lbcc / mode->clock; 793218893Sdim if (frac) 794218893Sdim lbcc++; 795218893Sdim 796218893Sdim minimum_lbcc = dw_mipi_dsi_get_minimum_lbcc(dsi); 797218893Sdim 798218893Sdim if (lbcc < minimum_lbcc) 799218893Sdim lbcc = minimum_lbcc; 800218893Sdim 801203954Srdivacky return lbcc; 802221345Sdim} 803221345Sdim 804221345Sdimstatic void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, 805221345Sdim const struct drm_display_mode *mode) 806203954Srdivacky{ 807193323Sed u32 htotal, hsa, hbp, lbcc; 808203954Srdivacky 809226633Sdim htotal = mode->htotal; 810226633Sdim hsa = mode->hsync_end - mode->hsync_start; 811203954Srdivacky hbp = mode->htotal - mode->hsync_end; 812226633Sdim 813226633Sdim /* 814226633Sdim * TODO dw drv improvements 815226633Sdim * computations below may be improved... 816226633Sdim */ 817239462Sdim lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal); 818239462Sdim dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc); 819226633Sdim 820226633Sdim lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa); 821226633Sdim dsi_write(dsi, DSI_VID_HSA_TIME, lbcc); 822203954Srdivacky 823221345Sdim lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp); 824221345Sdim dsi_write(dsi, DSI_VID_HBP_TIME, lbcc); 825221345Sdim} 826221345Sdim 827226633Sdimstatic void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, 828203954Srdivacky const struct drm_display_mode *mode) 829208599Srdivacky{ 830203954Srdivacky u32 vactive, vsa, vfp, vbp; 831193323Sed 832193323Sed vactive = mode->vdisplay; 833193323Sed vsa = mode->vsync_end - mode->vsync_start; 834199481Srdivacky vfp = mode->vsync_start - mode->vdisplay; 835218893Sdim vbp = mode->vtotal - mode->vsync_end; 836218893Sdim 837218893Sdim dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive); 838218893Sdim dsi_write(dsi, DSI_VID_VSA_LINES, vsa); 839218893Sdim dsi_write(dsi, DSI_VID_VFP_LINES, vfp); 840218893Sdim dsi_write(dsi, DSI_VID_VBP_LINES, vbp); 841218893Sdim} 842218893Sdim 843218893Sdimstatic void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) 844218893Sdim{ 845218893Sdim const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; 846218893Sdim struct dw_mipi_dsi_dphy_timing timing; 847218893Sdim u32 hw_version; 848218893Sdim int ret; 849218893Sdim 850221345Sdim ret = phy_ops->get_timing(dsi->plat_data->priv_data, 851221345Sdim dsi->lane_mbps, &timing); 852221345Sdim if (ret) 853221345Sdim DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n"); 854203954Srdivacky 855193323Sed /* 856208599Srdivacky * TODO dw drv improvements 857203954Srdivacky * data & clock lane timers should be computed according to panel 858203954Srdivacky * blankings and to the automatic clock lane control mode... 859207618Srdivacky * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with 860203954Srdivacky * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) 861226633Sdim */ 862226633Sdim 863226633Sdim hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; 864226633Sdim 865226633Sdim if (hw_version >= HWVER_131) { 866226633Sdim dsi_write(dsi, DSI_PHY_TMR_CFG, 867239462Sdim PHY_HS2LP_TIME_V131(timing.data_hs2lp) | 868239462Sdim PHY_LP2HS_TIME_V131(timing.data_lp2hs)); 869226633Sdim dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); 870226633Sdim } else { 871226633Sdim dsi_write(dsi, DSI_PHY_TMR_CFG, 872203954Srdivacky PHY_HS2LP_TIME(timing.data_hs2lp) | 873221345Sdim PHY_LP2HS_TIME(timing.data_lp2hs) | 874221345Sdim MAX_RD_TIME(10000)); 875221345Sdim } 876221345Sdim 877226633Sdim dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, 878226633Sdim PHY_CLKHS2LP_TIME(timing.clk_hs2lp) | 879203954Srdivacky PHY_CLKLP2HS_TIME(timing.clk_lp2hs)); 880203954Srdivacky} 881193323Sed 882193323Sedstatic void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) 883193323Sed{ 884218893Sdim /* 885193323Sed * TODO dw drv improvements 886218893Sdim * stop wait time should be the maximum between host dsi 887193323Sed * and panel stop wait times 888193323Sed */ 889218893Sdim dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | 890193323Sed N_LANES(dsi->lanes)); 891218893Sdim} 892218893Sdim 893218893Sdimstatic void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) 894218893Sdim{ 895218893Sdim /* Clear PHY state */ 896218893Sdim dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK 897218893Sdim | PHY_RSTZ | PHY_SHUTDOWNZ); 898218893Sdim dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); 899218893Sdim dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); 900193323Sed dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); 901218893Sdim} 902218893Sdim 903218893Sdimstatic void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) 904218893Sdim{ 905218893Sdim u32 val; 906263508Sdim int ret; 907263508Sdim 908218893Sdim dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | 909218893Sdim PHY_UNRSTZ | PHY_UNSHUTDOWNZ); 910218893Sdim 911218893Sdim ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, 912218893Sdim val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US); 913218893Sdim if (ret) 914218893Sdim DRM_DEBUG_DRIVER("failed to wait phy lock state\n"); 915218893Sdim 916218893Sdim ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, 917218893Sdim val, val & PHY_STOP_STATE_CLK_LANE, 1000, 918218893Sdim PHY_STATUS_TIMEOUT_US); 919218893Sdim if (ret) 920218893Sdim DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n"); 921218893Sdim} 922218893Sdim 923218893Sdimstatic void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) 924218893Sdim{ 925218893Sdim dsi_read(dsi, DSI_INT_ST0); 926218893Sdim dsi_read(dsi, DSI_INT_ST1); 927218893Sdim dsi_write(dsi, DSI_INT_MSK0, 0); 928218893Sdim dsi_write(dsi, DSI_INT_MSK1, 0); 929218893Sdim} 930203954Srdivacky 931193323Sedstatic void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, 932193323Sed struct drm_bridge_state *old_bridge_state) 933218893Sdim{ 934218893Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 935218893Sdim const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; 936218893Sdim 937203954Srdivacky /* 938218893Sdim * Switch to command mode before panel-bridge post_disable & 939219077Sdim * panel unprepare. 940219077Sdim * Note: panel-bridge disable & panel disable has been called 941219077Sdim * before by the drm framework. 942193323Sed */ 943193323Sed dw_mipi_dsi_set_mode(dsi, 0); 944218893Sdim 945218893Sdim if (phy_ops->power_off) 946218893Sdim phy_ops->power_off(dsi->plat_data->priv_data); 947218893Sdim 948203954Srdivacky if (dsi->slave) { 949203954Srdivacky dw_mipi_dsi_disable(dsi->slave); 950193323Sed clk_disable_unprepare(dsi->slave->pclk); 951218893Sdim pm_runtime_put(dsi->slave->dev); 952218893Sdim } 953218893Sdim dw_mipi_dsi_disable(dsi); 954218893Sdim 955203954Srdivacky clk_disable_unprepare(dsi->pclk); 956218893Sdim pm_runtime_put(dsi->dev); 957219077Sdim} 958219077Sdim 959219077Sdimstatic unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi) 960203954Srdivacky{ 961193323Sed /* this instance is the slave, so add the master's lanes */ 962218893Sdim if (dsi->master) 963218893Sdim return dsi->master->lanes + dsi->lanes; 964218893Sdim 965218893Sdim /* this instance is the master, so add the slave's lanes */ 966218893Sdim if (dsi->slave) 967218893Sdim return dsi->lanes + dsi->slave->lanes; 968218893Sdim 969218893Sdim /* single-dsi, so no other instance to consider */ 970218893Sdim return dsi->lanes; 971218893Sdim} 972218893Sdim 973218893Sdimstatic void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, 974218893Sdim const struct drm_display_mode *adjusted_mode) 975218893Sdim{ 976218893Sdim const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; 977218893Sdim void *priv_data = dsi->plat_data->priv_data; 978218893Sdim int ret; 979263508Sdim u32 lanes = dw_mipi_dsi_get_lanes(dsi); 980263508Sdim 981218893Sdim clk_prepare_enable(dsi->pclk); 982218893Sdim 983218893Sdim ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags, 984218893Sdim lanes, dsi->format, &dsi->lane_mbps); 985218893Sdim if (ret) 986218893Sdim DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n"); 987218893Sdim 988218893Sdim pm_runtime_get_sync(dsi->dev); 989218893Sdim dw_mipi_dsi_init(dsi); 990218893Sdim dw_mipi_dsi_dpi_config(dsi, adjusted_mode); 991218893Sdim dw_mipi_dsi_packet_handler_config(dsi); 992218893Sdim dw_mipi_dsi_video_mode_config(dsi); 993218893Sdim dw_mipi_dsi_video_packet_config(dsi, adjusted_mode); 994218893Sdim dw_mipi_dsi_command_mode_config(dsi); 995218893Sdim dw_mipi_dsi_line_timer_config(dsi, adjusted_mode); 996218893Sdim dw_mipi_dsi_vertical_timing_config(dsi, adjusted_mode); 997218893Sdim 998218893Sdim dw_mipi_dsi_dphy_init(dsi); 999218893Sdim dw_mipi_dsi_dphy_timing_config(dsi); 1000193323Sed dw_mipi_dsi_dphy_interface_config(dsi); 1001218893Sdim 1002218893Sdim dw_mipi_dsi_clear_err(dsi); 1003218893Sdim 1004218893Sdim ret = phy_ops->init(priv_data); 1005193323Sed if (ret) 1006193323Sed DRM_DEBUG_DRIVER("Phy init() failed\n"); 1007193323Sed 1008218893Sdim dw_mipi_dsi_dphy_enable(dsi); 1009218893Sdim 1010218893Sdim dw_mipi_dsi_wait_for_two_frames(adjusted_mode); 1011218893Sdim 1012193323Sed /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ 1013218893Sdim dw_mipi_dsi_set_mode(dsi, 0); 1014219077Sdim 1015219077Sdim if (phy_ops->power_on) 1016219077Sdim phy_ops->power_on(dsi->plat_data->priv_data); 1017193323Sed} 1018193323Sed 1019218893Sdimstatic void dw_mipi_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, 1020218893Sdim struct drm_bridge_state *old_bridge_state) 1021218893Sdim{ 1022218893Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 1023193323Sed 1024193323Sed /* Power up the dsi ctl into a command mode */ 1025193323Sed dw_mipi_dsi_mode_set(dsi, &dsi->mode); 1026218893Sdim if (dsi->slave) 1027218893Sdim dw_mipi_dsi_mode_set(dsi->slave, &dsi->mode); 1028218893Sdim} 1029218893Sdim 1030193323Sedstatic void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, 1031218893Sdim const struct drm_display_mode *mode, 1032219077Sdim const struct drm_display_mode *adjusted_mode) 1033219077Sdim{ 1034219077Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 1035193323Sed 1036193323Sed /* Store the display mode for later use in pre_enable callback */ 1037203954Srdivacky drm_mode_copy(&dsi->mode, adjusted_mode); 1038212904Sdim} 1039218893Sdim 1040218893Sdimstatic void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, 1041218893Sdim struct drm_bridge_state *old_bridge_state) 1042218893Sdim{ 1043218893Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 1044203954Srdivacky 1045203954Srdivacky /* Switch to video mode for panel-bridge enable & panel enable */ 1046203954Srdivacky dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); 1047218893Sdim if (dsi->slave) 1048218893Sdim dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); 1049218893Sdim} 1050218893Sdim 1051203954Srdivackystatic enum drm_mode_status 1052203954Srdivackydw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, 1053203954Srdivacky const struct drm_display_info *info, 1054218893Sdim const struct drm_display_mode *mode) 1055218893Sdim{ 1056218893Sdim struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 1057218893Sdim const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; 1058203954Srdivacky enum drm_mode_status mode_status = MODE_OK; 1059203954Srdivacky 1060203954Srdivacky if (pdata->mode_valid) 1061218893Sdim mode_status = pdata->mode_valid(pdata->priv_data, mode, 1062218893Sdim dsi->mode_flags, 1063218893Sdim dw_mipi_dsi_get_lanes(dsi), 1064218893Sdim dsi->format); 1065203954Srdivacky 1066203954Srdivacky return mode_status; 1067212904Sdim} 1068203954Srdivacky 1069203954Srdivackystatic int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, 1070203954Srdivacky enum drm_bridge_attach_flags flags) 1071203954Srdivacky{ 1072203954Srdivacky struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 1073203954Srdivacky 1074203954Srdivacky if (!bridge->encoder) { 1075203954Srdivacky DRM_ERROR("Parent encoder object not found\n"); 1076234353Sdim return -ENODEV; 1077203954Srdivacky } 1078203954Srdivacky 1079203954Srdivacky /* Set the encoder type as caller does not know it */ 1080234353Sdim bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI; 1081239462Sdim 1082239462Sdim /* Attach the panel-bridge to the dsi bridge */ 1083239462Sdim return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, 1084263508Sdim flags); 1085263508Sdim} 1086234353Sdim 1087234353Sdimstatic const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { 1088234353Sdim .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 1089234353Sdim .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 1090234353Sdim .atomic_get_input_bus_fmts = dw_mipi_dsi_bridge_atomic_get_input_bus_fmts, 1091234353Sdim .atomic_check = dw_mipi_dsi_bridge_atomic_check, 1092234353Sdim .atomic_reset = drm_atomic_helper_bridge_reset, 1093239462Sdim .atomic_pre_enable = dw_mipi_dsi_bridge_atomic_pre_enable, 1094239462Sdim .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, 1095239462Sdim .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, 1096263508Sdim .mode_set = dw_mipi_dsi_bridge_mode_set, 1097263508Sdim .mode_valid = dw_mipi_dsi_bridge_mode_valid, 1098234353Sdim .attach = dw_mipi_dsi_bridge_attach, 1099234353Sdim}; 1100234353Sdim 1101234353Sdim#ifdef CONFIG_DEBUG_FS 1102263508Sdim 1103263508Sdimstatic int dw_mipi_dsi_debugfs_write(void *data, u64 val) 1104234353Sdim{ 1105234353Sdim struct debugfs_entries *vpg = data; 1106234353Sdim struct dw_mipi_dsi *dsi; 1107234353Sdim u32 mode_cfg; 1108234353Sdim 1109219077Sdim if (!vpg) 1110219077Sdim return -ENODEV; 1111219077Sdim 1112218893Sdim dsi = vpg->dsi; 1113203954Srdivacky 1114234353Sdim *vpg->reg = (bool)val; 1115234353Sdim 1116234353Sdim mode_cfg = dsi_read(dsi, DSI_VID_MODE_CFG); 1117219077Sdim 1118219077Sdim if (*vpg->reg) 1119219077Sdim mode_cfg |= vpg->mask; 1120218893Sdim else 1121203954Srdivacky mode_cfg &= ~vpg->mask; 1122234353Sdim 1123234353Sdim dsi_write(dsi, DSI_VID_MODE_CFG, mode_cfg); 1124234353Sdim 1125219077Sdim return 0; 1126219077Sdim} 1127219077Sdim 1128218893Sdimstatic int dw_mipi_dsi_debugfs_show(void *data, u64 *val) 1129203954Srdivacky{ 1130234353Sdim struct debugfs_entries *vpg = data; 1131234353Sdim 1132234353Sdim if (!vpg) 1133219077Sdim return -ENODEV; 1134219077Sdim 1135219077Sdim *val = *vpg->reg; 1136218893Sdim 1137203954Srdivacky return 0; 1138234353Sdim} 1139234353Sdim 1140234353SdimDEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_mipi_dsi_debugfs_show, 1141203954Srdivacky dw_mipi_dsi_debugfs_write, "%llu\n"); 1142234353Sdim 1143234353Sdimstatic void debugfs_create_files(void *data) 1144234353Sdim{ 1145203954Srdivacky struct dw_mipi_dsi *dsi = data; 1146234353Sdim struct debugfs_entries debugfs[] = { 1147234353Sdim REGISTER(vpg, VID_MODE_VPG_ENABLE, dsi), 1148234353Sdim REGISTER(vpg_horizontal, VID_MODE_VPG_HORIZONTAL, dsi), 1149203954Srdivacky REGISTER(vpg_ber_pattern, VID_MODE_VPG_MODE, dsi), 1150234353Sdim }; 1151234353Sdim int i; 1152234353Sdim 1153203954Srdivacky dsi->debugfs_vpg = kmemdup(debugfs, sizeof(debugfs), GFP_KERNEL); 1154203954Srdivacky if (!dsi->debugfs_vpg) 1155203954Srdivacky return; 1156234353Sdim 1157234353Sdim for (i = 0; i < ARRAY_SIZE(debugfs); i++) 1158234353Sdim debugfs_create_file(dsi->debugfs_vpg[i].name, 0644, 1159219077Sdim dsi->debugfs, &dsi->debugfs_vpg[i], 1160219077Sdim &fops_x32); 1161219077Sdim} 1162218893Sdim 1163203954Srdivackystatic void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi) 1164234353Sdim{ 1165234353Sdim dsi->debugfs = debugfs_create_dir(dev_name(dsi->dev), NULL); 1166234353Sdim if (IS_ERR(dsi->debugfs)) { 1167219077Sdim dev_err(dsi->dev, "failed to create debugfs root\n"); 1168219077Sdim return; 1169219077Sdim } 1170218893Sdim 1171203954Srdivacky debugfs_create_files(dsi); 1172234353Sdim} 1173234353Sdim 1174234353Sdimstatic void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi) 1175219077Sdim{ 1176219077Sdim debugfs_remove_recursive(dsi->debugfs); 1177219077Sdim kfree(dsi->debugfs_vpg); 1178218893Sdim} 1179203954Srdivacky 1180234353Sdim#else 1181234353Sdim 1182234353Sdimstatic void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi) { } 1183219077Sdimstatic void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi) { } 1184219077Sdim 1185219077Sdim#endif /* CONFIG_DEBUG_FS */ 1186218893Sdim 1187203954Srdivackystatic struct dw_mipi_dsi * 1188234353Sdim__dw_mipi_dsi_probe(struct platform_device *pdev, 1189234353Sdim const struct dw_mipi_dsi_plat_data *plat_data) 1190234353Sdim{ 1191203954Srdivacky struct device *dev = &pdev->dev; 1192234353Sdim struct reset_control *apb_rst; 1193234353Sdim struct dw_mipi_dsi *dsi; 1194234353Sdim int ret; 1195203954Srdivacky 1196234353Sdim dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); 1197234353Sdim if (!dsi) 1198234353Sdim return ERR_PTR(-ENOMEM); 1199203954Srdivacky 1200234353Sdim dsi->dev = dev; 1201234353Sdim dsi->plat_data = plat_data; 1202234353Sdim 1203203954Srdivacky if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps || 1204234353Sdim !plat_data->phy_ops->get_timing) { 1205203954Srdivacky DRM_ERROR("Phy not properly configured\n"); 1206193323Sed return ERR_PTR(-ENODEV); 1207224145Sdim } 1208193323Sed 1209193323Sed if (!plat_data->base) { 1210218893Sdim dsi->base = devm_platform_ioremap_resource(pdev, 0); 1211218893Sdim if (IS_ERR(dsi->base)) 1212218893Sdim return ERR_PTR(-ENODEV); 1213218893Sdim 1214218893Sdim } else { 1215218893Sdim dsi->base = plat_data->base; 1216263508Sdim } 1217193323Sed 1218203954Srdivacky dsi->pclk = devm_clk_get(dev, "pclk"); 1219218893Sdim if (IS_ERR(dsi->pclk)) { 1220218893Sdim ret = PTR_ERR(dsi->pclk); 1221218893Sdim dev_err(dev, "Unable to get pclk: %d\n", ret); 1222218893Sdim return ERR_PTR(ret); 1223218893Sdim } 1224234353Sdim 1225219077Sdim /* 1226219077Sdim * Note that the reset was not defined in the initial device tree, so 1227219077Sdim * we have to be prepared for it not being found. 1228218893Sdim */ 1229193323Sed apb_rst = devm_reset_control_get_optional_exclusive(dev, "apb"); 1230218893Sdim if (IS_ERR(apb_rst)) { 1231218893Sdim ret = PTR_ERR(apb_rst); 1232263508Sdim 1233218893Sdim if (ret != -EPROBE_DEFER) 1234218893Sdim dev_err(dev, "Unable to get reset control: %d\n", ret); 1235234353Sdim 1236193323Sed return ERR_PTR(ret); 1237218893Sdim } 1238218893Sdim 1239218893Sdim if (apb_rst) { 1240218893Sdim ret = clk_prepare_enable(dsi->pclk); 1241218893Sdim if (ret) { 1242218893Sdim dev_err(dev, "%s: Failed to enable pclk\n", __func__); 1243263508Sdim return ERR_PTR(ret); 1244193323Sed } 1245203954Srdivacky 1246218893Sdim reset_control_assert(apb_rst); 1247218893Sdim usleep_range(10, 20); 1248218893Sdim reset_control_deassert(apb_rst); 1249218893Sdim 1250218893Sdim clk_disable_unprepare(dsi->pclk); 1251234353Sdim } 1252219077Sdim 1253219077Sdim dw_mipi_dsi_debugfs_init(dsi); 1254219077Sdim pm_runtime_enable(dev); 1255218893Sdim 1256193323Sed dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; 1257218893Sdim dsi->dsi_host.dev = dev; 1258218893Sdim ret = mipi_dsi_host_register(&dsi->dsi_host); 1259263508Sdim if (ret) { 1260218893Sdim dev_err(dev, "Failed to register MIPI host: %d\n", ret); 1261218893Sdim pm_runtime_disable(dev); 1262234353Sdim dw_mipi_dsi_debugfs_remove(dsi); 1263198090Srdivacky return ERR_PTR(ret); 1264218893Sdim } 1265218893Sdim 1266218893Sdim dsi->bridge.driver_private = dsi; 1267218893Sdim dsi->bridge.funcs = &dw_mipi_dsi_bridge_funcs; 1268218893Sdim dsi->bridge.of_node = pdev->dev.of_node; 1269218893Sdim 1270263508Sdim return dsi; 1271193323Sed} 1272203954Srdivacky 1273218893Sdimstatic void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) 1274218893Sdim{ 1275218893Sdim mipi_dsi_host_unregister(&dsi->dsi_host); 1276218893Sdim 1277218893Sdim pm_runtime_disable(dsi->dev); 1278234353Sdim dw_mipi_dsi_debugfs_remove(dsi); 1279219077Sdim} 1280219077Sdim 1281219077Sdimvoid dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave) 1282218893Sdim{ 1283193323Sed /* introduce controllers to each other */ 1284218893Sdim dsi->slave = slave; 1285218893Sdim dsi->slave->master = dsi; 1286263508Sdim 1287218893Sdim /* migrate settings for already attached displays */ 1288218893Sdim dsi->slave->lanes = dsi->lanes; 1289234353Sdim dsi->slave->channel = dsi->channel; 1290218893Sdim dsi->slave->format = dsi->format; 1291218893Sdim dsi->slave->mode_flags = dsi->mode_flags; 1292218893Sdim} 1293218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave); 1294218893Sdim 1295218893Sdimstruct drm_bridge *dw_mipi_dsi_get_bridge(struct dw_mipi_dsi *dsi) 1296218893Sdim{ 1297263508Sdim return &dsi->bridge; 1298218893Sdim} 1299218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_get_bridge); 1300218893Sdim 1301218893Sdim/* 1302218893Sdim * Probe/remove API, used from platforms based on the DRM bridge API. 1303218893Sdim */ 1304234353Sdimstruct dw_mipi_dsi * 1305219077Sdimdw_mipi_dsi_probe(struct platform_device *pdev, 1306219077Sdim const struct dw_mipi_dsi_plat_data *plat_data) 1307219077Sdim{ 1308218893Sdim return __dw_mipi_dsi_probe(pdev, plat_data); 1309218893Sdim} 1310218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_probe); 1311218893Sdim 1312263508Sdimvoid dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) 1313218893Sdim{ 1314218893Sdim __dw_mipi_dsi_remove(dsi); 1315234353Sdim} 1316218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); 1317234353Sdim 1318234353Sdim/* 1319234353Sdim * Bind/unbind API, used from platforms based on the component framework. 1320234353Sdim */ 1321234353Sdimint dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder) 1322234353Sdim{ 1323234353Sdim return drm_bridge_attach(encoder, &dsi->bridge, NULL, 0); 1324234353Sdim} 1325234353SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); 1326263508Sdim 1327218893Sdimvoid dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) 1328234353Sdim{ 1329234353Sdim} 1330234353SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); 1331234353Sdim 1332234353SdimMODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 1333234353SdimMODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); 1334234353SdimMODULE_DESCRIPTION("DW MIPI DSI host controller driver"); 1335234353SdimMODULE_LICENSE("GPL"); 1336234353SdimMODULE_ALIAS("platform:dw-mipi-dsi"); 1337234353Sdim