18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Samsung SoC MIPI DSI Master driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Samsung Electronics Co., Ltd 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contacts: Tomasz Figa <t.figa@samsung.com> 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/component.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 178c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 188c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <video/mipi_display.h> 248c2ecf20Sopenharmony_ci#include <video/videomode.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 288c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h> 308c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 318c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "exynos_drm_crtc.h" 368c2ecf20Sopenharmony_ci#include "exynos_drm_drv.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* returns true iff both arguments logically differs */ 398c2ecf20Sopenharmony_ci#define NEQV(a, b) (!(a) ^ !(b)) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* DSIM_STATUS */ 428c2ecf20Sopenharmony_ci#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) 438c2ecf20Sopenharmony_ci#define DSIM_STOP_STATE_CLK (1 << 8) 448c2ecf20Sopenharmony_ci#define DSIM_TX_READY_HS_CLK (1 << 10) 458c2ecf20Sopenharmony_ci#define DSIM_PLL_STABLE (1 << 31) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* DSIM_SWRST */ 488c2ecf20Sopenharmony_ci#define DSIM_FUNCRST (1 << 16) 498c2ecf20Sopenharmony_ci#define DSIM_SWRST (1 << 0) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* DSIM_TIMEOUT */ 528c2ecf20Sopenharmony_ci#define DSIM_LPDR_TIMEOUT(x) ((x) << 0) 538c2ecf20Sopenharmony_ci#define DSIM_BTA_TIMEOUT(x) ((x) << 16) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* DSIM_CLKCTRL */ 568c2ecf20Sopenharmony_ci#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0) 578c2ecf20Sopenharmony_ci#define DSIM_ESC_PRESCALER_MASK (0xffff << 0) 588c2ecf20Sopenharmony_ci#define DSIM_LANE_ESC_CLK_EN_CLK (1 << 19) 598c2ecf20Sopenharmony_ci#define DSIM_LANE_ESC_CLK_EN_DATA(x) (((x) & 0xf) << 20) 608c2ecf20Sopenharmony_ci#define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20) 618c2ecf20Sopenharmony_ci#define DSIM_BYTE_CLKEN (1 << 24) 628c2ecf20Sopenharmony_ci#define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25) 638c2ecf20Sopenharmony_ci#define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25) 648c2ecf20Sopenharmony_ci#define DSIM_PLL_BYPASS (1 << 27) 658c2ecf20Sopenharmony_ci#define DSIM_ESC_CLKEN (1 << 28) 668c2ecf20Sopenharmony_ci#define DSIM_TX_REQUEST_HSCLK (1 << 31) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* DSIM_CONFIG */ 698c2ecf20Sopenharmony_ci#define DSIM_LANE_EN_CLK (1 << 0) 708c2ecf20Sopenharmony_ci#define DSIM_LANE_EN(x) (((x) & 0xf) << 1) 718c2ecf20Sopenharmony_ci#define DSIM_NUM_OF_DATA_LANE(x) (((x) & 0x3) << 5) 728c2ecf20Sopenharmony_ci#define DSIM_SUB_PIX_FORMAT(x) (((x) & 0x7) << 8) 738c2ecf20Sopenharmony_ci#define DSIM_MAIN_PIX_FORMAT_MASK (0x7 << 12) 748c2ecf20Sopenharmony_ci#define DSIM_MAIN_PIX_FORMAT_RGB888 (0x7 << 12) 758c2ecf20Sopenharmony_ci#define DSIM_MAIN_PIX_FORMAT_RGB666 (0x6 << 12) 768c2ecf20Sopenharmony_ci#define DSIM_MAIN_PIX_FORMAT_RGB666_P (0x5 << 12) 778c2ecf20Sopenharmony_ci#define DSIM_MAIN_PIX_FORMAT_RGB565 (0x4 << 12) 788c2ecf20Sopenharmony_ci#define DSIM_SUB_VC (((x) & 0x3) << 16) 798c2ecf20Sopenharmony_ci#define DSIM_MAIN_VC (((x) & 0x3) << 18) 808c2ecf20Sopenharmony_ci#define DSIM_HSA_MODE (1 << 20) 818c2ecf20Sopenharmony_ci#define DSIM_HBP_MODE (1 << 21) 828c2ecf20Sopenharmony_ci#define DSIM_HFP_MODE (1 << 22) 838c2ecf20Sopenharmony_ci#define DSIM_HSE_MODE (1 << 23) 848c2ecf20Sopenharmony_ci#define DSIM_AUTO_MODE (1 << 24) 858c2ecf20Sopenharmony_ci#define DSIM_VIDEO_MODE (1 << 25) 868c2ecf20Sopenharmony_ci#define DSIM_BURST_MODE (1 << 26) 878c2ecf20Sopenharmony_ci#define DSIM_SYNC_INFORM (1 << 27) 888c2ecf20Sopenharmony_ci#define DSIM_EOT_DISABLE (1 << 28) 898c2ecf20Sopenharmony_ci#define DSIM_MFLUSH_VS (1 << 29) 908c2ecf20Sopenharmony_ci/* This flag is valid only for exynos3250/3472/5260/5430 */ 918c2ecf20Sopenharmony_ci#define DSIM_CLKLANE_STOP (1 << 30) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* DSIM_ESCMODE */ 948c2ecf20Sopenharmony_ci#define DSIM_TX_TRIGGER_RST (1 << 4) 958c2ecf20Sopenharmony_ci#define DSIM_TX_LPDT_LP (1 << 6) 968c2ecf20Sopenharmony_ci#define DSIM_CMD_LPDT_LP (1 << 7) 978c2ecf20Sopenharmony_ci#define DSIM_FORCE_BTA (1 << 16) 988c2ecf20Sopenharmony_ci#define DSIM_FORCE_STOP_STATE (1 << 20) 998c2ecf20Sopenharmony_ci#define DSIM_STOP_STATE_CNT(x) (((x) & 0x7ff) << 21) 1008c2ecf20Sopenharmony_ci#define DSIM_STOP_STATE_CNT_MASK (0x7ff << 21) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* DSIM_MDRESOL */ 1038c2ecf20Sopenharmony_ci#define DSIM_MAIN_STAND_BY (1 << 31) 1048c2ecf20Sopenharmony_ci#define DSIM_MAIN_VRESOL(x, num_bits) (((x) & ((1 << (num_bits)) - 1)) << 16) 1058c2ecf20Sopenharmony_ci#define DSIM_MAIN_HRESOL(x, num_bits) (((x) & ((1 << (num_bits)) - 1)) << 0) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* DSIM_MVPORCH */ 1088c2ecf20Sopenharmony_ci#define DSIM_CMD_ALLOW(x) ((x) << 28) 1098c2ecf20Sopenharmony_ci#define DSIM_STABLE_VFP(x) ((x) << 16) 1108c2ecf20Sopenharmony_ci#define DSIM_MAIN_VBP(x) ((x) << 0) 1118c2ecf20Sopenharmony_ci#define DSIM_CMD_ALLOW_MASK (0xf << 28) 1128c2ecf20Sopenharmony_ci#define DSIM_STABLE_VFP_MASK (0x7ff << 16) 1138c2ecf20Sopenharmony_ci#define DSIM_MAIN_VBP_MASK (0x7ff << 0) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* DSIM_MHPORCH */ 1168c2ecf20Sopenharmony_ci#define DSIM_MAIN_HFP(x) ((x) << 16) 1178c2ecf20Sopenharmony_ci#define DSIM_MAIN_HBP(x) ((x) << 0) 1188c2ecf20Sopenharmony_ci#define DSIM_MAIN_HFP_MASK ((0xffff) << 16) 1198c2ecf20Sopenharmony_ci#define DSIM_MAIN_HBP_MASK ((0xffff) << 0) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* DSIM_MSYNC */ 1228c2ecf20Sopenharmony_ci#define DSIM_MAIN_VSA(x) ((x) << 22) 1238c2ecf20Sopenharmony_ci#define DSIM_MAIN_HSA(x) ((x) << 0) 1248c2ecf20Sopenharmony_ci#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22) 1258c2ecf20Sopenharmony_ci#define DSIM_MAIN_HSA_MASK ((0xffff) << 0) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* DSIM_SDRESOL */ 1288c2ecf20Sopenharmony_ci#define DSIM_SUB_STANDY(x) ((x) << 31) 1298c2ecf20Sopenharmony_ci#define DSIM_SUB_VRESOL(x) ((x) << 16) 1308c2ecf20Sopenharmony_ci#define DSIM_SUB_HRESOL(x) ((x) << 0) 1318c2ecf20Sopenharmony_ci#define DSIM_SUB_STANDY_MASK ((0x1) << 31) 1328c2ecf20Sopenharmony_ci#define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16) 1338c2ecf20Sopenharmony_ci#define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* DSIM_INTSRC */ 1368c2ecf20Sopenharmony_ci#define DSIM_INT_PLL_STABLE (1 << 31) 1378c2ecf20Sopenharmony_ci#define DSIM_INT_SW_RST_RELEASE (1 << 30) 1388c2ecf20Sopenharmony_ci#define DSIM_INT_SFR_FIFO_EMPTY (1 << 29) 1398c2ecf20Sopenharmony_ci#define DSIM_INT_SFR_HDR_FIFO_EMPTY (1 << 28) 1408c2ecf20Sopenharmony_ci#define DSIM_INT_BTA (1 << 25) 1418c2ecf20Sopenharmony_ci#define DSIM_INT_FRAME_DONE (1 << 24) 1428c2ecf20Sopenharmony_ci#define DSIM_INT_RX_TIMEOUT (1 << 21) 1438c2ecf20Sopenharmony_ci#define DSIM_INT_BTA_TIMEOUT (1 << 20) 1448c2ecf20Sopenharmony_ci#define DSIM_INT_RX_DONE (1 << 18) 1458c2ecf20Sopenharmony_ci#define DSIM_INT_RX_TE (1 << 17) 1468c2ecf20Sopenharmony_ci#define DSIM_INT_RX_ACK (1 << 16) 1478c2ecf20Sopenharmony_ci#define DSIM_INT_RX_ECC_ERR (1 << 15) 1488c2ecf20Sopenharmony_ci#define DSIM_INT_RX_CRC_ERR (1 << 14) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* DSIM_FIFOCTRL */ 1518c2ecf20Sopenharmony_ci#define DSIM_RX_DATA_FULL (1 << 25) 1528c2ecf20Sopenharmony_ci#define DSIM_RX_DATA_EMPTY (1 << 24) 1538c2ecf20Sopenharmony_ci#define DSIM_SFR_HEADER_FULL (1 << 23) 1548c2ecf20Sopenharmony_ci#define DSIM_SFR_HEADER_EMPTY (1 << 22) 1558c2ecf20Sopenharmony_ci#define DSIM_SFR_PAYLOAD_FULL (1 << 21) 1568c2ecf20Sopenharmony_ci#define DSIM_SFR_PAYLOAD_EMPTY (1 << 20) 1578c2ecf20Sopenharmony_ci#define DSIM_I80_HEADER_FULL (1 << 19) 1588c2ecf20Sopenharmony_ci#define DSIM_I80_HEADER_EMPTY (1 << 18) 1598c2ecf20Sopenharmony_ci#define DSIM_I80_PAYLOAD_FULL (1 << 17) 1608c2ecf20Sopenharmony_ci#define DSIM_I80_PAYLOAD_EMPTY (1 << 16) 1618c2ecf20Sopenharmony_ci#define DSIM_SD_HEADER_FULL (1 << 15) 1628c2ecf20Sopenharmony_ci#define DSIM_SD_HEADER_EMPTY (1 << 14) 1638c2ecf20Sopenharmony_ci#define DSIM_SD_PAYLOAD_FULL (1 << 13) 1648c2ecf20Sopenharmony_ci#define DSIM_SD_PAYLOAD_EMPTY (1 << 12) 1658c2ecf20Sopenharmony_ci#define DSIM_MD_HEADER_FULL (1 << 11) 1668c2ecf20Sopenharmony_ci#define DSIM_MD_HEADER_EMPTY (1 << 10) 1678c2ecf20Sopenharmony_ci#define DSIM_MD_PAYLOAD_FULL (1 << 9) 1688c2ecf20Sopenharmony_ci#define DSIM_MD_PAYLOAD_EMPTY (1 << 8) 1698c2ecf20Sopenharmony_ci#define DSIM_RX_FIFO (1 << 4) 1708c2ecf20Sopenharmony_ci#define DSIM_SFR_FIFO (1 << 3) 1718c2ecf20Sopenharmony_ci#define DSIM_I80_FIFO (1 << 2) 1728c2ecf20Sopenharmony_ci#define DSIM_SD_FIFO (1 << 1) 1738c2ecf20Sopenharmony_ci#define DSIM_MD_FIFO (1 << 0) 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* DSIM_PHYACCHR */ 1768c2ecf20Sopenharmony_ci#define DSIM_AFC_EN (1 << 14) 1778c2ecf20Sopenharmony_ci#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* DSIM_PLLCTRL */ 1808c2ecf20Sopenharmony_ci#define DSIM_FREQ_BAND(x) ((x) << 24) 1818c2ecf20Sopenharmony_ci#define DSIM_PLL_EN (1 << 23) 1828c2ecf20Sopenharmony_ci#define DSIM_PLL_P(x) ((x) << 13) 1838c2ecf20Sopenharmony_ci#define DSIM_PLL_M(x) ((x) << 4) 1848c2ecf20Sopenharmony_ci#define DSIM_PLL_S(x) ((x) << 1) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* DSIM_PHYCTRL */ 1878c2ecf20Sopenharmony_ci#define DSIM_PHYCTRL_ULPS_EXIT(x) (((x) & 0x1ff) << 0) 1888c2ecf20Sopenharmony_ci#define DSIM_PHYCTRL_B_DPHYCTL_VREG_LP (1 << 30) 1898c2ecf20Sopenharmony_ci#define DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP (1 << 14) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* DSIM_PHYTIMING */ 1928c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING_LPX(x) ((x) << 8) 1938c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING_HS_EXIT(x) ((x) << 0) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* DSIM_PHYTIMING1 */ 1968c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING1_CLK_PREPARE(x) ((x) << 24) 1978c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING1_CLK_ZERO(x) ((x) << 16) 1988c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING1_CLK_POST(x) ((x) << 8) 1998c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING1_CLK_TRAIL(x) ((x) << 0) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* DSIM_PHYTIMING2 */ 2028c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING2_HS_PREPARE(x) ((x) << 16) 2038c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING2_HS_ZERO(x) ((x) << 8) 2048c2ecf20Sopenharmony_ci#define DSIM_PHYTIMING2_HS_TRAIL(x) ((x) << 0) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define DSI_MAX_BUS_WIDTH 4 2078c2ecf20Sopenharmony_ci#define DSI_NUM_VIRTUAL_CHANNELS 4 2088c2ecf20Sopenharmony_ci#define DSI_TX_FIFO_SIZE 2048 2098c2ecf20Sopenharmony_ci#define DSI_RX_FIFO_SIZE 256 2108c2ecf20Sopenharmony_ci#define DSI_XFER_TIMEOUT_MS 100 2118c2ecf20Sopenharmony_ci#define DSI_RX_FIFO_EMPTY 0x30800002 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#define OLD_SCLK_MIPI_CLK_NAME "pll_clk" 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic const char *const clk_names[5] = { "bus_clk", "sclk_mipi", 2168c2ecf20Sopenharmony_ci "phyclk_mipidphy0_bitclkdiv8", "phyclk_mipidphy0_rxclkesc0", 2178c2ecf20Sopenharmony_ci "sclk_rgb_vclk_to_dsim0" }; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cienum exynos_dsi_transfer_type { 2208c2ecf20Sopenharmony_ci EXYNOS_DSI_TX, 2218c2ecf20Sopenharmony_ci EXYNOS_DSI_RX, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistruct exynos_dsi_transfer { 2258c2ecf20Sopenharmony_ci struct list_head list; 2268c2ecf20Sopenharmony_ci struct completion completed; 2278c2ecf20Sopenharmony_ci int result; 2288c2ecf20Sopenharmony_ci struct mipi_dsi_packet packet; 2298c2ecf20Sopenharmony_ci u16 flags; 2308c2ecf20Sopenharmony_ci u16 tx_done; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci u8 *rx_payload; 2338c2ecf20Sopenharmony_ci u16 rx_len; 2348c2ecf20Sopenharmony_ci u16 rx_done; 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define DSIM_STATE_ENABLED BIT(0) 2388c2ecf20Sopenharmony_ci#define DSIM_STATE_INITIALIZED BIT(1) 2398c2ecf20Sopenharmony_ci#define DSIM_STATE_CMD_LPM BIT(2) 2408c2ecf20Sopenharmony_ci#define DSIM_STATE_VIDOUT_AVAILABLE BIT(3) 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistruct exynos_dsi_driver_data { 2438c2ecf20Sopenharmony_ci const unsigned int *reg_ofs; 2448c2ecf20Sopenharmony_ci unsigned int plltmr_reg; 2458c2ecf20Sopenharmony_ci unsigned int has_freqband:1; 2468c2ecf20Sopenharmony_ci unsigned int has_clklane_stop:1; 2478c2ecf20Sopenharmony_ci unsigned int num_clks; 2488c2ecf20Sopenharmony_ci unsigned int max_freq; 2498c2ecf20Sopenharmony_ci unsigned int wait_for_reset; 2508c2ecf20Sopenharmony_ci unsigned int num_bits_resol; 2518c2ecf20Sopenharmony_ci const unsigned int *reg_values; 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistruct exynos_dsi { 2558c2ecf20Sopenharmony_ci struct drm_encoder encoder; 2568c2ecf20Sopenharmony_ci struct mipi_dsi_host dsi_host; 2578c2ecf20Sopenharmony_ci struct drm_connector connector; 2588c2ecf20Sopenharmony_ci struct drm_panel *panel; 2598c2ecf20Sopenharmony_ci struct list_head bridge_chain; 2608c2ecf20Sopenharmony_ci struct drm_bridge *out_bridge; 2618c2ecf20Sopenharmony_ci struct device *dev; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci void __iomem *reg_base; 2648c2ecf20Sopenharmony_ci struct phy *phy; 2658c2ecf20Sopenharmony_ci struct clk **clks; 2668c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[2]; 2678c2ecf20Sopenharmony_ci int irq; 2688c2ecf20Sopenharmony_ci int te_gpio; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci u32 pll_clk_rate; 2718c2ecf20Sopenharmony_ci u32 burst_clk_rate; 2728c2ecf20Sopenharmony_ci u32 esc_clk_rate; 2738c2ecf20Sopenharmony_ci u32 lanes; 2748c2ecf20Sopenharmony_ci u32 mode_flags; 2758c2ecf20Sopenharmony_ci u32 format; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci int state; 2788c2ecf20Sopenharmony_ci struct drm_property *brightness; 2798c2ecf20Sopenharmony_ci struct completion completed; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci spinlock_t transfer_lock; /* protects transfer_list */ 2828c2ecf20Sopenharmony_ci struct list_head transfer_list; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data; 2858c2ecf20Sopenharmony_ci struct device_node *in_bridge_node; 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) 2898c2ecf20Sopenharmony_ci#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci return container_of(e, struct exynos_dsi, encoder); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cienum reg_idx { 2978c2ecf20Sopenharmony_ci DSIM_STATUS_REG, /* Status register */ 2988c2ecf20Sopenharmony_ci DSIM_SWRST_REG, /* Software reset register */ 2998c2ecf20Sopenharmony_ci DSIM_CLKCTRL_REG, /* Clock control register */ 3008c2ecf20Sopenharmony_ci DSIM_TIMEOUT_REG, /* Time out register */ 3018c2ecf20Sopenharmony_ci DSIM_CONFIG_REG, /* Configuration register */ 3028c2ecf20Sopenharmony_ci DSIM_ESCMODE_REG, /* Escape mode register */ 3038c2ecf20Sopenharmony_ci DSIM_MDRESOL_REG, 3048c2ecf20Sopenharmony_ci DSIM_MVPORCH_REG, /* Main display Vporch register */ 3058c2ecf20Sopenharmony_ci DSIM_MHPORCH_REG, /* Main display Hporch register */ 3068c2ecf20Sopenharmony_ci DSIM_MSYNC_REG, /* Main display sync area register */ 3078c2ecf20Sopenharmony_ci DSIM_INTSRC_REG, /* Interrupt source register */ 3088c2ecf20Sopenharmony_ci DSIM_INTMSK_REG, /* Interrupt mask register */ 3098c2ecf20Sopenharmony_ci DSIM_PKTHDR_REG, /* Packet Header FIFO register */ 3108c2ecf20Sopenharmony_ci DSIM_PAYLOAD_REG, /* Payload FIFO register */ 3118c2ecf20Sopenharmony_ci DSIM_RXFIFO_REG, /* Read FIFO register */ 3128c2ecf20Sopenharmony_ci DSIM_FIFOCTRL_REG, /* FIFO status and control register */ 3138c2ecf20Sopenharmony_ci DSIM_PLLCTRL_REG, /* PLL control register */ 3148c2ecf20Sopenharmony_ci DSIM_PHYCTRL_REG, 3158c2ecf20Sopenharmony_ci DSIM_PHYTIMING_REG, 3168c2ecf20Sopenharmony_ci DSIM_PHYTIMING1_REG, 3178c2ecf20Sopenharmony_ci DSIM_PHYTIMING2_REG, 3188c2ecf20Sopenharmony_ci NUM_REGS 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic inline void exynos_dsi_write(struct exynos_dsi *dsi, enum reg_idx idx, 3228c2ecf20Sopenharmony_ci u32 val) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci writel(val, dsi->reg_base + dsi->driver_data->reg_ofs[idx]); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline u32 exynos_dsi_read(struct exynos_dsi *dsi, enum reg_idx idx) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci return readl(dsi->reg_base + dsi->driver_data->reg_ofs[idx]); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic const unsigned int exynos_reg_ofs[] = { 3348c2ecf20Sopenharmony_ci [DSIM_STATUS_REG] = 0x00, 3358c2ecf20Sopenharmony_ci [DSIM_SWRST_REG] = 0x04, 3368c2ecf20Sopenharmony_ci [DSIM_CLKCTRL_REG] = 0x08, 3378c2ecf20Sopenharmony_ci [DSIM_TIMEOUT_REG] = 0x0c, 3388c2ecf20Sopenharmony_ci [DSIM_CONFIG_REG] = 0x10, 3398c2ecf20Sopenharmony_ci [DSIM_ESCMODE_REG] = 0x14, 3408c2ecf20Sopenharmony_ci [DSIM_MDRESOL_REG] = 0x18, 3418c2ecf20Sopenharmony_ci [DSIM_MVPORCH_REG] = 0x1c, 3428c2ecf20Sopenharmony_ci [DSIM_MHPORCH_REG] = 0x20, 3438c2ecf20Sopenharmony_ci [DSIM_MSYNC_REG] = 0x24, 3448c2ecf20Sopenharmony_ci [DSIM_INTSRC_REG] = 0x2c, 3458c2ecf20Sopenharmony_ci [DSIM_INTMSK_REG] = 0x30, 3468c2ecf20Sopenharmony_ci [DSIM_PKTHDR_REG] = 0x34, 3478c2ecf20Sopenharmony_ci [DSIM_PAYLOAD_REG] = 0x38, 3488c2ecf20Sopenharmony_ci [DSIM_RXFIFO_REG] = 0x3c, 3498c2ecf20Sopenharmony_ci [DSIM_FIFOCTRL_REG] = 0x44, 3508c2ecf20Sopenharmony_ci [DSIM_PLLCTRL_REG] = 0x4c, 3518c2ecf20Sopenharmony_ci [DSIM_PHYCTRL_REG] = 0x5c, 3528c2ecf20Sopenharmony_ci [DSIM_PHYTIMING_REG] = 0x64, 3538c2ecf20Sopenharmony_ci [DSIM_PHYTIMING1_REG] = 0x68, 3548c2ecf20Sopenharmony_ci [DSIM_PHYTIMING2_REG] = 0x6c, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const unsigned int exynos5433_reg_ofs[] = { 3588c2ecf20Sopenharmony_ci [DSIM_STATUS_REG] = 0x04, 3598c2ecf20Sopenharmony_ci [DSIM_SWRST_REG] = 0x0C, 3608c2ecf20Sopenharmony_ci [DSIM_CLKCTRL_REG] = 0x10, 3618c2ecf20Sopenharmony_ci [DSIM_TIMEOUT_REG] = 0x14, 3628c2ecf20Sopenharmony_ci [DSIM_CONFIG_REG] = 0x18, 3638c2ecf20Sopenharmony_ci [DSIM_ESCMODE_REG] = 0x1C, 3648c2ecf20Sopenharmony_ci [DSIM_MDRESOL_REG] = 0x20, 3658c2ecf20Sopenharmony_ci [DSIM_MVPORCH_REG] = 0x24, 3668c2ecf20Sopenharmony_ci [DSIM_MHPORCH_REG] = 0x28, 3678c2ecf20Sopenharmony_ci [DSIM_MSYNC_REG] = 0x2C, 3688c2ecf20Sopenharmony_ci [DSIM_INTSRC_REG] = 0x34, 3698c2ecf20Sopenharmony_ci [DSIM_INTMSK_REG] = 0x38, 3708c2ecf20Sopenharmony_ci [DSIM_PKTHDR_REG] = 0x3C, 3718c2ecf20Sopenharmony_ci [DSIM_PAYLOAD_REG] = 0x40, 3728c2ecf20Sopenharmony_ci [DSIM_RXFIFO_REG] = 0x44, 3738c2ecf20Sopenharmony_ci [DSIM_FIFOCTRL_REG] = 0x4C, 3748c2ecf20Sopenharmony_ci [DSIM_PLLCTRL_REG] = 0x94, 3758c2ecf20Sopenharmony_ci [DSIM_PHYCTRL_REG] = 0xA4, 3768c2ecf20Sopenharmony_ci [DSIM_PHYTIMING_REG] = 0xB4, 3778c2ecf20Sopenharmony_ci [DSIM_PHYTIMING1_REG] = 0xB8, 3788c2ecf20Sopenharmony_ci [DSIM_PHYTIMING2_REG] = 0xBC, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cienum reg_value_idx { 3828c2ecf20Sopenharmony_ci RESET_TYPE, 3838c2ecf20Sopenharmony_ci PLL_TIMER, 3848c2ecf20Sopenharmony_ci STOP_STATE_CNT, 3858c2ecf20Sopenharmony_ci PHYCTRL_ULPS_EXIT, 3868c2ecf20Sopenharmony_ci PHYCTRL_VREG_LP, 3878c2ecf20Sopenharmony_ci PHYCTRL_SLEW_UP, 3888c2ecf20Sopenharmony_ci PHYTIMING_LPX, 3898c2ecf20Sopenharmony_ci PHYTIMING_HS_EXIT, 3908c2ecf20Sopenharmony_ci PHYTIMING_CLK_PREPARE, 3918c2ecf20Sopenharmony_ci PHYTIMING_CLK_ZERO, 3928c2ecf20Sopenharmony_ci PHYTIMING_CLK_POST, 3938c2ecf20Sopenharmony_ci PHYTIMING_CLK_TRAIL, 3948c2ecf20Sopenharmony_ci PHYTIMING_HS_PREPARE, 3958c2ecf20Sopenharmony_ci PHYTIMING_HS_ZERO, 3968c2ecf20Sopenharmony_ci PHYTIMING_HS_TRAIL 3978c2ecf20Sopenharmony_ci}; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic const unsigned int reg_values[] = { 4008c2ecf20Sopenharmony_ci [RESET_TYPE] = DSIM_SWRST, 4018c2ecf20Sopenharmony_ci [PLL_TIMER] = 500, 4028c2ecf20Sopenharmony_ci [STOP_STATE_CNT] = 0xf, 4038c2ecf20Sopenharmony_ci [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x0af), 4048c2ecf20Sopenharmony_ci [PHYCTRL_VREG_LP] = 0, 4058c2ecf20Sopenharmony_ci [PHYCTRL_SLEW_UP] = 0, 4068c2ecf20Sopenharmony_ci [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06), 4078c2ecf20Sopenharmony_ci [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0b), 4088c2ecf20Sopenharmony_ci [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x07), 4098c2ecf20Sopenharmony_ci [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x27), 4108c2ecf20Sopenharmony_ci [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0d), 4118c2ecf20Sopenharmony_ci [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x08), 4128c2ecf20Sopenharmony_ci [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x09), 4138c2ecf20Sopenharmony_ci [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x0d), 4148c2ecf20Sopenharmony_ci [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0b), 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic const unsigned int exynos5422_reg_values[] = { 4188c2ecf20Sopenharmony_ci [RESET_TYPE] = DSIM_SWRST, 4198c2ecf20Sopenharmony_ci [PLL_TIMER] = 500, 4208c2ecf20Sopenharmony_ci [STOP_STATE_CNT] = 0xf, 4218c2ecf20Sopenharmony_ci [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf), 4228c2ecf20Sopenharmony_ci [PHYCTRL_VREG_LP] = 0, 4238c2ecf20Sopenharmony_ci [PHYCTRL_SLEW_UP] = 0, 4248c2ecf20Sopenharmony_ci [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x08), 4258c2ecf20Sopenharmony_ci [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0d), 4268c2ecf20Sopenharmony_ci [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09), 4278c2ecf20Sopenharmony_ci [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x30), 4288c2ecf20Sopenharmony_ci [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e), 4298c2ecf20Sopenharmony_ci [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x0a), 4308c2ecf20Sopenharmony_ci [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0c), 4318c2ecf20Sopenharmony_ci [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x11), 4328c2ecf20Sopenharmony_ci [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0d), 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic const unsigned int exynos5433_reg_values[] = { 4368c2ecf20Sopenharmony_ci [RESET_TYPE] = DSIM_FUNCRST, 4378c2ecf20Sopenharmony_ci [PLL_TIMER] = 22200, 4388c2ecf20Sopenharmony_ci [STOP_STATE_CNT] = 0xa, 4398c2ecf20Sopenharmony_ci [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x190), 4408c2ecf20Sopenharmony_ci [PHYCTRL_VREG_LP] = DSIM_PHYCTRL_B_DPHYCTL_VREG_LP, 4418c2ecf20Sopenharmony_ci [PHYCTRL_SLEW_UP] = DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP, 4428c2ecf20Sopenharmony_ci [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x07), 4438c2ecf20Sopenharmony_ci [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0c), 4448c2ecf20Sopenharmony_ci [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09), 4458c2ecf20Sopenharmony_ci [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x2d), 4468c2ecf20Sopenharmony_ci [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e), 4478c2ecf20Sopenharmony_ci [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x09), 4488c2ecf20Sopenharmony_ci [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0b), 4498c2ecf20Sopenharmony_ci [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x10), 4508c2ecf20Sopenharmony_ci [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c), 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic const struct exynos_dsi_driver_data exynos3_dsi_driver_data = { 4548c2ecf20Sopenharmony_ci .reg_ofs = exynos_reg_ofs, 4558c2ecf20Sopenharmony_ci .plltmr_reg = 0x50, 4568c2ecf20Sopenharmony_ci .has_freqband = 1, 4578c2ecf20Sopenharmony_ci .has_clklane_stop = 1, 4588c2ecf20Sopenharmony_ci .num_clks = 2, 4598c2ecf20Sopenharmony_ci .max_freq = 1000, 4608c2ecf20Sopenharmony_ci .wait_for_reset = 1, 4618c2ecf20Sopenharmony_ci .num_bits_resol = 11, 4628c2ecf20Sopenharmony_ci .reg_values = reg_values, 4638c2ecf20Sopenharmony_ci}; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic const struct exynos_dsi_driver_data exynos4_dsi_driver_data = { 4668c2ecf20Sopenharmony_ci .reg_ofs = exynos_reg_ofs, 4678c2ecf20Sopenharmony_ci .plltmr_reg = 0x50, 4688c2ecf20Sopenharmony_ci .has_freqband = 1, 4698c2ecf20Sopenharmony_ci .has_clklane_stop = 1, 4708c2ecf20Sopenharmony_ci .num_clks = 2, 4718c2ecf20Sopenharmony_ci .max_freq = 1000, 4728c2ecf20Sopenharmony_ci .wait_for_reset = 1, 4738c2ecf20Sopenharmony_ci .num_bits_resol = 11, 4748c2ecf20Sopenharmony_ci .reg_values = reg_values, 4758c2ecf20Sopenharmony_ci}; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic const struct exynos_dsi_driver_data exynos5_dsi_driver_data = { 4788c2ecf20Sopenharmony_ci .reg_ofs = exynos_reg_ofs, 4798c2ecf20Sopenharmony_ci .plltmr_reg = 0x58, 4808c2ecf20Sopenharmony_ci .num_clks = 2, 4818c2ecf20Sopenharmony_ci .max_freq = 1000, 4828c2ecf20Sopenharmony_ci .wait_for_reset = 1, 4838c2ecf20Sopenharmony_ci .num_bits_resol = 11, 4848c2ecf20Sopenharmony_ci .reg_values = reg_values, 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = { 4888c2ecf20Sopenharmony_ci .reg_ofs = exynos5433_reg_ofs, 4898c2ecf20Sopenharmony_ci .plltmr_reg = 0xa0, 4908c2ecf20Sopenharmony_ci .has_clklane_stop = 1, 4918c2ecf20Sopenharmony_ci .num_clks = 5, 4928c2ecf20Sopenharmony_ci .max_freq = 1500, 4938c2ecf20Sopenharmony_ci .wait_for_reset = 0, 4948c2ecf20Sopenharmony_ci .num_bits_resol = 12, 4958c2ecf20Sopenharmony_ci .reg_values = exynos5433_reg_values, 4968c2ecf20Sopenharmony_ci}; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = { 4998c2ecf20Sopenharmony_ci .reg_ofs = exynos5433_reg_ofs, 5008c2ecf20Sopenharmony_ci .plltmr_reg = 0xa0, 5018c2ecf20Sopenharmony_ci .has_clklane_stop = 1, 5028c2ecf20Sopenharmony_ci .num_clks = 2, 5038c2ecf20Sopenharmony_ci .max_freq = 1500, 5048c2ecf20Sopenharmony_ci .wait_for_reset = 1, 5058c2ecf20Sopenharmony_ci .num_bits_resol = 12, 5068c2ecf20Sopenharmony_ci .reg_values = exynos5422_reg_values, 5078c2ecf20Sopenharmony_ci}; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic const struct of_device_id exynos_dsi_of_match[] = { 5108c2ecf20Sopenharmony_ci { .compatible = "samsung,exynos3250-mipi-dsi", 5118c2ecf20Sopenharmony_ci .data = &exynos3_dsi_driver_data }, 5128c2ecf20Sopenharmony_ci { .compatible = "samsung,exynos4210-mipi-dsi", 5138c2ecf20Sopenharmony_ci .data = &exynos4_dsi_driver_data }, 5148c2ecf20Sopenharmony_ci { .compatible = "samsung,exynos5410-mipi-dsi", 5158c2ecf20Sopenharmony_ci .data = &exynos5_dsi_driver_data }, 5168c2ecf20Sopenharmony_ci { .compatible = "samsung,exynos5422-mipi-dsi", 5178c2ecf20Sopenharmony_ci .data = &exynos5422_dsi_driver_data }, 5188c2ecf20Sopenharmony_ci { .compatible = "samsung,exynos5433-mipi-dsi", 5198c2ecf20Sopenharmony_ci .data = &exynos5433_dsi_driver_data }, 5208c2ecf20Sopenharmony_ci { } 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) 5268c2ecf20Sopenharmony_ci return; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci dev_err(dsi->dev, "timeout waiting for reset\n"); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void exynos_dsi_reset(struct exynos_dsi *dsi) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci u32 reset_val = dsi->driver_data->reg_values[RESET_TYPE]; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci reinit_completion(&dsi->completed); 5368c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_SWRST_REG, reset_val); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci#ifndef MHZ 5408c2ecf20Sopenharmony_ci#define MHZ (1000*1000) 5418c2ecf20Sopenharmony_ci#endif 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, 5448c2ecf20Sopenharmony_ci unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 5478c2ecf20Sopenharmony_ci unsigned long best_freq = 0; 5488c2ecf20Sopenharmony_ci u32 min_delta = 0xffffffff; 5498c2ecf20Sopenharmony_ci u8 p_min, p_max; 5508c2ecf20Sopenharmony_ci u8 _p, best_p; 5518c2ecf20Sopenharmony_ci u16 _m, best_m; 5528c2ecf20Sopenharmony_ci u8 _s, best_s; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci p_min = DIV_ROUND_UP(fin, (12 * MHZ)); 5558c2ecf20Sopenharmony_ci p_max = fin / (6 * MHZ); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci for (_p = p_min; _p <= p_max; ++_p) { 5588c2ecf20Sopenharmony_ci for (_s = 0; _s <= 5; ++_s) { 5598c2ecf20Sopenharmony_ci u64 tmp; 5608c2ecf20Sopenharmony_ci u32 delta; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci tmp = (u64)fout * (_p << _s); 5638c2ecf20Sopenharmony_ci do_div(tmp, fin); 5648c2ecf20Sopenharmony_ci _m = tmp; 5658c2ecf20Sopenharmony_ci if (_m < 41 || _m > 125) 5668c2ecf20Sopenharmony_ci continue; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci tmp = (u64)_m * fin; 5698c2ecf20Sopenharmony_ci do_div(tmp, _p); 5708c2ecf20Sopenharmony_ci if (tmp < 500 * MHZ || 5718c2ecf20Sopenharmony_ci tmp > driver_data->max_freq * MHZ) 5728c2ecf20Sopenharmony_ci continue; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci tmp = (u64)_m * fin; 5758c2ecf20Sopenharmony_ci do_div(tmp, _p << _s); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci delta = abs(fout - tmp); 5788c2ecf20Sopenharmony_ci if (delta < min_delta) { 5798c2ecf20Sopenharmony_ci best_p = _p; 5808c2ecf20Sopenharmony_ci best_m = _m; 5818c2ecf20Sopenharmony_ci best_s = _s; 5828c2ecf20Sopenharmony_ci min_delta = delta; 5838c2ecf20Sopenharmony_ci best_freq = tmp; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (best_freq) { 5898c2ecf20Sopenharmony_ci *p = best_p; 5908c2ecf20Sopenharmony_ci *m = best_m; 5918c2ecf20Sopenharmony_ci *s = best_s; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return best_freq; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, 5988c2ecf20Sopenharmony_ci unsigned long freq) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 6018c2ecf20Sopenharmony_ci unsigned long fin, fout; 6028c2ecf20Sopenharmony_ci int timeout; 6038c2ecf20Sopenharmony_ci u8 p, s; 6048c2ecf20Sopenharmony_ci u16 m; 6058c2ecf20Sopenharmony_ci u32 reg; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci fin = dsi->pll_clk_rate; 6088c2ecf20Sopenharmony_ci fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s); 6098c2ecf20Sopenharmony_ci if (!fout) { 6108c2ecf20Sopenharmony_ci dev_err(dsi->dev, 6118c2ecf20Sopenharmony_ci "failed to find PLL PMS for requested frequency\n"); 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci writel(driver_data->reg_values[PLL_TIMER], 6178c2ecf20Sopenharmony_ci dsi->reg_base + driver_data->plltmr_reg); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci reg = DSIM_PLL_EN | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (driver_data->has_freqband) { 6228c2ecf20Sopenharmony_ci static const unsigned long freq_bands[] = { 6238c2ecf20Sopenharmony_ci 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, 6248c2ecf20Sopenharmony_ci 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, 6258c2ecf20Sopenharmony_ci 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, 6268c2ecf20Sopenharmony_ci 770 * MHZ, 870 * MHZ, 950 * MHZ, 6278c2ecf20Sopenharmony_ci }; 6288c2ecf20Sopenharmony_ci int band; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) 6318c2ecf20Sopenharmony_ci if (fout < freq_bands[band]) 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci dev_dbg(dsi->dev, "band %d\n", band); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci reg |= DSIM_FREQ_BAND(band); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PLLCTRL_REG, reg); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci timeout = 1000; 6428c2ecf20Sopenharmony_ci do { 6438c2ecf20Sopenharmony_ci if (timeout-- == 0) { 6448c2ecf20Sopenharmony_ci dev_err(dsi->dev, "PLL failed to stabilize\n"); 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_STATUS_REG); 6488c2ecf20Sopenharmony_ci } while ((reg & DSIM_PLL_STABLE) == 0); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return fout; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int exynos_dsi_enable_clock(struct exynos_dsi *dsi) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci unsigned long hs_clk, byte_clk, esc_clk; 6568c2ecf20Sopenharmony_ci unsigned long esc_div; 6578c2ecf20Sopenharmony_ci u32 reg; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate); 6608c2ecf20Sopenharmony_ci if (!hs_clk) { 6618c2ecf20Sopenharmony_ci dev_err(dsi->dev, "failed to configure DSI PLL\n"); 6628c2ecf20Sopenharmony_ci return -EFAULT; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci byte_clk = hs_clk / 8; 6668c2ecf20Sopenharmony_ci esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate); 6678c2ecf20Sopenharmony_ci esc_clk = byte_clk / esc_div; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (esc_clk > 20 * MHZ) { 6708c2ecf20Sopenharmony_ci ++esc_div; 6718c2ecf20Sopenharmony_ci esc_clk = byte_clk / esc_div; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n", 6758c2ecf20Sopenharmony_ci hs_clk, byte_clk, esc_clk); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_CLKCTRL_REG); 6788c2ecf20Sopenharmony_ci reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK 6798c2ecf20Sopenharmony_ci | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS 6808c2ecf20Sopenharmony_ci | DSIM_BYTE_CLK_SRC_MASK); 6818c2ecf20Sopenharmony_ci reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN 6828c2ecf20Sopenharmony_ci | DSIM_ESC_PRESCALER(esc_div) 6838c2ecf20Sopenharmony_ci | DSIM_LANE_ESC_CLK_EN_CLK 6848c2ecf20Sopenharmony_ci | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1) 6858c2ecf20Sopenharmony_ci | DSIM_BYTE_CLK_SRC(0) 6868c2ecf20Sopenharmony_ci | DSIM_TX_REQUEST_HSCLK; 6878c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_CLKCTRL_REG, reg); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 6958c2ecf20Sopenharmony_ci const unsigned int *reg_values = driver_data->reg_values; 6968c2ecf20Sopenharmony_ci u32 reg; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (driver_data->has_freqband) 6998c2ecf20Sopenharmony_ci return; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* B D-PHY: D-PHY Master & Slave Analog Block control */ 7028c2ecf20Sopenharmony_ci reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] | 7038c2ecf20Sopenharmony_ci reg_values[PHYCTRL_SLEW_UP]; 7048c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PHYCTRL_REG, reg); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * T LPX: Transmitted length of any Low-Power state period 7088c2ecf20Sopenharmony_ci * T HS-EXIT: Time that the transmitter drives LP-11 following a HS 7098c2ecf20Sopenharmony_ci * burst 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_ci reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT]; 7128c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PHYTIMING_REG, reg); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * T CLK-PREPARE: Time that the transmitter drives the Clock Lane LP-00 7168c2ecf20Sopenharmony_ci * Line state immediately before the HS-0 Line state starting the 7178c2ecf20Sopenharmony_ci * HS transmission 7188c2ecf20Sopenharmony_ci * T CLK-ZERO: Time that the transmitter drives the HS-0 state prior to 7198c2ecf20Sopenharmony_ci * transmitting the Clock. 7208c2ecf20Sopenharmony_ci * T CLK_POST: Time that the transmitter continues to send HS clock 7218c2ecf20Sopenharmony_ci * after the last associated Data Lane has transitioned to LP Mode 7228c2ecf20Sopenharmony_ci * Interval is defined as the period from the end of T HS-TRAIL to 7238c2ecf20Sopenharmony_ci * the beginning of T CLK-TRAIL 7248c2ecf20Sopenharmony_ci * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after 7258c2ecf20Sopenharmony_ci * the last payload clock bit of a HS transmission burst 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci reg = reg_values[PHYTIMING_CLK_PREPARE] | 7288c2ecf20Sopenharmony_ci reg_values[PHYTIMING_CLK_ZERO] | 7298c2ecf20Sopenharmony_ci reg_values[PHYTIMING_CLK_POST] | 7308c2ecf20Sopenharmony_ci reg_values[PHYTIMING_CLK_TRAIL]; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PHYTIMING1_REG, reg); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * T HS-PREPARE: Time that the transmitter drives the Data Lane LP-00 7368c2ecf20Sopenharmony_ci * Line state immediately before the HS-0 Line state starting the 7378c2ecf20Sopenharmony_ci * HS transmission 7388c2ecf20Sopenharmony_ci * T HS-ZERO: Time that the transmitter drives the HS-0 state prior to 7398c2ecf20Sopenharmony_ci * transmitting the Sync sequence. 7408c2ecf20Sopenharmony_ci * T HS-TRAIL: Time that the transmitter drives the flipped differential 7418c2ecf20Sopenharmony_ci * state after last payload data bit of a HS transmission burst 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] | 7448c2ecf20Sopenharmony_ci reg_values[PHYTIMING_HS_TRAIL]; 7458c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PHYTIMING2_REG, reg); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void exynos_dsi_disable_clock(struct exynos_dsi *dsi) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci u32 reg; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_CLKCTRL_REG); 7538c2ecf20Sopenharmony_ci reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK 7548c2ecf20Sopenharmony_ci | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN); 7558c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_CLKCTRL_REG, reg); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_PLLCTRL_REG); 7588c2ecf20Sopenharmony_ci reg &= ~DSIM_PLL_EN; 7598c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PLLCTRL_REG, reg); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci u32 reg = exynos_dsi_read(dsi, DSIM_CONFIG_REG); 7658c2ecf20Sopenharmony_ci reg |= (DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1) | DSIM_LANE_EN_CLK | 7668c2ecf20Sopenharmony_ci DSIM_LANE_EN(lane)); 7678c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_CONFIG_REG, reg); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int exynos_dsi_init_link(struct exynos_dsi *dsi) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 7738c2ecf20Sopenharmony_ci int timeout; 7748c2ecf20Sopenharmony_ci u32 reg; 7758c2ecf20Sopenharmony_ci u32 lanes_mask; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* Initialize FIFO pointers */ 7788c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_FIFOCTRL_REG); 7798c2ecf20Sopenharmony_ci reg &= ~0x1f; 7808c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_FIFOCTRL_REG, reg); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci usleep_range(9000, 11000); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci reg |= 0x1f; 7858c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_FIFOCTRL_REG, reg); 7868c2ecf20Sopenharmony_ci usleep_range(9000, 11000); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* DSI configuration */ 7898c2ecf20Sopenharmony_ci reg = 0; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* 7928c2ecf20Sopenharmony_ci * The first bit of mode_flags specifies display configuration. 7938c2ecf20Sopenharmony_ci * If this bit is set[= MIPI_DSI_MODE_VIDEO], dsi will support video 7948c2ecf20Sopenharmony_ci * mode, otherwise it will support command mode. 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 7978c2ecf20Sopenharmony_ci reg |= DSIM_VIDEO_MODE; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* 8008c2ecf20Sopenharmony_ci * The user manual describes that following bits are ignored in 8018c2ecf20Sopenharmony_ci * command mode. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) 8048c2ecf20Sopenharmony_ci reg |= DSIM_MFLUSH_VS; 8058c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 8068c2ecf20Sopenharmony_ci reg |= DSIM_SYNC_INFORM; 8078c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) 8088c2ecf20Sopenharmony_ci reg |= DSIM_BURST_MODE; 8098c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT) 8108c2ecf20Sopenharmony_ci reg |= DSIM_AUTO_MODE; 8118c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE) 8128c2ecf20Sopenharmony_ci reg |= DSIM_HSE_MODE; 8138c2ecf20Sopenharmony_ci if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)) 8148c2ecf20Sopenharmony_ci reg |= DSIM_HFP_MODE; 8158c2ecf20Sopenharmony_ci if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)) 8168c2ecf20Sopenharmony_ci reg |= DSIM_HBP_MODE; 8178c2ecf20Sopenharmony_ci if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)) 8188c2ecf20Sopenharmony_ci reg |= DSIM_HSA_MODE; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) 8228c2ecf20Sopenharmony_ci reg |= DSIM_EOT_DISABLE; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci switch (dsi->format) { 8258c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB888: 8268c2ecf20Sopenharmony_ci reg |= DSIM_MAIN_PIX_FORMAT_RGB888; 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB666: 8298c2ecf20Sopenharmony_ci reg |= DSIM_MAIN_PIX_FORMAT_RGB666; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB666_PACKED: 8328c2ecf20Sopenharmony_ci reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci case MIPI_DSI_FMT_RGB565: 8358c2ecf20Sopenharmony_ci reg |= DSIM_MAIN_PIX_FORMAT_RGB565; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci default: 8388c2ecf20Sopenharmony_ci dev_err(dsi->dev, "invalid pixel format\n"); 8398c2ecf20Sopenharmony_ci return -EINVAL; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* 8438c2ecf20Sopenharmony_ci * Use non-continuous clock mode if the periparal wants and 8448c2ecf20Sopenharmony_ci * host controller supports 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * In non-continous clock mode, host controller will turn off 8478c2ecf20Sopenharmony_ci * the HS clock between high-speed transmissions to reduce 8488c2ecf20Sopenharmony_ci * power consumption. 8498c2ecf20Sopenharmony_ci */ 8508c2ecf20Sopenharmony_ci if (driver_data->has_clklane_stop && 8518c2ecf20Sopenharmony_ci dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { 8528c2ecf20Sopenharmony_ci reg |= DSIM_CLKLANE_STOP; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_CONFIG_REG, reg); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci lanes_mask = BIT(dsi->lanes) - 1; 8578c2ecf20Sopenharmony_ci exynos_dsi_enable_lane(dsi, lanes_mask); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* Check clock and data lane state are stop state */ 8608c2ecf20Sopenharmony_ci timeout = 100; 8618c2ecf20Sopenharmony_ci do { 8628c2ecf20Sopenharmony_ci if (timeout-- == 0) { 8638c2ecf20Sopenharmony_ci dev_err(dsi->dev, "waiting for bus lanes timed out\n"); 8648c2ecf20Sopenharmony_ci return -EFAULT; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_STATUS_REG); 8688c2ecf20Sopenharmony_ci if ((reg & DSIM_STOP_STATE_DAT(lanes_mask)) 8698c2ecf20Sopenharmony_ci != DSIM_STOP_STATE_DAT(lanes_mask)) 8708c2ecf20Sopenharmony_ci continue; 8718c2ecf20Sopenharmony_ci } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK))); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_ESCMODE_REG); 8748c2ecf20Sopenharmony_ci reg &= ~DSIM_STOP_STATE_CNT_MASK; 8758c2ecf20Sopenharmony_ci reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); 8768c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_ESCMODE_REG, reg); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); 8798c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_TIMEOUT_REG, reg); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode; 8878c2ecf20Sopenharmony_ci unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; 8888c2ecf20Sopenharmony_ci u32 reg; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 8918c2ecf20Sopenharmony_ci reg = DSIM_CMD_ALLOW(0xf) 8928c2ecf20Sopenharmony_ci | DSIM_STABLE_VFP(m->vsync_start - m->vdisplay) 8938c2ecf20Sopenharmony_ci | DSIM_MAIN_VBP(m->vtotal - m->vsync_end); 8948c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_MVPORCH_REG, reg); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci reg = DSIM_MAIN_HFP(m->hsync_start - m->hdisplay) 8978c2ecf20Sopenharmony_ci | DSIM_MAIN_HBP(m->htotal - m->hsync_end); 8988c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_MHPORCH_REG, reg); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start) 9018c2ecf20Sopenharmony_ci | DSIM_MAIN_HSA(m->hsync_end - m->hsync_start); 9028c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_MSYNC_REG, reg); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci reg = DSIM_MAIN_HRESOL(m->hdisplay, num_bits_resol) | 9058c2ecf20Sopenharmony_ci DSIM_MAIN_VRESOL(m->vdisplay, num_bits_resol); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_MDRESOL_REG, reg); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci dev_dbg(dsi->dev, "LCD size = %dx%d\n", m->hdisplay, m->vdisplay); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci u32 reg; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_MDRESOL_REG); 9178c2ecf20Sopenharmony_ci if (enable) 9188c2ecf20Sopenharmony_ci reg |= DSIM_MAIN_STAND_BY; 9198c2ecf20Sopenharmony_ci else 9208c2ecf20Sopenharmony_ci reg &= ~DSIM_MAIN_STAND_BY; 9218c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_MDRESOL_REG, reg); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci int timeout = 2000; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci do { 9298c2ecf20Sopenharmony_ci u32 reg = exynos_dsi_read(dsi, DSIM_FIFOCTRL_REG); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (!(reg & DSIM_SFR_HEADER_FULL)) 9328c2ecf20Sopenharmony_ci return 0; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (!cond_resched()) 9358c2ecf20Sopenharmony_ci usleep_range(950, 1050); 9368c2ecf20Sopenharmony_ci } while (--timeout); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci u32 v = exynos_dsi_read(dsi, DSIM_ESCMODE_REG); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (lpm) 9468c2ecf20Sopenharmony_ci v |= DSIM_CMD_LPDT_LP; 9478c2ecf20Sopenharmony_ci else 9488c2ecf20Sopenharmony_ci v &= ~DSIM_CMD_LPDT_LP; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_ESCMODE_REG, v); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void exynos_dsi_force_bta(struct exynos_dsi *dsi) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci u32 v = exynos_dsi_read(dsi, DSIM_ESCMODE_REG); 9568c2ecf20Sopenharmony_ci v |= DSIM_FORCE_BTA; 9578c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_ESCMODE_REG, v); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, 9618c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct device *dev = dsi->dev; 9648c2ecf20Sopenharmony_ci struct mipi_dsi_packet *pkt = &xfer->packet; 9658c2ecf20Sopenharmony_ci const u8 *payload = pkt->payload + xfer->tx_done; 9668c2ecf20Sopenharmony_ci u16 length = pkt->payload_length - xfer->tx_done; 9678c2ecf20Sopenharmony_ci bool first = !xfer->tx_done; 9688c2ecf20Sopenharmony_ci u32 reg; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci dev_dbg(dev, "< xfer %pK: tx len %u, done %u, rx len %u, done %u\n", 9718c2ecf20Sopenharmony_ci xfer, length, xfer->tx_done, xfer->rx_len, xfer->rx_done); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (length > DSI_TX_FIFO_SIZE) 9748c2ecf20Sopenharmony_ci length = DSI_TX_FIFO_SIZE; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci xfer->tx_done += length; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* Send payload */ 9798c2ecf20Sopenharmony_ci while (length >= 4) { 9808c2ecf20Sopenharmony_ci reg = get_unaligned_le32(payload); 9818c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PAYLOAD_REG, reg); 9828c2ecf20Sopenharmony_ci payload += 4; 9838c2ecf20Sopenharmony_ci length -= 4; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci reg = 0; 9878c2ecf20Sopenharmony_ci switch (length) { 9888c2ecf20Sopenharmony_ci case 3: 9898c2ecf20Sopenharmony_ci reg |= payload[2] << 16; 9908c2ecf20Sopenharmony_ci fallthrough; 9918c2ecf20Sopenharmony_ci case 2: 9928c2ecf20Sopenharmony_ci reg |= payload[1] << 8; 9938c2ecf20Sopenharmony_ci fallthrough; 9948c2ecf20Sopenharmony_ci case 1: 9958c2ecf20Sopenharmony_ci reg |= payload[0]; 9968c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PAYLOAD_REG, reg); 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Send packet header */ 10018c2ecf20Sopenharmony_ci if (!first) 10028c2ecf20Sopenharmony_ci return; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci reg = get_unaligned_le32(pkt->header); 10058c2ecf20Sopenharmony_ci if (exynos_dsi_wait_for_hdr_fifo(dsi)) { 10068c2ecf20Sopenharmony_ci dev_err(dev, "waiting for header FIFO timed out\n"); 10078c2ecf20Sopenharmony_ci return; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM, 10118c2ecf20Sopenharmony_ci dsi->state & DSIM_STATE_CMD_LPM)) { 10128c2ecf20Sopenharmony_ci exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM); 10138c2ecf20Sopenharmony_ci dsi->state ^= DSIM_STATE_CMD_LPM; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_PKTHDR_REG, reg); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (xfer->flags & MIPI_DSI_MSG_REQ_ACK) 10198c2ecf20Sopenharmony_ci exynos_dsi_force_bta(dsi); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, 10238c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci u8 *payload = xfer->rx_payload + xfer->rx_done; 10268c2ecf20Sopenharmony_ci bool first = !xfer->rx_done; 10278c2ecf20Sopenharmony_ci struct device *dev = dsi->dev; 10288c2ecf20Sopenharmony_ci u16 length; 10298c2ecf20Sopenharmony_ci u32 reg; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (first) { 10328c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci switch (reg & 0x3f) { 10358c2ecf20Sopenharmony_ci case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: 10368c2ecf20Sopenharmony_ci case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: 10378c2ecf20Sopenharmony_ci if (xfer->rx_len >= 2) { 10388c2ecf20Sopenharmony_ci payload[1] = reg >> 16; 10398c2ecf20Sopenharmony_ci ++xfer->rx_done; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci fallthrough; 10428c2ecf20Sopenharmony_ci case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: 10438c2ecf20Sopenharmony_ci case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: 10448c2ecf20Sopenharmony_ci payload[0] = reg >> 8; 10458c2ecf20Sopenharmony_ci ++xfer->rx_done; 10468c2ecf20Sopenharmony_ci xfer->rx_len = xfer->rx_done; 10478c2ecf20Sopenharmony_ci xfer->result = 0; 10488c2ecf20Sopenharmony_ci goto clear_fifo; 10498c2ecf20Sopenharmony_ci case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: 10508c2ecf20Sopenharmony_ci dev_err(dev, "DSI Error Report: 0x%04x\n", 10518c2ecf20Sopenharmony_ci (reg >> 8) & 0xffff); 10528c2ecf20Sopenharmony_ci xfer->result = 0; 10538c2ecf20Sopenharmony_ci goto clear_fifo; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci length = (reg >> 8) & 0xffff; 10578c2ecf20Sopenharmony_ci if (length > xfer->rx_len) { 10588c2ecf20Sopenharmony_ci dev_err(dev, 10598c2ecf20Sopenharmony_ci "response too long (%u > %u bytes), stripping\n", 10608c2ecf20Sopenharmony_ci xfer->rx_len, length); 10618c2ecf20Sopenharmony_ci length = xfer->rx_len; 10628c2ecf20Sopenharmony_ci } else if (length < xfer->rx_len) 10638c2ecf20Sopenharmony_ci xfer->rx_len = length; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci length = xfer->rx_len - xfer->rx_done; 10678c2ecf20Sopenharmony_ci xfer->rx_done += length; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Receive payload */ 10708c2ecf20Sopenharmony_ci while (length >= 4) { 10718c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG); 10728c2ecf20Sopenharmony_ci payload[0] = (reg >> 0) & 0xff; 10738c2ecf20Sopenharmony_ci payload[1] = (reg >> 8) & 0xff; 10748c2ecf20Sopenharmony_ci payload[2] = (reg >> 16) & 0xff; 10758c2ecf20Sopenharmony_ci payload[3] = (reg >> 24) & 0xff; 10768c2ecf20Sopenharmony_ci payload += 4; 10778c2ecf20Sopenharmony_ci length -= 4; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (length) { 10818c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG); 10828c2ecf20Sopenharmony_ci switch (length) { 10838c2ecf20Sopenharmony_ci case 3: 10848c2ecf20Sopenharmony_ci payload[2] = (reg >> 16) & 0xff; 10858c2ecf20Sopenharmony_ci fallthrough; 10868c2ecf20Sopenharmony_ci case 2: 10878c2ecf20Sopenharmony_ci payload[1] = (reg >> 8) & 0xff; 10888c2ecf20Sopenharmony_ci fallthrough; 10898c2ecf20Sopenharmony_ci case 1: 10908c2ecf20Sopenharmony_ci payload[0] = reg & 0xff; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (xfer->rx_done == xfer->rx_len) 10958c2ecf20Sopenharmony_ci xfer->result = 0; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ciclear_fifo: 10988c2ecf20Sopenharmony_ci length = DSI_RX_FIFO_SIZE / 4; 10998c2ecf20Sopenharmony_ci do { 11008c2ecf20Sopenharmony_ci reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG); 11018c2ecf20Sopenharmony_ci if (reg == DSI_RX_FIFO_EMPTY) 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } while (--length); 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic void exynos_dsi_transfer_start(struct exynos_dsi *dsi) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci unsigned long flags; 11098c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer; 11108c2ecf20Sopenharmony_ci bool start = false; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ciagain: 11138c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (list_empty(&dsi->transfer_list)) { 11168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci xfer = list_first_entry(&dsi->transfer_list, 11218c2ecf20Sopenharmony_ci struct exynos_dsi_transfer, list); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (xfer->packet.payload_length && 11268c2ecf20Sopenharmony_ci xfer->tx_done == xfer->packet.payload_length) 11278c2ecf20Sopenharmony_ci /* waiting for RX */ 11288c2ecf20Sopenharmony_ci return; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci exynos_dsi_send_to_fifo(dsi, xfer); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (xfer->packet.payload_length || xfer->rx_len) 11338c2ecf20Sopenharmony_ci return; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci xfer->result = 0; 11368c2ecf20Sopenharmony_ci complete(&xfer->completed); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci list_del_init(&xfer->list); 11418c2ecf20Sopenharmony_ci start = !list_empty(&dsi->transfer_list); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (start) 11468c2ecf20Sopenharmony_ci goto again; 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer; 11528c2ecf20Sopenharmony_ci unsigned long flags; 11538c2ecf20Sopenharmony_ci bool start = true; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci if (list_empty(&dsi->transfer_list)) { 11588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11598c2ecf20Sopenharmony_ci return false; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci xfer = list_first_entry(&dsi->transfer_list, 11638c2ecf20Sopenharmony_ci struct exynos_dsi_transfer, list); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci dev_dbg(dsi->dev, 11688c2ecf20Sopenharmony_ci "> xfer %pK, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n", 11698c2ecf20Sopenharmony_ci xfer, xfer->packet.payload_length, xfer->tx_done, xfer->rx_len, 11708c2ecf20Sopenharmony_ci xfer->rx_done); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci if (xfer->tx_done != xfer->packet.payload_length) 11738c2ecf20Sopenharmony_ci return true; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (xfer->rx_done != xfer->rx_len) 11768c2ecf20Sopenharmony_ci exynos_dsi_read_from_fifo(dsi, xfer); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (xfer->rx_done != xfer->rx_len) 11798c2ecf20Sopenharmony_ci return true; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci list_del_init(&xfer->list); 11848c2ecf20Sopenharmony_ci start = !list_empty(&dsi->transfer_list); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (!xfer->rx_len) 11898c2ecf20Sopenharmony_ci xfer->result = 0; 11908c2ecf20Sopenharmony_ci complete(&xfer->completed); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci return start; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic void exynos_dsi_remove_transfer(struct exynos_dsi *dsi, 11968c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci unsigned long flags; 11998c2ecf20Sopenharmony_ci bool start; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (!list_empty(&dsi->transfer_list) && 12048c2ecf20Sopenharmony_ci xfer == list_first_entry(&dsi->transfer_list, 12058c2ecf20Sopenharmony_ci struct exynos_dsi_transfer, list)) { 12068c2ecf20Sopenharmony_ci list_del_init(&xfer->list); 12078c2ecf20Sopenharmony_ci start = !list_empty(&dsi->transfer_list); 12088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 12098c2ecf20Sopenharmony_ci if (start) 12108c2ecf20Sopenharmony_ci exynos_dsi_transfer_start(dsi); 12118c2ecf20Sopenharmony_ci return; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci list_del_init(&xfer->list); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic int exynos_dsi_transfer(struct exynos_dsi *dsi, 12208c2ecf20Sopenharmony_ci struct exynos_dsi_transfer *xfer) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci unsigned long flags; 12238c2ecf20Sopenharmony_ci bool stopped; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci xfer->tx_done = 0; 12268c2ecf20Sopenharmony_ci xfer->rx_done = 0; 12278c2ecf20Sopenharmony_ci xfer->result = -ETIMEDOUT; 12288c2ecf20Sopenharmony_ci init_completion(&xfer->completed); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci spin_lock_irqsave(&dsi->transfer_lock, flags); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci stopped = list_empty(&dsi->transfer_list); 12338c2ecf20Sopenharmony_ci list_add_tail(&xfer->list, &dsi->transfer_list); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dsi->transfer_lock, flags); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (stopped) 12388c2ecf20Sopenharmony_ci exynos_dsi_transfer_start(dsi); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci wait_for_completion_timeout(&xfer->completed, 12418c2ecf20Sopenharmony_ci msecs_to_jiffies(DSI_XFER_TIMEOUT_MS)); 12428c2ecf20Sopenharmony_ci if (xfer->result == -ETIMEDOUT) { 12438c2ecf20Sopenharmony_ci struct mipi_dsi_packet *pkt = &xfer->packet; 12448c2ecf20Sopenharmony_ci exynos_dsi_remove_transfer(dsi, xfer); 12458c2ecf20Sopenharmony_ci dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 4, pkt->header, 12468c2ecf20Sopenharmony_ci (int)pkt->payload_length, pkt->payload); 12478c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* Also covers hardware timeout condition */ 12518c2ecf20Sopenharmony_ci return xfer->result; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic irqreturn_t exynos_dsi_irq(int irq, void *dev_id) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = dev_id; 12578c2ecf20Sopenharmony_ci u32 status; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci status = exynos_dsi_read(dsi, DSIM_INTSRC_REG); 12608c2ecf20Sopenharmony_ci if (!status) { 12618c2ecf20Sopenharmony_ci static unsigned long int j; 12628c2ecf20Sopenharmony_ci if (printk_timed_ratelimit(&j, 500)) 12638c2ecf20Sopenharmony_ci dev_warn(dsi->dev, "spurious interrupt\n"); 12648c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_INTSRC_REG, status); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (status & DSIM_INT_SW_RST_RELEASE) { 12698c2ecf20Sopenharmony_ci u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY | 12708c2ecf20Sopenharmony_ci DSIM_INT_SFR_HDR_FIFO_EMPTY | DSIM_INT_RX_ECC_ERR | 12718c2ecf20Sopenharmony_ci DSIM_INT_SW_RST_RELEASE); 12728c2ecf20Sopenharmony_ci exynos_dsi_write(dsi, DSIM_INTMSK_REG, mask); 12738c2ecf20Sopenharmony_ci complete(&dsi->completed); 12748c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY | 12788c2ecf20Sopenharmony_ci DSIM_INT_PLL_STABLE))) 12798c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (exynos_dsi_transfer_finish(dsi)) 12828c2ecf20Sopenharmony_ci exynos_dsi_transfer_start(dsi); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; 12908c2ecf20Sopenharmony_ci struct drm_encoder *encoder = &dsi->encoder; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) 12938c2ecf20Sopenharmony_ci exynos_drm_crtc_te_handler(encoder->crtc); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic void exynos_dsi_enable_irq(struct exynos_dsi *dsi) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci enable_irq(dsi->irq); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (gpio_is_valid(dsi->te_gpio)) 13038c2ecf20Sopenharmony_ci enable_irq(gpio_to_irq(dsi->te_gpio)); 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic void exynos_dsi_disable_irq(struct exynos_dsi *dsi) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci if (gpio_is_valid(dsi->te_gpio)) 13098c2ecf20Sopenharmony_ci disable_irq(gpio_to_irq(dsi->te_gpio)); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci disable_irq(dsi->irq); 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic int exynos_dsi_init(struct exynos_dsi *dsi) 13158c2ecf20Sopenharmony_ci{ 13168c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci exynos_dsi_reset(dsi); 13198c2ecf20Sopenharmony_ci exynos_dsi_enable_irq(dsi); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (driver_data->reg_values[RESET_TYPE] == DSIM_FUNCRST) 13228c2ecf20Sopenharmony_ci exynos_dsi_enable_lane(dsi, BIT(dsi->lanes) - 1); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci exynos_dsi_enable_clock(dsi); 13258c2ecf20Sopenharmony_ci if (driver_data->wait_for_reset) 13268c2ecf20Sopenharmony_ci exynos_dsi_wait_for_reset(dsi); 13278c2ecf20Sopenharmony_ci exynos_dsi_set_phy_ctrl(dsi); 13288c2ecf20Sopenharmony_ci exynos_dsi_init_link(dsi); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci return 0; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic int exynos_dsi_register_te_irq(struct exynos_dsi *dsi, 13348c2ecf20Sopenharmony_ci struct device *panel) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci int ret; 13378c2ecf20Sopenharmony_ci int te_gpio_irq; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci dsi->te_gpio = of_get_named_gpio(panel->of_node, "te-gpios", 0); 13408c2ecf20Sopenharmony_ci if (dsi->te_gpio == -ENOENT) 13418c2ecf20Sopenharmony_ci return 0; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (!gpio_is_valid(dsi->te_gpio)) { 13448c2ecf20Sopenharmony_ci ret = dsi->te_gpio; 13458c2ecf20Sopenharmony_ci dev_err(dsi->dev, "cannot get te-gpios, %d\n", ret); 13468c2ecf20Sopenharmony_ci goto out; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci ret = gpio_request(dsi->te_gpio, "te_gpio"); 13508c2ecf20Sopenharmony_ci if (ret) { 13518c2ecf20Sopenharmony_ci dev_err(dsi->dev, "gpio request failed with %d\n", ret); 13528c2ecf20Sopenharmony_ci goto out; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci te_gpio_irq = gpio_to_irq(dsi->te_gpio); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL, 13588c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, "TE", dsi); 13598c2ecf20Sopenharmony_ci if (ret) { 13608c2ecf20Sopenharmony_ci dev_err(dsi->dev, "request interrupt failed with %d\n", ret); 13618c2ecf20Sopenharmony_ci gpio_free(dsi->te_gpio); 13628c2ecf20Sopenharmony_ci goto out; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ciout: 13668c2ecf20Sopenharmony_ci return ret; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci if (gpio_is_valid(dsi->te_gpio)) { 13728c2ecf20Sopenharmony_ci free_irq(gpio_to_irq(dsi->te_gpio), dsi); 13738c2ecf20Sopenharmony_ci gpio_free(dsi->te_gpio); 13748c2ecf20Sopenharmony_ci dsi->te_gpio = -ENOENT; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci} 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_cistatic void exynos_dsi_enable(struct drm_encoder *encoder) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 13818c2ecf20Sopenharmony_ci struct drm_bridge *iter; 13828c2ecf20Sopenharmony_ci int ret; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (dsi->state & DSIM_STATE_ENABLED) 13858c2ecf20Sopenharmony_ci return; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci pm_runtime_get_sync(dsi->dev); 13888c2ecf20Sopenharmony_ci dsi->state |= DSIM_STATE_ENABLED; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (dsi->panel) { 13918c2ecf20Sopenharmony_ci ret = drm_panel_prepare(dsi->panel); 13928c2ecf20Sopenharmony_ci if (ret < 0) 13938c2ecf20Sopenharmony_ci goto err_put_sync; 13948c2ecf20Sopenharmony_ci } else { 13958c2ecf20Sopenharmony_ci list_for_each_entry_reverse(iter, &dsi->bridge_chain, 13968c2ecf20Sopenharmony_ci chain_node) { 13978c2ecf20Sopenharmony_ci if (iter->funcs->pre_enable) 13988c2ecf20Sopenharmony_ci iter->funcs->pre_enable(iter); 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci exynos_dsi_set_display_mode(dsi); 14038c2ecf20Sopenharmony_ci exynos_dsi_set_display_enable(dsi, true); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (dsi->panel) { 14068c2ecf20Sopenharmony_ci ret = drm_panel_enable(dsi->panel); 14078c2ecf20Sopenharmony_ci if (ret < 0) 14088c2ecf20Sopenharmony_ci goto err_display_disable; 14098c2ecf20Sopenharmony_ci } else { 14108c2ecf20Sopenharmony_ci list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { 14118c2ecf20Sopenharmony_ci if (iter->funcs->enable) 14128c2ecf20Sopenharmony_ci iter->funcs->enable(iter); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; 14178c2ecf20Sopenharmony_ci return; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cierr_display_disable: 14208c2ecf20Sopenharmony_ci exynos_dsi_set_display_enable(dsi, false); 14218c2ecf20Sopenharmony_ci drm_panel_unprepare(dsi->panel); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cierr_put_sync: 14248c2ecf20Sopenharmony_ci dsi->state &= ~DSIM_STATE_ENABLED; 14258c2ecf20Sopenharmony_ci pm_runtime_put(dsi->dev); 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic void exynos_dsi_disable(struct drm_encoder *encoder) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 14318c2ecf20Sopenharmony_ci struct drm_bridge *iter; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci if (!(dsi->state & DSIM_STATE_ENABLED)) 14348c2ecf20Sopenharmony_ci return; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci drm_panel_disable(dsi->panel); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { 14418c2ecf20Sopenharmony_ci if (iter->funcs->disable) 14428c2ecf20Sopenharmony_ci iter->funcs->disable(iter); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci exynos_dsi_set_display_enable(dsi, false); 14468c2ecf20Sopenharmony_ci drm_panel_unprepare(dsi->panel); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { 14498c2ecf20Sopenharmony_ci if (iter->funcs->post_disable) 14508c2ecf20Sopenharmony_ci iter->funcs->post_disable(iter); 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci dsi->state &= ~DSIM_STATE_ENABLED; 14548c2ecf20Sopenharmony_ci pm_runtime_put_sync(dsi->dev); 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic enum drm_connector_status 14588c2ecf20Sopenharmony_ciexynos_dsi_detect(struct drm_connector *connector, bool force) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci return connector->status; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic void exynos_dsi_connector_destroy(struct drm_connector *connector) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 14668c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 14678c2ecf20Sopenharmony_ci connector->dev = NULL; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs exynos_dsi_connector_funcs = { 14718c2ecf20Sopenharmony_ci .detect = exynos_dsi_detect, 14728c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 14738c2ecf20Sopenharmony_ci .destroy = exynos_dsi_connector_destroy, 14748c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 14758c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 14768c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 14778c2ecf20Sopenharmony_ci}; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic int exynos_dsi_get_modes(struct drm_connector *connector) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = connector_to_dsi(connector); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (dsi->panel) 14848c2ecf20Sopenharmony_ci return drm_panel_get_modes(dsi->panel, connector); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { 14908c2ecf20Sopenharmony_ci .get_modes = exynos_dsi_get_modes, 14918c2ecf20Sopenharmony_ci}; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic int exynos_dsi_create_connector(struct drm_encoder *encoder) 14948c2ecf20Sopenharmony_ci{ 14958c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 14968c2ecf20Sopenharmony_ci struct drm_connector *connector = &dsi->connector; 14978c2ecf20Sopenharmony_ci struct drm_device *drm = encoder->dev; 14988c2ecf20Sopenharmony_ci int ret; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci connector->polled = DRM_CONNECTOR_POLL_HPD; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci ret = drm_connector_init(drm, connector, &exynos_dsi_connector_funcs, 15038c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DSI); 15048c2ecf20Sopenharmony_ci if (ret) { 15058c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dsi->dev, 15068c2ecf20Sopenharmony_ci "Failed to initialize connector with drm\n"); 15078c2ecf20Sopenharmony_ci return ret; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci connector->status = connector_status_disconnected; 15118c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); 15128c2ecf20Sopenharmony_ci drm_connector_attach_encoder(connector, encoder); 15138c2ecf20Sopenharmony_ci if (!drm->registered) 15148c2ecf20Sopenharmony_ci return 0; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci connector->funcs->reset(connector); 15178c2ecf20Sopenharmony_ci drm_connector_register(connector); 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { 15228c2ecf20Sopenharmony_ci .enable = exynos_dsi_enable, 15238c2ecf20Sopenharmony_ci .disable = exynos_dsi_disable, 15248c2ecf20Sopenharmony_ci}; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, exynos_dsi_of_match); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic int exynos_dsi_host_attach(struct mipi_dsi_host *host, 15298c2ecf20Sopenharmony_ci struct mipi_dsi_device *device) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = host_to_dsi(host); 15328c2ecf20Sopenharmony_ci struct drm_encoder *encoder = &dsi->encoder; 15338c2ecf20Sopenharmony_ci struct drm_device *drm = encoder->dev; 15348c2ecf20Sopenharmony_ci struct drm_bridge *out_bridge; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci out_bridge = of_drm_find_bridge(device->dev.of_node); 15378c2ecf20Sopenharmony_ci if (out_bridge) { 15388c2ecf20Sopenharmony_ci drm_bridge_attach(encoder, out_bridge, NULL, 0); 15398c2ecf20Sopenharmony_ci dsi->out_bridge = out_bridge; 15408c2ecf20Sopenharmony_ci list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); 15418c2ecf20Sopenharmony_ci } else { 15428c2ecf20Sopenharmony_ci int ret = exynos_dsi_create_connector(encoder); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (ret) { 15458c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dsi->dev, 15468c2ecf20Sopenharmony_ci "failed to create connector ret = %d\n", 15478c2ecf20Sopenharmony_ci ret); 15488c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 15498c2ecf20Sopenharmony_ci return ret; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci dsi->panel = of_drm_find_panel(device->dev.of_node); 15538c2ecf20Sopenharmony_ci if (IS_ERR(dsi->panel)) 15548c2ecf20Sopenharmony_ci dsi->panel = NULL; 15558c2ecf20Sopenharmony_ci else 15568c2ecf20Sopenharmony_ci dsi->connector.status = connector_status_connected; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* 15608c2ecf20Sopenharmony_ci * This is a temporary solution and should be made by more generic way. 15618c2ecf20Sopenharmony_ci * 15628c2ecf20Sopenharmony_ci * If attached panel device is for command mode one, dsi should register 15638c2ecf20Sopenharmony_ci * TE interrupt handler. 15648c2ecf20Sopenharmony_ci */ 15658c2ecf20Sopenharmony_ci if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) { 15668c2ecf20Sopenharmony_ci int ret = exynos_dsi_register_te_irq(dsi, &device->dev); 15678c2ecf20Sopenharmony_ci if (ret) 15688c2ecf20Sopenharmony_ci return ret; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci mutex_lock(&drm->mode_config.mutex); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci dsi->lanes = device->lanes; 15748c2ecf20Sopenharmony_ci dsi->format = device->format; 15758c2ecf20Sopenharmony_ci dsi->mode_flags = device->mode_flags; 15768c2ecf20Sopenharmony_ci exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode = 15778c2ecf20Sopenharmony_ci !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci mutex_unlock(&drm->mode_config.mutex); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (drm->mode_config.poll_enabled) 15828c2ecf20Sopenharmony_ci drm_kms_helper_hotplug_event(drm); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci return 0; 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic int exynos_dsi_host_detach(struct mipi_dsi_host *host, 15888c2ecf20Sopenharmony_ci struct mipi_dsi_device *device) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = host_to_dsi(host); 15918c2ecf20Sopenharmony_ci struct drm_device *drm = dsi->encoder.dev; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (dsi->panel) { 15948c2ecf20Sopenharmony_ci mutex_lock(&drm->mode_config.mutex); 15958c2ecf20Sopenharmony_ci exynos_dsi_disable(&dsi->encoder); 15968c2ecf20Sopenharmony_ci dsi->panel = NULL; 15978c2ecf20Sopenharmony_ci dsi->connector.status = connector_status_disconnected; 15988c2ecf20Sopenharmony_ci mutex_unlock(&drm->mode_config.mutex); 15998c2ecf20Sopenharmony_ci } else { 16008c2ecf20Sopenharmony_ci if (dsi->out_bridge->funcs->detach) 16018c2ecf20Sopenharmony_ci dsi->out_bridge->funcs->detach(dsi->out_bridge); 16028c2ecf20Sopenharmony_ci dsi->out_bridge = NULL; 16038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dsi->bridge_chain); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (drm->mode_config.poll_enabled) 16078c2ecf20Sopenharmony_ci drm_kms_helper_hotplug_event(drm); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci exynos_dsi_unregister_te_irq(dsi); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return 0; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, 16158c2ecf20Sopenharmony_ci const struct mipi_dsi_msg *msg) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = host_to_dsi(host); 16188c2ecf20Sopenharmony_ci struct exynos_dsi_transfer xfer; 16198c2ecf20Sopenharmony_ci int ret; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (!(dsi->state & DSIM_STATE_ENABLED)) 16228c2ecf20Sopenharmony_ci return -EINVAL; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (!(dsi->state & DSIM_STATE_INITIALIZED)) { 16258c2ecf20Sopenharmony_ci ret = exynos_dsi_init(dsi); 16268c2ecf20Sopenharmony_ci if (ret) 16278c2ecf20Sopenharmony_ci return ret; 16288c2ecf20Sopenharmony_ci dsi->state |= DSIM_STATE_INITIALIZED; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci ret = mipi_dsi_create_packet(&xfer.packet, msg); 16328c2ecf20Sopenharmony_ci if (ret < 0) 16338c2ecf20Sopenharmony_ci return ret; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci xfer.rx_len = msg->rx_len; 16368c2ecf20Sopenharmony_ci xfer.rx_payload = msg->rx_buf; 16378c2ecf20Sopenharmony_ci xfer.flags = msg->flags; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci ret = exynos_dsi_transfer(dsi, &xfer); 16408c2ecf20Sopenharmony_ci return (ret < 0) ? ret : xfer.rx_done; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic const struct mipi_dsi_host_ops exynos_dsi_ops = { 16448c2ecf20Sopenharmony_ci .attach = exynos_dsi_host_attach, 16458c2ecf20Sopenharmony_ci .detach = exynos_dsi_host_detach, 16468c2ecf20Sopenharmony_ci .transfer = exynos_dsi_host_transfer, 16478c2ecf20Sopenharmony_ci}; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic int exynos_dsi_of_read_u32(const struct device_node *np, 16508c2ecf20Sopenharmony_ci const char *propname, u32 *out_value) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci int ret = of_property_read_u32(np, propname, out_value); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci if (ret < 0) 16558c2ecf20Sopenharmony_ci pr_err("%pOF: failed to get '%s' property\n", np, propname); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci return ret; 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cienum { 16618c2ecf20Sopenharmony_ci DSI_PORT_IN, 16628c2ecf20Sopenharmony_ci DSI_PORT_OUT 16638c2ecf20Sopenharmony_ci}; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic int exynos_dsi_parse_dt(struct exynos_dsi *dsi) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct device *dev = dsi->dev; 16688c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 16698c2ecf20Sopenharmony_ci int ret; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", 16728c2ecf20Sopenharmony_ci &dsi->pll_clk_rate); 16738c2ecf20Sopenharmony_ci if (ret < 0) 16748c2ecf20Sopenharmony_ci return ret; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency", 16778c2ecf20Sopenharmony_ci &dsi->burst_clk_rate); 16788c2ecf20Sopenharmony_ci if (ret < 0) 16798c2ecf20Sopenharmony_ci return ret; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci ret = exynos_dsi_of_read_u32(node, "samsung,esc-clock-frequency", 16828c2ecf20Sopenharmony_ci &dsi->esc_clk_rate); 16838c2ecf20Sopenharmony_ci if (ret < 0) 16848c2ecf20Sopenharmony_ci return ret; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci dsi->in_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci return 0; 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic int exynos_dsi_bind(struct device *dev, struct device *master, 16928c2ecf20Sopenharmony_ci void *data) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci struct drm_encoder *encoder = dev_get_drvdata(dev); 16958c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 16968c2ecf20Sopenharmony_ci struct drm_device *drm_dev = data; 16978c2ecf20Sopenharmony_ci struct drm_bridge *in_bridge; 16988c2ecf20Sopenharmony_ci int ret; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); 17058c2ecf20Sopenharmony_ci if (ret < 0) 17068c2ecf20Sopenharmony_ci return ret; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (dsi->in_bridge_node) { 17098c2ecf20Sopenharmony_ci in_bridge = of_drm_find_bridge(dsi->in_bridge_node); 17108c2ecf20Sopenharmony_ci if (in_bridge) 17118c2ecf20Sopenharmony_ci drm_bridge_attach(encoder, in_bridge, NULL, 0); 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci return mipi_dsi_host_register(&dsi->dsi_host); 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_cistatic void exynos_dsi_unbind(struct device *dev, struct device *master, 17188c2ecf20Sopenharmony_ci void *data) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct drm_encoder *encoder = dev_get_drvdata(dev); 17218c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci exynos_dsi_disable(encoder); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci mipi_dsi_host_unregister(&dsi->dsi_host); 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic const struct component_ops exynos_dsi_component_ops = { 17298c2ecf20Sopenharmony_ci .bind = exynos_dsi_bind, 17308c2ecf20Sopenharmony_ci .unbind = exynos_dsi_unbind, 17318c2ecf20Sopenharmony_ci}; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistatic int exynos_dsi_probe(struct platform_device *pdev) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 17368c2ecf20Sopenharmony_ci struct resource *res; 17378c2ecf20Sopenharmony_ci struct exynos_dsi *dsi; 17388c2ecf20Sopenharmony_ci int ret, i; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); 17418c2ecf20Sopenharmony_ci if (!dsi) 17428c2ecf20Sopenharmony_ci return -ENOMEM; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci /* To be checked as invalid one */ 17458c2ecf20Sopenharmony_ci dsi->te_gpio = -ENOENT; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci init_completion(&dsi->completed); 17488c2ecf20Sopenharmony_ci spin_lock_init(&dsi->transfer_lock); 17498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dsi->transfer_list); 17508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dsi->bridge_chain); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci dsi->dsi_host.ops = &exynos_dsi_ops; 17538c2ecf20Sopenharmony_ci dsi->dsi_host.dev = dev; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci dsi->dev = dev; 17568c2ecf20Sopenharmony_ci dsi->driver_data = of_device_get_match_data(dev); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci dsi->supplies[0].supply = "vddcore"; 17598c2ecf20Sopenharmony_ci dsi->supplies[1].supply = "vddio"; 17608c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies), 17618c2ecf20Sopenharmony_ci dsi->supplies); 17628c2ecf20Sopenharmony_ci if (ret) 17638c2ecf20Sopenharmony_ci return dev_err_probe(dev, ret, "failed to get regulators\n"); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci dsi->clks = devm_kcalloc(dev, 17668c2ecf20Sopenharmony_ci dsi->driver_data->num_clks, sizeof(*dsi->clks), 17678c2ecf20Sopenharmony_ci GFP_KERNEL); 17688c2ecf20Sopenharmony_ci if (!dsi->clks) 17698c2ecf20Sopenharmony_ci return -ENOMEM; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci for (i = 0; i < dsi->driver_data->num_clks; i++) { 17728c2ecf20Sopenharmony_ci dsi->clks[i] = devm_clk_get(dev, clk_names[i]); 17738c2ecf20Sopenharmony_ci if (IS_ERR(dsi->clks[i])) { 17748c2ecf20Sopenharmony_ci if (strcmp(clk_names[i], "sclk_mipi") == 0) { 17758c2ecf20Sopenharmony_ci dsi->clks[i] = devm_clk_get(dev, 17768c2ecf20Sopenharmony_ci OLD_SCLK_MIPI_CLK_NAME); 17778c2ecf20Sopenharmony_ci if (!IS_ERR(dsi->clks[i])) 17788c2ecf20Sopenharmony_ci continue; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci dev_info(dev, "failed to get the clock: %s\n", 17828c2ecf20Sopenharmony_ci clk_names[i]); 17838c2ecf20Sopenharmony_ci return PTR_ERR(dsi->clks[i]); 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 17888c2ecf20Sopenharmony_ci dsi->reg_base = devm_ioremap_resource(dev, res); 17898c2ecf20Sopenharmony_ci if (IS_ERR(dsi->reg_base)) { 17908c2ecf20Sopenharmony_ci dev_err(dev, "failed to remap io region\n"); 17918c2ecf20Sopenharmony_ci return PTR_ERR(dsi->reg_base); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci dsi->phy = devm_phy_get(dev, "dsim"); 17958c2ecf20Sopenharmony_ci if (IS_ERR(dsi->phy)) { 17968c2ecf20Sopenharmony_ci dev_info(dev, "failed to get dsim phy\n"); 17978c2ecf20Sopenharmony_ci return PTR_ERR(dsi->phy); 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci dsi->irq = platform_get_irq(pdev, 0); 18018c2ecf20Sopenharmony_ci if (dsi->irq < 0) 18028c2ecf20Sopenharmony_ci return dsi->irq; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, dsi->irq, NULL, 18058c2ecf20Sopenharmony_ci exynos_dsi_irq, 18068c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_NO_AUTOEN, 18078c2ecf20Sopenharmony_ci dev_name(dev), dsi); 18088c2ecf20Sopenharmony_ci if (ret) { 18098c2ecf20Sopenharmony_ci dev_err(dev, "failed to request dsi irq\n"); 18108c2ecf20Sopenharmony_ci return ret; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci ret = exynos_dsi_parse_dt(dsi); 18148c2ecf20Sopenharmony_ci if (ret) 18158c2ecf20Sopenharmony_ci return ret; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, &dsi->encoder); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci ret = component_add(dev, &exynos_dsi_component_ops); 18228c2ecf20Sopenharmony_ci if (ret) 18238c2ecf20Sopenharmony_ci goto err_disable_runtime; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci return 0; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_cierr_disable_runtime: 18288c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 18298c2ecf20Sopenharmony_ci of_node_put(dsi->in_bridge_node); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci return ret; 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic int exynos_dsi_remove(struct platform_device *pdev) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = platform_get_drvdata(pdev); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci of_node_put(dsi->in_bridge_node); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci component_del(&pdev->dev, &exynos_dsi_component_ops); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci return 0; 18458c2ecf20Sopenharmony_ci} 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_cistatic int __maybe_unused exynos_dsi_suspend(struct device *dev) 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci struct drm_encoder *encoder = dev_get_drvdata(dev); 18508c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 18518c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 18528c2ecf20Sopenharmony_ci int ret, i; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (dsi->state & DSIM_STATE_INITIALIZED) { 18578c2ecf20Sopenharmony_ci dsi->state &= ~DSIM_STATE_INITIALIZED; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci exynos_dsi_disable_clock(dsi); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci exynos_dsi_disable_irq(dsi); 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci dsi->state &= ~DSIM_STATE_CMD_LPM; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci phy_power_off(dsi->phy); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci for (i = driver_data->num_clks - 1; i > -1; i--) 18698c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->clks[i]); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 18728c2ecf20Sopenharmony_ci if (ret < 0) 18738c2ecf20Sopenharmony_ci dev_err(dsi->dev, "cannot disable regulators %d\n", ret); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci return 0; 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic int __maybe_unused exynos_dsi_resume(struct device *dev) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci struct drm_encoder *encoder = dev_get_drvdata(dev); 18818c2ecf20Sopenharmony_ci struct exynos_dsi *dsi = encoder_to_dsi(encoder); 18828c2ecf20Sopenharmony_ci const struct exynos_dsi_driver_data *driver_data = dsi->driver_data; 18838c2ecf20Sopenharmony_ci int ret, i; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 18868c2ecf20Sopenharmony_ci if (ret < 0) { 18878c2ecf20Sopenharmony_ci dev_err(dsi->dev, "cannot enable regulators %d\n", ret); 18888c2ecf20Sopenharmony_ci return ret; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci for (i = 0; i < driver_data->num_clks; i++) { 18928c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dsi->clks[i]); 18938c2ecf20Sopenharmony_ci if (ret < 0) 18948c2ecf20Sopenharmony_ci goto err_clk; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci ret = phy_power_on(dsi->phy); 18988c2ecf20Sopenharmony_ci if (ret < 0) { 18998c2ecf20Sopenharmony_ci dev_err(dsi->dev, "cannot enable phy %d\n", ret); 19008c2ecf20Sopenharmony_ci goto err_clk; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci return 0; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_cierr_clk: 19068c2ecf20Sopenharmony_ci while (--i > -1) 19078c2ecf20Sopenharmony_ci clk_disable_unprepare(dsi->clks[i]); 19088c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci return ret; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic const struct dev_pm_ops exynos_dsi_pm_ops = { 19148c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL) 19158c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 19168c2ecf20Sopenharmony_ci pm_runtime_force_resume) 19178c2ecf20Sopenharmony_ci}; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistruct platform_driver dsi_driver = { 19208c2ecf20Sopenharmony_ci .probe = exynos_dsi_probe, 19218c2ecf20Sopenharmony_ci .remove = exynos_dsi_remove, 19228c2ecf20Sopenharmony_ci .driver = { 19238c2ecf20Sopenharmony_ci .name = "exynos-dsi", 19248c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19258c2ecf20Sopenharmony_ci .pm = &exynos_dsi_pm_ops, 19268c2ecf20Sopenharmony_ci .of_match_table = exynos_dsi_of_match, 19278c2ecf20Sopenharmony_ci }, 19288c2ecf20Sopenharmony_ci}; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); 19318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 19328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); 19338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1934