18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Broadcom
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/**
78c2ecf20Sopenharmony_ci * DOC: VC4 DSI0/DSI1 module
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * BCM2835 contains two DSI modules, DSI0 and DSI1.  DSI0 is a
108c2ecf20Sopenharmony_ci * single-lane DSI controller, while DSI1 is a more modern 4-lane DSI
118c2ecf20Sopenharmony_ci * controller.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Most Raspberry Pi boards expose DSI1 as their "DISPLAY" connector,
148c2ecf20Sopenharmony_ci * while the compute module brings both DSI0 and DSI1 out.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * This driver has been tested for DSI1 video-mode display only
178c2ecf20Sopenharmony_ci * currently, with most of the information necessary for DSI0
188c2ecf20Sopenharmony_ci * hopefully present.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
228c2ecf20Sopenharmony_ci#include <linux/clk.h>
238c2ecf20Sopenharmony_ci#include <linux/completion.h>
248c2ecf20Sopenharmony_ci#include <linux/component.h>
258c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
268c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
278c2ecf20Sopenharmony_ci#include <linux/i2c.h>
288c2ecf20Sopenharmony_ci#include <linux/io.h>
298c2ecf20Sopenharmony_ci#include <linux/of_address.h>
308c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
318c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
348c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h>
358c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
368c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h>
378c2ecf20Sopenharmony_ci#include <drm/drm_of.h>
388c2ecf20Sopenharmony_ci#include <drm/drm_panel.h>
398c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
408c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include "vc4_drv.h"
438c2ecf20Sopenharmony_ci#include "vc4_regs.h"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define DSI_CMD_FIFO_DEPTH  16
468c2ecf20Sopenharmony_ci#define DSI_PIX_FIFO_DEPTH 256
478c2ecf20Sopenharmony_ci#define DSI_PIX_FIFO_WIDTH   4
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define DSI0_CTRL		0x00
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Command packet control. */
528c2ecf20Sopenharmony_ci#define DSI0_TXPKT1C		0x04 /* AKA PKTC */
538c2ecf20Sopenharmony_ci#define DSI1_TXPKT1C		0x04
548c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_TRIG_CMD_MASK	VC4_MASK(31, 24)
558c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_TRIG_CMD_SHIFT	24
568c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_REPEAT_MASK	VC4_MASK(23, 10)
578c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_REPEAT_SHIFT	10
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_DISPLAY_NO_MASK	VC4_MASK(9, 8)
608c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_DISPLAY_NO_SHIFT	8
618c2ecf20Sopenharmony_ci/* Short, trigger, BTA, or a long packet that fits all in CMDFIFO. */
628c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_DISPLAY_NO_SHORT		0
638c2ecf20Sopenharmony_ci/* Primary display where cmdfifo provides part of the payload and
648c2ecf20Sopenharmony_ci * pixelvalve the rest.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_DISPLAY_NO_PRIMARY		1
678c2ecf20Sopenharmony_ci/* Secondary display where cmdfifo provides part of the payload and
688c2ecf20Sopenharmony_ci * pixfifo the rest.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_DISPLAY_NO_SECONDARY	2
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_TX_TIME_MASK	VC4_MASK(7, 6)
738c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_TX_TIME_SHIFT	6
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_MASK	VC4_MASK(5, 4)
768c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_SHIFT	4
778c2ecf20Sopenharmony_ci/* Command only.  Uses TXPKT1H and DISPLAY_NO */
788c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_TX	0
798c2ecf20Sopenharmony_ci/* Command with BTA for either ack or read data. */
808c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_RX	1
818c2ecf20Sopenharmony_ci/* Trigger according to TRIG_CMD */
828c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_TRIG	2
838c2ecf20Sopenharmony_ci/* BTA alone for getting error status after a command, or a TE trigger
848c2ecf20Sopenharmony_ci * without a previous command.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_CTRL_BTA	3
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_MODE_LP	BIT(3)
898c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_TYPE_LONG	BIT(2)
908c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_TE_EN		BIT(1)
918c2ecf20Sopenharmony_ci# define DSI_TXPKT1C_CMD_EN		BIT(0)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/* Command packet header. */
948c2ecf20Sopenharmony_ci#define DSI0_TXPKT1H		0x08 /* AKA PKTH */
958c2ecf20Sopenharmony_ci#define DSI1_TXPKT1H		0x08
968c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_CMDFIFO_MASK	VC4_MASK(31, 24)
978c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_CMDFIFO_SHIFT	24
988c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_PARAM_MASK	VC4_MASK(23, 8)
998c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_PARAM_SHIFT	8
1008c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_DT_MASK		VC4_MASK(7, 0)
1018c2ecf20Sopenharmony_ci# define DSI_TXPKT1H_BC_DT_SHIFT	0
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define DSI0_RXPKT1H		0x0c /* AKA RX1_PKTH */
1048c2ecf20Sopenharmony_ci#define DSI1_RXPKT1H		0x14
1058c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_CRC_ERR		BIT(31)
1068c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DET_ERR		BIT(30)
1078c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_ECC_ERR		BIT(29)
1088c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_COR_ERR		BIT(28)
1098c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_INCOMP_PKT		BIT(25)
1108c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_PKT_TYPE_LONG	BIT(24)
1118c2ecf20Sopenharmony_ci/* Byte count if DSI_RXPKT1H_PKT_TYPE_LONG */
1128c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_BC_PARAM_MASK	VC4_MASK(23, 8)
1138c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_BC_PARAM_SHIFT	8
1148c2ecf20Sopenharmony_ci/* Short return bytes if !DSI_RXPKT1H_PKT_TYPE_LONG */
1158c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_SHORT_1_MASK	VC4_MASK(23, 16)
1168c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_SHORT_1_SHIFT	16
1178c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_SHORT_0_MASK	VC4_MASK(15, 8)
1188c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_SHORT_0_SHIFT	8
1198c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DT_LP_CMD_MASK	VC4_MASK(7, 0)
1208c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DT_LP_CMD_SHIFT	0
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci#define DSI0_RXPKT2H		0x10 /* AKA RX2_PKTH */
1238c2ecf20Sopenharmony_ci#define DSI1_RXPKT2H		0x18
1248c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DET_ERR		BIT(30)
1258c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_ECC_ERR		BIT(29)
1268c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_COR_ERR		BIT(28)
1278c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_INCOMP_PKT		BIT(25)
1288c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_BC_PARAM_MASK	VC4_MASK(23, 8)
1298c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_BC_PARAM_SHIFT	8
1308c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DT_MASK		VC4_MASK(7, 0)
1318c2ecf20Sopenharmony_ci# define DSI_RXPKT1H_DT_SHIFT		0
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define DSI0_TXPKT_CMD_FIFO	0x14 /* AKA CMD_DATAF */
1348c2ecf20Sopenharmony_ci#define DSI1_TXPKT_CMD_FIFO	0x1c
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define DSI0_DISP0_CTRL		0x18
1378c2ecf20Sopenharmony_ci# define DSI_DISP0_PIX_CLK_DIV_MASK	VC4_MASK(21, 13)
1388c2ecf20Sopenharmony_ci# define DSI_DISP0_PIX_CLK_DIV_SHIFT	13
1398c2ecf20Sopenharmony_ci# define DSI_DISP0_LP_STOP_CTRL_MASK	VC4_MASK(12, 11)
1408c2ecf20Sopenharmony_ci# define DSI_DISP0_LP_STOP_CTRL_SHIFT	11
1418c2ecf20Sopenharmony_ci# define DSI_DISP0_LP_STOP_DISABLE	0
1428c2ecf20Sopenharmony_ci# define DSI_DISP0_LP_STOP_PERLINE	1
1438c2ecf20Sopenharmony_ci# define DSI_DISP0_LP_STOP_PERFRAME	2
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* Transmit RGB pixels and null packets only during HACTIVE, instead
1468c2ecf20Sopenharmony_ci * of going to LP-STOP.
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_ci# define DSI_DISP_HACTIVE_NULL		BIT(10)
1498c2ecf20Sopenharmony_ci/* Transmit blanking packet only during vblank, instead of allowing LP-STOP. */
1508c2ecf20Sopenharmony_ci# define DSI_DISP_VBLP_CTRL		BIT(9)
1518c2ecf20Sopenharmony_ci/* Transmit blanking packet only during HFP, instead of allowing LP-STOP. */
1528c2ecf20Sopenharmony_ci# define DSI_DISP_HFP_CTRL		BIT(8)
1538c2ecf20Sopenharmony_ci/* Transmit blanking packet only during HBP, instead of allowing LP-STOP. */
1548c2ecf20Sopenharmony_ci# define DSI_DISP_HBP_CTRL		BIT(7)
1558c2ecf20Sopenharmony_ci# define DSI_DISP0_CHANNEL_MASK		VC4_MASK(6, 5)
1568c2ecf20Sopenharmony_ci# define DSI_DISP0_CHANNEL_SHIFT	5
1578c2ecf20Sopenharmony_ci/* Enables end events for HSYNC/VSYNC, not just start events. */
1588c2ecf20Sopenharmony_ci# define DSI_DISP0_ST_END		BIT(4)
1598c2ecf20Sopenharmony_ci# define DSI_DISP0_PFORMAT_MASK		VC4_MASK(3, 2)
1608c2ecf20Sopenharmony_ci# define DSI_DISP0_PFORMAT_SHIFT	2
1618c2ecf20Sopenharmony_ci# define DSI_PFORMAT_RGB565		0
1628c2ecf20Sopenharmony_ci# define DSI_PFORMAT_RGB666_PACKED	1
1638c2ecf20Sopenharmony_ci# define DSI_PFORMAT_RGB666		2
1648c2ecf20Sopenharmony_ci# define DSI_PFORMAT_RGB888		3
1658c2ecf20Sopenharmony_ci/* Default is VIDEO mode. */
1668c2ecf20Sopenharmony_ci# define DSI_DISP0_COMMAND_MODE		BIT(1)
1678c2ecf20Sopenharmony_ci# define DSI_DISP0_ENABLE		BIT(0)
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#define DSI0_DISP1_CTRL		0x1c
1708c2ecf20Sopenharmony_ci#define DSI1_DISP1_CTRL		0x2c
1718c2ecf20Sopenharmony_ci/* Format of the data written to TXPKT_PIX_FIFO. */
1728c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_MASK		VC4_MASK(2, 1)
1738c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_SHIFT	1
1748c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_16BIT	0
1758c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_24BIT	1
1768c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_32BIT_LE	2
1778c2ecf20Sopenharmony_ci# define DSI_DISP1_PFORMAT_32BIT_BE	3
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/* DISP1 is always command mode. */
1808c2ecf20Sopenharmony_ci# define DSI_DISP1_ENABLE		BIT(0)
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define DSI0_TXPKT_PIX_FIFO		0x20 /* AKA PIX_FIFO */
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci#define DSI0_INT_STAT			0x24
1858c2ecf20Sopenharmony_ci#define DSI0_INT_EN			0x28
1868c2ecf20Sopenharmony_ci# define DSI0_INT_FIFO_ERR		BIT(25)
1878c2ecf20Sopenharmony_ci# define DSI0_INT_CMDC_DONE_MASK	VC4_MASK(24, 23)
1888c2ecf20Sopenharmony_ci# define DSI0_INT_CMDC_DONE_SHIFT	23
1898c2ecf20Sopenharmony_ci#  define DSI0_INT_CMDC_DONE_NO_REPEAT		1
1908c2ecf20Sopenharmony_ci#  define DSI0_INT_CMDC_DONE_REPEAT		3
1918c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_DIR_RTF		BIT(22)
1928c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D1_ULPS		BIT(21)
1938c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D1_STOP		BIT(20)
1948c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_RXLPDT		BIT(19)
1958c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_RXTRIG		BIT(18)
1968c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D0_ULPS		BIT(17)
1978c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D0_LPDT		BIT(16)
1988c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D0_FTR		BIT(15)
1998c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_D0_STOP		BIT(14)
2008c2ecf20Sopenharmony_ci/* Signaled when the clock lane enters the given state. */
2018c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_CLK_ULPS		BIT(13)
2028c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_CLK_HS		BIT(12)
2038c2ecf20Sopenharmony_ci# define DSI0_INT_PHY_CLK_FTR		BIT(11)
2048c2ecf20Sopenharmony_ci/* Signaled on timeouts */
2058c2ecf20Sopenharmony_ci# define DSI0_INT_PR_TO			BIT(10)
2068c2ecf20Sopenharmony_ci# define DSI0_INT_TA_TO			BIT(9)
2078c2ecf20Sopenharmony_ci# define DSI0_INT_LPRX_TO		BIT(8)
2088c2ecf20Sopenharmony_ci# define DSI0_INT_HSTX_TO		BIT(7)
2098c2ecf20Sopenharmony_ci/* Contention on a line when trying to drive the line low */
2108c2ecf20Sopenharmony_ci# define DSI0_INT_ERR_CONT_LP1		BIT(6)
2118c2ecf20Sopenharmony_ci# define DSI0_INT_ERR_CONT_LP0		BIT(5)
2128c2ecf20Sopenharmony_ci/* Control error: incorrect line state sequence on data lane 0. */
2138c2ecf20Sopenharmony_ci# define DSI0_INT_ERR_CONTROL		BIT(4)
2148c2ecf20Sopenharmony_ci# define DSI0_INT_ERR_SYNC_ESC		BIT(3)
2158c2ecf20Sopenharmony_ci# define DSI0_INT_RX2_PKT		BIT(2)
2168c2ecf20Sopenharmony_ci# define DSI0_INT_RX1_PKT		BIT(1)
2178c2ecf20Sopenharmony_ci# define DSI0_INT_CMD_PKT		BIT(0)
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define DSI0_INTERRUPTS_ALWAYS_ENABLED	(DSI0_INT_ERR_SYNC_ESC | \
2208c2ecf20Sopenharmony_ci					 DSI0_INT_ERR_CONTROL |	 \
2218c2ecf20Sopenharmony_ci					 DSI0_INT_ERR_CONT_LP0 | \
2228c2ecf20Sopenharmony_ci					 DSI0_INT_ERR_CONT_LP1 | \
2238c2ecf20Sopenharmony_ci					 DSI0_INT_HSTX_TO |	 \
2248c2ecf20Sopenharmony_ci					 DSI0_INT_LPRX_TO |	 \
2258c2ecf20Sopenharmony_ci					 DSI0_INT_TA_TO |	 \
2268c2ecf20Sopenharmony_ci					 DSI0_INT_PR_TO)
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D3_ULPS		BIT(30)
2298c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D3_STOP		BIT(29)
2308c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D2_ULPS		BIT(28)
2318c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D2_STOP		BIT(27)
2328c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D1_ULPS		BIT(26)
2338c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D1_STOP		BIT(25)
2348c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D0_ULPS		BIT(24)
2358c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D0_STOP		BIT(23)
2368c2ecf20Sopenharmony_ci# define DSI1_INT_FIFO_ERR		BIT(22)
2378c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_DIR_RTF		BIT(21)
2388c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_RXLPDT		BIT(20)
2398c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_RXTRIG		BIT(19)
2408c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_D0_LPDT		BIT(18)
2418c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_DIR_FTR		BIT(17)
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/* Signaled when the clock lane enters the given state. */
2448c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_CLOCK_ULPS	BIT(16)
2458c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_CLOCK_HS		BIT(15)
2468c2ecf20Sopenharmony_ci# define DSI1_INT_PHY_CLOCK_STOP	BIT(14)
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/* Signaled on timeouts */
2498c2ecf20Sopenharmony_ci# define DSI1_INT_PR_TO			BIT(13)
2508c2ecf20Sopenharmony_ci# define DSI1_INT_TA_TO			BIT(12)
2518c2ecf20Sopenharmony_ci# define DSI1_INT_LPRX_TO		BIT(11)
2528c2ecf20Sopenharmony_ci# define DSI1_INT_HSTX_TO		BIT(10)
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/* Contention on a line when trying to drive the line low */
2558c2ecf20Sopenharmony_ci# define DSI1_INT_ERR_CONT_LP1		BIT(9)
2568c2ecf20Sopenharmony_ci# define DSI1_INT_ERR_CONT_LP0		BIT(8)
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* Control error: incorrect line state sequence on data lane 0. */
2598c2ecf20Sopenharmony_ci# define DSI1_INT_ERR_CONTROL		BIT(7)
2608c2ecf20Sopenharmony_ci/* LPDT synchronization error (bits received not a multiple of 8. */
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci# define DSI1_INT_ERR_SYNC_ESC		BIT(6)
2638c2ecf20Sopenharmony_ci/* Signaled after receiving an error packet from the display in
2648c2ecf20Sopenharmony_ci * response to a read.
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_ci# define DSI1_INT_RXPKT2		BIT(5)
2678c2ecf20Sopenharmony_ci/* Signaled after receiving a packet.  The header and optional short
2688c2ecf20Sopenharmony_ci * response will be in RXPKT1H, and a long response will be in the
2698c2ecf20Sopenharmony_ci * RXPKT_FIFO.
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_ci# define DSI1_INT_RXPKT1		BIT(4)
2728c2ecf20Sopenharmony_ci# define DSI1_INT_TXPKT2_DONE		BIT(3)
2738c2ecf20Sopenharmony_ci# define DSI1_INT_TXPKT2_END		BIT(2)
2748c2ecf20Sopenharmony_ci/* Signaled after all repeats of TXPKT1 are transferred. */
2758c2ecf20Sopenharmony_ci# define DSI1_INT_TXPKT1_DONE		BIT(1)
2768c2ecf20Sopenharmony_ci/* Signaled after each TXPKT1 repeat is scheduled. */
2778c2ecf20Sopenharmony_ci# define DSI1_INT_TXPKT1_END		BIT(0)
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci#define DSI1_INTERRUPTS_ALWAYS_ENABLED	(DSI1_INT_ERR_SYNC_ESC | \
2808c2ecf20Sopenharmony_ci					 DSI1_INT_ERR_CONTROL |	 \
2818c2ecf20Sopenharmony_ci					 DSI1_INT_ERR_CONT_LP0 | \
2828c2ecf20Sopenharmony_ci					 DSI1_INT_ERR_CONT_LP1 | \
2838c2ecf20Sopenharmony_ci					 DSI1_INT_HSTX_TO |	 \
2848c2ecf20Sopenharmony_ci					 DSI1_INT_LPRX_TO |	 \
2858c2ecf20Sopenharmony_ci					 DSI1_INT_TA_TO |	 \
2868c2ecf20Sopenharmony_ci					 DSI1_INT_PR_TO)
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci#define DSI0_STAT		0x2c
2898c2ecf20Sopenharmony_ci#define DSI0_HSTX_TO_CNT	0x30
2908c2ecf20Sopenharmony_ci#define DSI0_LPRX_TO_CNT	0x34
2918c2ecf20Sopenharmony_ci#define DSI0_TA_TO_CNT		0x38
2928c2ecf20Sopenharmony_ci#define DSI0_PR_TO_CNT		0x3c
2938c2ecf20Sopenharmony_ci#define DSI0_PHYC		0x40
2948c2ecf20Sopenharmony_ci# define DSI1_PHYC_ESC_CLK_LPDT_MASK	VC4_MASK(25, 20)
2958c2ecf20Sopenharmony_ci# define DSI1_PHYC_ESC_CLK_LPDT_SHIFT	20
2968c2ecf20Sopenharmony_ci# define DSI1_PHYC_HS_CLK_CONTINUOUS	BIT(18)
2978c2ecf20Sopenharmony_ci# define DSI0_PHYC_ESC_CLK_LPDT_MASK	VC4_MASK(17, 12)
2988c2ecf20Sopenharmony_ci# define DSI0_PHYC_ESC_CLK_LPDT_SHIFT	12
2998c2ecf20Sopenharmony_ci# define DSI1_PHYC_CLANE_ULPS		BIT(17)
3008c2ecf20Sopenharmony_ci# define DSI1_PHYC_CLANE_ENABLE		BIT(16)
3018c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE3_ULPS		BIT(13)
3028c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE3_ENABLE		BIT(12)
3038c2ecf20Sopenharmony_ci# define DSI0_PHYC_HS_CLK_CONTINUOUS	BIT(10)
3048c2ecf20Sopenharmony_ci# define DSI0_PHYC_CLANE_ULPS		BIT(9)
3058c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE2_ULPS		BIT(9)
3068c2ecf20Sopenharmony_ci# define DSI0_PHYC_CLANE_ENABLE		BIT(8)
3078c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE2_ENABLE		BIT(8)
3088c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE1_ULPS		BIT(5)
3098c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE1_ENABLE		BIT(4)
3108c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE0_FORCE_STOP	BIT(2)
3118c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE0_ULPS		BIT(1)
3128c2ecf20Sopenharmony_ci# define DSI_PHYC_DLANE0_ENABLE		BIT(0)
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci#define DSI0_HS_CLT0		0x44
3158c2ecf20Sopenharmony_ci#define DSI0_HS_CLT1		0x48
3168c2ecf20Sopenharmony_ci#define DSI0_HS_CLT2		0x4c
3178c2ecf20Sopenharmony_ci#define DSI0_HS_DLT3		0x50
3188c2ecf20Sopenharmony_ci#define DSI0_HS_DLT4		0x54
3198c2ecf20Sopenharmony_ci#define DSI0_HS_DLT5		0x58
3208c2ecf20Sopenharmony_ci#define DSI0_HS_DLT6		0x5c
3218c2ecf20Sopenharmony_ci#define DSI0_HS_DLT7		0x60
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci#define DSI0_PHY_AFEC0		0x64
3248c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_DDR2CLK_EN		BIT(26)
3258c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_DDRCLK_EN		BIT(25)
3268c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_LATCH_ULPS		BIT(24)
3278c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE3_MASK		VC4_MASK(31, 29)
3288c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE3_SHIFT	29
3298c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE2_MASK		VC4_MASK(28, 26)
3308c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE2_SHIFT	26
3318c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE1_MASK		VC4_MASK(27, 23)
3328c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE1_SHIFT	23
3338c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE0_MASK		VC4_MASK(22, 20)
3348c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_DLANE0_SHIFT	20
3358c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_CLANE_MASK		VC4_MASK(19, 17)
3368c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_IDR_CLANE_SHIFT		17
3378c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_DLANE1_MASK	VC4_MASK(23, 20)
3388c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_DLANE1_SHIFT	20
3398c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_DLANE0_MASK	VC4_MASK(19, 16)
3408c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_DLANE0_SHIFT	16
3418c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_CLANE_MASK	VC4_MASK(15, 12)
3428c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_ACTRL_CLANE_SHIFT	12
3438c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_DDR2CLK_EN		BIT(16)
3448c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_DDRCLK_EN		BIT(15)
3458c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_LATCH_ULPS		BIT(14)
3468c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_RESET			BIT(13)
3478c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_PD			BIT(12)
3488c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_RESET			BIT(11)
3498c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_PD_BG			BIT(11)
3508c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_PD			BIT(10)
3518c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_PD_DLANE3		BIT(10)
3528c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_PD_BG			BIT(9)
3538c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_PD_DLANE2		BIT(9)
3548c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC0_PD_DLANE1		BIT(8)
3558c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC0_PD_DLANE1		BIT(8)
3568c2ecf20Sopenharmony_ci# define DSI_PHY_AFEC0_PTATADJ_MASK		VC4_MASK(7, 4)
3578c2ecf20Sopenharmony_ci# define DSI_PHY_AFEC0_PTATADJ_SHIFT		4
3588c2ecf20Sopenharmony_ci# define DSI_PHY_AFEC0_CTATADJ_MASK		VC4_MASK(3, 0)
3598c2ecf20Sopenharmony_ci# define DSI_PHY_AFEC0_CTATADJ_SHIFT		0
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci#define DSI0_PHY_AFEC1		0x68
3628c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_DLANE1_MASK		VC4_MASK(10, 8)
3638c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT	8
3648c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_DLANE0_MASK		VC4_MASK(6, 4)
3658c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_DLANE0_SHIFT	4
3668c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_CLANE_MASK		VC4_MASK(2, 0)
3678c2ecf20Sopenharmony_ci# define DSI0_PHY_AFEC1_IDR_CLANE_SHIFT		0
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci#define DSI0_TST_SEL		0x6c
3708c2ecf20Sopenharmony_ci#define DSI0_TST_MON		0x70
3718c2ecf20Sopenharmony_ci#define DSI0_ID			0x74
3728c2ecf20Sopenharmony_ci# define DSI_ID_VALUE		0x00647369
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci#define DSI1_CTRL		0x00
3758c2ecf20Sopenharmony_ci# define DSI_CTRL_HS_CLKC_MASK		VC4_MASK(15, 14)
3768c2ecf20Sopenharmony_ci# define DSI_CTRL_HS_CLKC_SHIFT		14
3778c2ecf20Sopenharmony_ci# define DSI_CTRL_HS_CLKC_BYTE		0
3788c2ecf20Sopenharmony_ci# define DSI_CTRL_HS_CLKC_DDR2		1
3798c2ecf20Sopenharmony_ci# define DSI_CTRL_HS_CLKC_DDR		2
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci# define DSI_CTRL_RX_LPDT_EOT_DISABLE	BIT(13)
3828c2ecf20Sopenharmony_ci# define DSI_CTRL_LPDT_EOT_DISABLE	BIT(12)
3838c2ecf20Sopenharmony_ci# define DSI_CTRL_HSDT_EOT_DISABLE	BIT(11)
3848c2ecf20Sopenharmony_ci# define DSI_CTRL_SOFT_RESET_CFG	BIT(10)
3858c2ecf20Sopenharmony_ci# define DSI_CTRL_CAL_BYTE		BIT(9)
3868c2ecf20Sopenharmony_ci# define DSI_CTRL_INV_BYTE		BIT(8)
3878c2ecf20Sopenharmony_ci# define DSI_CTRL_CLR_LDF		BIT(7)
3888c2ecf20Sopenharmony_ci# define DSI0_CTRL_CLR_PBCF		BIT(6)
3898c2ecf20Sopenharmony_ci# define DSI1_CTRL_CLR_RXF		BIT(6)
3908c2ecf20Sopenharmony_ci# define DSI0_CTRL_CLR_CPBCF		BIT(5)
3918c2ecf20Sopenharmony_ci# define DSI1_CTRL_CLR_PDF		BIT(5)
3928c2ecf20Sopenharmony_ci# define DSI0_CTRL_CLR_PDF		BIT(4)
3938c2ecf20Sopenharmony_ci# define DSI1_CTRL_CLR_CDF		BIT(4)
3948c2ecf20Sopenharmony_ci# define DSI0_CTRL_CLR_CDF		BIT(3)
3958c2ecf20Sopenharmony_ci# define DSI0_CTRL_CTRL2		BIT(2)
3968c2ecf20Sopenharmony_ci# define DSI1_CTRL_DISABLE_DISP_CRCC	BIT(2)
3978c2ecf20Sopenharmony_ci# define DSI0_CTRL_CTRL1		BIT(1)
3988c2ecf20Sopenharmony_ci# define DSI1_CTRL_DISABLE_DISP_ECCC	BIT(1)
3998c2ecf20Sopenharmony_ci# define DSI0_CTRL_CTRL0		BIT(0)
4008c2ecf20Sopenharmony_ci# define DSI1_CTRL_EN			BIT(0)
4018c2ecf20Sopenharmony_ci# define DSI0_CTRL_RESET_FIFOS		(DSI_CTRL_CLR_LDF | \
4028c2ecf20Sopenharmony_ci					 DSI0_CTRL_CLR_PBCF | \
4038c2ecf20Sopenharmony_ci					 DSI0_CTRL_CLR_CPBCF |	\
4048c2ecf20Sopenharmony_ci					 DSI0_CTRL_CLR_PDF | \
4058c2ecf20Sopenharmony_ci					 DSI0_CTRL_CLR_CDF)
4068c2ecf20Sopenharmony_ci# define DSI1_CTRL_RESET_FIFOS		(DSI_CTRL_CLR_LDF | \
4078c2ecf20Sopenharmony_ci					 DSI1_CTRL_CLR_RXF | \
4088c2ecf20Sopenharmony_ci					 DSI1_CTRL_CLR_PDF | \
4098c2ecf20Sopenharmony_ci					 DSI1_CTRL_CLR_CDF)
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci#define DSI1_TXPKT2C		0x0c
4128c2ecf20Sopenharmony_ci#define DSI1_TXPKT2H		0x10
4138c2ecf20Sopenharmony_ci#define DSI1_TXPKT_PIX_FIFO	0x20
4148c2ecf20Sopenharmony_ci#define DSI1_RXPKT_FIFO		0x24
4158c2ecf20Sopenharmony_ci#define DSI1_DISP0_CTRL		0x28
4168c2ecf20Sopenharmony_ci#define DSI1_INT_STAT		0x30
4178c2ecf20Sopenharmony_ci#define DSI1_INT_EN		0x34
4188c2ecf20Sopenharmony_ci/* State reporting bits.  These mostly behave like INT_STAT, where
4198c2ecf20Sopenharmony_ci * writing a 1 clears the bit.
4208c2ecf20Sopenharmony_ci */
4218c2ecf20Sopenharmony_ci#define DSI1_STAT		0x38
4228c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D3_ULPS		BIT(31)
4238c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D3_STOP		BIT(30)
4248c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D2_ULPS		BIT(29)
4258c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D2_STOP		BIT(28)
4268c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D1_ULPS		BIT(27)
4278c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D1_STOP		BIT(26)
4288c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D0_ULPS		BIT(25)
4298c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D0_STOP		BIT(24)
4308c2ecf20Sopenharmony_ci# define DSI1_STAT_FIFO_ERR		BIT(23)
4318c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_RXLPDT		BIT(22)
4328c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_RXTRIG		BIT(21)
4338c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_D0_LPDT		BIT(20)
4348c2ecf20Sopenharmony_ci/* Set when in forward direction */
4358c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_DIR		BIT(19)
4368c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_CLOCK_ULPS	BIT(18)
4378c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_CLOCK_HS		BIT(17)
4388c2ecf20Sopenharmony_ci# define DSI1_STAT_PHY_CLOCK_STOP	BIT(16)
4398c2ecf20Sopenharmony_ci# define DSI1_STAT_PR_TO		BIT(15)
4408c2ecf20Sopenharmony_ci# define DSI1_STAT_TA_TO		BIT(14)
4418c2ecf20Sopenharmony_ci# define DSI1_STAT_LPRX_TO		BIT(13)
4428c2ecf20Sopenharmony_ci# define DSI1_STAT_HSTX_TO		BIT(12)
4438c2ecf20Sopenharmony_ci# define DSI1_STAT_ERR_CONT_LP1		BIT(11)
4448c2ecf20Sopenharmony_ci# define DSI1_STAT_ERR_CONT_LP0		BIT(10)
4458c2ecf20Sopenharmony_ci# define DSI1_STAT_ERR_CONTROL		BIT(9)
4468c2ecf20Sopenharmony_ci# define DSI1_STAT_ERR_SYNC_ESC		BIT(8)
4478c2ecf20Sopenharmony_ci# define DSI1_STAT_RXPKT2		BIT(7)
4488c2ecf20Sopenharmony_ci# define DSI1_STAT_RXPKT1		BIT(6)
4498c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT2_BUSY		BIT(5)
4508c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT2_DONE		BIT(4)
4518c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT2_END		BIT(3)
4528c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT1_BUSY		BIT(2)
4538c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT1_DONE		BIT(1)
4548c2ecf20Sopenharmony_ci# define DSI1_STAT_TXPKT1_END		BIT(0)
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci#define DSI1_HSTX_TO_CNT	0x3c
4578c2ecf20Sopenharmony_ci#define DSI1_LPRX_TO_CNT	0x40
4588c2ecf20Sopenharmony_ci#define DSI1_TA_TO_CNT		0x44
4598c2ecf20Sopenharmony_ci#define DSI1_PR_TO_CNT		0x48
4608c2ecf20Sopenharmony_ci#define DSI1_PHYC		0x4c
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci#define DSI1_HS_CLT0		0x50
4638c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CZERO_MASK		VC4_MASK(26, 18)
4648c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CZERO_SHIFT	18
4658c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CPRE_MASK		VC4_MASK(17, 9)
4668c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CPRE_SHIFT		9
4678c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CPREP_MASK		VC4_MASK(8, 0)
4688c2ecf20Sopenharmony_ci# define DSI_HS_CLT0_CPREP_SHIFT	0
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci#define DSI1_HS_CLT1		0x54
4718c2ecf20Sopenharmony_ci# define DSI_HS_CLT1_CTRAIL_MASK	VC4_MASK(17, 9)
4728c2ecf20Sopenharmony_ci# define DSI_HS_CLT1_CTRAIL_SHIFT	9
4738c2ecf20Sopenharmony_ci# define DSI_HS_CLT1_CPOST_MASK		VC4_MASK(8, 0)
4748c2ecf20Sopenharmony_ci# define DSI_HS_CLT1_CPOST_SHIFT	0
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci#define DSI1_HS_CLT2		0x58
4778c2ecf20Sopenharmony_ci# define DSI_HS_CLT2_WUP_MASK		VC4_MASK(23, 0)
4788c2ecf20Sopenharmony_ci# define DSI_HS_CLT2_WUP_SHIFT		0
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci#define DSI1_HS_DLT3		0x5c
4818c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_EXIT_MASK		VC4_MASK(26, 18)
4828c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_EXIT_SHIFT		18
4838c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_ZERO_MASK		VC4_MASK(17, 9)
4848c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_ZERO_SHIFT		9
4858c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_PRE_MASK		VC4_MASK(8, 0)
4868c2ecf20Sopenharmony_ci# define DSI_HS_DLT3_PRE_SHIFT		0
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci#define DSI1_HS_DLT4		0x60
4898c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_ANLAT_MASK		VC4_MASK(22, 18)
4908c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_ANLAT_SHIFT	18
4918c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_TRAIL_MASK		VC4_MASK(17, 9)
4928c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_TRAIL_SHIFT	9
4938c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_LPX_MASK		VC4_MASK(8, 0)
4948c2ecf20Sopenharmony_ci# define DSI_HS_DLT4_LPX_SHIFT		0
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci#define DSI1_HS_DLT5		0x64
4978c2ecf20Sopenharmony_ci# define DSI_HS_DLT5_INIT_MASK		VC4_MASK(23, 0)
4988c2ecf20Sopenharmony_ci# define DSI_HS_DLT5_INIT_SHIFT		0
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci#define DSI1_HS_DLT6		0x68
5018c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_GET_MASK	VC4_MASK(31, 24)
5028c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_GET_SHIFT	24
5038c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_SURE_MASK	VC4_MASK(23, 16)
5048c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_SURE_SHIFT	16
5058c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_GO_MASK		VC4_MASK(15, 8)
5068c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_TA_GO_SHIFT	8
5078c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_LP_LPX_MASK	VC4_MASK(7, 0)
5088c2ecf20Sopenharmony_ci# define DSI_HS_DLT6_LP_LPX_SHIFT	0
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci#define DSI1_HS_DLT7		0x6c
5118c2ecf20Sopenharmony_ci# define DSI_HS_DLT7_LP_WUP_MASK	VC4_MASK(23, 0)
5128c2ecf20Sopenharmony_ci# define DSI_HS_DLT7_LP_WUP_SHIFT	0
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci#define DSI1_PHY_AFEC0		0x70
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci#define DSI1_PHY_AFEC1		0x74
5178c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE3_MASK	VC4_MASK(19, 16)
5188c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE3_SHIFT	16
5198c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE2_MASK	VC4_MASK(15, 12)
5208c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE2_SHIFT	12
5218c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE1_MASK	VC4_MASK(11, 8)
5228c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE1_SHIFT	8
5238c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE0_MASK	VC4_MASK(7, 4)
5248c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_DLANE0_SHIFT	4
5258c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_CLANE_MASK	VC4_MASK(3, 0)
5268c2ecf20Sopenharmony_ci# define DSI1_PHY_AFEC1_ACTRL_CLANE_SHIFT	0
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci#define DSI1_TST_SEL		0x78
5298c2ecf20Sopenharmony_ci#define DSI1_TST_MON		0x7c
5308c2ecf20Sopenharmony_ci#define DSI1_PHY_TST1		0x80
5318c2ecf20Sopenharmony_ci#define DSI1_PHY_TST2		0x84
5328c2ecf20Sopenharmony_ci#define DSI1_PHY_FIFO_STAT	0x88
5338c2ecf20Sopenharmony_ci/* Actually, all registers in the range that aren't otherwise claimed
5348c2ecf20Sopenharmony_ci * will return the ID.
5358c2ecf20Sopenharmony_ci */
5368c2ecf20Sopenharmony_ci#define DSI1_ID			0x8c
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistruct vc4_dsi_variant {
5398c2ecf20Sopenharmony_ci	/* Whether we're on bcm2835's DSI0 or DSI1. */
5408c2ecf20Sopenharmony_ci	unsigned int port;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	bool broken_axi_workaround;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	const char *debugfs_name;
5458c2ecf20Sopenharmony_ci	const struct debugfs_reg32 *regs;
5468c2ecf20Sopenharmony_ci	size_t nregs;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci};
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci/* General DSI hardware state. */
5518c2ecf20Sopenharmony_cistruct vc4_dsi {
5528c2ecf20Sopenharmony_ci	struct platform_device *pdev;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	struct mipi_dsi_host dsi_host;
5558c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
5568c2ecf20Sopenharmony_ci	struct drm_bridge *bridge;
5578c2ecf20Sopenharmony_ci	struct list_head bridge_chain;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	void __iomem *regs;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	struct dma_chan *reg_dma_chan;
5628c2ecf20Sopenharmony_ci	dma_addr_t reg_dma_paddr;
5638c2ecf20Sopenharmony_ci	u32 *reg_dma_mem;
5648c2ecf20Sopenharmony_ci	dma_addr_t reg_paddr;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	const struct vc4_dsi_variant *variant;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	/* DSI channel for the panel we're connected to. */
5698c2ecf20Sopenharmony_ci	u32 channel;
5708c2ecf20Sopenharmony_ci	u32 lanes;
5718c2ecf20Sopenharmony_ci	u32 format;
5728c2ecf20Sopenharmony_ci	u32 divider;
5738c2ecf20Sopenharmony_ci	u32 mode_flags;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* Input clock from CPRMAN to the digital PHY, for the DSI
5768c2ecf20Sopenharmony_ci	 * escape clock.
5778c2ecf20Sopenharmony_ci	 */
5788c2ecf20Sopenharmony_ci	struct clk *escape_clock;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/* Input clock to the analog PHY, used to generate the DSI bit
5818c2ecf20Sopenharmony_ci	 * clock.
5828c2ecf20Sopenharmony_ci	 */
5838c2ecf20Sopenharmony_ci	struct clk *pll_phy_clock;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* HS Clocks generated within the DSI analog PHY. */
5868c2ecf20Sopenharmony_ci	struct clk_fixed_factor phy_clocks[3];
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	struct clk_hw_onecell_data *clk_onecell;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/* Pixel clock output to the pixelvalve, generated from the HS
5918c2ecf20Sopenharmony_ci	 * clock.
5928c2ecf20Sopenharmony_ci	 */
5938c2ecf20Sopenharmony_ci	struct clk *pixel_clock;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	struct completion xfer_completion;
5968c2ecf20Sopenharmony_ci	int xfer_result;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	struct debugfs_regset32 regset;
5998c2ecf20Sopenharmony_ci};
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host)
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic inline void
6048c2ecf20Sopenharmony_cidsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct dma_chan *chan = dsi->reg_dma_chan;
6078c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *tx;
6088c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
6098c2ecf20Sopenharmony_ci	int ret;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	/* DSI0 should be able to write normally. */
6128c2ecf20Sopenharmony_ci	if (!chan) {
6138c2ecf20Sopenharmony_ci		writel(val, dsi->regs + offset);
6148c2ecf20Sopenharmony_ci		return;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	*dsi->reg_dma_mem = val;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	tx = chan->device->device_prep_dma_memcpy(chan,
6208c2ecf20Sopenharmony_ci						  dsi->reg_paddr + offset,
6218c2ecf20Sopenharmony_ci						  dsi->reg_dma_paddr,
6228c2ecf20Sopenharmony_ci						  4, 0);
6238c2ecf20Sopenharmony_ci	if (!tx) {
6248c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to set up DMA register write\n");
6258c2ecf20Sopenharmony_ci		return;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	cookie = tx->tx_submit(tx);
6298c2ecf20Sopenharmony_ci	ret = dma_submit_error(cookie);
6308c2ecf20Sopenharmony_ci	if (ret) {
6318c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to submit DMA: %d\n", ret);
6328c2ecf20Sopenharmony_ci		return;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci	ret = dma_sync_wait(chan, cookie);
6358c2ecf20Sopenharmony_ci	if (ret)
6368c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to wait for DMA: %d\n", ret);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci#define DSI_READ(offset) readl(dsi->regs + (offset))
6408c2ecf20Sopenharmony_ci#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
6418c2ecf20Sopenharmony_ci#define DSI_PORT_READ(offset) \
6428c2ecf20Sopenharmony_ci	DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
6438c2ecf20Sopenharmony_ci#define DSI_PORT_WRITE(offset, val) \
6448c2ecf20Sopenharmony_ci	DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val)
6458c2ecf20Sopenharmony_ci#define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit)
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci/* VC4 DSI encoder KMS struct */
6488c2ecf20Sopenharmony_cistruct vc4_dsi_encoder {
6498c2ecf20Sopenharmony_ci	struct vc4_encoder base;
6508c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi;
6518c2ecf20Sopenharmony_ci};
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic inline struct vc4_dsi_encoder *
6548c2ecf20Sopenharmony_cito_vc4_dsi_encoder(struct drm_encoder *encoder)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	return container_of(encoder, struct vc4_dsi_encoder, base.base);
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 dsi0_regs[] = {
6608c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_CTRL),
6618c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_STAT),
6628c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HSTX_TO_CNT),
6638c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_LPRX_TO_CNT),
6648c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_TA_TO_CNT),
6658c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_PR_TO_CNT),
6668c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_DISP0_CTRL),
6678c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_DISP1_CTRL),
6688c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_INT_STAT),
6698c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_INT_EN),
6708c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_PHYC),
6718c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_CLT0),
6728c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_CLT1),
6738c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_CLT2),
6748c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_DLT3),
6758c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_DLT4),
6768c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_DLT5),
6778c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_DLT6),
6788c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_HS_DLT7),
6798c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_PHY_AFEC0),
6808c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_PHY_AFEC1),
6818c2ecf20Sopenharmony_ci	VC4_REG32(DSI0_ID),
6828c2ecf20Sopenharmony_ci};
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 dsi1_regs[] = {
6858c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_CTRL),
6868c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_STAT),
6878c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HSTX_TO_CNT),
6888c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_LPRX_TO_CNT),
6898c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_TA_TO_CNT),
6908c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_PR_TO_CNT),
6918c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_DISP0_CTRL),
6928c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_DISP1_CTRL),
6938c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_INT_STAT),
6948c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_INT_EN),
6958c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_PHYC),
6968c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_CLT0),
6978c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_CLT1),
6988c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_CLT2),
6998c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_DLT3),
7008c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_DLT4),
7018c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_DLT5),
7028c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_DLT6),
7038c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_HS_DLT7),
7048c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_PHY_AFEC0),
7058c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_PHY_AFEC1),
7068c2ecf20Sopenharmony_ci	VC4_REG32(DSI1_ID),
7078c2ecf20Sopenharmony_ci};
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic void vc4_dsi_latch_ulps(struct vc4_dsi *dsi, bool latch)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	u32 afec0 = DSI_PORT_READ(PHY_AFEC0);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (latch)
7148c2ecf20Sopenharmony_ci		afec0 |= DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS);
7158c2ecf20Sopenharmony_ci	else
7168c2ecf20Sopenharmony_ci		afec0 &= ~DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PHY_AFEC0, afec0);
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci/* Enters or exits Ultra Low Power State. */
7228c2ecf20Sopenharmony_cistatic void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	bool non_continuous = dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS;
7258c2ecf20Sopenharmony_ci	u32 phyc_ulps = ((non_continuous ? DSI_PORT_BIT(PHYC_CLANE_ULPS) : 0) |
7268c2ecf20Sopenharmony_ci			 DSI_PHYC_DLANE0_ULPS |
7278c2ecf20Sopenharmony_ci			 (dsi->lanes > 1 ? DSI_PHYC_DLANE1_ULPS : 0) |
7288c2ecf20Sopenharmony_ci			 (dsi->lanes > 2 ? DSI_PHYC_DLANE2_ULPS : 0) |
7298c2ecf20Sopenharmony_ci			 (dsi->lanes > 3 ? DSI_PHYC_DLANE3_ULPS : 0));
7308c2ecf20Sopenharmony_ci	u32 stat_ulps = ((non_continuous ? DSI1_STAT_PHY_CLOCK_ULPS : 0) |
7318c2ecf20Sopenharmony_ci			 DSI1_STAT_PHY_D0_ULPS |
7328c2ecf20Sopenharmony_ci			 (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_ULPS : 0) |
7338c2ecf20Sopenharmony_ci			 (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_ULPS : 0) |
7348c2ecf20Sopenharmony_ci			 (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_ULPS : 0));
7358c2ecf20Sopenharmony_ci	u32 stat_stop = ((non_continuous ? DSI1_STAT_PHY_CLOCK_STOP : 0) |
7368c2ecf20Sopenharmony_ci			 DSI1_STAT_PHY_D0_STOP |
7378c2ecf20Sopenharmony_ci			 (dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) |
7388c2ecf20Sopenharmony_ci			 (dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) |
7398c2ecf20Sopenharmony_ci			 (dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0));
7408c2ecf20Sopenharmony_ci	int ret;
7418c2ecf20Sopenharmony_ci	bool ulps_currently_enabled = (DSI_PORT_READ(PHY_AFEC0) &
7428c2ecf20Sopenharmony_ci				       DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS));
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (ulps == ulps_currently_enabled)
7458c2ecf20Sopenharmony_ci		return;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(STAT, stat_ulps);
7488c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) | phyc_ulps);
7498c2ecf20Sopenharmony_ci	ret = wait_for((DSI_PORT_READ(STAT) & stat_ulps) == stat_ulps, 200);
7508c2ecf20Sopenharmony_ci	if (ret) {
7518c2ecf20Sopenharmony_ci		dev_warn(&dsi->pdev->dev,
7528c2ecf20Sopenharmony_ci			 "Timeout waiting for DSI ULPS entry: STAT 0x%08x",
7538c2ecf20Sopenharmony_ci			 DSI_PORT_READ(STAT));
7548c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps);
7558c2ecf20Sopenharmony_ci		vc4_dsi_latch_ulps(dsi, false);
7568c2ecf20Sopenharmony_ci		return;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	/* The DSI module can't be disabled while the module is
7608c2ecf20Sopenharmony_ci	 * generating ULPS state.  So, to be able to disable the
7618c2ecf20Sopenharmony_ci	 * module, we have the AFE latch the ULPS state and continue
7628c2ecf20Sopenharmony_ci	 * on to having the module enter STOP.
7638c2ecf20Sopenharmony_ci	 */
7648c2ecf20Sopenharmony_ci	vc4_dsi_latch_ulps(dsi, ulps);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(STAT, stat_stop);
7678c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps);
7688c2ecf20Sopenharmony_ci	ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200);
7698c2ecf20Sopenharmony_ci	if (ret) {
7708c2ecf20Sopenharmony_ci		dev_warn(&dsi->pdev->dev,
7718c2ecf20Sopenharmony_ci			 "Timeout waiting for DSI STOP entry: STAT 0x%08x",
7728c2ecf20Sopenharmony_ci			 DSI_PORT_READ(STAT));
7738c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps);
7748c2ecf20Sopenharmony_ci		return;
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_cistatic u32
7798c2ecf20Sopenharmony_cidsi_hs_timing(u32 ui_ns, u32 ns, u32 ui)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	/* The HS timings have to be rounded up to a multiple of 8
7828c2ecf20Sopenharmony_ci	 * because we're using the byte clock.
7838c2ecf20Sopenharmony_ci	 */
7848c2ecf20Sopenharmony_ci	return roundup(ui + DIV_ROUND_UP(ns, ui_ns), 8);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/* ESC always runs at 100Mhz. */
7888c2ecf20Sopenharmony_ci#define ESC_TIME_NS 10
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic u32
7918c2ecf20Sopenharmony_cidsi_esc_timing(u32 ns)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(ns, ESC_TIME_NS);
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
7998c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = vc4_encoder->dsi;
8008c2ecf20Sopenharmony_ci	struct device *dev = &dsi->pdev->dev;
8018c2ecf20Sopenharmony_ci	struct drm_bridge *iter;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
8048c2ecf20Sopenharmony_ci		if (iter->funcs->disable)
8058c2ecf20Sopenharmony_ci			iter->funcs->disable(iter);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci		if (iter == dsi->bridge)
8088c2ecf20Sopenharmony_ci			break;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	vc4_dsi_ulps(dsi, true);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	list_for_each_entry_from(iter, &dsi->bridge_chain, chain_node) {
8148c2ecf20Sopenharmony_ci		if (iter->funcs->post_disable)
8158c2ecf20Sopenharmony_ci			iter->funcs->post_disable(iter);
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->pll_phy_clock);
8198c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->escape_clock);
8208c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->pixel_clock);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	pm_runtime_put(dev);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci/* Extends the mode's blank intervals to handle BCM2835's integer-only
8268c2ecf20Sopenharmony_ci * DSI PLL divider.
8278c2ecf20Sopenharmony_ci *
8288c2ecf20Sopenharmony_ci * On 2835, PLLD is set to 2Ghz, and may not be changed by the display
8298c2ecf20Sopenharmony_ci * driver since most peripherals are hanging off of the PLLD_PER
8308c2ecf20Sopenharmony_ci * divider.  PLLD_DSI1, which drives our DSI bit clock (and therefore
8318c2ecf20Sopenharmony_ci * the pixel clock), only has an integer divider off of DSI.
8328c2ecf20Sopenharmony_ci *
8338c2ecf20Sopenharmony_ci * To get our panel mode to refresh at the expected 60Hz, we need to
8348c2ecf20Sopenharmony_ci * extend the horizontal blank time.  This means we drive a
8358c2ecf20Sopenharmony_ci * higher-than-expected clock rate to the panel, but that's what the
8368c2ecf20Sopenharmony_ci * firmware does too.
8378c2ecf20Sopenharmony_ci */
8388c2ecf20Sopenharmony_cistatic bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
8398c2ecf20Sopenharmony_ci				       const struct drm_display_mode *mode,
8408c2ecf20Sopenharmony_ci				       struct drm_display_mode *adjusted_mode)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
8438c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = vc4_encoder->dsi;
8448c2ecf20Sopenharmony_ci	struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
8458c2ecf20Sopenharmony_ci	unsigned long parent_rate = clk_get_rate(phy_parent);
8468c2ecf20Sopenharmony_ci	unsigned long pixel_clock_hz = mode->clock * 1000;
8478c2ecf20Sopenharmony_ci	unsigned long pll_clock = pixel_clock_hz * dsi->divider;
8488c2ecf20Sopenharmony_ci	int divider;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	/* Find what divider gets us a faster clock than the requested
8518c2ecf20Sopenharmony_ci	 * pixel clock.
8528c2ecf20Sopenharmony_ci	 */
8538c2ecf20Sopenharmony_ci	for (divider = 1; divider < 255; divider++) {
8548c2ecf20Sopenharmony_ci		if (parent_rate / (divider + 1) < pll_clock)
8558c2ecf20Sopenharmony_ci			break;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	/* Now that we've picked a PLL divider, calculate back to its
8598c2ecf20Sopenharmony_ci	 * pixel clock.
8608c2ecf20Sopenharmony_ci	 */
8618c2ecf20Sopenharmony_ci	pll_clock = parent_rate / divider;
8628c2ecf20Sopenharmony_ci	pixel_clock_hz = pll_clock / dsi->divider;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	adjusted_mode->clock = pixel_clock_hz / 1000;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
8678c2ecf20Sopenharmony_ci	adjusted_mode->htotal = adjusted_mode->clock * mode->htotal /
8688c2ecf20Sopenharmony_ci				mode->clock;
8698c2ecf20Sopenharmony_ci	adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
8708c2ecf20Sopenharmony_ci	adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return true;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
8788c2ecf20Sopenharmony_ci	struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
8798c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = vc4_encoder->dsi;
8808c2ecf20Sopenharmony_ci	struct device *dev = &dsi->pdev->dev;
8818c2ecf20Sopenharmony_ci	bool debug_dump_regs = false;
8828c2ecf20Sopenharmony_ci	struct drm_bridge *iter;
8838c2ecf20Sopenharmony_ci	unsigned long hs_clock;
8848c2ecf20Sopenharmony_ci	u32 ui_ns;
8858c2ecf20Sopenharmony_ci	/* Minimum LP state duration in escape clock cycles. */
8868c2ecf20Sopenharmony_ci	u32 lpx = dsi_esc_timing(60);
8878c2ecf20Sopenharmony_ci	unsigned long pixel_clock_hz = mode->clock * 1000;
8888c2ecf20Sopenharmony_ci	unsigned long dsip_clock;
8898c2ecf20Sopenharmony_ci	unsigned long phy_clock;
8908c2ecf20Sopenharmony_ci	int ret;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
8938c2ecf20Sopenharmony_ci	if (ret) {
8948c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->variant->port);
8958c2ecf20Sopenharmony_ci		return;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (debug_dump_regs) {
8998c2ecf20Sopenharmony_ci		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
9008c2ecf20Sopenharmony_ci		dev_info(&dsi->pdev->dev, "DSI regs before:\n");
9018c2ecf20Sopenharmony_ci		drm_print_regset32(&p, &dsi->regset);
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* Round up the clk_set_rate() request slightly, since
9058c2ecf20Sopenharmony_ci	 * PLLD_DSI1 is an integer divider and its rate selection will
9068c2ecf20Sopenharmony_ci	 * never round up.
9078c2ecf20Sopenharmony_ci	 */
9088c2ecf20Sopenharmony_ci	phy_clock = (pixel_clock_hz + 1000) * dsi->divider;
9098c2ecf20Sopenharmony_ci	ret = clk_set_rate(dsi->pll_phy_clock, phy_clock);
9108c2ecf20Sopenharmony_ci	if (ret) {
9118c2ecf20Sopenharmony_ci		dev_err(&dsi->pdev->dev,
9128c2ecf20Sopenharmony_ci			"Failed to set phy clock to %ld: %d\n", phy_clock, ret);
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/* Reset the DSI and all its fifos. */
9168c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(CTRL,
9178c2ecf20Sopenharmony_ci		       DSI_CTRL_SOFT_RESET_CFG |
9188c2ecf20Sopenharmony_ci		       DSI_PORT_BIT(CTRL_RESET_FIFOS));
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(CTRL,
9218c2ecf20Sopenharmony_ci		       DSI_CTRL_HSDT_EOT_DISABLE |
9228c2ecf20Sopenharmony_ci		       DSI_CTRL_RX_LPDT_EOT_DISABLE);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	/* Clear all stat bits so we see what has happened during enable. */
9258c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT));
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* Set AFE CTR00/CTR1 to release powerdown of analog. */
9288c2ecf20Sopenharmony_ci	if (dsi->variant->port == 0) {
9298c2ecf20Sopenharmony_ci		u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) |
9308c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ));
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		if (dsi->lanes < 2)
9338c2ecf20Sopenharmony_ci			afec0 |= DSI0_PHY_AFEC0_PD_DLANE1;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci		if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO))
9368c2ecf20Sopenharmony_ci			afec0 |= DSI0_PHY_AFEC0_RESET;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHY_AFEC0, afec0);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		/* AFEC reset hold time */
9418c2ecf20Sopenharmony_ci		mdelay(1);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHY_AFEC1,
9448c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE1) |
9458c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE0) |
9468c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_CLANE));
9478c2ecf20Sopenharmony_ci	} else {
9488c2ecf20Sopenharmony_ci		u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) |
9498c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ) |
9508c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_CLANE) |
9518c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE0) |
9528c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE1) |
9538c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE2) |
9548c2ecf20Sopenharmony_ci			     VC4_SET_FIELD(6, DSI1_PHY_AFEC0_IDR_DLANE3));
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		if (dsi->lanes < 4)
9578c2ecf20Sopenharmony_ci			afec0 |= DSI1_PHY_AFEC0_PD_DLANE3;
9588c2ecf20Sopenharmony_ci		if (dsi->lanes < 3)
9598c2ecf20Sopenharmony_ci			afec0 |= DSI1_PHY_AFEC0_PD_DLANE2;
9608c2ecf20Sopenharmony_ci		if (dsi->lanes < 2)
9618c2ecf20Sopenharmony_ci			afec0 |= DSI1_PHY_AFEC0_PD_DLANE1;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci		afec0 |= DSI1_PHY_AFEC0_RESET;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHY_AFEC0, afec0);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(PHY_AFEC1, 0);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		/* AFEC reset hold time */
9708c2ecf20Sopenharmony_ci		mdelay(1);
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(dsi->escape_clock);
9748c2ecf20Sopenharmony_ci	if (ret) {
9758c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to turn on DSI escape clock: %d\n", ret);
9768c2ecf20Sopenharmony_ci		return;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(dsi->pll_phy_clock);
9808c2ecf20Sopenharmony_ci	if (ret) {
9818c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to turn on DSI PLL: %d\n", ret);
9828c2ecf20Sopenharmony_ci		return;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	hs_clock = clk_get_rate(dsi->pll_phy_clock);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate,
9888c2ecf20Sopenharmony_ci	 * not the pixel clock rate.  DSIxP take from the APHY's byte,
9898c2ecf20Sopenharmony_ci	 * DDR2, or DDR4 clock (we use byte) and feed into the PV at
9908c2ecf20Sopenharmony_ci	 * that rate.  Separately, a value derived from PIX_CLK_DIV
9918c2ecf20Sopenharmony_ci	 * and HS_CLKC is fed into the PV to divide down to the actual
9928c2ecf20Sopenharmony_ci	 * pixel clock for pushing pixels into DSI.
9938c2ecf20Sopenharmony_ci	 */
9948c2ecf20Sopenharmony_ci	dsip_clock = phy_clock / 8;
9958c2ecf20Sopenharmony_ci	ret = clk_set_rate(dsi->pixel_clock, dsip_clock);
9968c2ecf20Sopenharmony_ci	if (ret) {
9978c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to set pixel clock to %ldHz: %d\n",
9988c2ecf20Sopenharmony_ci			dsip_clock, ret);
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(dsi->pixel_clock);
10028c2ecf20Sopenharmony_ci	if (ret) {
10038c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to turn on DSI pixel clock: %d\n", ret);
10048c2ecf20Sopenharmony_ci		return;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* How many ns one DSI unit interval is.  Note that the clock
10088c2ecf20Sopenharmony_ci	 * is DDR, so there's an extra divide by 2.
10098c2ecf20Sopenharmony_ci	 */
10108c2ecf20Sopenharmony_ci	ui_ns = DIV_ROUND_UP(500000000, hs_clock);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_CLT0,
10138c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 262, 0),
10148c2ecf20Sopenharmony_ci				     DSI_HS_CLT0_CZERO) |
10158c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 0, 8),
10168c2ecf20Sopenharmony_ci				     DSI_HS_CLT0_CPRE) |
10178c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 38, 0),
10188c2ecf20Sopenharmony_ci				     DSI_HS_CLT0_CPREP));
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_CLT1,
10218c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 0),
10228c2ecf20Sopenharmony_ci				     DSI_HS_CLT1_CTRAIL) |
10238c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 60, 52),
10248c2ecf20Sopenharmony_ci				     DSI_HS_CLT1_CPOST));
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_CLT2,
10278c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 1000000, 0),
10288c2ecf20Sopenharmony_ci				     DSI_HS_CLT2_WUP));
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_DLT3,
10318c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 100, 0),
10328c2ecf20Sopenharmony_ci				     DSI_HS_DLT3_EXIT) |
10338c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 105, 6),
10348c2ecf20Sopenharmony_ci				     DSI_HS_DLT3_ZERO) |
10358c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, 40, 4),
10368c2ecf20Sopenharmony_ci				     DSI_HS_DLT3_PRE));
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_DLT4,
10398c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_hs_timing(ui_ns, lpx * ESC_TIME_NS, 0),
10408c2ecf20Sopenharmony_ci				     DSI_HS_DLT4_LPX) |
10418c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(max(dsi_hs_timing(ui_ns, 0, 8),
10428c2ecf20Sopenharmony_ci					 dsi_hs_timing(ui_ns, 60, 4)),
10438c2ecf20Sopenharmony_ci				     DSI_HS_DLT4_TRAIL) |
10448c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(0, DSI_HS_DLT4_ANLAT));
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	/* T_INIT is how long STOP is driven after power-up to
10478c2ecf20Sopenharmony_ci	 * indicate to the slave (also coming out of power-up) that
10488c2ecf20Sopenharmony_ci	 * master init is complete, and should be greater than the
10498c2ecf20Sopenharmony_ci	 * maximum of two value: T_INIT,MASTER and T_INIT,SLAVE.  The
10508c2ecf20Sopenharmony_ci	 * D-PHY spec gives a minimum 100us for T_INIT,MASTER and
10518c2ecf20Sopenharmony_ci	 * T_INIT,SLAVE, while allowing protocols on top of it to give
10528c2ecf20Sopenharmony_ci	 * greater minimums.  The vc4 firmware uses an extremely
10538c2ecf20Sopenharmony_ci	 * conservative 5ms, and we maintain that here.
10548c2ecf20Sopenharmony_ci	 */
10558c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_DLT5, VC4_SET_FIELD(dsi_hs_timing(ui_ns,
10568c2ecf20Sopenharmony_ci							    5 * 1000 * 1000, 0),
10578c2ecf20Sopenharmony_ci					      DSI_HS_DLT5_INIT));
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_DLT6,
10608c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(lpx * 5, DSI_HS_DLT6_TA_GET) |
10618c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(lpx, DSI_HS_DLT6_TA_SURE) |
10628c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(lpx * 4, DSI_HS_DLT6_TA_GO) |
10638c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(lpx, DSI_HS_DLT6_LP_LPX));
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HS_DLT7,
10668c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(dsi_esc_timing(1000000),
10678c2ecf20Sopenharmony_ci				     DSI_HS_DLT7_LP_WUP));
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PHYC,
10708c2ecf20Sopenharmony_ci		       DSI_PHYC_DLANE0_ENABLE |
10718c2ecf20Sopenharmony_ci		       (dsi->lanes >= 2 ? DSI_PHYC_DLANE1_ENABLE : 0) |
10728c2ecf20Sopenharmony_ci		       (dsi->lanes >= 3 ? DSI_PHYC_DLANE2_ENABLE : 0) |
10738c2ecf20Sopenharmony_ci		       (dsi->lanes >= 4 ? DSI_PHYC_DLANE3_ENABLE : 0) |
10748c2ecf20Sopenharmony_ci		       DSI_PORT_BIT(PHYC_CLANE_ENABLE) |
10758c2ecf20Sopenharmony_ci		       ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ?
10768c2ecf20Sopenharmony_ci			0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) |
10778c2ecf20Sopenharmony_ci		       (dsi->variant->port == 0 ?
10788c2ecf20Sopenharmony_ci			VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) :
10798c2ecf20Sopenharmony_ci			VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT)));
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(CTRL,
10828c2ecf20Sopenharmony_ci		       DSI_PORT_READ(CTRL) |
10838c2ecf20Sopenharmony_ci		       DSI_CTRL_CAL_BYTE);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	/* HS timeout in HS clock cycles: disabled. */
10868c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(HSTX_TO_CNT, 0);
10878c2ecf20Sopenharmony_ci	/* LP receive timeout in HS clocks. */
10888c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(LPRX_TO_CNT, 0xffffff);
10898c2ecf20Sopenharmony_ci	/* Bus turnaround timeout */
10908c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(TA_TO_CNT, 100000);
10918c2ecf20Sopenharmony_ci	/* Display reset sequence timeout */
10928c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PR_TO_CNT, 100000);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	/* Set up DISP1 for transferring long command payloads through
10958c2ecf20Sopenharmony_ci	 * the pixfifo.
10968c2ecf20Sopenharmony_ci	 */
10978c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(DISP1_CTRL,
10988c2ecf20Sopenharmony_ci		       VC4_SET_FIELD(DSI_DISP1_PFORMAT_32BIT_LE,
10998c2ecf20Sopenharmony_ci				     DSI_DISP1_PFORMAT) |
11008c2ecf20Sopenharmony_ci		       DSI_DISP1_ENABLE);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	/* Ungate the block. */
11038c2ecf20Sopenharmony_ci	if (dsi->variant->port == 0)
11048c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0);
11058c2ecf20Sopenharmony_ci	else
11068c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	/* Bring AFE out of reset. */
11098c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(PHY_AFEC0,
11108c2ecf20Sopenharmony_ci		       DSI_PORT_READ(PHY_AFEC0) &
11118c2ecf20Sopenharmony_ci		       ~DSI_PORT_BIT(PHY_AFEC0_RESET));
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	vc4_dsi_ulps(dsi, false);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
11168c2ecf20Sopenharmony_ci		if (iter->funcs->pre_enable)
11178c2ecf20Sopenharmony_ci			iter->funcs->pre_enable(iter);
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
11218c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(DISP0_CTRL,
11228c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(dsi->divider,
11238c2ecf20Sopenharmony_ci					     DSI_DISP0_PIX_CLK_DIV) |
11248c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
11258c2ecf20Sopenharmony_ci			       VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
11268c2ecf20Sopenharmony_ci					     DSI_DISP0_LP_STOP_CTRL) |
11278c2ecf20Sopenharmony_ci			       DSI_DISP0_ST_END |
11288c2ecf20Sopenharmony_ci			       DSI_DISP0_ENABLE);
11298c2ecf20Sopenharmony_ci	} else {
11308c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(DISP0_CTRL,
11318c2ecf20Sopenharmony_ci			       DSI_DISP0_COMMAND_MODE |
11328c2ecf20Sopenharmony_ci			       DSI_DISP0_ENABLE);
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
11368c2ecf20Sopenharmony_ci		if (iter->funcs->enable)
11378c2ecf20Sopenharmony_ci			iter->funcs->enable(iter);
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	if (debug_dump_regs) {
11418c2ecf20Sopenharmony_ci		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
11428c2ecf20Sopenharmony_ci		dev_info(&dsi->pdev->dev, "DSI regs after:\n");
11438c2ecf20Sopenharmony_ci		drm_print_regset32(&p, &dsi->regset);
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_cistatic ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
11488c2ecf20Sopenharmony_ci				     const struct mipi_dsi_msg *msg)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = host_to_dsi(host);
11518c2ecf20Sopenharmony_ci	struct mipi_dsi_packet packet;
11528c2ecf20Sopenharmony_ci	u32 pkth = 0, pktc = 0;
11538c2ecf20Sopenharmony_ci	int i, ret;
11548c2ecf20Sopenharmony_ci	bool is_long = mipi_dsi_packet_format_is_long(msg->type);
11558c2ecf20Sopenharmony_ci	u32 cmd_fifo_len = 0, pix_fifo_len = 0;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	mipi_dsi_create_packet(&packet, msg);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	pkth |= VC4_SET_FIELD(packet.header[0], DSI_TXPKT1H_BC_DT);
11608c2ecf20Sopenharmony_ci	pkth |= VC4_SET_FIELD(packet.header[1] |
11618c2ecf20Sopenharmony_ci			      (packet.header[2] << 8),
11628c2ecf20Sopenharmony_ci			      DSI_TXPKT1H_BC_PARAM);
11638c2ecf20Sopenharmony_ci	if (is_long) {
11648c2ecf20Sopenharmony_ci		/* Divide data across the various FIFOs we have available.
11658c2ecf20Sopenharmony_ci		 * The command FIFO takes byte-oriented data, but is of
11668c2ecf20Sopenharmony_ci		 * limited size. The pixel FIFO (never actually used for
11678c2ecf20Sopenharmony_ci		 * pixel data in reality) is word oriented, and substantially
11688c2ecf20Sopenharmony_ci		 * larger. So, we use the pixel FIFO for most of the data,
11698c2ecf20Sopenharmony_ci		 * sending the residual bytes in the command FIFO at the start.
11708c2ecf20Sopenharmony_ci		 *
11718c2ecf20Sopenharmony_ci		 * With this arrangement, the command FIFO will never get full.
11728c2ecf20Sopenharmony_ci		 */
11738c2ecf20Sopenharmony_ci		if (packet.payload_length <= 16) {
11748c2ecf20Sopenharmony_ci			cmd_fifo_len = packet.payload_length;
11758c2ecf20Sopenharmony_ci			pix_fifo_len = 0;
11768c2ecf20Sopenharmony_ci		} else {
11778c2ecf20Sopenharmony_ci			cmd_fifo_len = (packet.payload_length %
11788c2ecf20Sopenharmony_ci					DSI_PIX_FIFO_WIDTH);
11798c2ecf20Sopenharmony_ci			pix_fifo_len = ((packet.payload_length - cmd_fifo_len) /
11808c2ecf20Sopenharmony_ci					DSI_PIX_FIFO_WIDTH);
11818c2ecf20Sopenharmony_ci		}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci		WARN_ON_ONCE(pix_fifo_len >= DSI_PIX_FIFO_DEPTH);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci		pkth |= VC4_SET_FIELD(cmd_fifo_len, DSI_TXPKT1H_BC_CMDFIFO);
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (msg->rx_len) {
11898c2ecf20Sopenharmony_ci		pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_RX,
11908c2ecf20Sopenharmony_ci				      DSI_TXPKT1C_CMD_CTRL);
11918c2ecf20Sopenharmony_ci	} else {
11928c2ecf20Sopenharmony_ci		pktc |= VC4_SET_FIELD(DSI_TXPKT1C_CMD_CTRL_TX,
11938c2ecf20Sopenharmony_ci				      DSI_TXPKT1C_CMD_CTRL);
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	for (i = 0; i < cmd_fifo_len; i++)
11978c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(TXPKT_CMD_FIFO, packet.payload[i]);
11988c2ecf20Sopenharmony_ci	for (i = 0; i < pix_fifo_len; i++) {
11998c2ecf20Sopenharmony_ci		const u8 *pix = packet.payload + cmd_fifo_len + i * 4;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(TXPKT_PIX_FIFO,
12028c2ecf20Sopenharmony_ci			       pix[0] |
12038c2ecf20Sopenharmony_ci			       pix[1] << 8 |
12048c2ecf20Sopenharmony_ci			       pix[2] << 16 |
12058c2ecf20Sopenharmony_ci			       pix[3] << 24);
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (msg->flags & MIPI_DSI_MSG_USE_LPM)
12098c2ecf20Sopenharmony_ci		pktc |= DSI_TXPKT1C_CMD_MODE_LP;
12108c2ecf20Sopenharmony_ci	if (is_long)
12118c2ecf20Sopenharmony_ci		pktc |= DSI_TXPKT1C_CMD_TYPE_LONG;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	/* Send one copy of the packet.  Larger repeats are used for pixel
12148c2ecf20Sopenharmony_ci	 * data in command mode.
12158c2ecf20Sopenharmony_ci	 */
12168c2ecf20Sopenharmony_ci	pktc |= VC4_SET_FIELD(1, DSI_TXPKT1C_CMD_REPEAT);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	pktc |= DSI_TXPKT1C_CMD_EN;
12198c2ecf20Sopenharmony_ci	if (pix_fifo_len) {
12208c2ecf20Sopenharmony_ci		pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SECONDARY,
12218c2ecf20Sopenharmony_ci				      DSI_TXPKT1C_DISPLAY_NO);
12228c2ecf20Sopenharmony_ci	} else {
12238c2ecf20Sopenharmony_ci		pktc |= VC4_SET_FIELD(DSI_TXPKT1C_DISPLAY_NO_SHORT,
12248c2ecf20Sopenharmony_ci				      DSI_TXPKT1C_DISPLAY_NO);
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	/* Enable the appropriate interrupt for the transfer completion. */
12288c2ecf20Sopenharmony_ci	dsi->xfer_result = 0;
12298c2ecf20Sopenharmony_ci	reinit_completion(&dsi->xfer_completion);
12308c2ecf20Sopenharmony_ci	if (dsi->variant->port == 0) {
12318c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(INT_STAT,
12328c2ecf20Sopenharmony_ci			       DSI0_INT_CMDC_DONE_MASK | DSI1_INT_PHY_DIR_RTF);
12338c2ecf20Sopenharmony_ci		if (msg->rx_len) {
12348c2ecf20Sopenharmony_ci			DSI_PORT_WRITE(INT_EN, (DSI0_INTERRUPTS_ALWAYS_ENABLED |
12358c2ecf20Sopenharmony_ci						DSI0_INT_PHY_DIR_RTF));
12368c2ecf20Sopenharmony_ci		} else {
12378c2ecf20Sopenharmony_ci			DSI_PORT_WRITE(INT_EN,
12388c2ecf20Sopenharmony_ci				       (DSI0_INTERRUPTS_ALWAYS_ENABLED |
12398c2ecf20Sopenharmony_ci					VC4_SET_FIELD(DSI0_INT_CMDC_DONE_NO_REPEAT,
12408c2ecf20Sopenharmony_ci						      DSI0_INT_CMDC_DONE)));
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci	} else {
12438c2ecf20Sopenharmony_ci		DSI_PORT_WRITE(INT_STAT,
12448c2ecf20Sopenharmony_ci			       DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
12458c2ecf20Sopenharmony_ci		if (msg->rx_len) {
12468c2ecf20Sopenharmony_ci			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
12478c2ecf20Sopenharmony_ci						DSI1_INT_PHY_DIR_RTF));
12488c2ecf20Sopenharmony_ci		} else {
12498c2ecf20Sopenharmony_ci			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
12508c2ecf20Sopenharmony_ci						DSI1_INT_TXPKT1_DONE));
12518c2ecf20Sopenharmony_ci		}
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	/* Send the packet. */
12558c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(TXPKT1H, pkth);
12568c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(TXPKT1C, pktc);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&dsi->xfer_completion,
12598c2ecf20Sopenharmony_ci					 msecs_to_jiffies(1000))) {
12608c2ecf20Sopenharmony_ci		dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout");
12618c2ecf20Sopenharmony_ci		dev_err(&dsi->pdev->dev, "instat: 0x%08x\n",
12628c2ecf20Sopenharmony_ci			DSI_PORT_READ(INT_STAT));
12638c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
12648c2ecf20Sopenharmony_ci	} else {
12658c2ecf20Sopenharmony_ci		ret = dsi->xfer_result;
12668c2ecf20Sopenharmony_ci	}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	if (ret)
12718c2ecf20Sopenharmony_ci		goto reset_fifo_and_return;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (ret == 0 && msg->rx_len) {
12748c2ecf20Sopenharmony_ci		u32 rxpkt1h = DSI_PORT_READ(RXPKT1H);
12758c2ecf20Sopenharmony_ci		u8 *msg_rx = msg->rx_buf;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci		if (rxpkt1h & DSI_RXPKT1H_PKT_TYPE_LONG) {
12788c2ecf20Sopenharmony_ci			u32 rxlen = VC4_GET_FIELD(rxpkt1h,
12798c2ecf20Sopenharmony_ci						  DSI_RXPKT1H_BC_PARAM);
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci			if (rxlen != msg->rx_len) {
12828c2ecf20Sopenharmony_ci				DRM_ERROR("DSI returned %db, expecting %db\n",
12838c2ecf20Sopenharmony_ci					  rxlen, (int)msg->rx_len);
12848c2ecf20Sopenharmony_ci				ret = -ENXIO;
12858c2ecf20Sopenharmony_ci				goto reset_fifo_and_return;
12868c2ecf20Sopenharmony_ci			}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci			for (i = 0; i < msg->rx_len; i++)
12898c2ecf20Sopenharmony_ci				msg_rx[i] = DSI_READ(DSI1_RXPKT_FIFO);
12908c2ecf20Sopenharmony_ci		} else {
12918c2ecf20Sopenharmony_ci			/* FINISHME: Handle AWER */
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci			msg_rx[0] = VC4_GET_FIELD(rxpkt1h,
12948c2ecf20Sopenharmony_ci						  DSI_RXPKT1H_SHORT_0);
12958c2ecf20Sopenharmony_ci			if (msg->rx_len > 1) {
12968c2ecf20Sopenharmony_ci				msg_rx[1] = VC4_GET_FIELD(rxpkt1h,
12978c2ecf20Sopenharmony_ci							  DSI_RXPKT1H_SHORT_1);
12988c2ecf20Sopenharmony_ci			}
12998c2ecf20Sopenharmony_ci		}
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	return ret;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cireset_fifo_and_return:
13058c2ecf20Sopenharmony_ci	DRM_ERROR("DSI transfer failed, resetting: %d\n", ret);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN);
13088c2ecf20Sopenharmony_ci	udelay(1);
13098c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(CTRL,
13108c2ecf20Sopenharmony_ci		       DSI_PORT_READ(CTRL) |
13118c2ecf20Sopenharmony_ci		       DSI_PORT_BIT(CTRL_RESET_FIFOS));
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(TXPKT1C, 0);
13148c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
13158c2ecf20Sopenharmony_ci	return ret;
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_cistatic int vc4_dsi_host_attach(struct mipi_dsi_host *host,
13198c2ecf20Sopenharmony_ci			       struct mipi_dsi_device *device)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = host_to_dsi(host);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	dsi->lanes = device->lanes;
13248c2ecf20Sopenharmony_ci	dsi->channel = device->channel;
13258c2ecf20Sopenharmony_ci	dsi->mode_flags = device->mode_flags;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	switch (device->format) {
13288c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB888:
13298c2ecf20Sopenharmony_ci		dsi->format = DSI_PFORMAT_RGB888;
13308c2ecf20Sopenharmony_ci		dsi->divider = 24 / dsi->lanes;
13318c2ecf20Sopenharmony_ci		break;
13328c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666:
13338c2ecf20Sopenharmony_ci		dsi->format = DSI_PFORMAT_RGB666;
13348c2ecf20Sopenharmony_ci		dsi->divider = 24 / dsi->lanes;
13358c2ecf20Sopenharmony_ci		break;
13368c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666_PACKED:
13378c2ecf20Sopenharmony_ci		dsi->format = DSI_PFORMAT_RGB666_PACKED;
13388c2ecf20Sopenharmony_ci		dsi->divider = 18 / dsi->lanes;
13398c2ecf20Sopenharmony_ci		break;
13408c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB565:
13418c2ecf20Sopenharmony_ci		dsi->format = DSI_PFORMAT_RGB565;
13428c2ecf20Sopenharmony_ci		dsi->divider = 16 / dsi->lanes;
13438c2ecf20Sopenharmony_ci		break;
13448c2ecf20Sopenharmony_ci	default:
13458c2ecf20Sopenharmony_ci		dev_err(&dsi->pdev->dev, "Unknown DSI format: %d.\n",
13468c2ecf20Sopenharmony_ci			dsi->format);
13478c2ecf20Sopenharmony_ci		return 0;
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
13518c2ecf20Sopenharmony_ci		dev_err(&dsi->pdev->dev,
13528c2ecf20Sopenharmony_ci			"Only VIDEO mode panels supported currently.\n");
13538c2ecf20Sopenharmony_ci		return 0;
13548c2ecf20Sopenharmony_ci	}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	return 0;
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_cistatic int vc4_dsi_host_detach(struct mipi_dsi_host *host,
13608c2ecf20Sopenharmony_ci			       struct mipi_dsi_device *device)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	return 0;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_cistatic const struct mipi_dsi_host_ops vc4_dsi_host_ops = {
13668c2ecf20Sopenharmony_ci	.attach = vc4_dsi_host_attach,
13678c2ecf20Sopenharmony_ci	.detach = vc4_dsi_host_detach,
13688c2ecf20Sopenharmony_ci	.transfer = vc4_dsi_host_transfer,
13698c2ecf20Sopenharmony_ci};
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
13728c2ecf20Sopenharmony_ci	.disable = vc4_dsi_encoder_disable,
13738c2ecf20Sopenharmony_ci	.enable = vc4_dsi_encoder_enable,
13748c2ecf20Sopenharmony_ci	.mode_fixup = vc4_dsi_encoder_mode_fixup,
13758c2ecf20Sopenharmony_ci};
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_cistatic const struct vc4_dsi_variant bcm2835_dsi1_variant = {
13788c2ecf20Sopenharmony_ci	.port			= 1,
13798c2ecf20Sopenharmony_ci	.broken_axi_workaround	= true,
13808c2ecf20Sopenharmony_ci	.debugfs_name		= "dsi1_regs",
13818c2ecf20Sopenharmony_ci	.regs			= dsi1_regs,
13828c2ecf20Sopenharmony_ci	.nregs			= ARRAY_SIZE(dsi1_regs),
13838c2ecf20Sopenharmony_ci};
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cistatic const struct of_device_id vc4_dsi_dt_match[] = {
13868c2ecf20Sopenharmony_ci	{ .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant },
13878c2ecf20Sopenharmony_ci	{}
13888c2ecf20Sopenharmony_ci};
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_cistatic void dsi_handle_error(struct vc4_dsi *dsi,
13918c2ecf20Sopenharmony_ci			     irqreturn_t *ret, u32 stat, u32 bit,
13928c2ecf20Sopenharmony_ci			     const char *type)
13938c2ecf20Sopenharmony_ci{
13948c2ecf20Sopenharmony_ci	if (!(stat & bit))
13958c2ecf20Sopenharmony_ci		return;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	DRM_ERROR("DSI%d: %s error\n", dsi->variant->port, type);
13988c2ecf20Sopenharmony_ci	*ret = IRQ_HANDLED;
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci/*
14028c2ecf20Sopenharmony_ci * Initial handler for port 1 where we need the reg_dma workaround.
14038c2ecf20Sopenharmony_ci * The register DMA writes sleep, so we can't do it in the top half.
14048c2ecf20Sopenharmony_ci * Instead we use IRQF_ONESHOT so that the IRQ gets disabled in the
14058c2ecf20Sopenharmony_ci * parent interrupt contrller until our interrupt thread is done.
14068c2ecf20Sopenharmony_ci */
14078c2ecf20Sopenharmony_cistatic irqreturn_t vc4_dsi_irq_defer_to_thread_handler(int irq, void *data)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = data;
14108c2ecf20Sopenharmony_ci	u32 stat = DSI_PORT_READ(INT_STAT);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (!stat)
14138c2ecf20Sopenharmony_ci		return IRQ_NONE;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	return IRQ_WAKE_THREAD;
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci/*
14198c2ecf20Sopenharmony_ci * Normal IRQ handler for port 0, or the threaded IRQ handler for port
14208c2ecf20Sopenharmony_ci * 1 where we need the reg_dma workaround.
14218c2ecf20Sopenharmony_ci */
14228c2ecf20Sopenharmony_cistatic irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = data;
14258c2ecf20Sopenharmony_ci	u32 stat = DSI_PORT_READ(INT_STAT);
14268c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(INT_STAT, stat);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14318c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_ERR_SYNC_ESC), "LPDT sync");
14328c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14338c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_ERR_CONTROL), "data lane 0 sequence");
14348c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14358c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_ERR_CONT_LP0), "LP0 contention");
14368c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14378c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_ERR_CONT_LP1), "LP1 contention");
14388c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14398c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_HSTX_TO), "HSTX timeout");
14408c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14418c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_LPRX_TO), "LPRX timeout");
14428c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14438c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_TA_TO), "turnaround timeout");
14448c2ecf20Sopenharmony_ci	dsi_handle_error(dsi, &ret, stat,
14458c2ecf20Sopenharmony_ci			 DSI_PORT_BIT(INT_PR_TO), "peripheral reset timeout");
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	if (stat & ((dsi->variant->port ? DSI1_INT_TXPKT1_DONE :
14488c2ecf20Sopenharmony_ci					  DSI0_INT_CMDC_DONE_MASK) |
14498c2ecf20Sopenharmony_ci		    DSI_PORT_BIT(INT_PHY_DIR_RTF))) {
14508c2ecf20Sopenharmony_ci		complete(&dsi->xfer_completion);
14518c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
14528c2ecf20Sopenharmony_ci	} else if (stat & DSI_PORT_BIT(INT_HSTX_TO)) {
14538c2ecf20Sopenharmony_ci		complete(&dsi->xfer_completion);
14548c2ecf20Sopenharmony_ci		dsi->xfer_result = -ETIMEDOUT;
14558c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	return ret;
14598c2ecf20Sopenharmony_ci}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci/**
14628c2ecf20Sopenharmony_ci * vc4_dsi_init_phy_clocks - Exposes clocks generated by the analog
14638c2ecf20Sopenharmony_ci * PHY that are consumed by CPRMAN (clk-bcm2835.c).
14648c2ecf20Sopenharmony_ci * @dsi: DSI encoder
14658c2ecf20Sopenharmony_ci */
14668c2ecf20Sopenharmony_cistatic int
14678c2ecf20Sopenharmony_civc4_dsi_init_phy_clocks(struct vc4_dsi *dsi)
14688c2ecf20Sopenharmony_ci{
14698c2ecf20Sopenharmony_ci	struct device *dev = &dsi->pdev->dev;
14708c2ecf20Sopenharmony_ci	const char *parent_name = __clk_get_name(dsi->pll_phy_clock);
14718c2ecf20Sopenharmony_ci	static const struct {
14728c2ecf20Sopenharmony_ci		const char *name;
14738c2ecf20Sopenharmony_ci		int div;
14748c2ecf20Sopenharmony_ci	} phy_clocks[] = {
14758c2ecf20Sopenharmony_ci		{ "byte", 8 },
14768c2ecf20Sopenharmony_ci		{ "ddr2", 4 },
14778c2ecf20Sopenharmony_ci		{ "ddr", 2 },
14788c2ecf20Sopenharmony_ci	};
14798c2ecf20Sopenharmony_ci	int i;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	dsi->clk_onecell = devm_kzalloc(dev,
14828c2ecf20Sopenharmony_ci					sizeof(*dsi->clk_onecell) +
14838c2ecf20Sopenharmony_ci					ARRAY_SIZE(phy_clocks) *
14848c2ecf20Sopenharmony_ci					sizeof(struct clk_hw *),
14858c2ecf20Sopenharmony_ci					GFP_KERNEL);
14868c2ecf20Sopenharmony_ci	if (!dsi->clk_onecell)
14878c2ecf20Sopenharmony_ci		return -ENOMEM;
14888c2ecf20Sopenharmony_ci	dsi->clk_onecell->num = ARRAY_SIZE(phy_clocks);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) {
14918c2ecf20Sopenharmony_ci		struct clk_fixed_factor *fix = &dsi->phy_clocks[i];
14928c2ecf20Sopenharmony_ci		struct clk_init_data init;
14938c2ecf20Sopenharmony_ci		char clk_name[16];
14948c2ecf20Sopenharmony_ci		int ret;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci		snprintf(clk_name, sizeof(clk_name),
14978c2ecf20Sopenharmony_ci			 "dsi%u_%s", dsi->variant->port, phy_clocks[i].name);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci		/* We just use core fixed factor clock ops for the PHY
15008c2ecf20Sopenharmony_ci		 * clocks.  The clocks are actually gated by the
15018c2ecf20Sopenharmony_ci		 * PHY_AFEC0_DDRCLK_EN bits, which we should be
15028c2ecf20Sopenharmony_ci		 * setting if we use the DDR/DDR2 clocks.  However,
15038c2ecf20Sopenharmony_ci		 * vc4_dsi_encoder_enable() is setting up both AFEC0,
15048c2ecf20Sopenharmony_ci		 * setting both our parent DSI PLL's rate and this
15058c2ecf20Sopenharmony_ci		 * clock's rate, so it knows if DDR/DDR2 are going to
15068c2ecf20Sopenharmony_ci		 * be used and could enable the gates itself.
15078c2ecf20Sopenharmony_ci		 */
15088c2ecf20Sopenharmony_ci		fix->mult = 1;
15098c2ecf20Sopenharmony_ci		fix->div = phy_clocks[i].div;
15108c2ecf20Sopenharmony_ci		fix->hw.init = &init;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci		memset(&init, 0, sizeof(init));
15138c2ecf20Sopenharmony_ci		init.parent_names = &parent_name;
15148c2ecf20Sopenharmony_ci		init.num_parents = 1;
15158c2ecf20Sopenharmony_ci		init.name = clk_name;
15168c2ecf20Sopenharmony_ci		init.ops = &clk_fixed_factor_ops;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		ret = devm_clk_hw_register(dev, &fix->hw);
15198c2ecf20Sopenharmony_ci		if (ret)
15208c2ecf20Sopenharmony_ci			return ret;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci		dsi->clk_onecell->hws[i] = &fix->hw;
15238c2ecf20Sopenharmony_ci	}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	return of_clk_add_hw_provider(dev->of_node,
15268c2ecf20Sopenharmony_ci				      of_clk_hw_onecell_get,
15278c2ecf20Sopenharmony_ci				      dsi->clk_onecell);
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_cistatic int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
15338c2ecf20Sopenharmony_ci	struct drm_device *drm = dev_get_drvdata(master);
15348c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = dev_get_drvdata(dev);
15358c2ecf20Sopenharmony_ci	struct vc4_dsi_encoder *vc4_dsi_encoder;
15368c2ecf20Sopenharmony_ci	struct drm_panel *panel;
15378c2ecf20Sopenharmony_ci	const struct of_device_id *match;
15388c2ecf20Sopenharmony_ci	dma_cap_mask_t dma_mask;
15398c2ecf20Sopenharmony_ci	int ret;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	match = of_match_device(vc4_dsi_dt_match, dev);
15428c2ecf20Sopenharmony_ci	if (!match)
15438c2ecf20Sopenharmony_ci		return -ENODEV;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	dsi->variant = match->data;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder),
15488c2ecf20Sopenharmony_ci				       GFP_KERNEL);
15498c2ecf20Sopenharmony_ci	if (!vc4_dsi_encoder)
15508c2ecf20Sopenharmony_ci		return -ENOMEM;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dsi->bridge_chain);
15538c2ecf20Sopenharmony_ci	vc4_dsi_encoder->base.type = dsi->variant->port ?
15548c2ecf20Sopenharmony_ci			VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0;
15558c2ecf20Sopenharmony_ci	vc4_dsi_encoder->dsi = dsi;
15568c2ecf20Sopenharmony_ci	dsi->encoder = &vc4_dsi_encoder->base.base;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	dsi->regs = vc4_ioremap_regs(pdev, 0);
15598c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->regs))
15608c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->regs);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	dsi->regset.base = dsi->regs;
15638c2ecf20Sopenharmony_ci	dsi->regset.regs = dsi->variant->regs;
15648c2ecf20Sopenharmony_ci	dsi->regset.nregs = dsi->variant->nregs;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (DSI_PORT_READ(ID) != DSI_ID_VALUE) {
15678c2ecf20Sopenharmony_ci		dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
15688c2ecf20Sopenharmony_ci			DSI_PORT_READ(ID), DSI_ID_VALUE);
15698c2ecf20Sopenharmony_ci		return -ENODEV;
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	/* DSI1 has a broken AXI slave that doesn't respond to writes
15738c2ecf20Sopenharmony_ci	 * from the ARM.  It does handle writes from the DMA engine,
15748c2ecf20Sopenharmony_ci	 * so set up a channel for talking to it.
15758c2ecf20Sopenharmony_ci	 */
15768c2ecf20Sopenharmony_ci	if (dsi->variant->broken_axi_workaround) {
15778c2ecf20Sopenharmony_ci		dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
15788c2ecf20Sopenharmony_ci						      &dsi->reg_dma_paddr,
15798c2ecf20Sopenharmony_ci						      GFP_KERNEL);
15808c2ecf20Sopenharmony_ci		if (!dsi->reg_dma_mem) {
15818c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to get DMA memory\n");
15828c2ecf20Sopenharmony_ci			return -ENOMEM;
15838c2ecf20Sopenharmony_ci		}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci		dma_cap_zero(dma_mask);
15868c2ecf20Sopenharmony_ci		dma_cap_set(DMA_MEMCPY, dma_mask);
15878c2ecf20Sopenharmony_ci		dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask);
15888c2ecf20Sopenharmony_ci		if (IS_ERR(dsi->reg_dma_chan)) {
15898c2ecf20Sopenharmony_ci			ret = PTR_ERR(dsi->reg_dma_chan);
15908c2ecf20Sopenharmony_ci			if (ret != -EPROBE_DEFER)
15918c2ecf20Sopenharmony_ci				DRM_ERROR("Failed to get DMA channel: %d\n",
15928c2ecf20Sopenharmony_ci					  ret);
15938c2ecf20Sopenharmony_ci			return ret;
15948c2ecf20Sopenharmony_ci		}
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		/* Get the physical address of the device's registers.  The
15978c2ecf20Sopenharmony_ci		 * struct resource for the regs gives us the bus address
15988c2ecf20Sopenharmony_ci		 * instead.
15998c2ecf20Sopenharmony_ci		 */
16008c2ecf20Sopenharmony_ci		dsi->reg_paddr = be32_to_cpup(of_get_address(dev->of_node,
16018c2ecf20Sopenharmony_ci							     0, NULL, NULL));
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	init_completion(&dsi->xfer_completion);
16058c2ecf20Sopenharmony_ci	/* At startup enable error-reporting interrupts and nothing else. */
16068c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
16078c2ecf20Sopenharmony_ci	/* Clear any existing interrupt state. */
16088c2ecf20Sopenharmony_ci	DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	if (dsi->reg_dma_mem)
16118c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
16128c2ecf20Sopenharmony_ci						vc4_dsi_irq_defer_to_thread_handler,
16138c2ecf20Sopenharmony_ci						vc4_dsi_irq_handler,
16148c2ecf20Sopenharmony_ci						IRQF_ONESHOT,
16158c2ecf20Sopenharmony_ci						"vc4 dsi", dsi);
16168c2ecf20Sopenharmony_ci	else
16178c2ecf20Sopenharmony_ci		ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
16188c2ecf20Sopenharmony_ci				       vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
16198c2ecf20Sopenharmony_ci	if (ret) {
16208c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
16218c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to get interrupt: %d\n", ret);
16228c2ecf20Sopenharmony_ci		return ret;
16238c2ecf20Sopenharmony_ci	}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	dsi->escape_clock = devm_clk_get(dev, "escape");
16268c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->escape_clock)) {
16278c2ecf20Sopenharmony_ci		ret = PTR_ERR(dsi->escape_clock);
16288c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
16298c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to get escape clock: %d\n", ret);
16308c2ecf20Sopenharmony_ci		return ret;
16318c2ecf20Sopenharmony_ci	}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	dsi->pll_phy_clock = devm_clk_get(dev, "phy");
16348c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->pll_phy_clock)) {
16358c2ecf20Sopenharmony_ci		ret = PTR_ERR(dsi->pll_phy_clock);
16368c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
16378c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to get phy clock: %d\n", ret);
16388c2ecf20Sopenharmony_ci		return ret;
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	dsi->pixel_clock = devm_clk_get(dev, "pixel");
16428c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->pixel_clock)) {
16438c2ecf20Sopenharmony_ci		ret = PTR_ERR(dsi->pixel_clock);
16448c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
16458c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to get pixel clock: %d\n", ret);
16468c2ecf20Sopenharmony_ci		return ret;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
16508c2ecf20Sopenharmony_ci					  &panel, &dsi->bridge);
16518c2ecf20Sopenharmony_ci	if (ret) {
16528c2ecf20Sopenharmony_ci		/* If the bridge or panel pointed by dev->of_node is not
16538c2ecf20Sopenharmony_ci		 * enabled, just return 0 here so that we don't prevent the DRM
16548c2ecf20Sopenharmony_ci		 * dev from being registered. Of course that means the DSI
16558c2ecf20Sopenharmony_ci		 * encoder won't be exposed, but that's not a problem since
16568c2ecf20Sopenharmony_ci		 * nothing is connected to it.
16578c2ecf20Sopenharmony_ci		 */
16588c2ecf20Sopenharmony_ci		if (ret == -ENODEV)
16598c2ecf20Sopenharmony_ci			return 0;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci		return ret;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	if (panel) {
16658c2ecf20Sopenharmony_ci		dsi->bridge = devm_drm_panel_bridge_add_typed(dev, panel,
16668c2ecf20Sopenharmony_ci							      DRM_MODE_CONNECTOR_DSI);
16678c2ecf20Sopenharmony_ci		if (IS_ERR(dsi->bridge))
16688c2ecf20Sopenharmony_ci			return PTR_ERR(dsi->bridge);
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	/* The esc clock rate is supposed to always be 100Mhz. */
16728c2ecf20Sopenharmony_ci	ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
16738c2ecf20Sopenharmony_ci	if (ret) {
16748c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to set esc clock: %d\n", ret);
16758c2ecf20Sopenharmony_ci		return ret;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	ret = vc4_dsi_init_phy_clocks(dsi);
16798c2ecf20Sopenharmony_ci	if (ret)
16808c2ecf20Sopenharmony_ci		return ret;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
16838c2ecf20Sopenharmony_ci	drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, 0);
16868c2ecf20Sopenharmony_ci	if (ret) {
16878c2ecf20Sopenharmony_ci		dev_err(dev, "bridge attach failed: %d\n", ret);
16888c2ecf20Sopenharmony_ci		return ret;
16898c2ecf20Sopenharmony_ci	}
16908c2ecf20Sopenharmony_ci	/* Disable the atomic helper calls into the bridge.  We
16918c2ecf20Sopenharmony_ci	 * manually call the bridge pre_enable / enable / etc. calls
16928c2ecf20Sopenharmony_ci	 * from our driver, since we need to sequence them within the
16938c2ecf20Sopenharmony_ci	 * encoder's enable/disable paths.
16948c2ecf20Sopenharmony_ci	 */
16958c2ecf20Sopenharmony_ci	list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain);
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset);
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	return 0;
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cistatic void vc4_dsi_unbind(struct device *dev, struct device *master,
17058c2ecf20Sopenharmony_ci			   void *data)
17068c2ecf20Sopenharmony_ci{
17078c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = dev_get_drvdata(dev);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	if (dsi->bridge)
17108c2ecf20Sopenharmony_ci		pm_runtime_disable(dev);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	/*
17138c2ecf20Sopenharmony_ci	 * Restore the bridge_chain so the bridge detach procedure can happen
17148c2ecf20Sopenharmony_ci	 * normally.
17158c2ecf20Sopenharmony_ci	 */
17168c2ecf20Sopenharmony_ci	list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain);
17178c2ecf20Sopenharmony_ci	drm_encoder_cleanup(dsi->encoder);
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic const struct component_ops vc4_dsi_ops = {
17218c2ecf20Sopenharmony_ci	.bind   = vc4_dsi_bind,
17228c2ecf20Sopenharmony_ci	.unbind = vc4_dsi_unbind,
17238c2ecf20Sopenharmony_ci};
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic int vc4_dsi_dev_probe(struct platform_device *pdev)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
17288c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi;
17298c2ecf20Sopenharmony_ci	int ret;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
17328c2ecf20Sopenharmony_ci	if (!dsi)
17338c2ecf20Sopenharmony_ci		return -ENOMEM;
17348c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, dsi);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	dsi->pdev = pdev;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	/* Note, the initialization sequence for DSI and panels is
17398c2ecf20Sopenharmony_ci	 * tricky.  The component bind above won't get past its
17408c2ecf20Sopenharmony_ci	 * -EPROBE_DEFER until the panel/bridge probes.  The
17418c2ecf20Sopenharmony_ci	 * panel/bridge will return -EPROBE_DEFER until it has a
17428c2ecf20Sopenharmony_ci	 * mipi_dsi_host to register its device to.  So, we register
17438c2ecf20Sopenharmony_ci	 * the host during pdev probe time, so vc4 as a whole can then
17448c2ecf20Sopenharmony_ci	 * -EPROBE_DEFER its component bind process until the panel
17458c2ecf20Sopenharmony_ci	 * successfully attaches.
17468c2ecf20Sopenharmony_ci	 */
17478c2ecf20Sopenharmony_ci	dsi->dsi_host.ops = &vc4_dsi_host_ops;
17488c2ecf20Sopenharmony_ci	dsi->dsi_host.dev = dev;
17498c2ecf20Sopenharmony_ci	mipi_dsi_host_register(&dsi->dsi_host);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	ret = component_add(&pdev->dev, &vc4_dsi_ops);
17528c2ecf20Sopenharmony_ci	if (ret) {
17538c2ecf20Sopenharmony_ci		mipi_dsi_host_unregister(&dsi->dsi_host);
17548c2ecf20Sopenharmony_ci		return ret;
17558c2ecf20Sopenharmony_ci	}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	return 0;
17588c2ecf20Sopenharmony_ci}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_cistatic int vc4_dsi_dev_remove(struct platform_device *pdev)
17618c2ecf20Sopenharmony_ci{
17628c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
17638c2ecf20Sopenharmony_ci	struct vc4_dsi *dsi = dev_get_drvdata(dev);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	component_del(&pdev->dev, &vc4_dsi_ops);
17668c2ecf20Sopenharmony_ci	mipi_dsi_host_unregister(&dsi->dsi_host);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	return 0;
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_cistruct platform_driver vc4_dsi_driver = {
17728c2ecf20Sopenharmony_ci	.probe = vc4_dsi_dev_probe,
17738c2ecf20Sopenharmony_ci	.remove = vc4_dsi_dev_remove,
17748c2ecf20Sopenharmony_ci	.driver = {
17758c2ecf20Sopenharmony_ci		.name = "vc4_dsi",
17768c2ecf20Sopenharmony_ci		.of_match_table = vc4_dsi_dt_match,
17778c2ecf20Sopenharmony_ci	},
17788c2ecf20Sopenharmony_ci};
1779