1dec72739SThierry Reding /* 2dec72739SThierry Reding * Copyright (C) 2013 NVIDIA Corporation 3dec72739SThierry Reding * 49a2ac2dcSThierry Reding * This program is free software; you can redistribute it and/or modify 59a2ac2dcSThierry Reding * it under the terms of the GNU General Public License version 2 as 69a2ac2dcSThierry Reding * published by the Free Software Foundation. 7dec72739SThierry Reding */ 8dec72739SThierry Reding 9dec72739SThierry Reding #include <linux/clk.h> 10dec72739SThierry Reding #include <linux/debugfs.h> 11dec72739SThierry Reding #include <linux/host1x.h> 12dec72739SThierry Reding #include <linux/module.h> 13dec72739SThierry Reding #include <linux/of.h> 14e94236cdSThierry Reding #include <linux/of_platform.h> 15dec72739SThierry Reding #include <linux/platform_device.h> 16dec72739SThierry Reding #include <linux/reset.h> 17dec72739SThierry Reding 183b077afbSThierry Reding #include <linux/regulator/consumer.h> 193b077afbSThierry Reding 20dec72739SThierry Reding #include <drm/drm_mipi_dsi.h> 21dec72739SThierry Reding #include <drm/drm_panel.h> 22dec72739SThierry Reding 23dec72739SThierry Reding #include <video/mipi_display.h> 24dec72739SThierry Reding 25dec72739SThierry Reding #include "dc.h" 26dec72739SThierry Reding #include "drm.h" 27dec72739SThierry Reding #include "dsi.h" 28dec72739SThierry Reding #include "mipi-phy.h" 29dec72739SThierry Reding 30dec72739SThierry Reding struct tegra_dsi { 31dec72739SThierry Reding struct host1x_client client; 32dec72739SThierry Reding struct tegra_output output; 33dec72739SThierry Reding struct device *dev; 34dec72739SThierry Reding 35dec72739SThierry Reding void __iomem *regs; 36dec72739SThierry Reding 37dec72739SThierry Reding struct reset_control *rst; 38dec72739SThierry Reding struct clk *clk_parent; 39dec72739SThierry Reding struct clk *clk_lp; 40dec72739SThierry Reding struct clk *clk; 41dec72739SThierry Reding 42dec72739SThierry Reding struct drm_info_list *debugfs_files; 43dec72739SThierry Reding struct drm_minor *minor; 44dec72739SThierry Reding struct dentry *debugfs; 45dec72739SThierry Reding 4617297a28SThierry Reding unsigned long flags; 47dec72739SThierry Reding enum mipi_dsi_pixel_format format; 48dec72739SThierry Reding unsigned int lanes; 49dec72739SThierry Reding 50dec72739SThierry Reding struct tegra_mipi_device *mipi; 51dec72739SThierry Reding struct mipi_dsi_host host; 523b077afbSThierry Reding 533b077afbSThierry Reding struct regulator *vdd; 54334ae6b5SThierry Reding bool enabled; 55976cebc3SThierry Reding 56976cebc3SThierry Reding unsigned int video_fifo_depth; 57976cebc3SThierry Reding unsigned int host_fifo_depth; 58e94236cdSThierry Reding 59e94236cdSThierry Reding /* for ganged-mode support */ 60e94236cdSThierry Reding struct tegra_dsi *master; 61e94236cdSThierry Reding struct tegra_dsi *slave; 62dec72739SThierry Reding }; 63dec72739SThierry Reding 64dec72739SThierry Reding static inline struct tegra_dsi * 65dec72739SThierry Reding host1x_client_to_dsi(struct host1x_client *client) 66dec72739SThierry Reding { 67dec72739SThierry Reding return container_of(client, struct tegra_dsi, client); 68dec72739SThierry Reding } 69dec72739SThierry Reding 70dec72739SThierry Reding static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host) 71dec72739SThierry Reding { 72dec72739SThierry Reding return container_of(host, struct tegra_dsi, host); 73dec72739SThierry Reding } 74dec72739SThierry Reding 75dec72739SThierry Reding static inline struct tegra_dsi *to_dsi(struct tegra_output *output) 76dec72739SThierry Reding { 77dec72739SThierry Reding return container_of(output, struct tegra_dsi, output); 78dec72739SThierry Reding } 79dec72739SThierry Reding 80dec72739SThierry Reding static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi, 81dec72739SThierry Reding unsigned long reg) 82dec72739SThierry Reding { 83dec72739SThierry Reding return readl(dsi->regs + (reg << 2)); 84dec72739SThierry Reding } 85dec72739SThierry Reding 86dec72739SThierry Reding static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value, 87dec72739SThierry Reding unsigned long reg) 88dec72739SThierry Reding { 89dec72739SThierry Reding writel(value, dsi->regs + (reg << 2)); 90dec72739SThierry Reding } 91dec72739SThierry Reding 92dec72739SThierry Reding static int tegra_dsi_show_regs(struct seq_file *s, void *data) 93dec72739SThierry Reding { 94dec72739SThierry Reding struct drm_info_node *node = s->private; 95dec72739SThierry Reding struct tegra_dsi *dsi = node->info_ent->data; 96dec72739SThierry Reding 97dec72739SThierry Reding #define DUMP_REG(name) \ 98dec72739SThierry Reding seq_printf(s, "%-32s %#05x %08lx\n", #name, name, \ 99dec72739SThierry Reding tegra_dsi_readl(dsi, name)) 100dec72739SThierry Reding 101dec72739SThierry Reding DUMP_REG(DSI_INCR_SYNCPT); 102dec72739SThierry Reding DUMP_REG(DSI_INCR_SYNCPT_CONTROL); 103dec72739SThierry Reding DUMP_REG(DSI_INCR_SYNCPT_ERROR); 104dec72739SThierry Reding DUMP_REG(DSI_CTXSW); 105dec72739SThierry Reding DUMP_REG(DSI_RD_DATA); 106dec72739SThierry Reding DUMP_REG(DSI_WR_DATA); 107dec72739SThierry Reding DUMP_REG(DSI_POWER_CONTROL); 108dec72739SThierry Reding DUMP_REG(DSI_INT_ENABLE); 109dec72739SThierry Reding DUMP_REG(DSI_INT_STATUS); 110dec72739SThierry Reding DUMP_REG(DSI_INT_MASK); 111dec72739SThierry Reding DUMP_REG(DSI_HOST_CONTROL); 112dec72739SThierry Reding DUMP_REG(DSI_CONTROL); 113dec72739SThierry Reding DUMP_REG(DSI_SOL_DELAY); 114dec72739SThierry Reding DUMP_REG(DSI_MAX_THRESHOLD); 115dec72739SThierry Reding DUMP_REG(DSI_TRIGGER); 116dec72739SThierry Reding DUMP_REG(DSI_TX_CRC); 117dec72739SThierry Reding DUMP_REG(DSI_STATUS); 118dec72739SThierry Reding 119dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_CONTROL); 120dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_0); 121dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_1); 122dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_2); 123dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_3); 124dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_4); 125dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_5); 126dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_6); 127dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_7); 128dec72739SThierry Reding 129dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_0_LO); 130dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_0_HI); 131dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_1_LO); 132dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_1_HI); 133dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_2_LO); 134dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_2_HI); 135dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_3_LO); 136dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_3_HI); 137dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_4_LO); 138dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_4_HI); 139dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_5_LO); 140dec72739SThierry Reding DUMP_REG(DSI_PKT_SEQ_5_HI); 141dec72739SThierry Reding 142dec72739SThierry Reding DUMP_REG(DSI_DCS_CMDS); 143dec72739SThierry Reding 144dec72739SThierry Reding DUMP_REG(DSI_PKT_LEN_0_1); 145dec72739SThierry Reding DUMP_REG(DSI_PKT_LEN_2_3); 146dec72739SThierry Reding DUMP_REG(DSI_PKT_LEN_4_5); 147dec72739SThierry Reding DUMP_REG(DSI_PKT_LEN_6_7); 148dec72739SThierry Reding 149dec72739SThierry Reding DUMP_REG(DSI_PHY_TIMING_0); 150dec72739SThierry Reding DUMP_REG(DSI_PHY_TIMING_1); 151dec72739SThierry Reding DUMP_REG(DSI_PHY_TIMING_2); 152dec72739SThierry Reding DUMP_REG(DSI_BTA_TIMING); 153dec72739SThierry Reding 154dec72739SThierry Reding DUMP_REG(DSI_TIMEOUT_0); 155dec72739SThierry Reding DUMP_REG(DSI_TIMEOUT_1); 156dec72739SThierry Reding DUMP_REG(DSI_TO_TALLY); 157dec72739SThierry Reding 158dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_0); 159dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_CD); 160dec72739SThierry Reding DUMP_REG(DSI_PAD_CD_STATUS); 161dec72739SThierry Reding DUMP_REG(DSI_VIDEO_MODE_CONTROL); 162dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_1); 163dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_2); 164dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_3); 165dec72739SThierry Reding DUMP_REG(DSI_PAD_CONTROL_4); 166dec72739SThierry Reding 167dec72739SThierry Reding DUMP_REG(DSI_GANGED_MODE_CONTROL); 168dec72739SThierry Reding DUMP_REG(DSI_GANGED_MODE_START); 169dec72739SThierry Reding DUMP_REG(DSI_GANGED_MODE_SIZE); 170dec72739SThierry Reding 171dec72739SThierry Reding DUMP_REG(DSI_RAW_DATA_BYTE_COUNT); 172dec72739SThierry Reding DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL); 173dec72739SThierry Reding 174dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_8); 175dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_9); 176dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_10); 177dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_11); 178dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_12); 179dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_13); 180dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_14); 181dec72739SThierry Reding DUMP_REG(DSI_INIT_SEQ_DATA_15); 182dec72739SThierry Reding 183dec72739SThierry Reding #undef DUMP_REG 184dec72739SThierry Reding 185dec72739SThierry Reding return 0; 186dec72739SThierry Reding } 187dec72739SThierry Reding 188dec72739SThierry Reding static struct drm_info_list debugfs_files[] = { 189dec72739SThierry Reding { "regs", tegra_dsi_show_regs, 0, NULL }, 190dec72739SThierry Reding }; 191dec72739SThierry Reding 192dec72739SThierry Reding static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi, 193dec72739SThierry Reding struct drm_minor *minor) 194dec72739SThierry Reding { 195dec72739SThierry Reding const char *name = dev_name(dsi->dev); 196dec72739SThierry Reding unsigned int i; 197dec72739SThierry Reding int err; 198dec72739SThierry Reding 199dec72739SThierry Reding dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root); 200dec72739SThierry Reding if (!dsi->debugfs) 201dec72739SThierry Reding return -ENOMEM; 202dec72739SThierry Reding 203dec72739SThierry Reding dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 204dec72739SThierry Reding GFP_KERNEL); 205dec72739SThierry Reding if (!dsi->debugfs_files) { 206dec72739SThierry Reding err = -ENOMEM; 207dec72739SThierry Reding goto remove; 208dec72739SThierry Reding } 209dec72739SThierry Reding 210dec72739SThierry Reding for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) 211dec72739SThierry Reding dsi->debugfs_files[i].data = dsi; 212dec72739SThierry Reding 213dec72739SThierry Reding err = drm_debugfs_create_files(dsi->debugfs_files, 214dec72739SThierry Reding ARRAY_SIZE(debugfs_files), 215dec72739SThierry Reding dsi->debugfs, minor); 216dec72739SThierry Reding if (err < 0) 217dec72739SThierry Reding goto free; 218dec72739SThierry Reding 219dec72739SThierry Reding dsi->minor = minor; 220dec72739SThierry Reding 221dec72739SThierry Reding return 0; 222dec72739SThierry Reding 223dec72739SThierry Reding free: 224dec72739SThierry Reding kfree(dsi->debugfs_files); 225dec72739SThierry Reding dsi->debugfs_files = NULL; 226dec72739SThierry Reding remove: 227dec72739SThierry Reding debugfs_remove(dsi->debugfs); 228dec72739SThierry Reding dsi->debugfs = NULL; 229dec72739SThierry Reding 230dec72739SThierry Reding return err; 231dec72739SThierry Reding } 232dec72739SThierry Reding 233dec72739SThierry Reding static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi) 234dec72739SThierry Reding { 235dec72739SThierry Reding drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files), 236dec72739SThierry Reding dsi->minor); 237dec72739SThierry Reding dsi->minor = NULL; 238dec72739SThierry Reding 239dec72739SThierry Reding kfree(dsi->debugfs_files); 240dec72739SThierry Reding dsi->debugfs_files = NULL; 241dec72739SThierry Reding 242dec72739SThierry Reding debugfs_remove(dsi->debugfs); 243dec72739SThierry Reding dsi->debugfs = NULL; 244dec72739SThierry Reding 245dec72739SThierry Reding return 0; 246dec72739SThierry Reding } 247dec72739SThierry Reding 248dec72739SThierry Reding #define PKT_ID0(id) ((((id) & 0x3f) << 3) | (1 << 9)) 249dec72739SThierry Reding #define PKT_LEN0(len) (((len) & 0x07) << 0) 250dec72739SThierry Reding #define PKT_ID1(id) ((((id) & 0x3f) << 13) | (1 << 19)) 251dec72739SThierry Reding #define PKT_LEN1(len) (((len) & 0x07) << 10) 252dec72739SThierry Reding #define PKT_ID2(id) ((((id) & 0x3f) << 23) | (1 << 29)) 253dec72739SThierry Reding #define PKT_LEN2(len) (((len) & 0x07) << 20) 254dec72739SThierry Reding 255dec72739SThierry Reding #define PKT_LP (1 << 30) 256dec72739SThierry Reding #define NUM_PKT_SEQ 12 257dec72739SThierry Reding 25817297a28SThierry Reding /* 25917297a28SThierry Reding * non-burst mode with sync pulses 26017297a28SThierry Reding */ 26117297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = { 262dec72739SThierry Reding [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) | 263dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 264dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | 265dec72739SThierry Reding PKT_LP, 266dec72739SThierry Reding [ 1] = 0, 267dec72739SThierry Reding [ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) | 268dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 269dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | 270dec72739SThierry Reding PKT_LP, 271dec72739SThierry Reding [ 3] = 0, 272dec72739SThierry Reding [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 273dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 274dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | 275dec72739SThierry Reding PKT_LP, 276dec72739SThierry Reding [ 5] = 0, 277dec72739SThierry Reding [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 278dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 279dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0), 280dec72739SThierry Reding [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) | 281dec72739SThierry Reding PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) | 282dec72739SThierry Reding PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4), 283dec72739SThierry Reding [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 284dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 285dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | 286dec72739SThierry Reding PKT_LP, 287dec72739SThierry Reding [ 9] = 0, 288dec72739SThierry Reding [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 289dec72739SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | 290dec72739SThierry Reding PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0), 291dec72739SThierry Reding [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) | 292dec72739SThierry Reding PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) | 293dec72739SThierry Reding PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4), 294dec72739SThierry Reding }; 295dec72739SThierry Reding 29617297a28SThierry Reding /* 29717297a28SThierry Reding * non-burst mode with sync events 29817297a28SThierry Reding */ 29917297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = { 30017297a28SThierry Reding [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) | 30117297a28SThierry Reding PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | 30217297a28SThierry Reding PKT_LP, 30317297a28SThierry Reding [ 1] = 0, 30417297a28SThierry Reding [ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 30517297a28SThierry Reding PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | 30617297a28SThierry Reding PKT_LP, 30717297a28SThierry Reding [ 3] = 0, 30817297a28SThierry Reding [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 30917297a28SThierry Reding PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | 31017297a28SThierry Reding PKT_LP, 31117297a28SThierry Reding [ 5] = 0, 31217297a28SThierry Reding [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 31317297a28SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) | 31417297a28SThierry Reding PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3), 31517297a28SThierry Reding [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), 31617297a28SThierry Reding [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 31717297a28SThierry Reding PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) | 31817297a28SThierry Reding PKT_LP, 31917297a28SThierry Reding [ 9] = 0, 32017297a28SThierry Reding [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | 32117297a28SThierry Reding PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) | 32217297a28SThierry Reding PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3), 32317297a28SThierry Reding [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), 32417297a28SThierry Reding }; 32517297a28SThierry Reding 326337b443dSThierry Reding static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = { 327337b443dSThierry Reding [ 0] = 0, 328337b443dSThierry Reding [ 1] = 0, 329337b443dSThierry Reding [ 2] = 0, 330337b443dSThierry Reding [ 3] = 0, 331337b443dSThierry Reding [ 4] = 0, 332337b443dSThierry Reding [ 5] = 0, 333337b443dSThierry Reding [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP, 334337b443dSThierry Reding [ 7] = 0, 335337b443dSThierry Reding [ 8] = 0, 336337b443dSThierry Reding [ 9] = 0, 337337b443dSThierry Reding [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP, 338337b443dSThierry Reding [11] = 0, 339337b443dSThierry Reding }; 340337b443dSThierry Reding 341dec72739SThierry Reding static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) 342dec72739SThierry Reding { 343dec72739SThierry Reding struct mipi_dphy_timing timing; 344dec72739SThierry Reding unsigned long value, period; 345dec72739SThierry Reding long rate; 346dec72739SThierry Reding int err; 347dec72739SThierry Reding 348dec72739SThierry Reding rate = clk_get_rate(dsi->clk); 349dec72739SThierry Reding if (rate < 0) 350dec72739SThierry Reding return rate; 351dec72739SThierry Reding 352369bc65bSThierry Reding period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2); 353dec72739SThierry Reding 354dec72739SThierry Reding err = mipi_dphy_timing_get_default(&timing, period); 355dec72739SThierry Reding if (err < 0) 356dec72739SThierry Reding return err; 357dec72739SThierry Reding 358dec72739SThierry Reding err = mipi_dphy_timing_validate(&timing, period); 359dec72739SThierry Reding if (err < 0) { 360dec72739SThierry Reding dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err); 361dec72739SThierry Reding return err; 362dec72739SThierry Reding } 363dec72739SThierry Reding 364dec72739SThierry Reding /* 365dec72739SThierry Reding * The D-PHY timing fields below are expressed in byte-clock cycles, 366dec72739SThierry Reding * so multiply the period by 8. 367dec72739SThierry Reding */ 368dec72739SThierry Reding period *= 8; 369dec72739SThierry Reding 370dec72739SThierry Reding value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 | 371dec72739SThierry Reding DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 | 372dec72739SThierry Reding DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 | 373dec72739SThierry Reding DSI_TIMING_FIELD(timing.hsprepare, period, 1); 374dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0); 375dec72739SThierry Reding 376dec72739SThierry Reding value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 | 377dec72739SThierry Reding DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 | 378dec72739SThierry Reding DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 | 379dec72739SThierry Reding DSI_TIMING_FIELD(timing.lpx, period, 1); 380dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1); 381dec72739SThierry Reding 382dec72739SThierry Reding value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 | 383dec72739SThierry Reding DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 | 384dec72739SThierry Reding DSI_TIMING_FIELD(0xff * period, period, 0) << 0; 385dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2); 386dec72739SThierry Reding 387dec72739SThierry Reding value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 | 388dec72739SThierry Reding DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 | 389dec72739SThierry Reding DSI_TIMING_FIELD(timing.tago, period, 1); 390dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_BTA_TIMING); 391dec72739SThierry Reding 392dec72739SThierry Reding return 0; 393dec72739SThierry Reding } 394dec72739SThierry Reding 395dec72739SThierry Reding static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format, 396dec72739SThierry Reding unsigned int *mulp, unsigned int *divp) 397dec72739SThierry Reding { 398dec72739SThierry Reding switch (format) { 399dec72739SThierry Reding case MIPI_DSI_FMT_RGB666_PACKED: 400dec72739SThierry Reding case MIPI_DSI_FMT_RGB888: 401dec72739SThierry Reding *mulp = 3; 402dec72739SThierry Reding *divp = 1; 403dec72739SThierry Reding break; 404dec72739SThierry Reding 405dec72739SThierry Reding case MIPI_DSI_FMT_RGB565: 406dec72739SThierry Reding *mulp = 2; 407dec72739SThierry Reding *divp = 1; 408dec72739SThierry Reding break; 409dec72739SThierry Reding 410dec72739SThierry Reding case MIPI_DSI_FMT_RGB666: 411dec72739SThierry Reding *mulp = 9; 412dec72739SThierry Reding *divp = 4; 413dec72739SThierry Reding break; 414dec72739SThierry Reding 415dec72739SThierry Reding default: 416dec72739SThierry Reding return -EINVAL; 417dec72739SThierry Reding } 418dec72739SThierry Reding 419dec72739SThierry Reding return 0; 420dec72739SThierry Reding } 421dec72739SThierry Reding 422f7d6889bSThierry Reding static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format, 423f7d6889bSThierry Reding enum tegra_dsi_format *fmt) 424f7d6889bSThierry Reding { 425f7d6889bSThierry Reding switch (format) { 426f7d6889bSThierry Reding case MIPI_DSI_FMT_RGB888: 427f7d6889bSThierry Reding *fmt = TEGRA_DSI_FORMAT_24P; 428f7d6889bSThierry Reding break; 429f7d6889bSThierry Reding 430f7d6889bSThierry Reding case MIPI_DSI_FMT_RGB666: 431f7d6889bSThierry Reding *fmt = TEGRA_DSI_FORMAT_18NP; 432f7d6889bSThierry Reding break; 433f7d6889bSThierry Reding 434f7d6889bSThierry Reding case MIPI_DSI_FMT_RGB666_PACKED: 435f7d6889bSThierry Reding *fmt = TEGRA_DSI_FORMAT_18P; 436f7d6889bSThierry Reding break; 437f7d6889bSThierry Reding 438f7d6889bSThierry Reding case MIPI_DSI_FMT_RGB565: 439f7d6889bSThierry Reding *fmt = TEGRA_DSI_FORMAT_16P; 440f7d6889bSThierry Reding break; 441f7d6889bSThierry Reding 442f7d6889bSThierry Reding default: 443f7d6889bSThierry Reding return -EINVAL; 444f7d6889bSThierry Reding } 445f7d6889bSThierry Reding 446f7d6889bSThierry Reding return 0; 447f7d6889bSThierry Reding } 448f7d6889bSThierry Reding 449e94236cdSThierry Reding static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start, 450e94236cdSThierry Reding unsigned int size) 451e94236cdSThierry Reding { 452e94236cdSThierry Reding u32 value; 453e94236cdSThierry Reding 454e94236cdSThierry Reding tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START); 455e94236cdSThierry Reding tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE); 456e94236cdSThierry Reding 457e94236cdSThierry Reding value = DSI_GANGED_MODE_CONTROL_ENABLE; 458e94236cdSThierry Reding tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL); 459e94236cdSThierry Reding } 460e94236cdSThierry Reding 461563eff1fSThierry Reding static void tegra_dsi_enable(struct tegra_dsi *dsi) 462dec72739SThierry Reding { 463563eff1fSThierry Reding u32 value; 464dec72739SThierry Reding 465563eff1fSThierry Reding value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); 466563eff1fSThierry Reding value |= DSI_POWER_CONTROL_ENABLE; 467563eff1fSThierry Reding tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); 468e94236cdSThierry Reding 469e94236cdSThierry Reding if (dsi->slave) 470e94236cdSThierry Reding tegra_dsi_enable(dsi->slave); 471e94236cdSThierry Reding } 472e94236cdSThierry Reding 473e94236cdSThierry Reding static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi) 474e94236cdSThierry Reding { 475e94236cdSThierry Reding if (dsi->master) 476e94236cdSThierry Reding return dsi->master->lanes + dsi->lanes; 477e94236cdSThierry Reding 478e94236cdSThierry Reding if (dsi->slave) 479e94236cdSThierry Reding return dsi->lanes + dsi->slave->lanes; 480e94236cdSThierry Reding 481e94236cdSThierry Reding return dsi->lanes; 482563eff1fSThierry Reding } 483563eff1fSThierry Reding 484563eff1fSThierry Reding static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, 485563eff1fSThierry Reding const struct drm_display_mode *mode) 486563eff1fSThierry Reding { 487563eff1fSThierry Reding unsigned int hact, hsw, hbp, hfp, i, mul, div; 488563eff1fSThierry Reding enum tegra_dsi_format format; 489563eff1fSThierry Reding const u32 *pkt_seq; 490563eff1fSThierry Reding u32 value; 491563eff1fSThierry Reding int err; 492334ae6b5SThierry Reding 49317297a28SThierry Reding if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { 49417297a28SThierry Reding DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); 49517297a28SThierry Reding pkt_seq = pkt_seq_video_non_burst_sync_pulses; 496337b443dSThierry Reding } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) { 49717297a28SThierry Reding DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); 49817297a28SThierry Reding pkt_seq = pkt_seq_video_non_burst_sync_events; 499337b443dSThierry Reding } else { 500337b443dSThierry Reding DRM_DEBUG_KMS("Command mode\n"); 501337b443dSThierry Reding pkt_seq = pkt_seq_command_mode; 50217297a28SThierry Reding } 50317297a28SThierry Reding 504dec72739SThierry Reding err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); 505dec72739SThierry Reding if (err < 0) 506dec72739SThierry Reding return err; 507dec72739SThierry Reding 508f7d6889bSThierry Reding err = tegra_dsi_get_format(dsi->format, &format); 509f7d6889bSThierry Reding if (err < 0) 510f7d6889bSThierry Reding return err; 511f7d6889bSThierry Reding 512f7d6889bSThierry Reding value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) | 513dec72739SThierry Reding DSI_CONTROL_LANES(dsi->lanes - 1) | 514563eff1fSThierry Reding DSI_CONTROL_SOURCE(pipe); 515dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_CONTROL); 516dec72739SThierry Reding 517976cebc3SThierry Reding tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD); 518dec72739SThierry Reding 519563eff1fSThierry Reding value = DSI_HOST_CONTROL_HS; 520dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); 521dec72739SThierry Reding 522dec72739SThierry Reding value = tegra_dsi_readl(dsi, DSI_CONTROL); 523563eff1fSThierry Reding 5240c6b1e4bSAlexandre Courbot if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) 525dec72739SThierry Reding value |= DSI_CONTROL_HS_CLK_CTRL; 526563eff1fSThierry Reding 527dec72739SThierry Reding value &= ~DSI_CONTROL_TX_TRIG(3); 528337b443dSThierry Reding 529337b443dSThierry Reding /* enable DCS commands for command mode */ 530337b443dSThierry Reding if (dsi->flags & MIPI_DSI_MODE_VIDEO) 531dec72739SThierry Reding value &= ~DSI_CONTROL_DCS_ENABLE; 532337b443dSThierry Reding else 533337b443dSThierry Reding value |= DSI_CONTROL_DCS_ENABLE; 534337b443dSThierry Reding 535dec72739SThierry Reding value |= DSI_CONTROL_VIDEO_ENABLE; 536dec72739SThierry Reding value &= ~DSI_CONTROL_HOST_ENABLE; 537dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_CONTROL); 538dec72739SThierry Reding 539dec72739SThierry Reding err = tegra_dsi_set_phy_timing(dsi); 540dec72739SThierry Reding if (err < 0) 541dec72739SThierry Reding return err; 542dec72739SThierry Reding 543dec72739SThierry Reding for (i = 0; i < NUM_PKT_SEQ; i++) 544dec72739SThierry Reding tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); 545dec72739SThierry Reding 546337b443dSThierry Reding if (dsi->flags & MIPI_DSI_MODE_VIDEO) { 547dec72739SThierry Reding /* horizontal active pixels */ 548dec72739SThierry Reding hact = mode->hdisplay * mul / div; 549dec72739SThierry Reding 550dec72739SThierry Reding /* horizontal sync width */ 551dec72739SThierry Reding hsw = (mode->hsync_end - mode->hsync_start) * mul / div; 552dec72739SThierry Reding hsw -= 10; 553dec72739SThierry Reding 554dec72739SThierry Reding /* horizontal back porch */ 555dec72739SThierry Reding hbp = (mode->htotal - mode->hsync_end) * mul / div; 556dec72739SThierry Reding hbp -= 14; 557dec72739SThierry Reding 558dec72739SThierry Reding /* horizontal front porch */ 559dec72739SThierry Reding hfp = (mode->hsync_start - mode->hdisplay) * mul / div; 560dec72739SThierry Reding hfp -= 8; 561dec72739SThierry Reding 562dec72739SThierry Reding tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); 563dec72739SThierry Reding tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); 564dec72739SThierry Reding tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); 565dec72739SThierry Reding tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); 566dec72739SThierry Reding 567563eff1fSThierry Reding /* set SOL delay (for non-burst mode only) */ 568dec72739SThierry Reding tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); 569e94236cdSThierry Reding 570e94236cdSThierry Reding /* TODO: implement ganged mode */ 571337b443dSThierry Reding } else { 572337b443dSThierry Reding u16 bytes; 573337b443dSThierry Reding 574e94236cdSThierry Reding if (dsi->master || dsi->slave) { 575e94236cdSThierry Reding /* 576e94236cdSThierry Reding * For ganged mode, assume symmetric left-right mode. 577e94236cdSThierry Reding */ 578e94236cdSThierry Reding bytes = 1 + (mode->hdisplay / 2) * mul / div; 579e94236cdSThierry Reding } else { 580337b443dSThierry Reding /* 1 byte (DCS command) + pixel data */ 581337b443dSThierry Reding bytes = 1 + mode->hdisplay * mul / div; 582e94236cdSThierry Reding } 583337b443dSThierry Reding 584337b443dSThierry Reding tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1); 585337b443dSThierry Reding tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3); 586337b443dSThierry Reding tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5); 587337b443dSThierry Reding tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7); 588337b443dSThierry Reding 589337b443dSThierry Reding value = MIPI_DCS_WRITE_MEMORY_START << 8 | 590337b443dSThierry Reding MIPI_DCS_WRITE_MEMORY_CONTINUE; 591337b443dSThierry Reding tegra_dsi_writel(dsi, value, DSI_DCS_CMDS); 592337b443dSThierry Reding 593e94236cdSThierry Reding /* set SOL delay */ 594e94236cdSThierry Reding if (dsi->master || dsi->slave) { 595e94236cdSThierry Reding unsigned int lanes = tegra_dsi_get_lanes(dsi); 596e94236cdSThierry Reding unsigned long delay, bclk, bclk_ganged; 597e94236cdSThierry Reding 598e94236cdSThierry Reding /* SOL to valid, valid to FIFO and FIFO write delay */ 599e94236cdSThierry Reding delay = 4 + 4 + 2; 600e94236cdSThierry Reding delay = DIV_ROUND_UP(delay * mul, div * lanes); 601e94236cdSThierry Reding /* FIFO read delay */ 602e94236cdSThierry Reding delay = delay + 6; 603e94236cdSThierry Reding 604e94236cdSThierry Reding bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes); 605e94236cdSThierry Reding bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); 606e94236cdSThierry Reding value = bclk - bclk_ganged + delay + 20; 607e94236cdSThierry Reding } else { 608e94236cdSThierry Reding /* TODO: revisit for non-ganged mode */ 609337b443dSThierry Reding value = 8 * mul / div; 610e94236cdSThierry Reding } 611337b443dSThierry Reding 612337b443dSThierry Reding tegra_dsi_writel(dsi, value, DSI_SOL_DELAY); 613337b443dSThierry Reding } 614dec72739SThierry Reding 615e94236cdSThierry Reding if (dsi->slave) { 616e94236cdSThierry Reding err = tegra_dsi_configure(dsi->slave, pipe, mode); 617e94236cdSThierry Reding if (err < 0) 618e94236cdSThierry Reding return err; 619e94236cdSThierry Reding 620e94236cdSThierry Reding /* 621e94236cdSThierry Reding * TODO: Support modes other than symmetrical left-right 622e94236cdSThierry Reding * split. 623e94236cdSThierry Reding */ 624e94236cdSThierry Reding tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2); 625e94236cdSThierry Reding tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2, 626e94236cdSThierry Reding mode->hdisplay / 2); 627e94236cdSThierry Reding } 628e94236cdSThierry Reding 629563eff1fSThierry Reding return 0; 630563eff1fSThierry Reding } 631563eff1fSThierry Reding 632563eff1fSThierry Reding static int tegra_output_dsi_enable(struct tegra_output *output) 633563eff1fSThierry Reding { 634563eff1fSThierry Reding struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 635563eff1fSThierry Reding const struct drm_display_mode *mode = &dc->base.mode; 636563eff1fSThierry Reding struct tegra_dsi *dsi = to_dsi(output); 637563eff1fSThierry Reding u32 value; 638563eff1fSThierry Reding int err; 639563eff1fSThierry Reding 640563eff1fSThierry Reding if (dsi->enabled) 641563eff1fSThierry Reding return 0; 642563eff1fSThierry Reding 643563eff1fSThierry Reding err = tegra_dsi_configure(dsi, dc->pipe, mode); 644563eff1fSThierry Reding if (err < 0) 645563eff1fSThierry Reding return err; 646563eff1fSThierry Reding 647dec72739SThierry Reding /* enable display controller */ 648dec72739SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 649dec72739SThierry Reding value |= DSI_ENABLE; 650dec72739SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 651dec72739SThierry Reding 652dec72739SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 653dec72739SThierry Reding value &= ~DISP_CTRL_MODE_MASK; 654dec72739SThierry Reding value |= DISP_CTRL_MODE_C_DISPLAY; 655dec72739SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 656dec72739SThierry Reding 65772d30286SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 65872d30286SThierry Reding value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 65972d30286SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; 66072d30286SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 66172d30286SThierry Reding 662dec72739SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); 663dec72739SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); 664dec72739SThierry Reding 665dec72739SThierry Reding /* enable DSI controller */ 666563eff1fSThierry Reding tegra_dsi_enable(dsi); 667dec72739SThierry Reding 668334ae6b5SThierry Reding dsi->enabled = true; 669334ae6b5SThierry Reding 670dec72739SThierry Reding return 0; 671dec72739SThierry Reding } 672dec72739SThierry Reding 673563eff1fSThierry Reding static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout) 674563eff1fSThierry Reding { 675563eff1fSThierry Reding u32 value; 676563eff1fSThierry Reding 677563eff1fSThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 678563eff1fSThierry Reding 679563eff1fSThierry Reding while (time_before(jiffies, timeout)) { 680563eff1fSThierry Reding value = tegra_dsi_readl(dsi, DSI_STATUS); 681563eff1fSThierry Reding if (value & DSI_STATUS_IDLE) 682563eff1fSThierry Reding return 0; 683563eff1fSThierry Reding 684563eff1fSThierry Reding usleep_range(1000, 2000); 685563eff1fSThierry Reding } 686563eff1fSThierry Reding 687563eff1fSThierry Reding return -ETIMEDOUT; 688563eff1fSThierry Reding } 689563eff1fSThierry Reding 690563eff1fSThierry Reding static void tegra_dsi_video_disable(struct tegra_dsi *dsi) 691563eff1fSThierry Reding { 692563eff1fSThierry Reding u32 value; 693563eff1fSThierry Reding 694563eff1fSThierry Reding value = tegra_dsi_readl(dsi, DSI_CONTROL); 695563eff1fSThierry Reding value &= ~DSI_CONTROL_VIDEO_ENABLE; 696563eff1fSThierry Reding tegra_dsi_writel(dsi, value, DSI_CONTROL); 697e94236cdSThierry Reding 698e94236cdSThierry Reding if (dsi->slave) 699e94236cdSThierry Reding tegra_dsi_video_disable(dsi->slave); 700e94236cdSThierry Reding } 701e94236cdSThierry Reding 702e94236cdSThierry Reding static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi) 703e94236cdSThierry Reding { 704e94236cdSThierry Reding tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START); 705e94236cdSThierry Reding tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE); 706e94236cdSThierry Reding tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); 707563eff1fSThierry Reding } 708563eff1fSThierry Reding 709563eff1fSThierry Reding static void tegra_dsi_disable(struct tegra_dsi *dsi) 710563eff1fSThierry Reding { 711563eff1fSThierry Reding u32 value; 712563eff1fSThierry Reding 713e94236cdSThierry Reding if (dsi->slave) { 714e94236cdSThierry Reding tegra_dsi_ganged_disable(dsi->slave); 715e94236cdSThierry Reding tegra_dsi_ganged_disable(dsi); 716e94236cdSThierry Reding } 717e94236cdSThierry Reding 718563eff1fSThierry Reding value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); 719563eff1fSThierry Reding value &= ~DSI_POWER_CONTROL_ENABLE; 720563eff1fSThierry Reding tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); 721563eff1fSThierry Reding 722e94236cdSThierry Reding if (dsi->slave) 723e94236cdSThierry Reding tegra_dsi_disable(dsi->slave); 724e94236cdSThierry Reding 725563eff1fSThierry Reding usleep_range(5000, 10000); 726563eff1fSThierry Reding } 727563eff1fSThierry Reding 728dec72739SThierry Reding static int tegra_output_dsi_disable(struct tegra_output *output) 729dec72739SThierry Reding { 730dec72739SThierry Reding struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 731dec72739SThierry Reding struct tegra_dsi *dsi = to_dsi(output); 732dec72739SThierry Reding unsigned long value; 733563eff1fSThierry Reding int err; 734dec72739SThierry Reding 735334ae6b5SThierry Reding if (!dsi->enabled) 736334ae6b5SThierry Reding return 0; 737334ae6b5SThierry Reding 738563eff1fSThierry Reding tegra_dsi_video_disable(dsi); 739dec72739SThierry Reding 740dec72739SThierry Reding /* 74172d30286SThierry Reding * The following accesses registers of the display controller, so make 74272d30286SThierry Reding * sure it's only executed when the output is attached to one. 743dec72739SThierry Reding */ 744dec72739SThierry Reding if (dc) { 74572d30286SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 74672d30286SThierry Reding value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 74772d30286SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); 74872d30286SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 74972d30286SThierry Reding 750dec72739SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 751dec72739SThierry Reding value &= ~DISP_CTRL_MODE_MASK; 752dec72739SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 753dec72739SThierry Reding 754dec72739SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 755dec72739SThierry Reding value &= ~DSI_ENABLE; 756dec72739SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 75772d30286SThierry Reding 75872d30286SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); 75972d30286SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); 760dec72739SThierry Reding } 761dec72739SThierry Reding 762563eff1fSThierry Reding err = tegra_dsi_wait_idle(dsi, 100); 763563eff1fSThierry Reding if (err < 0) 764563eff1fSThierry Reding dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err); 765563eff1fSThierry Reding 766563eff1fSThierry Reding tegra_dsi_disable(dsi); 767563eff1fSThierry Reding 768334ae6b5SThierry Reding dsi->enabled = false; 769334ae6b5SThierry Reding 770dec72739SThierry Reding return 0; 771dec72739SThierry Reding } 772dec72739SThierry Reding 7733f6b406fSThierry Reding static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, 7743f6b406fSThierry Reding unsigned int vrefresh) 7753f6b406fSThierry Reding { 7763f6b406fSThierry Reding unsigned int timeout; 7773f6b406fSThierry Reding u32 value; 7783f6b406fSThierry Reding 7793f6b406fSThierry Reding /* one frame high-speed transmission timeout */ 7803f6b406fSThierry Reding timeout = (bclk / vrefresh) / 512; 7813f6b406fSThierry Reding value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout); 7823f6b406fSThierry Reding tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0); 7833f6b406fSThierry Reding 7843f6b406fSThierry Reding /* 2 ms peripheral timeout for panel */ 7853f6b406fSThierry Reding timeout = 2 * bclk / 512 * 1000; 7863f6b406fSThierry Reding value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000); 7873f6b406fSThierry Reding tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1); 7883f6b406fSThierry Reding 7893f6b406fSThierry Reding value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); 7903f6b406fSThierry Reding tegra_dsi_writel(dsi, value, DSI_TO_TALLY); 791e94236cdSThierry Reding 792e94236cdSThierry Reding if (dsi->slave) 793e94236cdSThierry Reding tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh); 7943f6b406fSThierry Reding } 7953f6b406fSThierry Reding 796dec72739SThierry Reding static int tegra_output_dsi_setup_clock(struct tegra_output *output, 79791eded9bSThierry Reding struct clk *clk, unsigned long pclk, 79891eded9bSThierry Reding unsigned int *divp) 799dec72739SThierry Reding { 800dec72739SThierry Reding struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 801dec72739SThierry Reding struct drm_display_mode *mode = &dc->base.mode; 802dec72739SThierry Reding struct tegra_dsi *dsi = to_dsi(output); 803e94236cdSThierry Reding unsigned int mul, div, vrefresh, lanes; 8043f6b406fSThierry Reding unsigned long bclk, plld; 805dec72739SThierry Reding int err; 806dec72739SThierry Reding 807e94236cdSThierry Reding lanes = tegra_dsi_get_lanes(dsi); 808e94236cdSThierry Reding 809dec72739SThierry Reding err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); 810dec72739SThierry Reding if (err < 0) 811dec72739SThierry Reding return err; 812dec72739SThierry Reding 813e94236cdSThierry Reding DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes); 814dec72739SThierry Reding vrefresh = drm_mode_vrefresh(mode); 81591eded9bSThierry Reding DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); 816dec72739SThierry Reding 81791eded9bSThierry Reding /* compute byte clock */ 818e94236cdSThierry Reding bclk = (pclk * mul) / (div * lanes); 81991eded9bSThierry Reding 82091eded9bSThierry Reding /* 82191eded9bSThierry Reding * Compute bit clock and round up to the next MHz. 82291eded9bSThierry Reding */ 823*030611ecSThierry Reding plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC; 82491eded9bSThierry Reding 82591eded9bSThierry Reding /* 82691eded9bSThierry Reding * We divide the frequency by two here, but we make up for that by 82791eded9bSThierry Reding * setting the shift clock divider (further below) to half of the 82891eded9bSThierry Reding * correct value. 82991eded9bSThierry Reding */ 83091eded9bSThierry Reding plld /= 2; 831dec72739SThierry Reding 832dec72739SThierry Reding err = clk_set_parent(clk, dsi->clk_parent); 833dec72739SThierry Reding if (err < 0) { 834dec72739SThierry Reding dev_err(dsi->dev, "failed to set parent clock: %d\n", err); 835dec72739SThierry Reding return err; 836dec72739SThierry Reding } 837dec72739SThierry Reding 83891eded9bSThierry Reding err = clk_set_rate(dsi->clk_parent, plld); 839dec72739SThierry Reding if (err < 0) { 840dec72739SThierry Reding dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n", 84191eded9bSThierry Reding plld); 842dec72739SThierry Reding return err; 843dec72739SThierry Reding } 844dec72739SThierry Reding 845dec72739SThierry Reding /* 84691eded9bSThierry Reding * Derive pixel clock from bit clock using the shift clock divider. 84791eded9bSThierry Reding * Note that this is only half of what we would expect, but we need 84891eded9bSThierry Reding * that to make up for the fact that we divided the bit clock by a 84991eded9bSThierry Reding * factor of two above. 85091eded9bSThierry Reding * 85191eded9bSThierry Reding * It's not clear exactly why this is necessary, but the display is 85291eded9bSThierry Reding * not working properly otherwise. Perhaps the PLLs cannot generate 85391eded9bSThierry Reding * frequencies sufficiently high. 85491eded9bSThierry Reding */ 855e94236cdSThierry Reding *divp = ((8 * mul) / (div * lanes)) - 2; 85691eded9bSThierry Reding 85791eded9bSThierry Reding /* 858dec72739SThierry Reding * XXX: Move the below somewhere else so that we don't need to have 859dec72739SThierry Reding * access to the vrefresh in this function? 860dec72739SThierry Reding */ 8613f6b406fSThierry Reding tegra_dsi_set_timeout(dsi, bclk, vrefresh); 862dec72739SThierry Reding 863dec72739SThierry Reding return 0; 864dec72739SThierry Reding } 865dec72739SThierry Reding 866dec72739SThierry Reding static int tegra_output_dsi_check_mode(struct tegra_output *output, 867dec72739SThierry Reding struct drm_display_mode *mode, 868dec72739SThierry Reding enum drm_mode_status *status) 869dec72739SThierry Reding { 870dec72739SThierry Reding /* 871dec72739SThierry Reding * FIXME: For now, always assume that the mode is okay. 872dec72739SThierry Reding */ 873dec72739SThierry Reding 874dec72739SThierry Reding *status = MODE_OK; 875dec72739SThierry Reding 876dec72739SThierry Reding return 0; 877dec72739SThierry Reding } 878dec72739SThierry Reding 879dec72739SThierry Reding static const struct tegra_output_ops dsi_ops = { 880dec72739SThierry Reding .enable = tegra_output_dsi_enable, 881dec72739SThierry Reding .disable = tegra_output_dsi_disable, 882dec72739SThierry Reding .setup_clock = tegra_output_dsi_setup_clock, 883dec72739SThierry Reding .check_mode = tegra_output_dsi_check_mode, 884dec72739SThierry Reding }; 885dec72739SThierry Reding 886dec72739SThierry Reding static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) 887dec72739SThierry Reding { 888dec72739SThierry Reding unsigned long value; 889dec72739SThierry Reding 890dec72739SThierry Reding value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0); 891dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0); 892dec72739SThierry Reding 893dec72739SThierry Reding return 0; 894dec72739SThierry Reding } 895dec72739SThierry Reding 896dec72739SThierry Reding static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) 897dec72739SThierry Reding { 898183ef288SThierry Reding u32 value; 899dec72739SThierry Reding 900dec72739SThierry Reding tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); 901dec72739SThierry Reding tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); 902dec72739SThierry Reding tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); 903dec72739SThierry Reding tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); 904dec72739SThierry Reding tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); 905dec72739SThierry Reding 906dec72739SThierry Reding /* start calibration */ 907dec72739SThierry Reding tegra_dsi_pad_enable(dsi); 908dec72739SThierry Reding 909dec72739SThierry Reding value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) | 910dec72739SThierry Reding DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) | 911dec72739SThierry Reding DSI_PAD_OUT_CLK(0x0); 912dec72739SThierry Reding tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2); 913dec72739SThierry Reding 914dec72739SThierry Reding return tegra_mipi_calibrate(dsi->mipi); 915dec72739SThierry Reding } 916dec72739SThierry Reding 917dec72739SThierry Reding static int tegra_dsi_init(struct host1x_client *client) 918dec72739SThierry Reding { 9199910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 920dec72739SThierry Reding struct tegra_dsi *dsi = host1x_client_to_dsi(client); 921dec72739SThierry Reding int err; 922dec72739SThierry Reding 923e94236cdSThierry Reding /* Gangsters must not register their own outputs. */ 924e94236cdSThierry Reding if (!dsi->master) { 925dec72739SThierry Reding dsi->output.type = TEGRA_OUTPUT_DSI; 926dec72739SThierry Reding dsi->output.dev = client->dev; 927dec72739SThierry Reding dsi->output.ops = &dsi_ops; 928dec72739SThierry Reding 9299910f5c4SThierry Reding err = tegra_output_init(drm, &dsi->output); 930dec72739SThierry Reding if (err < 0) { 931dec72739SThierry Reding dev_err(client->dev, "output setup failed: %d\n", err); 932dec72739SThierry Reding return err; 933dec72739SThierry Reding } 934e94236cdSThierry Reding } 935dec72739SThierry Reding 936dec72739SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 9379910f5c4SThierry Reding err = tegra_dsi_debugfs_init(dsi, drm->primary); 938dec72739SThierry Reding if (err < 0) 939dec72739SThierry Reding dev_err(dsi->dev, "debugfs setup failed: %d\n", err); 940dec72739SThierry Reding } 941dec72739SThierry Reding 942dec72739SThierry Reding return 0; 943dec72739SThierry Reding } 944dec72739SThierry Reding 945dec72739SThierry Reding static int tegra_dsi_exit(struct host1x_client *client) 946dec72739SThierry Reding { 947dec72739SThierry Reding struct tegra_dsi *dsi = host1x_client_to_dsi(client); 948dec72739SThierry Reding int err; 949dec72739SThierry Reding 950dec72739SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 951dec72739SThierry Reding err = tegra_dsi_debugfs_exit(dsi); 952dec72739SThierry Reding if (err < 0) 953dec72739SThierry Reding dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); 954dec72739SThierry Reding } 955dec72739SThierry Reding 956e94236cdSThierry Reding if (!dsi->master) { 957dec72739SThierry Reding err = tegra_output_disable(&dsi->output); 958dec72739SThierry Reding if (err < 0) { 959e94236cdSThierry Reding dev_err(client->dev, "output failed to disable: %d\n", 960e94236cdSThierry Reding err); 961dec72739SThierry Reding return err; 962dec72739SThierry Reding } 963dec72739SThierry Reding 964dec72739SThierry Reding err = tegra_output_exit(&dsi->output); 965dec72739SThierry Reding if (err < 0) { 966e94236cdSThierry Reding dev_err(client->dev, "output cleanup failed: %d\n", 967e94236cdSThierry Reding err); 968dec72739SThierry Reding return err; 969dec72739SThierry Reding } 970e94236cdSThierry Reding } 971dec72739SThierry Reding 972dec72739SThierry Reding return 0; 973dec72739SThierry Reding } 974dec72739SThierry Reding 975dec72739SThierry Reding static const struct host1x_client_ops dsi_client_ops = { 976dec72739SThierry Reding .init = tegra_dsi_init, 977dec72739SThierry Reding .exit = tegra_dsi_exit, 978dec72739SThierry Reding }; 979dec72739SThierry Reding 980dec72739SThierry Reding static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) 981dec72739SThierry Reding { 982dec72739SThierry Reding struct clk *parent; 983dec72739SThierry Reding int err; 984dec72739SThierry Reding 985dec72739SThierry Reding parent = clk_get_parent(dsi->clk); 986dec72739SThierry Reding if (!parent) 987dec72739SThierry Reding return -EINVAL; 988dec72739SThierry Reding 989dec72739SThierry Reding err = clk_set_parent(parent, dsi->clk_parent); 990dec72739SThierry Reding if (err < 0) 991dec72739SThierry Reding return err; 992dec72739SThierry Reding 993dec72739SThierry Reding return 0; 994dec72739SThierry Reding } 995dec72739SThierry Reding 9960fffdf6cSThierry Reding static const char * const error_report[16] = { 9970fffdf6cSThierry Reding "SoT Error", 9980fffdf6cSThierry Reding "SoT Sync Error", 9990fffdf6cSThierry Reding "EoT Sync Error", 10000fffdf6cSThierry Reding "Escape Mode Entry Command Error", 10010fffdf6cSThierry Reding "Low-Power Transmit Sync Error", 10020fffdf6cSThierry Reding "Peripheral Timeout Error", 10030fffdf6cSThierry Reding "False Control Error", 10040fffdf6cSThierry Reding "Contention Detected", 10050fffdf6cSThierry Reding "ECC Error, single-bit", 10060fffdf6cSThierry Reding "ECC Error, multi-bit", 10070fffdf6cSThierry Reding "Checksum Error", 10080fffdf6cSThierry Reding "DSI Data Type Not Recognized", 10090fffdf6cSThierry Reding "DSI VC ID Invalid", 10100fffdf6cSThierry Reding "Invalid Transmission Length", 10110fffdf6cSThierry Reding "Reserved", 10120fffdf6cSThierry Reding "DSI Protocol Violation", 10130fffdf6cSThierry Reding }; 10140fffdf6cSThierry Reding 10150fffdf6cSThierry Reding static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi, 10160fffdf6cSThierry Reding const struct mipi_dsi_msg *msg, 10170fffdf6cSThierry Reding size_t count) 10180fffdf6cSThierry Reding { 10190fffdf6cSThierry Reding u8 *rx = msg->rx_buf; 10200fffdf6cSThierry Reding unsigned int i, j, k; 10210fffdf6cSThierry Reding size_t size = 0; 10220fffdf6cSThierry Reding u16 errors; 10230fffdf6cSThierry Reding u32 value; 10240fffdf6cSThierry Reding 10250fffdf6cSThierry Reding /* read and parse packet header */ 10260fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_RD_DATA); 10270fffdf6cSThierry Reding 10280fffdf6cSThierry Reding switch (value & 0x3f) { 10290fffdf6cSThierry Reding case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: 10300fffdf6cSThierry Reding errors = (value >> 8) & 0xffff; 10310fffdf6cSThierry Reding dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n", 10320fffdf6cSThierry Reding errors); 10330fffdf6cSThierry Reding for (i = 0; i < ARRAY_SIZE(error_report); i++) 10340fffdf6cSThierry Reding if (errors & BIT(i)) 10350fffdf6cSThierry Reding dev_dbg(dsi->dev, " %2u: %s\n", i, 10360fffdf6cSThierry Reding error_report[i]); 10370fffdf6cSThierry Reding break; 10380fffdf6cSThierry Reding 10390fffdf6cSThierry Reding case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: 10400fffdf6cSThierry Reding rx[0] = (value >> 8) & 0xff; 10410fffdf6cSThierry Reding size = 1; 10420fffdf6cSThierry Reding break; 10430fffdf6cSThierry Reding 10440fffdf6cSThierry Reding case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: 10450fffdf6cSThierry Reding rx[0] = (value >> 8) & 0xff; 10460fffdf6cSThierry Reding rx[1] = (value >> 16) & 0xff; 10470fffdf6cSThierry Reding size = 2; 10480fffdf6cSThierry Reding break; 10490fffdf6cSThierry Reding 10500fffdf6cSThierry Reding case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: 10510fffdf6cSThierry Reding size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); 10520fffdf6cSThierry Reding break; 10530fffdf6cSThierry Reding 10540fffdf6cSThierry Reding case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: 10550fffdf6cSThierry Reding size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); 10560fffdf6cSThierry Reding break; 10570fffdf6cSThierry Reding 10580fffdf6cSThierry Reding default: 10590fffdf6cSThierry Reding dev_err(dsi->dev, "unhandled response type: %02x\n", 10600fffdf6cSThierry Reding value & 0x3f); 10610fffdf6cSThierry Reding return -EPROTO; 10620fffdf6cSThierry Reding } 10630fffdf6cSThierry Reding 10640fffdf6cSThierry Reding size = min(size, msg->rx_len); 10650fffdf6cSThierry Reding 10660fffdf6cSThierry Reding if (msg->rx_buf && size > 0) { 10670fffdf6cSThierry Reding for (i = 0, j = 0; i < count - 1; i++, j += 4) { 10680fffdf6cSThierry Reding u8 *rx = msg->rx_buf + j; 10690fffdf6cSThierry Reding 10700fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_RD_DATA); 10710fffdf6cSThierry Reding 10720fffdf6cSThierry Reding for (k = 0; k < 4 && (j + k) < msg->rx_len; k++) 10730fffdf6cSThierry Reding rx[j + k] = (value >> (k << 3)) & 0xff; 10740fffdf6cSThierry Reding } 10750fffdf6cSThierry Reding } 10760fffdf6cSThierry Reding 10770fffdf6cSThierry Reding return size; 10780fffdf6cSThierry Reding } 10790fffdf6cSThierry Reding 10800fffdf6cSThierry Reding static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout) 10810fffdf6cSThierry Reding { 10820fffdf6cSThierry Reding tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER); 10830fffdf6cSThierry Reding 10840fffdf6cSThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 10850fffdf6cSThierry Reding 10860fffdf6cSThierry Reding while (time_before(jiffies, timeout)) { 10870fffdf6cSThierry Reding u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER); 10880fffdf6cSThierry Reding if ((value & DSI_TRIGGER_HOST) == 0) 10890fffdf6cSThierry Reding return 0; 10900fffdf6cSThierry Reding 10910fffdf6cSThierry Reding usleep_range(1000, 2000); 10920fffdf6cSThierry Reding } 10930fffdf6cSThierry Reding 10940fffdf6cSThierry Reding DRM_DEBUG_KMS("timeout waiting for transmission to complete\n"); 10950fffdf6cSThierry Reding return -ETIMEDOUT; 10960fffdf6cSThierry Reding } 10970fffdf6cSThierry Reding 10980fffdf6cSThierry Reding static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi, 10990fffdf6cSThierry Reding unsigned long timeout) 11000fffdf6cSThierry Reding { 11010fffdf6cSThierry Reding timeout = jiffies + msecs_to_jiffies(250); 11020fffdf6cSThierry Reding 11030fffdf6cSThierry Reding while (time_before(jiffies, timeout)) { 11040fffdf6cSThierry Reding u32 value = tegra_dsi_readl(dsi, DSI_STATUS); 11050fffdf6cSThierry Reding u8 count = value & 0x1f; 11060fffdf6cSThierry Reding 11070fffdf6cSThierry Reding if (count > 0) 11080fffdf6cSThierry Reding return count; 11090fffdf6cSThierry Reding 11100fffdf6cSThierry Reding usleep_range(1000, 2000); 11110fffdf6cSThierry Reding } 11120fffdf6cSThierry Reding 11130fffdf6cSThierry Reding DRM_DEBUG_KMS("peripheral returned no data\n"); 11140fffdf6cSThierry Reding return -ETIMEDOUT; 11150fffdf6cSThierry Reding } 11160fffdf6cSThierry Reding 11170fffdf6cSThierry Reding static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset, 11180fffdf6cSThierry Reding const void *buffer, size_t size) 11190fffdf6cSThierry Reding { 11200fffdf6cSThierry Reding const u8 *buf = buffer; 11210fffdf6cSThierry Reding size_t i, j; 11220fffdf6cSThierry Reding u32 value; 11230fffdf6cSThierry Reding 11240fffdf6cSThierry Reding for (j = 0; j < size; j += 4) { 11250fffdf6cSThierry Reding value = 0; 11260fffdf6cSThierry Reding 11270fffdf6cSThierry Reding for (i = 0; i < 4 && j + i < size; i++) 11280fffdf6cSThierry Reding value |= buf[j + i] << (i << 3); 11290fffdf6cSThierry Reding 11300fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_WR_DATA); 11310fffdf6cSThierry Reding } 11320fffdf6cSThierry Reding } 11330fffdf6cSThierry Reding 11340fffdf6cSThierry Reding static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host, 11350fffdf6cSThierry Reding const struct mipi_dsi_msg *msg) 11360fffdf6cSThierry Reding { 11370fffdf6cSThierry Reding struct tegra_dsi *dsi = host_to_tegra(host); 11380fffdf6cSThierry Reding struct mipi_dsi_packet packet; 11390fffdf6cSThierry Reding const u8 *header; 11400fffdf6cSThierry Reding size_t count; 11410fffdf6cSThierry Reding ssize_t err; 11420fffdf6cSThierry Reding u32 value; 11430fffdf6cSThierry Reding 11440fffdf6cSThierry Reding err = mipi_dsi_create_packet(&packet, msg); 11450fffdf6cSThierry Reding if (err < 0) 11460fffdf6cSThierry Reding return err; 11470fffdf6cSThierry Reding 11480fffdf6cSThierry Reding header = packet.header; 11490fffdf6cSThierry Reding 11500fffdf6cSThierry Reding /* maximum FIFO depth is 1920 words */ 11510fffdf6cSThierry Reding if (packet.size > dsi->video_fifo_depth * 4) 11520fffdf6cSThierry Reding return -ENOSPC; 11530fffdf6cSThierry Reding 11540fffdf6cSThierry Reding /* reset underflow/overflow flags */ 11550fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_STATUS); 11560fffdf6cSThierry Reding if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) { 11570fffdf6cSThierry Reding value = DSI_HOST_CONTROL_FIFO_RESET; 11580fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); 11590fffdf6cSThierry Reding usleep_range(10, 20); 11600fffdf6cSThierry Reding } 11610fffdf6cSThierry Reding 11620fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); 11630fffdf6cSThierry Reding value |= DSI_POWER_CONTROL_ENABLE; 11640fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); 11650fffdf6cSThierry Reding 11660fffdf6cSThierry Reding usleep_range(5000, 10000); 11670fffdf6cSThierry Reding 11680fffdf6cSThierry Reding value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | 11690fffdf6cSThierry Reding DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; 11700fffdf6cSThierry Reding 11710fffdf6cSThierry Reding if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0) 11720fffdf6cSThierry Reding value |= DSI_HOST_CONTROL_HS; 11730fffdf6cSThierry Reding 11740fffdf6cSThierry Reding /* 11750fffdf6cSThierry Reding * The host FIFO has a maximum of 64 words, so larger transmissions 11760fffdf6cSThierry Reding * need to use the video FIFO. 11770fffdf6cSThierry Reding */ 11780fffdf6cSThierry Reding if (packet.size > dsi->host_fifo_depth * 4) 11790fffdf6cSThierry Reding value |= DSI_HOST_CONTROL_FIFO_SEL; 11800fffdf6cSThierry Reding 11810fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); 11820fffdf6cSThierry Reding 11830fffdf6cSThierry Reding /* 11840fffdf6cSThierry Reding * For reads and messages with explicitly requested ACK, generate a 11850fffdf6cSThierry Reding * BTA sequence after the transmission of the packet. 11860fffdf6cSThierry Reding */ 11870fffdf6cSThierry Reding if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || 11880fffdf6cSThierry Reding (msg->rx_buf && msg->rx_len > 0)) { 11890fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL); 11900fffdf6cSThierry Reding value |= DSI_HOST_CONTROL_PKT_BTA; 11910fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); 11920fffdf6cSThierry Reding } 11930fffdf6cSThierry Reding 11940fffdf6cSThierry Reding value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE; 11950fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_CONTROL); 11960fffdf6cSThierry Reding 11970fffdf6cSThierry Reding /* write packet header, ECC is generated by hardware */ 11980fffdf6cSThierry Reding value = header[2] << 16 | header[1] << 8 | header[0]; 11990fffdf6cSThierry Reding tegra_dsi_writel(dsi, value, DSI_WR_DATA); 12000fffdf6cSThierry Reding 12010fffdf6cSThierry Reding /* write payload (if any) */ 12020fffdf6cSThierry Reding if (packet.payload_length > 0) 12030fffdf6cSThierry Reding tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload, 12040fffdf6cSThierry Reding packet.payload_length); 12050fffdf6cSThierry Reding 12060fffdf6cSThierry Reding err = tegra_dsi_transmit(dsi, 250); 12070fffdf6cSThierry Reding if (err < 0) 12080fffdf6cSThierry Reding return err; 12090fffdf6cSThierry Reding 12100fffdf6cSThierry Reding if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || 12110fffdf6cSThierry Reding (msg->rx_buf && msg->rx_len > 0)) { 12120fffdf6cSThierry Reding err = tegra_dsi_wait_for_response(dsi, 250); 12130fffdf6cSThierry Reding if (err < 0) 12140fffdf6cSThierry Reding return err; 12150fffdf6cSThierry Reding 12160fffdf6cSThierry Reding count = err; 12170fffdf6cSThierry Reding 12180fffdf6cSThierry Reding value = tegra_dsi_readl(dsi, DSI_RD_DATA); 12190fffdf6cSThierry Reding switch (value) { 12200fffdf6cSThierry Reding case 0x84: 12210fffdf6cSThierry Reding /* 12220fffdf6cSThierry Reding dev_dbg(dsi->dev, "ACK\n"); 12230fffdf6cSThierry Reding */ 12240fffdf6cSThierry Reding break; 12250fffdf6cSThierry Reding 12260fffdf6cSThierry Reding case 0x87: 12270fffdf6cSThierry Reding /* 12280fffdf6cSThierry Reding dev_dbg(dsi->dev, "ESCAPE\n"); 12290fffdf6cSThierry Reding */ 12300fffdf6cSThierry Reding break; 12310fffdf6cSThierry Reding 12320fffdf6cSThierry Reding default: 12330fffdf6cSThierry Reding dev_err(dsi->dev, "unknown status: %08x\n", value); 12340fffdf6cSThierry Reding break; 12350fffdf6cSThierry Reding } 12360fffdf6cSThierry Reding 12370fffdf6cSThierry Reding if (count > 1) { 12380fffdf6cSThierry Reding err = tegra_dsi_read_response(dsi, msg, count); 12390fffdf6cSThierry Reding if (err < 0) 12400fffdf6cSThierry Reding dev_err(dsi->dev, 12410fffdf6cSThierry Reding "failed to parse response: %zd\n", 12420fffdf6cSThierry Reding err); 12430fffdf6cSThierry Reding else { 12440fffdf6cSThierry Reding /* 12450fffdf6cSThierry Reding * For read commands, return the number of 12460fffdf6cSThierry Reding * bytes returned by the peripheral. 12470fffdf6cSThierry Reding */ 12480fffdf6cSThierry Reding count = err; 12490fffdf6cSThierry Reding } 12500fffdf6cSThierry Reding } 12510fffdf6cSThierry Reding } else { 12520fffdf6cSThierry Reding /* 12530fffdf6cSThierry Reding * For write commands, we have transmitted the 4-byte header 12540fffdf6cSThierry Reding * plus the variable-length payload. 12550fffdf6cSThierry Reding */ 12560fffdf6cSThierry Reding count = 4 + packet.payload_length; 12570fffdf6cSThierry Reding } 12580fffdf6cSThierry Reding 12590fffdf6cSThierry Reding return count; 12600fffdf6cSThierry Reding } 12610fffdf6cSThierry Reding 1262e94236cdSThierry Reding static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi) 1263e94236cdSThierry Reding { 1264e94236cdSThierry Reding struct clk *parent; 1265e94236cdSThierry Reding int err; 1266e94236cdSThierry Reding 1267e94236cdSThierry Reding /* make sure both DSI controllers share the same PLL */ 1268e94236cdSThierry Reding parent = clk_get_parent(dsi->slave->clk); 1269e94236cdSThierry Reding if (!parent) 1270e94236cdSThierry Reding return -EINVAL; 1271e94236cdSThierry Reding 1272e94236cdSThierry Reding err = clk_set_parent(parent, dsi->clk_parent); 1273e94236cdSThierry Reding if (err < 0) 1274e94236cdSThierry Reding return err; 1275e94236cdSThierry Reding 1276e94236cdSThierry Reding return 0; 1277e94236cdSThierry Reding } 1278e94236cdSThierry Reding 1279dec72739SThierry Reding static int tegra_dsi_host_attach(struct mipi_dsi_host *host, 1280dec72739SThierry Reding struct mipi_dsi_device *device) 1281dec72739SThierry Reding { 1282dec72739SThierry Reding struct tegra_dsi *dsi = host_to_tegra(host); 1283dec72739SThierry Reding 128417297a28SThierry Reding dsi->flags = device->mode_flags; 1285dec72739SThierry Reding dsi->format = device->format; 1286dec72739SThierry Reding dsi->lanes = device->lanes; 1287dec72739SThierry Reding 1288e94236cdSThierry Reding if (dsi->slave) { 1289e94236cdSThierry Reding int err; 1290e94236cdSThierry Reding 1291e94236cdSThierry Reding dev_dbg(dsi->dev, "attaching dual-channel device %s\n", 1292e94236cdSThierry Reding dev_name(&device->dev)); 1293e94236cdSThierry Reding 1294e94236cdSThierry Reding err = tegra_dsi_ganged_setup(dsi); 1295e94236cdSThierry Reding if (err < 0) { 1296e94236cdSThierry Reding dev_err(dsi->dev, "failed to set up ganged mode: %d\n", 1297e94236cdSThierry Reding err); 1298e94236cdSThierry Reding return err; 1299e94236cdSThierry Reding } 1300e94236cdSThierry Reding } 1301e94236cdSThierry Reding 1302e94236cdSThierry Reding /* 1303e94236cdSThierry Reding * Slaves don't have a panel associated with them, so they provide 1304e94236cdSThierry Reding * merely the second channel. 1305e94236cdSThierry Reding */ 1306e94236cdSThierry Reding if (!dsi->master) { 1307e94236cdSThierry Reding struct tegra_output *output = &dsi->output; 1308e94236cdSThierry Reding 1309dec72739SThierry Reding output->panel = of_drm_find_panel(device->dev.of_node); 1310e94236cdSThierry Reding if (output->panel && output->connector.dev) { 1311e94236cdSThierry Reding drm_panel_attach(output->panel, &output->connector); 1312dec72739SThierry Reding drm_helper_hpd_irq_event(output->connector.dev); 1313dec72739SThierry Reding } 1314e94236cdSThierry Reding } 1315dec72739SThierry Reding 1316dec72739SThierry Reding return 0; 1317dec72739SThierry Reding } 1318dec72739SThierry Reding 1319dec72739SThierry Reding static int tegra_dsi_host_detach(struct mipi_dsi_host *host, 1320dec72739SThierry Reding struct mipi_dsi_device *device) 1321dec72739SThierry Reding { 1322dec72739SThierry Reding struct tegra_dsi *dsi = host_to_tegra(host); 1323dec72739SThierry Reding struct tegra_output *output = &dsi->output; 1324dec72739SThierry Reding 1325dec72739SThierry Reding if (output->panel && &device->dev == output->panel->dev) { 1326ba3df979SThierry Reding output->panel = NULL; 1327ba3df979SThierry Reding 1328dec72739SThierry Reding if (output->connector.dev) 1329dec72739SThierry Reding drm_helper_hpd_irq_event(output->connector.dev); 1330dec72739SThierry Reding } 1331dec72739SThierry Reding 1332dec72739SThierry Reding return 0; 1333dec72739SThierry Reding } 1334dec72739SThierry Reding 1335dec72739SThierry Reding static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { 1336dec72739SThierry Reding .attach = tegra_dsi_host_attach, 1337dec72739SThierry Reding .detach = tegra_dsi_host_detach, 13380fffdf6cSThierry Reding .transfer = tegra_dsi_host_transfer, 1339dec72739SThierry Reding }; 1340dec72739SThierry Reding 1341e94236cdSThierry Reding static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) 1342e94236cdSThierry Reding { 1343e94236cdSThierry Reding struct device_node *np; 1344e94236cdSThierry Reding 1345e94236cdSThierry Reding np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); 1346e94236cdSThierry Reding if (np) { 1347e94236cdSThierry Reding struct platform_device *gangster = of_find_device_by_node(np); 1348e94236cdSThierry Reding 1349e94236cdSThierry Reding dsi->slave = platform_get_drvdata(gangster); 1350e94236cdSThierry Reding of_node_put(np); 1351e94236cdSThierry Reding 1352e94236cdSThierry Reding if (!dsi->slave) 1353e94236cdSThierry Reding return -EPROBE_DEFER; 1354e94236cdSThierry Reding 1355e94236cdSThierry Reding dsi->slave->master = dsi; 1356e94236cdSThierry Reding } 1357e94236cdSThierry Reding 1358e94236cdSThierry Reding return 0; 1359e94236cdSThierry Reding } 1360e94236cdSThierry Reding 1361dec72739SThierry Reding static int tegra_dsi_probe(struct platform_device *pdev) 1362dec72739SThierry Reding { 1363dec72739SThierry Reding struct tegra_dsi *dsi; 1364dec72739SThierry Reding struct resource *regs; 1365dec72739SThierry Reding int err; 1366dec72739SThierry Reding 1367dec72739SThierry Reding dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); 1368dec72739SThierry Reding if (!dsi) 1369dec72739SThierry Reding return -ENOMEM; 1370dec72739SThierry Reding 1371dec72739SThierry Reding dsi->output.dev = dsi->dev = &pdev->dev; 1372976cebc3SThierry Reding dsi->video_fifo_depth = 1920; 1373976cebc3SThierry Reding dsi->host_fifo_depth = 64; 1374dec72739SThierry Reding 1375e94236cdSThierry Reding err = tegra_dsi_ganged_probe(dsi); 1376e94236cdSThierry Reding if (err < 0) 1377e94236cdSThierry Reding return err; 1378e94236cdSThierry Reding 1379dec72739SThierry Reding err = tegra_output_probe(&dsi->output); 1380dec72739SThierry Reding if (err < 0) 1381dec72739SThierry Reding return err; 1382dec72739SThierry Reding 1383ba3df979SThierry Reding dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD; 1384ba3df979SThierry Reding 1385dec72739SThierry Reding /* 1386dec72739SThierry Reding * Assume these values by default. When a DSI peripheral driver 1387dec72739SThierry Reding * attaches to the DSI host, the parameters will be taken from 1388dec72739SThierry Reding * the attached device. 1389dec72739SThierry Reding */ 139017297a28SThierry Reding dsi->flags = MIPI_DSI_MODE_VIDEO; 1391dec72739SThierry Reding dsi->format = MIPI_DSI_FMT_RGB888; 1392dec72739SThierry Reding dsi->lanes = 4; 1393dec72739SThierry Reding 1394dec72739SThierry Reding dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); 1395dec72739SThierry Reding if (IS_ERR(dsi->rst)) 1396dec72739SThierry Reding return PTR_ERR(dsi->rst); 1397dec72739SThierry Reding 1398183ef288SThierry Reding err = reset_control_deassert(dsi->rst); 1399183ef288SThierry Reding if (err < 0) { 1400183ef288SThierry Reding dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n", 1401183ef288SThierry Reding err); 1402183ef288SThierry Reding return err; 1403183ef288SThierry Reding } 1404183ef288SThierry Reding 1405dec72739SThierry Reding dsi->clk = devm_clk_get(&pdev->dev, NULL); 1406dec72739SThierry Reding if (IS_ERR(dsi->clk)) { 1407dec72739SThierry Reding dev_err(&pdev->dev, "cannot get DSI clock\n"); 1408d2d0a9d2SThierry Reding err = PTR_ERR(dsi->clk); 1409d2d0a9d2SThierry Reding goto reset; 1410dec72739SThierry Reding } 1411dec72739SThierry Reding 1412dec72739SThierry Reding err = clk_prepare_enable(dsi->clk); 1413dec72739SThierry Reding if (err < 0) { 1414dec72739SThierry Reding dev_err(&pdev->dev, "cannot enable DSI clock\n"); 1415d2d0a9d2SThierry Reding goto reset; 1416dec72739SThierry Reding } 1417dec72739SThierry Reding 1418dec72739SThierry Reding dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); 1419dec72739SThierry Reding if (IS_ERR(dsi->clk_lp)) { 1420dec72739SThierry Reding dev_err(&pdev->dev, "cannot get low-power clock\n"); 1421d2d0a9d2SThierry Reding err = PTR_ERR(dsi->clk_lp); 1422d2d0a9d2SThierry Reding goto disable_clk; 1423dec72739SThierry Reding } 1424dec72739SThierry Reding 1425dec72739SThierry Reding err = clk_prepare_enable(dsi->clk_lp); 1426dec72739SThierry Reding if (err < 0) { 1427dec72739SThierry Reding dev_err(&pdev->dev, "cannot enable low-power clock\n"); 1428d2d0a9d2SThierry Reding goto disable_clk; 1429dec72739SThierry Reding } 1430dec72739SThierry Reding 1431dec72739SThierry Reding dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); 1432dec72739SThierry Reding if (IS_ERR(dsi->clk_parent)) { 1433dec72739SThierry Reding dev_err(&pdev->dev, "cannot get parent clock\n"); 1434d2d0a9d2SThierry Reding err = PTR_ERR(dsi->clk_parent); 1435d2d0a9d2SThierry Reding goto disable_clk_lp; 1436dec72739SThierry Reding } 1437dec72739SThierry Reding 14383b077afbSThierry Reding dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); 14393b077afbSThierry Reding if (IS_ERR(dsi->vdd)) { 14403b077afbSThierry Reding dev_err(&pdev->dev, "cannot get VDD supply\n"); 1441d2d0a9d2SThierry Reding err = PTR_ERR(dsi->vdd); 1442d2d0a9d2SThierry Reding goto disable_clk_lp; 14433b077afbSThierry Reding } 14443b077afbSThierry Reding 14453b077afbSThierry Reding err = regulator_enable(dsi->vdd); 14463b077afbSThierry Reding if (err < 0) { 14473b077afbSThierry Reding dev_err(&pdev->dev, "cannot enable VDD supply\n"); 1448d2d0a9d2SThierry Reding goto disable_clk_lp; 14493b077afbSThierry Reding } 14503b077afbSThierry Reding 1451dec72739SThierry Reding err = tegra_dsi_setup_clocks(dsi); 1452dec72739SThierry Reding if (err < 0) { 1453dec72739SThierry Reding dev_err(&pdev->dev, "cannot setup clocks\n"); 1454d2d0a9d2SThierry Reding goto disable_vdd; 1455dec72739SThierry Reding } 1456dec72739SThierry Reding 1457dec72739SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1458dec72739SThierry Reding dsi->regs = devm_ioremap_resource(&pdev->dev, regs); 1459d2d0a9d2SThierry Reding if (IS_ERR(dsi->regs)) { 1460d2d0a9d2SThierry Reding err = PTR_ERR(dsi->regs); 1461d2d0a9d2SThierry Reding goto disable_vdd; 1462d2d0a9d2SThierry Reding } 1463dec72739SThierry Reding 1464dec72739SThierry Reding dsi->mipi = tegra_mipi_request(&pdev->dev); 1465d2d0a9d2SThierry Reding if (IS_ERR(dsi->mipi)) { 1466d2d0a9d2SThierry Reding err = PTR_ERR(dsi->mipi); 1467d2d0a9d2SThierry Reding goto disable_vdd; 1468d2d0a9d2SThierry Reding } 1469dec72739SThierry Reding 1470183ef288SThierry Reding err = tegra_dsi_pad_calibrate(dsi); 1471183ef288SThierry Reding if (err < 0) { 1472183ef288SThierry Reding dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); 1473d2d0a9d2SThierry Reding goto mipi_free; 1474183ef288SThierry Reding } 1475183ef288SThierry Reding 1476dec72739SThierry Reding dsi->host.ops = &tegra_dsi_host_ops; 1477dec72739SThierry Reding dsi->host.dev = &pdev->dev; 1478dec72739SThierry Reding 1479dec72739SThierry Reding err = mipi_dsi_host_register(&dsi->host); 1480dec72739SThierry Reding if (err < 0) { 1481dec72739SThierry Reding dev_err(&pdev->dev, "failed to register DSI host: %d\n", err); 1482d2d0a9d2SThierry Reding goto mipi_free; 1483dec72739SThierry Reding } 1484dec72739SThierry Reding 1485dec72739SThierry Reding INIT_LIST_HEAD(&dsi->client.list); 1486dec72739SThierry Reding dsi->client.ops = &dsi_client_ops; 1487dec72739SThierry Reding dsi->client.dev = &pdev->dev; 1488dec72739SThierry Reding 1489dec72739SThierry Reding err = host1x_client_register(&dsi->client); 1490dec72739SThierry Reding if (err < 0) { 1491dec72739SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 1492dec72739SThierry Reding err); 1493d2d0a9d2SThierry Reding goto unregister; 1494dec72739SThierry Reding } 1495dec72739SThierry Reding 1496dec72739SThierry Reding platform_set_drvdata(pdev, dsi); 1497dec72739SThierry Reding 1498dec72739SThierry Reding return 0; 1499d2d0a9d2SThierry Reding 1500d2d0a9d2SThierry Reding unregister: 1501d2d0a9d2SThierry Reding mipi_dsi_host_unregister(&dsi->host); 1502d2d0a9d2SThierry Reding mipi_free: 1503d2d0a9d2SThierry Reding tegra_mipi_free(dsi->mipi); 1504d2d0a9d2SThierry Reding disable_vdd: 1505d2d0a9d2SThierry Reding regulator_disable(dsi->vdd); 1506d2d0a9d2SThierry Reding disable_clk_lp: 1507d2d0a9d2SThierry Reding clk_disable_unprepare(dsi->clk_lp); 1508d2d0a9d2SThierry Reding disable_clk: 1509d2d0a9d2SThierry Reding clk_disable_unprepare(dsi->clk); 1510d2d0a9d2SThierry Reding reset: 1511d2d0a9d2SThierry Reding reset_control_assert(dsi->rst); 1512d2d0a9d2SThierry Reding return err; 1513dec72739SThierry Reding } 1514dec72739SThierry Reding 1515dec72739SThierry Reding static int tegra_dsi_remove(struct platform_device *pdev) 1516dec72739SThierry Reding { 1517dec72739SThierry Reding struct tegra_dsi *dsi = platform_get_drvdata(pdev); 1518dec72739SThierry Reding int err; 1519dec72739SThierry Reding 1520dec72739SThierry Reding err = host1x_client_unregister(&dsi->client); 1521dec72739SThierry Reding if (err < 0) { 1522dec72739SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1523dec72739SThierry Reding err); 1524dec72739SThierry Reding return err; 1525dec72739SThierry Reding } 1526dec72739SThierry Reding 1527dec72739SThierry Reding mipi_dsi_host_unregister(&dsi->host); 1528dec72739SThierry Reding tegra_mipi_free(dsi->mipi); 1529dec72739SThierry Reding 15303b077afbSThierry Reding regulator_disable(dsi->vdd); 1531dec72739SThierry Reding clk_disable_unprepare(dsi->clk_lp); 1532dec72739SThierry Reding clk_disable_unprepare(dsi->clk); 1533cb825d89SThierry Reding reset_control_assert(dsi->rst); 1534dec72739SThierry Reding 1535dec72739SThierry Reding err = tegra_output_remove(&dsi->output); 1536dec72739SThierry Reding if (err < 0) { 1537dec72739SThierry Reding dev_err(&pdev->dev, "failed to remove output: %d\n", err); 1538dec72739SThierry Reding return err; 1539dec72739SThierry Reding } 1540dec72739SThierry Reding 1541dec72739SThierry Reding return 0; 1542dec72739SThierry Reding } 1543dec72739SThierry Reding 1544dec72739SThierry Reding static const struct of_device_id tegra_dsi_of_match[] = { 1545dec72739SThierry Reding { .compatible = "nvidia,tegra114-dsi", }, 1546dec72739SThierry Reding { }, 1547dec72739SThierry Reding }; 1548ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dsi_of_match); 1549dec72739SThierry Reding 1550dec72739SThierry Reding struct platform_driver tegra_dsi_driver = { 1551dec72739SThierry Reding .driver = { 1552dec72739SThierry Reding .name = "tegra-dsi", 1553dec72739SThierry Reding .of_match_table = tegra_dsi_of_match, 1554dec72739SThierry Reding }, 1555dec72739SThierry Reding .probe = tegra_dsi_probe, 1556dec72739SThierry Reding .remove = tegra_dsi_remove, 1557dec72739SThierry Reding }; 1558