18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2013 NVIDIA Corporation
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk.h>
78c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/host1x.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
168c2ecf20Sopenharmony_ci#include <linux/reset.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <video/mipi_display.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
218c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h>
228c2ecf20Sopenharmony_ci#include <drm/drm_file.h>
238c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h>
248c2ecf20Sopenharmony_ci#include <drm/drm_panel.h>
258c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "dc.h"
288c2ecf20Sopenharmony_ci#include "drm.h"
298c2ecf20Sopenharmony_ci#include "dsi.h"
308c2ecf20Sopenharmony_ci#include "mipi-phy.h"
318c2ecf20Sopenharmony_ci#include "trace.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct tegra_dsi_state {
348c2ecf20Sopenharmony_ci	struct drm_connector_state base;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	struct mipi_dphy_timing timing;
378c2ecf20Sopenharmony_ci	unsigned long period;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	unsigned int vrefresh;
408c2ecf20Sopenharmony_ci	unsigned int lanes;
418c2ecf20Sopenharmony_ci	unsigned long pclk;
428c2ecf20Sopenharmony_ci	unsigned long bclk;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	enum tegra_dsi_format format;
458c2ecf20Sopenharmony_ci	unsigned int mul;
468c2ecf20Sopenharmony_ci	unsigned int div;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline struct tegra_dsi_state *
508c2ecf20Sopenharmony_cito_dsi_state(struct drm_connector_state *state)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	return container_of(state, struct tegra_dsi_state, base);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct tegra_dsi {
568c2ecf20Sopenharmony_ci	struct host1x_client client;
578c2ecf20Sopenharmony_ci	struct tegra_output output;
588c2ecf20Sopenharmony_ci	struct device *dev;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	void __iomem *regs;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	struct reset_control *rst;
638c2ecf20Sopenharmony_ci	struct clk *clk_parent;
648c2ecf20Sopenharmony_ci	struct clk *clk_lp;
658c2ecf20Sopenharmony_ci	struct clk *clk;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct drm_info_list *debugfs_files;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	unsigned long flags;
708c2ecf20Sopenharmony_ci	enum mipi_dsi_pixel_format format;
718c2ecf20Sopenharmony_ci	unsigned int lanes;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	struct tegra_mipi_device *mipi;
748c2ecf20Sopenharmony_ci	struct mipi_dsi_host host;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	struct regulator *vdd;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	unsigned int video_fifo_depth;
798c2ecf20Sopenharmony_ci	unsigned int host_fifo_depth;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* for ganged-mode support */
828c2ecf20Sopenharmony_ci	struct tegra_dsi *master;
838c2ecf20Sopenharmony_ci	struct tegra_dsi *slave;
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline struct tegra_dsi *
878c2ecf20Sopenharmony_cihost1x_client_to_dsi(struct host1x_client *client)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	return container_of(client, struct tegra_dsi, client);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	return container_of(host, struct tegra_dsi, host);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic inline struct tegra_dsi *to_dsi(struct tegra_output *output)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return container_of(output, struct tegra_dsi, output);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	return to_dsi_state(dsi->output.connector.state);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned int offset)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	u32 value = readl(dsi->regs + (offset << 2));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	trace_dsi_readl(dsi->dev, offset, value);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return value;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
1178c2ecf20Sopenharmony_ci				    unsigned int offset)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	trace_dsi_writel(dsi->dev, offset, value);
1208c2ecf20Sopenharmony_ci	writel(value, dsi->regs + (offset << 2));
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci#define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name }
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 tegra_dsi_regs[] = {
1268c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INCR_SYNCPT),
1278c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INCR_SYNCPT_CONTROL),
1288c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INCR_SYNCPT_ERROR),
1298c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_CTXSW),
1308c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_RD_DATA),
1318c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_WR_DATA),
1328c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_POWER_CONTROL),
1338c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INT_ENABLE),
1348c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INT_STATUS),
1358c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INT_MASK),
1368c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_HOST_CONTROL),
1378c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_CONTROL),
1388c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_SOL_DELAY),
1398c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_MAX_THRESHOLD),
1408c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_TRIGGER),
1418c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_TX_CRC),
1428c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_STATUS),
1438c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_CONTROL),
1448c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_0),
1458c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_1),
1468c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_2),
1478c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_3),
1488c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_4),
1498c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_5),
1508c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_6),
1518c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_7),
1528c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_0_LO),
1538c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_0_HI),
1548c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_1_LO),
1558c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_1_HI),
1568c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_2_LO),
1578c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_2_HI),
1588c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_3_LO),
1598c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_3_HI),
1608c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_4_LO),
1618c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_4_HI),
1628c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_5_LO),
1638c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_SEQ_5_HI),
1648c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_DCS_CMDS),
1658c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_LEN_0_1),
1668c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_LEN_2_3),
1678c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_LEN_4_5),
1688c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PKT_LEN_6_7),
1698c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PHY_TIMING_0),
1708c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PHY_TIMING_1),
1718c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PHY_TIMING_2),
1728c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_BTA_TIMING),
1738c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_TIMEOUT_0),
1748c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_TIMEOUT_1),
1758c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_TO_TALLY),
1768c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_0),
1778c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_CD),
1788c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CD_STATUS),
1798c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_VIDEO_MODE_CONTROL),
1808c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_1),
1818c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_2),
1828c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_3),
1838c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_PAD_CONTROL_4),
1848c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL),
1858c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_GANGED_MODE_START),
1868c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_GANGED_MODE_SIZE),
1878c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT),
1888c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL),
1898c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8),
1908c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9),
1918c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10),
1928c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11),
1938c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12),
1948c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13),
1958c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14),
1968c2ecf20Sopenharmony_ci	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15),
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int tegra_dsi_show_regs(struct seq_file *s, void *data)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct drm_info_node *node = s->private;
2028c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = node->info_ent->data;
2038c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = dsi->output.encoder.crtc;
2048c2ecf20Sopenharmony_ci	struct drm_device *drm = node->minor->dev;
2058c2ecf20Sopenharmony_ci	unsigned int i;
2068c2ecf20Sopenharmony_ci	int err = 0;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	drm_modeset_lock_all(drm);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!crtc || !crtc->state->active) {
2118c2ecf20Sopenharmony_ci		err = -EBUSY;
2128c2ecf20Sopenharmony_ci		goto unlock;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tegra_dsi_regs); i++) {
2168c2ecf20Sopenharmony_ci		unsigned int offset = tegra_dsi_regs[i].offset;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		seq_printf(s, "%-32s %#05x %08x\n", tegra_dsi_regs[i].name,
2198c2ecf20Sopenharmony_ci			   offset, tegra_dsi_readl(dsi, offset));
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ciunlock:
2238c2ecf20Sopenharmony_ci	drm_modeset_unlock_all(drm);
2248c2ecf20Sopenharmony_ci	return err;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic struct drm_info_list debugfs_files[] = {
2288c2ecf20Sopenharmony_ci	{ "regs", tegra_dsi_show_regs, 0, NULL },
2298c2ecf20Sopenharmony_ci};
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int tegra_dsi_late_register(struct drm_connector *connector)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct tegra_output *output = connector_to_output(connector);
2348c2ecf20Sopenharmony_ci	unsigned int i, count = ARRAY_SIZE(debugfs_files);
2358c2ecf20Sopenharmony_ci	struct drm_minor *minor = connector->dev->primary;
2368c2ecf20Sopenharmony_ci	struct dentry *root = connector->debugfs_entry;
2378c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = to_dsi(output);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
2408c2ecf20Sopenharmony_ci				     GFP_KERNEL);
2418c2ecf20Sopenharmony_ci	if (!dsi->debugfs_files)
2428c2ecf20Sopenharmony_ci		return -ENOMEM;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
2458c2ecf20Sopenharmony_ci		dsi->debugfs_files[i].data = dsi;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	drm_debugfs_create_files(dsi->debugfs_files, count, root, minor);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic void tegra_dsi_early_unregister(struct drm_connector *connector)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct tegra_output *output = connector_to_output(connector);
2558c2ecf20Sopenharmony_ci	unsigned int count = ARRAY_SIZE(debugfs_files);
2568c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = to_dsi(output);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	drm_debugfs_remove_files(dsi->debugfs_files, count,
2598c2ecf20Sopenharmony_ci				 connector->dev->primary);
2608c2ecf20Sopenharmony_ci	kfree(dsi->debugfs_files);
2618c2ecf20Sopenharmony_ci	dsi->debugfs_files = NULL;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci#define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
2658c2ecf20Sopenharmony_ci#define PKT_LEN0(len)	(((len) & 0x07) <<  0)
2668c2ecf20Sopenharmony_ci#define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
2678c2ecf20Sopenharmony_ci#define PKT_LEN1(len)	(((len) & 0x07) << 10)
2688c2ecf20Sopenharmony_ci#define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
2698c2ecf20Sopenharmony_ci#define PKT_LEN2(len)	(((len) & 0x07) << 20)
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#define PKT_LP		(1 << 30)
2728c2ecf20Sopenharmony_ci#define NUM_PKT_SEQ	12
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/*
2758c2ecf20Sopenharmony_ci * non-burst mode with sync pulses
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_cistatic const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
2788c2ecf20Sopenharmony_ci	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
2798c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
2808c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
2818c2ecf20Sopenharmony_ci	       PKT_LP,
2828c2ecf20Sopenharmony_ci	[ 1] = 0,
2838c2ecf20Sopenharmony_ci	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
2848c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
2858c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
2868c2ecf20Sopenharmony_ci	       PKT_LP,
2878c2ecf20Sopenharmony_ci	[ 3] = 0,
2888c2ecf20Sopenharmony_ci	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
2898c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
2908c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
2918c2ecf20Sopenharmony_ci	       PKT_LP,
2928c2ecf20Sopenharmony_ci	[ 5] = 0,
2938c2ecf20Sopenharmony_ci	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
2948c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
2958c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
2968c2ecf20Sopenharmony_ci	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
2978c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
2988c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
2998c2ecf20Sopenharmony_ci	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3008c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
3018c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
3028c2ecf20Sopenharmony_ci	       PKT_LP,
3038c2ecf20Sopenharmony_ci	[ 9] = 0,
3048c2ecf20Sopenharmony_ci	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3058c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
3068c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
3078c2ecf20Sopenharmony_ci	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
3088c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
3098c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * non-burst mode with sync events
3148c2ecf20Sopenharmony_ci */
3158c2ecf20Sopenharmony_cistatic const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
3168c2ecf20Sopenharmony_ci	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
3178c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
3188c2ecf20Sopenharmony_ci	       PKT_LP,
3198c2ecf20Sopenharmony_ci	[ 1] = 0,
3208c2ecf20Sopenharmony_ci	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3218c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
3228c2ecf20Sopenharmony_ci	       PKT_LP,
3238c2ecf20Sopenharmony_ci	[ 3] = 0,
3248c2ecf20Sopenharmony_ci	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3258c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
3268c2ecf20Sopenharmony_ci	       PKT_LP,
3278c2ecf20Sopenharmony_ci	[ 5] = 0,
3288c2ecf20Sopenharmony_ci	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3298c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
3308c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
3318c2ecf20Sopenharmony_ci	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
3328c2ecf20Sopenharmony_ci	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3338c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
3348c2ecf20Sopenharmony_ci	       PKT_LP,
3358c2ecf20Sopenharmony_ci	[ 9] = 0,
3368c2ecf20Sopenharmony_ci	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
3378c2ecf20Sopenharmony_ci	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
3388c2ecf20Sopenharmony_ci	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
3398c2ecf20Sopenharmony_ci	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
3408c2ecf20Sopenharmony_ci};
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
3438c2ecf20Sopenharmony_ci	[ 0] = 0,
3448c2ecf20Sopenharmony_ci	[ 1] = 0,
3458c2ecf20Sopenharmony_ci	[ 2] = 0,
3468c2ecf20Sopenharmony_ci	[ 3] = 0,
3478c2ecf20Sopenharmony_ci	[ 4] = 0,
3488c2ecf20Sopenharmony_ci	[ 5] = 0,
3498c2ecf20Sopenharmony_ci	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
3508c2ecf20Sopenharmony_ci	[ 7] = 0,
3518c2ecf20Sopenharmony_ci	[ 8] = 0,
3528c2ecf20Sopenharmony_ci	[ 9] = 0,
3538c2ecf20Sopenharmony_ci	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
3548c2ecf20Sopenharmony_ci	[11] = 0,
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
3588c2ecf20Sopenharmony_ci				     unsigned long period,
3598c2ecf20Sopenharmony_ci				     const struct mipi_dphy_timing *timing)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	u32 value;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
3648c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
3658c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
3668c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->hsprepare, period, 1);
3678c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
3708c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
3718c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
3728c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->lpx, period, 1);
3738c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
3768c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
3778c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
3788c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
3818c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
3828c2ecf20Sopenharmony_ci		DSI_TIMING_FIELD(timing->tago, period, 1);
3838c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (dsi->slave)
3868c2ecf20Sopenharmony_ci		tegra_dsi_set_phy_timing(dsi->slave, period, timing);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
3908c2ecf20Sopenharmony_ci				unsigned int *mulp, unsigned int *divp)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	switch (format) {
3938c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666_PACKED:
3948c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB888:
3958c2ecf20Sopenharmony_ci		*mulp = 3;
3968c2ecf20Sopenharmony_ci		*divp = 1;
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB565:
4008c2ecf20Sopenharmony_ci		*mulp = 2;
4018c2ecf20Sopenharmony_ci		*divp = 1;
4028c2ecf20Sopenharmony_ci		break;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666:
4058c2ecf20Sopenharmony_ci		*mulp = 9;
4068c2ecf20Sopenharmony_ci		*divp = 4;
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	default:
4108c2ecf20Sopenharmony_ci		return -EINVAL;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
4178c2ecf20Sopenharmony_ci				enum tegra_dsi_format *fmt)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	switch (format) {
4208c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB888:
4218c2ecf20Sopenharmony_ci		*fmt = TEGRA_DSI_FORMAT_24P;
4228c2ecf20Sopenharmony_ci		break;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666:
4258c2ecf20Sopenharmony_ci		*fmt = TEGRA_DSI_FORMAT_18NP;
4268c2ecf20Sopenharmony_ci		break;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB666_PACKED:
4298c2ecf20Sopenharmony_ci		*fmt = TEGRA_DSI_FORMAT_18P;
4308c2ecf20Sopenharmony_ci		break;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	case MIPI_DSI_FMT_RGB565:
4338c2ecf20Sopenharmony_ci		*fmt = TEGRA_DSI_FORMAT_16P;
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	default:
4378c2ecf20Sopenharmony_ci		return -EINVAL;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	return 0;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
4448c2ecf20Sopenharmony_ci				    unsigned int size)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	u32 value;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
4498c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	value = DSI_GANGED_MODE_CONTROL_ENABLE;
4528c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic void tegra_dsi_enable(struct tegra_dsi *dsi)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	u32 value;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
4608c2ecf20Sopenharmony_ci	value |= DSI_POWER_CONTROL_ENABLE;
4618c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (dsi->slave)
4648c2ecf20Sopenharmony_ci		tegra_dsi_enable(dsi->slave);
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	if (dsi->master)
4708c2ecf20Sopenharmony_ci		return dsi->master->lanes + dsi->lanes;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (dsi->slave)
4738c2ecf20Sopenharmony_ci		return dsi->lanes + dsi->slave->lanes;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return dsi->lanes;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
4798c2ecf20Sopenharmony_ci				const struct drm_display_mode *mode)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	unsigned int hact, hsw, hbp, hfp, i, mul, div;
4828c2ecf20Sopenharmony_ci	struct tegra_dsi_state *state;
4838c2ecf20Sopenharmony_ci	const u32 *pkt_seq;
4848c2ecf20Sopenharmony_ci	u32 value;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* XXX: pass in state into this function? */
4878c2ecf20Sopenharmony_ci	if (dsi->master)
4888c2ecf20Sopenharmony_ci		state = tegra_dsi_get_state(dsi->master);
4898c2ecf20Sopenharmony_ci	else
4908c2ecf20Sopenharmony_ci		state = tegra_dsi_get_state(dsi);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	mul = state->mul;
4938c2ecf20Sopenharmony_ci	div = state->div;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
4968c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
4978c2ecf20Sopenharmony_ci		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
4988c2ecf20Sopenharmony_ci	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
4998c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
5008c2ecf20Sopenharmony_ci		pkt_seq = pkt_seq_video_non_burst_sync_events;
5018c2ecf20Sopenharmony_ci	} else {
5028c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Command mode\n");
5038c2ecf20Sopenharmony_ci		pkt_seq = pkt_seq_command_mode;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	value = DSI_CONTROL_CHANNEL(0) |
5078c2ecf20Sopenharmony_ci		DSI_CONTROL_FORMAT(state->format) |
5088c2ecf20Sopenharmony_ci		DSI_CONTROL_LANES(dsi->lanes - 1) |
5098c2ecf20Sopenharmony_ci		DSI_CONTROL_SOURCE(pipe);
5108c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_CONTROL);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	value = DSI_HOST_CONTROL_HS;
5158c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_CONTROL);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
5208c2ecf20Sopenharmony_ci		value |= DSI_CONTROL_HS_CLK_CTRL;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	value &= ~DSI_CONTROL_TX_TRIG(3);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* enable DCS commands for command mode */
5258c2ecf20Sopenharmony_ci	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
5268c2ecf20Sopenharmony_ci		value &= ~DSI_CONTROL_DCS_ENABLE;
5278c2ecf20Sopenharmony_ci	else
5288c2ecf20Sopenharmony_ci		value |= DSI_CONTROL_DCS_ENABLE;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	value |= DSI_CONTROL_VIDEO_ENABLE;
5318c2ecf20Sopenharmony_ci	value &= ~DSI_CONTROL_HOST_ENABLE;
5328c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_CONTROL);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_PKT_SEQ; i++)
5358c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
5388c2ecf20Sopenharmony_ci		/* horizontal active pixels */
5398c2ecf20Sopenharmony_ci		hact = mode->hdisplay * mul / div;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		/* horizontal sync width */
5428c2ecf20Sopenharmony_ci		hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		/* horizontal back porch */
5458c2ecf20Sopenharmony_ci		hbp = (mode->htotal - mode->hsync_end) * mul / div;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		if ((dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
5488c2ecf20Sopenharmony_ci			hbp += hsw;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		/* horizontal front porch */
5518c2ecf20Sopenharmony_ci		hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		/* subtract packet overhead */
5548c2ecf20Sopenharmony_ci		hsw -= 10;
5558c2ecf20Sopenharmony_ci		hbp -= 14;
5568c2ecf20Sopenharmony_ci		hfp -= 8;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
5598c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
5608c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
5618c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		/* set SOL delay (for non-burst mode only) */
5648c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		/* TODO: implement ganged mode */
5678c2ecf20Sopenharmony_ci	} else {
5688c2ecf20Sopenharmony_ci		u16 bytes;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		if (dsi->master || dsi->slave) {
5718c2ecf20Sopenharmony_ci			/*
5728c2ecf20Sopenharmony_ci			 * For ganged mode, assume symmetric left-right mode.
5738c2ecf20Sopenharmony_ci			 */
5748c2ecf20Sopenharmony_ci			bytes = 1 + (mode->hdisplay / 2) * mul / div;
5758c2ecf20Sopenharmony_ci		} else {
5768c2ecf20Sopenharmony_ci			/* 1 byte (DCS command) + pixel data */
5778c2ecf20Sopenharmony_ci			bytes = 1 + mode->hdisplay * mul / div;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
5818c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
5828c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
5838c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
5868c2ecf20Sopenharmony_ci			MIPI_DCS_WRITE_MEMORY_CONTINUE;
5878c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		/* set SOL delay */
5908c2ecf20Sopenharmony_ci		if (dsi->master || dsi->slave) {
5918c2ecf20Sopenharmony_ci			unsigned long delay, bclk, bclk_ganged;
5928c2ecf20Sopenharmony_ci			unsigned int lanes = state->lanes;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci			/* SOL to valid, valid to FIFO and FIFO write delay */
5958c2ecf20Sopenharmony_ci			delay = 4 + 4 + 2;
5968c2ecf20Sopenharmony_ci			delay = DIV_ROUND_UP(delay * mul, div * lanes);
5978c2ecf20Sopenharmony_ci			/* FIFO read delay */
5988c2ecf20Sopenharmony_ci			delay = delay + 6;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes);
6018c2ecf20Sopenharmony_ci			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
6028c2ecf20Sopenharmony_ci			value = bclk - bclk_ganged + delay + 20;
6038c2ecf20Sopenharmony_ci		} else {
6048c2ecf20Sopenharmony_ci			/* TODO: revisit for non-ganged mode */
6058c2ecf20Sopenharmony_ci			value = 8 * mul / div;
6068c2ecf20Sopenharmony_ci		}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (dsi->slave) {
6128c2ecf20Sopenharmony_ci		tegra_dsi_configure(dsi->slave, pipe, mode);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		/*
6158c2ecf20Sopenharmony_ci		 * TODO: Support modes other than symmetrical left-right
6168c2ecf20Sopenharmony_ci		 * split.
6178c2ecf20Sopenharmony_ci		 */
6188c2ecf20Sopenharmony_ci		tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
6198c2ecf20Sopenharmony_ci		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
6208c2ecf20Sopenharmony_ci					mode->hdisplay / 2);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	u32 value;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(timeout);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	while (time_before(jiffies, timeout)) {
6318c2ecf20Sopenharmony_ci		value = tegra_dsi_readl(dsi, DSI_STATUS);
6328c2ecf20Sopenharmony_ci		if (value & DSI_STATUS_IDLE)
6338c2ecf20Sopenharmony_ci			return 0;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic void tegra_dsi_video_disable(struct tegra_dsi *dsi)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	u32 value;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_CONTROL);
6468c2ecf20Sopenharmony_ci	value &= ~DSI_CONTROL_VIDEO_ENABLE;
6478c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_CONTROL);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (dsi->slave)
6508c2ecf20Sopenharmony_ci		tegra_dsi_video_disable(dsi->slave);
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
6568c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
6578c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	u32 value;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
6658c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	return 0;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	u32 value;
6738c2ecf20Sopenharmony_ci	int err;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	/*
6768c2ecf20Sopenharmony_ci	 * XXX Is this still needed? The module reset is deasserted right
6778c2ecf20Sopenharmony_ci	 * before this function is called.
6788c2ecf20Sopenharmony_ci	 */
6798c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
6808c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
6818c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
6828c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
6838c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/* start calibration */
6868c2ecf20Sopenharmony_ci	tegra_dsi_pad_enable(dsi);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
6898c2ecf20Sopenharmony_ci		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
6908c2ecf20Sopenharmony_ci		DSI_PAD_OUT_CLK(0x0);
6918c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
6948c2ecf20Sopenharmony_ci		DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
6958c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	err = tegra_mipi_start_calibration(dsi->mipi);
6988c2ecf20Sopenharmony_ci	if (err < 0)
6998c2ecf20Sopenharmony_ci		return err;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return tegra_mipi_finish_calibration(dsi->mipi);
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
7058c2ecf20Sopenharmony_ci				  unsigned int vrefresh)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	unsigned int timeout;
7088c2ecf20Sopenharmony_ci	u32 value;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/* one frame high-speed transmission timeout */
7118c2ecf20Sopenharmony_ci	timeout = (bclk / vrefresh) / 512;
7128c2ecf20Sopenharmony_ci	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
7138c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* 2 ms peripheral timeout for panel */
7168c2ecf20Sopenharmony_ci	timeout = 2 * bclk / 512 * 1000;
7178c2ecf20Sopenharmony_ci	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
7188c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
7218c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (dsi->slave)
7248c2ecf20Sopenharmony_ci		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic void tegra_dsi_disable(struct tegra_dsi *dsi)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	u32 value;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (dsi->slave) {
7328c2ecf20Sopenharmony_ci		tegra_dsi_ganged_disable(dsi->slave);
7338c2ecf20Sopenharmony_ci		tegra_dsi_ganged_disable(dsi);
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
7378c2ecf20Sopenharmony_ci	value &= ~DSI_POWER_CONTROL_ENABLE;
7388c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (dsi->slave)
7418c2ecf20Sopenharmony_ci		tegra_dsi_disable(dsi->slave);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	usleep_range(5000, 10000);
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cistatic void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	u32 value;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
7518c2ecf20Sopenharmony_ci	value &= ~DSI_POWER_CONTROL_ENABLE;
7528c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	usleep_range(300, 1000);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
7578c2ecf20Sopenharmony_ci	value |= DSI_POWER_CONTROL_ENABLE;
7588c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	usleep_range(300, 1000);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_TRIGGER);
7638c2ecf20Sopenharmony_ci	if (value)
7648c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if (dsi->slave)
7678c2ecf20Sopenharmony_ci		tegra_dsi_soft_reset(dsi->slave);
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic void tegra_dsi_connector_reset(struct drm_connector *connector)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct tegra_dsi_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (!state)
7758c2ecf20Sopenharmony_ci		return;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	if (connector->state) {
7788c2ecf20Sopenharmony_ci		__drm_atomic_helper_connector_destroy_state(connector->state);
7798c2ecf20Sopenharmony_ci		kfree(connector->state);
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	__drm_atomic_helper_connector_reset(connector, &state->base);
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic struct drm_connector_state *
7868c2ecf20Sopenharmony_citegra_dsi_connector_duplicate_state(struct drm_connector *connector)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct tegra_dsi_state *state = to_dsi_state(connector->state);
7898c2ecf20Sopenharmony_ci	struct tegra_dsi_state *copy;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
7928c2ecf20Sopenharmony_ci	if (!copy)
7938c2ecf20Sopenharmony_ci		return NULL;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	__drm_atomic_helper_connector_duplicate_state(connector,
7968c2ecf20Sopenharmony_ci						      &copy->base);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return &copy->base;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs tegra_dsi_connector_funcs = {
8028c2ecf20Sopenharmony_ci	.reset = tegra_dsi_connector_reset,
8038c2ecf20Sopenharmony_ci	.detect = tegra_output_connector_detect,
8048c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
8058c2ecf20Sopenharmony_ci	.destroy = tegra_output_connector_destroy,
8068c2ecf20Sopenharmony_ci	.atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
8078c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
8088c2ecf20Sopenharmony_ci	.late_register = tegra_dsi_late_register,
8098c2ecf20Sopenharmony_ci	.early_unregister = tegra_dsi_early_unregister,
8108c2ecf20Sopenharmony_ci};
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cistatic enum drm_mode_status
8138c2ecf20Sopenharmony_citegra_dsi_connector_mode_valid(struct drm_connector *connector,
8148c2ecf20Sopenharmony_ci			       struct drm_display_mode *mode)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	return MODE_OK;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
8208c2ecf20Sopenharmony_ci	.get_modes = tegra_output_connector_get_modes,
8218c2ecf20Sopenharmony_ci	.mode_valid = tegra_dsi_connector_mode_valid,
8228c2ecf20Sopenharmony_ci};
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic void tegra_dsi_unprepare(struct tegra_dsi *dsi)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	int err;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (dsi->slave)
8298c2ecf20Sopenharmony_ci		tegra_dsi_unprepare(dsi->slave);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	err = tegra_mipi_disable(dsi->mipi);
8328c2ecf20Sopenharmony_ci	if (err < 0)
8338c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n",
8348c2ecf20Sopenharmony_ci			err);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	err = host1x_client_suspend(&dsi->client);
8378c2ecf20Sopenharmony_ci	if (err < 0)
8388c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to suspend: %d\n", err);
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct tegra_output *output = encoder_to_output(encoder);
8448c2ecf20Sopenharmony_ci	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
8458c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = to_dsi(output);
8468c2ecf20Sopenharmony_ci	u32 value;
8478c2ecf20Sopenharmony_ci	int err;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (output->panel)
8508c2ecf20Sopenharmony_ci		drm_panel_disable(output->panel);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	tegra_dsi_video_disable(dsi);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	/*
8558c2ecf20Sopenharmony_ci	 * The following accesses registers of the display controller, so make
8568c2ecf20Sopenharmony_ci	 * sure it's only executed when the output is attached to one.
8578c2ecf20Sopenharmony_ci	 */
8588c2ecf20Sopenharmony_ci	if (dc) {
8598c2ecf20Sopenharmony_ci		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
8608c2ecf20Sopenharmony_ci		value &= ~DSI_ENABLE;
8618c2ecf20Sopenharmony_ci		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		tegra_dc_commit(dc);
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	err = tegra_dsi_wait_idle(dsi, 100);
8678c2ecf20Sopenharmony_ci	if (err < 0)
8688c2ecf20Sopenharmony_ci		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	tegra_dsi_soft_reset(dsi);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (output->panel)
8738c2ecf20Sopenharmony_ci		drm_panel_unprepare(output->panel);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	tegra_dsi_disable(dsi);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	tegra_dsi_unprepare(dsi);
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic int tegra_dsi_prepare(struct tegra_dsi *dsi)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	int err;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	err = host1x_client_resume(&dsi->client);
8858c2ecf20Sopenharmony_ci	if (err < 0) {
8868c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to resume: %d\n", err);
8878c2ecf20Sopenharmony_ci		return err;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	err = tegra_mipi_enable(dsi->mipi);
8918c2ecf20Sopenharmony_ci	if (err < 0)
8928c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to enable MIPI calibration: %d\n",
8938c2ecf20Sopenharmony_ci			err);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	err = tegra_dsi_pad_calibrate(dsi);
8968c2ecf20Sopenharmony_ci	if (err < 0)
8978c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	if (dsi->slave)
9008c2ecf20Sopenharmony_ci		tegra_dsi_prepare(dsi->slave);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return 0;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cistatic void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
9088c2ecf20Sopenharmony_ci	struct tegra_output *output = encoder_to_output(encoder);
9098c2ecf20Sopenharmony_ci	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
9108c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = to_dsi(output);
9118c2ecf20Sopenharmony_ci	struct tegra_dsi_state *state;
9128c2ecf20Sopenharmony_ci	u32 value;
9138c2ecf20Sopenharmony_ci	int err;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	err = tegra_dsi_prepare(dsi);
9168c2ecf20Sopenharmony_ci	if (err < 0) {
9178c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to prepare: %d\n", err);
9188c2ecf20Sopenharmony_ci		return;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	state = tegra_dsi_get_state(dsi);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	/*
9268c2ecf20Sopenharmony_ci	 * The D-PHY timing fields are expressed in byte-clock cycles, so
9278c2ecf20Sopenharmony_ci	 * multiply the period by 8.
9288c2ecf20Sopenharmony_ci	 */
9298c2ecf20Sopenharmony_ci	tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	if (output->panel)
9328c2ecf20Sopenharmony_ci		drm_panel_prepare(output->panel);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	tegra_dsi_configure(dsi, dc->pipe, mode);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	/* enable display controller */
9378c2ecf20Sopenharmony_ci	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
9388c2ecf20Sopenharmony_ci	value |= DSI_ENABLE;
9398c2ecf20Sopenharmony_ci	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	tegra_dc_commit(dc);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* enable DSI controller */
9448c2ecf20Sopenharmony_ci	tegra_dsi_enable(dsi);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (output->panel)
9478c2ecf20Sopenharmony_ci		drm_panel_enable(output->panel);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic int
9518c2ecf20Sopenharmony_citegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
9528c2ecf20Sopenharmony_ci			       struct drm_crtc_state *crtc_state,
9538c2ecf20Sopenharmony_ci			       struct drm_connector_state *conn_state)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct tegra_output *output = encoder_to_output(encoder);
9568c2ecf20Sopenharmony_ci	struct tegra_dsi_state *state = to_dsi_state(conn_state);
9578c2ecf20Sopenharmony_ci	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
9588c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = to_dsi(output);
9598c2ecf20Sopenharmony_ci	unsigned int scdiv;
9608c2ecf20Sopenharmony_ci	unsigned long plld;
9618c2ecf20Sopenharmony_ci	int err;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	state->pclk = crtc_state->mode.clock * 1000;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
9668c2ecf20Sopenharmony_ci	if (err < 0)
9678c2ecf20Sopenharmony_ci		return err;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	state->lanes = tegra_dsi_get_lanes(dsi);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	err = tegra_dsi_get_format(dsi->format, &state->format);
9728c2ecf20Sopenharmony_ci	if (err < 0)
9738c2ecf20Sopenharmony_ci		return err;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	/* compute byte clock */
9788c2ecf20Sopenharmony_ci	state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
9818c2ecf20Sopenharmony_ci		      state->lanes);
9828c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
9838c2ecf20Sopenharmony_ci		      state->vrefresh);
9848c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	/*
9878c2ecf20Sopenharmony_ci	 * Compute bit clock and round up to the next MHz.
9888c2ecf20Sopenharmony_ci	 */
9898c2ecf20Sopenharmony_ci	plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
9908c2ecf20Sopenharmony_ci	state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	err = mipi_dphy_timing_get_default(&state->timing, state->period);
9938c2ecf20Sopenharmony_ci	if (err < 0)
9948c2ecf20Sopenharmony_ci		return err;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	err = mipi_dphy_timing_validate(&state->timing, state->period);
9978c2ecf20Sopenharmony_ci	if (err < 0) {
9988c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
9998c2ecf20Sopenharmony_ci		return err;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	/*
10038c2ecf20Sopenharmony_ci	 * We divide the frequency by two here, but we make up for that by
10048c2ecf20Sopenharmony_ci	 * setting the shift clock divider (further below) to half of the
10058c2ecf20Sopenharmony_ci	 * correct value.
10068c2ecf20Sopenharmony_ci	 */
10078c2ecf20Sopenharmony_ci	plld /= 2;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	/*
10108c2ecf20Sopenharmony_ci	 * Derive pixel clock from bit clock using the shift clock divider.
10118c2ecf20Sopenharmony_ci	 * Note that this is only half of what we would expect, but we need
10128c2ecf20Sopenharmony_ci	 * that to make up for the fact that we divided the bit clock by a
10138c2ecf20Sopenharmony_ci	 * factor of two above.
10148c2ecf20Sopenharmony_ci	 *
10158c2ecf20Sopenharmony_ci	 * It's not clear exactly why this is necessary, but the display is
10168c2ecf20Sopenharmony_ci	 * not working properly otherwise. Perhaps the PLLs cannot generate
10178c2ecf20Sopenharmony_ci	 * frequencies sufficiently high.
10188c2ecf20Sopenharmony_ci	 */
10198c2ecf20Sopenharmony_ci	scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
10228c2ecf20Sopenharmony_ci					 plld, scdiv);
10238c2ecf20Sopenharmony_ci	if (err < 0) {
10248c2ecf20Sopenharmony_ci		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
10258c2ecf20Sopenharmony_ci		return err;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	return err;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
10328c2ecf20Sopenharmony_ci	.disable = tegra_dsi_encoder_disable,
10338c2ecf20Sopenharmony_ci	.enable = tegra_dsi_encoder_enable,
10348c2ecf20Sopenharmony_ci	.atomic_check = tegra_dsi_encoder_atomic_check,
10358c2ecf20Sopenharmony_ci};
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int tegra_dsi_init(struct host1x_client *client)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	struct drm_device *drm = dev_get_drvdata(client->host);
10408c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
10418c2ecf20Sopenharmony_ci	int err;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	/* Gangsters must not register their own outputs. */
10448c2ecf20Sopenharmony_ci	if (!dsi->master) {
10458c2ecf20Sopenharmony_ci		dsi->output.dev = client->dev;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci		drm_connector_init(drm, &dsi->output.connector,
10488c2ecf20Sopenharmony_ci				   &tegra_dsi_connector_funcs,
10498c2ecf20Sopenharmony_ci				   DRM_MODE_CONNECTOR_DSI);
10508c2ecf20Sopenharmony_ci		drm_connector_helper_add(&dsi->output.connector,
10518c2ecf20Sopenharmony_ci					 &tegra_dsi_connector_helper_funcs);
10528c2ecf20Sopenharmony_ci		dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci		drm_simple_encoder_init(drm, &dsi->output.encoder,
10558c2ecf20Sopenharmony_ci					DRM_MODE_ENCODER_DSI);
10568c2ecf20Sopenharmony_ci		drm_encoder_helper_add(&dsi->output.encoder,
10578c2ecf20Sopenharmony_ci				       &tegra_dsi_encoder_helper_funcs);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci		drm_connector_attach_encoder(&dsi->output.connector,
10608c2ecf20Sopenharmony_ci						  &dsi->output.encoder);
10618c2ecf20Sopenharmony_ci		drm_connector_register(&dsi->output.connector);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		err = tegra_output_init(drm, &dsi->output);
10648c2ecf20Sopenharmony_ci		if (err < 0)
10658c2ecf20Sopenharmony_ci			dev_err(dsi->dev, "failed to initialize output: %d\n",
10668c2ecf20Sopenharmony_ci				err);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci		dsi->output.encoder.possible_crtcs = 0x3;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return 0;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic int tegra_dsi_exit(struct host1x_client *client)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	tegra_output_exit(&dsi->output);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return 0;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic int tegra_dsi_runtime_suspend(struct host1x_client *client)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
10868c2ecf20Sopenharmony_ci	struct device *dev = client->dev;
10878c2ecf20Sopenharmony_ci	int err;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (dsi->rst) {
10908c2ecf20Sopenharmony_ci		err = reset_control_assert(dsi->rst);
10918c2ecf20Sopenharmony_ci		if (err < 0) {
10928c2ecf20Sopenharmony_ci			dev_err(dev, "failed to assert reset: %d\n", err);
10938c2ecf20Sopenharmony_ci			return err;
10948c2ecf20Sopenharmony_ci		}
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->clk_lp);
11008c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->clk);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	regulator_disable(dsi->vdd);
11038c2ecf20Sopenharmony_ci	pm_runtime_put_sync(dev);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	return 0;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic int tegra_dsi_runtime_resume(struct host1x_client *client)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
11118c2ecf20Sopenharmony_ci	struct device *dev = client->dev;
11128c2ecf20Sopenharmony_ci	int err;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	err = pm_runtime_resume_and_get(dev);
11158c2ecf20Sopenharmony_ci	if (err < 0) {
11168c2ecf20Sopenharmony_ci		dev_err(dev, "failed to get runtime PM: %d\n", err);
11178c2ecf20Sopenharmony_ci		return err;
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	err = regulator_enable(dsi->vdd);
11218c2ecf20Sopenharmony_ci	if (err < 0) {
11228c2ecf20Sopenharmony_ci		dev_err(dev, "failed to enable VDD supply: %d\n", err);
11238c2ecf20Sopenharmony_ci		goto put_rpm;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	err = clk_prepare_enable(dsi->clk);
11278c2ecf20Sopenharmony_ci	if (err < 0) {
11288c2ecf20Sopenharmony_ci		dev_err(dev, "cannot enable DSI clock: %d\n", err);
11298c2ecf20Sopenharmony_ci		goto disable_vdd;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	err = clk_prepare_enable(dsi->clk_lp);
11338c2ecf20Sopenharmony_ci	if (err < 0) {
11348c2ecf20Sopenharmony_ci		dev_err(dev, "cannot enable low-power clock: %d\n", err);
11358c2ecf20Sopenharmony_ci		goto disable_clk;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	if (dsi->rst) {
11418c2ecf20Sopenharmony_ci		err = reset_control_deassert(dsi->rst);
11428c2ecf20Sopenharmony_ci		if (err < 0) {
11438c2ecf20Sopenharmony_ci			dev_err(dev, "cannot assert reset: %d\n", err);
11448c2ecf20Sopenharmony_ci			goto disable_clk_lp;
11458c2ecf20Sopenharmony_ci		}
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	return 0;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_cidisable_clk_lp:
11518c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->clk_lp);
11528c2ecf20Sopenharmony_cidisable_clk:
11538c2ecf20Sopenharmony_ci	clk_disable_unprepare(dsi->clk);
11548c2ecf20Sopenharmony_cidisable_vdd:
11558c2ecf20Sopenharmony_ci	regulator_disable(dsi->vdd);
11568c2ecf20Sopenharmony_ciput_rpm:
11578c2ecf20Sopenharmony_ci	pm_runtime_put_sync(dev);
11588c2ecf20Sopenharmony_ci	return err;
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_cistatic const struct host1x_client_ops dsi_client_ops = {
11628c2ecf20Sopenharmony_ci	.init = tegra_dsi_init,
11638c2ecf20Sopenharmony_ci	.exit = tegra_dsi_exit,
11648c2ecf20Sopenharmony_ci	.suspend = tegra_dsi_runtime_suspend,
11658c2ecf20Sopenharmony_ci	.resume = tegra_dsi_runtime_resume,
11668c2ecf20Sopenharmony_ci};
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	struct clk *parent;
11718c2ecf20Sopenharmony_ci	int err;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	parent = clk_get_parent(dsi->clk);
11748c2ecf20Sopenharmony_ci	if (!parent)
11758c2ecf20Sopenharmony_ci		return -EINVAL;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	err = clk_set_parent(parent, dsi->clk_parent);
11788c2ecf20Sopenharmony_ci	if (err < 0)
11798c2ecf20Sopenharmony_ci		return err;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	return 0;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic const char * const error_report[16] = {
11858c2ecf20Sopenharmony_ci	"SoT Error",
11868c2ecf20Sopenharmony_ci	"SoT Sync Error",
11878c2ecf20Sopenharmony_ci	"EoT Sync Error",
11888c2ecf20Sopenharmony_ci	"Escape Mode Entry Command Error",
11898c2ecf20Sopenharmony_ci	"Low-Power Transmit Sync Error",
11908c2ecf20Sopenharmony_ci	"Peripheral Timeout Error",
11918c2ecf20Sopenharmony_ci	"False Control Error",
11928c2ecf20Sopenharmony_ci	"Contention Detected",
11938c2ecf20Sopenharmony_ci	"ECC Error, single-bit",
11948c2ecf20Sopenharmony_ci	"ECC Error, multi-bit",
11958c2ecf20Sopenharmony_ci	"Checksum Error",
11968c2ecf20Sopenharmony_ci	"DSI Data Type Not Recognized",
11978c2ecf20Sopenharmony_ci	"DSI VC ID Invalid",
11988c2ecf20Sopenharmony_ci	"Invalid Transmission Length",
11998c2ecf20Sopenharmony_ci	"Reserved",
12008c2ecf20Sopenharmony_ci	"DSI Protocol Violation",
12018c2ecf20Sopenharmony_ci};
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
12048c2ecf20Sopenharmony_ci				       const struct mipi_dsi_msg *msg,
12058c2ecf20Sopenharmony_ci				       size_t count)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	u8 *rx = msg->rx_buf;
12088c2ecf20Sopenharmony_ci	unsigned int i, j, k;
12098c2ecf20Sopenharmony_ci	size_t size = 0;
12108c2ecf20Sopenharmony_ci	u16 errors;
12118c2ecf20Sopenharmony_ci	u32 value;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	/* read and parse packet header */
12148c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	switch (value & 0x3f) {
12178c2ecf20Sopenharmony_ci	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
12188c2ecf20Sopenharmony_ci		errors = (value >> 8) & 0xffff;
12198c2ecf20Sopenharmony_ci		dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
12208c2ecf20Sopenharmony_ci			errors);
12218c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(error_report); i++)
12228c2ecf20Sopenharmony_ci			if (errors & BIT(i))
12238c2ecf20Sopenharmony_ci				dev_dbg(dsi->dev, "  %2u: %s\n", i,
12248c2ecf20Sopenharmony_ci					error_report[i]);
12258c2ecf20Sopenharmony_ci		break;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
12288c2ecf20Sopenharmony_ci		rx[0] = (value >> 8) & 0xff;
12298c2ecf20Sopenharmony_ci		size = 1;
12308c2ecf20Sopenharmony_ci		break;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
12338c2ecf20Sopenharmony_ci		rx[0] = (value >>  8) & 0xff;
12348c2ecf20Sopenharmony_ci		rx[1] = (value >> 16) & 0xff;
12358c2ecf20Sopenharmony_ci		size = 2;
12368c2ecf20Sopenharmony_ci		break;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
12398c2ecf20Sopenharmony_ci		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
12408c2ecf20Sopenharmony_ci		break;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
12438c2ecf20Sopenharmony_ci		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
12448c2ecf20Sopenharmony_ci		break;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	default:
12478c2ecf20Sopenharmony_ci		dev_err(dsi->dev, "unhandled response type: %02x\n",
12488c2ecf20Sopenharmony_ci			value & 0x3f);
12498c2ecf20Sopenharmony_ci		return -EPROTO;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	size = min(size, msg->rx_len);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (msg->rx_buf && size > 0) {
12558c2ecf20Sopenharmony_ci		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
12568c2ecf20Sopenharmony_ci			u8 *rx = msg->rx_buf + j;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
12618c2ecf20Sopenharmony_ci				rx[j + k] = (value >> (k << 3)) & 0xff;
12628c2ecf20Sopenharmony_ci		}
12638c2ecf20Sopenharmony_ci	}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	return size;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(timeout);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	while (time_before(jiffies, timeout)) {
12758c2ecf20Sopenharmony_ci		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
12768c2ecf20Sopenharmony_ci		if ((value & DSI_TRIGGER_HOST) == 0)
12778c2ecf20Sopenharmony_ci			return 0;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
12838c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cistatic int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
12878c2ecf20Sopenharmony_ci				       unsigned long timeout)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(250);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	while (time_before(jiffies, timeout)) {
12928c2ecf20Sopenharmony_ci		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
12938c2ecf20Sopenharmony_ci		u8 count = value & 0x1f;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci		if (count > 0)
12968c2ecf20Sopenharmony_ci			return count;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("peripheral returned no data\n");
13028c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
13038c2ecf20Sopenharmony_ci}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_cistatic void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
13068c2ecf20Sopenharmony_ci			      const void *buffer, size_t size)
13078c2ecf20Sopenharmony_ci{
13088c2ecf20Sopenharmony_ci	const u8 *buf = buffer;
13098c2ecf20Sopenharmony_ci	size_t i, j;
13108c2ecf20Sopenharmony_ci	u32 value;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	for (j = 0; j < size; j += 4) {
13138c2ecf20Sopenharmony_ci		value = 0;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		for (i = 0; i < 4 && j + i < size; i++)
13168c2ecf20Sopenharmony_ci			value |= buf[j + i] << (i << 3);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, value, DSI_WR_DATA);
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cistatic ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
13238c2ecf20Sopenharmony_ci				       const struct mipi_dsi_msg *msg)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host_to_tegra(host);
13268c2ecf20Sopenharmony_ci	struct mipi_dsi_packet packet;
13278c2ecf20Sopenharmony_ci	const u8 *header;
13288c2ecf20Sopenharmony_ci	size_t count;
13298c2ecf20Sopenharmony_ci	ssize_t err;
13308c2ecf20Sopenharmony_ci	u32 value;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	err = mipi_dsi_create_packet(&packet, msg);
13338c2ecf20Sopenharmony_ci	if (err < 0)
13348c2ecf20Sopenharmony_ci		return err;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	header = packet.header;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	/* maximum FIFO depth is 1920 words */
13398c2ecf20Sopenharmony_ci	if (packet.size > dsi->video_fifo_depth * 4)
13408c2ecf20Sopenharmony_ci		return -ENOSPC;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	/* reset underflow/overflow flags */
13438c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_STATUS);
13448c2ecf20Sopenharmony_ci	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
13458c2ecf20Sopenharmony_ci		value = DSI_HOST_CONTROL_FIFO_RESET;
13468c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13478c2ecf20Sopenharmony_ci		usleep_range(10, 20);
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
13518c2ecf20Sopenharmony_ci	value |= DSI_POWER_CONTROL_ENABLE;
13528c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	usleep_range(5000, 10000);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
13578c2ecf20Sopenharmony_ci		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
13608c2ecf20Sopenharmony_ci		value |= DSI_HOST_CONTROL_HS;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	/*
13638c2ecf20Sopenharmony_ci	 * The host FIFO has a maximum of 64 words, so larger transmissions
13648c2ecf20Sopenharmony_ci	 * need to use the video FIFO.
13658c2ecf20Sopenharmony_ci	 */
13668c2ecf20Sopenharmony_ci	if (packet.size > dsi->host_fifo_depth * 4)
13678c2ecf20Sopenharmony_ci		value |= DSI_HOST_CONTROL_FIFO_SEL;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	/*
13728c2ecf20Sopenharmony_ci	 * For reads and messages with explicitly requested ACK, generate a
13738c2ecf20Sopenharmony_ci	 * BTA sequence after the transmission of the packet.
13748c2ecf20Sopenharmony_ci	 */
13758c2ecf20Sopenharmony_ci	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
13768c2ecf20Sopenharmony_ci	    (msg->rx_buf && msg->rx_len > 0)) {
13778c2ecf20Sopenharmony_ci		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
13788c2ecf20Sopenharmony_ci		value |= DSI_HOST_CONTROL_PKT_BTA;
13798c2ecf20Sopenharmony_ci		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
13838c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_CONTROL);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	/* write packet header, ECC is generated by hardware */
13868c2ecf20Sopenharmony_ci	value = header[2] << 16 | header[1] << 8 | header[0];
13878c2ecf20Sopenharmony_ci	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* write payload (if any) */
13908c2ecf20Sopenharmony_ci	if (packet.payload_length > 0)
13918c2ecf20Sopenharmony_ci		tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
13928c2ecf20Sopenharmony_ci				  packet.payload_length);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	err = tegra_dsi_transmit(dsi, 250);
13958c2ecf20Sopenharmony_ci	if (err < 0)
13968c2ecf20Sopenharmony_ci		return err;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
13998c2ecf20Sopenharmony_ci	    (msg->rx_buf && msg->rx_len > 0)) {
14008c2ecf20Sopenharmony_ci		err = tegra_dsi_wait_for_response(dsi, 250);
14018c2ecf20Sopenharmony_ci		if (err < 0)
14028c2ecf20Sopenharmony_ci			return err;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		count = err;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
14078c2ecf20Sopenharmony_ci		switch (value) {
14088c2ecf20Sopenharmony_ci		case 0x84:
14098c2ecf20Sopenharmony_ci			/*
14108c2ecf20Sopenharmony_ci			dev_dbg(dsi->dev, "ACK\n");
14118c2ecf20Sopenharmony_ci			*/
14128c2ecf20Sopenharmony_ci			break;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci		case 0x87:
14158c2ecf20Sopenharmony_ci			/*
14168c2ecf20Sopenharmony_ci			dev_dbg(dsi->dev, "ESCAPE\n");
14178c2ecf20Sopenharmony_ci			*/
14188c2ecf20Sopenharmony_ci			break;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		default:
14218c2ecf20Sopenharmony_ci			dev_err(dsi->dev, "unknown status: %08x\n", value);
14228c2ecf20Sopenharmony_ci			break;
14238c2ecf20Sopenharmony_ci		}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci		if (count > 1) {
14268c2ecf20Sopenharmony_ci			err = tegra_dsi_read_response(dsi, msg, count);
14278c2ecf20Sopenharmony_ci			if (err < 0)
14288c2ecf20Sopenharmony_ci				dev_err(dsi->dev,
14298c2ecf20Sopenharmony_ci					"failed to parse response: %zd\n",
14308c2ecf20Sopenharmony_ci					err);
14318c2ecf20Sopenharmony_ci			else {
14328c2ecf20Sopenharmony_ci				/*
14338c2ecf20Sopenharmony_ci				 * For read commands, return the number of
14348c2ecf20Sopenharmony_ci				 * bytes returned by the peripheral.
14358c2ecf20Sopenharmony_ci				 */
14368c2ecf20Sopenharmony_ci				count = err;
14378c2ecf20Sopenharmony_ci			}
14388c2ecf20Sopenharmony_ci		}
14398c2ecf20Sopenharmony_ci	} else {
14408c2ecf20Sopenharmony_ci		/*
14418c2ecf20Sopenharmony_ci		 * For write commands, we have transmitted the 4-byte header
14428c2ecf20Sopenharmony_ci		 * plus the variable-length payload.
14438c2ecf20Sopenharmony_ci		 */
14448c2ecf20Sopenharmony_ci		count = 4 + packet.payload_length;
14458c2ecf20Sopenharmony_ci	}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	return count;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct clk *parent;
14538c2ecf20Sopenharmony_ci	int err;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	/* make sure both DSI controllers share the same PLL */
14568c2ecf20Sopenharmony_ci	parent = clk_get_parent(dsi->slave->clk);
14578c2ecf20Sopenharmony_ci	if (!parent)
14588c2ecf20Sopenharmony_ci		return -EINVAL;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	err = clk_set_parent(parent, dsi->clk_parent);
14618c2ecf20Sopenharmony_ci	if (err < 0)
14628c2ecf20Sopenharmony_ci		return err;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	return 0;
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_cistatic int tegra_dsi_host_attach(struct mipi_dsi_host *host,
14688c2ecf20Sopenharmony_ci				 struct mipi_dsi_device *device)
14698c2ecf20Sopenharmony_ci{
14708c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host_to_tegra(host);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	dsi->flags = device->mode_flags;
14738c2ecf20Sopenharmony_ci	dsi->format = device->format;
14748c2ecf20Sopenharmony_ci	dsi->lanes = device->lanes;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	if (dsi->slave) {
14778c2ecf20Sopenharmony_ci		int err;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci		dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
14808c2ecf20Sopenharmony_ci			dev_name(&device->dev));
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci		err = tegra_dsi_ganged_setup(dsi);
14838c2ecf20Sopenharmony_ci		if (err < 0) {
14848c2ecf20Sopenharmony_ci			dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
14858c2ecf20Sopenharmony_ci				err);
14868c2ecf20Sopenharmony_ci			return err;
14878c2ecf20Sopenharmony_ci		}
14888c2ecf20Sopenharmony_ci	}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	/*
14918c2ecf20Sopenharmony_ci	 * Slaves don't have a panel associated with them, so they provide
14928c2ecf20Sopenharmony_ci	 * merely the second channel.
14938c2ecf20Sopenharmony_ci	 */
14948c2ecf20Sopenharmony_ci	if (!dsi->master) {
14958c2ecf20Sopenharmony_ci		struct tegra_output *output = &dsi->output;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		output->panel = of_drm_find_panel(device->dev.of_node);
14988c2ecf20Sopenharmony_ci		if (IS_ERR(output->panel))
14998c2ecf20Sopenharmony_ci			output->panel = NULL;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci		if (output->panel && output->connector.dev)
15028c2ecf20Sopenharmony_ci			drm_helper_hpd_irq_event(output->connector.dev);
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	return 0;
15068c2ecf20Sopenharmony_ci}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_cistatic int tegra_dsi_host_detach(struct mipi_dsi_host *host,
15098c2ecf20Sopenharmony_ci				 struct mipi_dsi_device *device)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = host_to_tegra(host);
15128c2ecf20Sopenharmony_ci	struct tegra_output *output = &dsi->output;
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	if (output->panel && &device->dev == output->panel->dev) {
15158c2ecf20Sopenharmony_ci		output->panel = NULL;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci		if (output->connector.dev)
15188c2ecf20Sopenharmony_ci			drm_helper_hpd_irq_event(output->connector.dev);
15198c2ecf20Sopenharmony_ci	}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	return 0;
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_cistatic const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
15258c2ecf20Sopenharmony_ci	.attach = tegra_dsi_host_attach,
15268c2ecf20Sopenharmony_ci	.detach = tegra_dsi_host_detach,
15278c2ecf20Sopenharmony_ci	.transfer = tegra_dsi_host_transfer,
15288c2ecf20Sopenharmony_ci};
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_cistatic int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	struct device_node *np;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
15358c2ecf20Sopenharmony_ci	if (np) {
15368c2ecf20Sopenharmony_ci		struct platform_device *gangster = of_find_device_by_node(np);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		dsi->slave = platform_get_drvdata(gangster);
15398c2ecf20Sopenharmony_ci		of_node_put(np);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci		if (!dsi->slave) {
15428c2ecf20Sopenharmony_ci			put_device(&gangster->dev);
15438c2ecf20Sopenharmony_ci			return -EPROBE_DEFER;
15448c2ecf20Sopenharmony_ci		}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		dsi->slave->master = dsi;
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	return 0;
15508c2ecf20Sopenharmony_ci}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_cistatic int tegra_dsi_probe(struct platform_device *pdev)
15538c2ecf20Sopenharmony_ci{
15548c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi;
15558c2ecf20Sopenharmony_ci	struct resource *regs;
15568c2ecf20Sopenharmony_ci	int err;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
15598c2ecf20Sopenharmony_ci	if (!dsi)
15608c2ecf20Sopenharmony_ci		return -ENOMEM;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	dsi->output.dev = dsi->dev = &pdev->dev;
15638c2ecf20Sopenharmony_ci	dsi->video_fifo_depth = 1920;
15648c2ecf20Sopenharmony_ci	dsi->host_fifo_depth = 64;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	err = tegra_dsi_ganged_probe(dsi);
15678c2ecf20Sopenharmony_ci	if (err < 0)
15688c2ecf20Sopenharmony_ci		return err;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	err = tegra_output_probe(&dsi->output);
15718c2ecf20Sopenharmony_ci	if (err < 0)
15728c2ecf20Sopenharmony_ci		return err;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	/*
15778c2ecf20Sopenharmony_ci	 * Assume these values by default. When a DSI peripheral driver
15788c2ecf20Sopenharmony_ci	 * attaches to the DSI host, the parameters will be taken from
15798c2ecf20Sopenharmony_ci	 * the attached device.
15808c2ecf20Sopenharmony_ci	 */
15818c2ecf20Sopenharmony_ci	dsi->flags = MIPI_DSI_MODE_VIDEO;
15828c2ecf20Sopenharmony_ci	dsi->format = MIPI_DSI_FMT_RGB888;
15838c2ecf20Sopenharmony_ci	dsi->lanes = 4;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	if (!pdev->dev.pm_domain) {
15868c2ecf20Sopenharmony_ci		dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
15878c2ecf20Sopenharmony_ci		if (IS_ERR(dsi->rst))
15888c2ecf20Sopenharmony_ci			return PTR_ERR(dsi->rst);
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	dsi->clk = devm_clk_get(&pdev->dev, NULL);
15928c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->clk)) {
15938c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot get DSI clock\n");
15948c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->clk);
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
15988c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->clk_lp)) {
15998c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot get low-power clock\n");
16008c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->clk_lp);
16018c2ecf20Sopenharmony_ci	}
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
16048c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->clk_parent)) {
16058c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot get parent clock\n");
16068c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->clk_parent);
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
16108c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->vdd)) {
16118c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot get VDD supply\n");
16128c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->vdd);
16138c2ecf20Sopenharmony_ci	}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	err = tegra_dsi_setup_clocks(dsi);
16168c2ecf20Sopenharmony_ci	if (err < 0) {
16178c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot setup clocks\n");
16188c2ecf20Sopenharmony_ci		return err;
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
16228c2ecf20Sopenharmony_ci	dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
16238c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->regs))
16248c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->regs);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node);
16278c2ecf20Sopenharmony_ci	if (IS_ERR(dsi->mipi))
16288c2ecf20Sopenharmony_ci		return PTR_ERR(dsi->mipi);
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	dsi->host.ops = &tegra_dsi_host_ops;
16318c2ecf20Sopenharmony_ci	dsi->host.dev = &pdev->dev;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	err = mipi_dsi_host_register(&dsi->host);
16348c2ecf20Sopenharmony_ci	if (err < 0) {
16358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
16368c2ecf20Sopenharmony_ci		goto mipi_free;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, dsi);
16408c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dsi->client.list);
16438c2ecf20Sopenharmony_ci	dsi->client.ops = &dsi_client_ops;
16448c2ecf20Sopenharmony_ci	dsi->client.dev = &pdev->dev;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	err = host1x_client_register(&dsi->client);
16478c2ecf20Sopenharmony_ci	if (err < 0) {
16488c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
16498c2ecf20Sopenharmony_ci			err);
16508c2ecf20Sopenharmony_ci		goto unregister;
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	return 0;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ciunregister:
16568c2ecf20Sopenharmony_ci	mipi_dsi_host_unregister(&dsi->host);
16578c2ecf20Sopenharmony_cimipi_free:
16588c2ecf20Sopenharmony_ci	tegra_mipi_free(dsi->mipi);
16598c2ecf20Sopenharmony_ci	return err;
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_cistatic int tegra_dsi_remove(struct platform_device *pdev)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	struct tegra_dsi *dsi = platform_get_drvdata(pdev);
16658c2ecf20Sopenharmony_ci	int err;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	err = host1x_client_unregister(&dsi->client);
16708c2ecf20Sopenharmony_ci	if (err < 0) {
16718c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
16728c2ecf20Sopenharmony_ci			err);
16738c2ecf20Sopenharmony_ci		return err;
16748c2ecf20Sopenharmony_ci	}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	tegra_output_remove(&dsi->output);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	mipi_dsi_host_unregister(&dsi->host);
16798c2ecf20Sopenharmony_ci	tegra_mipi_free(dsi->mipi);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	return 0;
16828c2ecf20Sopenharmony_ci}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_dsi_of_match[] = {
16858c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra210-dsi", },
16868c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra132-dsi", },
16878c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra124-dsi", },
16888c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra114-dsi", },
16898c2ecf20Sopenharmony_ci	{ },
16908c2ecf20Sopenharmony_ci};
16918c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistruct platform_driver tegra_dsi_driver = {
16948c2ecf20Sopenharmony_ci	.driver = {
16958c2ecf20Sopenharmony_ci		.name = "tegra-dsi",
16968c2ecf20Sopenharmony_ci		.of_match_table = tegra_dsi_of_match,
16978c2ecf20Sopenharmony_ci	},
16988c2ecf20Sopenharmony_ci	.probe = tegra_dsi_probe,
16998c2ecf20Sopenharmony_ci	.remove = tegra_dsi_remove,
17008c2ecf20Sopenharmony_ci};
1701