1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27eb8f069SAndrzej Hajda /*
37eb8f069SAndrzej Hajda  * Samsung SoC MIPI DSI Master driver.
47eb8f069SAndrzej Hajda  *
57eb8f069SAndrzej Hajda  * Copyright (c) 2014 Samsung Electronics Co., Ltd
67eb8f069SAndrzej Hajda  *
77eb8f069SAndrzej Hajda  * Contacts: Tomasz Figa <t.figa@samsung.com>
87eb8f069SAndrzej Hajda */
97eb8f069SAndrzej Hajda 
107eb8f069SAndrzej Hajda #include <linux/clk.h>
112bda34d7SSam Ravnborg #include <linux/delay.h>
122bda34d7SSam Ravnborg #include <linux/component.h>
13e17ddeccSYoungJun Cho #include <linux/gpio/consumer.h>
147eb8f069SAndrzej Hajda #include <linux/irq.h>
1544d214a7SJagan Teki #include <linux/media-bus-format.h>
169a320415SYoungJun Cho #include <linux/of_device.h>
17f5f3b9baSHyungwon Hwang #include <linux/of_graph.h>
187eb8f069SAndrzej Hajda #include <linux/phy/phy.h>
197eb8f069SAndrzej Hajda #include <linux/regulator/consumer.h>
202bda34d7SSam Ravnborg 
212bda34d7SSam Ravnborg #include <asm/unaligned.h>
227eb8f069SAndrzej Hajda 
237eb8f069SAndrzej Hajda #include <video/mipi_display.h>
247eb8f069SAndrzej Hajda #include <video/videomode.h>
257eb8f069SAndrzej Hajda 
262bda34d7SSam Ravnborg #include <drm/drm_atomic_helper.h>
27ee68c743SBoris Brezillon #include <drm/drm_bridge.h>
282bda34d7SSam Ravnborg #include <drm/drm_mipi_dsi.h>
29ea16c74cSJagan Teki #include <drm/drm_panel.h>
302bda34d7SSam Ravnborg #include <drm/drm_print.h>
312bda34d7SSam Ravnborg #include <drm/drm_probe_helper.h>
323e1fe32dSThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
332bda34d7SSam Ravnborg 
34e17ddeccSYoungJun Cho #include "exynos_drm_crtc.h"
357eb8f069SAndrzej Hajda #include "exynos_drm_drv.h"
367eb8f069SAndrzej Hajda 
377eb8f069SAndrzej Hajda /* returns true iff both arguments logically differs */
387eb8f069SAndrzej Hajda #define NEQV(a, b) (!(a) ^ !(b))
397eb8f069SAndrzej Hajda 
407eb8f069SAndrzej Hajda /* DSIM_STATUS */
417eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_DAT(x)		(((x) & 0xf) << 0)
427eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CLK		(1 << 8)
437eb8f069SAndrzej Hajda #define DSIM_TX_READY_HS_CLK		(1 << 10)
447eb8f069SAndrzej Hajda #define DSIM_PLL_STABLE			(1 << 31)
457eb8f069SAndrzej Hajda 
467eb8f069SAndrzej Hajda /* DSIM_SWRST */
477eb8f069SAndrzej Hajda #define DSIM_FUNCRST			(1 << 16)
487eb8f069SAndrzej Hajda #define DSIM_SWRST			(1 << 0)
497eb8f069SAndrzej Hajda 
507eb8f069SAndrzej Hajda /* DSIM_TIMEOUT */
517eb8f069SAndrzej Hajda #define DSIM_LPDR_TIMEOUT(x)		((x) << 0)
527eb8f069SAndrzej Hajda #define DSIM_BTA_TIMEOUT(x)		((x) << 16)
537eb8f069SAndrzej Hajda 
547eb8f069SAndrzej Hajda /* DSIM_CLKCTRL */
557eb8f069SAndrzej Hajda #define DSIM_ESC_PRESCALER(x)		(((x) & 0xffff) << 0)
567eb8f069SAndrzej Hajda #define DSIM_ESC_PRESCALER_MASK		(0xffff << 0)
577eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_CLK	(1 << 19)
587eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_DATA(x)	(((x) & 0xf) << 20)
597eb8f069SAndrzej Hajda #define DSIM_LANE_ESC_CLK_EN_DATA_MASK	(0xf << 20)
607eb8f069SAndrzej Hajda #define DSIM_BYTE_CLKEN			(1 << 24)
617eb8f069SAndrzej Hajda #define DSIM_BYTE_CLK_SRC(x)		(((x) & 0x3) << 25)
627eb8f069SAndrzej Hajda #define DSIM_BYTE_CLK_SRC_MASK		(0x3 << 25)
637eb8f069SAndrzej Hajda #define DSIM_PLL_BYPASS			(1 << 27)
647eb8f069SAndrzej Hajda #define DSIM_ESC_CLKEN			(1 << 28)
657eb8f069SAndrzej Hajda #define DSIM_TX_REQUEST_HSCLK		(1 << 31)
667eb8f069SAndrzej Hajda 
677eb8f069SAndrzej Hajda /* DSIM_CONFIG */
687eb8f069SAndrzej Hajda #define DSIM_LANE_EN_CLK		(1 << 0)
697eb8f069SAndrzej Hajda #define DSIM_LANE_EN(x)			(((x) & 0xf) << 1)
707eb8f069SAndrzej Hajda #define DSIM_NUM_OF_DATA_LANE(x)	(((x) & 0x3) << 5)
717eb8f069SAndrzej Hajda #define DSIM_SUB_PIX_FORMAT(x)		(((x) & 0x7) << 8)
727eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_MASK	(0x7 << 12)
737eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB888	(0x7 << 12)
747eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB666	(0x6 << 12)
757eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB666_P	(0x5 << 12)
767eb8f069SAndrzej Hajda #define DSIM_MAIN_PIX_FORMAT_RGB565	(0x4 << 12)
777eb8f069SAndrzej Hajda #define DSIM_SUB_VC			(((x) & 0x3) << 16)
787eb8f069SAndrzej Hajda #define DSIM_MAIN_VC			(((x) & 0x3) << 18)
792e337a8dSJagan Teki #define DSIM_HSA_DISABLE_MODE		(1 << 20)
802e337a8dSJagan Teki #define DSIM_HBP_DISABLE_MODE		(1 << 21)
812e337a8dSJagan Teki #define DSIM_HFP_DISABLE_MODE		(1 << 22)
822e337a8dSJagan Teki /*
832e337a8dSJagan Teki  * The i.MX 8M Mini Applications Processor Reference Manual,
842e337a8dSJagan Teki  * Rev. 3, 11/2020 Page 4091
852e337a8dSJagan Teki  * The i.MX 8M Nano Applications Processor Reference Manual,
862e337a8dSJagan Teki  * Rev. 2, 07/2022 Page 3058
872e337a8dSJagan Teki  * The i.MX 8M Plus Applications Processor Reference Manual,
882e337a8dSJagan Teki  * Rev. 1, 06/2021 Page 5436
892e337a8dSJagan Teki  * named this bit as 'HseDisableMode' but the bit definition
902e337a8dSJagan Teki  * is quite opposite like
912e337a8dSJagan Teki  * 0 = Disables transfer
922e337a8dSJagan Teki  * 1 = Enables transfer
932e337a8dSJagan Teki  * which clearly states that HSE is not a disable bit.
942e337a8dSJagan Teki  *
952e337a8dSJagan Teki  * This bit is named as per the manual even though it is not
962e337a8dSJagan Teki  * a disable bit however the driver logic for handling HSE
972e337a8dSJagan Teki  * is based on the MIPI_DSI_MODE_VIDEO_HSE flag itself.
982e337a8dSJagan Teki  */
992e337a8dSJagan Teki #define DSIM_HSE_DISABLE_MODE		(1 << 23)
1007eb8f069SAndrzej Hajda #define DSIM_AUTO_MODE			(1 << 24)
1017eb8f069SAndrzej Hajda #define DSIM_VIDEO_MODE			(1 << 25)
1027eb8f069SAndrzej Hajda #define DSIM_BURST_MODE			(1 << 26)
1037eb8f069SAndrzej Hajda #define DSIM_SYNC_INFORM		(1 << 27)
1047eb8f069SAndrzej Hajda #define DSIM_EOT_DISABLE		(1 << 28)
1057eb8f069SAndrzej Hajda #define DSIM_MFLUSH_VS			(1 << 29)
1066bdc92eeSKrzysztof Kozlowski /* This flag is valid only for exynos3250/3472/5260/5430 */
10778d3a8c6SInki Dae #define DSIM_CLKLANE_STOP		(1 << 30)
1087eb8f069SAndrzej Hajda 
1097eb8f069SAndrzej Hajda /* DSIM_ESCMODE */
1107eb8f069SAndrzej Hajda #define DSIM_TX_TRIGGER_RST		(1 << 4)
1117eb8f069SAndrzej Hajda #define DSIM_TX_LPDT_LP			(1 << 6)
1127eb8f069SAndrzej Hajda #define DSIM_CMD_LPDT_LP		(1 << 7)
1137eb8f069SAndrzej Hajda #define DSIM_FORCE_BTA			(1 << 16)
1147eb8f069SAndrzej Hajda #define DSIM_FORCE_STOP_STATE		(1 << 20)
1157eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CNT(x)		(((x) & 0x7ff) << 21)
1167eb8f069SAndrzej Hajda #define DSIM_STOP_STATE_CNT_MASK	(0x7ff << 21)
1177eb8f069SAndrzej Hajda 
1187eb8f069SAndrzej Hajda /* DSIM_MDRESOL */
1197eb8f069SAndrzej Hajda #define DSIM_MAIN_STAND_BY		(1 << 31)
120d668e8bfSHyungwon Hwang #define DSIM_MAIN_VRESOL(x, num_bits)	(((x) & ((1 << (num_bits)) - 1)) << 16)
121d668e8bfSHyungwon Hwang #define DSIM_MAIN_HRESOL(x, num_bits)	(((x) & ((1 << (num_bits)) - 1)) << 0)
1227eb8f069SAndrzej Hajda 
1237eb8f069SAndrzej Hajda /* DSIM_MVPORCH */
1247eb8f069SAndrzej Hajda #define DSIM_CMD_ALLOW(x)		((x) << 28)
1257eb8f069SAndrzej Hajda #define DSIM_STABLE_VFP(x)		((x) << 16)
1267eb8f069SAndrzej Hajda #define DSIM_MAIN_VBP(x)		((x) << 0)
1277eb8f069SAndrzej Hajda #define DSIM_CMD_ALLOW_MASK		(0xf << 28)
1287eb8f069SAndrzej Hajda #define DSIM_STABLE_VFP_MASK		(0x7ff << 16)
1297eb8f069SAndrzej Hajda #define DSIM_MAIN_VBP_MASK		(0x7ff << 0)
1307eb8f069SAndrzej Hajda 
1317eb8f069SAndrzej Hajda /* DSIM_MHPORCH */
1327eb8f069SAndrzej Hajda #define DSIM_MAIN_HFP(x)		((x) << 16)
1337eb8f069SAndrzej Hajda #define DSIM_MAIN_HBP(x)		((x) << 0)
1347eb8f069SAndrzej Hajda #define DSIM_MAIN_HFP_MASK		((0xffff) << 16)
1357eb8f069SAndrzej Hajda #define DSIM_MAIN_HBP_MASK		((0xffff) << 0)
1367eb8f069SAndrzej Hajda 
1377eb8f069SAndrzej Hajda /* DSIM_MSYNC */
1387eb8f069SAndrzej Hajda #define DSIM_MAIN_VSA(x)		((x) << 22)
1397eb8f069SAndrzej Hajda #define DSIM_MAIN_HSA(x)		((x) << 0)
1407eb8f069SAndrzej Hajda #define DSIM_MAIN_VSA_MASK		((0x3ff) << 22)
1417eb8f069SAndrzej Hajda #define DSIM_MAIN_HSA_MASK		((0xffff) << 0)
1427eb8f069SAndrzej Hajda 
1437eb8f069SAndrzej Hajda /* DSIM_SDRESOL */
1447eb8f069SAndrzej Hajda #define DSIM_SUB_STANDY(x)		((x) << 31)
1457eb8f069SAndrzej Hajda #define DSIM_SUB_VRESOL(x)		((x) << 16)
1467eb8f069SAndrzej Hajda #define DSIM_SUB_HRESOL(x)		((x) << 0)
1477eb8f069SAndrzej Hajda #define DSIM_SUB_STANDY_MASK		((0x1) << 31)
1487eb8f069SAndrzej Hajda #define DSIM_SUB_VRESOL_MASK		((0x7ff) << 16)
1497eb8f069SAndrzej Hajda #define DSIM_SUB_HRESOL_MASK		((0x7ff) << 0)
1507eb8f069SAndrzej Hajda 
1517eb8f069SAndrzej Hajda /* DSIM_INTSRC */
1527eb8f069SAndrzej Hajda #define DSIM_INT_PLL_STABLE		(1 << 31)
1537eb8f069SAndrzej Hajda #define DSIM_INT_SW_RST_RELEASE		(1 << 30)
1547eb8f069SAndrzej Hajda #define DSIM_INT_SFR_FIFO_EMPTY		(1 << 29)
155e6f988a4SHyungwon Hwang #define DSIM_INT_SFR_HDR_FIFO_EMPTY	(1 << 28)
1567eb8f069SAndrzej Hajda #define DSIM_INT_BTA			(1 << 25)
1577eb8f069SAndrzej Hajda #define DSIM_INT_FRAME_DONE		(1 << 24)
1587eb8f069SAndrzej Hajda #define DSIM_INT_RX_TIMEOUT		(1 << 21)
1597eb8f069SAndrzej Hajda #define DSIM_INT_BTA_TIMEOUT		(1 << 20)
1607eb8f069SAndrzej Hajda #define DSIM_INT_RX_DONE		(1 << 18)
1617eb8f069SAndrzej Hajda #define DSIM_INT_RX_TE			(1 << 17)
1627eb8f069SAndrzej Hajda #define DSIM_INT_RX_ACK			(1 << 16)
1637eb8f069SAndrzej Hajda #define DSIM_INT_RX_ECC_ERR		(1 << 15)
1647eb8f069SAndrzej Hajda #define DSIM_INT_RX_CRC_ERR		(1 << 14)
1657eb8f069SAndrzej Hajda 
1667eb8f069SAndrzej Hajda /* DSIM_FIFOCTRL */
1677eb8f069SAndrzej Hajda #define DSIM_RX_DATA_FULL		(1 << 25)
1687eb8f069SAndrzej Hajda #define DSIM_RX_DATA_EMPTY		(1 << 24)
1697eb8f069SAndrzej Hajda #define DSIM_SFR_HEADER_FULL		(1 << 23)
1707eb8f069SAndrzej Hajda #define DSIM_SFR_HEADER_EMPTY		(1 << 22)
1717eb8f069SAndrzej Hajda #define DSIM_SFR_PAYLOAD_FULL		(1 << 21)
1727eb8f069SAndrzej Hajda #define DSIM_SFR_PAYLOAD_EMPTY		(1 << 20)
1737eb8f069SAndrzej Hajda #define DSIM_I80_HEADER_FULL		(1 << 19)
1747eb8f069SAndrzej Hajda #define DSIM_I80_HEADER_EMPTY		(1 << 18)
1757eb8f069SAndrzej Hajda #define DSIM_I80_PAYLOAD_FULL		(1 << 17)
1767eb8f069SAndrzej Hajda #define DSIM_I80_PAYLOAD_EMPTY		(1 << 16)
1777eb8f069SAndrzej Hajda #define DSIM_SD_HEADER_FULL		(1 << 15)
1787eb8f069SAndrzej Hajda #define DSIM_SD_HEADER_EMPTY		(1 << 14)
1797eb8f069SAndrzej Hajda #define DSIM_SD_PAYLOAD_FULL		(1 << 13)
1807eb8f069SAndrzej Hajda #define DSIM_SD_PAYLOAD_EMPTY		(1 << 12)
1817eb8f069SAndrzej Hajda #define DSIM_MD_HEADER_FULL		(1 << 11)
1827eb8f069SAndrzej Hajda #define DSIM_MD_HEADER_EMPTY		(1 << 10)
1837eb8f069SAndrzej Hajda #define DSIM_MD_PAYLOAD_FULL		(1 << 9)
1847eb8f069SAndrzej Hajda #define DSIM_MD_PAYLOAD_EMPTY		(1 << 8)
1857eb8f069SAndrzej Hajda #define DSIM_RX_FIFO			(1 << 4)
1867eb8f069SAndrzej Hajda #define DSIM_SFR_FIFO			(1 << 3)
1877eb8f069SAndrzej Hajda #define DSIM_I80_FIFO			(1 << 2)
1887eb8f069SAndrzej Hajda #define DSIM_SD_FIFO			(1 << 1)
1897eb8f069SAndrzej Hajda #define DSIM_MD_FIFO			(1 << 0)
1907eb8f069SAndrzej Hajda 
1917eb8f069SAndrzej Hajda /* DSIM_PHYACCHR */
1927eb8f069SAndrzej Hajda #define DSIM_AFC_EN			(1 << 14)
1937eb8f069SAndrzej Hajda #define DSIM_AFC_CTL(x)			(((x) & 0x7) << 5)
1947eb8f069SAndrzej Hajda 
1957eb8f069SAndrzej Hajda /* DSIM_PLLCTRL */
1967eb8f069SAndrzej Hajda #define DSIM_FREQ_BAND(x)		((x) << 24)
1977eb8f069SAndrzej Hajda #define DSIM_PLL_EN			(1 << 23)
198c4f8bdadSJagan Teki #define DSIM_PLL_P(x, offset)		((x) << (offset))
1997eb8f069SAndrzej Hajda #define DSIM_PLL_M(x)			((x) << 4)
2007eb8f069SAndrzej Hajda #define DSIM_PLL_S(x)			((x) << 1)
2017eb8f069SAndrzej Hajda 
2029a320415SYoungJun Cho /* DSIM_PHYCTRL */
2039a320415SYoungJun Cho #define DSIM_PHYCTRL_ULPS_EXIT(x)	(((x) & 0x1ff) << 0)
204e6f988a4SHyungwon Hwang #define DSIM_PHYCTRL_B_DPHYCTL_VREG_LP	(1 << 30)
205e6f988a4SHyungwon Hwang #define DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP	(1 << 14)
2069a320415SYoungJun Cho 
2079a320415SYoungJun Cho /* DSIM_PHYTIMING */
2089a320415SYoungJun Cho #define DSIM_PHYTIMING_LPX(x)		((x) << 8)
2099a320415SYoungJun Cho #define DSIM_PHYTIMING_HS_EXIT(x)	((x) << 0)
2109a320415SYoungJun Cho 
2119a320415SYoungJun Cho /* DSIM_PHYTIMING1 */
2129a320415SYoungJun Cho #define DSIM_PHYTIMING1_CLK_PREPARE(x)	((x) << 24)
2139a320415SYoungJun Cho #define DSIM_PHYTIMING1_CLK_ZERO(x)	((x) << 16)
2149a320415SYoungJun Cho #define DSIM_PHYTIMING1_CLK_POST(x)	((x) << 8)
2159a320415SYoungJun Cho #define DSIM_PHYTIMING1_CLK_TRAIL(x)	((x) << 0)
2169a320415SYoungJun Cho 
2179a320415SYoungJun Cho /* DSIM_PHYTIMING2 */
2189a320415SYoungJun Cho #define DSIM_PHYTIMING2_HS_PREPARE(x)	((x) << 16)
2199a320415SYoungJun Cho #define DSIM_PHYTIMING2_HS_ZERO(x)	((x) << 8)
2209a320415SYoungJun Cho #define DSIM_PHYTIMING2_HS_TRAIL(x)	((x) << 0)
2219a320415SYoungJun Cho 
2227eb8f069SAndrzej Hajda #define DSI_MAX_BUS_WIDTH		4
2237eb8f069SAndrzej Hajda #define DSI_NUM_VIRTUAL_CHANNELS	4
2247eb8f069SAndrzej Hajda #define DSI_TX_FIFO_SIZE		2048
2257eb8f069SAndrzej Hajda #define DSI_RX_FIFO_SIZE		256
2267eb8f069SAndrzej Hajda #define DSI_XFER_TIMEOUT_MS		100
2277eb8f069SAndrzej Hajda #define DSI_RX_FIFO_EMPTY		0x30800002
2287eb8f069SAndrzej Hajda 
22926269af9SHyungwon Hwang #define OLD_SCLK_MIPI_CLK_NAME "pll_clk"
23026269af9SHyungwon Hwang 
231a046e7bfSBernard Zhao static const char *const clk_names[5] = { "bus_clk", "sclk_mipi",
232e6f988a4SHyungwon Hwang 	"phyclk_mipidphy0_bitclkdiv8", "phyclk_mipidphy0_rxclkesc0",
233e6f988a4SHyungwon Hwang 	"sclk_rgb_vclk_to_dsim0" };
2340ff03fd1SHyungwon Hwang 
2357eb8f069SAndrzej Hajda enum exynos_dsi_transfer_type {
2367eb8f069SAndrzej Hajda 	EXYNOS_DSI_TX,
2377eb8f069SAndrzej Hajda 	EXYNOS_DSI_RX,
2387eb8f069SAndrzej Hajda };
2397eb8f069SAndrzej Hajda 
2407eb8f069SAndrzej Hajda struct exynos_dsi_transfer {
2417eb8f069SAndrzej Hajda 	struct list_head list;
2427eb8f069SAndrzej Hajda 	struct completion completed;
2437eb8f069SAndrzej Hajda 	int result;
2446c81e96dSAndrzej Hajda 	struct mipi_dsi_packet packet;
2457eb8f069SAndrzej Hajda 	u16 flags;
2467eb8f069SAndrzej Hajda 	u16 tx_done;
2477eb8f069SAndrzej Hajda 
2487eb8f069SAndrzej Hajda 	u8 *rx_payload;
2497eb8f069SAndrzej Hajda 	u16 rx_len;
2507eb8f069SAndrzej Hajda 	u16 rx_done;
2517eb8f069SAndrzej Hajda };
2527eb8f069SAndrzej Hajda 
2537eb8f069SAndrzej Hajda #define DSIM_STATE_ENABLED		BIT(0)
2547eb8f069SAndrzej Hajda #define DSIM_STATE_INITIALIZED		BIT(1)
2557eb8f069SAndrzej Hajda #define DSIM_STATE_CMD_LPM		BIT(2)
2560e480f6fSHyungwon Hwang #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
2577eb8f069SAndrzej Hajda 
258bb57453dSMarek Szyprowski #define exynos_dsi_hw_is_exynos(hw) \
259bb57453dSMarek Szyprowski 	((hw) >= DSIM_TYPE_EXYNOS3250 && (hw) <= DSIM_TYPE_EXYNOS5433)
260bb57453dSMarek Szyprowski 
2617e9f0d32SJagan Teki enum exynos_dsi_type {
2627e9f0d32SJagan Teki 	DSIM_TYPE_EXYNOS3250,
2637e9f0d32SJagan Teki 	DSIM_TYPE_EXYNOS4210,
2647e9f0d32SJagan Teki 	DSIM_TYPE_EXYNOS5410,
2657e9f0d32SJagan Teki 	DSIM_TYPE_EXYNOS5422,
2667e9f0d32SJagan Teki 	DSIM_TYPE_EXYNOS5433,
26788576e23SJagan Teki 	DSIM_TYPE_IMX8MM,
2687e9f0d32SJagan Teki 	DSIM_TYPE_COUNT,
2697e9f0d32SJagan Teki };
2707e9f0d32SJagan Teki 
2719a320415SYoungJun Cho struct exynos_dsi_driver_data {
272b115361eSAndrzej Hajda 	const unsigned int *reg_ofs;
2739a320415SYoungJun Cho 	unsigned int plltmr_reg;
2749a320415SYoungJun Cho 	unsigned int has_freqband:1;
27578d3a8c6SInki Dae 	unsigned int has_clklane_stop:1;
276d668e8bfSHyungwon Hwang 	unsigned int num_clks;
277d668e8bfSHyungwon Hwang 	unsigned int max_freq;
278d668e8bfSHyungwon Hwang 	unsigned int wait_for_reset;
279d668e8bfSHyungwon Hwang 	unsigned int num_bits_resol;
280c4f8bdadSJagan Teki 	unsigned int pll_p_offset;
281b115361eSAndrzej Hajda 	const unsigned int *reg_values;
2829a320415SYoungJun Cho };
2839a320415SYoungJun Cho 
2847e9f0d32SJagan Teki struct exynos_dsi_plat_data {
2857e9f0d32SJagan Teki 	enum exynos_dsi_type hw_type;
286*70e360f9SJagan Teki 	const struct exynos_dsim_host_ops *host_ops;
2877e9f0d32SJagan Teki };
2887e9f0d32SJagan Teki 
2897eb8f069SAndrzej Hajda struct exynos_dsi {
2907eb8f069SAndrzej Hajda 	struct mipi_dsi_host dsi_host;
291f9bfd326SJagan Teki 	struct drm_bridge bridge;
2926afb7721SMaciej Purski 	struct drm_bridge *out_bridge;
2937eb8f069SAndrzej Hajda 	struct device *dev;
294aee039e6SJagan Teki 	struct drm_display_mode mode;
2957eb8f069SAndrzej Hajda 
2967eb8f069SAndrzej Hajda 	void __iomem *reg_base;
2977eb8f069SAndrzej Hajda 	struct phy *phy;
2980ff03fd1SHyungwon Hwang 	struct clk **clks;
2997eb8f069SAndrzej Hajda 	struct regulator_bulk_data supplies[2];
3007eb8f069SAndrzej Hajda 	int irq;
301ee6c8b5aSMaíra Canal 	struct gpio_desc *te_gpio;
3027eb8f069SAndrzej Hajda 
3037eb8f069SAndrzej Hajda 	u32 pll_clk_rate;
3047eb8f069SAndrzej Hajda 	u32 burst_clk_rate;
3057eb8f069SAndrzej Hajda 	u32 esc_clk_rate;
3067eb8f069SAndrzej Hajda 	u32 lanes;
3077eb8f069SAndrzej Hajda 	u32 mode_flags;
3087eb8f069SAndrzej Hajda 	u32 format;
3097eb8f069SAndrzej Hajda 
3107eb8f069SAndrzej Hajda 	int state;
3117eb8f069SAndrzej Hajda 	struct drm_property *brightness;
3127eb8f069SAndrzej Hajda 	struct completion completed;
3137eb8f069SAndrzej Hajda 
3147eb8f069SAndrzej Hajda 	spinlock_t transfer_lock; /* protects transfer_list */
3157eb8f069SAndrzej Hajda 	struct list_head transfer_list;
3169a320415SYoungJun Cho 
3172154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data;
3187e9f0d32SJagan Teki 	const struct exynos_dsi_plat_data *plat_data;
319*70e360f9SJagan Teki 
320*70e360f9SJagan Teki 	void *priv;
321*70e360f9SJagan Teki };
322*70e360f9SJagan Teki 
323*70e360f9SJagan Teki struct exynos_dsim_host_ops {
324*70e360f9SJagan Teki 	int (*register_host)(struct exynos_dsi *dsim);
325*70e360f9SJagan Teki 	void (*unregister_host)(struct exynos_dsi *dsim);
326*70e360f9SJagan Teki 	int (*attach)(struct exynos_dsi *dsim, struct mipi_dsi_device *device);
327*70e360f9SJagan Teki 	void (*detach)(struct exynos_dsi *dsim, struct mipi_dsi_device *device);
328*70e360f9SJagan Teki };
329*70e360f9SJagan Teki 
330*70e360f9SJagan Teki struct exynos_dsi_enc {
331*70e360f9SJagan Teki 	struct drm_encoder encoder;
3327eb8f069SAndrzej Hajda };
3337eb8f069SAndrzej Hajda 
3347eb8f069SAndrzej Hajda #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
3357eb8f069SAndrzej Hajda 
336f9bfd326SJagan Teki static inline struct exynos_dsi *bridge_to_dsi(struct drm_bridge *b)
3375cd5db80SAndrzej Hajda {
338f9bfd326SJagan Teki 	return container_of(b, struct exynos_dsi, bridge);
3395cd5db80SAndrzej Hajda }
3405cd5db80SAndrzej Hajda 
341d668e8bfSHyungwon Hwang enum reg_idx {
342d668e8bfSHyungwon Hwang 	DSIM_STATUS_REG,	/* Status register */
343d668e8bfSHyungwon Hwang 	DSIM_SWRST_REG,		/* Software reset register */
344d668e8bfSHyungwon Hwang 	DSIM_CLKCTRL_REG,	/* Clock control register */
345d668e8bfSHyungwon Hwang 	DSIM_TIMEOUT_REG,	/* Time out register */
346d668e8bfSHyungwon Hwang 	DSIM_CONFIG_REG,	/* Configuration register */
347d668e8bfSHyungwon Hwang 	DSIM_ESCMODE_REG,	/* Escape mode register */
348d668e8bfSHyungwon Hwang 	DSIM_MDRESOL_REG,
349d668e8bfSHyungwon Hwang 	DSIM_MVPORCH_REG,	/* Main display Vporch register */
350d668e8bfSHyungwon Hwang 	DSIM_MHPORCH_REG,	/* Main display Hporch register */
351d668e8bfSHyungwon Hwang 	DSIM_MSYNC_REG,		/* Main display sync area register */
352d668e8bfSHyungwon Hwang 	DSIM_INTSRC_REG,	/* Interrupt source register */
353d668e8bfSHyungwon Hwang 	DSIM_INTMSK_REG,	/* Interrupt mask register */
354d668e8bfSHyungwon Hwang 	DSIM_PKTHDR_REG,	/* Packet Header FIFO register */
355d668e8bfSHyungwon Hwang 	DSIM_PAYLOAD_REG,	/* Payload FIFO register */
356d668e8bfSHyungwon Hwang 	DSIM_RXFIFO_REG,	/* Read FIFO register */
357d668e8bfSHyungwon Hwang 	DSIM_FIFOCTRL_REG,	/* FIFO status and control register */
358d668e8bfSHyungwon Hwang 	DSIM_PLLCTRL_REG,	/* PLL control register */
359d668e8bfSHyungwon Hwang 	DSIM_PHYCTRL_REG,
360d668e8bfSHyungwon Hwang 	DSIM_PHYTIMING_REG,
361d668e8bfSHyungwon Hwang 	DSIM_PHYTIMING1_REG,
362d668e8bfSHyungwon Hwang 	DSIM_PHYTIMING2_REG,
363d668e8bfSHyungwon Hwang 	NUM_REGS
364d668e8bfSHyungwon Hwang };
365bb32e408SAndrzej Hajda 
366bb32e408SAndrzej Hajda static inline void exynos_dsi_write(struct exynos_dsi *dsi, enum reg_idx idx,
367bb32e408SAndrzej Hajda 				    u32 val)
368bb32e408SAndrzej Hajda {
3696c81e96dSAndrzej Hajda 
370bb32e408SAndrzej Hajda 	writel(val, dsi->reg_base + dsi->driver_data->reg_ofs[idx]);
371bb32e408SAndrzej Hajda }
372bb32e408SAndrzej Hajda 
373bb32e408SAndrzej Hajda static inline u32 exynos_dsi_read(struct exynos_dsi *dsi, enum reg_idx idx)
374bb32e408SAndrzej Hajda {
375bb32e408SAndrzej Hajda 	return readl(dsi->reg_base + dsi->driver_data->reg_ofs[idx]);
376bb32e408SAndrzej Hajda }
377bb32e408SAndrzej Hajda 
378b115361eSAndrzej Hajda static const unsigned int exynos_reg_ofs[] = {
379d668e8bfSHyungwon Hwang 	[DSIM_STATUS_REG] =  0x00,
380d668e8bfSHyungwon Hwang 	[DSIM_SWRST_REG] =  0x04,
381d668e8bfSHyungwon Hwang 	[DSIM_CLKCTRL_REG] =  0x08,
382d668e8bfSHyungwon Hwang 	[DSIM_TIMEOUT_REG] =  0x0c,
383d668e8bfSHyungwon Hwang 	[DSIM_CONFIG_REG] =  0x10,
384d668e8bfSHyungwon Hwang 	[DSIM_ESCMODE_REG] =  0x14,
385d668e8bfSHyungwon Hwang 	[DSIM_MDRESOL_REG] =  0x18,
386d668e8bfSHyungwon Hwang 	[DSIM_MVPORCH_REG] =  0x1c,
387d668e8bfSHyungwon Hwang 	[DSIM_MHPORCH_REG] =  0x20,
388d668e8bfSHyungwon Hwang 	[DSIM_MSYNC_REG] =  0x24,
389d668e8bfSHyungwon Hwang 	[DSIM_INTSRC_REG] =  0x2c,
390d668e8bfSHyungwon Hwang 	[DSIM_INTMSK_REG] =  0x30,
391d668e8bfSHyungwon Hwang 	[DSIM_PKTHDR_REG] =  0x34,
392d668e8bfSHyungwon Hwang 	[DSIM_PAYLOAD_REG] =  0x38,
393d668e8bfSHyungwon Hwang 	[DSIM_RXFIFO_REG] =  0x3c,
394d668e8bfSHyungwon Hwang 	[DSIM_FIFOCTRL_REG] =  0x44,
395d668e8bfSHyungwon Hwang 	[DSIM_PLLCTRL_REG] =  0x4c,
396d668e8bfSHyungwon Hwang 	[DSIM_PHYCTRL_REG] =  0x5c,
397d668e8bfSHyungwon Hwang 	[DSIM_PHYTIMING_REG] =  0x64,
398d668e8bfSHyungwon Hwang 	[DSIM_PHYTIMING1_REG] =  0x68,
399d668e8bfSHyungwon Hwang 	[DSIM_PHYTIMING2_REG] =  0x6c,
400d668e8bfSHyungwon Hwang };
401d668e8bfSHyungwon Hwang 
402b115361eSAndrzej Hajda static const unsigned int exynos5433_reg_ofs[] = {
403e6f988a4SHyungwon Hwang 	[DSIM_STATUS_REG] = 0x04,
404e6f988a4SHyungwon Hwang 	[DSIM_SWRST_REG] = 0x0C,
405e6f988a4SHyungwon Hwang 	[DSIM_CLKCTRL_REG] = 0x10,
406e6f988a4SHyungwon Hwang 	[DSIM_TIMEOUT_REG] = 0x14,
407e6f988a4SHyungwon Hwang 	[DSIM_CONFIG_REG] = 0x18,
408e6f988a4SHyungwon Hwang 	[DSIM_ESCMODE_REG] = 0x1C,
409e6f988a4SHyungwon Hwang 	[DSIM_MDRESOL_REG] = 0x20,
410e6f988a4SHyungwon Hwang 	[DSIM_MVPORCH_REG] = 0x24,
411e6f988a4SHyungwon Hwang 	[DSIM_MHPORCH_REG] = 0x28,
412e6f988a4SHyungwon Hwang 	[DSIM_MSYNC_REG] = 0x2C,
413e6f988a4SHyungwon Hwang 	[DSIM_INTSRC_REG] = 0x34,
414e6f988a4SHyungwon Hwang 	[DSIM_INTMSK_REG] = 0x38,
415e6f988a4SHyungwon Hwang 	[DSIM_PKTHDR_REG] = 0x3C,
416e6f988a4SHyungwon Hwang 	[DSIM_PAYLOAD_REG] = 0x40,
417e6f988a4SHyungwon Hwang 	[DSIM_RXFIFO_REG] = 0x44,
418e6f988a4SHyungwon Hwang 	[DSIM_FIFOCTRL_REG] = 0x4C,
419e6f988a4SHyungwon Hwang 	[DSIM_PLLCTRL_REG] = 0x94,
420e6f988a4SHyungwon Hwang 	[DSIM_PHYCTRL_REG] = 0xA4,
421e6f988a4SHyungwon Hwang 	[DSIM_PHYTIMING_REG] = 0xB4,
422e6f988a4SHyungwon Hwang 	[DSIM_PHYTIMING1_REG] = 0xB8,
423e6f988a4SHyungwon Hwang 	[DSIM_PHYTIMING2_REG] = 0xBC,
424e6f988a4SHyungwon Hwang };
425e6f988a4SHyungwon Hwang 
426d668e8bfSHyungwon Hwang enum reg_value_idx {
427d668e8bfSHyungwon Hwang 	RESET_TYPE,
428d668e8bfSHyungwon Hwang 	PLL_TIMER,
429d668e8bfSHyungwon Hwang 	STOP_STATE_CNT,
430d668e8bfSHyungwon Hwang 	PHYCTRL_ULPS_EXIT,
431d668e8bfSHyungwon Hwang 	PHYCTRL_VREG_LP,
432d668e8bfSHyungwon Hwang 	PHYCTRL_SLEW_UP,
433d668e8bfSHyungwon Hwang 	PHYTIMING_LPX,
434d668e8bfSHyungwon Hwang 	PHYTIMING_HS_EXIT,
435d668e8bfSHyungwon Hwang 	PHYTIMING_CLK_PREPARE,
436d668e8bfSHyungwon Hwang 	PHYTIMING_CLK_ZERO,
437d668e8bfSHyungwon Hwang 	PHYTIMING_CLK_POST,
438d668e8bfSHyungwon Hwang 	PHYTIMING_CLK_TRAIL,
439d668e8bfSHyungwon Hwang 	PHYTIMING_HS_PREPARE,
440d668e8bfSHyungwon Hwang 	PHYTIMING_HS_ZERO,
441d668e8bfSHyungwon Hwang 	PHYTIMING_HS_TRAIL
442d668e8bfSHyungwon Hwang };
443d668e8bfSHyungwon Hwang 
444b115361eSAndrzej Hajda static const unsigned int reg_values[] = {
445d668e8bfSHyungwon Hwang 	[RESET_TYPE] = DSIM_SWRST,
446d668e8bfSHyungwon Hwang 	[PLL_TIMER] = 500,
447d668e8bfSHyungwon Hwang 	[STOP_STATE_CNT] = 0xf,
448d668e8bfSHyungwon Hwang 	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x0af),
449d668e8bfSHyungwon Hwang 	[PHYCTRL_VREG_LP] = 0,
450d668e8bfSHyungwon Hwang 	[PHYCTRL_SLEW_UP] = 0,
451d668e8bfSHyungwon Hwang 	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06),
452d668e8bfSHyungwon Hwang 	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0b),
453d668e8bfSHyungwon Hwang 	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x07),
454d668e8bfSHyungwon Hwang 	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x27),
455d668e8bfSHyungwon Hwang 	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0d),
456d668e8bfSHyungwon Hwang 	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x08),
457d668e8bfSHyungwon Hwang 	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x09),
458d668e8bfSHyungwon Hwang 	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x0d),
459d668e8bfSHyungwon Hwang 	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0b),
460d668e8bfSHyungwon Hwang };
461d668e8bfSHyungwon Hwang 
462b115361eSAndrzej Hajda static const unsigned int exynos5422_reg_values[] = {
463fdc2e108SChanho Park 	[RESET_TYPE] = DSIM_SWRST,
464fdc2e108SChanho Park 	[PLL_TIMER] = 500,
465fdc2e108SChanho Park 	[STOP_STATE_CNT] = 0xf,
466fdc2e108SChanho Park 	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf),
467fdc2e108SChanho Park 	[PHYCTRL_VREG_LP] = 0,
468fdc2e108SChanho Park 	[PHYCTRL_SLEW_UP] = 0,
469fdc2e108SChanho Park 	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x08),
470fdc2e108SChanho Park 	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0d),
471fdc2e108SChanho Park 	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09),
472fdc2e108SChanho Park 	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x30),
473fdc2e108SChanho Park 	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e),
474fdc2e108SChanho Park 	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x0a),
475fdc2e108SChanho Park 	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0c),
476fdc2e108SChanho Park 	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x11),
477fdc2e108SChanho Park 	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0d),
478fdc2e108SChanho Park };
479fdc2e108SChanho Park 
480b115361eSAndrzej Hajda static const unsigned int exynos5433_reg_values[] = {
481e6f988a4SHyungwon Hwang 	[RESET_TYPE] = DSIM_FUNCRST,
482e6f988a4SHyungwon Hwang 	[PLL_TIMER] = 22200,
483e6f988a4SHyungwon Hwang 	[STOP_STATE_CNT] = 0xa,
484e6f988a4SHyungwon Hwang 	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x190),
485e6f988a4SHyungwon Hwang 	[PHYCTRL_VREG_LP] = DSIM_PHYCTRL_B_DPHYCTL_VREG_LP,
486e6f988a4SHyungwon Hwang 	[PHYCTRL_SLEW_UP] = DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP,
487e6f988a4SHyungwon Hwang 	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x07),
488e6f988a4SHyungwon Hwang 	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0c),
489e6f988a4SHyungwon Hwang 	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09),
490e6f988a4SHyungwon Hwang 	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x2d),
491e6f988a4SHyungwon Hwang 	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e),
492e6f988a4SHyungwon Hwang 	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x09),
493e6f988a4SHyungwon Hwang 	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0b),
494e6f988a4SHyungwon Hwang 	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x10),
495e6f988a4SHyungwon Hwang 	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c),
496e6f988a4SHyungwon Hwang };
497e6f988a4SHyungwon Hwang 
498b115361eSAndrzej Hajda static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
499d668e8bfSHyungwon Hwang 	.reg_ofs = exynos_reg_ofs,
500473462a1SInki Dae 	.plltmr_reg = 0x50,
501473462a1SInki Dae 	.has_freqband = 1,
502473462a1SInki Dae 	.has_clklane_stop = 1,
503d668e8bfSHyungwon Hwang 	.num_clks = 2,
504d668e8bfSHyungwon Hwang 	.max_freq = 1000,
505d668e8bfSHyungwon Hwang 	.wait_for_reset = 1,
506d668e8bfSHyungwon Hwang 	.num_bits_resol = 11,
507c4f8bdadSJagan Teki 	.pll_p_offset = 13,
508d668e8bfSHyungwon Hwang 	.reg_values = reg_values,
509473462a1SInki Dae };
510473462a1SInki Dae 
511b115361eSAndrzej Hajda static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
512d668e8bfSHyungwon Hwang 	.reg_ofs = exynos_reg_ofs,
5139a320415SYoungJun Cho 	.plltmr_reg = 0x50,
5149a320415SYoungJun Cho 	.has_freqband = 1,
51578d3a8c6SInki Dae 	.has_clklane_stop = 1,
516d668e8bfSHyungwon Hwang 	.num_clks = 2,
517d668e8bfSHyungwon Hwang 	.max_freq = 1000,
518d668e8bfSHyungwon Hwang 	.wait_for_reset = 1,
519d668e8bfSHyungwon Hwang 	.num_bits_resol = 11,
520c4f8bdadSJagan Teki 	.pll_p_offset = 13,
521d668e8bfSHyungwon Hwang 	.reg_values = reg_values,
5229a320415SYoungJun Cho };
5239a320415SYoungJun Cho 
524b115361eSAndrzej Hajda static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
525d668e8bfSHyungwon Hwang 	.reg_ofs = exynos_reg_ofs,
5269a320415SYoungJun Cho 	.plltmr_reg = 0x58,
527d668e8bfSHyungwon Hwang 	.num_clks = 2,
528d668e8bfSHyungwon Hwang 	.max_freq = 1000,
529d668e8bfSHyungwon Hwang 	.wait_for_reset = 1,
530d668e8bfSHyungwon Hwang 	.num_bits_resol = 11,
531c4f8bdadSJagan Teki 	.pll_p_offset = 13,
532d668e8bfSHyungwon Hwang 	.reg_values = reg_values,
5339a320415SYoungJun Cho };
5349a320415SYoungJun Cho 
535b115361eSAndrzej Hajda static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
536e6f988a4SHyungwon Hwang 	.reg_ofs = exynos5433_reg_ofs,
537e6f988a4SHyungwon Hwang 	.plltmr_reg = 0xa0,
538e6f988a4SHyungwon Hwang 	.has_clklane_stop = 1,
539e6f988a4SHyungwon Hwang 	.num_clks = 5,
540e6f988a4SHyungwon Hwang 	.max_freq = 1500,
541e6f988a4SHyungwon Hwang 	.wait_for_reset = 0,
542e6f988a4SHyungwon Hwang 	.num_bits_resol = 12,
543c4f8bdadSJagan Teki 	.pll_p_offset = 13,
544e6f988a4SHyungwon Hwang 	.reg_values = exynos5433_reg_values,
545e6f988a4SHyungwon Hwang };
546e6f988a4SHyungwon Hwang 
547b115361eSAndrzej Hajda static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
548fdc2e108SChanho Park 	.reg_ofs = exynos5433_reg_ofs,
549fdc2e108SChanho Park 	.plltmr_reg = 0xa0,
550fdc2e108SChanho Park 	.has_clklane_stop = 1,
551fdc2e108SChanho Park 	.num_clks = 2,
552fdc2e108SChanho Park 	.max_freq = 1500,
553fdc2e108SChanho Park 	.wait_for_reset = 1,
554fdc2e108SChanho Park 	.num_bits_resol = 12,
555c4f8bdadSJagan Teki 	.pll_p_offset = 13,
556fdc2e108SChanho Park 	.reg_values = exynos5422_reg_values,
557fdc2e108SChanho Park };
558fdc2e108SChanho Park 
5597e9f0d32SJagan Teki static const struct exynos_dsi_driver_data *
5607e9f0d32SJagan Teki exynos_dsi_types[DSIM_TYPE_COUNT] = {
5617e9f0d32SJagan Teki 	[DSIM_TYPE_EXYNOS3250] = &exynos3_dsi_driver_data,
5627e9f0d32SJagan Teki 	[DSIM_TYPE_EXYNOS4210] = &exynos4_dsi_driver_data,
5637e9f0d32SJagan Teki 	[DSIM_TYPE_EXYNOS5410] = &exynos5_dsi_driver_data,
5647e9f0d32SJagan Teki 	[DSIM_TYPE_EXYNOS5422] = &exynos5422_dsi_driver_data,
5657e9f0d32SJagan Teki 	[DSIM_TYPE_EXYNOS5433] = &exynos5433_dsi_driver_data,
5669a320415SYoungJun Cho };
5679a320415SYoungJun Cho 
5687eb8f069SAndrzej Hajda static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
5697eb8f069SAndrzej Hajda {
5707eb8f069SAndrzej Hajda 	if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
5717eb8f069SAndrzej Hajda 		return;
5727eb8f069SAndrzej Hajda 
5737eb8f069SAndrzej Hajda 	dev_err(dsi->dev, "timeout waiting for reset\n");
5747eb8f069SAndrzej Hajda }
5757eb8f069SAndrzej Hajda 
5767eb8f069SAndrzej Hajda static void exynos_dsi_reset(struct exynos_dsi *dsi)
5777eb8f069SAndrzej Hajda {
578bb32e408SAndrzej Hajda 	u32 reset_val = dsi->driver_data->reg_values[RESET_TYPE];
579ba12ac2bSHyungwon Hwang 
5807eb8f069SAndrzej Hajda 	reinit_completion(&dsi->completed);
581bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_SWRST_REG, reset_val);
5827eb8f069SAndrzej Hajda }
5837eb8f069SAndrzej Hajda 
5847eb8f069SAndrzej Hajda #ifndef MHZ
5857eb8f069SAndrzej Hajda #define MHZ	(1000*1000)
5867eb8f069SAndrzej Hajda #endif
5877eb8f069SAndrzej Hajda 
5887eb8f069SAndrzej Hajda static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
5897eb8f069SAndrzej Hajda 		unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s)
5907eb8f069SAndrzej Hajda {
5912154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
5927eb8f069SAndrzej Hajda 	unsigned long best_freq = 0;
5937eb8f069SAndrzej Hajda 	u32 min_delta = 0xffffffff;
5947eb8f069SAndrzej Hajda 	u8 p_min, p_max;
5953f649ab7SKees Cook 	u8 _p, best_p;
5963f649ab7SKees Cook 	u16 _m, best_m;
5973f649ab7SKees Cook 	u8 _s, best_s;
5987eb8f069SAndrzej Hajda 
5997eb8f069SAndrzej Hajda 	p_min = DIV_ROUND_UP(fin, (12 * MHZ));
6007eb8f069SAndrzej Hajda 	p_max = fin / (6 * MHZ);
6017eb8f069SAndrzej Hajda 
6027eb8f069SAndrzej Hajda 	for (_p = p_min; _p <= p_max; ++_p) {
6037eb8f069SAndrzej Hajda 		for (_s = 0; _s <= 5; ++_s) {
6047eb8f069SAndrzej Hajda 			u64 tmp;
6057eb8f069SAndrzej Hajda 			u32 delta;
6067eb8f069SAndrzej Hajda 
6077eb8f069SAndrzej Hajda 			tmp = (u64)fout * (_p << _s);
6087eb8f069SAndrzej Hajda 			do_div(tmp, fin);
6097eb8f069SAndrzej Hajda 			_m = tmp;
6107eb8f069SAndrzej Hajda 			if (_m < 41 || _m > 125)
6117eb8f069SAndrzej Hajda 				continue;
6127eb8f069SAndrzej Hajda 
6137eb8f069SAndrzej Hajda 			tmp = (u64)_m * fin;
6147eb8f069SAndrzej Hajda 			do_div(tmp, _p);
615d668e8bfSHyungwon Hwang 			if (tmp < 500 * MHZ ||
616d668e8bfSHyungwon Hwang 					tmp > driver_data->max_freq * MHZ)
6177eb8f069SAndrzej Hajda 				continue;
6187eb8f069SAndrzej Hajda 
6197eb8f069SAndrzej Hajda 			tmp = (u64)_m * fin;
6207eb8f069SAndrzej Hajda 			do_div(tmp, _p << _s);
6217eb8f069SAndrzej Hajda 
6227eb8f069SAndrzej Hajda 			delta = abs(fout - tmp);
6237eb8f069SAndrzej Hajda 			if (delta < min_delta) {
6247eb8f069SAndrzej Hajda 				best_p = _p;
6257eb8f069SAndrzej Hajda 				best_m = _m;
6267eb8f069SAndrzej Hajda 				best_s = _s;
6277eb8f069SAndrzej Hajda 				min_delta = delta;
6287eb8f069SAndrzej Hajda 				best_freq = tmp;
6297eb8f069SAndrzej Hajda 			}
6307eb8f069SAndrzej Hajda 		}
6317eb8f069SAndrzej Hajda 	}
6327eb8f069SAndrzej Hajda 
6337eb8f069SAndrzej Hajda 	if (best_freq) {
6347eb8f069SAndrzej Hajda 		*p = best_p;
6357eb8f069SAndrzej Hajda 		*m = best_m;
6367eb8f069SAndrzej Hajda 		*s = best_s;
6377eb8f069SAndrzej Hajda 	}
6387eb8f069SAndrzej Hajda 
6397eb8f069SAndrzej Hajda 	return best_freq;
6407eb8f069SAndrzej Hajda }
6417eb8f069SAndrzej Hajda 
6427eb8f069SAndrzej Hajda static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
6437eb8f069SAndrzej Hajda 					unsigned long freq)
6447eb8f069SAndrzej Hajda {
6452154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
6467eb8f069SAndrzej Hajda 	unsigned long fin, fout;
6479a320415SYoungJun Cho 	int timeout;
6487eb8f069SAndrzej Hajda 	u8 p, s;
6497eb8f069SAndrzej Hajda 	u16 m;
6507eb8f069SAndrzej Hajda 	u32 reg;
6517eb8f069SAndrzej Hajda 
65226269af9SHyungwon Hwang 	fin = dsi->pll_clk_rate;
6537eb8f069SAndrzej Hajda 	fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s);
6547eb8f069SAndrzej Hajda 	if (!fout) {
6557eb8f069SAndrzej Hajda 		dev_err(dsi->dev,
6567eb8f069SAndrzej Hajda 			"failed to find PLL PMS for requested frequency\n");
6578525b5ecSYoungJun Cho 		return 0;
6587eb8f069SAndrzej Hajda 	}
6599a320415SYoungJun Cho 	dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s);
6609a320415SYoungJun Cho 
661d668e8bfSHyungwon Hwang 	writel(driver_data->reg_values[PLL_TIMER],
662d668e8bfSHyungwon Hwang 			dsi->reg_base + driver_data->plltmr_reg);
6639a320415SYoungJun Cho 
664c4f8bdadSJagan Teki 	reg = DSIM_PLL_EN | DSIM_PLL_P(p, driver_data->pll_p_offset) |
665c4f8bdadSJagan Teki 	      DSIM_PLL_M(m) | DSIM_PLL_S(s);
6669a320415SYoungJun Cho 
6679a320415SYoungJun Cho 	if (driver_data->has_freqband) {
6689a320415SYoungJun Cho 		static const unsigned long freq_bands[] = {
6699a320415SYoungJun Cho 			100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ,
6709a320415SYoungJun Cho 			270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ,
6719a320415SYoungJun Cho 			510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ,
6729a320415SYoungJun Cho 			770 * MHZ, 870 * MHZ, 950 * MHZ,
6739a320415SYoungJun Cho 		};
6749a320415SYoungJun Cho 		int band;
6757eb8f069SAndrzej Hajda 
6767eb8f069SAndrzej Hajda 		for (band = 0; band < ARRAY_SIZE(freq_bands); ++band)
6777eb8f069SAndrzej Hajda 			if (fout < freq_bands[band])
6787eb8f069SAndrzej Hajda 				break;
6797eb8f069SAndrzej Hajda 
6809a320415SYoungJun Cho 		dev_dbg(dsi->dev, "band %d\n", band);
6817eb8f069SAndrzej Hajda 
6829a320415SYoungJun Cho 		reg |= DSIM_FREQ_BAND(band);
6839a320415SYoungJun Cho 	}
6847eb8f069SAndrzej Hajda 
685bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PLLCTRL_REG, reg);
6867eb8f069SAndrzej Hajda 
6877eb8f069SAndrzej Hajda 	timeout = 1000;
6887eb8f069SAndrzej Hajda 	do {
6897eb8f069SAndrzej Hajda 		if (timeout-- == 0) {
6907eb8f069SAndrzej Hajda 			dev_err(dsi->dev, "PLL failed to stabilize\n");
6918525b5ecSYoungJun Cho 			return 0;
6927eb8f069SAndrzej Hajda 		}
693bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_STATUS_REG);
6947eb8f069SAndrzej Hajda 	} while ((reg & DSIM_PLL_STABLE) == 0);
6957eb8f069SAndrzej Hajda 
6967eb8f069SAndrzej Hajda 	return fout;
6977eb8f069SAndrzej Hajda }
6987eb8f069SAndrzej Hajda 
6997eb8f069SAndrzej Hajda static int exynos_dsi_enable_clock(struct exynos_dsi *dsi)
7007eb8f069SAndrzej Hajda {
7017eb8f069SAndrzej Hajda 	unsigned long hs_clk, byte_clk, esc_clk;
7027eb8f069SAndrzej Hajda 	unsigned long esc_div;
7037eb8f069SAndrzej Hajda 	u32 reg;
7047eb8f069SAndrzej Hajda 
7057eb8f069SAndrzej Hajda 	hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate);
7067eb8f069SAndrzej Hajda 	if (!hs_clk) {
7077eb8f069SAndrzej Hajda 		dev_err(dsi->dev, "failed to configure DSI PLL\n");
7087eb8f069SAndrzej Hajda 		return -EFAULT;
7097eb8f069SAndrzej Hajda 	}
7107eb8f069SAndrzej Hajda 
7117eb8f069SAndrzej Hajda 	byte_clk = hs_clk / 8;
7127eb8f069SAndrzej Hajda 	esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate);
7137eb8f069SAndrzej Hajda 	esc_clk = byte_clk / esc_div;
7147eb8f069SAndrzej Hajda 
7157eb8f069SAndrzej Hajda 	if (esc_clk > 20 * MHZ) {
7167eb8f069SAndrzej Hajda 		++esc_div;
7177eb8f069SAndrzej Hajda 		esc_clk = byte_clk / esc_div;
7187eb8f069SAndrzej Hajda 	}
7197eb8f069SAndrzej Hajda 
7207eb8f069SAndrzej Hajda 	dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n",
7217eb8f069SAndrzej Hajda 		hs_clk, byte_clk, esc_clk);
7227eb8f069SAndrzej Hajda 
723bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_CLKCTRL_REG);
7247eb8f069SAndrzej Hajda 	reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK
7257eb8f069SAndrzej Hajda 			| DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS
7267eb8f069SAndrzej Hajda 			| DSIM_BYTE_CLK_SRC_MASK);
7277eb8f069SAndrzej Hajda 	reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN
7287eb8f069SAndrzej Hajda 			| DSIM_ESC_PRESCALER(esc_div)
7297eb8f069SAndrzej Hajda 			| DSIM_LANE_ESC_CLK_EN_CLK
7307eb8f069SAndrzej Hajda 			| DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1)
7317eb8f069SAndrzej Hajda 			| DSIM_BYTE_CLK_SRC(0)
7327eb8f069SAndrzej Hajda 			| DSIM_TX_REQUEST_HSCLK;
733bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_CLKCTRL_REG, reg);
7347eb8f069SAndrzej Hajda 
7357eb8f069SAndrzej Hajda 	return 0;
7367eb8f069SAndrzej Hajda }
7377eb8f069SAndrzej Hajda 
7389a320415SYoungJun Cho static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
7399a320415SYoungJun Cho {
7402154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
741b115361eSAndrzej Hajda 	const unsigned int *reg_values = driver_data->reg_values;
7429a320415SYoungJun Cho 	u32 reg;
7439a320415SYoungJun Cho 
7449a320415SYoungJun Cho 	if (driver_data->has_freqband)
7459a320415SYoungJun Cho 		return;
7469a320415SYoungJun Cho 
7479a320415SYoungJun Cho 	/* B D-PHY: D-PHY Master & Slave Analog Block control */
748d668e8bfSHyungwon Hwang 	reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] |
749d668e8bfSHyungwon Hwang 		reg_values[PHYCTRL_SLEW_UP];
750bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PHYCTRL_REG, reg);
7519a320415SYoungJun Cho 
7529a320415SYoungJun Cho 	/*
7539a320415SYoungJun Cho 	 * T LPX: Transmitted length of any Low-Power state period
7549a320415SYoungJun Cho 	 * T HS-EXIT: Time that the transmitter drives LP-11 following a HS
7559a320415SYoungJun Cho 	 *	burst
7569a320415SYoungJun Cho 	 */
757d668e8bfSHyungwon Hwang 	reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT];
758bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PHYTIMING_REG, reg);
7599a320415SYoungJun Cho 
7609a320415SYoungJun Cho 	/*
7619a320415SYoungJun Cho 	 * T CLK-PREPARE: Time that the transmitter drives the Clock Lane LP-00
7629a320415SYoungJun Cho 	 *	Line state immediately before the HS-0 Line state starting the
7639a320415SYoungJun Cho 	 *	HS transmission
7649a320415SYoungJun Cho 	 * T CLK-ZERO: Time that the transmitter drives the HS-0 state prior to
7659a320415SYoungJun Cho 	 *	transmitting the Clock.
7669a320415SYoungJun Cho 	 * T CLK_POST: Time that the transmitter continues to send HS clock
7679a320415SYoungJun Cho 	 *	after the last associated Data Lane has transitioned to LP Mode
7689a320415SYoungJun Cho 	 *	Interval is defined as the period from the end of T HS-TRAIL to
7699a320415SYoungJun Cho 	 *	the beginning of T CLK-TRAIL
7709a320415SYoungJun Cho 	 * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after
7719a320415SYoungJun Cho 	 *	the last payload clock bit of a HS transmission burst
7729a320415SYoungJun Cho 	 */
773d668e8bfSHyungwon Hwang 	reg = reg_values[PHYTIMING_CLK_PREPARE] |
774d668e8bfSHyungwon Hwang 		reg_values[PHYTIMING_CLK_ZERO] |
775d668e8bfSHyungwon Hwang 		reg_values[PHYTIMING_CLK_POST] |
776d668e8bfSHyungwon Hwang 		reg_values[PHYTIMING_CLK_TRAIL];
777d668e8bfSHyungwon Hwang 
778bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PHYTIMING1_REG, reg);
7799a320415SYoungJun Cho 
7809a320415SYoungJun Cho 	/*
7819a320415SYoungJun Cho 	 * T HS-PREPARE: Time that the transmitter drives the Data Lane LP-00
7829a320415SYoungJun Cho 	 *	Line state immediately before the HS-0 Line state starting the
7839a320415SYoungJun Cho 	 *	HS transmission
7849a320415SYoungJun Cho 	 * T HS-ZERO: Time that the transmitter drives the HS-0 state prior to
7859a320415SYoungJun Cho 	 *	transmitting the Sync sequence.
7869a320415SYoungJun Cho 	 * T HS-TRAIL: Time that the transmitter drives the flipped differential
7879a320415SYoungJun Cho 	 *	state after last payload data bit of a HS transmission burst
7889a320415SYoungJun Cho 	 */
789d668e8bfSHyungwon Hwang 	reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] |
790d668e8bfSHyungwon Hwang 		reg_values[PHYTIMING_HS_TRAIL];
791bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PHYTIMING2_REG, reg);
7929a320415SYoungJun Cho }
7939a320415SYoungJun Cho 
7947eb8f069SAndrzej Hajda static void exynos_dsi_disable_clock(struct exynos_dsi *dsi)
7957eb8f069SAndrzej Hajda {
7967eb8f069SAndrzej Hajda 	u32 reg;
7977eb8f069SAndrzej Hajda 
798bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_CLKCTRL_REG);
7997eb8f069SAndrzej Hajda 	reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK
8007eb8f069SAndrzej Hajda 			| DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN);
801bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_CLKCTRL_REG, reg);
8027eb8f069SAndrzej Hajda 
803bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_PLLCTRL_REG);
8047eb8f069SAndrzej Hajda 	reg &= ~DSIM_PLL_EN;
805bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PLLCTRL_REG, reg);
8067eb8f069SAndrzej Hajda }
8077eb8f069SAndrzej Hajda 
808e6f988a4SHyungwon Hwang static void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane)
809e6f988a4SHyungwon Hwang {
810bb32e408SAndrzej Hajda 	u32 reg = exynos_dsi_read(dsi, DSIM_CONFIG_REG);
811e6f988a4SHyungwon Hwang 	reg |= (DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1) | DSIM_LANE_EN_CLK |
812e6f988a4SHyungwon Hwang 			DSIM_LANE_EN(lane));
813bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_CONFIG_REG, reg);
814e6f988a4SHyungwon Hwang }
815e6f988a4SHyungwon Hwang 
8167eb8f069SAndrzej Hajda static int exynos_dsi_init_link(struct exynos_dsi *dsi)
8177eb8f069SAndrzej Hajda {
8182154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
8197eb8f069SAndrzej Hajda 	int timeout;
8207eb8f069SAndrzej Hajda 	u32 reg;
8217eb8f069SAndrzej Hajda 	u32 lanes_mask;
8227eb8f069SAndrzej Hajda 
8237eb8f069SAndrzej Hajda 	/* Initialize FIFO pointers */
824bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_FIFOCTRL_REG);
8257eb8f069SAndrzej Hajda 	reg &= ~0x1f;
826bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_FIFOCTRL_REG, reg);
8277eb8f069SAndrzej Hajda 
8287eb8f069SAndrzej Hajda 	usleep_range(9000, 11000);
8297eb8f069SAndrzej Hajda 
8307eb8f069SAndrzej Hajda 	reg |= 0x1f;
831bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_FIFOCTRL_REG, reg);
8327eb8f069SAndrzej Hajda 	usleep_range(9000, 11000);
8337eb8f069SAndrzej Hajda 
8347eb8f069SAndrzej Hajda 	/* DSI configuration */
8357eb8f069SAndrzej Hajda 	reg = 0;
8367eb8f069SAndrzej Hajda 
8372f36e33aSYoungJun Cho 	/*
8382f36e33aSYoungJun Cho 	 * The first bit of mode_flags specifies display configuration.
8392f36e33aSYoungJun Cho 	 * If this bit is set[= MIPI_DSI_MODE_VIDEO], dsi will support video
8402f36e33aSYoungJun Cho 	 * mode, otherwise it will support command mode.
8412f36e33aSYoungJun Cho 	 */
8427eb8f069SAndrzej Hajda 	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
8437eb8f069SAndrzej Hajda 		reg |= DSIM_VIDEO_MODE;
8447eb8f069SAndrzej Hajda 
8452f36e33aSYoungJun Cho 		/*
8462f36e33aSYoungJun Cho 		 * The user manual describes that following bits are ignored in
8472f36e33aSYoungJun Cho 		 * command mode.
8482f36e33aSYoungJun Cho 		 */
8497eb8f069SAndrzej Hajda 		if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH))
8507eb8f069SAndrzej Hajda 			reg |= DSIM_MFLUSH_VS;
8517eb8f069SAndrzej Hajda 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
8527eb8f069SAndrzej Hajda 			reg |= DSIM_SYNC_INFORM;
8537eb8f069SAndrzej Hajda 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
8547eb8f069SAndrzej Hajda 			reg |= DSIM_BURST_MODE;
8557eb8f069SAndrzej Hajda 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
8567eb8f069SAndrzej Hajda 			reg |= DSIM_AUTO_MODE;
8577eb8f069SAndrzej Hajda 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
8582e337a8dSJagan Teki 			reg |= DSIM_HSE_DISABLE_MODE;
859996e1defSJagan Teki 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP)
8602e337a8dSJagan Teki 			reg |= DSIM_HFP_DISABLE_MODE;
861996e1defSJagan Teki 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP)
8622e337a8dSJagan Teki 			reg |= DSIM_HBP_DISABLE_MODE;
863996e1defSJagan Teki 		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HSA)
8642e337a8dSJagan Teki 			reg |= DSIM_HSA_DISABLE_MODE;
8657eb8f069SAndrzej Hajda 	}
8667eb8f069SAndrzej Hajda 
867996e1defSJagan Teki 	if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
8682f36e33aSYoungJun Cho 		reg |= DSIM_EOT_DISABLE;
8692f36e33aSYoungJun Cho 
8707eb8f069SAndrzej Hajda 	switch (dsi->format) {
8717eb8f069SAndrzej Hajda 	case MIPI_DSI_FMT_RGB888:
8727eb8f069SAndrzej Hajda 		reg |= DSIM_MAIN_PIX_FORMAT_RGB888;
8737eb8f069SAndrzej Hajda 		break;
8747eb8f069SAndrzej Hajda 	case MIPI_DSI_FMT_RGB666:
8757eb8f069SAndrzej Hajda 		reg |= DSIM_MAIN_PIX_FORMAT_RGB666;
8767eb8f069SAndrzej Hajda 		break;
8777eb8f069SAndrzej Hajda 	case MIPI_DSI_FMT_RGB666_PACKED:
8787eb8f069SAndrzej Hajda 		reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P;
8797eb8f069SAndrzej Hajda 		break;
8807eb8f069SAndrzej Hajda 	case MIPI_DSI_FMT_RGB565:
8817eb8f069SAndrzej Hajda 		reg |= DSIM_MAIN_PIX_FORMAT_RGB565;
8827eb8f069SAndrzej Hajda 		break;
8837eb8f069SAndrzej Hajda 	default:
8847eb8f069SAndrzej Hajda 		dev_err(dsi->dev, "invalid pixel format\n");
8857eb8f069SAndrzej Hajda 		return -EINVAL;
8867eb8f069SAndrzej Hajda 	}
8877eb8f069SAndrzej Hajda 
88878d3a8c6SInki Dae 	/*
88978d3a8c6SInki Dae 	 * Use non-continuous clock mode if the periparal wants and
89078d3a8c6SInki Dae 	 * host controller supports
89178d3a8c6SInki Dae 	 *
89278d3a8c6SInki Dae 	 * In non-continous clock mode, host controller will turn off
89378d3a8c6SInki Dae 	 * the HS clock between high-speed transmissions to reduce
89478d3a8c6SInki Dae 	 * power consumption.
89578d3a8c6SInki Dae 	 */
89678d3a8c6SInki Dae 	if (driver_data->has_clklane_stop &&
89778d3a8c6SInki Dae 			dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
89878d3a8c6SInki Dae 		reg |= DSIM_CLKLANE_STOP;
89978d3a8c6SInki Dae 	}
900bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_CONFIG_REG, reg);
901e6f988a4SHyungwon Hwang 
902e6f988a4SHyungwon Hwang 	lanes_mask = BIT(dsi->lanes) - 1;
903e6f988a4SHyungwon Hwang 	exynos_dsi_enable_lane(dsi, lanes_mask);
90478d3a8c6SInki Dae 
9057eb8f069SAndrzej Hajda 	/* Check clock and data lane state are stop state */
9067eb8f069SAndrzej Hajda 	timeout = 100;
9077eb8f069SAndrzej Hajda 	do {
9087eb8f069SAndrzej Hajda 		if (timeout-- == 0) {
9097eb8f069SAndrzej Hajda 			dev_err(dsi->dev, "waiting for bus lanes timed out\n");
9107eb8f069SAndrzej Hajda 			return -EFAULT;
9117eb8f069SAndrzej Hajda 		}
9127eb8f069SAndrzej Hajda 
913bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_STATUS_REG);
9147eb8f069SAndrzej Hajda 		if ((reg & DSIM_STOP_STATE_DAT(lanes_mask))
9157eb8f069SAndrzej Hajda 		    != DSIM_STOP_STATE_DAT(lanes_mask))
9167eb8f069SAndrzej Hajda 			continue;
9177eb8f069SAndrzej Hajda 	} while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK)));
9187eb8f069SAndrzej Hajda 
919bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_ESCMODE_REG);
9207eb8f069SAndrzej Hajda 	reg &= ~DSIM_STOP_STATE_CNT_MASK;
921d668e8bfSHyungwon Hwang 	reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]);
922bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_ESCMODE_REG, reg);
9237eb8f069SAndrzej Hajda 
9247eb8f069SAndrzej Hajda 	reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
925bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_TIMEOUT_REG, reg);
9267eb8f069SAndrzej Hajda 
9277eb8f069SAndrzej Hajda 	return 0;
9287eb8f069SAndrzej Hajda }
9297eb8f069SAndrzej Hajda 
9307eb8f069SAndrzej Hajda static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
9317eb8f069SAndrzej Hajda {
932aee039e6SJagan Teki 	struct drm_display_mode *m = &dsi->mode;
933d668e8bfSHyungwon Hwang 	unsigned int num_bits_resol = dsi->driver_data->num_bits_resol;
9347eb8f069SAndrzej Hajda 	u32 reg;
9357eb8f069SAndrzej Hajda 
9367eb8f069SAndrzej Hajda 	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
9377eb8f069SAndrzej Hajda 		reg = DSIM_CMD_ALLOW(0xf)
938e8929999SAndrzej Hajda 			| DSIM_STABLE_VFP(m->vsync_start - m->vdisplay)
939e8929999SAndrzej Hajda 			| DSIM_MAIN_VBP(m->vtotal - m->vsync_end);
940bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_MVPORCH_REG, reg);
9417eb8f069SAndrzej Hajda 
942e8929999SAndrzej Hajda 		reg = DSIM_MAIN_HFP(m->hsync_start - m->hdisplay)
943e8929999SAndrzej Hajda 			| DSIM_MAIN_HBP(m->htotal - m->hsync_end);
944bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_MHPORCH_REG, reg);
9457eb8f069SAndrzej Hajda 
946e8929999SAndrzej Hajda 		reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start)
947e8929999SAndrzej Hajda 			| DSIM_MAIN_HSA(m->hsync_end - m->hsync_start);
948bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_MSYNC_REG, reg);
9497eb8f069SAndrzej Hajda 	}
950e8929999SAndrzej Hajda 	reg =  DSIM_MAIN_HRESOL(m->hdisplay, num_bits_resol) |
951e8929999SAndrzej Hajda 		DSIM_MAIN_VRESOL(m->vdisplay, num_bits_resol);
9527eb8f069SAndrzej Hajda 
953bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_MDRESOL_REG, reg);
9547eb8f069SAndrzej Hajda 
955e8929999SAndrzej Hajda 	dev_dbg(dsi->dev, "LCD size = %dx%d\n", m->hdisplay, m->vdisplay);
9567eb8f069SAndrzej Hajda }
9577eb8f069SAndrzej Hajda 
9587eb8f069SAndrzej Hajda static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable)
9597eb8f069SAndrzej Hajda {
9607eb8f069SAndrzej Hajda 	u32 reg;
9617eb8f069SAndrzej Hajda 
962bb32e408SAndrzej Hajda 	reg = exynos_dsi_read(dsi, DSIM_MDRESOL_REG);
9637eb8f069SAndrzej Hajda 	if (enable)
9647eb8f069SAndrzej Hajda 		reg |= DSIM_MAIN_STAND_BY;
9657eb8f069SAndrzej Hajda 	else
9667eb8f069SAndrzej Hajda 		reg &= ~DSIM_MAIN_STAND_BY;
967bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_MDRESOL_REG, reg);
9687eb8f069SAndrzej Hajda }
9697eb8f069SAndrzej Hajda 
9707eb8f069SAndrzej Hajda static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi)
9717eb8f069SAndrzej Hajda {
9727eb8f069SAndrzej Hajda 	int timeout = 2000;
9737eb8f069SAndrzej Hajda 
9747eb8f069SAndrzej Hajda 	do {
975bb32e408SAndrzej Hajda 		u32 reg = exynos_dsi_read(dsi, DSIM_FIFOCTRL_REG);
9767eb8f069SAndrzej Hajda 
9777eb8f069SAndrzej Hajda 		if (!(reg & DSIM_SFR_HEADER_FULL))
9787eb8f069SAndrzej Hajda 			return 0;
9797eb8f069SAndrzej Hajda 
9807eb8f069SAndrzej Hajda 		if (!cond_resched())
9817eb8f069SAndrzej Hajda 			usleep_range(950, 1050);
9827eb8f069SAndrzej Hajda 	} while (--timeout);
9837eb8f069SAndrzej Hajda 
9847eb8f069SAndrzej Hajda 	return -ETIMEDOUT;
9857eb8f069SAndrzej Hajda }
9867eb8f069SAndrzej Hajda 
9877eb8f069SAndrzej Hajda static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm)
9887eb8f069SAndrzej Hajda {
989bb32e408SAndrzej Hajda 	u32 v = exynos_dsi_read(dsi, DSIM_ESCMODE_REG);
9907eb8f069SAndrzej Hajda 
9917eb8f069SAndrzej Hajda 	if (lpm)
9927eb8f069SAndrzej Hajda 		v |= DSIM_CMD_LPDT_LP;
9937eb8f069SAndrzej Hajda 	else
9947eb8f069SAndrzej Hajda 		v &= ~DSIM_CMD_LPDT_LP;
9957eb8f069SAndrzej Hajda 
996bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_ESCMODE_REG, v);
9977eb8f069SAndrzej Hajda }
9987eb8f069SAndrzej Hajda 
9997eb8f069SAndrzej Hajda static void exynos_dsi_force_bta(struct exynos_dsi *dsi)
10007eb8f069SAndrzej Hajda {
1001bb32e408SAndrzej Hajda 	u32 v = exynos_dsi_read(dsi, DSIM_ESCMODE_REG);
10027eb8f069SAndrzej Hajda 	v |= DSIM_FORCE_BTA;
1003bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_ESCMODE_REG, v);
10047eb8f069SAndrzej Hajda }
10057eb8f069SAndrzej Hajda 
10067eb8f069SAndrzej Hajda static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi,
10077eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer *xfer)
10087eb8f069SAndrzej Hajda {
10097eb8f069SAndrzej Hajda 	struct device *dev = dsi->dev;
10106c81e96dSAndrzej Hajda 	struct mipi_dsi_packet *pkt = &xfer->packet;
10116c81e96dSAndrzej Hajda 	const u8 *payload = pkt->payload + xfer->tx_done;
10126c81e96dSAndrzej Hajda 	u16 length = pkt->payload_length - xfer->tx_done;
10137eb8f069SAndrzej Hajda 	bool first = !xfer->tx_done;
10147eb8f069SAndrzej Hajda 	u32 reg;
10157eb8f069SAndrzej Hajda 
10169cdf0ed2SKrzysztof Kozlowski 	dev_dbg(dev, "< xfer %pK: tx len %u, done %u, rx len %u, done %u\n",
10176c81e96dSAndrzej Hajda 		xfer, length, xfer->tx_done, xfer->rx_len, xfer->rx_done);
10187eb8f069SAndrzej Hajda 
10197eb8f069SAndrzej Hajda 	if (length > DSI_TX_FIFO_SIZE)
10207eb8f069SAndrzej Hajda 		length = DSI_TX_FIFO_SIZE;
10217eb8f069SAndrzej Hajda 
10227eb8f069SAndrzej Hajda 	xfer->tx_done += length;
10237eb8f069SAndrzej Hajda 
10247eb8f069SAndrzej Hajda 	/* Send payload */
10257eb8f069SAndrzej Hajda 	while (length >= 4) {
10266c81e96dSAndrzej Hajda 		reg = get_unaligned_le32(payload);
1027bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_PAYLOAD_REG, reg);
10287eb8f069SAndrzej Hajda 		payload += 4;
10297eb8f069SAndrzej Hajda 		length -= 4;
10307eb8f069SAndrzej Hajda 	}
10317eb8f069SAndrzej Hajda 
10327eb8f069SAndrzej Hajda 	reg = 0;
10337eb8f069SAndrzej Hajda 	switch (length) {
10347eb8f069SAndrzej Hajda 	case 3:
10357eb8f069SAndrzej Hajda 		reg |= payload[2] << 16;
1036df561f66SGustavo A. R. Silva 		fallthrough;
10377eb8f069SAndrzej Hajda 	case 2:
10387eb8f069SAndrzej Hajda 		reg |= payload[1] << 8;
1039df561f66SGustavo A. R. Silva 		fallthrough;
10407eb8f069SAndrzej Hajda 	case 1:
10417eb8f069SAndrzej Hajda 		reg |= payload[0];
1042bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_PAYLOAD_REG, reg);
10437eb8f069SAndrzej Hajda 		break;
10447eb8f069SAndrzej Hajda 	}
10457eb8f069SAndrzej Hajda 
10467eb8f069SAndrzej Hajda 	/* Send packet header */
10477eb8f069SAndrzej Hajda 	if (!first)
10487eb8f069SAndrzej Hajda 		return;
10497eb8f069SAndrzej Hajda 
10506c81e96dSAndrzej Hajda 	reg = get_unaligned_le32(pkt->header);
10517eb8f069SAndrzej Hajda 	if (exynos_dsi_wait_for_hdr_fifo(dsi)) {
10527eb8f069SAndrzej Hajda 		dev_err(dev, "waiting for header FIFO timed out\n");
10537eb8f069SAndrzej Hajda 		return;
10547eb8f069SAndrzej Hajda 	}
10557eb8f069SAndrzej Hajda 
10567eb8f069SAndrzej Hajda 	if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM,
10577eb8f069SAndrzej Hajda 		 dsi->state & DSIM_STATE_CMD_LPM)) {
10587eb8f069SAndrzej Hajda 		exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM);
10597eb8f069SAndrzej Hajda 		dsi->state ^= DSIM_STATE_CMD_LPM;
10607eb8f069SAndrzej Hajda 	}
10617eb8f069SAndrzej Hajda 
1062bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_PKTHDR_REG, reg);
10637eb8f069SAndrzej Hajda 
10647eb8f069SAndrzej Hajda 	if (xfer->flags & MIPI_DSI_MSG_REQ_ACK)
10657eb8f069SAndrzej Hajda 		exynos_dsi_force_bta(dsi);
10667eb8f069SAndrzej Hajda }
10677eb8f069SAndrzej Hajda 
10687eb8f069SAndrzej Hajda static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi,
10697eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer *xfer)
10707eb8f069SAndrzej Hajda {
10717eb8f069SAndrzej Hajda 	u8 *payload = xfer->rx_payload + xfer->rx_done;
10727eb8f069SAndrzej Hajda 	bool first = !xfer->rx_done;
10737eb8f069SAndrzej Hajda 	struct device *dev = dsi->dev;
10747eb8f069SAndrzej Hajda 	u16 length;
10757eb8f069SAndrzej Hajda 	u32 reg;
10767eb8f069SAndrzej Hajda 
10777eb8f069SAndrzej Hajda 	if (first) {
1078bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG);
10797eb8f069SAndrzej Hajda 
10807eb8f069SAndrzej Hajda 		switch (reg & 0x3f) {
10817eb8f069SAndrzej Hajda 		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
10827eb8f069SAndrzej Hajda 		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
10837eb8f069SAndrzej Hajda 			if (xfer->rx_len >= 2) {
10847eb8f069SAndrzej Hajda 				payload[1] = reg >> 16;
10857eb8f069SAndrzej Hajda 				++xfer->rx_done;
10867eb8f069SAndrzej Hajda 			}
1087df561f66SGustavo A. R. Silva 			fallthrough;
10887eb8f069SAndrzej Hajda 		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
10897eb8f069SAndrzej Hajda 		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
10907eb8f069SAndrzej Hajda 			payload[0] = reg >> 8;
10917eb8f069SAndrzej Hajda 			++xfer->rx_done;
10927eb8f069SAndrzej Hajda 			xfer->rx_len = xfer->rx_done;
10937eb8f069SAndrzej Hajda 			xfer->result = 0;
10947eb8f069SAndrzej Hajda 			goto clear_fifo;
10957eb8f069SAndrzej Hajda 		case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
10967eb8f069SAndrzej Hajda 			dev_err(dev, "DSI Error Report: 0x%04x\n",
10977eb8f069SAndrzej Hajda 				(reg >> 8) & 0xffff);
10987eb8f069SAndrzej Hajda 			xfer->result = 0;
10997eb8f069SAndrzej Hajda 			goto clear_fifo;
11007eb8f069SAndrzej Hajda 		}
11017eb8f069SAndrzej Hajda 
11027eb8f069SAndrzej Hajda 		length = (reg >> 8) & 0xffff;
11037eb8f069SAndrzej Hajda 		if (length > xfer->rx_len) {
11047eb8f069SAndrzej Hajda 			dev_err(dev,
11057eb8f069SAndrzej Hajda 				"response too long (%u > %u bytes), stripping\n",
11067eb8f069SAndrzej Hajda 				xfer->rx_len, length);
11077eb8f069SAndrzej Hajda 			length = xfer->rx_len;
11087eb8f069SAndrzej Hajda 		} else if (length < xfer->rx_len)
11097eb8f069SAndrzej Hajda 			xfer->rx_len = length;
11107eb8f069SAndrzej Hajda 	}
11117eb8f069SAndrzej Hajda 
11127eb8f069SAndrzej Hajda 	length = xfer->rx_len - xfer->rx_done;
11137eb8f069SAndrzej Hajda 	xfer->rx_done += length;
11147eb8f069SAndrzej Hajda 
11157eb8f069SAndrzej Hajda 	/* Receive payload */
11167eb8f069SAndrzej Hajda 	while (length >= 4) {
1117bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG);
11187eb8f069SAndrzej Hajda 		payload[0] = (reg >>  0) & 0xff;
11197eb8f069SAndrzej Hajda 		payload[1] = (reg >>  8) & 0xff;
11207eb8f069SAndrzej Hajda 		payload[2] = (reg >> 16) & 0xff;
11217eb8f069SAndrzej Hajda 		payload[3] = (reg >> 24) & 0xff;
11227eb8f069SAndrzej Hajda 		payload += 4;
11237eb8f069SAndrzej Hajda 		length -= 4;
11247eb8f069SAndrzej Hajda 	}
11257eb8f069SAndrzej Hajda 
11267eb8f069SAndrzej Hajda 	if (length) {
1127bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG);
11287eb8f069SAndrzej Hajda 		switch (length) {
11297eb8f069SAndrzej Hajda 		case 3:
11307eb8f069SAndrzej Hajda 			payload[2] = (reg >> 16) & 0xff;
1131df561f66SGustavo A. R. Silva 			fallthrough;
11327eb8f069SAndrzej Hajda 		case 2:
11337eb8f069SAndrzej Hajda 			payload[1] = (reg >> 8) & 0xff;
1134df561f66SGustavo A. R. Silva 			fallthrough;
11357eb8f069SAndrzej Hajda 		case 1:
11367eb8f069SAndrzej Hajda 			payload[0] = reg & 0xff;
11377eb8f069SAndrzej Hajda 		}
11387eb8f069SAndrzej Hajda 	}
11397eb8f069SAndrzej Hajda 
11407eb8f069SAndrzej Hajda 	if (xfer->rx_done == xfer->rx_len)
11417eb8f069SAndrzej Hajda 		xfer->result = 0;
11427eb8f069SAndrzej Hajda 
11437eb8f069SAndrzej Hajda clear_fifo:
11447eb8f069SAndrzej Hajda 	length = DSI_RX_FIFO_SIZE / 4;
11457eb8f069SAndrzej Hajda 	do {
1146bb32e408SAndrzej Hajda 		reg = exynos_dsi_read(dsi, DSIM_RXFIFO_REG);
11477eb8f069SAndrzej Hajda 		if (reg == DSI_RX_FIFO_EMPTY)
11487eb8f069SAndrzej Hajda 			break;
11497eb8f069SAndrzej Hajda 	} while (--length);
11507eb8f069SAndrzej Hajda }
11517eb8f069SAndrzej Hajda 
11527eb8f069SAndrzej Hajda static void exynos_dsi_transfer_start(struct exynos_dsi *dsi)
11537eb8f069SAndrzej Hajda {
11547eb8f069SAndrzej Hajda 	unsigned long flags;
11557eb8f069SAndrzej Hajda 	struct exynos_dsi_transfer *xfer;
11567eb8f069SAndrzej Hajda 	bool start = false;
11577eb8f069SAndrzej Hajda 
11587eb8f069SAndrzej Hajda again:
11597eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
11607eb8f069SAndrzej Hajda 
11617eb8f069SAndrzej Hajda 	if (list_empty(&dsi->transfer_list)) {
11627eb8f069SAndrzej Hajda 		spin_unlock_irqrestore(&dsi->transfer_lock, flags);
11637eb8f069SAndrzej Hajda 		return;
11647eb8f069SAndrzej Hajda 	}
11657eb8f069SAndrzej Hajda 
11667eb8f069SAndrzej Hajda 	xfer = list_first_entry(&dsi->transfer_list,
11677eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer, list);
11687eb8f069SAndrzej Hajda 
11697eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
11707eb8f069SAndrzej Hajda 
11716c81e96dSAndrzej Hajda 	if (xfer->packet.payload_length &&
11726c81e96dSAndrzej Hajda 	    xfer->tx_done == xfer->packet.payload_length)
11737eb8f069SAndrzej Hajda 		/* waiting for RX */
11747eb8f069SAndrzej Hajda 		return;
11757eb8f069SAndrzej Hajda 
11767eb8f069SAndrzej Hajda 	exynos_dsi_send_to_fifo(dsi, xfer);
11777eb8f069SAndrzej Hajda 
11786c81e96dSAndrzej Hajda 	if (xfer->packet.payload_length || xfer->rx_len)
11797eb8f069SAndrzej Hajda 		return;
11807eb8f069SAndrzej Hajda 
11817eb8f069SAndrzej Hajda 	xfer->result = 0;
11827eb8f069SAndrzej Hajda 	complete(&xfer->completed);
11837eb8f069SAndrzej Hajda 
11847eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
11857eb8f069SAndrzej Hajda 
11867eb8f069SAndrzej Hajda 	list_del_init(&xfer->list);
11877eb8f069SAndrzej Hajda 	start = !list_empty(&dsi->transfer_list);
11887eb8f069SAndrzej Hajda 
11897eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
11907eb8f069SAndrzej Hajda 
11917eb8f069SAndrzej Hajda 	if (start)
11927eb8f069SAndrzej Hajda 		goto again;
11937eb8f069SAndrzej Hajda }
11947eb8f069SAndrzej Hajda 
11957eb8f069SAndrzej Hajda static bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi)
11967eb8f069SAndrzej Hajda {
11977eb8f069SAndrzej Hajda 	struct exynos_dsi_transfer *xfer;
11987eb8f069SAndrzej Hajda 	unsigned long flags;
11997eb8f069SAndrzej Hajda 	bool start = true;
12007eb8f069SAndrzej Hajda 
12017eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
12027eb8f069SAndrzej Hajda 
12037eb8f069SAndrzej Hajda 	if (list_empty(&dsi->transfer_list)) {
12047eb8f069SAndrzej Hajda 		spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12057eb8f069SAndrzej Hajda 		return false;
12067eb8f069SAndrzej Hajda 	}
12077eb8f069SAndrzej Hajda 
12087eb8f069SAndrzej Hajda 	xfer = list_first_entry(&dsi->transfer_list,
12097eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer, list);
12107eb8f069SAndrzej Hajda 
12117eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12127eb8f069SAndrzej Hajda 
12137eb8f069SAndrzej Hajda 	dev_dbg(dsi->dev,
12149cdf0ed2SKrzysztof Kozlowski 		"> xfer %pK, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n",
12156c81e96dSAndrzej Hajda 		xfer, xfer->packet.payload_length, xfer->tx_done, xfer->rx_len,
12166c81e96dSAndrzej Hajda 		xfer->rx_done);
12177eb8f069SAndrzej Hajda 
12186c81e96dSAndrzej Hajda 	if (xfer->tx_done != xfer->packet.payload_length)
12197eb8f069SAndrzej Hajda 		return true;
12207eb8f069SAndrzej Hajda 
12217eb8f069SAndrzej Hajda 	if (xfer->rx_done != xfer->rx_len)
12227eb8f069SAndrzej Hajda 		exynos_dsi_read_from_fifo(dsi, xfer);
12237eb8f069SAndrzej Hajda 
12247eb8f069SAndrzej Hajda 	if (xfer->rx_done != xfer->rx_len)
12257eb8f069SAndrzej Hajda 		return true;
12267eb8f069SAndrzej Hajda 
12277eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
12287eb8f069SAndrzej Hajda 
12297eb8f069SAndrzej Hajda 	list_del_init(&xfer->list);
12307eb8f069SAndrzej Hajda 	start = !list_empty(&dsi->transfer_list);
12317eb8f069SAndrzej Hajda 
12327eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12337eb8f069SAndrzej Hajda 
12347eb8f069SAndrzej Hajda 	if (!xfer->rx_len)
12357eb8f069SAndrzej Hajda 		xfer->result = 0;
12367eb8f069SAndrzej Hajda 	complete(&xfer->completed);
12377eb8f069SAndrzej Hajda 
12387eb8f069SAndrzej Hajda 	return start;
12397eb8f069SAndrzej Hajda }
12407eb8f069SAndrzej Hajda 
12417eb8f069SAndrzej Hajda static void exynos_dsi_remove_transfer(struct exynos_dsi *dsi,
12427eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer *xfer)
12437eb8f069SAndrzej Hajda {
12447eb8f069SAndrzej Hajda 	unsigned long flags;
12457eb8f069SAndrzej Hajda 	bool start;
12467eb8f069SAndrzej Hajda 
12477eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
12487eb8f069SAndrzej Hajda 
12497eb8f069SAndrzej Hajda 	if (!list_empty(&dsi->transfer_list) &&
12507eb8f069SAndrzej Hajda 	    xfer == list_first_entry(&dsi->transfer_list,
12517eb8f069SAndrzej Hajda 				     struct exynos_dsi_transfer, list)) {
12527eb8f069SAndrzej Hajda 		list_del_init(&xfer->list);
12537eb8f069SAndrzej Hajda 		start = !list_empty(&dsi->transfer_list);
12547eb8f069SAndrzej Hajda 		spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12557eb8f069SAndrzej Hajda 		if (start)
12567eb8f069SAndrzej Hajda 			exynos_dsi_transfer_start(dsi);
12577eb8f069SAndrzej Hajda 		return;
12587eb8f069SAndrzej Hajda 	}
12597eb8f069SAndrzej Hajda 
12607eb8f069SAndrzej Hajda 	list_del_init(&xfer->list);
12617eb8f069SAndrzej Hajda 
12627eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12637eb8f069SAndrzej Hajda }
12647eb8f069SAndrzej Hajda 
12657eb8f069SAndrzej Hajda static int exynos_dsi_transfer(struct exynos_dsi *dsi,
12667eb8f069SAndrzej Hajda 					struct exynos_dsi_transfer *xfer)
12677eb8f069SAndrzej Hajda {
12687eb8f069SAndrzej Hajda 	unsigned long flags;
12697eb8f069SAndrzej Hajda 	bool stopped;
12707eb8f069SAndrzej Hajda 
12717eb8f069SAndrzej Hajda 	xfer->tx_done = 0;
12727eb8f069SAndrzej Hajda 	xfer->rx_done = 0;
12737eb8f069SAndrzej Hajda 	xfer->result = -ETIMEDOUT;
12747eb8f069SAndrzej Hajda 	init_completion(&xfer->completed);
12757eb8f069SAndrzej Hajda 
12767eb8f069SAndrzej Hajda 	spin_lock_irqsave(&dsi->transfer_lock, flags);
12777eb8f069SAndrzej Hajda 
12787eb8f069SAndrzej Hajda 	stopped = list_empty(&dsi->transfer_list);
12797eb8f069SAndrzej Hajda 	list_add_tail(&xfer->list, &dsi->transfer_list);
12807eb8f069SAndrzej Hajda 
12817eb8f069SAndrzej Hajda 	spin_unlock_irqrestore(&dsi->transfer_lock, flags);
12827eb8f069SAndrzej Hajda 
12837eb8f069SAndrzej Hajda 	if (stopped)
12847eb8f069SAndrzej Hajda 		exynos_dsi_transfer_start(dsi);
12857eb8f069SAndrzej Hajda 
12867eb8f069SAndrzej Hajda 	wait_for_completion_timeout(&xfer->completed,
12877eb8f069SAndrzej Hajda 				    msecs_to_jiffies(DSI_XFER_TIMEOUT_MS));
12887eb8f069SAndrzej Hajda 	if (xfer->result == -ETIMEDOUT) {
12896c81e96dSAndrzej Hajda 		struct mipi_dsi_packet *pkt = &xfer->packet;
12907eb8f069SAndrzej Hajda 		exynos_dsi_remove_transfer(dsi, xfer);
12916c81e96dSAndrzej Hajda 		dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 4, pkt->header,
12926c81e96dSAndrzej Hajda 			(int)pkt->payload_length, pkt->payload);
12937eb8f069SAndrzej Hajda 		return -ETIMEDOUT;
12947eb8f069SAndrzej Hajda 	}
12957eb8f069SAndrzej Hajda 
12967eb8f069SAndrzej Hajda 	/* Also covers hardware timeout condition */
12977eb8f069SAndrzej Hajda 	return xfer->result;
12987eb8f069SAndrzej Hajda }
12997eb8f069SAndrzej Hajda 
13007eb8f069SAndrzej Hajda static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
13017eb8f069SAndrzej Hajda {
13027eb8f069SAndrzej Hajda 	struct exynos_dsi *dsi = dev_id;
13037eb8f069SAndrzej Hajda 	u32 status;
13047eb8f069SAndrzej Hajda 
1305bb32e408SAndrzej Hajda 	status = exynos_dsi_read(dsi, DSIM_INTSRC_REG);
13067eb8f069SAndrzej Hajda 	if (!status) {
13077eb8f069SAndrzej Hajda 		static unsigned long int j;
13087eb8f069SAndrzej Hajda 		if (printk_timed_ratelimit(&j, 500))
13097eb8f069SAndrzej Hajda 			dev_warn(dsi->dev, "spurious interrupt\n");
13107eb8f069SAndrzej Hajda 		return IRQ_HANDLED;
13117eb8f069SAndrzej Hajda 	}
1312bb32e408SAndrzej Hajda 	exynos_dsi_write(dsi, DSIM_INTSRC_REG, status);
13137eb8f069SAndrzej Hajda 
13147eb8f069SAndrzej Hajda 	if (status & DSIM_INT_SW_RST_RELEASE) {
1315e6f988a4SHyungwon Hwang 		u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY |
1316ecf81ed9SAndrzej Hajda 			DSIM_INT_SFR_HDR_FIFO_EMPTY | DSIM_INT_RX_ECC_ERR |
1317ecf81ed9SAndrzej Hajda 			DSIM_INT_SW_RST_RELEASE);
1318bb32e408SAndrzej Hajda 		exynos_dsi_write(dsi, DSIM_INTMSK_REG, mask);
13197eb8f069SAndrzej Hajda 		complete(&dsi->completed);
13207eb8f069SAndrzej Hajda 		return IRQ_HANDLED;
13217eb8f069SAndrzej Hajda 	}
13227eb8f069SAndrzej Hajda 
1323e6f988a4SHyungwon Hwang 	if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY |
1324ecf81ed9SAndrzej Hajda 			DSIM_INT_PLL_STABLE)))
13257eb8f069SAndrzej Hajda 		return IRQ_HANDLED;
13267eb8f069SAndrzej Hajda 
13277eb8f069SAndrzej Hajda 	if (exynos_dsi_transfer_finish(dsi))
13287eb8f069SAndrzej Hajda 		exynos_dsi_transfer_start(dsi);
13297eb8f069SAndrzej Hajda 
13307eb8f069SAndrzej Hajda 	return IRQ_HANDLED;
13317eb8f069SAndrzej Hajda }
13327eb8f069SAndrzej Hajda 
1333e17ddeccSYoungJun Cho static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
1334e17ddeccSYoungJun Cho {
1335e17ddeccSYoungJun Cho 	struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
1336*70e360f9SJagan Teki 	struct exynos_dsi_enc *dsi_enc = dsi->priv;
1337*70e360f9SJagan Teki 	struct drm_encoder *encoder = &dsi_enc->encoder;
1338e17ddeccSYoungJun Cho 
13390e480f6fSHyungwon Hwang 	if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)
1340e17ddeccSYoungJun Cho 		exynos_drm_crtc_te_handler(encoder->crtc);
1341e17ddeccSYoungJun Cho 
1342e17ddeccSYoungJun Cho 	return IRQ_HANDLED;
1343e17ddeccSYoungJun Cho }
1344e17ddeccSYoungJun Cho 
1345e17ddeccSYoungJun Cho static void exynos_dsi_enable_irq(struct exynos_dsi *dsi)
1346e17ddeccSYoungJun Cho {
1347e17ddeccSYoungJun Cho 	enable_irq(dsi->irq);
1348e17ddeccSYoungJun Cho 
1349ee6c8b5aSMaíra Canal 	if (dsi->te_gpio)
1350ee6c8b5aSMaíra Canal 		enable_irq(gpiod_to_irq(dsi->te_gpio));
1351e17ddeccSYoungJun Cho }
1352e17ddeccSYoungJun Cho 
1353e17ddeccSYoungJun Cho static void exynos_dsi_disable_irq(struct exynos_dsi *dsi)
1354e17ddeccSYoungJun Cho {
1355ee6c8b5aSMaíra Canal 	if (dsi->te_gpio)
1356ee6c8b5aSMaíra Canal 		disable_irq(gpiod_to_irq(dsi->te_gpio));
1357e17ddeccSYoungJun Cho 
1358e17ddeccSYoungJun Cho 	disable_irq(dsi->irq);
1359e17ddeccSYoungJun Cho }
1360e17ddeccSYoungJun Cho 
13617eb8f069SAndrzej Hajda static int exynos_dsi_init(struct exynos_dsi *dsi)
13627eb8f069SAndrzej Hajda {
13632154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
1364d668e8bfSHyungwon Hwang 
1365bb57453dSMarek Szyprowski 	if (dsi->state & DSIM_STATE_INITIALIZED)
1366bb57453dSMarek Szyprowski 		return 0;
1367bb57453dSMarek Szyprowski 
13687eb8f069SAndrzej Hajda 	exynos_dsi_reset(dsi);
1369e17ddeccSYoungJun Cho 	exynos_dsi_enable_irq(dsi);
1370e6f988a4SHyungwon Hwang 
1371e6f988a4SHyungwon Hwang 	if (driver_data->reg_values[RESET_TYPE] == DSIM_FUNCRST)
1372e6f988a4SHyungwon Hwang 		exynos_dsi_enable_lane(dsi, BIT(dsi->lanes) - 1);
1373e6f988a4SHyungwon Hwang 
13749a320415SYoungJun Cho 	exynos_dsi_enable_clock(dsi);
1375d668e8bfSHyungwon Hwang 	if (driver_data->wait_for_reset)
13767eb8f069SAndrzej Hajda 		exynos_dsi_wait_for_reset(dsi);
13779a320415SYoungJun Cho 	exynos_dsi_set_phy_ctrl(dsi);
13787eb8f069SAndrzej Hajda 	exynos_dsi_init_link(dsi);
13797eb8f069SAndrzej Hajda 
1380bb57453dSMarek Szyprowski 	dsi->state |= DSIM_STATE_INITIALIZED;
1381bb57453dSMarek Szyprowski 
13827eb8f069SAndrzej Hajda 	return 0;
13837eb8f069SAndrzej Hajda }
13847eb8f069SAndrzej Hajda 
1385295e7954SAndrzej Hajda static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi,
1386295e7954SAndrzej Hajda 				      struct device *panel)
1387e17ddeccSYoungJun Cho {
1388e17ddeccSYoungJun Cho 	int ret;
13890cef83a5SYoungJun Cho 	int te_gpio_irq;
1390e17ddeccSYoungJun Cho 
1391fedc8982SMarek Szyprowski 	dsi->te_gpio = gpiod_get_optional(panel, "te", GPIOD_IN);
13928e3fa9d8SMarek Szyprowski 	if (!dsi->te_gpio) {
13938e3fa9d8SMarek Szyprowski 		return 0;
13948e3fa9d8SMarek Szyprowski 	} else if (IS_ERR(dsi->te_gpio)) {
1395ee6c8b5aSMaíra Canal 		dev_err(dsi->dev, "gpio request failed with %ld\n",
1396ee6c8b5aSMaíra Canal 				PTR_ERR(dsi->te_gpio));
1397760cceffSInki Dae 		return PTR_ERR(dsi->te_gpio);
1398e17ddeccSYoungJun Cho 	}
1399e17ddeccSYoungJun Cho 
1400ee6c8b5aSMaíra Canal 	te_gpio_irq = gpiod_to_irq(dsi->te_gpio);
140151d1decaSHyungwon Hwang 
14020cef83a5SYoungJun Cho 	ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL,
1403a4e5eed2STian Tao 				   IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, "TE", dsi);
1404e17ddeccSYoungJun Cho 	if (ret) {
1405e17ddeccSYoungJun Cho 		dev_err(dsi->dev, "request interrupt failed with %d\n", ret);
1406ee6c8b5aSMaíra Canal 		gpiod_put(dsi->te_gpio);
1407760cceffSInki Dae 		return ret;
1408e17ddeccSYoungJun Cho 	}
1409e17ddeccSYoungJun Cho 
1410760cceffSInki Dae 	return 0;
1411e17ddeccSYoungJun Cho }
1412e17ddeccSYoungJun Cho 
1413e17ddeccSYoungJun Cho static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
1414e17ddeccSYoungJun Cho {
1415ee6c8b5aSMaíra Canal 	if (dsi->te_gpio) {
1416ee6c8b5aSMaíra Canal 		free_irq(gpiod_to_irq(dsi->te_gpio), dsi);
1417ee6c8b5aSMaíra Canal 		gpiod_put(dsi->te_gpio);
1418e17ddeccSYoungJun Cho 	}
1419e17ddeccSYoungJun Cho }
1420e17ddeccSYoungJun Cho 
142195a2441eSJagan Teki static void exynos_dsi_atomic_pre_enable(struct drm_bridge *bridge,
142295a2441eSJagan Teki 					 struct drm_bridge_state *old_bridge_state)
14237eb8f069SAndrzej Hajda {
1424f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
14257eb8f069SAndrzej Hajda 	int ret;
14267eb8f069SAndrzej Hajda 
14277eb8f069SAndrzej Hajda 	if (dsi->state & DSIM_STATE_ENABLED)
1428b6595dc7SGustavo Padovan 		return;
14297eb8f069SAndrzej Hajda 
1430445d3bedSInki Dae 	ret = pm_runtime_resume_and_get(dsi->dev);
1431445d3bedSInki Dae 	if (ret < 0) {
1432445d3bedSInki Dae 		dev_err(dsi->dev, "failed to enable DSI device.\n");
1433445d3bedSInki Dae 		return;
1434445d3bedSInki Dae 	}
1435445d3bedSInki Dae 
14360e480f6fSHyungwon Hwang 	dsi->state |= DSIM_STATE_ENABLED;
1437bb57453dSMarek Szyprowski 
1438bb57453dSMarek Szyprowski 	/*
1439bb57453dSMarek Szyprowski 	 * For Exynos-DSIM the downstream bridge, or panel are expecting
1440bb57453dSMarek Szyprowski 	 * the host initialization during DSI transfer.
1441bb57453dSMarek Szyprowski 	 */
1442bb57453dSMarek Szyprowski 	if (!exynos_dsi_hw_is_exynos(dsi->plat_data->hw_type)) {
1443bb57453dSMarek Szyprowski 		ret = exynos_dsi_init(dsi);
1444bb57453dSMarek Szyprowski 		if (ret)
1445bb57453dSMarek Szyprowski 			return;
1446bb57453dSMarek Szyprowski 	}
1447f66ff55aSBoris Brezillon }
14487eb8f069SAndrzej Hajda 
144995a2441eSJagan Teki static void exynos_dsi_atomic_enable(struct drm_bridge *bridge,
145095a2441eSJagan Teki 				     struct drm_bridge_state *old_bridge_state)
1451f9bfd326SJagan Teki {
1452f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
1453f9bfd326SJagan Teki 
14547eb8f069SAndrzej Hajda 	exynos_dsi_set_display_mode(dsi);
14557eb8f069SAndrzej Hajda 	exynos_dsi_set_display_enable(dsi, true);
14567eb8f069SAndrzej Hajda 
14570e480f6fSHyungwon Hwang 	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
1458f9bfd326SJagan Teki 
14598a08f671SMaciej Purski 	return;
14607eb8f069SAndrzej Hajda }
14617eb8f069SAndrzej Hajda 
146295a2441eSJagan Teki static void exynos_dsi_atomic_disable(struct drm_bridge *bridge,
146395a2441eSJagan Teki 				      struct drm_bridge_state *old_bridge_state)
14647eb8f069SAndrzej Hajda {
1465f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
1466b6595dc7SGustavo Padovan 
14677eb8f069SAndrzej Hajda 	if (!(dsi->state & DSIM_STATE_ENABLED))
14687eb8f069SAndrzej Hajda 		return;
14697eb8f069SAndrzej Hajda 
14700e480f6fSHyungwon Hwang 	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
1471f66ff55aSBoris Brezillon }
1472f66ff55aSBoris Brezillon 
147395a2441eSJagan Teki static void exynos_dsi_atomic_post_disable(struct drm_bridge *bridge,
147495a2441eSJagan Teki 					   struct drm_bridge_state *old_bridge_state)
1475f9bfd326SJagan Teki {
1476f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
1477f9bfd326SJagan Teki 
1478cdfb8694SAjay Kumar 	exynos_dsi_set_display_enable(dsi, false);
1479f66ff55aSBoris Brezillon 
14807eb8f069SAndrzej Hajda 	dsi->state &= ~DSIM_STATE_ENABLED;
1481ba6e4779SInki Dae 	pm_runtime_put_sync(dsi->dev);
14827eb8f069SAndrzej Hajda }
14837eb8f069SAndrzej Hajda 
148444d214a7SJagan Teki /*
148544d214a7SJagan Teki  * This pixel output formats list referenced from,
148644d214a7SJagan Teki  * AN13573 i.MX 8/RT MIPI DSI/CSI-2, Rev. 0, 21 March 2022
148744d214a7SJagan Teki  * 3.7.4 Pixel formats
148844d214a7SJagan Teki  * Table 14. DSI pixel packing formats
148944d214a7SJagan Teki  */
149044d214a7SJagan Teki static const u32 exynos_dsi_pixel_output_fmts[] = {
149144d214a7SJagan Teki 	MEDIA_BUS_FMT_YUYV10_1X20,
149244d214a7SJagan Teki 	MEDIA_BUS_FMT_YUYV12_1X24,
149344d214a7SJagan Teki 	MEDIA_BUS_FMT_UYVY8_1X16,
149444d214a7SJagan Teki 	MEDIA_BUS_FMT_RGB101010_1X30,
149544d214a7SJagan Teki 	MEDIA_BUS_FMT_RGB121212_1X36,
149644d214a7SJagan Teki 	MEDIA_BUS_FMT_RGB565_1X16,
149744d214a7SJagan Teki 	MEDIA_BUS_FMT_RGB666_1X18,
149844d214a7SJagan Teki 	MEDIA_BUS_FMT_RGB888_1X24,
149944d214a7SJagan Teki };
150044d214a7SJagan Teki 
150144d214a7SJagan Teki static bool exynos_dsi_pixel_output_fmt_supported(u32 fmt)
150244d214a7SJagan Teki {
150344d214a7SJagan Teki 	int i;
150444d214a7SJagan Teki 
150544d214a7SJagan Teki 	if (fmt == MEDIA_BUS_FMT_FIXED)
150644d214a7SJagan Teki 		return false;
150744d214a7SJagan Teki 
150844d214a7SJagan Teki 	for (i = 0; i < ARRAY_SIZE(exynos_dsi_pixel_output_fmts); i++) {
150944d214a7SJagan Teki 		if (exynos_dsi_pixel_output_fmts[i] == fmt)
151044d214a7SJagan Teki 			return true;
151144d214a7SJagan Teki 	}
151244d214a7SJagan Teki 
151344d214a7SJagan Teki 	return false;
151444d214a7SJagan Teki }
151544d214a7SJagan Teki 
151644d214a7SJagan Teki static u32 *
151744d214a7SJagan Teki exynos_dsi_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
151844d214a7SJagan Teki 				     struct drm_bridge_state *bridge_state,
151944d214a7SJagan Teki 				     struct drm_crtc_state *crtc_state,
152044d214a7SJagan Teki 				     struct drm_connector_state *conn_state,
152144d214a7SJagan Teki 				     u32 output_fmt,
152244d214a7SJagan Teki 				     unsigned int *num_input_fmts)
152344d214a7SJagan Teki {
152444d214a7SJagan Teki 	u32 *input_fmts;
152544d214a7SJagan Teki 
152644d214a7SJagan Teki 	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
152744d214a7SJagan Teki 	if (!input_fmts)
152844d214a7SJagan Teki 		return NULL;
152944d214a7SJagan Teki 
153044d214a7SJagan Teki 	if (!exynos_dsi_pixel_output_fmt_supported(output_fmt))
153144d214a7SJagan Teki 		/*
153244d214a7SJagan Teki 		 * Some bridge/display drivers are still not able to pass the
153344d214a7SJagan Teki 		 * correct format, so handle those pipelines by falling back
153444d214a7SJagan Teki 		 * to the default format till the supported formats finalized.
153544d214a7SJagan Teki 		 */
153644d214a7SJagan Teki 		output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
153744d214a7SJagan Teki 
153844d214a7SJagan Teki 	input_fmts[0] = output_fmt;
153944d214a7SJagan Teki 	*num_input_fmts = 1;
154044d214a7SJagan Teki 
154144d214a7SJagan Teki 	return input_fmts;
154244d214a7SJagan Teki }
154344d214a7SJagan Teki 
154488576e23SJagan Teki static int exynos_dsi_atomic_check(struct drm_bridge *bridge,
154588576e23SJagan Teki 				   struct drm_bridge_state *bridge_state,
154688576e23SJagan Teki 				   struct drm_crtc_state *crtc_state,
154788576e23SJagan Teki 				   struct drm_connector_state *conn_state)
154888576e23SJagan Teki {
154988576e23SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
155088576e23SJagan Teki 	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
155188576e23SJagan Teki 
155288576e23SJagan Teki 	/*
155388576e23SJagan Teki 	 * The i.MX8M Mini/Nano glue logic between LCDIF and DSIM
155488576e23SJagan Teki 	 * inverts HS/VS/DE sync signals polarity, therefore, while
155588576e23SJagan Teki 	 * i.MX 8M Mini Applications Processor Reference Manual Rev. 3, 11/2020
155688576e23SJagan Teki 	 * 13.6.3.5.2 RGB interface
155788576e23SJagan Teki 	 * i.MX 8M Nano Applications Processor Reference Manual Rev. 2, 07/2022
155888576e23SJagan Teki 	 * 13.6.2.7.2 RGB interface
155988576e23SJagan Teki 	 * both claim "Vsync, Hsync, and VDEN are active high signals.", the
156088576e23SJagan Teki 	 * LCDIF must generate inverted HS/VS/DE signals, i.e. active LOW.
156188576e23SJagan Teki 	 */
156288576e23SJagan Teki 	if (dsi->plat_data->hw_type == DSIM_TYPE_IMX8MM) {
156388576e23SJagan Teki 		adjusted_mode->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
156488576e23SJagan Teki 		adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
156588576e23SJagan Teki 	}
156688576e23SJagan Teki 
156788576e23SJagan Teki 	return 0;
156888576e23SJagan Teki }
156988576e23SJagan Teki 
1570f9bfd326SJagan Teki static void exynos_dsi_mode_set(struct drm_bridge *bridge,
1571f9bfd326SJagan Teki 				const struct drm_display_mode *mode,
1572f9bfd326SJagan Teki 				const struct drm_display_mode *adjusted_mode)
1573bd29823eSJagan Teki {
1574f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
1575bd29823eSJagan Teki 
1576bd29823eSJagan Teki 	drm_mode_copy(&dsi->mode, adjusted_mode);
1577bd29823eSJagan Teki }
1578bd29823eSJagan Teki 
1579f9bfd326SJagan Teki static int exynos_dsi_attach(struct drm_bridge *bridge,
1580f9bfd326SJagan Teki 			     enum drm_bridge_attach_flags flags)
1581f9bfd326SJagan Teki {
1582f9bfd326SJagan Teki 	struct exynos_dsi *dsi = bridge_to_dsi(bridge);
1583f9bfd326SJagan Teki 
15841a1ce789SJagan Teki 	return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
15851a1ce789SJagan Teki 				 flags);
1586f9bfd326SJagan Teki }
1587f9bfd326SJagan Teki 
1588f9bfd326SJagan Teki static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
158995a2441eSJagan Teki 	.atomic_duplicate_state		= drm_atomic_helper_bridge_duplicate_state,
159095a2441eSJagan Teki 	.atomic_destroy_state		= drm_atomic_helper_bridge_destroy_state,
159195a2441eSJagan Teki 	.atomic_reset			= drm_atomic_helper_bridge_reset,
159244d214a7SJagan Teki 	.atomic_get_input_bus_fmts	= exynos_dsi_atomic_get_input_bus_fmts,
159388576e23SJagan Teki 	.atomic_check			= exynos_dsi_atomic_check,
159495a2441eSJagan Teki 	.atomic_pre_enable		= exynos_dsi_atomic_pre_enable,
159595a2441eSJagan Teki 	.atomic_enable			= exynos_dsi_atomic_enable,
159695a2441eSJagan Teki 	.atomic_disable			= exynos_dsi_atomic_disable,
159795a2441eSJagan Teki 	.atomic_post_disable		= exynos_dsi_atomic_post_disable,
1598aee039e6SJagan Teki 	.mode_set			= exynos_dsi_mode_set,
1599f9bfd326SJagan Teki 	.attach				= exynos_dsi_attach,
16007eb8f069SAndrzej Hajda };
16017eb8f069SAndrzej Hajda 
1602295e7954SAndrzej Hajda static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
1603295e7954SAndrzej Hajda 				  struct mipi_dsi_device *device)
1604295e7954SAndrzej Hajda {
1605295e7954SAndrzej Hajda 	struct exynos_dsi *dsi = host_to_dsi(host);
1606*70e360f9SJagan Teki 	const struct exynos_dsi_plat_data *pdata = dsi->plat_data;
1607711c7adcSJagan Teki 	struct device *dev = dsi->dev;
1608e39a82bfSJagan Teki 	struct device_node *np = dev->of_node;
1609e39a82bfSJagan Teki 	struct device_node *remote;
1610ea16c74cSJagan Teki 	struct drm_panel *panel;
1611711c7adcSJagan Teki 	int ret;
16126afb7721SMaciej Purski 
1613e39a82bfSJagan Teki 	/*
1614e39a82bfSJagan Teki 	 * Devices can also be child nodes when we also control that device
1615e39a82bfSJagan Teki 	 * through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
1616e39a82bfSJagan Teki 	 *
1617e39a82bfSJagan Teki 	 * Lookup for a child node of the given parent that isn't either port
1618e39a82bfSJagan Teki 	 * or ports.
1619e39a82bfSJagan Teki 	 */
1620e39a82bfSJagan Teki 	for_each_available_child_of_node(np, remote) {
1621e39a82bfSJagan Teki 		if (of_node_name_eq(remote, "port") ||
1622e39a82bfSJagan Teki 		    of_node_name_eq(remote, "ports"))
1623e39a82bfSJagan Teki 			continue;
1624e39a82bfSJagan Teki 
1625e39a82bfSJagan Teki 		goto of_find_panel_or_bridge;
1626e39a82bfSJagan Teki 	}
1627e39a82bfSJagan Teki 
1628e39a82bfSJagan Teki 	/*
1629e39a82bfSJagan Teki 	 * of_graph_get_remote_node() produces a noisy error message if port
1630e39a82bfSJagan Teki 	 * node isn't found and the absence of the port is a legit case here,
1631e39a82bfSJagan Teki 	 * so at first we silently check whether graph presents in the
1632e39a82bfSJagan Teki 	 * device-tree node.
1633e39a82bfSJagan Teki 	 */
1634e39a82bfSJagan Teki 	if (!of_graph_is_present(np))
1635e39a82bfSJagan Teki 		return -ENODEV;
1636e39a82bfSJagan Teki 
1637e39a82bfSJagan Teki 	remote = of_graph_get_remote_node(np, 1, 0);
1638e39a82bfSJagan Teki 
1639e39a82bfSJagan Teki of_find_panel_or_bridge:
1640e39a82bfSJagan Teki 	if (!remote)
1641e39a82bfSJagan Teki 		return -ENODEV;
1642e39a82bfSJagan Teki 
1643e39a82bfSJagan Teki 	panel = of_drm_find_panel(remote);
1644ea16c74cSJagan Teki 	if (!IS_ERR(panel)) {
1645ea16c74cSJagan Teki 		dsi->out_bridge = devm_drm_panel_bridge_add(dev, panel);
1646ea16c74cSJagan Teki 	} else {
1647e39a82bfSJagan Teki 		dsi->out_bridge = of_drm_find_bridge(remote);
1648ea16c74cSJagan Teki 		if (!dsi->out_bridge)
1649ea16c74cSJagan Teki 			dsi->out_bridge = ERR_PTR(-EINVAL);
1650ea16c74cSJagan Teki 	}
1651ea16c74cSJagan Teki 
1652e39a82bfSJagan Teki 	of_node_put(remote);
1653e39a82bfSJagan Teki 
1654711c7adcSJagan Teki 	if (IS_ERR(dsi->out_bridge)) {
1655711c7adcSJagan Teki 		ret = PTR_ERR(dsi->out_bridge);
1656711c7adcSJagan Teki 		DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret);
16576afb7721SMaciej Purski 		return ret;
16586afb7721SMaciej Purski 	}
16596afb7721SMaciej Purski 
1660711c7adcSJagan Teki 	DRM_DEV_INFO(dev, "Attached %s device\n", device->name);
1661711c7adcSJagan Teki 
1662f9bfd326SJagan Teki 	drm_bridge_add(&dsi->bridge);
1663f9bfd326SJagan Teki 
1664295e7954SAndrzej Hajda 	/*
1665295e7954SAndrzej Hajda 	 * This is a temporary solution and should be made by more generic way.
1666295e7954SAndrzej Hajda 	 *
1667295e7954SAndrzej Hajda 	 * If attached panel device is for command mode one, dsi should register
1668295e7954SAndrzej Hajda 	 * TE interrupt handler.
1669295e7954SAndrzej Hajda 	 */
1670295e7954SAndrzej Hajda 	if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) {
1671711c7adcSJagan Teki 		ret = exynos_dsi_register_te_irq(dsi, &device->dev);
1672295e7954SAndrzej Hajda 		if (ret)
1673295e7954SAndrzej Hajda 			return ret;
1674295e7954SAndrzej Hajda 	}
1675295e7954SAndrzej Hajda 
1676*70e360f9SJagan Teki 	if (pdata->host_ops && pdata->host_ops->attach) {
1677*70e360f9SJagan Teki 		ret = pdata->host_ops->attach(dsi, device);
1678*70e360f9SJagan Teki 		if (ret)
1679*70e360f9SJagan Teki 			return ret;
1680*70e360f9SJagan Teki 	}
1681295e7954SAndrzej Hajda 
1682295e7954SAndrzej Hajda 	dsi->lanes = device->lanes;
1683295e7954SAndrzej Hajda 	dsi->format = device->format;
1684295e7954SAndrzej Hajda 	dsi->mode_flags = device->mode_flags;
1685295e7954SAndrzej Hajda 
1686295e7954SAndrzej Hajda 	return 0;
1687295e7954SAndrzej Hajda }
1688295e7954SAndrzej Hajda 
1689295e7954SAndrzej Hajda static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
1690295e7954SAndrzej Hajda 				  struct mipi_dsi_device *device)
1691295e7954SAndrzej Hajda {
1692295e7954SAndrzej Hajda 	struct exynos_dsi *dsi = host_to_dsi(host);
1693*70e360f9SJagan Teki 	const struct exynos_dsi_plat_data *pdata = dsi->plat_data;
1694295e7954SAndrzej Hajda 
16956afb7721SMaciej Purski 	dsi->out_bridge = NULL;
1696295e7954SAndrzej Hajda 
1697*70e360f9SJagan Teki 	if (pdata->host_ops && pdata->host_ops->detach)
1698*70e360f9SJagan Teki 		pdata->host_ops->detach(dsi, device);
1699295e7954SAndrzej Hajda 
1700295e7954SAndrzej Hajda 	exynos_dsi_unregister_te_irq(dsi);
1701295e7954SAndrzej Hajda 
1702f9bfd326SJagan Teki 	drm_bridge_remove(&dsi->bridge);
1703f9bfd326SJagan Teki 
1704295e7954SAndrzej Hajda 	return 0;
1705295e7954SAndrzej Hajda }
1706295e7954SAndrzej Hajda 
1707295e7954SAndrzej Hajda static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
1708295e7954SAndrzej Hajda 					 const struct mipi_dsi_msg *msg)
1709295e7954SAndrzej Hajda {
1710295e7954SAndrzej Hajda 	struct exynos_dsi *dsi = host_to_dsi(host);
1711295e7954SAndrzej Hajda 	struct exynos_dsi_transfer xfer;
1712295e7954SAndrzej Hajda 	int ret;
1713295e7954SAndrzej Hajda 
1714295e7954SAndrzej Hajda 	if (!(dsi->state & DSIM_STATE_ENABLED))
1715295e7954SAndrzej Hajda 		return -EINVAL;
1716295e7954SAndrzej Hajda 
1717295e7954SAndrzej Hajda 	ret = exynos_dsi_init(dsi);
1718295e7954SAndrzej Hajda 	if (ret)
1719295e7954SAndrzej Hajda 		return ret;
1720295e7954SAndrzej Hajda 
1721295e7954SAndrzej Hajda 	ret = mipi_dsi_create_packet(&xfer.packet, msg);
1722295e7954SAndrzej Hajda 	if (ret < 0)
1723295e7954SAndrzej Hajda 		return ret;
1724295e7954SAndrzej Hajda 
1725295e7954SAndrzej Hajda 	xfer.rx_len = msg->rx_len;
1726295e7954SAndrzej Hajda 	xfer.rx_payload = msg->rx_buf;
1727295e7954SAndrzej Hajda 	xfer.flags = msg->flags;
1728295e7954SAndrzej Hajda 
1729295e7954SAndrzej Hajda 	ret = exynos_dsi_transfer(dsi, &xfer);
1730295e7954SAndrzej Hajda 	return (ret < 0) ? ret : xfer.rx_done;
1731295e7954SAndrzej Hajda }
1732295e7954SAndrzej Hajda 
1733295e7954SAndrzej Hajda static const struct mipi_dsi_host_ops exynos_dsi_ops = {
1734295e7954SAndrzej Hajda 	.attach = exynos_dsi_host_attach,
1735295e7954SAndrzej Hajda 	.detach = exynos_dsi_host_detach,
1736295e7954SAndrzej Hajda 	.transfer = exynos_dsi_host_transfer,
1737295e7954SAndrzej Hajda };
1738295e7954SAndrzej Hajda 
17397eb8f069SAndrzej Hajda static int exynos_dsi_of_read_u32(const struct device_node *np,
17407eb8f069SAndrzej Hajda 				  const char *propname, u32 *out_value)
17417eb8f069SAndrzej Hajda {
17427eb8f069SAndrzej Hajda 	int ret = of_property_read_u32(np, propname, out_value);
17437eb8f069SAndrzej Hajda 
17447eb8f069SAndrzej Hajda 	if (ret < 0)
17454bf99144SRob Herring 		pr_err("%pOF: failed to get '%s' property\n", np, propname);
17467eb8f069SAndrzej Hajda 
17477eb8f069SAndrzej Hajda 	return ret;
17487eb8f069SAndrzej Hajda }
17497eb8f069SAndrzej Hajda 
17507eb8f069SAndrzej Hajda static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
17517eb8f069SAndrzej Hajda {
17527eb8f069SAndrzej Hajda 	struct device *dev = dsi->dev;
17537eb8f069SAndrzej Hajda 	struct device_node *node = dev->of_node;
17547eb8f069SAndrzej Hajda 	int ret;
17557eb8f069SAndrzej Hajda 
17567eb8f069SAndrzej Hajda 	ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
17577eb8f069SAndrzej Hajda 				     &dsi->pll_clk_rate);
17587eb8f069SAndrzej Hajda 	if (ret < 0)
17597eb8f069SAndrzej Hajda 		return ret;
17607eb8f069SAndrzej Hajda 
1761f2921d8cSHoegeun Kwon 	ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency",
17627eb8f069SAndrzej Hajda 				     &dsi->burst_clk_rate);
17637eb8f069SAndrzej Hajda 	if (ret < 0)
1764f2921d8cSHoegeun Kwon 		return ret;
17657eb8f069SAndrzej Hajda 
1766f2921d8cSHoegeun Kwon 	ret = exynos_dsi_of_read_u32(node, "samsung,esc-clock-frequency",
17677eb8f069SAndrzej Hajda 				     &dsi->esc_clk_rate);
1768f5f3b9baSHyungwon Hwang 	if (ret < 0)
1769f2921d8cSHoegeun Kwon 		return ret;
1770f5f3b9baSHyungwon Hwang 
1771f2921d8cSHoegeun Kwon 	return 0;
17727eb8f069SAndrzej Hajda }
17737eb8f069SAndrzej Hajda 
1774*70e360f9SJagan Teki static int exynos_dsim_host_attach(struct exynos_dsi *dsim,
1775*70e360f9SJagan Teki 				   struct mipi_dsi_device *device)
1776*70e360f9SJagan Teki {
1777*70e360f9SJagan Teki 	struct exynos_dsi_enc *dsi_enc = dsim->priv;
1778*70e360f9SJagan Teki 	struct drm_encoder *encoder = &dsi_enc->encoder;
1779*70e360f9SJagan Teki 	struct drm_device *drm = encoder->dev;
1780*70e360f9SJagan Teki 
1781*70e360f9SJagan Teki 	drm_bridge_attach(encoder, &dsim->bridge,
1782*70e360f9SJagan Teki 			  list_first_entry_or_null(&encoder->bridge_chain,
1783*70e360f9SJagan Teki 						   struct drm_bridge,
1784*70e360f9SJagan Teki 						   chain_node), 0);
1785*70e360f9SJagan Teki 
1786*70e360f9SJagan Teki 	mutex_lock(&drm->mode_config.mutex);
1787*70e360f9SJagan Teki 
1788*70e360f9SJagan Teki 	dsim->lanes = device->lanes;
1789*70e360f9SJagan Teki 	dsim->format = device->format;
1790*70e360f9SJagan Teki 	dsim->mode_flags = device->mode_flags;
1791*70e360f9SJagan Teki 	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
1792*70e360f9SJagan Teki 			!(dsim->mode_flags & MIPI_DSI_MODE_VIDEO);
1793*70e360f9SJagan Teki 
1794*70e360f9SJagan Teki 	mutex_unlock(&drm->mode_config.mutex);
1795*70e360f9SJagan Teki 
1796*70e360f9SJagan Teki 	if (drm->mode_config.poll_enabled)
1797*70e360f9SJagan Teki 		drm_kms_helper_hotplug_event(drm);
1798*70e360f9SJagan Teki 
1799*70e360f9SJagan Teki 	return 0;
1800*70e360f9SJagan Teki }
1801*70e360f9SJagan Teki 
1802*70e360f9SJagan Teki static void exynos_dsim_host_detach(struct exynos_dsi *dsim,
1803*70e360f9SJagan Teki 				    struct mipi_dsi_device *device)
1804*70e360f9SJagan Teki {
1805*70e360f9SJagan Teki 	struct exynos_dsi_enc *dsi_enc = dsim->priv;
1806*70e360f9SJagan Teki 	struct drm_device *drm = dsi_enc->encoder.dev;
1807*70e360f9SJagan Teki 
1808*70e360f9SJagan Teki 	if (drm->mode_config.poll_enabled)
1809*70e360f9SJagan Teki 		drm_kms_helper_hotplug_event(drm);
1810*70e360f9SJagan Teki }
1811*70e360f9SJagan Teki 
1812f37cd5e8SInki Dae static int exynos_dsi_bind(struct device *dev, struct device *master,
1813f37cd5e8SInki Dae 				void *data)
1814f37cd5e8SInki Dae {
1815e11e6df2SMichael Tretter 	struct exynos_dsi *dsi = dev_get_drvdata(dev);
1816*70e360f9SJagan Teki 	struct exynos_dsi_enc *dsi_enc = dsi->priv;
1817*70e360f9SJagan Teki 	struct drm_encoder *encoder = &dsi_enc->encoder;
1818f37cd5e8SInki Dae 	struct drm_device *drm_dev = data;
1819f37cd5e8SInki Dae 	int ret;
1820f37cd5e8SInki Dae 
18213e1fe32dSThomas Zimmermann 	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
18222b8376c8SGustavo Padovan 
18231ca582f1SAndrzej Hajda 	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
18241ca582f1SAndrzej Hajda 	if (ret < 0)
18251ca582f1SAndrzej Hajda 		return ret;
18261ca582f1SAndrzej Hajda 
1827f37cd5e8SInki Dae 	return mipi_dsi_host_register(&dsi->dsi_host);
1828f37cd5e8SInki Dae }
1829f37cd5e8SInki Dae 
1830f37cd5e8SInki Dae static void exynos_dsi_unbind(struct device *dev, struct device *master,
1831f37cd5e8SInki Dae 				void *data)
1832f37cd5e8SInki Dae {
1833e11e6df2SMichael Tretter 	struct exynos_dsi *dsi = dev_get_drvdata(dev);
1834f37cd5e8SInki Dae 
1835*70e360f9SJagan Teki 	dsi->bridge.funcs->atomic_disable(&dsi->bridge, NULL);
1836f37cd5e8SInki Dae 
18370ae46015SAndrzej Hajda 	mipi_dsi_host_unregister(&dsi->dsi_host);
1838f37cd5e8SInki Dae }
1839f37cd5e8SInki Dae 
1840f37cd5e8SInki Dae static const struct component_ops exynos_dsi_component_ops = {
1841f37cd5e8SInki Dae 	.bind	= exynos_dsi_bind,
1842f37cd5e8SInki Dae 	.unbind	= exynos_dsi_unbind,
1843f37cd5e8SInki Dae };
1844f37cd5e8SInki Dae 
1845*70e360f9SJagan Teki static int exynos_dsi_register_host(struct exynos_dsi *dsim)
1846*70e360f9SJagan Teki {
1847*70e360f9SJagan Teki 	struct exynos_dsi_enc *dsi_enc;
1848*70e360f9SJagan Teki 
1849*70e360f9SJagan Teki 	dsi_enc = devm_kzalloc(dsim->dev, sizeof(*dsi_enc), GFP_KERNEL);
1850*70e360f9SJagan Teki 	if (!dsi_enc)
1851*70e360f9SJagan Teki 		return -ENOMEM;
1852*70e360f9SJagan Teki 
1853*70e360f9SJagan Teki 	dsim->priv = dsi_enc;
1854*70e360f9SJagan Teki 	dsim->bridge.pre_enable_prev_first = true;
1855*70e360f9SJagan Teki 
1856*70e360f9SJagan Teki 	return component_add(dsim->dev, &exynos_dsi_component_ops);
1857*70e360f9SJagan Teki }
1858*70e360f9SJagan Teki 
1859*70e360f9SJagan Teki static void exynos_dsi_unregister_host(struct exynos_dsi *dsim)
1860*70e360f9SJagan Teki {
1861*70e360f9SJagan Teki 	component_del(dsim->dev, &exynos_dsi_component_ops);
1862*70e360f9SJagan Teki }
1863*70e360f9SJagan Teki 
1864*70e360f9SJagan Teki static int generic_dsim_register_host(struct exynos_dsi *dsim)
1865*70e360f9SJagan Teki {
1866*70e360f9SJagan Teki 	return mipi_dsi_host_register(&dsim->dsi_host);
1867*70e360f9SJagan Teki }
1868*70e360f9SJagan Teki 
1869*70e360f9SJagan Teki static void generic_dsim_unregister_host(struct exynos_dsi *dsim)
1870*70e360f9SJagan Teki {
1871*70e360f9SJagan Teki 	mipi_dsi_host_unregister(&dsim->dsi_host);
1872*70e360f9SJagan Teki }
1873*70e360f9SJagan Teki 
1874*70e360f9SJagan Teki static const struct exynos_dsim_host_ops generic_dsim_host_ops = {
1875*70e360f9SJagan Teki 	.register_host = generic_dsim_register_host,
1876*70e360f9SJagan Teki 	.unregister_host = generic_dsim_unregister_host,
1877*70e360f9SJagan Teki };
1878*70e360f9SJagan Teki 
1879184f37e5SJagan Teki static const struct drm_bridge_timings dsim_bridge_timings_de_low = {
1880184f37e5SJagan Teki 	.input_bus_flags = DRM_BUS_FLAG_DE_LOW,
1881184f37e5SJagan Teki };
1882184f37e5SJagan Teki 
18837eb8f069SAndrzej Hajda static int exynos_dsi_probe(struct platform_device *pdev)
18847eb8f069SAndrzej Hajda {
18852900c69cSAndrzej Hajda 	struct device *dev = &pdev->dev;
18867eb8f069SAndrzej Hajda 	struct exynos_dsi *dsi;
18870ff03fd1SHyungwon Hwang 	int ret, i;
18887eb8f069SAndrzej Hajda 
18892900c69cSAndrzej Hajda 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
18902900c69cSAndrzej Hajda 	if (!dsi)
18912900c69cSAndrzej Hajda 		return -ENOMEM;
18922900c69cSAndrzej Hajda 
18937eb8f069SAndrzej Hajda 	init_completion(&dsi->completed);
18947eb8f069SAndrzej Hajda 	spin_lock_init(&dsi->transfer_lock);
18957eb8f069SAndrzej Hajda 	INIT_LIST_HEAD(&dsi->transfer_list);
18967eb8f069SAndrzej Hajda 
18977eb8f069SAndrzej Hajda 	dsi->dsi_host.ops = &exynos_dsi_ops;
1898e2d2a1e0SAndrzej Hajda 	dsi->dsi_host.dev = dev;
18997eb8f069SAndrzej Hajda 
1900e2d2a1e0SAndrzej Hajda 	dsi->dev = dev;
19017e9f0d32SJagan Teki 	dsi->plat_data = of_device_get_match_data(dev);
19027e9f0d32SJagan Teki 	dsi->driver_data = exynos_dsi_types[dsi->plat_data->hw_type];
19037eb8f069SAndrzej Hajda 
19047eb8f069SAndrzej Hajda 	dsi->supplies[0].supply = "vddcore";
19057eb8f069SAndrzej Hajda 	dsi->supplies[1].supply = "vddio";
1906e2d2a1e0SAndrzej Hajda 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
19077eb8f069SAndrzej Hajda 				      dsi->supplies);
190873bb394cSKrzysztof Kozlowski 	if (ret)
190973bb394cSKrzysztof Kozlowski 		return dev_err_probe(dev, ret, "failed to get regulators\n");
19107eb8f069SAndrzej Hajda 
1911a86854d0SKees Cook 	dsi->clks = devm_kcalloc(dev,
1912a86854d0SKees Cook 			dsi->driver_data->num_clks, sizeof(*dsi->clks),
19130ff03fd1SHyungwon Hwang 			GFP_KERNEL);
1914e6f988a4SHyungwon Hwang 	if (!dsi->clks)
1915e6f988a4SHyungwon Hwang 		return -ENOMEM;
1916e6f988a4SHyungwon Hwang 
19170ff03fd1SHyungwon Hwang 	for (i = 0; i < dsi->driver_data->num_clks; i++) {
19180ff03fd1SHyungwon Hwang 		dsi->clks[i] = devm_clk_get(dev, clk_names[i]);
19190ff03fd1SHyungwon Hwang 		if (IS_ERR(dsi->clks[i])) {
19200ff03fd1SHyungwon Hwang 			if (strcmp(clk_names[i], "sclk_mipi") == 0) {
1921c0fd99d6SMarek Szyprowski 				dsi->clks[i] = devm_clk_get(dev,
1922c0fd99d6SMarek Szyprowski 							OLD_SCLK_MIPI_CLK_NAME);
1923c0fd99d6SMarek Szyprowski 				if (!IS_ERR(dsi->clks[i]))
19240ff03fd1SHyungwon Hwang 					continue;
19257eb8f069SAndrzej Hajda 			}
19267eb8f069SAndrzej Hajda 
19270ff03fd1SHyungwon Hwang 			dev_info(dev, "failed to get the clock: %s\n",
19280ff03fd1SHyungwon Hwang 					clk_names[i]);
19290ff03fd1SHyungwon Hwang 			return PTR_ERR(dsi->clks[i]);
19300ff03fd1SHyungwon Hwang 		}
19317eb8f069SAndrzej Hajda 	}
19327eb8f069SAndrzej Hajda 
193317ac76e0SCai Huoqing 	dsi->reg_base = devm_platform_ioremap_resource(pdev, 0);
193404562956SZhen Lei 	if (IS_ERR(dsi->reg_base))
193586650408SAndrzej Hajda 		return PTR_ERR(dsi->reg_base);
19367eb8f069SAndrzej Hajda 
19379528af4aSJagan Teki 	dsi->phy = devm_phy_optional_get(dev, "dsim");
19387eb8f069SAndrzej Hajda 	if (IS_ERR(dsi->phy)) {
1939e2d2a1e0SAndrzej Hajda 		dev_info(dev, "failed to get dsim phy\n");
194086650408SAndrzej Hajda 		return PTR_ERR(dsi->phy);
19417eb8f069SAndrzej Hajda 	}
19427eb8f069SAndrzej Hajda 
19437eb8f069SAndrzej Hajda 	dsi->irq = platform_get_irq(pdev, 0);
1944fdd79b0dSMarkus Elfring 	if (dsi->irq < 0)
194586650408SAndrzej Hajda 		return dsi->irq;
19467eb8f069SAndrzej Hajda 
1947e2d2a1e0SAndrzej Hajda 	ret = devm_request_threaded_irq(dev, dsi->irq, NULL,
1948a4e5eed2STian Tao 					exynos_dsi_irq,
1949a4e5eed2STian Tao 					IRQF_ONESHOT | IRQF_NO_AUTOEN,
1950e2d2a1e0SAndrzej Hajda 					dev_name(dev), dsi);
19517eb8f069SAndrzej Hajda 	if (ret) {
1952e2d2a1e0SAndrzej Hajda 		dev_err(dev, "failed to request dsi irq\n");
195386650408SAndrzej Hajda 		return ret;
19547eb8f069SAndrzej Hajda 	}
19557eb8f069SAndrzej Hajda 
1956547a7348SChristophe JAILLET 	ret = exynos_dsi_parse_dt(dsi);
1957547a7348SChristophe JAILLET 	if (ret)
1958547a7348SChristophe JAILLET 		return ret;
1959547a7348SChristophe JAILLET 
1960e11e6df2SMichael Tretter 	platform_set_drvdata(pdev, dsi);
19617eb8f069SAndrzej Hajda 
1962ba6e4779SInki Dae 	pm_runtime_enable(dev);
1963ba6e4779SInki Dae 
1964f9bfd326SJagan Teki 	dsi->bridge.funcs = &exynos_dsi_bridge_funcs;
1965f9bfd326SJagan Teki 	dsi->bridge.of_node = dev->of_node;
1966f9bfd326SJagan Teki 	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
19671a1ce789SJagan Teki 	dsi->bridge.pre_enable_prev_first = true;
1968f9bfd326SJagan Teki 
1969184f37e5SJagan Teki 	/* DE_LOW: i.MX8M Mini/Nano LCDIF-DSIM glue logic inverts HS/VS/DE */
1970184f37e5SJagan Teki 	if (dsi->plat_data->hw_type == DSIM_TYPE_IMX8MM)
1971184f37e5SJagan Teki 		dsi->bridge.timings = &dsim_bridge_timings_de_low;
1972184f37e5SJagan Teki 
1973*70e360f9SJagan Teki 	if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host)
1974*70e360f9SJagan Teki 		ret = dsi->plat_data->host_ops->register_host(dsi);
1975*70e360f9SJagan Teki 
1976547a7348SChristophe JAILLET 	if (ret)
1977547a7348SChristophe JAILLET 		goto err_disable_runtime;
1978547a7348SChristophe JAILLET 
1979547a7348SChristophe JAILLET 	return 0;
1980547a7348SChristophe JAILLET 
1981547a7348SChristophe JAILLET err_disable_runtime:
1982547a7348SChristophe JAILLET 	pm_runtime_disable(dev);
1983547a7348SChristophe JAILLET 
1984547a7348SChristophe JAILLET 	return ret;
19857eb8f069SAndrzej Hajda }
19867eb8f069SAndrzej Hajda 
19877eb8f069SAndrzej Hajda static int exynos_dsi_remove(struct platform_device *pdev)
19887eb8f069SAndrzej Hajda {
1989ba6e4779SInki Dae 	pm_runtime_disable(&pdev->dev);
1990ba6e4779SInki Dae 
1991df5225bcSInki Dae 	component_del(&pdev->dev, &exynos_dsi_component_ops);
1992df5225bcSInki Dae 
19937eb8f069SAndrzej Hajda 	return 0;
19947eb8f069SAndrzej Hajda }
19957eb8f069SAndrzej Hajda 
1996010848a7SArnd Bergmann static int __maybe_unused exynos_dsi_suspend(struct device *dev)
1997ba6e4779SInki Dae {
1998e11e6df2SMichael Tretter 	struct exynos_dsi *dsi = dev_get_drvdata(dev);
19992154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
2000ba6e4779SInki Dae 	int ret, i;
2001ba6e4779SInki Dae 
2002ba6e4779SInki Dae 	usleep_range(10000, 20000);
2003ba6e4779SInki Dae 
2004ba6e4779SInki Dae 	if (dsi->state & DSIM_STATE_INITIALIZED) {
2005ba6e4779SInki Dae 		dsi->state &= ~DSIM_STATE_INITIALIZED;
2006ba6e4779SInki Dae 
2007ba6e4779SInki Dae 		exynos_dsi_disable_clock(dsi);
2008ba6e4779SInki Dae 
2009ba6e4779SInki Dae 		exynos_dsi_disable_irq(dsi);
2010ba6e4779SInki Dae 	}
2011ba6e4779SInki Dae 
2012ba6e4779SInki Dae 	dsi->state &= ~DSIM_STATE_CMD_LPM;
2013ba6e4779SInki Dae 
2014ba6e4779SInki Dae 	phy_power_off(dsi->phy);
2015ba6e4779SInki Dae 
2016ba6e4779SInki Dae 	for (i = driver_data->num_clks - 1; i > -1; i--)
2017ba6e4779SInki Dae 		clk_disable_unprepare(dsi->clks[i]);
2018ba6e4779SInki Dae 
2019ba6e4779SInki Dae 	ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
2020ba6e4779SInki Dae 	if (ret < 0)
2021ba6e4779SInki Dae 		dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
2022ba6e4779SInki Dae 
2023ba6e4779SInki Dae 	return 0;
2024ba6e4779SInki Dae }
2025ba6e4779SInki Dae 
2026010848a7SArnd Bergmann static int __maybe_unused exynos_dsi_resume(struct device *dev)
2027ba6e4779SInki Dae {
2028e11e6df2SMichael Tretter 	struct exynos_dsi *dsi = dev_get_drvdata(dev);
20292154ac92SMarek Szyprowski 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
2030ba6e4779SInki Dae 	int ret, i;
2031ba6e4779SInki Dae 
2032ba6e4779SInki Dae 	ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
2033ba6e4779SInki Dae 	if (ret < 0) {
2034ba6e4779SInki Dae 		dev_err(dsi->dev, "cannot enable regulators %d\n", ret);
2035ba6e4779SInki Dae 		return ret;
2036ba6e4779SInki Dae 	}
2037ba6e4779SInki Dae 
2038ba6e4779SInki Dae 	for (i = 0; i < driver_data->num_clks; i++) {
2039ba6e4779SInki Dae 		ret = clk_prepare_enable(dsi->clks[i]);
2040ba6e4779SInki Dae 		if (ret < 0)
2041ba6e4779SInki Dae 			goto err_clk;
2042ba6e4779SInki Dae 	}
2043ba6e4779SInki Dae 
2044ba6e4779SInki Dae 	ret = phy_power_on(dsi->phy);
2045ba6e4779SInki Dae 	if (ret < 0) {
2046ba6e4779SInki Dae 		dev_err(dsi->dev, "cannot enable phy %d\n", ret);
2047ba6e4779SInki Dae 		goto err_clk;
2048ba6e4779SInki Dae 	}
2049ba6e4779SInki Dae 
2050ba6e4779SInki Dae 	return 0;
2051ba6e4779SInki Dae 
2052ba6e4779SInki Dae err_clk:
2053ba6e4779SInki Dae 	while (--i > -1)
2054ba6e4779SInki Dae 		clk_disable_unprepare(dsi->clks[i]);
2055ba6e4779SInki Dae 	regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
2056ba6e4779SInki Dae 
2057ba6e4779SInki Dae 	return ret;
2058ba6e4779SInki Dae }
2059ba6e4779SInki Dae 
2060ba6e4779SInki Dae static const struct dev_pm_ops exynos_dsi_pm_ops = {
2061ba6e4779SInki Dae 	SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
20627e915746SMarek Szyprowski 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
20637e915746SMarek Szyprowski 				pm_runtime_force_resume)
2064ba6e4779SInki Dae };
2065ba6e4779SInki Dae 
2066*70e360f9SJagan Teki static const struct exynos_dsim_host_ops exynos_dsi_host_ops = {
2067*70e360f9SJagan Teki 	.register_host = exynos_dsi_register_host,
2068*70e360f9SJagan Teki 	.unregister_host = exynos_dsi_unregister_host,
2069*70e360f9SJagan Teki 	.attach = exynos_dsim_host_attach,
2070*70e360f9SJagan Teki 	.detach = exynos_dsim_host_detach,
2071*70e360f9SJagan Teki };
2072*70e360f9SJagan Teki 
20737e9f0d32SJagan Teki static const struct exynos_dsi_plat_data exynos3250_dsi_pdata = {
20747e9f0d32SJagan Teki 	.hw_type = DSIM_TYPE_EXYNOS3250,
2075*70e360f9SJagan Teki 	.host_ops = &exynos_dsi_host_ops,
20767e9f0d32SJagan Teki };
20777e9f0d32SJagan Teki 
20787e9f0d32SJagan Teki static const struct exynos_dsi_plat_data exynos4210_dsi_pdata = {
20797e9f0d32SJagan Teki 	.hw_type = DSIM_TYPE_EXYNOS4210,
2080*70e360f9SJagan Teki 	.host_ops = &exynos_dsi_host_ops,
20817e9f0d32SJagan Teki };
20827e9f0d32SJagan Teki 
20837e9f0d32SJagan Teki static const struct exynos_dsi_plat_data exynos5410_dsi_pdata = {
20847e9f0d32SJagan Teki 	.hw_type = DSIM_TYPE_EXYNOS5410,
2085*70e360f9SJagan Teki 	.host_ops = &exynos_dsi_host_ops,
20867e9f0d32SJagan Teki };
20877e9f0d32SJagan Teki 
20887e9f0d32SJagan Teki static const struct exynos_dsi_plat_data exynos5422_dsi_pdata = {
20897e9f0d32SJagan Teki 	.hw_type = DSIM_TYPE_EXYNOS5422,
2090*70e360f9SJagan Teki 	.host_ops = &exynos_dsi_host_ops,
20917e9f0d32SJagan Teki };
20927e9f0d32SJagan Teki 
20937e9f0d32SJagan Teki static const struct exynos_dsi_plat_data exynos5433_dsi_pdata = {
20947e9f0d32SJagan Teki 	.hw_type = DSIM_TYPE_EXYNOS5433,
2095*70e360f9SJagan Teki 	.host_ops = &exynos_dsi_host_ops,
20967e9f0d32SJagan Teki };
20977e9f0d32SJagan Teki 
20987e9f0d32SJagan Teki static const struct of_device_id exynos_dsi_of_match[] = {
20997e9f0d32SJagan Teki 	{
21007e9f0d32SJagan Teki 		.compatible = "samsung,exynos3250-mipi-dsi",
21017e9f0d32SJagan Teki 		.data = &exynos3250_dsi_pdata,
21027e9f0d32SJagan Teki 	},
21037e9f0d32SJagan Teki 	{
21047e9f0d32SJagan Teki 		.compatible = "samsung,exynos4210-mipi-dsi",
21057e9f0d32SJagan Teki 		.data = &exynos4210_dsi_pdata,
21067e9f0d32SJagan Teki 	},
21077e9f0d32SJagan Teki 	{
21087e9f0d32SJagan Teki 		.compatible = "samsung,exynos5410-mipi-dsi",
21097e9f0d32SJagan Teki 		.data = &exynos5410_dsi_pdata,
21107e9f0d32SJagan Teki 	},
21117e9f0d32SJagan Teki 	{
21127e9f0d32SJagan Teki 		.compatible = "samsung,exynos5422-mipi-dsi",
21137e9f0d32SJagan Teki 		.data = &exynos5422_dsi_pdata,
21147e9f0d32SJagan Teki 	},
21157e9f0d32SJagan Teki 	{
21167e9f0d32SJagan Teki 		.compatible = "samsung,exynos5433-mipi-dsi",
21177e9f0d32SJagan Teki 		.data = &exynos5433_dsi_pdata,
21187e9f0d32SJagan Teki 	},
21197e9f0d32SJagan Teki 	{ /* sentinel. */ }
21207e9f0d32SJagan Teki };
21217e9f0d32SJagan Teki MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
21227e9f0d32SJagan Teki 
21237eb8f069SAndrzej Hajda struct platform_driver dsi_driver = {
21247eb8f069SAndrzej Hajda 	.probe = exynos_dsi_probe,
21257eb8f069SAndrzej Hajda 	.remove = exynos_dsi_remove,
21267eb8f069SAndrzej Hajda 	.driver = {
21277eb8f069SAndrzej Hajda 		   .name = "exynos-dsi",
21287eb8f069SAndrzej Hajda 		   .owner = THIS_MODULE,
2129ba6e4779SInki Dae 		   .pm = &exynos_dsi_pm_ops,
21307eb8f069SAndrzej Hajda 		   .of_match_table = exynos_dsi_of_match,
21317eb8f069SAndrzej Hajda 	},
21327eb8f069SAndrzej Hajda };
21337eb8f069SAndrzej Hajda 
21347eb8f069SAndrzej Hajda MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
21357eb8f069SAndrzej Hajda MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
21367eb8f069SAndrzej Hajda MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
21377eb8f069SAndrzej Hajda MODULE_LICENSE("GPL v2");
2138