17eb8f069SAndrzej Hajda /* 27eb8f069SAndrzej Hajda * Samsung SoC MIPI DSI Master driver. 37eb8f069SAndrzej Hajda * 47eb8f069SAndrzej Hajda * Copyright (c) 2014 Samsung Electronics Co., Ltd 57eb8f069SAndrzej Hajda * 67eb8f069SAndrzej Hajda * Contacts: Tomasz Figa <t.figa@samsung.com> 77eb8f069SAndrzej Hajda * 87eb8f069SAndrzej Hajda * This program is free software; you can redistribute it and/or modify 97eb8f069SAndrzej Hajda * it under the terms of the GNU General Public License version 2 as 107eb8f069SAndrzej Hajda * published by the Free Software Foundation. 117eb8f069SAndrzej Hajda */ 127eb8f069SAndrzej Hajda 137eb8f069SAndrzej Hajda #include <drm/drmP.h> 147eb8f069SAndrzej Hajda #include <drm/drm_crtc_helper.h> 157eb8f069SAndrzej Hajda #include <drm/drm_mipi_dsi.h> 167eb8f069SAndrzej Hajda #include <drm/drm_panel.h> 177eb8f069SAndrzej Hajda 187eb8f069SAndrzej Hajda #include <linux/clk.h> 19e17ddeccSYoungJun Cho #include <linux/gpio/consumer.h> 207eb8f069SAndrzej Hajda #include <linux/irq.h> 21e17ddeccSYoungJun Cho #include <linux/of_gpio.h> 227eb8f069SAndrzej Hajda #include <linux/phy/phy.h> 237eb8f069SAndrzej Hajda #include <linux/regulator/consumer.h> 24f37cd5e8SInki Dae #include <linux/component.h> 257eb8f069SAndrzej Hajda 267eb8f069SAndrzej Hajda #include <video/mipi_display.h> 277eb8f069SAndrzej Hajda #include <video/videomode.h> 287eb8f069SAndrzej Hajda 29e17ddeccSYoungJun Cho #include "exynos_drm_crtc.h" 307eb8f069SAndrzej Hajda #include "exynos_drm_drv.h" 317eb8f069SAndrzej Hajda 327eb8f069SAndrzej Hajda /* returns true iff both arguments logically differs */ 337eb8f069SAndrzej Hajda #define NEQV(a, b) (!(a) ^ !(b)) 347eb8f069SAndrzej Hajda 357eb8f069SAndrzej Hajda #define DSIM_STATUS_REG 0x0 /* Status register */ 367eb8f069SAndrzej Hajda #define DSIM_SWRST_REG 0x4 /* Software reset register */ 377eb8f069SAndrzej Hajda #define DSIM_CLKCTRL_REG 0x8 /* Clock control register */ 387eb8f069SAndrzej Hajda #define DSIM_TIMEOUT_REG 0xc /* Time out register */ 397eb8f069SAndrzej Hajda #define DSIM_CONFIG_REG 0x10 /* Configuration register */ 407eb8f069SAndrzej Hajda #define DSIM_ESCMODE_REG 0x14 /* Escape mode register */ 417eb8f069SAndrzej Hajda 427eb8f069SAndrzej Hajda /* Main display image resolution register */ 437eb8f069SAndrzej Hajda #define DSIM_MDRESOL_REG 0x18 447eb8f069SAndrzej Hajda #define DSIM_MVPORCH_REG 0x1c /* Main display Vporch register */ 457eb8f069SAndrzej Hajda #define DSIM_MHPORCH_REG 0x20 /* Main display Hporch register */ 467eb8f069SAndrzej Hajda #define DSIM_MSYNC_REG 0x24 /* Main display sync area register */ 477eb8f069SAndrzej Hajda 487eb8f069SAndrzej Hajda /* Sub display image resolution register */ 497eb8f069SAndrzej Hajda #define DSIM_SDRESOL_REG 0x28 507eb8f069SAndrzej Hajda #define DSIM_INTSRC_REG 0x2c /* Interrupt source register */ 517eb8f069SAndrzej Hajda #define DSIM_INTMSK_REG 0x30 /* Interrupt mask register */ 527eb8f069SAndrzej Hajda #define DSIM_PKTHDR_REG 0x34 /* Packet Header FIFO register */ 537eb8f069SAndrzej Hajda #define DSIM_PAYLOAD_REG 0x38 /* Payload FIFO register */ 547eb8f069SAndrzej Hajda #define DSIM_RXFIFO_REG 0x3c /* Read FIFO register */ 557eb8f069SAndrzej Hajda #define DSIM_FIFOTHLD_REG 0x40 /* FIFO threshold level register */ 567eb8f069SAndrzej Hajda #define DSIM_FIFOCTRL_REG 0x44 /* FIFO status and control register */ 577eb8f069SAndrzej Hajda 587eb8f069SAndrzej Hajda /* FIFO memory AC characteristic register */ 597eb8f069SAndrzej Hajda #define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ 607eb8f069SAndrzej Hajda #define DSIM_PLLTMR_REG 0x50 /* PLL timer register */ 617eb8f069SAndrzej Hajda #define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ 627eb8f069SAndrzej Hajda #define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ 637eb8f069SAndrzej Hajda 647eb8f069SAndrzej Hajda /* DSIM_STATUS */ 657eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) 667eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CLK (1 << 8) 677eb8f069SAndrzej Hajda #define DSIM_TX_READY_HS_CLK (1 << 10) 687eb8f069SAndrzej Hajda #define DSIM_PLL_STABLE (1 << 31) 697eb8f069SAndrzej Hajda 707eb8f069SAndrzej Hajda /* DSIM_SWRST */ 717eb8f069SAndrzej Hajda #define DSIM_FUNCRST (1 << 16) 727eb8f069SAndrzej Hajda #define DSIM_SWRST (1 << 0) 737eb8f069SAndrzej Hajda 747eb8f069SAndrzej Hajda /* DSIM_TIMEOUT */ 757eb8f069SAndrzej Hajda #define DSIM_LPDR_TIMEOUT(x) ((x) << 0) 767eb8f069SAndrzej Hajda #define DSIM_BTA_TIMEOUT(x) ((x) << 16) 777eb8f069SAndrzej Hajda 787eb8f069SAndrzej Hajda /* DSIM_CLKCTRL */ 797eb8f069SAndrzej Hajda #define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0) 807eb8f069SAndrzej Hajda #define DSIM_ESC_PRESCALER_MASK (0xffff << 0) 817eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_CLK (1 << 19) 827eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_DATA(x) (((x) & 0xf) << 20) 837eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20) 847eb8f069SAndrzej Hajda #define DSIM_BYTE_CLKEN (1 << 24) 857eb8f069SAndrzej Hajda #define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25) 867eb8f069SAndrzej Hajda #define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25) 877eb8f069SAndrzej Hajda #define DSIM_PLL_BYPASS (1 << 27) 887eb8f069SAndrzej Hajda #define DSIM_ESC_CLKEN (1 << 28) 897eb8f069SAndrzej Hajda #define DSIM_TX_REQUEST_HSCLK (1 << 31) 907eb8f069SAndrzej Hajda 917eb8f069SAndrzej Hajda /* DSIM_CONFIG */ 927eb8f069SAndrzej Hajda #define DSIM_LANE_EN_CLK (1 << 0) 937eb8f069SAndrzej Hajda #define DSIM_LANE_EN(x) (((x) & 0xf) << 1) 947eb8f069SAndrzej Hajda #define DSIM_NUM_OF_DATA_LANE(x) (((x) & 0x3) << 5) 957eb8f069SAndrzej Hajda #define DSIM_SUB_PIX_FORMAT(x) (((x) & 0x7) << 8) 967eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_MASK (0x7 << 12) 977eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB888 (0x7 << 12) 987eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB666 (0x6 << 12) 997eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB666_P (0x5 << 12) 1007eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB565 (0x4 << 12) 1017eb8f069SAndrzej Hajda #define DSIM_SUB_VC (((x) & 0x3) << 16) 1027eb8f069SAndrzej Hajda #define DSIM_MAIN_VC (((x) & 0x3) << 18) 1037eb8f069SAndrzej Hajda #define DSIM_HSA_MODE (1 << 20) 1047eb8f069SAndrzej Hajda #define DSIM_HBP_MODE (1 << 21) 1057eb8f069SAndrzej Hajda #define DSIM_HFP_MODE (1 << 22) 1067eb8f069SAndrzej Hajda #define DSIM_HSE_MODE (1 << 23) 1077eb8f069SAndrzej Hajda #define DSIM_AUTO_MODE (1 << 24) 1087eb8f069SAndrzej Hajda #define DSIM_VIDEO_MODE (1 << 25) 1097eb8f069SAndrzej Hajda #define DSIM_BURST_MODE (1 << 26) 1107eb8f069SAndrzej Hajda #define DSIM_SYNC_INFORM (1 << 27) 1117eb8f069SAndrzej Hajda #define DSIM_EOT_DISABLE (1 << 28) 1127eb8f069SAndrzej Hajda #define DSIM_MFLUSH_VS (1 << 29) 1137eb8f069SAndrzej Hajda 1147eb8f069SAndrzej Hajda /* DSIM_ESCMODE */ 1157eb8f069SAndrzej Hajda #define DSIM_TX_TRIGGER_RST (1 << 4) 1167eb8f069SAndrzej Hajda #define DSIM_TX_LPDT_LP (1 << 6) 1177eb8f069SAndrzej Hajda #define DSIM_CMD_LPDT_LP (1 << 7) 1187eb8f069SAndrzej Hajda #define DSIM_FORCE_BTA (1 << 16) 1197eb8f069SAndrzej Hajda #define DSIM_FORCE_STOP_STATE (1 << 20) 1207eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CNT(x) (((x) & 0x7ff) << 21) 1217eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CNT_MASK (0x7ff << 21) 1227eb8f069SAndrzej Hajda 1237eb8f069SAndrzej Hajda /* DSIM_MDRESOL */ 1247eb8f069SAndrzej Hajda #define DSIM_MAIN_STAND_BY (1 << 31) 1257eb8f069SAndrzej Hajda #define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16) 1267eb8f069SAndrzej Hajda #define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0) 1277eb8f069SAndrzej Hajda 1287eb8f069SAndrzej Hajda /* DSIM_MVPORCH */ 1297eb8f069SAndrzej Hajda #define DSIM_CMD_ALLOW(x) ((x) << 28) 1307eb8f069SAndrzej Hajda #define DSIM_STABLE_VFP(x) ((x) << 16) 1317eb8f069SAndrzej Hajda #define DSIM_MAIN_VBP(x) ((x) << 0) 1327eb8f069SAndrzej Hajda #define DSIM_CMD_ALLOW_MASK (0xf << 28) 1337eb8f069SAndrzej Hajda #define DSIM_STABLE_VFP_MASK (0x7ff << 16) 1347eb8f069SAndrzej Hajda #define DSIM_MAIN_VBP_MASK (0x7ff << 0) 1357eb8f069SAndrzej Hajda 1367eb8f069SAndrzej Hajda /* DSIM_MHPORCH */ 1377eb8f069SAndrzej Hajda #define DSIM_MAIN_HFP(x) ((x) << 16) 1387eb8f069SAndrzej Hajda #define DSIM_MAIN_HBP(x) ((x) << 0) 1397eb8f069SAndrzej Hajda #define DSIM_MAIN_HFP_MASK ((0xffff) << 16) 1407eb8f069SAndrzej Hajda #define DSIM_MAIN_HBP_MASK ((0xffff) << 0) 1417eb8f069SAndrzej Hajda 1427eb8f069SAndrzej Hajda /* DSIM_MSYNC */ 1437eb8f069SAndrzej Hajda #define DSIM_MAIN_VSA(x) ((x) << 22) 1447eb8f069SAndrzej Hajda #define DSIM_MAIN_HSA(x) ((x) << 0) 1457eb8f069SAndrzej Hajda #define DSIM_MAIN_VSA_MASK ((0x3ff) << 22) 1467eb8f069SAndrzej Hajda #define DSIM_MAIN_HSA_MASK ((0xffff) << 0) 1477eb8f069SAndrzej Hajda 1487eb8f069SAndrzej Hajda /* DSIM_SDRESOL */ 1497eb8f069SAndrzej Hajda #define DSIM_SUB_STANDY(x) ((x) << 31) 1507eb8f069SAndrzej Hajda #define DSIM_SUB_VRESOL(x) ((x) << 16) 1517eb8f069SAndrzej Hajda #define DSIM_SUB_HRESOL(x) ((x) << 0) 1527eb8f069SAndrzej Hajda #define DSIM_SUB_STANDY_MASK ((0x1) << 31) 1537eb8f069SAndrzej Hajda #define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16) 1547eb8f069SAndrzej Hajda #define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0) 1557eb8f069SAndrzej Hajda 1567eb8f069SAndrzej Hajda /* DSIM_INTSRC */ 1577eb8f069SAndrzej Hajda #define DSIM_INT_PLL_STABLE (1 << 31) 1587eb8f069SAndrzej Hajda #define DSIM_INT_SW_RST_RELEASE (1 << 30) 1597eb8f069SAndrzej Hajda #define DSIM_INT_SFR_FIFO_EMPTY (1 << 29) 1607eb8f069SAndrzej Hajda #define DSIM_INT_BTA (1 << 25) 1617eb8f069SAndrzej Hajda #define DSIM_INT_FRAME_DONE (1 << 24) 1627eb8f069SAndrzej Hajda #define DSIM_INT_RX_TIMEOUT (1 << 21) 1637eb8f069SAndrzej Hajda #define DSIM_INT_BTA_TIMEOUT (1 << 20) 1647eb8f069SAndrzej Hajda #define DSIM_INT_RX_DONE (1 << 18) 1657eb8f069SAndrzej Hajda #define DSIM_INT_RX_TE (1 << 17) 1667eb8f069SAndrzej Hajda #define DSIM_INT_RX_ACK (1 << 16) 1677eb8f069SAndrzej Hajda #define DSIM_INT_RX_ECC_ERR (1 << 15) 1687eb8f069SAndrzej Hajda #define DSIM_INT_RX_CRC_ERR (1 << 14) 1697eb8f069SAndrzej Hajda 1707eb8f069SAndrzej Hajda /* DSIM_FIFOCTRL */ 1717eb8f069SAndrzej Hajda #define DSIM_RX_DATA_FULL (1 << 25) 1727eb8f069SAndrzej Hajda #define DSIM_RX_DATA_EMPTY (1 << 24) 1737eb8f069SAndrzej Hajda #define DSIM_SFR_HEADER_FULL (1 << 23) 1747eb8f069SAndrzej Hajda #define DSIM_SFR_HEADER_EMPTY (1 << 22) 1757eb8f069SAndrzej Hajda #define DSIM_SFR_PAYLOAD_FULL (1 << 21) 1767eb8f069SAndrzej Hajda #define DSIM_SFR_PAYLOAD_EMPTY (1 << 20) 1777eb8f069SAndrzej Hajda #define DSIM_I80_HEADER_FULL (1 << 19) 1787eb8f069SAndrzej Hajda #define DSIM_I80_HEADER_EMPTY (1 << 18) 1797eb8f069SAndrzej Hajda #define DSIM_I80_PAYLOAD_FULL (1 << 17) 1807eb8f069SAndrzej Hajda #define DSIM_I80_PAYLOAD_EMPTY (1 << 16) 1817eb8f069SAndrzej Hajda #define DSIM_SD_HEADER_FULL (1 << 15) 1827eb8f069SAndrzej Hajda #define DSIM_SD_HEADER_EMPTY (1 << 14) 1837eb8f069SAndrzej Hajda #define DSIM_SD_PAYLOAD_FULL (1 << 13) 1847eb8f069SAndrzej Hajda #define DSIM_SD_PAYLOAD_EMPTY (1 << 12) 1857eb8f069SAndrzej Hajda #define DSIM_MD_HEADER_FULL (1 << 11) 1867eb8f069SAndrzej Hajda #define DSIM_MD_HEADER_EMPTY (1 << 10) 1877eb8f069SAndrzej Hajda #define DSIM_MD_PAYLOAD_FULL (1 << 9) 1887eb8f069SAndrzej Hajda #define DSIM_MD_PAYLOAD_EMPTY (1 << 8) 1897eb8f069SAndrzej Hajda #define DSIM_RX_FIFO (1 << 4) 1907eb8f069SAndrzej Hajda #define DSIM_SFR_FIFO (1 << 3) 1917eb8f069SAndrzej Hajda #define DSIM_I80_FIFO (1 << 2) 1927eb8f069SAndrzej Hajda #define DSIM_SD_FIFO (1 << 1) 1937eb8f069SAndrzej Hajda #define DSIM_MD_FIFO (1 << 0) 1947eb8f069SAndrzej Hajda 1957eb8f069SAndrzej Hajda /* DSIM_PHYACCHR */ 1967eb8f069SAndrzej Hajda #define DSIM_AFC_EN (1 << 14) 1977eb8f069SAndrzej Hajda #define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) 1987eb8f069SAndrzej Hajda 1997eb8f069SAndrzej Hajda /* DSIM_PLLCTRL */ 2007eb8f069SAndrzej Hajda #define DSIM_FREQ_BAND(x) ((x) << 24) 2017eb8f069SAndrzej Hajda #define DSIM_PLL_EN (1 << 23) 2027eb8f069SAndrzej Hajda #define DSIM_PLL_P(x) ((x) << 13) 2037eb8f069SAndrzej Hajda #define DSIM_PLL_M(x) ((x) << 4) 2047eb8f069SAndrzej Hajda #define DSIM_PLL_S(x) ((x) << 1) 2057eb8f069SAndrzej Hajda 2067eb8f069SAndrzej Hajda #define DSI_MAX_BUS_WIDTH 4 2077eb8f069SAndrzej Hajda #define DSI_NUM_VIRTUAL_CHANNELS 4 2087eb8f069SAndrzej Hajda #define DSI_TX_FIFO_SIZE 2048 2097eb8f069SAndrzej Hajda #define DSI_RX_FIFO_SIZE 256 2107eb8f069SAndrzej Hajda #define DSI_XFER_TIMEOUT_MS 100 2117eb8f069SAndrzej Hajda #define DSI_RX_FIFO_EMPTY 0x30800002 2127eb8f069SAndrzej Hajda 2137eb8f069SAndrzej Hajda enum exynos_dsi_transfer_type { 2147eb8f069SAndrzej Hajda EXYNOS_DSI_TX, 2157eb8f069SAndrzej Hajda EXYNOS_DSI_RX, 2167eb8f069SAndrzej Hajda }; 2177eb8f069SAndrzej Hajda 2187eb8f069SAndrzej Hajda struct exynos_dsi_transfer { 2197eb8f069SAndrzej Hajda struct list_head list; 2207eb8f069SAndrzej Hajda struct completion completed; 2217eb8f069SAndrzej Hajda int result; 2227eb8f069SAndrzej Hajda u8 data_id; 2237eb8f069SAndrzej Hajda u8 data[2]; 2247eb8f069SAndrzej Hajda u16 flags; 2257eb8f069SAndrzej Hajda 2267eb8f069SAndrzej Hajda const u8 *tx_payload; 2277eb8f069SAndrzej Hajda u16 tx_len; 2287eb8f069SAndrzej Hajda u16 tx_done; 2297eb8f069SAndrzej Hajda 2307eb8f069SAndrzej Hajda u8 *rx_payload; 2317eb8f069SAndrzej Hajda u16 rx_len; 2327eb8f069SAndrzej Hajda u16 rx_done; 2337eb8f069SAndrzej Hajda }; 2347eb8f069SAndrzej Hajda 2357eb8f069SAndrzej Hajda #define DSIM_STATE_ENABLED BIT(0) 2367eb8f069SAndrzej Hajda #define DSIM_STATE_INITIALIZED BIT(1) 2377eb8f069SAndrzej Hajda #define DSIM_STATE_CMD_LPM BIT(2) 2387eb8f069SAndrzej Hajda 2397eb8f069SAndrzej Hajda struct exynos_dsi { 2407eb8f069SAndrzej Hajda struct mipi_dsi_host dsi_host; 2417eb8f069SAndrzej Hajda struct drm_connector connector; 2427eb8f069SAndrzej Hajda struct drm_encoder *encoder; 2437eb8f069SAndrzej Hajda struct device_node *panel_node; 2447eb8f069SAndrzej Hajda struct drm_panel *panel; 2457eb8f069SAndrzej Hajda struct device *dev; 2467eb8f069SAndrzej Hajda 2477eb8f069SAndrzej Hajda void __iomem *reg_base; 2487eb8f069SAndrzej Hajda struct phy *phy; 2497eb8f069SAndrzej Hajda struct clk *pll_clk; 2507eb8f069SAndrzej Hajda struct clk *bus_clk; 2517eb8f069SAndrzej Hajda struct regulator_bulk_data supplies[2]; 2527eb8f069SAndrzej Hajda int irq; 253e17ddeccSYoungJun Cho int te_gpio; 2547eb8f069SAndrzej Hajda 2557eb8f069SAndrzej Hajda u32 pll_clk_rate; 2567eb8f069SAndrzej Hajda u32 burst_clk_rate; 2577eb8f069SAndrzej Hajda u32 esc_clk_rate; 2587eb8f069SAndrzej Hajda u32 lanes; 2597eb8f069SAndrzej Hajda u32 mode_flags; 2607eb8f069SAndrzej Hajda u32 format; 2617eb8f069SAndrzej Hajda struct videomode vm; 2627eb8f069SAndrzej Hajda 2637eb8f069SAndrzej Hajda int state; 2647eb8f069SAndrzej Hajda struct drm_property *brightness; 2657eb8f069SAndrzej Hajda struct completion completed; 2667eb8f069SAndrzej Hajda 2677eb8f069SAndrzej Hajda spinlock_t transfer_lock; /* protects transfer_list */ 2687eb8f069SAndrzej Hajda struct list_head transfer_list; 2697eb8f069SAndrzej Hajda }; 2707eb8f069SAndrzej Hajda 2717eb8f069SAndrzej Hajda #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) 2727eb8f069SAndrzej Hajda #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) 2737eb8f069SAndrzej Hajda 2747eb8f069SAndrzej Hajda static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) 2757eb8f069SAndrzej Hajda { 2767eb8f069SAndrzej Hajda if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) 2777eb8f069SAndrzej Hajda return; 2787eb8f069SAndrzej Hajda 2797eb8f069SAndrzej Hajda dev_err(dsi->dev, "timeout waiting for reset\n"); 2807eb8f069SAndrzej Hajda } 2817eb8f069SAndrzej Hajda 2827eb8f069SAndrzej Hajda static void exynos_dsi_reset(struct exynos_dsi *dsi) 2837eb8f069SAndrzej Hajda { 2847eb8f069SAndrzej Hajda reinit_completion(&dsi->completed); 2857eb8f069SAndrzej Hajda writel(DSIM_SWRST, dsi->reg_base + DSIM_SWRST_REG); 2867eb8f069SAndrzej Hajda } 2877eb8f069SAndrzej Hajda 2887eb8f069SAndrzej Hajda #ifndef MHZ 2897eb8f069SAndrzej Hajda #define MHZ (1000*1000) 2907eb8f069SAndrzej Hajda #endif 2917eb8f069SAndrzej Hajda 2927eb8f069SAndrzej Hajda static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, 2937eb8f069SAndrzej Hajda unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s) 2947eb8f069SAndrzej Hajda { 2957eb8f069SAndrzej Hajda unsigned long best_freq = 0; 2967eb8f069SAndrzej Hajda u32 min_delta = 0xffffffff; 2977eb8f069SAndrzej Hajda u8 p_min, p_max; 2987eb8f069SAndrzej Hajda u8 _p, uninitialized_var(best_p); 2997eb8f069SAndrzej Hajda u16 _m, uninitialized_var(best_m); 3007eb8f069SAndrzej Hajda u8 _s, uninitialized_var(best_s); 3017eb8f069SAndrzej Hajda 3027eb8f069SAndrzej Hajda p_min = DIV_ROUND_UP(fin, (12 * MHZ)); 3037eb8f069SAndrzej Hajda p_max = fin / (6 * MHZ); 3047eb8f069SAndrzej Hajda 3057eb8f069SAndrzej Hajda for (_p = p_min; _p <= p_max; ++_p) { 3067eb8f069SAndrzej Hajda for (_s = 0; _s <= 5; ++_s) { 3077eb8f069SAndrzej Hajda u64 tmp; 3087eb8f069SAndrzej Hajda u32 delta; 3097eb8f069SAndrzej Hajda 3107eb8f069SAndrzej Hajda tmp = (u64)fout * (_p << _s); 3117eb8f069SAndrzej Hajda do_div(tmp, fin); 3127eb8f069SAndrzej Hajda _m = tmp; 3137eb8f069SAndrzej Hajda if (_m < 41 || _m > 125) 3147eb8f069SAndrzej Hajda continue; 3157eb8f069SAndrzej Hajda 3167eb8f069SAndrzej Hajda tmp = (u64)_m * fin; 3177eb8f069SAndrzej Hajda do_div(tmp, _p); 3187eb8f069SAndrzej Hajda if (tmp < 500 * MHZ || tmp > 1000 * MHZ) 3197eb8f069SAndrzej Hajda continue; 3207eb8f069SAndrzej Hajda 3217eb8f069SAndrzej Hajda tmp = (u64)_m * fin; 3227eb8f069SAndrzej Hajda do_div(tmp, _p << _s); 3237eb8f069SAndrzej Hajda 3247eb8f069SAndrzej Hajda delta = abs(fout - tmp); 3257eb8f069SAndrzej Hajda if (delta < min_delta) { 3267eb8f069SAndrzej Hajda best_p = _p; 3277eb8f069SAndrzej Hajda best_m = _m; 3287eb8f069SAndrzej Hajda best_s = _s; 3297eb8f069SAndrzej Hajda min_delta = delta; 3307eb8f069SAndrzej Hajda best_freq = tmp; 3317eb8f069SAndrzej Hajda } 3327eb8f069SAndrzej Hajda } 3337eb8f069SAndrzej Hajda } 3347eb8f069SAndrzej Hajda 3357eb8f069SAndrzej Hajda if (best_freq) { 3367eb8f069SAndrzej Hajda *p = best_p; 3377eb8f069SAndrzej Hajda *m = best_m; 3387eb8f069SAndrzej Hajda *s = best_s; 3397eb8f069SAndrzej Hajda } 3407eb8f069SAndrzej Hajda 3417eb8f069SAndrzej Hajda return best_freq; 3427eb8f069SAndrzej Hajda } 3437eb8f069SAndrzej Hajda 3447eb8f069SAndrzej Hajda static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, 3457eb8f069SAndrzej Hajda unsigned long freq) 3467eb8f069SAndrzej Hajda { 3477eb8f069SAndrzej Hajda static const unsigned long freq_bands[] = { 3487eb8f069SAndrzej Hajda 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, 3497eb8f069SAndrzej Hajda 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, 3507eb8f069SAndrzej Hajda 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, 3517eb8f069SAndrzej Hajda 770 * MHZ, 870 * MHZ, 950 * MHZ, 3527eb8f069SAndrzej Hajda }; 3537eb8f069SAndrzej Hajda unsigned long fin, fout; 3547eb8f069SAndrzej Hajda int timeout, band; 3557eb8f069SAndrzej Hajda u8 p, s; 3567eb8f069SAndrzej Hajda u16 m; 3577eb8f069SAndrzej Hajda u32 reg; 3587eb8f069SAndrzej Hajda 3597eb8f069SAndrzej Hajda clk_set_rate(dsi->pll_clk, dsi->pll_clk_rate); 3607eb8f069SAndrzej Hajda 3617eb8f069SAndrzej Hajda fin = clk_get_rate(dsi->pll_clk); 3627eb8f069SAndrzej Hajda if (!fin) { 3637eb8f069SAndrzej Hajda dev_err(dsi->dev, "failed to get PLL clock frequency\n"); 3647eb8f069SAndrzej Hajda return 0; 3657eb8f069SAndrzej Hajda } 3667eb8f069SAndrzej Hajda 3677eb8f069SAndrzej Hajda dev_dbg(dsi->dev, "PLL input frequency: %lu\n", fin); 3687eb8f069SAndrzej Hajda 3697eb8f069SAndrzej Hajda fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s); 3707eb8f069SAndrzej Hajda if (!fout) { 3717eb8f069SAndrzej Hajda dev_err(dsi->dev, 3727eb8f069SAndrzej Hajda "failed to find PLL PMS for requested frequency\n"); 3737eb8f069SAndrzej Hajda return -EFAULT; 3747eb8f069SAndrzej Hajda } 3757eb8f069SAndrzej Hajda 3767eb8f069SAndrzej Hajda for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) 3777eb8f069SAndrzej Hajda if (fout < freq_bands[band]) 3787eb8f069SAndrzej Hajda break; 3797eb8f069SAndrzej Hajda 3807eb8f069SAndrzej Hajda dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout, 3817eb8f069SAndrzej Hajda p, m, s, band); 3827eb8f069SAndrzej Hajda 3837eb8f069SAndrzej Hajda writel(500, dsi->reg_base + DSIM_PLLTMR_REG); 3847eb8f069SAndrzej Hajda 3857eb8f069SAndrzej Hajda reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN 3867eb8f069SAndrzej Hajda | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); 3877eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); 3887eb8f069SAndrzej Hajda 3897eb8f069SAndrzej Hajda timeout = 1000; 3907eb8f069SAndrzej Hajda do { 3917eb8f069SAndrzej Hajda if (timeout-- == 0) { 3927eb8f069SAndrzej Hajda dev_err(dsi->dev, "PLL failed to stabilize\n"); 3937eb8f069SAndrzej Hajda return -EFAULT; 3947eb8f069SAndrzej Hajda } 3957eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_STATUS_REG); 3967eb8f069SAndrzej Hajda } while ((reg & DSIM_PLL_STABLE) == 0); 3977eb8f069SAndrzej Hajda 3987eb8f069SAndrzej Hajda return fout; 3997eb8f069SAndrzej Hajda } 4007eb8f069SAndrzej Hajda 4017eb8f069SAndrzej Hajda static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) 4027eb8f069SAndrzej Hajda { 4037eb8f069SAndrzej Hajda unsigned long hs_clk, byte_clk, esc_clk; 4047eb8f069SAndrzej Hajda unsigned long esc_div; 4057eb8f069SAndrzej Hajda u32 reg; 4067eb8f069SAndrzej Hajda 4077eb8f069SAndrzej Hajda hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate); 4087eb8f069SAndrzej Hajda if (!hs_clk) { 4097eb8f069SAndrzej Hajda dev_err(dsi->dev, "failed to configure DSI PLL\n"); 4107eb8f069SAndrzej Hajda return -EFAULT; 4117eb8f069SAndrzej Hajda } 4127eb8f069SAndrzej Hajda 4137eb8f069SAndrzej Hajda byte_clk = hs_clk / 8; 4147eb8f069SAndrzej Hajda esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate); 4157eb8f069SAndrzej Hajda esc_clk = byte_clk / esc_div; 4167eb8f069SAndrzej Hajda 4177eb8f069SAndrzej Hajda if (esc_clk > 20 * MHZ) { 4187eb8f069SAndrzej Hajda ++esc_div; 4197eb8f069SAndrzej Hajda esc_clk = byte_clk / esc_div; 4207eb8f069SAndrzej Hajda } 4217eb8f069SAndrzej Hajda 4227eb8f069SAndrzej Hajda dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n", 4237eb8f069SAndrzej Hajda hs_clk, byte_clk, esc_clk); 4247eb8f069SAndrzej Hajda 4257eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); 4267eb8f069SAndrzej Hajda reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK 4277eb8f069SAndrzej Hajda | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS 4287eb8f069SAndrzej Hajda | DSIM_BYTE_CLK_SRC_MASK); 4297eb8f069SAndrzej Hajda reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN 4307eb8f069SAndrzej Hajda | DSIM_ESC_PRESCALER(esc_div) 4317eb8f069SAndrzej Hajda | DSIM_LANE_ESC_CLK_EN_CLK 4327eb8f069SAndrzej Hajda | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1) 4337eb8f069SAndrzej Hajda | DSIM_BYTE_CLK_SRC(0) 4347eb8f069SAndrzej Hajda | DSIM_TX_REQUEST_HSCLK; 4357eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); 4367eb8f069SAndrzej Hajda 4377eb8f069SAndrzej Hajda return 0; 4387eb8f069SAndrzej Hajda } 4397eb8f069SAndrzej Hajda 4407eb8f069SAndrzej Hajda static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) 4417eb8f069SAndrzej Hajda { 4427eb8f069SAndrzej Hajda u32 reg; 4437eb8f069SAndrzej Hajda 4447eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); 4457eb8f069SAndrzej Hajda reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK 4467eb8f069SAndrzej Hajda | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN); 4477eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); 4487eb8f069SAndrzej Hajda 4497eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_PLLCTRL_REG); 4507eb8f069SAndrzej Hajda reg &= ~DSIM_PLL_EN; 4517eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); 4527eb8f069SAndrzej Hajda } 4537eb8f069SAndrzej Hajda 4547eb8f069SAndrzej Hajda static int exynos_dsi_init_link(struct exynos_dsi *dsi) 4557eb8f069SAndrzej Hajda { 4567eb8f069SAndrzej Hajda int timeout; 4577eb8f069SAndrzej Hajda u32 reg; 4587eb8f069SAndrzej Hajda u32 lanes_mask; 4597eb8f069SAndrzej Hajda 4607eb8f069SAndrzej Hajda /* Initialize FIFO pointers */ 4617eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); 4627eb8f069SAndrzej Hajda reg &= ~0x1f; 4637eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); 4647eb8f069SAndrzej Hajda 4657eb8f069SAndrzej Hajda usleep_range(9000, 11000); 4667eb8f069SAndrzej Hajda 4677eb8f069SAndrzej Hajda reg |= 0x1f; 4687eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); 4697eb8f069SAndrzej Hajda 4707eb8f069SAndrzej Hajda usleep_range(9000, 11000); 4717eb8f069SAndrzej Hajda 4727eb8f069SAndrzej Hajda /* DSI configuration */ 4737eb8f069SAndrzej Hajda reg = 0; 4747eb8f069SAndrzej Hajda 4752f36e33aSYoungJun Cho /* 4762f36e33aSYoungJun Cho * The first bit of mode_flags specifies display configuration. 4772f36e33aSYoungJun Cho * If this bit is set[= MIPI_DSI_MODE_VIDEO], dsi will support video 4782f36e33aSYoungJun Cho * mode, otherwise it will support command mode. 4792f36e33aSYoungJun Cho */ 4807eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 4817eb8f069SAndrzej Hajda reg |= DSIM_VIDEO_MODE; 4827eb8f069SAndrzej Hajda 4832f36e33aSYoungJun Cho /* 4842f36e33aSYoungJun Cho * The user manual describes that following bits are ignored in 4852f36e33aSYoungJun Cho * command mode. 4862f36e33aSYoungJun Cho */ 4877eb8f069SAndrzej Hajda if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) 4887eb8f069SAndrzej Hajda reg |= DSIM_MFLUSH_VS; 4897eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 4907eb8f069SAndrzej Hajda reg |= DSIM_SYNC_INFORM; 4917eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) 4927eb8f069SAndrzej Hajda reg |= DSIM_BURST_MODE; 4937eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT) 4947eb8f069SAndrzej Hajda reg |= DSIM_AUTO_MODE; 4957eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE) 4967eb8f069SAndrzej Hajda reg |= DSIM_HSE_MODE; 4977eb8f069SAndrzej Hajda if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)) 4987eb8f069SAndrzej Hajda reg |= DSIM_HFP_MODE; 4997eb8f069SAndrzej Hajda if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)) 5007eb8f069SAndrzej Hajda reg |= DSIM_HBP_MODE; 5017eb8f069SAndrzej Hajda if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)) 5027eb8f069SAndrzej Hajda reg |= DSIM_HSA_MODE; 5037eb8f069SAndrzej Hajda } 5047eb8f069SAndrzej Hajda 5052f36e33aSYoungJun Cho if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) 5062f36e33aSYoungJun Cho reg |= DSIM_EOT_DISABLE; 5072f36e33aSYoungJun Cho 5087eb8f069SAndrzej Hajda switch (dsi->format) { 5097eb8f069SAndrzej Hajda case MIPI_DSI_FMT_RGB888: 5107eb8f069SAndrzej Hajda reg |= DSIM_MAIN_PIX_FORMAT_RGB888; 5117eb8f069SAndrzej Hajda break; 5127eb8f069SAndrzej Hajda case MIPI_DSI_FMT_RGB666: 5137eb8f069SAndrzej Hajda reg |= DSIM_MAIN_PIX_FORMAT_RGB666; 5147eb8f069SAndrzej Hajda break; 5157eb8f069SAndrzej Hajda case MIPI_DSI_FMT_RGB666_PACKED: 5167eb8f069SAndrzej Hajda reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P; 5177eb8f069SAndrzej Hajda break; 5187eb8f069SAndrzej Hajda case MIPI_DSI_FMT_RGB565: 5197eb8f069SAndrzej Hajda reg |= DSIM_MAIN_PIX_FORMAT_RGB565; 5207eb8f069SAndrzej Hajda break; 5217eb8f069SAndrzej Hajda default: 5227eb8f069SAndrzej Hajda dev_err(dsi->dev, "invalid pixel format\n"); 5237eb8f069SAndrzej Hajda return -EINVAL; 5247eb8f069SAndrzej Hajda } 5257eb8f069SAndrzej Hajda 5267eb8f069SAndrzej Hajda reg |= DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1); 5277eb8f069SAndrzej Hajda 5287eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_CONFIG_REG); 5297eb8f069SAndrzej Hajda 5307eb8f069SAndrzej Hajda reg |= DSIM_LANE_EN_CLK; 5317eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_CONFIG_REG); 5327eb8f069SAndrzej Hajda 5337eb8f069SAndrzej Hajda lanes_mask = BIT(dsi->lanes) - 1; 5347eb8f069SAndrzej Hajda reg |= DSIM_LANE_EN(lanes_mask); 5357eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_CONFIG_REG); 5367eb8f069SAndrzej Hajda 5377eb8f069SAndrzej Hajda /* Check clock and data lane state are stop state */ 5387eb8f069SAndrzej Hajda timeout = 100; 5397eb8f069SAndrzej Hajda do { 5407eb8f069SAndrzej Hajda if (timeout-- == 0) { 5417eb8f069SAndrzej Hajda dev_err(dsi->dev, "waiting for bus lanes timed out\n"); 5427eb8f069SAndrzej Hajda return -EFAULT; 5437eb8f069SAndrzej Hajda } 5447eb8f069SAndrzej Hajda 5457eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_STATUS_REG); 5467eb8f069SAndrzej Hajda if ((reg & DSIM_STOP_STATE_DAT(lanes_mask)) 5477eb8f069SAndrzej Hajda != DSIM_STOP_STATE_DAT(lanes_mask)) 5487eb8f069SAndrzej Hajda continue; 5497eb8f069SAndrzej Hajda } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK))); 5507eb8f069SAndrzej Hajda 5517eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_ESCMODE_REG); 5527eb8f069SAndrzej Hajda reg &= ~DSIM_STOP_STATE_CNT_MASK; 5537eb8f069SAndrzej Hajda reg |= DSIM_STOP_STATE_CNT(0xf); 5547eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_ESCMODE_REG); 5557eb8f069SAndrzej Hajda 5567eb8f069SAndrzej Hajda reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); 5577eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_TIMEOUT_REG); 5587eb8f069SAndrzej Hajda 5597eb8f069SAndrzej Hajda return 0; 5607eb8f069SAndrzej Hajda } 5617eb8f069SAndrzej Hajda 5627eb8f069SAndrzej Hajda static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) 5637eb8f069SAndrzej Hajda { 5647eb8f069SAndrzej Hajda struct videomode *vm = &dsi->vm; 5657eb8f069SAndrzej Hajda u32 reg; 5667eb8f069SAndrzej Hajda 5677eb8f069SAndrzej Hajda if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 5687eb8f069SAndrzej Hajda reg = DSIM_CMD_ALLOW(0xf) 5697eb8f069SAndrzej Hajda | DSIM_STABLE_VFP(vm->vfront_porch) 5707eb8f069SAndrzej Hajda | DSIM_MAIN_VBP(vm->vback_porch); 5717eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_MVPORCH_REG); 5727eb8f069SAndrzej Hajda 5737eb8f069SAndrzej Hajda reg = DSIM_MAIN_HFP(vm->hfront_porch) 5747eb8f069SAndrzej Hajda | DSIM_MAIN_HBP(vm->hback_porch); 5757eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_MHPORCH_REG); 5767eb8f069SAndrzej Hajda 5777eb8f069SAndrzej Hajda reg = DSIM_MAIN_VSA(vm->vsync_len) 5787eb8f069SAndrzej Hajda | DSIM_MAIN_HSA(vm->hsync_len); 5797eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_MSYNC_REG); 5807eb8f069SAndrzej Hajda } 5817eb8f069SAndrzej Hajda 5827eb8f069SAndrzej Hajda reg = DSIM_MAIN_HRESOL(vm->hactive) | DSIM_MAIN_VRESOL(vm->vactive); 5837eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); 5847eb8f069SAndrzej Hajda 5857eb8f069SAndrzej Hajda dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive); 5867eb8f069SAndrzej Hajda } 5877eb8f069SAndrzej Hajda 5887eb8f069SAndrzej Hajda static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable) 5897eb8f069SAndrzej Hajda { 5907eb8f069SAndrzej Hajda u32 reg; 5917eb8f069SAndrzej Hajda 5927eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_MDRESOL_REG); 5937eb8f069SAndrzej Hajda if (enable) 5947eb8f069SAndrzej Hajda reg |= DSIM_MAIN_STAND_BY; 5957eb8f069SAndrzej Hajda else 5967eb8f069SAndrzej Hajda reg &= ~DSIM_MAIN_STAND_BY; 5977eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); 5987eb8f069SAndrzej Hajda } 5997eb8f069SAndrzej Hajda 6007eb8f069SAndrzej Hajda static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) 6017eb8f069SAndrzej Hajda { 6027eb8f069SAndrzej Hajda int timeout = 2000; 6037eb8f069SAndrzej Hajda 6047eb8f069SAndrzej Hajda do { 6057eb8f069SAndrzej Hajda u32 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); 6067eb8f069SAndrzej Hajda 6077eb8f069SAndrzej Hajda if (!(reg & DSIM_SFR_HEADER_FULL)) 6087eb8f069SAndrzej Hajda return 0; 6097eb8f069SAndrzej Hajda 6107eb8f069SAndrzej Hajda if (!cond_resched()) 6117eb8f069SAndrzej Hajda usleep_range(950, 1050); 6127eb8f069SAndrzej Hajda } while (--timeout); 6137eb8f069SAndrzej Hajda 6147eb8f069SAndrzej Hajda return -ETIMEDOUT; 6157eb8f069SAndrzej Hajda } 6167eb8f069SAndrzej Hajda 6177eb8f069SAndrzej Hajda static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm) 6187eb8f069SAndrzej Hajda { 6197eb8f069SAndrzej Hajda u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); 6207eb8f069SAndrzej Hajda 6217eb8f069SAndrzej Hajda if (lpm) 6227eb8f069SAndrzej Hajda v |= DSIM_CMD_LPDT_LP; 6237eb8f069SAndrzej Hajda else 6247eb8f069SAndrzej Hajda v &= ~DSIM_CMD_LPDT_LP; 6257eb8f069SAndrzej Hajda 6267eb8f069SAndrzej Hajda writel(v, dsi->reg_base + DSIM_ESCMODE_REG); 6277eb8f069SAndrzej Hajda } 6287eb8f069SAndrzej Hajda 6297eb8f069SAndrzej Hajda static void exynos_dsi_force_bta(struct exynos_dsi *dsi) 6307eb8f069SAndrzej Hajda { 6317eb8f069SAndrzej Hajda u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); 6327eb8f069SAndrzej Hajda 6337eb8f069SAndrzej Hajda v |= DSIM_FORCE_BTA; 6347eb8f069SAndrzej Hajda writel(v, dsi->reg_base + DSIM_ESCMODE_REG); 6357eb8f069SAndrzej Hajda } 6367eb8f069SAndrzej Hajda 6377eb8f069SAndrzej Hajda static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, 6387eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer) 6397eb8f069SAndrzej Hajda { 6407eb8f069SAndrzej Hajda struct device *dev = dsi->dev; 6417eb8f069SAndrzej Hajda const u8 *payload = xfer->tx_payload + xfer->tx_done; 6427eb8f069SAndrzej Hajda u16 length = xfer->tx_len - xfer->tx_done; 6437eb8f069SAndrzej Hajda bool first = !xfer->tx_done; 6447eb8f069SAndrzej Hajda u32 reg; 6457eb8f069SAndrzej Hajda 6467eb8f069SAndrzej Hajda dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n", 6477eb8f069SAndrzej Hajda xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done); 6487eb8f069SAndrzej Hajda 6497eb8f069SAndrzej Hajda if (length > DSI_TX_FIFO_SIZE) 6507eb8f069SAndrzej Hajda length = DSI_TX_FIFO_SIZE; 6517eb8f069SAndrzej Hajda 6527eb8f069SAndrzej Hajda xfer->tx_done += length; 6537eb8f069SAndrzej Hajda 6547eb8f069SAndrzej Hajda /* Send payload */ 6557eb8f069SAndrzej Hajda while (length >= 4) { 6567eb8f069SAndrzej Hajda reg = (payload[3] << 24) | (payload[2] << 16) 6577eb8f069SAndrzej Hajda | (payload[1] << 8) | payload[0]; 6587eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); 6597eb8f069SAndrzej Hajda payload += 4; 6607eb8f069SAndrzej Hajda length -= 4; 6617eb8f069SAndrzej Hajda } 6627eb8f069SAndrzej Hajda 6637eb8f069SAndrzej Hajda reg = 0; 6647eb8f069SAndrzej Hajda switch (length) { 6657eb8f069SAndrzej Hajda case 3: 6667eb8f069SAndrzej Hajda reg |= payload[2] << 16; 6677eb8f069SAndrzej Hajda /* Fall through */ 6687eb8f069SAndrzej Hajda case 2: 6697eb8f069SAndrzej Hajda reg |= payload[1] << 8; 6707eb8f069SAndrzej Hajda /* Fall through */ 6717eb8f069SAndrzej Hajda case 1: 6727eb8f069SAndrzej Hajda reg |= payload[0]; 6737eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); 6747eb8f069SAndrzej Hajda break; 6757eb8f069SAndrzej Hajda case 0: 6767eb8f069SAndrzej Hajda /* Do nothing */ 6777eb8f069SAndrzej Hajda break; 6787eb8f069SAndrzej Hajda } 6797eb8f069SAndrzej Hajda 6807eb8f069SAndrzej Hajda /* Send packet header */ 6817eb8f069SAndrzej Hajda if (!first) 6827eb8f069SAndrzej Hajda return; 6837eb8f069SAndrzej Hajda 6847eb8f069SAndrzej Hajda reg = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->data_id; 6857eb8f069SAndrzej Hajda if (exynos_dsi_wait_for_hdr_fifo(dsi)) { 6867eb8f069SAndrzej Hajda dev_err(dev, "waiting for header FIFO timed out\n"); 6877eb8f069SAndrzej Hajda return; 6887eb8f069SAndrzej Hajda } 6897eb8f069SAndrzej Hajda 6907eb8f069SAndrzej Hajda if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM, 6917eb8f069SAndrzej Hajda dsi->state & DSIM_STATE_CMD_LPM)) { 6927eb8f069SAndrzej Hajda exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM); 6937eb8f069SAndrzej Hajda dsi->state ^= DSIM_STATE_CMD_LPM; 6947eb8f069SAndrzej Hajda } 6957eb8f069SAndrzej Hajda 6967eb8f069SAndrzej Hajda writel(reg, dsi->reg_base + DSIM_PKTHDR_REG); 6977eb8f069SAndrzej Hajda 6987eb8f069SAndrzej Hajda if (xfer->flags & MIPI_DSI_MSG_REQ_ACK) 6997eb8f069SAndrzej Hajda exynos_dsi_force_bta(dsi); 7007eb8f069SAndrzej Hajda } 7017eb8f069SAndrzej Hajda 7027eb8f069SAndrzej Hajda static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, 7037eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer) 7047eb8f069SAndrzej Hajda { 7057eb8f069SAndrzej Hajda u8 *payload = xfer->rx_payload + xfer->rx_done; 7067eb8f069SAndrzej Hajda bool first = !xfer->rx_done; 7077eb8f069SAndrzej Hajda struct device *dev = dsi->dev; 7087eb8f069SAndrzej Hajda u16 length; 7097eb8f069SAndrzej Hajda u32 reg; 7107eb8f069SAndrzej Hajda 7117eb8f069SAndrzej Hajda if (first) { 7127eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); 7137eb8f069SAndrzej Hajda 7147eb8f069SAndrzej Hajda switch (reg & 0x3f) { 7157eb8f069SAndrzej Hajda case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: 7167eb8f069SAndrzej Hajda case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: 7177eb8f069SAndrzej Hajda if (xfer->rx_len >= 2) { 7187eb8f069SAndrzej Hajda payload[1] = reg >> 16; 7197eb8f069SAndrzej Hajda ++xfer->rx_done; 7207eb8f069SAndrzej Hajda } 7217eb8f069SAndrzej Hajda /* Fall through */ 7227eb8f069SAndrzej Hajda case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: 7237eb8f069SAndrzej Hajda case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: 7247eb8f069SAndrzej Hajda payload[0] = reg >> 8; 7257eb8f069SAndrzej Hajda ++xfer->rx_done; 7267eb8f069SAndrzej Hajda xfer->rx_len = xfer->rx_done; 7277eb8f069SAndrzej Hajda xfer->result = 0; 7287eb8f069SAndrzej Hajda goto clear_fifo; 7297eb8f069SAndrzej Hajda case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: 7307eb8f069SAndrzej Hajda dev_err(dev, "DSI Error Report: 0x%04x\n", 7317eb8f069SAndrzej Hajda (reg >> 8) & 0xffff); 7327eb8f069SAndrzej Hajda xfer->result = 0; 7337eb8f069SAndrzej Hajda goto clear_fifo; 7347eb8f069SAndrzej Hajda } 7357eb8f069SAndrzej Hajda 7367eb8f069SAndrzej Hajda length = (reg >> 8) & 0xffff; 7377eb8f069SAndrzej Hajda if (length > xfer->rx_len) { 7387eb8f069SAndrzej Hajda dev_err(dev, 7397eb8f069SAndrzej Hajda "response too long (%u > %u bytes), stripping\n", 7407eb8f069SAndrzej Hajda xfer->rx_len, length); 7417eb8f069SAndrzej Hajda length = xfer->rx_len; 7427eb8f069SAndrzej Hajda } else if (length < xfer->rx_len) 7437eb8f069SAndrzej Hajda xfer->rx_len = length; 7447eb8f069SAndrzej Hajda } 7457eb8f069SAndrzej Hajda 7467eb8f069SAndrzej Hajda length = xfer->rx_len - xfer->rx_done; 7477eb8f069SAndrzej Hajda xfer->rx_done += length; 7487eb8f069SAndrzej Hajda 7497eb8f069SAndrzej Hajda /* Receive payload */ 7507eb8f069SAndrzej Hajda while (length >= 4) { 7517eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); 7527eb8f069SAndrzej Hajda payload[0] = (reg >> 0) & 0xff; 7537eb8f069SAndrzej Hajda payload[1] = (reg >> 8) & 0xff; 7547eb8f069SAndrzej Hajda payload[2] = (reg >> 16) & 0xff; 7557eb8f069SAndrzej Hajda payload[3] = (reg >> 24) & 0xff; 7567eb8f069SAndrzej Hajda payload += 4; 7577eb8f069SAndrzej Hajda length -= 4; 7587eb8f069SAndrzej Hajda } 7597eb8f069SAndrzej Hajda 7607eb8f069SAndrzej Hajda if (length) { 7617eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); 7627eb8f069SAndrzej Hajda switch (length) { 7637eb8f069SAndrzej Hajda case 3: 7647eb8f069SAndrzej Hajda payload[2] = (reg >> 16) & 0xff; 7657eb8f069SAndrzej Hajda /* Fall through */ 7667eb8f069SAndrzej Hajda case 2: 7677eb8f069SAndrzej Hajda payload[1] = (reg >> 8) & 0xff; 7687eb8f069SAndrzej Hajda /* Fall through */ 7697eb8f069SAndrzej Hajda case 1: 7707eb8f069SAndrzej Hajda payload[0] = reg & 0xff; 7717eb8f069SAndrzej Hajda } 7727eb8f069SAndrzej Hajda } 7737eb8f069SAndrzej Hajda 7747eb8f069SAndrzej Hajda if (xfer->rx_done == xfer->rx_len) 7757eb8f069SAndrzej Hajda xfer->result = 0; 7767eb8f069SAndrzej Hajda 7777eb8f069SAndrzej Hajda clear_fifo: 7787eb8f069SAndrzej Hajda length = DSI_RX_FIFO_SIZE / 4; 7797eb8f069SAndrzej Hajda do { 7807eb8f069SAndrzej Hajda reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); 7817eb8f069SAndrzej Hajda if (reg == DSI_RX_FIFO_EMPTY) 7827eb8f069SAndrzej Hajda break; 7837eb8f069SAndrzej Hajda } while (--length); 7847eb8f069SAndrzej Hajda } 7857eb8f069SAndrzej Hajda 7867eb8f069SAndrzej Hajda static void exynos_dsi_transfer_start(struct exynos_dsi *dsi) 7877eb8f069SAndrzej Hajda { 7887eb8f069SAndrzej Hajda unsigned long flags; 7897eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer; 7907eb8f069SAndrzej Hajda bool start = false; 7917eb8f069SAndrzej Hajda 7927eb8f069SAndrzej Hajda again: 7937eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 7947eb8f069SAndrzej Hajda 7957eb8f069SAndrzej Hajda if (list_empty(&dsi->transfer_list)) { 7967eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 7977eb8f069SAndrzej Hajda return; 7987eb8f069SAndrzej Hajda } 7997eb8f069SAndrzej Hajda 8007eb8f069SAndrzej Hajda xfer = list_first_entry(&dsi->transfer_list, 8017eb8f069SAndrzej Hajda struct exynos_dsi_transfer, list); 8027eb8f069SAndrzej Hajda 8037eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8047eb8f069SAndrzej Hajda 8057eb8f069SAndrzej Hajda if (xfer->tx_len && xfer->tx_done == xfer->tx_len) 8067eb8f069SAndrzej Hajda /* waiting for RX */ 8077eb8f069SAndrzej Hajda return; 8087eb8f069SAndrzej Hajda 8097eb8f069SAndrzej Hajda exynos_dsi_send_to_fifo(dsi, xfer); 8107eb8f069SAndrzej Hajda 8117eb8f069SAndrzej Hajda if (xfer->tx_len || xfer->rx_len) 8127eb8f069SAndrzej Hajda return; 8137eb8f069SAndrzej Hajda 8147eb8f069SAndrzej Hajda xfer->result = 0; 8157eb8f069SAndrzej Hajda complete(&xfer->completed); 8167eb8f069SAndrzej Hajda 8177eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 8187eb8f069SAndrzej Hajda 8197eb8f069SAndrzej Hajda list_del_init(&xfer->list); 8207eb8f069SAndrzej Hajda start = !list_empty(&dsi->transfer_list); 8217eb8f069SAndrzej Hajda 8227eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8237eb8f069SAndrzej Hajda 8247eb8f069SAndrzej Hajda if (start) 8257eb8f069SAndrzej Hajda goto again; 8267eb8f069SAndrzej Hajda } 8277eb8f069SAndrzej Hajda 8287eb8f069SAndrzej Hajda static bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi) 8297eb8f069SAndrzej Hajda { 8307eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer; 8317eb8f069SAndrzej Hajda unsigned long flags; 8327eb8f069SAndrzej Hajda bool start = true; 8337eb8f069SAndrzej Hajda 8347eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 8357eb8f069SAndrzej Hajda 8367eb8f069SAndrzej Hajda if (list_empty(&dsi->transfer_list)) { 8377eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8387eb8f069SAndrzej Hajda return false; 8397eb8f069SAndrzej Hajda } 8407eb8f069SAndrzej Hajda 8417eb8f069SAndrzej Hajda xfer = list_first_entry(&dsi->transfer_list, 8427eb8f069SAndrzej Hajda struct exynos_dsi_transfer, list); 8437eb8f069SAndrzej Hajda 8447eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8457eb8f069SAndrzej Hajda 8467eb8f069SAndrzej Hajda dev_dbg(dsi->dev, 8477eb8f069SAndrzej Hajda "> xfer %p, tx_len %u, tx_done %u, rx_len %u, rx_done %u\n", 8487eb8f069SAndrzej Hajda xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done); 8497eb8f069SAndrzej Hajda 8507eb8f069SAndrzej Hajda if (xfer->tx_done != xfer->tx_len) 8517eb8f069SAndrzej Hajda return true; 8527eb8f069SAndrzej Hajda 8537eb8f069SAndrzej Hajda if (xfer->rx_done != xfer->rx_len) 8547eb8f069SAndrzej Hajda exynos_dsi_read_from_fifo(dsi, xfer); 8557eb8f069SAndrzej Hajda 8567eb8f069SAndrzej Hajda if (xfer->rx_done != xfer->rx_len) 8577eb8f069SAndrzej Hajda return true; 8587eb8f069SAndrzej Hajda 8597eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 8607eb8f069SAndrzej Hajda 8617eb8f069SAndrzej Hajda list_del_init(&xfer->list); 8627eb8f069SAndrzej Hajda start = !list_empty(&dsi->transfer_list); 8637eb8f069SAndrzej Hajda 8647eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8657eb8f069SAndrzej Hajda 8667eb8f069SAndrzej Hajda if (!xfer->rx_len) 8677eb8f069SAndrzej Hajda xfer->result = 0; 8687eb8f069SAndrzej Hajda complete(&xfer->completed); 8697eb8f069SAndrzej Hajda 8707eb8f069SAndrzej Hajda return start; 8717eb8f069SAndrzej Hajda } 8727eb8f069SAndrzej Hajda 8737eb8f069SAndrzej Hajda static void exynos_dsi_remove_transfer(struct exynos_dsi *dsi, 8747eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer) 8757eb8f069SAndrzej Hajda { 8767eb8f069SAndrzej Hajda unsigned long flags; 8777eb8f069SAndrzej Hajda bool start; 8787eb8f069SAndrzej Hajda 8797eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 8807eb8f069SAndrzej Hajda 8817eb8f069SAndrzej Hajda if (!list_empty(&dsi->transfer_list) && 8827eb8f069SAndrzej Hajda xfer == list_first_entry(&dsi->transfer_list, 8837eb8f069SAndrzej Hajda struct exynos_dsi_transfer, list)) { 8847eb8f069SAndrzej Hajda list_del_init(&xfer->list); 8857eb8f069SAndrzej Hajda start = !list_empty(&dsi->transfer_list); 8867eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8877eb8f069SAndrzej Hajda if (start) 8887eb8f069SAndrzej Hajda exynos_dsi_transfer_start(dsi); 8897eb8f069SAndrzej Hajda return; 8907eb8f069SAndrzej Hajda } 8917eb8f069SAndrzej Hajda 8927eb8f069SAndrzej Hajda list_del_init(&xfer->list); 8937eb8f069SAndrzej Hajda 8947eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 8957eb8f069SAndrzej Hajda } 8967eb8f069SAndrzej Hajda 8977eb8f069SAndrzej Hajda static int exynos_dsi_transfer(struct exynos_dsi *dsi, 8987eb8f069SAndrzej Hajda struct exynos_dsi_transfer *xfer) 8997eb8f069SAndrzej Hajda { 9007eb8f069SAndrzej Hajda unsigned long flags; 9017eb8f069SAndrzej Hajda bool stopped; 9027eb8f069SAndrzej Hajda 9037eb8f069SAndrzej Hajda xfer->tx_done = 0; 9047eb8f069SAndrzej Hajda xfer->rx_done = 0; 9057eb8f069SAndrzej Hajda xfer->result = -ETIMEDOUT; 9067eb8f069SAndrzej Hajda init_completion(&xfer->completed); 9077eb8f069SAndrzej Hajda 9087eb8f069SAndrzej Hajda spin_lock_irqsave(&dsi->transfer_lock, flags); 9097eb8f069SAndrzej Hajda 9107eb8f069SAndrzej Hajda stopped = list_empty(&dsi->transfer_list); 9117eb8f069SAndrzej Hajda list_add_tail(&xfer->list, &dsi->transfer_list); 9127eb8f069SAndrzej Hajda 9137eb8f069SAndrzej Hajda spin_unlock_irqrestore(&dsi->transfer_lock, flags); 9147eb8f069SAndrzej Hajda 9157eb8f069SAndrzej Hajda if (stopped) 9167eb8f069SAndrzej Hajda exynos_dsi_transfer_start(dsi); 9177eb8f069SAndrzej Hajda 9187eb8f069SAndrzej Hajda wait_for_completion_timeout(&xfer->completed, 9197eb8f069SAndrzej Hajda msecs_to_jiffies(DSI_XFER_TIMEOUT_MS)); 9207eb8f069SAndrzej Hajda if (xfer->result == -ETIMEDOUT) { 9217eb8f069SAndrzej Hajda exynos_dsi_remove_transfer(dsi, xfer); 9227eb8f069SAndrzej Hajda dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 2, xfer->data, 9237eb8f069SAndrzej Hajda xfer->tx_len, xfer->tx_payload); 9247eb8f069SAndrzej Hajda return -ETIMEDOUT; 9257eb8f069SAndrzej Hajda } 9267eb8f069SAndrzej Hajda 9277eb8f069SAndrzej Hajda /* Also covers hardware timeout condition */ 9287eb8f069SAndrzej Hajda return xfer->result; 9297eb8f069SAndrzej Hajda } 9307eb8f069SAndrzej Hajda 9317eb8f069SAndrzej Hajda static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) 9327eb8f069SAndrzej Hajda { 9337eb8f069SAndrzej Hajda struct exynos_dsi *dsi = dev_id; 9347eb8f069SAndrzej Hajda u32 status; 9357eb8f069SAndrzej Hajda 9367eb8f069SAndrzej Hajda status = readl(dsi->reg_base + DSIM_INTSRC_REG); 9377eb8f069SAndrzej Hajda if (!status) { 9387eb8f069SAndrzej Hajda static unsigned long int j; 9397eb8f069SAndrzej Hajda if (printk_timed_ratelimit(&j, 500)) 9407eb8f069SAndrzej Hajda dev_warn(dsi->dev, "spurious interrupt\n"); 9417eb8f069SAndrzej Hajda return IRQ_HANDLED; 9427eb8f069SAndrzej Hajda } 9437eb8f069SAndrzej Hajda writel(status, dsi->reg_base + DSIM_INTSRC_REG); 9447eb8f069SAndrzej Hajda 9457eb8f069SAndrzej Hajda if (status & DSIM_INT_SW_RST_RELEASE) { 9467eb8f069SAndrzej Hajda u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY); 9477eb8f069SAndrzej Hajda writel(mask, dsi->reg_base + DSIM_INTMSK_REG); 9487eb8f069SAndrzej Hajda complete(&dsi->completed); 9497eb8f069SAndrzej Hajda return IRQ_HANDLED; 9507eb8f069SAndrzej Hajda } 9517eb8f069SAndrzej Hajda 9527eb8f069SAndrzej Hajda if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY))) 9537eb8f069SAndrzej Hajda return IRQ_HANDLED; 9547eb8f069SAndrzej Hajda 9557eb8f069SAndrzej Hajda if (exynos_dsi_transfer_finish(dsi)) 9567eb8f069SAndrzej Hajda exynos_dsi_transfer_start(dsi); 9577eb8f069SAndrzej Hajda 9587eb8f069SAndrzej Hajda return IRQ_HANDLED; 9597eb8f069SAndrzej Hajda } 9607eb8f069SAndrzej Hajda 961e17ddeccSYoungJun Cho static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) 962e17ddeccSYoungJun Cho { 963e17ddeccSYoungJun Cho struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; 964e17ddeccSYoungJun Cho struct drm_encoder *encoder = dsi->encoder; 965e17ddeccSYoungJun Cho 966e17ddeccSYoungJun Cho if (dsi->state & DSIM_STATE_ENABLED) 967e17ddeccSYoungJun Cho exynos_drm_crtc_te_handler(encoder->crtc); 968e17ddeccSYoungJun Cho 969e17ddeccSYoungJun Cho return IRQ_HANDLED; 970e17ddeccSYoungJun Cho } 971e17ddeccSYoungJun Cho 972e17ddeccSYoungJun Cho static void exynos_dsi_enable_irq(struct exynos_dsi *dsi) 973e17ddeccSYoungJun Cho { 974e17ddeccSYoungJun Cho enable_irq(dsi->irq); 975e17ddeccSYoungJun Cho 976e17ddeccSYoungJun Cho if (gpio_is_valid(dsi->te_gpio)) 977e17ddeccSYoungJun Cho enable_irq(gpio_to_irq(dsi->te_gpio)); 978e17ddeccSYoungJun Cho } 979e17ddeccSYoungJun Cho 980e17ddeccSYoungJun Cho static void exynos_dsi_disable_irq(struct exynos_dsi *dsi) 981e17ddeccSYoungJun Cho { 982e17ddeccSYoungJun Cho if (gpio_is_valid(dsi->te_gpio)) 983e17ddeccSYoungJun Cho disable_irq(gpio_to_irq(dsi->te_gpio)); 984e17ddeccSYoungJun Cho 985e17ddeccSYoungJun Cho disable_irq(dsi->irq); 986e17ddeccSYoungJun Cho } 987e17ddeccSYoungJun Cho 9887eb8f069SAndrzej Hajda static int exynos_dsi_init(struct exynos_dsi *dsi) 9897eb8f069SAndrzej Hajda { 9907eb8f069SAndrzej Hajda exynos_dsi_enable_clock(dsi); 9917eb8f069SAndrzej Hajda exynos_dsi_reset(dsi); 992e17ddeccSYoungJun Cho exynos_dsi_enable_irq(dsi); 9937eb8f069SAndrzej Hajda exynos_dsi_wait_for_reset(dsi); 9947eb8f069SAndrzej Hajda exynos_dsi_init_link(dsi); 9957eb8f069SAndrzej Hajda 9967eb8f069SAndrzej Hajda return 0; 9977eb8f069SAndrzej Hajda } 9987eb8f069SAndrzej Hajda 999e17ddeccSYoungJun Cho static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) 1000e17ddeccSYoungJun Cho { 1001e17ddeccSYoungJun Cho int ret; 1002e17ddeccSYoungJun Cho 1003e17ddeccSYoungJun Cho dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0); 1004e17ddeccSYoungJun Cho if (!gpio_is_valid(dsi->te_gpio)) { 1005e17ddeccSYoungJun Cho dev_err(dsi->dev, "no te-gpios specified\n"); 1006e17ddeccSYoungJun Cho ret = dsi->te_gpio; 1007e17ddeccSYoungJun Cho goto out; 1008e17ddeccSYoungJun Cho } 1009e17ddeccSYoungJun Cho 1010e17ddeccSYoungJun Cho ret = gpio_request_one(dsi->te_gpio, GPIOF_IN, "te_gpio"); 1011e17ddeccSYoungJun Cho if (ret) { 1012e17ddeccSYoungJun Cho dev_err(dsi->dev, "gpio request failed with %d\n", ret); 1013e17ddeccSYoungJun Cho goto out; 1014e17ddeccSYoungJun Cho } 1015e17ddeccSYoungJun Cho 1016e17ddeccSYoungJun Cho /* 1017e17ddeccSYoungJun Cho * This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel 1018e17ddeccSYoungJun Cho * calls drm_panel_init() first then calls mipi_dsi_attach() in probe(). 1019e17ddeccSYoungJun Cho * It means that te_gpio is invalid when exynos_dsi_enable_irq() is 1020e17ddeccSYoungJun Cho * called by drm_panel_init() before panel is attached. 1021e17ddeccSYoungJun Cho */ 1022e17ddeccSYoungJun Cho ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio), 1023e17ddeccSYoungJun Cho exynos_dsi_te_irq_handler, NULL, 1024e17ddeccSYoungJun Cho IRQF_TRIGGER_RISING, "TE", dsi); 1025e17ddeccSYoungJun Cho if (ret) { 1026e17ddeccSYoungJun Cho dev_err(dsi->dev, "request interrupt failed with %d\n", ret); 1027e17ddeccSYoungJun Cho gpio_free(dsi->te_gpio); 1028e17ddeccSYoungJun Cho goto out; 1029e17ddeccSYoungJun Cho } 1030e17ddeccSYoungJun Cho 1031e17ddeccSYoungJun Cho out: 1032e17ddeccSYoungJun Cho return ret; 1033e17ddeccSYoungJun Cho } 1034e17ddeccSYoungJun Cho 1035e17ddeccSYoungJun Cho static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) 1036e17ddeccSYoungJun Cho { 1037e17ddeccSYoungJun Cho if (gpio_is_valid(dsi->te_gpio)) { 1038e17ddeccSYoungJun Cho free_irq(gpio_to_irq(dsi->te_gpio), dsi); 1039e17ddeccSYoungJun Cho gpio_free(dsi->te_gpio); 1040e17ddeccSYoungJun Cho dsi->te_gpio = -ENOENT; 1041e17ddeccSYoungJun Cho } 1042e17ddeccSYoungJun Cho } 1043e17ddeccSYoungJun Cho 10447eb8f069SAndrzej Hajda static int exynos_dsi_host_attach(struct mipi_dsi_host *host, 10457eb8f069SAndrzej Hajda struct mipi_dsi_device *device) 10467eb8f069SAndrzej Hajda { 10477eb8f069SAndrzej Hajda struct exynos_dsi *dsi = host_to_dsi(host); 10487eb8f069SAndrzej Hajda 10497eb8f069SAndrzej Hajda dsi->lanes = device->lanes; 10507eb8f069SAndrzej Hajda dsi->format = device->format; 10517eb8f069SAndrzej Hajda dsi->mode_flags = device->mode_flags; 10527eb8f069SAndrzej Hajda dsi->panel_node = device->dev.of_node; 10537eb8f069SAndrzej Hajda 10547eb8f069SAndrzej Hajda if (dsi->connector.dev) 10557eb8f069SAndrzej Hajda drm_helper_hpd_irq_event(dsi->connector.dev); 10567eb8f069SAndrzej Hajda 1057e17ddeccSYoungJun Cho /* 1058e17ddeccSYoungJun Cho * This is a temporary solution and should be made by more generic way. 1059e17ddeccSYoungJun Cho * 1060e17ddeccSYoungJun Cho * If attached panel device is for command mode one, dsi should register 1061e17ddeccSYoungJun Cho * TE interrupt handler. 1062e17ddeccSYoungJun Cho */ 1063e17ddeccSYoungJun Cho if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { 1064e17ddeccSYoungJun Cho int ret = exynos_dsi_register_te_irq(dsi); 1065e17ddeccSYoungJun Cho 1066e17ddeccSYoungJun Cho if (ret) 1067e17ddeccSYoungJun Cho return ret; 1068e17ddeccSYoungJun Cho } 1069e17ddeccSYoungJun Cho 10707eb8f069SAndrzej Hajda return 0; 10717eb8f069SAndrzej Hajda } 10727eb8f069SAndrzej Hajda 10737eb8f069SAndrzej Hajda static int exynos_dsi_host_detach(struct mipi_dsi_host *host, 10747eb8f069SAndrzej Hajda struct mipi_dsi_device *device) 10757eb8f069SAndrzej Hajda { 10767eb8f069SAndrzej Hajda struct exynos_dsi *dsi = host_to_dsi(host); 10777eb8f069SAndrzej Hajda 1078e17ddeccSYoungJun Cho exynos_dsi_unregister_te_irq(dsi); 1079e17ddeccSYoungJun Cho 10807eb8f069SAndrzej Hajda dsi->panel_node = NULL; 10817eb8f069SAndrzej Hajda 10827eb8f069SAndrzej Hajda if (dsi->connector.dev) 10837eb8f069SAndrzej Hajda drm_helper_hpd_irq_event(dsi->connector.dev); 10847eb8f069SAndrzej Hajda 10857eb8f069SAndrzej Hajda return 0; 10867eb8f069SAndrzej Hajda } 10877eb8f069SAndrzej Hajda 10887eb8f069SAndrzej Hajda /* distinguish between short and long DSI packet types */ 10897eb8f069SAndrzej Hajda static bool exynos_dsi_is_short_dsi_type(u8 type) 10907eb8f069SAndrzej Hajda { 10917eb8f069SAndrzej Hajda return (type & 0x0f) <= 8; 10927eb8f069SAndrzej Hajda } 10937eb8f069SAndrzej Hajda 10947eb8f069SAndrzej Hajda static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, 10957eb8f069SAndrzej Hajda struct mipi_dsi_msg *msg) 10967eb8f069SAndrzej Hajda { 10977eb8f069SAndrzej Hajda struct exynos_dsi *dsi = host_to_dsi(host); 10987eb8f069SAndrzej Hajda struct exynos_dsi_transfer xfer; 10997eb8f069SAndrzej Hajda int ret; 11007eb8f069SAndrzej Hajda 11017eb8f069SAndrzej Hajda if (!(dsi->state & DSIM_STATE_INITIALIZED)) { 11027eb8f069SAndrzej Hajda ret = exynos_dsi_init(dsi); 11037eb8f069SAndrzej Hajda if (ret) 11047eb8f069SAndrzej Hajda return ret; 11057eb8f069SAndrzej Hajda dsi->state |= DSIM_STATE_INITIALIZED; 11067eb8f069SAndrzej Hajda } 11077eb8f069SAndrzej Hajda 11087eb8f069SAndrzej Hajda if (msg->tx_len == 0) 11097eb8f069SAndrzej Hajda return -EINVAL; 11107eb8f069SAndrzej Hajda 11117eb8f069SAndrzej Hajda xfer.data_id = msg->type | (msg->channel << 6); 11127eb8f069SAndrzej Hajda 11137eb8f069SAndrzej Hajda if (exynos_dsi_is_short_dsi_type(msg->type)) { 11147eb8f069SAndrzej Hajda const char *tx_buf = msg->tx_buf; 11157eb8f069SAndrzej Hajda 11167eb8f069SAndrzej Hajda if (msg->tx_len > 2) 11177eb8f069SAndrzej Hajda return -EINVAL; 11187eb8f069SAndrzej Hajda xfer.tx_len = 0; 11197eb8f069SAndrzej Hajda xfer.data[0] = tx_buf[0]; 11207eb8f069SAndrzej Hajda xfer.data[1] = (msg->tx_len == 2) ? tx_buf[1] : 0; 11217eb8f069SAndrzej Hajda } else { 11227eb8f069SAndrzej Hajda xfer.tx_len = msg->tx_len; 11237eb8f069SAndrzej Hajda xfer.data[0] = msg->tx_len & 0xff; 11247eb8f069SAndrzej Hajda xfer.data[1] = msg->tx_len >> 8; 11257eb8f069SAndrzej Hajda xfer.tx_payload = msg->tx_buf; 11267eb8f069SAndrzej Hajda } 11277eb8f069SAndrzej Hajda 11287eb8f069SAndrzej Hajda xfer.rx_len = msg->rx_len; 11297eb8f069SAndrzej Hajda xfer.rx_payload = msg->rx_buf; 11307eb8f069SAndrzej Hajda xfer.flags = msg->flags; 11317eb8f069SAndrzej Hajda 11327eb8f069SAndrzej Hajda ret = exynos_dsi_transfer(dsi, &xfer); 11337eb8f069SAndrzej Hajda return (ret < 0) ? ret : xfer.rx_done; 11347eb8f069SAndrzej Hajda } 11357eb8f069SAndrzej Hajda 11367eb8f069SAndrzej Hajda static const struct mipi_dsi_host_ops exynos_dsi_ops = { 11377eb8f069SAndrzej Hajda .attach = exynos_dsi_host_attach, 11387eb8f069SAndrzej Hajda .detach = exynos_dsi_host_detach, 11397eb8f069SAndrzej Hajda .transfer = exynos_dsi_host_transfer, 11407eb8f069SAndrzej Hajda }; 11417eb8f069SAndrzej Hajda 11427eb8f069SAndrzej Hajda static int exynos_dsi_poweron(struct exynos_dsi *dsi) 11437eb8f069SAndrzej Hajda { 11447eb8f069SAndrzej Hajda int ret; 11457eb8f069SAndrzej Hajda 11467eb8f069SAndrzej Hajda ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 11477eb8f069SAndrzej Hajda if (ret < 0) { 11487eb8f069SAndrzej Hajda dev_err(dsi->dev, "cannot enable regulators %d\n", ret); 11497eb8f069SAndrzej Hajda return ret; 11507eb8f069SAndrzej Hajda } 11517eb8f069SAndrzej Hajda 11527eb8f069SAndrzej Hajda ret = clk_prepare_enable(dsi->bus_clk); 11537eb8f069SAndrzej Hajda if (ret < 0) { 11547eb8f069SAndrzej Hajda dev_err(dsi->dev, "cannot enable bus clock %d\n", ret); 11557eb8f069SAndrzej Hajda goto err_bus_clk; 11567eb8f069SAndrzej Hajda } 11577eb8f069SAndrzej Hajda 11587eb8f069SAndrzej Hajda ret = clk_prepare_enable(dsi->pll_clk); 11597eb8f069SAndrzej Hajda if (ret < 0) { 11607eb8f069SAndrzej Hajda dev_err(dsi->dev, "cannot enable pll clock %d\n", ret); 11617eb8f069SAndrzej Hajda goto err_pll_clk; 11627eb8f069SAndrzej Hajda } 11637eb8f069SAndrzej Hajda 11647eb8f069SAndrzej Hajda ret = phy_power_on(dsi->phy); 11657eb8f069SAndrzej Hajda if (ret < 0) { 11667eb8f069SAndrzej Hajda dev_err(dsi->dev, "cannot enable phy %d\n", ret); 11677eb8f069SAndrzej Hajda goto err_phy; 11687eb8f069SAndrzej Hajda } 11697eb8f069SAndrzej Hajda 11707eb8f069SAndrzej Hajda return 0; 11717eb8f069SAndrzej Hajda 11727eb8f069SAndrzej Hajda err_phy: 11737eb8f069SAndrzej Hajda clk_disable_unprepare(dsi->pll_clk); 11747eb8f069SAndrzej Hajda err_pll_clk: 11757eb8f069SAndrzej Hajda clk_disable_unprepare(dsi->bus_clk); 11767eb8f069SAndrzej Hajda err_bus_clk: 11777eb8f069SAndrzej Hajda regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 11787eb8f069SAndrzej Hajda 11797eb8f069SAndrzej Hajda return ret; 11807eb8f069SAndrzej Hajda } 11817eb8f069SAndrzej Hajda 11827eb8f069SAndrzej Hajda static void exynos_dsi_poweroff(struct exynos_dsi *dsi) 11837eb8f069SAndrzej Hajda { 11847eb8f069SAndrzej Hajda int ret; 11857eb8f069SAndrzej Hajda 11867eb8f069SAndrzej Hajda usleep_range(10000, 20000); 11877eb8f069SAndrzej Hajda 11887eb8f069SAndrzej Hajda if (dsi->state & DSIM_STATE_INITIALIZED) { 11897eb8f069SAndrzej Hajda dsi->state &= ~DSIM_STATE_INITIALIZED; 11907eb8f069SAndrzej Hajda 11917eb8f069SAndrzej Hajda exynos_dsi_disable_clock(dsi); 11927eb8f069SAndrzej Hajda 1193e17ddeccSYoungJun Cho exynos_dsi_disable_irq(dsi); 11947eb8f069SAndrzej Hajda } 11957eb8f069SAndrzej Hajda 11967eb8f069SAndrzej Hajda dsi->state &= ~DSIM_STATE_CMD_LPM; 11977eb8f069SAndrzej Hajda 11987eb8f069SAndrzej Hajda phy_power_off(dsi->phy); 11997eb8f069SAndrzej Hajda 12007eb8f069SAndrzej Hajda clk_disable_unprepare(dsi->pll_clk); 12017eb8f069SAndrzej Hajda clk_disable_unprepare(dsi->bus_clk); 12027eb8f069SAndrzej Hajda 12037eb8f069SAndrzej Hajda ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); 12047eb8f069SAndrzej Hajda if (ret < 0) 12057eb8f069SAndrzej Hajda dev_err(dsi->dev, "cannot disable regulators %d\n", ret); 12067eb8f069SAndrzej Hajda } 12077eb8f069SAndrzej Hajda 12087eb8f069SAndrzej Hajda static int exynos_dsi_enable(struct exynos_dsi *dsi) 12097eb8f069SAndrzej Hajda { 12107eb8f069SAndrzej Hajda int ret; 12117eb8f069SAndrzej Hajda 12127eb8f069SAndrzej Hajda if (dsi->state & DSIM_STATE_ENABLED) 12137eb8f069SAndrzej Hajda return 0; 12147eb8f069SAndrzej Hajda 12157eb8f069SAndrzej Hajda ret = exynos_dsi_poweron(dsi); 12167eb8f069SAndrzej Hajda if (ret < 0) 12177eb8f069SAndrzej Hajda return ret; 12187eb8f069SAndrzej Hajda 12197eb8f069SAndrzej Hajda ret = drm_panel_enable(dsi->panel); 12207eb8f069SAndrzej Hajda if (ret < 0) { 12217eb8f069SAndrzej Hajda exynos_dsi_poweroff(dsi); 12227eb8f069SAndrzej Hajda return ret; 12237eb8f069SAndrzej Hajda } 12247eb8f069SAndrzej Hajda 12257eb8f069SAndrzej Hajda exynos_dsi_set_display_mode(dsi); 12267eb8f069SAndrzej Hajda exynos_dsi_set_display_enable(dsi, true); 12277eb8f069SAndrzej Hajda 12287eb8f069SAndrzej Hajda dsi->state |= DSIM_STATE_ENABLED; 12297eb8f069SAndrzej Hajda 12307eb8f069SAndrzej Hajda return 0; 12317eb8f069SAndrzej Hajda } 12327eb8f069SAndrzej Hajda 12337eb8f069SAndrzej Hajda static void exynos_dsi_disable(struct exynos_dsi *dsi) 12347eb8f069SAndrzej Hajda { 12357eb8f069SAndrzej Hajda if (!(dsi->state & DSIM_STATE_ENABLED)) 12367eb8f069SAndrzej Hajda return; 12377eb8f069SAndrzej Hajda 12387eb8f069SAndrzej Hajda exynos_dsi_set_display_enable(dsi, false); 12397eb8f069SAndrzej Hajda drm_panel_disable(dsi->panel); 12407eb8f069SAndrzej Hajda exynos_dsi_poweroff(dsi); 12417eb8f069SAndrzej Hajda 12427eb8f069SAndrzej Hajda dsi->state &= ~DSIM_STATE_ENABLED; 12437eb8f069SAndrzej Hajda } 12447eb8f069SAndrzej Hajda 12457eb8f069SAndrzej Hajda static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) 12467eb8f069SAndrzej Hajda { 12477eb8f069SAndrzej Hajda struct exynos_dsi *dsi = display->ctx; 12487eb8f069SAndrzej Hajda 12497eb8f069SAndrzej Hajda if (dsi->panel) { 12507eb8f069SAndrzej Hajda switch (mode) { 12517eb8f069SAndrzej Hajda case DRM_MODE_DPMS_ON: 12527eb8f069SAndrzej Hajda exynos_dsi_enable(dsi); 12537eb8f069SAndrzej Hajda break; 12547eb8f069SAndrzej Hajda case DRM_MODE_DPMS_STANDBY: 12557eb8f069SAndrzej Hajda case DRM_MODE_DPMS_SUSPEND: 12567eb8f069SAndrzej Hajda case DRM_MODE_DPMS_OFF: 12577eb8f069SAndrzej Hajda exynos_dsi_disable(dsi); 12587eb8f069SAndrzej Hajda break; 12597eb8f069SAndrzej Hajda default: 12607eb8f069SAndrzej Hajda break; 12617eb8f069SAndrzej Hajda } 12627eb8f069SAndrzej Hajda } 12637eb8f069SAndrzej Hajda } 12647eb8f069SAndrzej Hajda 12657eb8f069SAndrzej Hajda static enum drm_connector_status 12667eb8f069SAndrzej Hajda exynos_dsi_detect(struct drm_connector *connector, bool force) 12677eb8f069SAndrzej Hajda { 12687eb8f069SAndrzej Hajda struct exynos_dsi *dsi = connector_to_dsi(connector); 12697eb8f069SAndrzej Hajda 12707eb8f069SAndrzej Hajda if (!dsi->panel) { 12717eb8f069SAndrzej Hajda dsi->panel = of_drm_find_panel(dsi->panel_node); 12727eb8f069SAndrzej Hajda if (dsi->panel) 12737eb8f069SAndrzej Hajda drm_panel_attach(dsi->panel, &dsi->connector); 12747eb8f069SAndrzej Hajda } else if (!dsi->panel_node) { 12757eb8f069SAndrzej Hajda struct exynos_drm_display *display; 12767eb8f069SAndrzej Hajda 12777eb8f069SAndrzej Hajda display = platform_get_drvdata(to_platform_device(dsi->dev)); 12787eb8f069SAndrzej Hajda exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); 12797eb8f069SAndrzej Hajda drm_panel_detach(dsi->panel); 12807eb8f069SAndrzej Hajda dsi->panel = NULL; 12817eb8f069SAndrzej Hajda } 12827eb8f069SAndrzej Hajda 12837eb8f069SAndrzej Hajda if (dsi->panel) 12847eb8f069SAndrzej Hajda return connector_status_connected; 12857eb8f069SAndrzej Hajda 12867eb8f069SAndrzej Hajda return connector_status_disconnected; 12877eb8f069SAndrzej Hajda } 12887eb8f069SAndrzej Hajda 12897eb8f069SAndrzej Hajda static void exynos_dsi_connector_destroy(struct drm_connector *connector) 12907eb8f069SAndrzej Hajda { 12917eb8f069SAndrzej Hajda } 12927eb8f069SAndrzej Hajda 12937eb8f069SAndrzej Hajda static struct drm_connector_funcs exynos_dsi_connector_funcs = { 12947eb8f069SAndrzej Hajda .dpms = drm_helper_connector_dpms, 12957eb8f069SAndrzej Hajda .detect = exynos_dsi_detect, 12967eb8f069SAndrzej Hajda .fill_modes = drm_helper_probe_single_connector_modes, 12977eb8f069SAndrzej Hajda .destroy = exynos_dsi_connector_destroy, 12987eb8f069SAndrzej Hajda }; 12997eb8f069SAndrzej Hajda 13007eb8f069SAndrzej Hajda static int exynos_dsi_get_modes(struct drm_connector *connector) 13017eb8f069SAndrzej Hajda { 13027eb8f069SAndrzej Hajda struct exynos_dsi *dsi = connector_to_dsi(connector); 13037eb8f069SAndrzej Hajda 13047eb8f069SAndrzej Hajda if (dsi->panel) 13057eb8f069SAndrzej Hajda return dsi->panel->funcs->get_modes(dsi->panel); 13067eb8f069SAndrzej Hajda 13077eb8f069SAndrzej Hajda return 0; 13087eb8f069SAndrzej Hajda } 13097eb8f069SAndrzej Hajda 13107eb8f069SAndrzej Hajda static int exynos_dsi_mode_valid(struct drm_connector *connector, 13117eb8f069SAndrzej Hajda struct drm_display_mode *mode) 13127eb8f069SAndrzej Hajda { 13137eb8f069SAndrzej Hajda return MODE_OK; 13147eb8f069SAndrzej Hajda } 13157eb8f069SAndrzej Hajda 13167eb8f069SAndrzej Hajda static struct drm_encoder * 13177eb8f069SAndrzej Hajda exynos_dsi_best_encoder(struct drm_connector *connector) 13187eb8f069SAndrzej Hajda { 13197eb8f069SAndrzej Hajda struct exynos_dsi *dsi = connector_to_dsi(connector); 13207eb8f069SAndrzej Hajda 13217eb8f069SAndrzej Hajda return dsi->encoder; 13227eb8f069SAndrzej Hajda } 13237eb8f069SAndrzej Hajda 13247eb8f069SAndrzej Hajda static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { 13257eb8f069SAndrzej Hajda .get_modes = exynos_dsi_get_modes, 13267eb8f069SAndrzej Hajda .mode_valid = exynos_dsi_mode_valid, 13277eb8f069SAndrzej Hajda .best_encoder = exynos_dsi_best_encoder, 13287eb8f069SAndrzej Hajda }; 13297eb8f069SAndrzej Hajda 13307eb8f069SAndrzej Hajda static int exynos_dsi_create_connector(struct exynos_drm_display *display, 13317eb8f069SAndrzej Hajda struct drm_encoder *encoder) 13327eb8f069SAndrzej Hajda { 13337eb8f069SAndrzej Hajda struct exynos_dsi *dsi = display->ctx; 13347eb8f069SAndrzej Hajda struct drm_connector *connector = &dsi->connector; 13357eb8f069SAndrzej Hajda int ret; 13367eb8f069SAndrzej Hajda 13377eb8f069SAndrzej Hajda dsi->encoder = encoder; 13387eb8f069SAndrzej Hajda 13397eb8f069SAndrzej Hajda connector->polled = DRM_CONNECTOR_POLL_HPD; 13407eb8f069SAndrzej Hajda 13417eb8f069SAndrzej Hajda ret = drm_connector_init(encoder->dev, connector, 13427eb8f069SAndrzej Hajda &exynos_dsi_connector_funcs, 13437eb8f069SAndrzej Hajda DRM_MODE_CONNECTOR_DSI); 13447eb8f069SAndrzej Hajda if (ret) { 13457eb8f069SAndrzej Hajda DRM_ERROR("Failed to initialize connector with drm\n"); 13467eb8f069SAndrzej Hajda return ret; 13477eb8f069SAndrzej Hajda } 13487eb8f069SAndrzej Hajda 13497eb8f069SAndrzej Hajda drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); 135034ea3d38SThomas Wood drm_connector_register(connector); 13517eb8f069SAndrzej Hajda drm_mode_connector_attach_encoder(connector, encoder); 13527eb8f069SAndrzej Hajda 13537eb8f069SAndrzej Hajda return 0; 13547eb8f069SAndrzej Hajda } 13557eb8f069SAndrzej Hajda 13567eb8f069SAndrzej Hajda static void exynos_dsi_mode_set(struct exynos_drm_display *display, 13577eb8f069SAndrzej Hajda struct drm_display_mode *mode) 13587eb8f069SAndrzej Hajda { 13597eb8f069SAndrzej Hajda struct exynos_dsi *dsi = display->ctx; 13607eb8f069SAndrzej Hajda struct videomode *vm = &dsi->vm; 13617eb8f069SAndrzej Hajda 13627eb8f069SAndrzej Hajda vm->hactive = mode->hdisplay; 13637eb8f069SAndrzej Hajda vm->vactive = mode->vdisplay; 13647eb8f069SAndrzej Hajda vm->vfront_porch = mode->vsync_start - mode->vdisplay; 13657eb8f069SAndrzej Hajda vm->vback_porch = mode->vtotal - mode->vsync_end; 13667eb8f069SAndrzej Hajda vm->vsync_len = mode->vsync_end - mode->vsync_start; 13677eb8f069SAndrzej Hajda vm->hfront_porch = mode->hsync_start - mode->hdisplay; 13687eb8f069SAndrzej Hajda vm->hback_porch = mode->htotal - mode->hsync_end; 13697eb8f069SAndrzej Hajda vm->hsync_len = mode->hsync_end - mode->hsync_start; 13707eb8f069SAndrzej Hajda } 13717eb8f069SAndrzej Hajda 13727eb8f069SAndrzej Hajda static struct exynos_drm_display_ops exynos_dsi_display_ops = { 13737eb8f069SAndrzej Hajda .create_connector = exynos_dsi_create_connector, 13747eb8f069SAndrzej Hajda .mode_set = exynos_dsi_mode_set, 13757eb8f069SAndrzej Hajda .dpms = exynos_dsi_dpms 13767eb8f069SAndrzej Hajda }; 13777eb8f069SAndrzej Hajda 13787eb8f069SAndrzej Hajda static struct exynos_drm_display exynos_dsi_display = { 13797eb8f069SAndrzej Hajda .type = EXYNOS_DISPLAY_TYPE_LCD, 13807eb8f069SAndrzej Hajda .ops = &exynos_dsi_display_ops, 13817eb8f069SAndrzej Hajda }; 13827eb8f069SAndrzej Hajda 13837eb8f069SAndrzej Hajda /* of_* functions will be removed after merge of of_graph patches */ 13847eb8f069SAndrzej Hajda static struct device_node * 13857eb8f069SAndrzej Hajda of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg) 13867eb8f069SAndrzej Hajda { 13877eb8f069SAndrzej Hajda struct device_node *np; 13887eb8f069SAndrzej Hajda 13897eb8f069SAndrzej Hajda for_each_child_of_node(parent, np) { 13907eb8f069SAndrzej Hajda u32 r; 13917eb8f069SAndrzej Hajda 13927eb8f069SAndrzej Hajda if (!np->name || of_node_cmp(np->name, name)) 13937eb8f069SAndrzej Hajda continue; 13947eb8f069SAndrzej Hajda 13957eb8f069SAndrzej Hajda if (of_property_read_u32(np, "reg", &r) < 0) 13967eb8f069SAndrzej Hajda r = 0; 13977eb8f069SAndrzej Hajda 13987eb8f069SAndrzej Hajda if (reg == r) 13997eb8f069SAndrzej Hajda break; 14007eb8f069SAndrzej Hajda } 14017eb8f069SAndrzej Hajda 14027eb8f069SAndrzej Hajda return np; 14037eb8f069SAndrzej Hajda } 14047eb8f069SAndrzej Hajda 14057eb8f069SAndrzej Hajda static struct device_node *of_graph_get_port_by_reg(struct device_node *parent, 14067eb8f069SAndrzej Hajda u32 reg) 14077eb8f069SAndrzej Hajda { 14087eb8f069SAndrzej Hajda struct device_node *ports, *port; 14097eb8f069SAndrzej Hajda 14107eb8f069SAndrzej Hajda ports = of_get_child_by_name(parent, "ports"); 14117eb8f069SAndrzej Hajda if (ports) 14127eb8f069SAndrzej Hajda parent = ports; 14137eb8f069SAndrzej Hajda 14147eb8f069SAndrzej Hajda port = of_get_child_by_name_reg(parent, "port", reg); 14157eb8f069SAndrzej Hajda 14167eb8f069SAndrzej Hajda of_node_put(ports); 14177eb8f069SAndrzej Hajda 14187eb8f069SAndrzej Hajda return port; 14197eb8f069SAndrzej Hajda } 14207eb8f069SAndrzej Hajda 14217eb8f069SAndrzej Hajda static struct device_node * 14227eb8f069SAndrzej Hajda of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg) 14237eb8f069SAndrzej Hajda { 14247eb8f069SAndrzej Hajda return of_get_child_by_name_reg(port, "endpoint", reg); 14257eb8f069SAndrzej Hajda } 14267eb8f069SAndrzej Hajda 14277eb8f069SAndrzej Hajda static int exynos_dsi_of_read_u32(const struct device_node *np, 14287eb8f069SAndrzej Hajda const char *propname, u32 *out_value) 14297eb8f069SAndrzej Hajda { 14307eb8f069SAndrzej Hajda int ret = of_property_read_u32(np, propname, out_value); 14317eb8f069SAndrzej Hajda 14327eb8f069SAndrzej Hajda if (ret < 0) 14337eb8f069SAndrzej Hajda pr_err("%s: failed to get '%s' property\n", np->full_name, 14347eb8f069SAndrzej Hajda propname); 14357eb8f069SAndrzej Hajda 14367eb8f069SAndrzej Hajda return ret; 14377eb8f069SAndrzej Hajda } 14387eb8f069SAndrzej Hajda 14397eb8f069SAndrzej Hajda enum { 14407eb8f069SAndrzej Hajda DSI_PORT_IN, 14417eb8f069SAndrzej Hajda DSI_PORT_OUT 14427eb8f069SAndrzej Hajda }; 14437eb8f069SAndrzej Hajda 14447eb8f069SAndrzej Hajda static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) 14457eb8f069SAndrzej Hajda { 14467eb8f069SAndrzej Hajda struct device *dev = dsi->dev; 14477eb8f069SAndrzej Hajda struct device_node *node = dev->of_node; 14487eb8f069SAndrzej Hajda struct device_node *port, *ep; 14497eb8f069SAndrzej Hajda int ret; 14507eb8f069SAndrzej Hajda 14517eb8f069SAndrzej Hajda ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", 14527eb8f069SAndrzej Hajda &dsi->pll_clk_rate); 14537eb8f069SAndrzej Hajda if (ret < 0) 14547eb8f069SAndrzej Hajda return ret; 14557eb8f069SAndrzej Hajda 14567eb8f069SAndrzej Hajda port = of_graph_get_port_by_reg(node, DSI_PORT_OUT); 14577eb8f069SAndrzej Hajda if (!port) { 14587eb8f069SAndrzej Hajda dev_err(dev, "no output port specified\n"); 14597eb8f069SAndrzej Hajda return -EINVAL; 14607eb8f069SAndrzej Hajda } 14617eb8f069SAndrzej Hajda 14627eb8f069SAndrzej Hajda ep = of_graph_get_endpoint_by_reg(port, 0); 14637eb8f069SAndrzej Hajda of_node_put(port); 14647eb8f069SAndrzej Hajda if (!ep) { 14657eb8f069SAndrzej Hajda dev_err(dev, "no endpoint specified in output port\n"); 14667eb8f069SAndrzej Hajda return -EINVAL; 14677eb8f069SAndrzej Hajda } 14687eb8f069SAndrzej Hajda 14697eb8f069SAndrzej Hajda ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency", 14707eb8f069SAndrzej Hajda &dsi->burst_clk_rate); 14717eb8f069SAndrzej Hajda if (ret < 0) 14727eb8f069SAndrzej Hajda goto end; 14737eb8f069SAndrzej Hajda 14747eb8f069SAndrzej Hajda ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency", 14757eb8f069SAndrzej Hajda &dsi->esc_clk_rate); 14767eb8f069SAndrzej Hajda 14777eb8f069SAndrzej Hajda end: 14787eb8f069SAndrzej Hajda of_node_put(ep); 14797eb8f069SAndrzej Hajda 14807eb8f069SAndrzej Hajda return ret; 14817eb8f069SAndrzej Hajda } 14827eb8f069SAndrzej Hajda 1483f37cd5e8SInki Dae static int exynos_dsi_bind(struct device *dev, struct device *master, 1484f37cd5e8SInki Dae void *data) 1485f37cd5e8SInki Dae { 1486f37cd5e8SInki Dae struct drm_device *drm_dev = data; 1487f37cd5e8SInki Dae struct exynos_dsi *dsi; 1488f37cd5e8SInki Dae int ret; 1489f37cd5e8SInki Dae 1490f37cd5e8SInki Dae ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display); 1491f37cd5e8SInki Dae if (ret) { 1492f37cd5e8SInki Dae DRM_ERROR("Encoder create [%d] failed with %d\n", 1493f37cd5e8SInki Dae exynos_dsi_display.type, ret); 1494f37cd5e8SInki Dae return ret; 1495f37cd5e8SInki Dae } 1496f37cd5e8SInki Dae 1497f37cd5e8SInki Dae dsi = exynos_dsi_display.ctx; 1498f37cd5e8SInki Dae 1499f37cd5e8SInki Dae return mipi_dsi_host_register(&dsi->dsi_host); 1500f37cd5e8SInki Dae } 1501f37cd5e8SInki Dae 1502f37cd5e8SInki Dae static void exynos_dsi_unbind(struct device *dev, struct device *master, 1503f37cd5e8SInki Dae void *data) 1504f37cd5e8SInki Dae { 1505f37cd5e8SInki Dae struct exynos_dsi *dsi = exynos_dsi_display.ctx; 1506f37cd5e8SInki Dae struct drm_encoder *encoder = dsi->encoder; 1507f37cd5e8SInki Dae 1508f37cd5e8SInki Dae exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF); 1509f37cd5e8SInki Dae 1510f37cd5e8SInki Dae mipi_dsi_host_unregister(&dsi->dsi_host); 1511f37cd5e8SInki Dae 1512f37cd5e8SInki Dae encoder->funcs->destroy(encoder); 1513f37cd5e8SInki Dae drm_connector_cleanup(&dsi->connector); 1514f37cd5e8SInki Dae } 1515f37cd5e8SInki Dae 1516f37cd5e8SInki Dae static const struct component_ops exynos_dsi_component_ops = { 1517f37cd5e8SInki Dae .bind = exynos_dsi_bind, 1518f37cd5e8SInki Dae .unbind = exynos_dsi_unbind, 1519f37cd5e8SInki Dae }; 1520f37cd5e8SInki Dae 15217eb8f069SAndrzej Hajda static int exynos_dsi_probe(struct platform_device *pdev) 15227eb8f069SAndrzej Hajda { 15237eb8f069SAndrzej Hajda struct resource *res; 15247eb8f069SAndrzej Hajda struct exynos_dsi *dsi; 15257eb8f069SAndrzej Hajda int ret; 15267eb8f069SAndrzej Hajda 1527df5225bcSInki Dae ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, 1528df5225bcSInki Dae exynos_dsi_display.type); 1529df5225bcSInki Dae if (ret) 1530df5225bcSInki Dae return ret; 1531df5225bcSInki Dae 15327eb8f069SAndrzej Hajda dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); 15337eb8f069SAndrzej Hajda if (!dsi) { 15347eb8f069SAndrzej Hajda dev_err(&pdev->dev, "failed to allocate dsi object.\n"); 1535df5225bcSInki Dae ret = -ENOMEM; 1536df5225bcSInki Dae goto err_del_component; 15377eb8f069SAndrzej Hajda } 15387eb8f069SAndrzej Hajda 1539e17ddeccSYoungJun Cho /* To be checked as invalid one */ 1540e17ddeccSYoungJun Cho dsi->te_gpio = -ENOENT; 1541e17ddeccSYoungJun Cho 15427eb8f069SAndrzej Hajda init_completion(&dsi->completed); 15437eb8f069SAndrzej Hajda spin_lock_init(&dsi->transfer_lock); 15447eb8f069SAndrzej Hajda INIT_LIST_HEAD(&dsi->transfer_list); 15457eb8f069SAndrzej Hajda 15467eb8f069SAndrzej Hajda dsi->dsi_host.ops = &exynos_dsi_ops; 15477eb8f069SAndrzej Hajda dsi->dsi_host.dev = &pdev->dev; 15487eb8f069SAndrzej Hajda 15497eb8f069SAndrzej Hajda dsi->dev = &pdev->dev; 15507eb8f069SAndrzej Hajda 15517eb8f069SAndrzej Hajda ret = exynos_dsi_parse_dt(dsi); 15527eb8f069SAndrzej Hajda if (ret) 1553df5225bcSInki Dae goto err_del_component; 15547eb8f069SAndrzej Hajda 15557eb8f069SAndrzej Hajda dsi->supplies[0].supply = "vddcore"; 15567eb8f069SAndrzej Hajda dsi->supplies[1].supply = "vddio"; 15577eb8f069SAndrzej Hajda ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies), 15587eb8f069SAndrzej Hajda dsi->supplies); 15597eb8f069SAndrzej Hajda if (ret) { 15607eb8f069SAndrzej Hajda dev_info(&pdev->dev, "failed to get regulators: %d\n", ret); 15617eb8f069SAndrzej Hajda return -EPROBE_DEFER; 15627eb8f069SAndrzej Hajda } 15637eb8f069SAndrzej Hajda 15647eb8f069SAndrzej Hajda dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk"); 15657eb8f069SAndrzej Hajda if (IS_ERR(dsi->pll_clk)) { 15667eb8f069SAndrzej Hajda dev_info(&pdev->dev, "failed to get dsi pll input clock\n"); 1567df5225bcSInki Dae ret = PTR_ERR(dsi->pll_clk); 1568df5225bcSInki Dae goto err_del_component; 15697eb8f069SAndrzej Hajda } 15707eb8f069SAndrzej Hajda 15717eb8f069SAndrzej Hajda dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); 15727eb8f069SAndrzej Hajda if (IS_ERR(dsi->bus_clk)) { 15737eb8f069SAndrzej Hajda dev_info(&pdev->dev, "failed to get dsi bus clock\n"); 1574df5225bcSInki Dae ret = PTR_ERR(dsi->bus_clk); 1575df5225bcSInki Dae goto err_del_component; 15767eb8f069SAndrzej Hajda } 15777eb8f069SAndrzej Hajda 15787eb8f069SAndrzej Hajda res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15797eb8f069SAndrzej Hajda dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); 1580293d3f6aSJingoo Han if (IS_ERR(dsi->reg_base)) { 15817eb8f069SAndrzej Hajda dev_err(&pdev->dev, "failed to remap io region\n"); 1582df5225bcSInki Dae ret = PTR_ERR(dsi->reg_base); 1583df5225bcSInki Dae goto err_del_component; 15847eb8f069SAndrzej Hajda } 15857eb8f069SAndrzej Hajda 15867eb8f069SAndrzej Hajda dsi->phy = devm_phy_get(&pdev->dev, "dsim"); 15877eb8f069SAndrzej Hajda if (IS_ERR(dsi->phy)) { 15887eb8f069SAndrzej Hajda dev_info(&pdev->dev, "failed to get dsim phy\n"); 1589df5225bcSInki Dae ret = PTR_ERR(dsi->phy); 1590df5225bcSInki Dae goto err_del_component; 15917eb8f069SAndrzej Hajda } 15927eb8f069SAndrzej Hajda 15937eb8f069SAndrzej Hajda dsi->irq = platform_get_irq(pdev, 0); 15947eb8f069SAndrzej Hajda if (dsi->irq < 0) { 15957eb8f069SAndrzej Hajda dev_err(&pdev->dev, "failed to request dsi irq resource\n"); 1596df5225bcSInki Dae ret = dsi->irq; 1597df5225bcSInki Dae goto err_del_component; 15987eb8f069SAndrzej Hajda } 15997eb8f069SAndrzej Hajda 16007eb8f069SAndrzej Hajda irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); 16017eb8f069SAndrzej Hajda ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL, 16027eb8f069SAndrzej Hajda exynos_dsi_irq, IRQF_ONESHOT, 16037eb8f069SAndrzej Hajda dev_name(&pdev->dev), dsi); 16047eb8f069SAndrzej Hajda if (ret) { 16057eb8f069SAndrzej Hajda dev_err(&pdev->dev, "failed to request dsi irq\n"); 1606df5225bcSInki Dae goto err_del_component; 16077eb8f069SAndrzej Hajda } 16087eb8f069SAndrzej Hajda 16097eb8f069SAndrzej Hajda exynos_dsi_display.ctx = dsi; 16107eb8f069SAndrzej Hajda 16117eb8f069SAndrzej Hajda platform_set_drvdata(pdev, &exynos_dsi_display); 16127eb8f069SAndrzej Hajda 1613df5225bcSInki Dae ret = component_add(&pdev->dev, &exynos_dsi_component_ops); 1614df5225bcSInki Dae if (ret) 1615df5225bcSInki Dae goto err_del_component; 1616df5225bcSInki Dae 1617df5225bcSInki Dae return ret; 1618df5225bcSInki Dae 1619df5225bcSInki Dae err_del_component: 1620df5225bcSInki Dae exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); 1621df5225bcSInki Dae return ret; 16227eb8f069SAndrzej Hajda } 16237eb8f069SAndrzej Hajda 16247eb8f069SAndrzej Hajda static int exynos_dsi_remove(struct platform_device *pdev) 16257eb8f069SAndrzej Hajda { 1626df5225bcSInki Dae component_del(&pdev->dev, &exynos_dsi_component_ops); 1627df5225bcSInki Dae exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); 1628df5225bcSInki Dae 16297eb8f069SAndrzej Hajda return 0; 16307eb8f069SAndrzej Hajda } 16317eb8f069SAndrzej Hajda 16327eb8f069SAndrzej Hajda static struct of_device_id exynos_dsi_of_match[] = { 16337eb8f069SAndrzej Hajda { .compatible = "samsung,exynos4210-mipi-dsi" }, 16347eb8f069SAndrzej Hajda { } 16357eb8f069SAndrzej Hajda }; 16367eb8f069SAndrzej Hajda 16377eb8f069SAndrzej Hajda struct platform_driver dsi_driver = { 16387eb8f069SAndrzej Hajda .probe = exynos_dsi_probe, 16397eb8f069SAndrzej Hajda .remove = exynos_dsi_remove, 16407eb8f069SAndrzej Hajda .driver = { 16417eb8f069SAndrzej Hajda .name = "exynos-dsi", 16427eb8f069SAndrzej Hajda .owner = THIS_MODULE, 16437eb8f069SAndrzej Hajda .of_match_table = exynos_dsi_of_match, 16447eb8f069SAndrzej Hajda }, 16457eb8f069SAndrzej Hajda }; 16467eb8f069SAndrzej Hajda 16477eb8f069SAndrzej Hajda MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); 16487eb8f069SAndrzej Hajda MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 16497eb8f069SAndrzej Hajda MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); 16507eb8f069SAndrzej Hajda MODULE_LICENSE("GPL v2"); 1651