18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright: 2017 Cadence Design Systems, Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@bootlin.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 148c2ecf20Sopenharmony_ci#include <video/mipi_display.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of_address.h> 218c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 248c2ecf20Sopenharmony_ci#include <linux/reset.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 278c2ecf20Sopenharmony_ci#include <linux/phy/phy-mipi-dphy.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define IP_CONF 0x0 308c2ecf20Sopenharmony_ci#define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) 318c2ecf20Sopenharmony_ci#define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21) 328c2ecf20Sopenharmony_ci#define VRS_FIFO_DEPTH(x) (((x) & GENMASK(20, 16)) >> 16) 338c2ecf20Sopenharmony_ci#define DIRCMD_FIFO_DEPTH(x) (((x) & GENMASK(15, 13)) >> 13) 348c2ecf20Sopenharmony_ci#define SDI_IFACE_32 BIT(12) 358c2ecf20Sopenharmony_ci#define INTERNAL_DATAPATH_32 (0 << 10) 368c2ecf20Sopenharmony_ci#define INTERNAL_DATAPATH_16 (1 << 10) 378c2ecf20Sopenharmony_ci#define INTERNAL_DATAPATH_8 (3 << 10) 388c2ecf20Sopenharmony_ci#define INTERNAL_DATAPATH_SIZE ((x) & GENMASK(11, 10)) 398c2ecf20Sopenharmony_ci#define NUM_IFACE(x) ((((x) & GENMASK(9, 8)) >> 8) + 1) 408c2ecf20Sopenharmony_ci#define MAX_LANE_NB(x) (((x) & GENMASK(7, 6)) >> 6) 418c2ecf20Sopenharmony_ci#define RX_FIFO_DEPTH(x) ((x) & GENMASK(5, 0)) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define MCTL_MAIN_DATA_CTL 0x4 448c2ecf20Sopenharmony_ci#define TE_MIPI_POLLING_EN BIT(25) 458c2ecf20Sopenharmony_ci#define TE_HW_POLLING_EN BIT(24) 468c2ecf20Sopenharmony_ci#define DISP_EOT_GEN BIT(18) 478c2ecf20Sopenharmony_ci#define HOST_EOT_GEN BIT(17) 488c2ecf20Sopenharmony_ci#define DISP_GEN_CHECKSUM BIT(16) 498c2ecf20Sopenharmony_ci#define DISP_GEN_ECC BIT(15) 508c2ecf20Sopenharmony_ci#define BTA_EN BIT(14) 518c2ecf20Sopenharmony_ci#define READ_EN BIT(13) 528c2ecf20Sopenharmony_ci#define REG_TE_EN BIT(12) 538c2ecf20Sopenharmony_ci#define IF_TE_EN(x) BIT(8 + (x)) 548c2ecf20Sopenharmony_ci#define TVG_SEL BIT(6) 558c2ecf20Sopenharmony_ci#define VID_EN BIT(5) 568c2ecf20Sopenharmony_ci#define IF_VID_SELECT(x) ((x) << 2) 578c2ecf20Sopenharmony_ci#define IF_VID_SELECT_MASK GENMASK(3, 2) 588c2ecf20Sopenharmony_ci#define IF_VID_MODE BIT(1) 598c2ecf20Sopenharmony_ci#define LINK_EN BIT(0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define MCTL_MAIN_PHY_CTL 0x8 628c2ecf20Sopenharmony_ci#define HS_INVERT_DAT(x) BIT(19 + ((x) * 2)) 638c2ecf20Sopenharmony_ci#define SWAP_PINS_DAT(x) BIT(18 + ((x) * 2)) 648c2ecf20Sopenharmony_ci#define HS_INVERT_CLK BIT(17) 658c2ecf20Sopenharmony_ci#define SWAP_PINS_CLK BIT(16) 668c2ecf20Sopenharmony_ci#define HS_SKEWCAL_EN BIT(15) 678c2ecf20Sopenharmony_ci#define WAIT_BURST_TIME(x) ((x) << 10) 688c2ecf20Sopenharmony_ci#define DATA_ULPM_EN(x) BIT(6 + (x)) 698c2ecf20Sopenharmony_ci#define CLK_ULPM_EN BIT(5) 708c2ecf20Sopenharmony_ci#define CLK_CONTINUOUS BIT(4) 718c2ecf20Sopenharmony_ci#define DATA_LANE_EN(x) BIT((x) - 1) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define MCTL_MAIN_EN 0xc 748c2ecf20Sopenharmony_ci#define DATA_FORCE_STOP BIT(17) 758c2ecf20Sopenharmony_ci#define CLK_FORCE_STOP BIT(16) 768c2ecf20Sopenharmony_ci#define IF_EN(x) BIT(13 + (x)) 778c2ecf20Sopenharmony_ci#define DATA_LANE_ULPM_REQ(l) BIT(9 + (l)) 788c2ecf20Sopenharmony_ci#define CLK_LANE_ULPM_REQ BIT(8) 798c2ecf20Sopenharmony_ci#define DATA_LANE_START(x) BIT(4 + (x)) 808c2ecf20Sopenharmony_ci#define CLK_LANE_EN BIT(3) 818c2ecf20Sopenharmony_ci#define PLL_START BIT(0) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define MCTL_DPHY_CFG0 0x10 848c2ecf20Sopenharmony_ci#define DPHY_C_RSTB BIT(20) 858c2ecf20Sopenharmony_ci#define DPHY_D_RSTB(x) GENMASK(15 + (x), 16) 868c2ecf20Sopenharmony_ci#define DPHY_PLL_PDN BIT(10) 878c2ecf20Sopenharmony_ci#define DPHY_CMN_PDN BIT(9) 888c2ecf20Sopenharmony_ci#define DPHY_C_PDN BIT(8) 898c2ecf20Sopenharmony_ci#define DPHY_D_PDN(x) GENMASK(3 + (x), 4) 908c2ecf20Sopenharmony_ci#define DPHY_ALL_D_PDN GENMASK(7, 4) 918c2ecf20Sopenharmony_ci#define DPHY_PLL_PSO BIT(1) 928c2ecf20Sopenharmony_ci#define DPHY_CMN_PSO BIT(0) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define MCTL_DPHY_TIMEOUT1 0x14 958c2ecf20Sopenharmony_ci#define HSTX_TIMEOUT(x) ((x) << 4) 968c2ecf20Sopenharmony_ci#define HSTX_TIMEOUT_MAX GENMASK(17, 0) 978c2ecf20Sopenharmony_ci#define CLK_DIV(x) (x) 988c2ecf20Sopenharmony_ci#define CLK_DIV_MAX GENMASK(3, 0) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define MCTL_DPHY_TIMEOUT2 0x18 1018c2ecf20Sopenharmony_ci#define LPRX_TIMEOUT(x) (x) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define MCTL_ULPOUT_TIME 0x1c 1048c2ecf20Sopenharmony_ci#define DATA_LANE_ULPOUT_TIME(x) ((x) << 9) 1058c2ecf20Sopenharmony_ci#define CLK_LANE_ULPOUT_TIME(x) (x) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define MCTL_3DVIDEO_CTL 0x20 1088c2ecf20Sopenharmony_ci#define VID_VSYNC_3D_EN BIT(7) 1098c2ecf20Sopenharmony_ci#define VID_VSYNC_3D_LR BIT(5) 1108c2ecf20Sopenharmony_ci#define VID_VSYNC_3D_SECOND_EN BIT(4) 1118c2ecf20Sopenharmony_ci#define VID_VSYNC_3DFORMAT_LINE (0 << 2) 1128c2ecf20Sopenharmony_ci#define VID_VSYNC_3DFORMAT_FRAME (1 << 2) 1138c2ecf20Sopenharmony_ci#define VID_VSYNC_3DFORMAT_PIXEL (2 << 2) 1148c2ecf20Sopenharmony_ci#define VID_VSYNC_3DMODE_OFF 0 1158c2ecf20Sopenharmony_ci#define VID_VSYNC_3DMODE_PORTRAIT 1 1168c2ecf20Sopenharmony_ci#define VID_VSYNC_3DMODE_LANDSCAPE 2 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define MCTL_MAIN_STS 0x24 1198c2ecf20Sopenharmony_ci#define MCTL_MAIN_STS_CTL 0x130 1208c2ecf20Sopenharmony_ci#define MCTL_MAIN_STS_CLR 0x150 1218c2ecf20Sopenharmony_ci#define MCTL_MAIN_STS_FLAG 0x170 1228c2ecf20Sopenharmony_ci#define HS_SKEWCAL_DONE BIT(11) 1238c2ecf20Sopenharmony_ci#define IF_UNTERM_PKT_ERR(x) BIT(8 + (x)) 1248c2ecf20Sopenharmony_ci#define LPRX_TIMEOUT_ERR BIT(7) 1258c2ecf20Sopenharmony_ci#define HSTX_TIMEOUT_ERR BIT(6) 1268c2ecf20Sopenharmony_ci#define DATA_LANE_RDY(l) BIT(2 + (l)) 1278c2ecf20Sopenharmony_ci#define CLK_LANE_RDY BIT(1) 1288c2ecf20Sopenharmony_ci#define PLL_LOCKED BIT(0) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define MCTL_DPHY_ERR 0x28 1318c2ecf20Sopenharmony_ci#define MCTL_DPHY_ERR_CTL1 0x148 1328c2ecf20Sopenharmony_ci#define MCTL_DPHY_ERR_CLR 0x168 1338c2ecf20Sopenharmony_ci#define MCTL_DPHY_ERR_FLAG 0x188 1348c2ecf20Sopenharmony_ci#define ERR_CONT_LP(x, l) BIT(18 + ((x) * 4) + (l)) 1358c2ecf20Sopenharmony_ci#define ERR_CONTROL(l) BIT(14 + (l)) 1368c2ecf20Sopenharmony_ci#define ERR_SYNESC(l) BIT(10 + (l)) 1378c2ecf20Sopenharmony_ci#define ERR_ESC(l) BIT(6 + (l)) 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define MCTL_DPHY_ERR_CTL2 0x14c 1408c2ecf20Sopenharmony_ci#define ERR_CONT_LP_EDGE(x, l) BIT(12 + ((x) * 4) + (l)) 1418c2ecf20Sopenharmony_ci#define ERR_CONTROL_EDGE(l) BIT(8 + (l)) 1428c2ecf20Sopenharmony_ci#define ERR_SYN_ESC_EDGE(l) BIT(4 + (l)) 1438c2ecf20Sopenharmony_ci#define ERR_ESC_EDGE(l) BIT(0 + (l)) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define MCTL_LANE_STS 0x2c 1468c2ecf20Sopenharmony_ci#define PPI_C_TX_READY_HS BIT(18) 1478c2ecf20Sopenharmony_ci#define DPHY_PLL_LOCK BIT(17) 1488c2ecf20Sopenharmony_ci#define PPI_D_RX_ULPS_ESC(x) (((x) & GENMASK(15, 12)) >> 12) 1498c2ecf20Sopenharmony_ci#define LANE_STATE_START 0 1508c2ecf20Sopenharmony_ci#define LANE_STATE_IDLE 1 1518c2ecf20Sopenharmony_ci#define LANE_STATE_WRITE 2 1528c2ecf20Sopenharmony_ci#define LANE_STATE_ULPM 3 1538c2ecf20Sopenharmony_ci#define LANE_STATE_READ 4 1548c2ecf20Sopenharmony_ci#define DATA_LANE_STATE(l, val) \ 1558c2ecf20Sopenharmony_ci (((val) >> (2 + 2 * (l) + ((l) ? 1 : 0))) & GENMASK((l) ? 1 : 2, 0)) 1568c2ecf20Sopenharmony_ci#define CLK_LANE_STATE_HS 2 1578c2ecf20Sopenharmony_ci#define CLK_LANE_STATE(val) ((val) & GENMASK(1, 0)) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define DSC_MODE_CTL 0x30 1608c2ecf20Sopenharmony_ci#define DSC_MODE_EN BIT(0) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define DSC_CMD_SEND 0x34 1638c2ecf20Sopenharmony_ci#define DSC_SEND_PPS BIT(0) 1648c2ecf20Sopenharmony_ci#define DSC_EXECUTE_QUEUE BIT(1) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define DSC_PPS_WRDAT 0x38 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define DSC_MODE_STS 0x3c 1698c2ecf20Sopenharmony_ci#define DSC_PPS_DONE BIT(1) 1708c2ecf20Sopenharmony_ci#define DSC_EXEC_DONE BIT(2) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define CMD_MODE_CTL 0x70 1738c2ecf20Sopenharmony_ci#define IF_LP_EN(x) BIT(9 + (x)) 1748c2ecf20Sopenharmony_ci#define IF_VCHAN_ID(x, c) ((c) << ((x) * 2)) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define CMD_MODE_CTL2 0x74 1778c2ecf20Sopenharmony_ci#define TE_TIMEOUT(x) ((x) << 11) 1788c2ecf20Sopenharmony_ci#define FILL_VALUE(x) ((x) << 3) 1798c2ecf20Sopenharmony_ci#define ARB_IF_WITH_HIGHEST_PRIORITY(x) ((x) << 1) 1808c2ecf20Sopenharmony_ci#define ARB_ROUND_ROBIN_MODE BIT(0) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define CMD_MODE_STS 0x78 1838c2ecf20Sopenharmony_ci#define CMD_MODE_STS_CTL 0x134 1848c2ecf20Sopenharmony_ci#define CMD_MODE_STS_CLR 0x154 1858c2ecf20Sopenharmony_ci#define CMD_MODE_STS_FLAG 0x174 1868c2ecf20Sopenharmony_ci#define ERR_IF_UNDERRUN(x) BIT(4 + (x)) 1878c2ecf20Sopenharmony_ci#define ERR_UNWANTED_READ BIT(3) 1888c2ecf20Sopenharmony_ci#define ERR_TE_MISS BIT(2) 1898c2ecf20Sopenharmony_ci#define ERR_NO_TE BIT(1) 1908c2ecf20Sopenharmony_ci#define CSM_RUNNING BIT(0) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define DIRECT_CMD_SEND 0x80 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define DIRECT_CMD_MAIN_SETTINGS 0x84 1958c2ecf20Sopenharmony_ci#define TRIGGER_VAL(x) ((x) << 25) 1968c2ecf20Sopenharmony_ci#define CMD_LP_EN BIT(24) 1978c2ecf20Sopenharmony_ci#define CMD_SIZE(x) ((x) << 16) 1988c2ecf20Sopenharmony_ci#define CMD_VCHAN_ID(x) ((x) << 14) 1998c2ecf20Sopenharmony_ci#define CMD_DATATYPE(x) ((x) << 8) 2008c2ecf20Sopenharmony_ci#define CMD_LONG BIT(3) 2018c2ecf20Sopenharmony_ci#define WRITE_CMD 0 2028c2ecf20Sopenharmony_ci#define READ_CMD 1 2038c2ecf20Sopenharmony_ci#define TE_REQ 4 2048c2ecf20Sopenharmony_ci#define TRIGGER_REQ 5 2058c2ecf20Sopenharmony_ci#define BTA_REQ 6 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define DIRECT_CMD_STS 0x88 2088c2ecf20Sopenharmony_ci#define DIRECT_CMD_STS_CTL 0x138 2098c2ecf20Sopenharmony_ci#define DIRECT_CMD_STS_CLR 0x158 2108c2ecf20Sopenharmony_ci#define DIRECT_CMD_STS_FLAG 0x178 2118c2ecf20Sopenharmony_ci#define RCVD_ACK_VAL(val) ((val) >> 16) 2128c2ecf20Sopenharmony_ci#define RCVD_TRIGGER_VAL(val) (((val) & GENMASK(14, 11)) >> 11) 2138c2ecf20Sopenharmony_ci#define READ_COMPLETED_WITH_ERR BIT(10) 2148c2ecf20Sopenharmony_ci#define BTA_FINISHED BIT(9) 2158c2ecf20Sopenharmony_ci#define BTA_COMPLETED BIT(8) 2168c2ecf20Sopenharmony_ci#define TE_RCVD BIT(7) 2178c2ecf20Sopenharmony_ci#define TRIGGER_RCVD BIT(6) 2188c2ecf20Sopenharmony_ci#define ACK_WITH_ERR_RCVD BIT(5) 2198c2ecf20Sopenharmony_ci#define ACK_RCVD BIT(4) 2208c2ecf20Sopenharmony_ci#define READ_COMPLETED BIT(3) 2218c2ecf20Sopenharmony_ci#define TRIGGER_COMPLETED BIT(2) 2228c2ecf20Sopenharmony_ci#define WRITE_COMPLETED BIT(1) 2238c2ecf20Sopenharmony_ci#define SENDING_CMD BIT(0) 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#define DIRECT_CMD_STOP_READ 0x8c 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define DIRECT_CMD_WRDATA 0x90 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define DIRECT_CMD_FIFO_RST 0x94 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci#define DIRECT_CMD_RDDATA 0xa0 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define DIRECT_CMD_RD_PROPS 0xa4 2348c2ecf20Sopenharmony_ci#define RD_DCS BIT(18) 2358c2ecf20Sopenharmony_ci#define RD_VCHAN_ID(val) (((val) >> 16) & GENMASK(1, 0)) 2368c2ecf20Sopenharmony_ci#define RD_SIZE(val) ((val) & GENMASK(15, 0)) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define DIRECT_CMD_RD_STS 0xa8 2398c2ecf20Sopenharmony_ci#define DIRECT_CMD_RD_STS_CTL 0x13c 2408c2ecf20Sopenharmony_ci#define DIRECT_CMD_RD_STS_CLR 0x15c 2418c2ecf20Sopenharmony_ci#define DIRECT_CMD_RD_STS_FLAG 0x17c 2428c2ecf20Sopenharmony_ci#define ERR_EOT_WITH_ERR BIT(8) 2438c2ecf20Sopenharmony_ci#define ERR_MISSING_EOT BIT(7) 2448c2ecf20Sopenharmony_ci#define ERR_WRONG_LENGTH BIT(6) 2458c2ecf20Sopenharmony_ci#define ERR_OVERSIZE BIT(5) 2468c2ecf20Sopenharmony_ci#define ERR_RECEIVE BIT(4) 2478c2ecf20Sopenharmony_ci#define ERR_UNDECODABLE BIT(3) 2488c2ecf20Sopenharmony_ci#define ERR_CHECKSUM BIT(2) 2498c2ecf20Sopenharmony_ci#define ERR_UNCORRECTABLE BIT(1) 2508c2ecf20Sopenharmony_ci#define ERR_FIXED BIT(0) 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci#define VID_MAIN_CTL 0xb0 2538c2ecf20Sopenharmony_ci#define VID_IGNORE_MISS_VSYNC BIT(31) 2548c2ecf20Sopenharmony_ci#define VID_FIELD_SW BIT(28) 2558c2ecf20Sopenharmony_ci#define VID_INTERLACED_EN BIT(27) 2568c2ecf20Sopenharmony_ci#define RECOVERY_MODE(x) ((x) << 25) 2578c2ecf20Sopenharmony_ci#define RECOVERY_MODE_NEXT_HSYNC 0 2588c2ecf20Sopenharmony_ci#define RECOVERY_MODE_NEXT_STOP_POINT 2 2598c2ecf20Sopenharmony_ci#define RECOVERY_MODE_NEXT_VSYNC 3 2608c2ecf20Sopenharmony_ci#define REG_BLKEOL_MODE(x) ((x) << 23) 2618c2ecf20Sopenharmony_ci#define REG_BLKLINE_MODE(x) ((x) << 21) 2628c2ecf20Sopenharmony_ci#define REG_BLK_MODE_NULL_PKT 0 2638c2ecf20Sopenharmony_ci#define REG_BLK_MODE_BLANKING_PKT 1 2648c2ecf20Sopenharmony_ci#define REG_BLK_MODE_LP 2 2658c2ecf20Sopenharmony_ci#define SYNC_PULSE_HORIZONTAL BIT(20) 2668c2ecf20Sopenharmony_ci#define SYNC_PULSE_ACTIVE BIT(19) 2678c2ecf20Sopenharmony_ci#define BURST_MODE BIT(18) 2688c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_MASK GENMASK(17, 14) 2698c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB565 (0 << 14) 2708c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB666_PACKED (1 << 14) 2718c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB666 (2 << 14) 2728c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB888 (3 << 14) 2738c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB101010 (4 << 14) 2748c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_RGB121212 (5 << 14) 2758c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_YUV420 (8 << 14) 2768c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_YUV422_PACKED (9 << 14) 2778c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_YUV422 (10 << 14) 2788c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_YUV422_24B (11 << 14) 2798c2ecf20Sopenharmony_ci#define VID_PIXEL_MODE_DSC_COMP (12 << 14) 2808c2ecf20Sopenharmony_ci#define VID_DATATYPE(x) ((x) << 8) 2818c2ecf20Sopenharmony_ci#define VID_VIRTCHAN_ID(iface, x) ((x) << (4 + (iface) * 2)) 2828c2ecf20Sopenharmony_ci#define STOP_MODE(x) ((x) << 2) 2838c2ecf20Sopenharmony_ci#define START_MODE(x) (x) 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#define VID_VSIZE1 0xb4 2868c2ecf20Sopenharmony_ci#define VFP_LEN(x) ((x) << 12) 2878c2ecf20Sopenharmony_ci#define VBP_LEN(x) ((x) << 6) 2888c2ecf20Sopenharmony_ci#define VSA_LEN(x) (x) 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci#define VID_VSIZE2 0xb8 2918c2ecf20Sopenharmony_ci#define VACT_LEN(x) (x) 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci#define VID_HSIZE1 0xc0 2948c2ecf20Sopenharmony_ci#define HBP_LEN(x) ((x) << 16) 2958c2ecf20Sopenharmony_ci#define HSA_LEN(x) (x) 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci#define VID_HSIZE2 0xc4 2988c2ecf20Sopenharmony_ci#define HFP_LEN(x) ((x) << 16) 2998c2ecf20Sopenharmony_ci#define HACT_LEN(x) (x) 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci#define VID_BLKSIZE1 0xcc 3028c2ecf20Sopenharmony_ci#define BLK_EOL_PKT_LEN(x) ((x) << 15) 3038c2ecf20Sopenharmony_ci#define BLK_LINE_EVENT_PKT_LEN(x) (x) 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci#define VID_BLKSIZE2 0xd0 3068c2ecf20Sopenharmony_ci#define BLK_LINE_PULSE_PKT_LEN(x) (x) 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci#define VID_PKT_TIME 0xd8 3098c2ecf20Sopenharmony_ci#define BLK_EOL_DURATION(x) (x) 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define VID_DPHY_TIME 0xdc 3128c2ecf20Sopenharmony_ci#define REG_WAKEUP_TIME(x) ((x) << 17) 3138c2ecf20Sopenharmony_ci#define REG_LINE_DURATION(x) (x) 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci#define VID_ERR_COLOR1 0xe0 3168c2ecf20Sopenharmony_ci#define COL_GREEN(x) ((x) << 12) 3178c2ecf20Sopenharmony_ci#define COL_RED(x) (x) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci#define VID_ERR_COLOR2 0xe4 3208c2ecf20Sopenharmony_ci#define PAD_VAL(x) ((x) << 12) 3218c2ecf20Sopenharmony_ci#define COL_BLUE(x) (x) 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define VID_VPOS 0xe8 3248c2ecf20Sopenharmony_ci#define LINE_VAL(val) (((val) & GENMASK(14, 2)) >> 2) 3258c2ecf20Sopenharmony_ci#define LINE_POS(val) ((val) & GENMASK(1, 0)) 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci#define VID_HPOS 0xec 3288c2ecf20Sopenharmony_ci#define HORIZ_VAL(val) (((val) & GENMASK(17, 3)) >> 3) 3298c2ecf20Sopenharmony_ci#define HORIZ_POS(val) ((val) & GENMASK(2, 0)) 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci#define VID_MODE_STS 0xf0 3328c2ecf20Sopenharmony_ci#define VID_MODE_STS_CTL 0x140 3338c2ecf20Sopenharmony_ci#define VID_MODE_STS_CLR 0x160 3348c2ecf20Sopenharmony_ci#define VID_MODE_STS_FLAG 0x180 3358c2ecf20Sopenharmony_ci#define VSG_RECOVERY BIT(10) 3368c2ecf20Sopenharmony_ci#define ERR_VRS_WRONG_LEN BIT(9) 3378c2ecf20Sopenharmony_ci#define ERR_LONG_READ BIT(8) 3388c2ecf20Sopenharmony_ci#define ERR_LINE_WRITE BIT(7) 3398c2ecf20Sopenharmony_ci#define ERR_BURST_WRITE BIT(6) 3408c2ecf20Sopenharmony_ci#define ERR_SMALL_HEIGHT BIT(5) 3418c2ecf20Sopenharmony_ci#define ERR_SMALL_LEN BIT(4) 3428c2ecf20Sopenharmony_ci#define ERR_MISSING_VSYNC BIT(3) 3438c2ecf20Sopenharmony_ci#define ERR_MISSING_HSYNC BIT(2) 3448c2ecf20Sopenharmony_ci#define ERR_MISSING_DATA BIT(1) 3458c2ecf20Sopenharmony_ci#define VSG_RUNNING BIT(0) 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci#define VID_VCA_SETTING1 0xf4 3488c2ecf20Sopenharmony_ci#define BURST_LP BIT(16) 3498c2ecf20Sopenharmony_ci#define MAX_BURST_LIMIT(x) (x) 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#define VID_VCA_SETTING2 0xf8 3528c2ecf20Sopenharmony_ci#define MAX_LINE_LIMIT(x) ((x) << 16) 3538c2ecf20Sopenharmony_ci#define EXACT_BURST_LIMIT(x) (x) 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci#define TVG_CTL 0xfc 3568c2ecf20Sopenharmony_ci#define TVG_STRIPE_SIZE(x) ((x) << 5) 3578c2ecf20Sopenharmony_ci#define TVG_MODE_MASK GENMASK(4, 3) 3588c2ecf20Sopenharmony_ci#define TVG_MODE_SINGLE_COLOR (0 << 3) 3598c2ecf20Sopenharmony_ci#define TVG_MODE_VSTRIPES (2 << 3) 3608c2ecf20Sopenharmony_ci#define TVG_MODE_HSTRIPES (3 << 3) 3618c2ecf20Sopenharmony_ci#define TVG_STOPMODE_MASK GENMASK(2, 1) 3628c2ecf20Sopenharmony_ci#define TVG_STOPMODE_EOF (0 << 1) 3638c2ecf20Sopenharmony_ci#define TVG_STOPMODE_EOL (1 << 1) 3648c2ecf20Sopenharmony_ci#define TVG_STOPMODE_NOW (2 << 1) 3658c2ecf20Sopenharmony_ci#define TVG_RUN BIT(0) 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci#define TVG_IMG_SIZE 0x100 3688c2ecf20Sopenharmony_ci#define TVG_NBLINES(x) ((x) << 16) 3698c2ecf20Sopenharmony_ci#define TVG_LINE_SIZE(x) (x) 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci#define TVG_COLOR1 0x104 3728c2ecf20Sopenharmony_ci#define TVG_COL1_GREEN(x) ((x) << 12) 3738c2ecf20Sopenharmony_ci#define TVG_COL1_RED(x) (x) 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci#define TVG_COLOR1_BIS 0x108 3768c2ecf20Sopenharmony_ci#define TVG_COL1_BLUE(x) (x) 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci#define TVG_COLOR2 0x10c 3798c2ecf20Sopenharmony_ci#define TVG_COL2_GREEN(x) ((x) << 12) 3808c2ecf20Sopenharmony_ci#define TVG_COL2_RED(x) (x) 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci#define TVG_COLOR2_BIS 0x110 3838c2ecf20Sopenharmony_ci#define TVG_COL2_BLUE(x) (x) 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci#define TVG_STS 0x114 3868c2ecf20Sopenharmony_ci#define TVG_STS_CTL 0x144 3878c2ecf20Sopenharmony_ci#define TVG_STS_CLR 0x164 3888c2ecf20Sopenharmony_ci#define TVG_STS_FLAG 0x184 3898c2ecf20Sopenharmony_ci#define TVG_STS_RUNNING BIT(0) 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci#define STS_CTL_EDGE(e) ((e) << 16) 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci#define DPHY_LANES_MAP 0x198 3948c2ecf20Sopenharmony_ci#define DAT_REMAP_CFG(b, l) ((l) << ((b) * 8)) 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci#define DPI_IRQ_EN 0x1a0 3978c2ecf20Sopenharmony_ci#define DPI_IRQ_CLR 0x1a4 3988c2ecf20Sopenharmony_ci#define DPI_IRQ_STS 0x1a8 3998c2ecf20Sopenharmony_ci#define PIXEL_BUF_OVERFLOW BIT(0) 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci#define DPI_CFG 0x1ac 4028c2ecf20Sopenharmony_ci#define DPI_CFG_FIFO_DEPTH(x) ((x) >> 16) 4038c2ecf20Sopenharmony_ci#define DPI_CFG_FIFO_LEVEL(x) ((x) & GENMASK(15, 0)) 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci#define TEST_GENERIC 0x1f0 4068c2ecf20Sopenharmony_ci#define TEST_STATUS(x) ((x) >> 16) 4078c2ecf20Sopenharmony_ci#define TEST_CTRL(x) (x) 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#define ID_REG 0x1fc 4108c2ecf20Sopenharmony_ci#define REV_VENDOR_ID(x) (((x) & GENMASK(31, 20)) >> 20) 4118c2ecf20Sopenharmony_ci#define REV_PRODUCT_ID(x) (((x) & GENMASK(19, 12)) >> 12) 4128c2ecf20Sopenharmony_ci#define REV_HW(x) (((x) & GENMASK(11, 8)) >> 8) 4138c2ecf20Sopenharmony_ci#define REV_MAJOR(x) (((x) & GENMASK(7, 4)) >> 4) 4148c2ecf20Sopenharmony_ci#define REV_MINOR(x) ((x) & GENMASK(3, 0)) 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci#define DSI_OUTPUT_PORT 0 4178c2ecf20Sopenharmony_ci#define DSI_INPUT_PORT(inputid) (1 + (inputid)) 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci#define DSI_HBP_FRAME_OVERHEAD 12 4208c2ecf20Sopenharmony_ci#define DSI_HSA_FRAME_OVERHEAD 14 4218c2ecf20Sopenharmony_ci#define DSI_HFP_FRAME_OVERHEAD 6 4228c2ecf20Sopenharmony_ci#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4 4238c2ecf20Sopenharmony_ci#define DSI_BLANKING_FRAME_OVERHEAD 6 4248c2ecf20Sopenharmony_ci#define DSI_NULL_FRAME_OVERHEAD 6 4258c2ecf20Sopenharmony_ci#define DSI_EOT_PKT_SIZE 4 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistruct cdns_dsi_output { 4288c2ecf20Sopenharmony_ci struct mipi_dsi_device *dev; 4298c2ecf20Sopenharmony_ci struct drm_panel *panel; 4308c2ecf20Sopenharmony_ci struct drm_bridge *bridge; 4318c2ecf20Sopenharmony_ci union phy_configure_opts phy_opts; 4328c2ecf20Sopenharmony_ci}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cienum cdns_dsi_input_id { 4358c2ecf20Sopenharmony_ci CDNS_SDI_INPUT, 4368c2ecf20Sopenharmony_ci CDNS_DPI_INPUT, 4378c2ecf20Sopenharmony_ci CDNS_DSC_INPUT, 4388c2ecf20Sopenharmony_ci}; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistruct cdns_dsi_cfg { 4418c2ecf20Sopenharmony_ci unsigned int hfp; 4428c2ecf20Sopenharmony_ci unsigned int hsa; 4438c2ecf20Sopenharmony_ci unsigned int hbp; 4448c2ecf20Sopenharmony_ci unsigned int hact; 4458c2ecf20Sopenharmony_ci unsigned int htotal; 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistruct cdns_dsi_input { 4498c2ecf20Sopenharmony_ci enum cdns_dsi_input_id id; 4508c2ecf20Sopenharmony_ci struct drm_bridge bridge; 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistruct cdns_dsi { 4548c2ecf20Sopenharmony_ci struct mipi_dsi_host base; 4558c2ecf20Sopenharmony_ci void __iomem *regs; 4568c2ecf20Sopenharmony_ci struct cdns_dsi_input input; 4578c2ecf20Sopenharmony_ci struct cdns_dsi_output output; 4588c2ecf20Sopenharmony_ci unsigned int direct_cmd_fifo_depth; 4598c2ecf20Sopenharmony_ci unsigned int rx_fifo_depth; 4608c2ecf20Sopenharmony_ci struct completion direct_cmd_comp; 4618c2ecf20Sopenharmony_ci struct clk *dsi_p_clk; 4628c2ecf20Sopenharmony_ci struct reset_control *dsi_p_rst; 4638c2ecf20Sopenharmony_ci struct clk *dsi_sys_clk; 4648c2ecf20Sopenharmony_ci bool link_initialized; 4658c2ecf20Sopenharmony_ci struct phy *dphy; 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci return container_of(input, struct cdns_dsi, input); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic inline struct cdns_dsi *to_cdns_dsi(struct mipi_dsi_host *host) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci return container_of(host, struct cdns_dsi, base); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic inline struct cdns_dsi_input * 4798c2ecf20Sopenharmony_cibridge_to_cdns_dsi_input(struct drm_bridge *bridge) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci return container_of(bridge, struct cdns_dsi_input, bridge); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode, 4858c2ecf20Sopenharmony_ci bool mode_valid_check) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci if (mode_valid_check) 4888c2ecf20Sopenharmony_ci return mode->hsync_start - mode->hdisplay; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return mode->crtc_hsync_start - mode->crtc_hdisplay; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, 4948c2ecf20Sopenharmony_ci unsigned int dpi_bpp, 4958c2ecf20Sopenharmony_ci unsigned int dsi_pkt_overhead) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci unsigned int dsi_timing = DIV_ROUND_UP(dpi_timing * dpi_bpp, 8); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (dsi_timing < dsi_pkt_overhead) 5008c2ecf20Sopenharmony_ci dsi_timing = 0; 5018c2ecf20Sopenharmony_ci else 5028c2ecf20Sopenharmony_ci dsi_timing -= dsi_pkt_overhead; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return dsi_timing; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, 5088c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 5098c2ecf20Sopenharmony_ci struct cdns_dsi_cfg *dsi_cfg, 5108c2ecf20Sopenharmony_ci bool mode_valid_check) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 5138c2ecf20Sopenharmony_ci unsigned int tmp; 5148c2ecf20Sopenharmony_ci bool sync_pulse = false; 5158c2ecf20Sopenharmony_ci int bpp; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci memset(dsi_cfg, 0, sizeof(*dsi_cfg)); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 5208c2ecf20Sopenharmony_ci sync_pulse = true; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (mode_valid_check) 5258c2ecf20Sopenharmony_ci tmp = mode->htotal - 5268c2ecf20Sopenharmony_ci (sync_pulse ? mode->hsync_end : mode->hsync_start); 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci tmp = mode->crtc_htotal - 5298c2ecf20Sopenharmony_ci (sync_pulse ? 5308c2ecf20Sopenharmony_ci mode->crtc_hsync_end : mode->crtc_hsync_start); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci dsi_cfg->hbp = dpi_to_dsi_timing(tmp, bpp, DSI_HBP_FRAME_OVERHEAD); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (sync_pulse) { 5358c2ecf20Sopenharmony_ci if (mode_valid_check) 5368c2ecf20Sopenharmony_ci tmp = mode->hsync_end - mode->hsync_start; 5378c2ecf20Sopenharmony_ci else 5388c2ecf20Sopenharmony_ci tmp = mode->crtc_hsync_end - mode->crtc_hsync_start; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci dsi_cfg->hsa = dpi_to_dsi_timing(tmp, bpp, 5418c2ecf20Sopenharmony_ci DSI_HSA_FRAME_OVERHEAD); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci dsi_cfg->hact = dpi_to_dsi_timing(mode_valid_check ? 5458c2ecf20Sopenharmony_ci mode->hdisplay : mode->crtc_hdisplay, 5468c2ecf20Sopenharmony_ci bpp, 0); 5478c2ecf20Sopenharmony_ci dsi_cfg->hfp = dpi_to_dsi_timing(mode_to_dpi_hfp(mode, mode_valid_check), 5488c2ecf20Sopenharmony_ci bpp, DSI_HFP_FRAME_OVERHEAD); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi, 5548c2ecf20Sopenharmony_ci struct cdns_dsi_cfg *dsi_cfg, 5558c2ecf20Sopenharmony_ci struct phy_configure_opts_mipi_dphy *phy_cfg, 5568c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 5578c2ecf20Sopenharmony_ci bool mode_valid_check) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 5608c2ecf20Sopenharmony_ci unsigned long long dlane_bps; 5618c2ecf20Sopenharmony_ci unsigned long adj_dsi_htotal; 5628c2ecf20Sopenharmony_ci unsigned long dsi_htotal; 5638c2ecf20Sopenharmony_ci unsigned long dpi_htotal; 5648c2ecf20Sopenharmony_ci unsigned long dpi_hz; 5658c2ecf20Sopenharmony_ci unsigned int dsi_hfp_ext; 5668c2ecf20Sopenharmony_ci unsigned int lanes = output->dev->lanes; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; 5698c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 5708c2ecf20Sopenharmony_ci dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci dsi_htotal += dsi_cfg->hact; 5738c2ecf20Sopenharmony_ci dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Make sure DSI htotal is aligned on a lane boundary when calculating 5778c2ecf20Sopenharmony_ci * the expected data rate. This is done by extending HFP in case of 5788c2ecf20Sopenharmony_ci * misalignment. 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci adj_dsi_htotal = dsi_htotal; 5818c2ecf20Sopenharmony_ci if (dsi_htotal % lanes) 5828c2ecf20Sopenharmony_ci adj_dsi_htotal += lanes - (dsi_htotal % lanes); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci dpi_hz = (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000; 5858c2ecf20Sopenharmony_ci dlane_bps = (unsigned long long)dpi_hz * adj_dsi_htotal; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* data rate in bytes/sec is not an integer, refuse the mode. */ 5888c2ecf20Sopenharmony_ci dpi_htotal = mode_valid_check ? mode->htotal : mode->crtc_htotal; 5898c2ecf20Sopenharmony_ci if (do_div(dlane_bps, lanes * dpi_htotal)) 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* data rate was in bytes/sec, convert to bits/sec. */ 5938c2ecf20Sopenharmony_ci phy_cfg->hs_clk_rate = dlane_bps * 8; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; 5968c2ecf20Sopenharmony_ci dsi_cfg->hfp += dsi_hfp_ext; 5978c2ecf20Sopenharmony_ci dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return 0; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int cdns_dsi_check_conf(struct cdns_dsi *dsi, 6038c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 6048c2ecf20Sopenharmony_ci struct cdns_dsi_cfg *dsi_cfg, 6058c2ecf20Sopenharmony_ci bool mode_valid_check) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 6088c2ecf20Sopenharmony_ci struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; 6098c2ecf20Sopenharmony_ci unsigned long dsi_hss_hsa_hse_hbp; 6108c2ecf20Sopenharmony_ci unsigned int nlanes = output->dev->lanes; 6118c2ecf20Sopenharmony_ci int ret; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check); 6148c2ecf20Sopenharmony_ci if (ret) 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000, 6188c2ecf20Sopenharmony_ci mipi_dsi_pixel_format_to_bpp(output->dev->format), 6198c2ecf20Sopenharmony_ci nlanes, phy_cfg); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check); 6228c2ecf20Sopenharmony_ci if (ret) 6238c2ecf20Sopenharmony_ci return ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &output->phy_opts); 6268c2ecf20Sopenharmony_ci if (ret) 6278c2ecf20Sopenharmony_ci return ret; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci dsi_hss_hsa_hse_hbp = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; 6308c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 6318c2ecf20Sopenharmony_ci dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* 6348c2ecf20Sopenharmony_ci * Make sure DPI(HFP) > DSI(HSS+HSA+HSE+HBP) to guarantee that the FIFO 6358c2ecf20Sopenharmony_ci * is empty before we start a receiving a new line on the DPI 6368c2ecf20Sopenharmony_ci * interface. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci if ((u64)phy_cfg->hs_clk_rate * 6398c2ecf20Sopenharmony_ci mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < 6408c2ecf20Sopenharmony_ci (u64)dsi_hss_hsa_hse_hbp * 6418c2ecf20Sopenharmony_ci (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) 6428c2ecf20Sopenharmony_ci return -EINVAL; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int cdns_dsi_bridge_attach(struct drm_bridge *bridge, 6488c2ecf20Sopenharmony_ci enum drm_bridge_attach_flags flags) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); 6518c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = input_to_dsi(input); 6528c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) { 6558c2ecf20Sopenharmony_ci dev_err(dsi->base.dev, 6568c2ecf20Sopenharmony_ci "cdns-dsi driver is only compatible with DRM devices supporting atomic updates"); 6578c2ecf20Sopenharmony_ci return -ENOTSUPP; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return drm_bridge_attach(bridge->encoder, output->bridge, bridge, 6618c2ecf20Sopenharmony_ci flags); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic enum drm_mode_status 6658c2ecf20Sopenharmony_cicdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, 6668c2ecf20Sopenharmony_ci const struct drm_display_info *info, 6678c2ecf20Sopenharmony_ci const struct drm_display_mode *mode) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); 6708c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = input_to_dsi(input); 6718c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 6728c2ecf20Sopenharmony_ci struct cdns_dsi_cfg dsi_cfg; 6738c2ecf20Sopenharmony_ci int bpp, ret; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* 6768c2ecf20Sopenharmony_ci * VFP_DSI should be less than VFP_DPI and VFP_DSI should be at 6778c2ecf20Sopenharmony_ci * least 1. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_ci if (mode->vtotal - mode->vsync_end < 2) 6808c2ecf20Sopenharmony_ci return MODE_V_ILLEGAL; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* VSA_DSI = VSA_DPI and must be at least 2. */ 6838c2ecf20Sopenharmony_ci if (mode->vsync_end - mode->vsync_start < 2) 6848c2ecf20Sopenharmony_ci return MODE_V_ILLEGAL; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* HACT must be 32-bits aligned. */ 6878c2ecf20Sopenharmony_ci bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); 6888c2ecf20Sopenharmony_ci if ((mode->hdisplay * bpp) % 32) 6898c2ecf20Sopenharmony_ci return MODE_H_ILLEGAL; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, true); 6928c2ecf20Sopenharmony_ci if (ret) 6938c2ecf20Sopenharmony_ci return MODE_BAD; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return MODE_OK; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic void cdns_dsi_bridge_disable(struct drm_bridge *bridge) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); 7018c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = input_to_dsi(input); 7028c2ecf20Sopenharmony_ci u32 val; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci val = readl(dsi->regs + MCTL_MAIN_DATA_CTL); 7058c2ecf20Sopenharmony_ci val &= ~(IF_VID_SELECT_MASK | IF_VID_MODE | VID_EN | HOST_EOT_GEN | 7068c2ecf20Sopenharmony_ci DISP_EOT_GEN); 7078c2ecf20Sopenharmony_ci writel(val, dsi->regs + MCTL_MAIN_DATA_CTL); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci val = readl(dsi->regs + MCTL_MAIN_EN) & ~IF_EN(input->id); 7108c2ecf20Sopenharmony_ci writel(val, dsi->regs + MCTL_MAIN_EN); 7118c2ecf20Sopenharmony_ci pm_runtime_put(dsi->base.dev); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void cdns_dsi_hs_init(struct cdns_dsi *dsi) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 7178c2ecf20Sopenharmony_ci u32 status; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* 7208c2ecf20Sopenharmony_ci * Power all internal DPHY blocks down and maintain their reset line 7218c2ecf20Sopenharmony_ci * asserted before changing the DPHY config. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_ci writel(DPHY_CMN_PSO | DPHY_PLL_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | 7248c2ecf20Sopenharmony_ci DPHY_CMN_PDN | DPHY_PLL_PDN, 7258c2ecf20Sopenharmony_ci dsi->regs + MCTL_DPHY_CFG0); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci phy_init(dsi->dphy); 7288c2ecf20Sopenharmony_ci phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY); 7298c2ecf20Sopenharmony_ci phy_configure(dsi->dphy, &output->phy_opts); 7308c2ecf20Sopenharmony_ci phy_power_on(dsi->dphy); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Activate the PLL and wait until it's locked. */ 7338c2ecf20Sopenharmony_ci writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR); 7348c2ecf20Sopenharmony_ci writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN, 7358c2ecf20Sopenharmony_ci dsi->regs + MCTL_DPHY_CFG0); 7368c2ecf20Sopenharmony_ci WARN_ON_ONCE(readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status, 7378c2ecf20Sopenharmony_ci status & PLL_LOCKED, 100, 100)); 7388c2ecf20Sopenharmony_ci /* De-assert data and clock reset lines. */ 7398c2ecf20Sopenharmony_ci writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | 7408c2ecf20Sopenharmony_ci DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB, 7418c2ecf20Sopenharmony_ci dsi->regs + MCTL_DPHY_CFG0); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void cdns_dsi_init_link(struct cdns_dsi *dsi) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 7478c2ecf20Sopenharmony_ci unsigned long sysclk_period, ulpout; 7488c2ecf20Sopenharmony_ci u32 val; 7498c2ecf20Sopenharmony_ci int i; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (dsi->link_initialized) 7528c2ecf20Sopenharmony_ci return; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci val = 0; 7558c2ecf20Sopenharmony_ci for (i = 1; i < output->dev->lanes; i++) 7568c2ecf20Sopenharmony_ci val |= DATA_LANE_EN(i); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (!(output->dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) 7598c2ecf20Sopenharmony_ci val |= CLK_CONTINUOUS; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci writel(val, dsi->regs + MCTL_MAIN_PHY_CTL); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* ULPOUT should be set to 1ms and is expressed in sysclk cycles. */ 7648c2ecf20Sopenharmony_ci sysclk_period = NSEC_PER_SEC / clk_get_rate(dsi->dsi_sys_clk); 7658c2ecf20Sopenharmony_ci ulpout = DIV_ROUND_UP(NSEC_PER_MSEC, sysclk_period); 7668c2ecf20Sopenharmony_ci writel(CLK_LANE_ULPOUT_TIME(ulpout) | DATA_LANE_ULPOUT_TIME(ulpout), 7678c2ecf20Sopenharmony_ci dsi->regs + MCTL_ULPOUT_TIME); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci writel(LINK_EN, dsi->regs + MCTL_MAIN_DATA_CTL); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci val = CLK_LANE_EN | PLL_START; 7728c2ecf20Sopenharmony_ci for (i = 0; i < output->dev->lanes; i++) 7738c2ecf20Sopenharmony_ci val |= DATA_LANE_START(i); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci writel(val, dsi->regs + MCTL_MAIN_EN); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci dsi->link_initialized = true; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic void cdns_dsi_bridge_enable(struct drm_bridge *bridge) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); 7838c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = input_to_dsi(input); 7848c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 7858c2ecf20Sopenharmony_ci struct drm_display_mode *mode; 7868c2ecf20Sopenharmony_ci struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; 7878c2ecf20Sopenharmony_ci unsigned long tx_byte_period; 7888c2ecf20Sopenharmony_ci struct cdns_dsi_cfg dsi_cfg; 7898c2ecf20Sopenharmony_ci u32 tmp, reg_wakeup, div; 7908c2ecf20Sopenharmony_ci int nlanes; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) 7938c2ecf20Sopenharmony_ci return; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci mode = &bridge->encoder->crtc->state->adjusted_mode; 7968c2ecf20Sopenharmony_ci nlanes = output->dev->lanes; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci cdns_dsi_hs_init(dsi); 8018c2ecf20Sopenharmony_ci cdns_dsi_init_link(dsi); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), 8048c2ecf20Sopenharmony_ci dsi->regs + VID_HSIZE1); 8058c2ecf20Sopenharmony_ci writel(HFP_LEN(dsi_cfg.hfp) | HACT_LEN(dsi_cfg.hact), 8068c2ecf20Sopenharmony_ci dsi->regs + VID_HSIZE2); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci writel(VBP_LEN(mode->crtc_vtotal - mode->crtc_vsync_end - 1) | 8098c2ecf20Sopenharmony_ci VFP_LEN(mode->crtc_vsync_start - mode->crtc_vdisplay) | 8108c2ecf20Sopenharmony_ci VSA_LEN(mode->crtc_vsync_end - mode->crtc_vsync_start + 1), 8118c2ecf20Sopenharmony_ci dsi->regs + VID_VSIZE1); 8128c2ecf20Sopenharmony_ci writel(mode->crtc_vdisplay, dsi->regs + VID_VSIZE2); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci tmp = dsi_cfg.htotal - 8158c2ecf20Sopenharmony_ci (dsi_cfg.hsa + DSI_BLANKING_FRAME_OVERHEAD + 8168c2ecf20Sopenharmony_ci DSI_HSA_FRAME_OVERHEAD); 8178c2ecf20Sopenharmony_ci writel(BLK_LINE_PULSE_PKT_LEN(tmp), dsi->regs + VID_BLKSIZE2); 8188c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 8198c2ecf20Sopenharmony_ci writel(MAX_LINE_LIMIT(tmp - DSI_NULL_FRAME_OVERHEAD), 8208c2ecf20Sopenharmony_ci dsi->regs + VID_VCA_SETTING2); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci tmp = dsi_cfg.htotal - 8238c2ecf20Sopenharmony_ci (DSI_HSS_VSS_VSE_FRAME_OVERHEAD + DSI_BLANKING_FRAME_OVERHEAD); 8248c2ecf20Sopenharmony_ci writel(BLK_LINE_EVENT_PKT_LEN(tmp), dsi->regs + VID_BLKSIZE1); 8258c2ecf20Sopenharmony_ci if (!(output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) 8268c2ecf20Sopenharmony_ci writel(MAX_LINE_LIMIT(tmp - DSI_NULL_FRAME_OVERHEAD), 8278c2ecf20Sopenharmony_ci dsi->regs + VID_VCA_SETTING2); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci tmp = DIV_ROUND_UP(dsi_cfg.htotal, nlanes) - 8308c2ecf20Sopenharmony_ci DIV_ROUND_UP(dsi_cfg.hsa, nlanes); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (!(output->dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) 8338c2ecf20Sopenharmony_ci tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, 8368c2ecf20Sopenharmony_ci phy_cfg->hs_clk_rate); 8378c2ecf20Sopenharmony_ci reg_wakeup = (phy_cfg->hs_prepare + phy_cfg->hs_zero) / tx_byte_period; 8388c2ecf20Sopenharmony_ci writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp), 8398c2ecf20Sopenharmony_ci dsi->regs + VID_DPHY_TIME); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * HSTX and LPRX timeouts are both expressed in TX byte clk cycles and 8438c2ecf20Sopenharmony_ci * both should be set to at least the time it takes to transmit a 8448c2ecf20Sopenharmony_ci * frame. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci tmp = NSEC_PER_SEC / drm_mode_vrefresh(mode); 8478c2ecf20Sopenharmony_ci tmp /= tx_byte_period; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci for (div = 0; div <= CLK_DIV_MAX; div++) { 8508c2ecf20Sopenharmony_ci if (tmp <= HSTX_TIMEOUT_MAX) 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci tmp >>= 1; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (tmp > HSTX_TIMEOUT_MAX) 8578c2ecf20Sopenharmony_ci tmp = HSTX_TIMEOUT_MAX; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci writel(CLK_DIV(div) | HSTX_TIMEOUT(tmp), 8608c2ecf20Sopenharmony_ci dsi->regs + MCTL_DPHY_TIMEOUT1); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci writel(LPRX_TIMEOUT(tmp), dsi->regs + MCTL_DPHY_TIMEOUT2); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO) { 8658c2ecf20Sopenharmony_ci switch (output->dev->format) { 8668c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB888: 8678c2ecf20Sopenharmony_ci tmp = VID_PIXEL_MODE_RGB888 | 8688c2ecf20Sopenharmony_ci VID_DATATYPE(MIPI_DSI_PACKED_PIXEL_STREAM_24); 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB666: 8728c2ecf20Sopenharmony_ci tmp = VID_PIXEL_MODE_RGB666 | 8738c2ecf20Sopenharmony_ci VID_DATATYPE(MIPI_DSI_PIXEL_STREAM_3BYTE_18); 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB666_PACKED: 8778c2ecf20Sopenharmony_ci tmp = VID_PIXEL_MODE_RGB666_PACKED | 8788c2ecf20Sopenharmony_ci VID_DATATYPE(MIPI_DSI_PACKED_PIXEL_STREAM_18); 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB565: 8828c2ecf20Sopenharmony_ci tmp = VID_PIXEL_MODE_RGB565 | 8838c2ecf20Sopenharmony_ci VID_DATATYPE(MIPI_DSI_PACKED_PIXEL_STREAM_16); 8848c2ecf20Sopenharmony_ci break; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci default: 8878c2ecf20Sopenharmony_ci dev_err(dsi->base.dev, "Unsupported DSI format\n"); 8888c2ecf20Sopenharmony_ci return; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 8928c2ecf20Sopenharmony_ci tmp |= SYNC_PULSE_ACTIVE | SYNC_PULSE_HORIZONTAL; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci tmp |= REG_BLKLINE_MODE(REG_BLK_MODE_BLANKING_PKT) | 8958c2ecf20Sopenharmony_ci REG_BLKEOL_MODE(REG_BLK_MODE_BLANKING_PKT) | 8968c2ecf20Sopenharmony_ci RECOVERY_MODE(RECOVERY_MODE_NEXT_HSYNC) | 8978c2ecf20Sopenharmony_ci VID_IGNORE_MISS_VSYNC; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci writel(tmp, dsi->regs + VID_MAIN_CTL); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci tmp = readl(dsi->regs + MCTL_MAIN_DATA_CTL); 9038c2ecf20Sopenharmony_ci tmp &= ~(IF_VID_SELECT_MASK | HOST_EOT_GEN | IF_VID_MODE); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (!(output->dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) 9068c2ecf20Sopenharmony_ci tmp |= HOST_EOT_GEN; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO) 9098c2ecf20Sopenharmony_ci tmp |= IF_VID_MODE | IF_VID_SELECT(input->id) | VID_EN; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci writel(tmp, dsi->regs + MCTL_MAIN_DATA_CTL); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci tmp = readl(dsi->regs + MCTL_MAIN_EN) | IF_EN(input->id); 9148c2ecf20Sopenharmony_ci writel(tmp, dsi->regs + MCTL_MAIN_EN); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs cdns_dsi_bridge_funcs = { 9188c2ecf20Sopenharmony_ci .attach = cdns_dsi_bridge_attach, 9198c2ecf20Sopenharmony_ci .mode_valid = cdns_dsi_bridge_mode_valid, 9208c2ecf20Sopenharmony_ci .disable = cdns_dsi_bridge_disable, 9218c2ecf20Sopenharmony_ci .enable = cdns_dsi_bridge_enable, 9228c2ecf20Sopenharmony_ci}; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int cdns_dsi_attach(struct mipi_dsi_host *host, 9258c2ecf20Sopenharmony_ci struct mipi_dsi_device *dev) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = to_cdns_dsi(host); 9288c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 9298c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = &dsi->input; 9308c2ecf20Sopenharmony_ci struct drm_bridge *bridge; 9318c2ecf20Sopenharmony_ci struct drm_panel *panel; 9328c2ecf20Sopenharmony_ci struct device_node *np; 9338c2ecf20Sopenharmony_ci int ret; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* 9368c2ecf20Sopenharmony_ci * We currently do not support connecting several DSI devices to the 9378c2ecf20Sopenharmony_ci * same host. In order to support that we'd need the DRM bridge 9388c2ecf20Sopenharmony_ci * framework to allow dynamic reconfiguration of the bridge chain. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci if (output->dev) 9418c2ecf20Sopenharmony_ci return -EBUSY; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* We do not support burst mode yet. */ 9448c2ecf20Sopenharmony_ci if (dev->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) 9458c2ecf20Sopenharmony_ci return -ENOTSUPP; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* 9488c2ecf20Sopenharmony_ci * The host <-> device link might be described using an OF-graph 9498c2ecf20Sopenharmony_ci * representation, in this case we extract the device of_node from 9508c2ecf20Sopenharmony_ci * this representation, otherwise we use dsidev->dev.of_node which 9518c2ecf20Sopenharmony_ci * should have been filled by the core. 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci np = of_graph_get_remote_node(dsi->base.dev->of_node, DSI_OUTPUT_PORT, 9548c2ecf20Sopenharmony_ci dev->channel); 9558c2ecf20Sopenharmony_ci if (!np) 9568c2ecf20Sopenharmony_ci np = of_node_get(dev->dev.of_node); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci panel = of_drm_find_panel(np); 9598c2ecf20Sopenharmony_ci if (!IS_ERR(panel)) { 9608c2ecf20Sopenharmony_ci bridge = drm_panel_bridge_add_typed(panel, 9618c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DSI); 9628c2ecf20Sopenharmony_ci } else { 9638c2ecf20Sopenharmony_ci bridge = of_drm_find_bridge(dev->dev.of_node); 9648c2ecf20Sopenharmony_ci if (!bridge) 9658c2ecf20Sopenharmony_ci bridge = ERR_PTR(-EINVAL); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci of_node_put(np); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (IS_ERR(bridge)) { 9718c2ecf20Sopenharmony_ci ret = PTR_ERR(bridge); 9728c2ecf20Sopenharmony_ci dev_err(host->dev, "failed to add DSI device %s (err = %d)", 9738c2ecf20Sopenharmony_ci dev->name, ret); 9748c2ecf20Sopenharmony_ci return ret; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci output->dev = dev; 9788c2ecf20Sopenharmony_ci output->bridge = bridge; 9798c2ecf20Sopenharmony_ci output->panel = panel; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * The DSI output has been properly configured, we can now safely 9838c2ecf20Sopenharmony_ci * register the input to the bridge framework so that it can take place 9848c2ecf20Sopenharmony_ci * in a display pipeline. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_ci drm_bridge_add(&input->bridge); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic int cdns_dsi_detach(struct mipi_dsi_host *host, 9928c2ecf20Sopenharmony_ci struct mipi_dsi_device *dev) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = to_cdns_dsi(host); 9958c2ecf20Sopenharmony_ci struct cdns_dsi_output *output = &dsi->output; 9968c2ecf20Sopenharmony_ci struct cdns_dsi_input *input = &dsi->input; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci drm_bridge_remove(&input->bridge); 9998c2ecf20Sopenharmony_ci if (output->panel) 10008c2ecf20Sopenharmony_ci drm_panel_bridge_remove(output->bridge); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic irqreturn_t cdns_dsi_interrupt(int irq, void *data) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = data; 10088c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 10098c2ecf20Sopenharmony_ci u32 flag, ctl; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci flag = readl(dsi->regs + DIRECT_CMD_STS_FLAG); 10128c2ecf20Sopenharmony_ci if (flag) { 10138c2ecf20Sopenharmony_ci ctl = readl(dsi->regs + DIRECT_CMD_STS_CTL); 10148c2ecf20Sopenharmony_ci ctl &= ~flag; 10158c2ecf20Sopenharmony_ci writel(ctl, dsi->regs + DIRECT_CMD_STS_CTL); 10168c2ecf20Sopenharmony_ci complete(&dsi->direct_cmd_comp); 10178c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return ret; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic ssize_t cdns_dsi_transfer(struct mipi_dsi_host *host, 10248c2ecf20Sopenharmony_ci const struct mipi_dsi_msg *msg) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = to_cdns_dsi(host); 10278c2ecf20Sopenharmony_ci u32 cmd, sts, val, wait = WRITE_COMPLETED, ctl = 0; 10288c2ecf20Sopenharmony_ci struct mipi_dsi_packet packet; 10298c2ecf20Sopenharmony_ci int ret, i, tx_len, rx_len; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(host->dev); 10328c2ecf20Sopenharmony_ci if (ret < 0) 10338c2ecf20Sopenharmony_ci return ret; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci cdns_dsi_init_link(dsi); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci ret = mipi_dsi_create_packet(&packet, msg); 10388c2ecf20Sopenharmony_ci if (ret) 10398c2ecf20Sopenharmony_ci goto out; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci tx_len = msg->tx_buf ? msg->tx_len : 0; 10428c2ecf20Sopenharmony_ci rx_len = msg->rx_buf ? msg->rx_len : 0; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* For read operations, the maximum TX len is 2. */ 10458c2ecf20Sopenharmony_ci if (rx_len && tx_len > 2) { 10468c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 10478c2ecf20Sopenharmony_ci goto out; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* TX len is limited by the CMD FIFO depth. */ 10518c2ecf20Sopenharmony_ci if (tx_len > dsi->direct_cmd_fifo_depth) { 10528c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 10538c2ecf20Sopenharmony_ci goto out; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* RX len is limited by the RX FIFO depth. */ 10578c2ecf20Sopenharmony_ci if (rx_len > dsi->rx_fifo_depth) { 10588c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 10598c2ecf20Sopenharmony_ci goto out; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci cmd = CMD_SIZE(tx_len) | CMD_VCHAN_ID(msg->channel) | 10638c2ecf20Sopenharmony_ci CMD_DATATYPE(msg->type); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (msg->flags & MIPI_DSI_MSG_USE_LPM) 10668c2ecf20Sopenharmony_ci cmd |= CMD_LP_EN; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (mipi_dsi_packet_format_is_long(msg->type)) 10698c2ecf20Sopenharmony_ci cmd |= CMD_LONG; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (rx_len) { 10728c2ecf20Sopenharmony_ci cmd |= READ_CMD; 10738c2ecf20Sopenharmony_ci wait = READ_COMPLETED_WITH_ERR | READ_COMPLETED; 10748c2ecf20Sopenharmony_ci ctl = READ_EN | BTA_EN; 10758c2ecf20Sopenharmony_ci } else if (msg->flags & MIPI_DSI_MSG_REQ_ACK) { 10768c2ecf20Sopenharmony_ci cmd |= BTA_REQ; 10778c2ecf20Sopenharmony_ci wait = ACK_WITH_ERR_RCVD | ACK_RCVD; 10788c2ecf20Sopenharmony_ci ctl = BTA_EN; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci writel(readl(dsi->regs + MCTL_MAIN_DATA_CTL) | ctl, 10828c2ecf20Sopenharmony_ci dsi->regs + MCTL_MAIN_DATA_CTL); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci writel(cmd, dsi->regs + DIRECT_CMD_MAIN_SETTINGS); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci for (i = 0; i < tx_len; i += 4) { 10878c2ecf20Sopenharmony_ci const u8 *buf = msg->tx_buf; 10888c2ecf20Sopenharmony_ci int j; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci val = 0; 10918c2ecf20Sopenharmony_ci for (j = 0; j < 4 && j + i < tx_len; j++) 10928c2ecf20Sopenharmony_ci val |= (u32)buf[i + j] << (8 * j); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci writel(val, dsi->regs + DIRECT_CMD_WRDATA); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Clear status flags before sending the command. */ 10988c2ecf20Sopenharmony_ci writel(wait, dsi->regs + DIRECT_CMD_STS_CLR); 10998c2ecf20Sopenharmony_ci writel(wait, dsi->regs + DIRECT_CMD_STS_CTL); 11008c2ecf20Sopenharmony_ci reinit_completion(&dsi->direct_cmd_comp); 11018c2ecf20Sopenharmony_ci writel(0, dsi->regs + DIRECT_CMD_SEND); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci wait_for_completion_timeout(&dsi->direct_cmd_comp, 11048c2ecf20Sopenharmony_ci msecs_to_jiffies(1000)); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci sts = readl(dsi->regs + DIRECT_CMD_STS); 11078c2ecf20Sopenharmony_ci writel(wait, dsi->regs + DIRECT_CMD_STS_CLR); 11088c2ecf20Sopenharmony_ci writel(0, dsi->regs + DIRECT_CMD_STS_CTL); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci writel(readl(dsi->regs + MCTL_MAIN_DATA_CTL) & ~ctl, 11118c2ecf20Sopenharmony_ci dsi->regs + MCTL_MAIN_DATA_CTL); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* We did not receive the events we were waiting for. */ 11148c2ecf20Sopenharmony_ci if (!(sts & wait)) { 11158c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 11168c2ecf20Sopenharmony_ci goto out; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* 'READ' or 'WRITE with ACK' failed. */ 11208c2ecf20Sopenharmony_ci if (sts & (READ_COMPLETED_WITH_ERR | ACK_WITH_ERR_RCVD)) { 11218c2ecf20Sopenharmony_ci ret = -EIO; 11228c2ecf20Sopenharmony_ci goto out; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci for (i = 0; i < rx_len; i += 4) { 11268c2ecf20Sopenharmony_ci u8 *buf = msg->rx_buf; 11278c2ecf20Sopenharmony_ci int j; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci val = readl(dsi->regs + DIRECT_CMD_RDDATA); 11308c2ecf20Sopenharmony_ci for (j = 0; j < 4 && j + i < rx_len; j++) 11318c2ecf20Sopenharmony_ci buf[i + j] = val >> (8 * j); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ciout: 11358c2ecf20Sopenharmony_ci pm_runtime_put(host->dev); 11368c2ecf20Sopenharmony_ci return ret; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic const struct mipi_dsi_host_ops cdns_dsi_ops = { 11408c2ecf20Sopenharmony_ci .attach = cdns_dsi_attach, 11418c2ecf20Sopenharmony_ci .detach = cdns_dsi_detach, 11428c2ecf20Sopenharmony_ci .transfer = cdns_dsi_transfer, 11438c2ecf20Sopenharmony_ci}; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int __maybe_unused cdns_dsi_resume(struct device *dev) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = dev_get_drvdata(dev); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci reset_control_deassert(dsi->dsi_p_rst); 11508c2ecf20Sopenharmony_ci clk_prepare_enable(dsi->dsi_p_clk); 11518c2ecf20Sopenharmony_ci clk_prepare_enable(dsi->dsi_sys_clk); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return 0; 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic int __maybe_unused cdns_dsi_suspend(struct device *dev) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = dev_get_drvdata(dev); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->dsi_sys_clk); 11618c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->dsi_p_clk); 11628c2ecf20Sopenharmony_ci reset_control_assert(dsi->dsi_p_rst); 11638c2ecf20Sopenharmony_ci dsi->link_initialized = false; 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, 11688c2ecf20Sopenharmony_ci NULL); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int cdns_dsi_drm_probe(struct platform_device *pdev) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct cdns_dsi *dsi; 11738c2ecf20Sopenharmony_ci struct cdns_dsi_input *input; 11748c2ecf20Sopenharmony_ci struct resource *res; 11758c2ecf20Sopenharmony_ci int ret, irq; 11768c2ecf20Sopenharmony_ci u32 val; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); 11798c2ecf20Sopenharmony_ci if (!dsi) 11808c2ecf20Sopenharmony_ci return -ENOMEM; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dsi); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci input = &dsi->input; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 11878c2ecf20Sopenharmony_ci dsi->regs = devm_ioremap_resource(&pdev->dev, res); 11888c2ecf20Sopenharmony_ci if (IS_ERR(dsi->regs)) 11898c2ecf20Sopenharmony_ci return PTR_ERR(dsi->regs); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci dsi->dsi_p_clk = devm_clk_get(&pdev->dev, "dsi_p_clk"); 11928c2ecf20Sopenharmony_ci if (IS_ERR(dsi->dsi_p_clk)) 11938c2ecf20Sopenharmony_ci return PTR_ERR(dsi->dsi_p_clk); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci dsi->dsi_p_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, 11968c2ecf20Sopenharmony_ci "dsi_p_rst"); 11978c2ecf20Sopenharmony_ci if (IS_ERR(dsi->dsi_p_rst)) 11988c2ecf20Sopenharmony_ci return PTR_ERR(dsi->dsi_p_rst); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci dsi->dsi_sys_clk = devm_clk_get(&pdev->dev, "dsi_sys_clk"); 12018c2ecf20Sopenharmony_ci if (IS_ERR(dsi->dsi_sys_clk)) 12028c2ecf20Sopenharmony_ci return PTR_ERR(dsi->dsi_sys_clk); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 12058c2ecf20Sopenharmony_ci if (irq < 0) 12068c2ecf20Sopenharmony_ci return irq; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci dsi->dphy = devm_phy_get(&pdev->dev, "dphy"); 12098c2ecf20Sopenharmony_ci if (IS_ERR(dsi->dphy)) 12108c2ecf20Sopenharmony_ci return PTR_ERR(dsi->dphy); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dsi->dsi_p_clk); 12138c2ecf20Sopenharmony_ci if (ret) 12148c2ecf20Sopenharmony_ci return ret; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci val = readl(dsi->regs + ID_REG); 12178c2ecf20Sopenharmony_ci if (REV_VENDOR_ID(val) != 0xcad) { 12188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid vendor id\n"); 12198c2ecf20Sopenharmony_ci ret = -EINVAL; 12208c2ecf20Sopenharmony_ci goto err_disable_pclk; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci val = readl(dsi->regs + IP_CONF); 12248c2ecf20Sopenharmony_ci dsi->direct_cmd_fifo_depth = 1 << (DIRCMD_FIFO_DEPTH(val) + 2); 12258c2ecf20Sopenharmony_ci dsi->rx_fifo_depth = RX_FIFO_DEPTH(val); 12268c2ecf20Sopenharmony_ci init_completion(&dsi->direct_cmd_comp); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci writel(0, dsi->regs + MCTL_MAIN_DATA_CTL); 12298c2ecf20Sopenharmony_ci writel(0, dsi->regs + MCTL_MAIN_EN); 12308c2ecf20Sopenharmony_ci writel(0, dsi->regs + MCTL_MAIN_PHY_CTL); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci /* 12338c2ecf20Sopenharmony_ci * We only support the DPI input, so force input->id to 12348c2ecf20Sopenharmony_ci * CDNS_DPI_INPUT. 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci input->id = CDNS_DPI_INPUT; 12378c2ecf20Sopenharmony_ci input->bridge.funcs = &cdns_dsi_bridge_funcs; 12388c2ecf20Sopenharmony_ci input->bridge.of_node = pdev->dev.of_node; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Mask all interrupts before registering the IRQ handler. */ 12418c2ecf20Sopenharmony_ci writel(0, dsi->regs + MCTL_MAIN_STS_CTL); 12428c2ecf20Sopenharmony_ci writel(0, dsi->regs + MCTL_DPHY_ERR_CTL1); 12438c2ecf20Sopenharmony_ci writel(0, dsi->regs + CMD_MODE_STS_CTL); 12448c2ecf20Sopenharmony_ci writel(0, dsi->regs + DIRECT_CMD_STS_CTL); 12458c2ecf20Sopenharmony_ci writel(0, dsi->regs + DIRECT_CMD_RD_STS_CTL); 12468c2ecf20Sopenharmony_ci writel(0, dsi->regs + VID_MODE_STS_CTL); 12478c2ecf20Sopenharmony_ci writel(0, dsi->regs + TVG_STS_CTL); 12488c2ecf20Sopenharmony_ci writel(0, dsi->regs + DPI_IRQ_EN); 12498c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, cdns_dsi_interrupt, 0, 12508c2ecf20Sopenharmony_ci dev_name(&pdev->dev), dsi); 12518c2ecf20Sopenharmony_ci if (ret) 12528c2ecf20Sopenharmony_ci goto err_disable_pclk; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 12558c2ecf20Sopenharmony_ci dsi->base.dev = &pdev->dev; 12568c2ecf20Sopenharmony_ci dsi->base.ops = &cdns_dsi_ops; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci ret = mipi_dsi_host_register(&dsi->base); 12598c2ecf20Sopenharmony_ci if (ret) 12608c2ecf20Sopenharmony_ci goto err_disable_runtime_pm; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->dsi_p_clk); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci return 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cierr_disable_runtime_pm: 12678c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cierr_disable_pclk: 12708c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->dsi_p_clk); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return ret; 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cistatic int cdns_dsi_drm_remove(struct platform_device *pdev) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci struct cdns_dsi *dsi = platform_get_drvdata(pdev); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci mipi_dsi_host_unregister(&dsi->base); 12808c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return 0; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic const struct of_device_id cdns_dsi_of_match[] = { 12868c2ecf20Sopenharmony_ci { .compatible = "cdns,dsi" }, 12878c2ecf20Sopenharmony_ci { }, 12888c2ecf20Sopenharmony_ci}; 12898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cdns_dsi_of_match); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic struct platform_driver cdns_dsi_platform_driver = { 12928c2ecf20Sopenharmony_ci .probe = cdns_dsi_drm_probe, 12938c2ecf20Sopenharmony_ci .remove = cdns_dsi_drm_remove, 12948c2ecf20Sopenharmony_ci .driver = { 12958c2ecf20Sopenharmony_ci .name = "cdns-dsi", 12968c2ecf20Sopenharmony_ci .of_match_table = cdns_dsi_of_match, 12978c2ecf20Sopenharmony_ci .pm = &cdns_dsi_pm_ops, 12988c2ecf20Sopenharmony_ci }, 12998c2ecf20Sopenharmony_ci}; 13008c2ecf20Sopenharmony_cimodule_platform_driver(cdns_dsi_platform_driver); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>"); 13038c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence DSI driver"); 13048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 13058c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:cdns-dsi"); 13068c2ecf20Sopenharmony_ci 1307