blob: 55748bc081e8e66e202f242419bcad1d55a55a69 [file] [log] [blame]
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001/*
2 * linux/drivers/video/omap2/dss/dsi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "DSI"
21
22#include <linux/kernel.h>
23#include <linux/io.h>
24#include <linux/clk.h>
25#include <linux/device.h>
26#include <linux/err.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/mutex.h>
Paul Gortmaker355b2002011-07-03 16:17:28 -040030#include <linux/module.h>
Tomi Valkeinenb9eb5d72010-01-11 16:33:56 +020031#include <linux/semaphore.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020032#include <linux/seq_file.h>
33#include <linux/platform_device.h>
34#include <linux/regulator/consumer.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020035#include <linux/wait.h>
Tomi Valkeinen18946f62010-01-12 14:16:41 +020036#include <linux/workqueue.h>
Tomi Valkeinen40885ab2010-07-28 15:53:38 +030037#include <linux/sched.h>
Archit Tanejaf1da39d2011-05-12 17:26:27 +053038#include <linux/slab.h>
Archit Taneja5a8b5722011-05-12 17:26:29 +053039#include <linux/debugfs.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030040#include <linux/pm_runtime.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020041
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030042#include <video/omapdss.h>
Archit Taneja7a7c48f2011-08-25 18:25:03 +053043#include <video/mipi_display.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020044
45#include "dss.h"
Archit Taneja819d8072011-03-01 11:54:00 +053046#include "dss_features.h"
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020047
48/*#define VERBOSE_IRQ*/
49#define DSI_CATCH_MISSING_TE
50
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020051struct dsi_reg { u16 idx; };
52
53#define DSI_REG(idx) ((const struct dsi_reg) { idx })
54
55#define DSI_SZ_REGS SZ_1K
56/* DSI Protocol Engine */
57
58#define DSI_REVISION DSI_REG(0x0000)
59#define DSI_SYSCONFIG DSI_REG(0x0010)
60#define DSI_SYSSTATUS DSI_REG(0x0014)
61#define DSI_IRQSTATUS DSI_REG(0x0018)
62#define DSI_IRQENABLE DSI_REG(0x001C)
63#define DSI_CTRL DSI_REG(0x0040)
Archit Taneja75d72472011-05-16 15:17:08 +053064#define DSI_GNQ DSI_REG(0x0044)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020065#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
66#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
67#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
68#define DSI_CLK_CTRL DSI_REG(0x0054)
69#define DSI_TIMING1 DSI_REG(0x0058)
70#define DSI_TIMING2 DSI_REG(0x005C)
71#define DSI_VM_TIMING1 DSI_REG(0x0060)
72#define DSI_VM_TIMING2 DSI_REG(0x0064)
73#define DSI_VM_TIMING3 DSI_REG(0x0068)
74#define DSI_CLK_TIMING DSI_REG(0x006C)
75#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
76#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
77#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
78#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
79#define DSI_VM_TIMING4 DSI_REG(0x0080)
80#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
81#define DSI_VM_TIMING5 DSI_REG(0x0088)
82#define DSI_VM_TIMING6 DSI_REG(0x008C)
83#define DSI_VM_TIMING7 DSI_REG(0x0090)
84#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
85#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
86#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
87#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
88#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
89#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
90#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
91#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
92
93/* DSIPHY_SCP */
94
95#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
96#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
97#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
98#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +030099#define DSI_DSIPHY_CFG10 DSI_REG(0x200 + 0x0028)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200100
101/* DSI_PLL_CTRL_SCP */
102
103#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
104#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
105#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
106#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
107#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
108
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530109#define REG_GET(dsidev, idx, start, end) \
110 FLD_GET(dsi_read_reg(dsidev, idx), start, end)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200111
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530112#define REG_FLD_MOD(dsidev, idx, val, start, end) \
113 dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200114
115/* Global interrupts */
116#define DSI_IRQ_VC0 (1 << 0)
117#define DSI_IRQ_VC1 (1 << 1)
118#define DSI_IRQ_VC2 (1 << 2)
119#define DSI_IRQ_VC3 (1 << 3)
120#define DSI_IRQ_WAKEUP (1 << 4)
121#define DSI_IRQ_RESYNC (1 << 5)
122#define DSI_IRQ_PLL_LOCK (1 << 7)
123#define DSI_IRQ_PLL_UNLOCK (1 << 8)
124#define DSI_IRQ_PLL_RECALL (1 << 9)
125#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
126#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
127#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
128#define DSI_IRQ_TE_TRIGGER (1 << 16)
129#define DSI_IRQ_ACK_TRIGGER (1 << 17)
130#define DSI_IRQ_SYNC_LOST (1 << 18)
131#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
132#define DSI_IRQ_TA_TIMEOUT (1 << 20)
133#define DSI_IRQ_ERROR_MASK \
134 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
Archit Taneja8af6ff02011-09-05 16:48:27 +0530135 DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200136#define DSI_IRQ_CHANNEL_MASK 0xf
137
138/* Virtual channel interrupts */
139#define DSI_VC_IRQ_CS (1 << 0)
140#define DSI_VC_IRQ_ECC_CORR (1 << 1)
141#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
142#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
143#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
144#define DSI_VC_IRQ_BTA (1 << 5)
145#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
146#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
147#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
148#define DSI_VC_IRQ_ERROR_MASK \
149 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
150 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
151 DSI_VC_IRQ_FIFO_TX_UDF)
152
153/* ComplexIO interrupts */
154#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
155#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
156#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200157#define DSI_CIO_IRQ_ERRSYNCESC4 (1 << 3)
158#define DSI_CIO_IRQ_ERRSYNCESC5 (1 << 4)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200159#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
160#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
161#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200162#define DSI_CIO_IRQ_ERRESC4 (1 << 8)
163#define DSI_CIO_IRQ_ERRESC5 (1 << 9)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200164#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
165#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
166#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200167#define DSI_CIO_IRQ_ERRCONTROL4 (1 << 13)
168#define DSI_CIO_IRQ_ERRCONTROL5 (1 << 14)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200169#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
170#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
171#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200172#define DSI_CIO_IRQ_STATEULPS4 (1 << 18)
173#define DSI_CIO_IRQ_STATEULPS5 (1 << 19)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200174#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
175#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
176#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
177#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
178#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
179#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200180#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
181#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
182#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
183#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200184#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
185#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
Tomi Valkeinenbbecb502010-05-10 14:35:33 +0300186#define DSI_CIO_IRQ_ERROR_MASK \
187 (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
Tomi Valkeinen67056152011-03-24 16:30:17 +0200188 DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
189 DSI_CIO_IRQ_ERRSYNCESC5 | \
190 DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
191 DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
192 DSI_CIO_IRQ_ERRESC5 | \
193 DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
194 DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
195 DSI_CIO_IRQ_ERRCONTROL5 | \
Tomi Valkeinenbbecb502010-05-10 14:35:33 +0300196 DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
197 DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
Tomi Valkeinen67056152011-03-24 16:30:17 +0200198 DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
199 DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
200 DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200201
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200202typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
203
204#define DSI_MAX_NR_ISRS 2
Tomi Valkeinen739a7f42011-10-13 11:22:06 +0300205#define DSI_MAX_NR_LANES 5
206
207enum dsi_lane_function {
208 DSI_LANE_UNUSED = 0,
209 DSI_LANE_CLK,
210 DSI_LANE_DATA1,
211 DSI_LANE_DATA2,
212 DSI_LANE_DATA3,
213 DSI_LANE_DATA4,
214};
215
216struct dsi_lane_config {
217 enum dsi_lane_function function;
218 u8 polarity;
219};
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200220
221struct dsi_isr_data {
222 omap_dsi_isr_t isr;
223 void *arg;
224 u32 mask;
225};
226
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200227enum fifo_size {
228 DSI_FIFO_SIZE_0 = 0,
229 DSI_FIFO_SIZE_32 = 1,
230 DSI_FIFO_SIZE_64 = 2,
231 DSI_FIFO_SIZE_96 = 3,
232 DSI_FIFO_SIZE_128 = 4,
233};
234
Archit Tanejad6049142011-08-22 11:58:08 +0530235enum dsi_vc_source {
236 DSI_VC_SOURCE_L4 = 0,
237 DSI_VC_SOURCE_VP,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200238};
239
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200240struct dsi_irq_stats {
241 unsigned long last_reset;
242 unsigned irq_count;
243 unsigned dsi_irqs[32];
244 unsigned vc_irqs[4][32];
245 unsigned cio_irqs[32];
246};
247
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200248struct dsi_isr_tables {
249 struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
250 struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
251 struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
252};
253
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530254struct dsi_data {
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +0000255 struct platform_device *pdev;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200256 void __iomem *base;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300257
Tomi Valkeinen11ee9602012-03-09 16:07:39 +0200258 int module_id;
259
archit tanejaaffe3602011-02-23 08:41:03 +0000260 int irq;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200261
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300262 struct clk *dss_clk;
263 struct clk *sys_clk;
264
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200265 struct dsi_clock_info current_cinfo;
266
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +0300267 bool vdds_dsi_enabled;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200268 struct regulator *vdds_dsi_reg;
269
270 struct {
Archit Tanejad6049142011-08-22 11:58:08 +0530271 enum dsi_vc_source source;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200272 struct omap_dss_device *dssdev;
273 enum fifo_size fifo_size;
Archit Taneja5ee3c142011-03-02 12:35:53 +0530274 int vc_id;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200275 } vc[4];
276
277 struct mutex lock;
Tomi Valkeinenb9eb5d72010-01-11 16:33:56 +0200278 struct semaphore bus_lock;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200279
280 unsigned pll_locked;
281
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200282 spinlock_t irq_lock;
283 struct dsi_isr_tables isr_tables;
284 /* space for a copy used by the interrupt handler */
285 struct dsi_isr_tables isr_tables_copy;
286
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200287 int update_channel;
Tomi Valkeinen5476e742011-11-03 16:34:20 +0200288#ifdef DEBUG
289 unsigned update_bytes;
290#endif
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200291
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200292 bool te_enabled;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +0300293 bool ulps_enabled;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200294
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200295 void (*framedone_callback)(int, void *);
296 void *framedone_data;
297
298 struct delayed_work framedone_timeout_work;
299
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200300#ifdef DSI_CATCH_MISSING_TE
301 struct timer_list te_timer;
302#endif
303
304 unsigned long cache_req_pck;
305 unsigned long cache_clk_freq;
306 struct dsi_clock_info cache_cinfo;
307
308 u32 errors;
309 spinlock_t errors_lock;
310#ifdef DEBUG
311 ktime_t perf_setup_time;
312 ktime_t perf_start_time;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200313#endif
314 int debug_read;
315 int debug_write;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200316
317#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
318 spinlock_t irq_stats_lock;
319 struct dsi_irq_stats irq_stats;
320#endif
Taneja, Archit49641112011-03-14 23:28:23 -0500321 /* DSI PLL Parameter Ranges */
322 unsigned long regm_max, regn_max;
323 unsigned long regm_dispc_max, regm_dsi_max;
324 unsigned long fint_min, fint_max;
325 unsigned long lpdiv_max;
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +0300326
Tomi Valkeinend9820852011-10-12 15:05:59 +0300327 unsigned num_lanes_supported;
Archit Taneja75d72472011-05-16 15:17:08 +0530328
Tomi Valkeinen739a7f42011-10-13 11:22:06 +0300329 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
330 unsigned num_lanes_used;
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +0300331
332 unsigned scp_clk_refcount;
Archit Taneja7d2572f2012-06-29 14:31:07 +0530333
334 struct dss_lcd_mgr_config mgr_config;
Archit Tanejae67458a2012-08-13 14:17:30 +0530335 struct omap_video_timings timings;
Archit Taneja02c39602012-08-10 15:01:33 +0530336 enum omap_dss_dsi_pixel_format pix_fmt;
Archit Tanejadca2b152012-08-16 18:02:00 +0530337 enum omap_dss_dsi_mode mode;
Archit Taneja0b3ffe32012-08-13 22:13:39 +0530338 struct omap_dss_dsi_videomode_timings vm_timings;
Archit Taneja81b87f52012-09-26 16:30:49 +0530339
340 struct omap_dss_output output;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530341};
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200342
Archit Taneja2e868db2011-05-12 17:26:28 +0530343struct dsi_packet_sent_handler_data {
344 struct platform_device *dsidev;
345 struct completion *completion;
346};
347
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530348static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
349
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200350#ifdef DEBUG
Rusty Russell90ab5ee2012-01-13 09:32:20 +1030351static bool dsi_perf;
352module_param(dsi_perf, bool, 0644);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200353#endif
354
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530355static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
356{
357 return dev_get_drvdata(&dsidev->dev);
358}
359
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530360static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
361{
362 return dsi_pdev_map[dssdev->phy.dsi.module];
363}
364
365struct platform_device *dsi_get_dsidev_from_id(int module)
366{
367 return dsi_pdev_map[module];
368}
369
370static inline void dsi_write_reg(struct platform_device *dsidev,
371 const struct dsi_reg idx, u32 val)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200372{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530373 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
374
375 __raw_writel(val, dsi->base + idx.idx);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200376}
377
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530378static inline u32 dsi_read_reg(struct platform_device *dsidev,
379 const struct dsi_reg idx)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200380{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530381 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
382
383 return __raw_readl(dsi->base + idx.idx);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200384}
385
Archit Taneja1ffefe72011-05-12 17:26:24 +0530386void dsi_bus_lock(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200387{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530388 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
389 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
390
391 down(&dsi->bus_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200392}
393EXPORT_SYMBOL(dsi_bus_lock);
394
Archit Taneja1ffefe72011-05-12 17:26:24 +0530395void dsi_bus_unlock(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200396{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530397 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
398 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
399
400 up(&dsi->bus_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200401}
402EXPORT_SYMBOL(dsi_bus_unlock);
403
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530404static bool dsi_bus_is_locked(struct platform_device *dsidev)
Tomi Valkeinen4f765022010-01-18 16:27:52 +0200405{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530406 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
407
408 return dsi->bus_lock.count == 0;
Tomi Valkeinen4f765022010-01-18 16:27:52 +0200409}
410
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +0200411static void dsi_completion_handler(void *data, u32 mask)
412{
413 complete((struct completion *)data);
414}
415
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530416static inline int wait_for_bit_change(struct platform_device *dsidev,
417 const struct dsi_reg idx, int bitnum, int value)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200418{
Tomi Valkeinen3b984092011-10-13 19:06:49 +0300419 unsigned long timeout;
420 ktime_t wait;
421 int t;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200422
Tomi Valkeinen3b984092011-10-13 19:06:49 +0300423 /* first busyloop to see if the bit changes right away */
424 t = 100;
425 while (t-- > 0) {
426 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
427 return value;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200428 }
429
Tomi Valkeinen3b984092011-10-13 19:06:49 +0300430 /* then loop for 500ms, sleeping for 1ms in between */
431 timeout = jiffies + msecs_to_jiffies(500);
432 while (time_before(jiffies, timeout)) {
433 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
434 return value;
435
436 wait = ns_to_ktime(1000 * 1000);
437 set_current_state(TASK_UNINTERRUPTIBLE);
438 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
439 }
440
441 return !value;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200442}
443
Archit Tanejaa3b3cc22011-09-08 18:42:16 +0530444u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
445{
446 switch (fmt) {
447 case OMAP_DSS_DSI_FMT_RGB888:
448 case OMAP_DSS_DSI_FMT_RGB666:
449 return 24;
450 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
451 return 18;
452 case OMAP_DSS_DSI_FMT_RGB565:
453 return 16;
454 default:
455 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300456 return 0;
Archit Tanejaa3b3cc22011-09-08 18:42:16 +0530457 }
458}
459
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200460#ifdef DEBUG
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530461static void dsi_perf_mark_setup(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200462{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530463 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
464 dsi->perf_setup_time = ktime_get();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200465}
466
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530467static void dsi_perf_mark_start(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200468{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530469 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
470 dsi->perf_start_time = ktime_get();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200471}
472
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530473static void dsi_perf_show(struct platform_device *dsidev, const char *name)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200474{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530475 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200476 ktime_t t, setup_time, trans_time;
477 u32 total_bytes;
478 u32 setup_us, trans_us, total_us;
479
480 if (!dsi_perf)
481 return;
482
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200483 t = ktime_get();
484
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530485 setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200486 setup_us = (u32)ktime_to_us(setup_time);
487 if (setup_us == 0)
488 setup_us = 1;
489
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530490 trans_time = ktime_sub(t, dsi->perf_start_time);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200491 trans_us = (u32)ktime_to_us(trans_time);
492 if (trans_us == 0)
493 trans_us = 1;
494
495 total_us = setup_us + trans_us;
496
Tomi Valkeinen5476e742011-11-03 16:34:20 +0200497 total_bytes = dsi->update_bytes;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200498
Tomi Valkeinen1bbb2752010-01-11 16:41:10 +0200499 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
500 "%u bytes, %u kbytes/sec\n",
501 name,
502 setup_us,
503 trans_us,
504 total_us,
505 1000*1000 / total_us,
506 total_bytes,
507 total_bytes * 1000 / total_us);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200508}
509#else
Tomi Valkeinen4a9a5e32011-05-23 16:36:09 +0300510static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
511{
512}
513
514static inline void dsi_perf_mark_start(struct platform_device *dsidev)
515{
516}
517
518static inline void dsi_perf_show(struct platform_device *dsidev,
519 const char *name)
520{
521}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200522#endif
523
524static void print_irq_status(u32 status)
525{
Tomi Valkeinend80d4992011-03-02 15:53:07 +0200526 if (status == 0)
527 return;
528
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200529#ifndef VERBOSE_IRQ
530 if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
531 return;
532#endif
533 printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
534
535#define PIS(x) \
536 if (status & DSI_IRQ_##x) \
537 printk(#x " ");
538#ifdef VERBOSE_IRQ
539 PIS(VC0);
540 PIS(VC1);
541 PIS(VC2);
542 PIS(VC3);
543#endif
544 PIS(WAKEUP);
545 PIS(RESYNC);
546 PIS(PLL_LOCK);
547 PIS(PLL_UNLOCK);
548 PIS(PLL_RECALL);
549 PIS(COMPLEXIO_ERR);
550 PIS(HS_TX_TIMEOUT);
551 PIS(LP_RX_TIMEOUT);
552 PIS(TE_TRIGGER);
553 PIS(ACK_TRIGGER);
554 PIS(SYNC_LOST);
555 PIS(LDO_POWER_GOOD);
556 PIS(TA_TIMEOUT);
557#undef PIS
558
559 printk("\n");
560}
561
562static void print_irq_status_vc(int channel, u32 status)
563{
Tomi Valkeinend80d4992011-03-02 15:53:07 +0200564 if (status == 0)
565 return;
566
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200567#ifndef VERBOSE_IRQ
568 if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
569 return;
570#endif
571 printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
572
573#define PIS(x) \
574 if (status & DSI_VC_IRQ_##x) \
575 printk(#x " ");
576 PIS(CS);
577 PIS(ECC_CORR);
578#ifdef VERBOSE_IRQ
579 PIS(PACKET_SENT);
580#endif
581 PIS(FIFO_TX_OVF);
582 PIS(FIFO_RX_OVF);
583 PIS(BTA);
584 PIS(ECC_NO_CORR);
585 PIS(FIFO_TX_UDF);
586 PIS(PP_BUSY_CHANGE);
587#undef PIS
588 printk("\n");
589}
590
591static void print_irq_status_cio(u32 status)
592{
Tomi Valkeinend80d4992011-03-02 15:53:07 +0200593 if (status == 0)
594 return;
595
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200596 printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
597
598#define PIS(x) \
599 if (status & DSI_CIO_IRQ_##x) \
600 printk(#x " ");
601 PIS(ERRSYNCESC1);
602 PIS(ERRSYNCESC2);
603 PIS(ERRSYNCESC3);
604 PIS(ERRESC1);
605 PIS(ERRESC2);
606 PIS(ERRESC3);
607 PIS(ERRCONTROL1);
608 PIS(ERRCONTROL2);
609 PIS(ERRCONTROL3);
610 PIS(STATEULPS1);
611 PIS(STATEULPS2);
612 PIS(STATEULPS3);
613 PIS(ERRCONTENTIONLP0_1);
614 PIS(ERRCONTENTIONLP1_1);
615 PIS(ERRCONTENTIONLP0_2);
616 PIS(ERRCONTENTIONLP1_2);
617 PIS(ERRCONTENTIONLP0_3);
618 PIS(ERRCONTENTIONLP1_3);
619 PIS(ULPSACTIVENOT_ALL0);
620 PIS(ULPSACTIVENOT_ALL1);
621#undef PIS
622
623 printk("\n");
624}
625
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200626#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530627static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
628 u32 *vcstatus, u32 ciostatus)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200629{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530630 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200631 int i;
632
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530633 spin_lock(&dsi->irq_stats_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200634
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530635 dsi->irq_stats.irq_count++;
636 dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200637
638 for (i = 0; i < 4; ++i)
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530639 dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200640
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530641 dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200642
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530643 spin_unlock(&dsi->irq_stats_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200644}
645#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530646#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200647#endif
648
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200649static int debug_irq;
650
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530651static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
652 u32 *vcstatus, u32 ciostatus)
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200653{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530654 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200655 int i;
656
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200657 if (irqstatus & DSI_IRQ_ERROR_MASK) {
658 DSSERR("DSI error, irqstatus %x\n", irqstatus);
659 print_irq_status(irqstatus);
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530660 spin_lock(&dsi->errors_lock);
661 dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
662 spin_unlock(&dsi->errors_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200663 } else if (debug_irq) {
664 print_irq_status(irqstatus);
665 }
666
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200667 for (i = 0; i < 4; ++i) {
668 if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
669 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
670 i, vcstatus[i]);
671 print_irq_status_vc(i, vcstatus[i]);
672 } else if (debug_irq) {
673 print_irq_status_vc(i, vcstatus[i]);
674 }
675 }
676
677 if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
678 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
679 print_irq_status_cio(ciostatus);
680 } else if (debug_irq) {
681 print_irq_status_cio(ciostatus);
682 }
683}
684
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200685static void dsi_call_isrs(struct dsi_isr_data *isr_array,
686 unsigned isr_array_size, u32 irqstatus)
687{
688 struct dsi_isr_data *isr_data;
689 int i;
690
691 for (i = 0; i < isr_array_size; i++) {
692 isr_data = &isr_array[i];
693 if (isr_data->isr && isr_data->mask & irqstatus)
694 isr_data->isr(isr_data->arg, irqstatus);
695 }
696}
697
698static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
699 u32 irqstatus, u32 *vcstatus, u32 ciostatus)
700{
701 int i;
702
703 dsi_call_isrs(isr_tables->isr_table,
704 ARRAY_SIZE(isr_tables->isr_table),
705 irqstatus);
706
707 for (i = 0; i < 4; ++i) {
708 if (vcstatus[i] == 0)
709 continue;
710 dsi_call_isrs(isr_tables->isr_table_vc[i],
711 ARRAY_SIZE(isr_tables->isr_table_vc[i]),
712 vcstatus[i]);
713 }
714
715 if (ciostatus != 0)
716 dsi_call_isrs(isr_tables->isr_table_cio,
717 ARRAY_SIZE(isr_tables->isr_table_cio),
718 ciostatus);
719}
720
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200721static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
722{
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530723 struct platform_device *dsidev;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530724 struct dsi_data *dsi;
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200725 u32 irqstatus, vcstatus[4], ciostatus;
726 int i;
727
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530728 dsidev = (struct platform_device *) arg;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530729 dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530730
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530731 spin_lock(&dsi->irq_lock);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200732
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530733 irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200734
735 /* IRQ is not for us */
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200736 if (!irqstatus) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530737 spin_unlock(&dsi->irq_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200738 return IRQ_NONE;
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200739 }
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200740
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530741 dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200742 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530743 dsi_read_reg(dsidev, DSI_IRQSTATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200744
745 for (i = 0; i < 4; ++i) {
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200746 if ((irqstatus & (1 << i)) == 0) {
747 vcstatus[i] = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200748 continue;
Tomi Valkeinenab83b142010-06-09 15:31:01 +0300749 }
750
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530751 vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200752
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530753 dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200754 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530755 dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200756 }
757
758 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530759 ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200760
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530761 dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200762 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530763 dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200764 } else {
765 ciostatus = 0;
766 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200767
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200768#ifdef DSI_CATCH_MISSING_TE
769 if (irqstatus & DSI_IRQ_TE_TRIGGER)
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530770 del_timer(&dsi->te_timer);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200771#endif
772
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200773 /* make a copy and unlock, so that isrs can unregister
774 * themselves */
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530775 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
776 sizeof(dsi->isr_tables));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200777
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530778 spin_unlock(&dsi->irq_lock);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200779
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530780 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200781
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530782 dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200783
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530784 dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200785
archit tanejaaffe3602011-02-23 08:41:03 +0000786 return IRQ_HANDLED;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200787}
788
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530789/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530790static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
791 struct dsi_isr_data *isr_array,
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200792 unsigned isr_array_size, u32 default_mask,
793 const struct dsi_reg enable_reg,
794 const struct dsi_reg status_reg)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200795{
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200796 struct dsi_isr_data *isr_data;
797 u32 mask;
798 u32 old_mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200799 int i;
800
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200801 mask = default_mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200802
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200803 for (i = 0; i < isr_array_size; i++) {
804 isr_data = &isr_array[i];
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200805
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200806 if (isr_data->isr == NULL)
807 continue;
808
809 mask |= isr_data->mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200810 }
811
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530812 old_mask = dsi_read_reg(dsidev, enable_reg);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200813 /* clear the irqstatus for newly enabled irqs */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530814 dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
815 dsi_write_reg(dsidev, enable_reg, mask);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200816
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200817 /* flush posted writes */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530818 dsi_read_reg(dsidev, enable_reg);
819 dsi_read_reg(dsidev, status_reg);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200820}
821
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530822/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530823static void _omap_dsi_set_irqs(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200824{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530825 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200826 u32 mask = DSI_IRQ_ERROR_MASK;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200827#ifdef DSI_CATCH_MISSING_TE
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200828 mask |= DSI_IRQ_TE_TRIGGER;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200829#endif
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530830 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
831 ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200832 DSI_IRQENABLE, DSI_IRQSTATUS);
833}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200834
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530835/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530836static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200837{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530838 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
839
840 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
841 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200842 DSI_VC_IRQ_ERROR_MASK,
843 DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
844}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200845
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530846/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530847static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200848{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530849 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
850
851 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
852 ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200853 DSI_CIO_IRQ_ERROR_MASK,
854 DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
855}
856
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530857static void _dsi_initialize_irq(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200858{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530859 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200860 unsigned long flags;
861 int vc;
862
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530863 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200864
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530865 memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200866
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530867 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200868 for (vc = 0; vc < 4; ++vc)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530869 _omap_dsi_set_irqs_vc(dsidev, vc);
870 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200871
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530872 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200873}
874
875static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
876 struct dsi_isr_data *isr_array, unsigned isr_array_size)
877{
878 struct dsi_isr_data *isr_data;
879 int free_idx;
880 int i;
881
882 BUG_ON(isr == NULL);
883
884 /* check for duplicate entry and find a free slot */
885 free_idx = -1;
886 for (i = 0; i < isr_array_size; i++) {
887 isr_data = &isr_array[i];
888
889 if (isr_data->isr == isr && isr_data->arg == arg &&
890 isr_data->mask == mask) {
891 return -EINVAL;
892 }
893
894 if (isr_data->isr == NULL && free_idx == -1)
895 free_idx = i;
896 }
897
898 if (free_idx == -1)
899 return -EBUSY;
900
901 isr_data = &isr_array[free_idx];
902 isr_data->isr = isr;
903 isr_data->arg = arg;
904 isr_data->mask = mask;
905
906 return 0;
907}
908
909static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
910 struct dsi_isr_data *isr_array, unsigned isr_array_size)
911{
912 struct dsi_isr_data *isr_data;
913 int i;
914
915 for (i = 0; i < isr_array_size; i++) {
916 isr_data = &isr_array[i];
917 if (isr_data->isr != isr || isr_data->arg != arg ||
918 isr_data->mask != mask)
919 continue;
920
921 isr_data->isr = NULL;
922 isr_data->arg = NULL;
923 isr_data->mask = 0;
924
925 return 0;
926 }
927
928 return -EINVAL;
929}
930
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530931static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
932 void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200933{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530934 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200935 unsigned long flags;
936 int r;
937
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530938 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200939
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530940 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
941 ARRAY_SIZE(dsi->isr_tables.isr_table));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200942
943 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530944 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200945
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530946 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200947
948 return r;
949}
950
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530951static int dsi_unregister_isr(struct platform_device *dsidev,
952 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200953{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530954 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200955 unsigned long flags;
956 int r;
957
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530958 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200959
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530960 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
961 ARRAY_SIZE(dsi->isr_tables.isr_table));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200962
963 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530964 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200965
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530966 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200967
968 return r;
969}
970
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530971static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
972 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200973{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530974 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200975 unsigned long flags;
976 int r;
977
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530978 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200979
980 r = _dsi_register_isr(isr, arg, mask,
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530981 dsi->isr_tables.isr_table_vc[channel],
982 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200983
984 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530985 _omap_dsi_set_irqs_vc(dsidev, channel);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200986
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530987 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200988
989 return r;
990}
991
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530992static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
993 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200994{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530995 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200996 unsigned long flags;
997 int r;
998
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530999 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001000
1001 r = _dsi_unregister_isr(isr, arg, mask,
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301002 dsi->isr_tables.isr_table_vc[channel],
1003 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001004
1005 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301006 _omap_dsi_set_irqs_vc(dsidev, channel);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001007
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301008 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001009
1010 return r;
1011}
1012
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301013static int dsi_register_isr_cio(struct platform_device *dsidev,
1014 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001015{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301016 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001017 unsigned long flags;
1018 int r;
1019
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301020 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001021
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301022 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1023 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001024
1025 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301026 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001027
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301028 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001029
1030 return r;
1031}
1032
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301033static int dsi_unregister_isr_cio(struct platform_device *dsidev,
1034 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001035{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301036 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001037 unsigned long flags;
1038 int r;
1039
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301040 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001041
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301042 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1043 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001044
1045 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301046 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001047
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301048 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001049
1050 return r;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001051}
1052
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301053static u32 dsi_get_errors(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001054{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301055 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001056 unsigned long flags;
1057 u32 e;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301058 spin_lock_irqsave(&dsi->errors_lock, flags);
1059 e = dsi->errors;
1060 dsi->errors = 0;
1061 spin_unlock_irqrestore(&dsi->errors_lock, flags);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001062 return e;
1063}
1064
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001065int dsi_runtime_get(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001066{
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001067 int r;
1068 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1069
1070 DSSDBG("dsi_runtime_get\n");
1071
1072 r = pm_runtime_get_sync(&dsi->pdev->dev);
1073 WARN_ON(r < 0);
1074 return r < 0 ? r : 0;
1075}
1076
1077void dsi_runtime_put(struct platform_device *dsidev)
1078{
1079 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1080 int r;
1081
1082 DSSDBG("dsi_runtime_put\n");
1083
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +02001084 r = pm_runtime_put_sync(&dsi->pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +03001085 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001086}
1087
1088/* source clock for DSI PLL. this could also be PCLKFREE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301089static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
1090 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001091{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301092 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1093
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001094 if (enable)
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301095 clk_prepare_enable(dsi->sys_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001096 else
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301097 clk_disable_unprepare(dsi->sys_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001098
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301099 if (enable && dsi->pll_locked) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301100 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001101 DSSERR("cannot lock PLL when enabling clocks\n");
1102 }
1103}
1104
1105#ifdef DEBUG
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301106static void _dsi_print_reset_status(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001107{
1108 u32 l;
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001109 int b0, b1, b2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001110
1111 if (!dss_debug)
1112 return;
1113
1114 /* A dummy read using the SCP interface to any DSIPHY register is
1115 * required after DSIPHY reset to complete the reset of the DSI complex
1116 * I/O. */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301117 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001118
1119 printk(KERN_DEBUG "DSI resets: ");
1120
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301121 l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001122 printk("PLL (%d) ", FLD_GET(l, 0, 0));
1123
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301124 l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001125 printk("CIO (%d) ", FLD_GET(l, 29, 29));
1126
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001127 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
1128 b0 = 28;
1129 b1 = 27;
1130 b2 = 26;
1131 } else {
1132 b0 = 24;
1133 b1 = 25;
1134 b2 = 26;
1135 }
1136
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301137 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001138 printk("PHY (%x%x%x, %d, %d, %d)\n",
1139 FLD_GET(l, b0, b0),
1140 FLD_GET(l, b1, b1),
1141 FLD_GET(l, b2, b2),
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001142 FLD_GET(l, 29, 29),
1143 FLD_GET(l, 30, 30),
1144 FLD_GET(l, 31, 31));
1145}
1146#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301147#define _dsi_print_reset_status(x)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001148#endif
1149
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301150static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001151{
1152 DSSDBG("dsi_if_enable(%d)\n", enable);
1153
1154 enable = enable ? 1 : 0;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301155 REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001156
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301157 if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001158 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
1159 return -EIO;
1160 }
1161
1162 return 0;
1163}
1164
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301165unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001166{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301167 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1168
1169 return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001170}
1171
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301172static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001173{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301174 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1175
1176 return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001177}
1178
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301179static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001180{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301181 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1182
1183 return dsi->current_cinfo.clkin4ddr / 16;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001184}
1185
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301186static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001187{
1188 unsigned long r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001189 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001190
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02001191 if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
Archit Taneja1bb47832011-02-24 14:17:30 +05301192 /* DSI FCLK source is DSS_CLK_FCK */
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001193 r = clk_get_rate(dsi->dss_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001194 } else {
Archit Taneja1bb47832011-02-24 14:17:30 +05301195 /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301196 r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001197 }
1198
1199 return r;
1200}
1201
1202static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
1203{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301204 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301205 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001206 unsigned long dsi_fclk;
1207 unsigned lp_clk_div;
1208 unsigned long lp_clk;
1209
Tomi Valkeinenc6940a32011-02-22 13:36:10 +02001210 lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001211
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301212 if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001213 return -EINVAL;
1214
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301215 dsi_fclk = dsi_fclk_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001216
1217 lp_clk = dsi_fclk / 2 / lp_clk_div;
1218
1219 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301220 dsi->current_cinfo.lp_clk = lp_clk;
1221 dsi->current_cinfo.lp_clk_div = lp_clk_div;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001222
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301223 /* LP_CLK_DIVISOR */
1224 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001225
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301226 /* LP_RX_SYNCHRO_ENABLE */
1227 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001228
1229 return 0;
1230}
1231
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301232static void dsi_enable_scp_clk(struct platform_device *dsidev)
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001233{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301234 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1235
1236 if (dsi->scp_clk_refcount++ == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301237 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001238}
1239
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301240static void dsi_disable_scp_clk(struct platform_device *dsidev)
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001241{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301242 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1243
1244 WARN_ON(dsi->scp_clk_refcount == 0);
1245 if (--dsi->scp_clk_refcount == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301246 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001247}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001248
1249enum dsi_pll_power_state {
1250 DSI_PLL_POWER_OFF = 0x0,
1251 DSI_PLL_POWER_ON_HSCLK = 0x1,
1252 DSI_PLL_POWER_ON_ALL = 0x2,
1253 DSI_PLL_POWER_ON_DIV = 0x3,
1254};
1255
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301256static int dsi_pll_power(struct platform_device *dsidev,
1257 enum dsi_pll_power_state state)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001258{
1259 int t = 0;
1260
Tomi Valkeinenc94dfe052011-04-15 10:42:59 +03001261 /* DSI-PLL power command 0x3 is not working */
1262 if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
1263 state == DSI_PLL_POWER_ON_DIV)
1264 state = DSI_PLL_POWER_ON_ALL;
1265
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301266 /* PLL_PWR_CMD */
1267 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001268
1269 /* PLL_PWR_STATUS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301270 while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001271 if (++t > 1000) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001272 DSSERR("Failed to set DSI PLL power mode to %d\n",
1273 state);
1274 return -ENODEV;
1275 }
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001276 udelay(1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001277 }
1278
1279 return 0;
1280}
1281
1282/* calculate clock rates using dividers in cinfo */
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001283static int dsi_calc_clock_rates(struct platform_device *dsidev,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001284 struct dsi_clock_info *cinfo)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001285{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301286 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1287
1288 if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001289 return -EINVAL;
1290
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301291 if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001292 return -EINVAL;
1293
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301294 if (cinfo->regm_dispc > dsi->regm_dispc_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001295 return -EINVAL;
1296
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301297 if (cinfo->regm_dsi > dsi->regm_dsi_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001298 return -EINVAL;
1299
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001300 cinfo->clkin = clk_get_rate(dsi->sys_clk);
1301 cinfo->fint = cinfo->clkin / cinfo->regn;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001302
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301303 if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001304 return -EINVAL;
1305
1306 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
1307
1308 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
1309 return -EINVAL;
1310
Archit Taneja1bb47832011-02-24 14:17:30 +05301311 if (cinfo->regm_dispc > 0)
1312 cinfo->dsi_pll_hsdiv_dispc_clk =
1313 cinfo->clkin4ddr / cinfo->regm_dispc;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001314 else
Archit Taneja1bb47832011-02-24 14:17:30 +05301315 cinfo->dsi_pll_hsdiv_dispc_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001316
Archit Taneja1bb47832011-02-24 14:17:30 +05301317 if (cinfo->regm_dsi > 0)
1318 cinfo->dsi_pll_hsdiv_dsi_clk =
1319 cinfo->clkin4ddr / cinfo->regm_dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001320 else
Archit Taneja1bb47832011-02-24 14:17:30 +05301321 cinfo->dsi_pll_hsdiv_dsi_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001322
1323 return 0;
1324}
1325
Archit Taneja6d523e72012-06-21 09:33:55 +05301326int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301327 unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001328 struct dispc_clock_info *dispc_cinfo)
1329{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301330 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001331 struct dsi_clock_info cur, best;
1332 struct dispc_clock_info best_dispc;
1333 int min_fck_per_pck;
1334 int match = 0;
Archit Taneja1bb47832011-02-24 14:17:30 +05301335 unsigned long dss_sys_clk, max_dss_fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001336
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001337 dss_sys_clk = clk_get_rate(dsi->sys_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001338
Taneja, Archit31ef8232011-03-14 23:28:22 -05001339 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
Archit Taneja819d8072011-03-01 11:54:00 +05301340
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301341 if (req_pck == dsi->cache_req_pck &&
1342 dsi->cache_cinfo.clkin == dss_sys_clk) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001343 DSSDBG("DSI clock info found from cache\n");
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301344 *dsi_cinfo = dsi->cache_cinfo;
Archit Taneja6d523e72012-06-21 09:33:55 +05301345 dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk,
1346 dispc_cinfo);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001347 return 0;
1348 }
1349
1350 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
1351
1352 if (min_fck_per_pck &&
Archit Taneja819d8072011-03-01 11:54:00 +05301353 req_pck * min_fck_per_pck > max_dss_fck) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001354 DSSERR("Requested pixel clock not possible with the current "
1355 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
1356 "the constraint off.\n");
1357 min_fck_per_pck = 0;
1358 }
1359
1360 DSSDBG("dsi_pll_calc\n");
1361
1362retry:
1363 memset(&best, 0, sizeof(best));
1364 memset(&best_dispc, 0, sizeof(best_dispc));
1365
1366 memset(&cur, 0, sizeof(cur));
Archit Taneja1bb47832011-02-24 14:17:30 +05301367 cur.clkin = dss_sys_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001368
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001369 /* 0.75MHz < Fint = clkin / regn < 2.1MHz */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001370 /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301371 for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001372 cur.fint = cur.clkin / cur.regn;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001373
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301374 if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001375 continue;
1376
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001377 /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301378 for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001379 unsigned long a, b;
1380
1381 a = 2 * cur.regm * (cur.clkin/1000);
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001382 b = cur.regn;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001383 cur.clkin4ddr = a / b * 1000;
1384
1385 if (cur.clkin4ddr > 1800 * 1000 * 1000)
1386 break;
1387
Archit Taneja1bb47832011-02-24 14:17:30 +05301388 /* dsi_pll_hsdiv_dispc_clk(MHz) =
1389 * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301390 for (cur.regm_dispc = 1; cur.regm_dispc <
1391 dsi->regm_dispc_max; ++cur.regm_dispc) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001392 struct dispc_clock_info cur_dispc;
Archit Taneja1bb47832011-02-24 14:17:30 +05301393 cur.dsi_pll_hsdiv_dispc_clk =
1394 cur.clkin4ddr / cur.regm_dispc;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001395
1396 /* this will narrow down the search a bit,
1397 * but still give pixclocks below what was
1398 * requested */
Archit Taneja1bb47832011-02-24 14:17:30 +05301399 if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001400 break;
1401
Archit Taneja1bb47832011-02-24 14:17:30 +05301402 if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001403 continue;
1404
1405 if (min_fck_per_pck &&
Archit Taneja1bb47832011-02-24 14:17:30 +05301406 cur.dsi_pll_hsdiv_dispc_clk <
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001407 req_pck * min_fck_per_pck)
1408 continue;
1409
1410 match = 1;
1411
Archit Taneja6d523e72012-06-21 09:33:55 +05301412 dispc_find_clk_divs(req_pck,
Archit Taneja1bb47832011-02-24 14:17:30 +05301413 cur.dsi_pll_hsdiv_dispc_clk,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001414 &cur_dispc);
1415
1416 if (abs(cur_dispc.pck - req_pck) <
1417 abs(best_dispc.pck - req_pck)) {
1418 best = cur;
1419 best_dispc = cur_dispc;
1420
1421 if (cur_dispc.pck == req_pck)
1422 goto found;
1423 }
1424 }
1425 }
1426 }
1427found:
1428 if (!match) {
1429 if (min_fck_per_pck) {
1430 DSSERR("Could not find suitable clock settings.\n"
1431 "Turning FCK/PCK constraint off and"
1432 "trying again.\n");
1433 min_fck_per_pck = 0;
1434 goto retry;
1435 }
1436
1437 DSSERR("Could not find suitable clock settings.\n");
1438
1439 return -EINVAL;
1440 }
1441
Archit Taneja1bb47832011-02-24 14:17:30 +05301442 /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
1443 best.regm_dsi = 0;
1444 best.dsi_pll_hsdiv_dsi_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001445
1446 if (dsi_cinfo)
1447 *dsi_cinfo = best;
1448 if (dispc_cinfo)
1449 *dispc_cinfo = best_dispc;
1450
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301451 dsi->cache_req_pck = req_pck;
1452 dsi->cache_clk_freq = 0;
1453 dsi->cache_cinfo = best;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001454
1455 return 0;
1456}
1457
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001458static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
Tomi Valkeinend66b1582012-09-24 15:15:06 +03001459 unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001460{
1461 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1462 struct dsi_clock_info cur, best;
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001463
1464 DSSDBG("dsi_pll_calc_ddrfreq\n");
1465
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001466 memset(&best, 0, sizeof(best));
1467 memset(&cur, 0, sizeof(cur));
1468
Tomi Valkeinend66b1582012-09-24 15:15:06 +03001469 cur.clkin = clk_get_rate(dsi->sys_clk);
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001470
1471 for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
1472 cur.fint = cur.clkin / cur.regn;
1473
1474 if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
1475 continue;
1476
1477 /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
1478 for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
1479 unsigned long a, b;
1480
1481 a = 2 * cur.regm * (cur.clkin/1000);
1482 b = cur.regn;
1483 cur.clkin4ddr = a / b * 1000;
1484
1485 if (cur.clkin4ddr > 1800 * 1000 * 1000)
1486 break;
1487
1488 if (abs(cur.clkin4ddr - req_clkin4ddr) <
1489 abs(best.clkin4ddr - req_clkin4ddr)) {
1490 best = cur;
1491 DSSDBG("best %ld\n", best.clkin4ddr);
1492 }
1493
1494 if (cur.clkin4ddr == req_clkin4ddr)
1495 goto found;
1496 }
1497 }
1498found:
Tomi Valkeinenee144e62012-08-10 16:50:51 +03001499 if (cinfo)
1500 *cinfo = best;
1501
1502 return 0;
1503}
1504
Tomi Valkeinend66b1582012-09-24 15:15:06 +03001505static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
1506 struct dsi_clock_info *cinfo)
1507{
1508 unsigned long max_dsi_fck;
1509
1510 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
1511
1512 cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
1513 cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
1514}
1515
1516static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
1517 unsigned long req_pck, struct dsi_clock_info *cinfo,
1518 struct dispc_clock_info *dispc_cinfo)
1519{
1520 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1521 unsigned regm_dispc, best_regm_dispc;
1522 unsigned long dispc_clk, best_dispc_clk;
1523 int min_fck_per_pck;
1524 unsigned long max_dss_fck;
1525 struct dispc_clock_info best_dispc;
1526 bool match;
1527
1528 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
1529
1530 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
1531
1532 if (min_fck_per_pck &&
1533 req_pck * min_fck_per_pck > max_dss_fck) {
1534 DSSERR("Requested pixel clock not possible with the current "
1535 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
1536 "the constraint off.\n");
1537 min_fck_per_pck = 0;
1538 }
1539
1540retry:
1541 best_regm_dispc = 0;
1542 best_dispc_clk = 0;
1543 memset(&best_dispc, 0, sizeof(best_dispc));
1544 match = false;
1545
1546 for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
1547 struct dispc_clock_info cur_dispc;
1548
1549 dispc_clk = cinfo->clkin4ddr / regm_dispc;
1550
1551 /* this will narrow down the search a bit,
1552 * but still give pixclocks below what was
1553 * requested */
1554 if (dispc_clk < req_pck)
1555 break;
1556
1557 if (dispc_clk > max_dss_fck)
1558 continue;
1559
1560 if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
1561 continue;
1562
1563 match = true;
1564
1565 dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
1566
1567 if (abs(cur_dispc.pck - req_pck) <
1568 abs(best_dispc.pck - req_pck)) {
1569 best_regm_dispc = regm_dispc;
1570 best_dispc_clk = dispc_clk;
1571 best_dispc = cur_dispc;
1572
1573 if (cur_dispc.pck == req_pck)
1574 goto found;
1575 }
1576 }
1577
1578 if (!match) {
1579 if (min_fck_per_pck) {
1580 DSSERR("Could not find suitable clock settings.\n"
1581 "Turning FCK/PCK constraint off and"
1582 "trying again.\n");
1583 min_fck_per_pck = 0;
1584 goto retry;
1585 }
1586
1587 DSSERR("Could not find suitable clock settings.\n");
1588
1589 return -EINVAL;
1590 }
1591found:
1592 cinfo->regm_dispc = best_regm_dispc;
1593 cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
1594
1595 *dispc_cinfo = best_dispc;
1596
1597 return 0;
1598}
1599
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301600int dsi_pll_set_clock_div(struct platform_device *dsidev,
1601 struct dsi_clock_info *cinfo)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001602{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301603 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001604 int r = 0;
1605 u32 l;
Archit Taneja9613c022011-03-22 06:33:36 -05001606 int f = 0;
Taneja, Archit49641112011-03-14 23:28:23 -05001607 u8 regn_start, regn_end, regm_start, regm_end;
1608 u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001609
1610 DSSDBGF();
1611
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001612 dsi->current_cinfo.clkin = cinfo->clkin;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301613 dsi->current_cinfo.fint = cinfo->fint;
1614 dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
1615 dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
Archit Taneja1bb47832011-02-24 14:17:30 +05301616 cinfo->dsi_pll_hsdiv_dispc_clk;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301617 dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
Archit Taneja1bb47832011-02-24 14:17:30 +05301618 cinfo->dsi_pll_hsdiv_dsi_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001619
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301620 dsi->current_cinfo.regn = cinfo->regn;
1621 dsi->current_cinfo.regm = cinfo->regm;
1622 dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
1623 dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001624
1625 DSSDBG("DSI Fint %ld\n", cinfo->fint);
1626
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001627 DSSDBG("clkin rate %ld\n", cinfo->clkin);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001628
1629 /* DSIPHY == CLKIN4DDR */
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001630 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001631 cinfo->regm,
1632 cinfo->regn,
1633 cinfo->clkin,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001634 cinfo->clkin4ddr);
1635
1636 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
1637 cinfo->clkin4ddr / 1000 / 1000 / 2);
1638
1639 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1640
Archit Taneja1bb47832011-02-24 14:17:30 +05301641 DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
Archit Taneja89a35e52011-04-12 13:52:23 +05301642 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
1643 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
Archit Taneja1bb47832011-02-24 14:17:30 +05301644 cinfo->dsi_pll_hsdiv_dispc_clk);
1645 DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
Archit Taneja89a35e52011-04-12 13:52:23 +05301646 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
1647 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
Archit Taneja1bb47832011-02-24 14:17:30 +05301648 cinfo->dsi_pll_hsdiv_dsi_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001649
Taneja, Archit49641112011-03-14 23:28:23 -05001650 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
1651 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
1652 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
1653 &regm_dispc_end);
1654 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
1655 &regm_dsi_end);
1656
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301657 /* DSI_PLL_AUTOMODE = manual */
1658 REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001659
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301660 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001661 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
Taneja, Archit49641112011-03-14 23:28:23 -05001662 /* DSI_PLL_REGN */
1663 l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
1664 /* DSI_PLL_REGM */
1665 l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
1666 /* DSI_CLOCK_DIV */
Archit Taneja1bb47832011-02-24 14:17:30 +05301667 l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
Taneja, Archit49641112011-03-14 23:28:23 -05001668 regm_dispc_start, regm_dispc_end);
1669 /* DSIPROTO_CLOCK_DIV */
Archit Taneja1bb47832011-02-24 14:17:30 +05301670 l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
Taneja, Archit49641112011-03-14 23:28:23 -05001671 regm_dsi_start, regm_dsi_end);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301672 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001673
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301674 BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
Archit Taneja9613c022011-03-22 06:33:36 -05001675
Tomi Valkeinenf8ef3d62012-08-22 16:00:31 +03001676 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
1677
Archit Taneja9613c022011-03-22 06:33:36 -05001678 if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
1679 f = cinfo->fint < 1000000 ? 0x3 :
1680 cinfo->fint < 1250000 ? 0x4 :
1681 cinfo->fint < 1500000 ? 0x5 :
1682 cinfo->fint < 1750000 ? 0x6 :
1683 0x7;
Tomi Valkeinenf8ef3d62012-08-22 16:00:31 +03001684
1685 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
1686 } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
1687 f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
1688
1689 l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
Archit Taneja9613c022011-03-22 06:33:36 -05001690 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001691
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001692 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1693 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1694 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
Tomi Valkeinen6d446102012-08-22 16:00:40 +03001695 if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
1696 l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301697 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001698
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301699 REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001700
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301701 if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001702 DSSERR("dsi pll go bit not going down.\n");
1703 r = -EIO;
1704 goto err;
1705 }
1706
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301707 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001708 DSSERR("cannot lock PLL\n");
1709 r = -EIO;
1710 goto err;
1711 }
1712
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301713 dsi->pll_locked = 1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001714
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301715 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001716 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1717 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1718 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1719 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1720 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1721 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1722 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1723 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1724 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1725 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1726 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1727 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1728 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1729 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301730 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001731
1732 DSSDBG("PLL config done\n");
1733err:
1734 return r;
1735}
1736
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301737int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
1738 bool enable_hsdiv)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001739{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301740 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001741 int r = 0;
1742 enum dsi_pll_power_state pwstate;
1743
1744 DSSDBG("PLL init\n");
1745
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301746 if (dsi->vdds_dsi_reg == NULL) {
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001747 struct regulator *vdds_dsi;
1748
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301749 vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001750
1751 if (IS_ERR(vdds_dsi)) {
1752 DSSERR("can't get VDDS_DSI regulator\n");
1753 return PTR_ERR(vdds_dsi);
1754 }
1755
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301756 dsi->vdds_dsi_reg = vdds_dsi;
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001757 }
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001758
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301759 dsi_enable_pll_clock(dsidev, 1);
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001760 /*
1761 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
1762 */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301763 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001764
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301765 if (!dsi->vdds_dsi_enabled) {
1766 r = regulator_enable(dsi->vdds_dsi_reg);
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001767 if (r)
1768 goto err0;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301769 dsi->vdds_dsi_enabled = true;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001770 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001771
1772 /* XXX PLL does not come out of reset without this... */
1773 dispc_pck_free_enable(1);
1774
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301775 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001776 DSSERR("PLL not coming out of reset.\n");
1777 r = -ENODEV;
Ville Syrjälä481dfa02010-04-22 22:50:04 +02001778 dispc_pck_free_enable(0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001779 goto err1;
1780 }
1781
1782 /* XXX ... but if left on, we get problems when planes do not
1783 * fill the whole display. No idea about this */
1784 dispc_pck_free_enable(0);
1785
1786 if (enable_hsclk && enable_hsdiv)
1787 pwstate = DSI_PLL_POWER_ON_ALL;
1788 else if (enable_hsclk)
1789 pwstate = DSI_PLL_POWER_ON_HSCLK;
1790 else if (enable_hsdiv)
1791 pwstate = DSI_PLL_POWER_ON_DIV;
1792 else
1793 pwstate = DSI_PLL_POWER_OFF;
1794
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301795 r = dsi_pll_power(dsidev, pwstate);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001796
1797 if (r)
1798 goto err1;
1799
1800 DSSDBG("PLL init done\n");
1801
1802 return 0;
1803err1:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301804 if (dsi->vdds_dsi_enabled) {
1805 regulator_disable(dsi->vdds_dsi_reg);
1806 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001807 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001808err0:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301809 dsi_disable_scp_clk(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301810 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001811 return r;
1812}
1813
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301814void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001815{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301816 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1817
1818 dsi->pll_locked = 0;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301819 dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001820 if (disconnect_lanes) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301821 WARN_ON(!dsi->vdds_dsi_enabled);
1822 regulator_disable(dsi->vdds_dsi_reg);
1823 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001824 }
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001825
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301826 dsi_disable_scp_clk(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301827 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001828
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001829 DSSDBG("PLL uninit done\n");
1830}
1831
Archit Taneja5a8b5722011-05-12 17:26:29 +05301832static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
1833 struct seq_file *s)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001834{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301835 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1836 struct dsi_clock_info *cinfo = &dsi->current_cinfo;
Archit Taneja89a35e52011-04-12 13:52:23 +05301837 enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02001838 int dsi_module = dsi->module_id;
Archit Taneja067a57e2011-03-02 11:57:25 +05301839
1840 dispc_clk_src = dss_get_dispc_clk_source();
Archit Taneja5a8b5722011-05-12 17:26:29 +05301841 dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001842
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001843 if (dsi_runtime_get(dsidev))
1844 return;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001845
Archit Taneja5a8b5722011-05-12 17:26:29 +05301846 seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001847
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02001848 seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001849
1850 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1851
1852 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1853 cinfo->clkin4ddr, cinfo->regm);
1854
Archit Taneja84309f12011-12-12 11:47:41 +05301855 seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
1856 dss_feat_get_clk_source_name(dsi_module == 0 ?
1857 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
1858 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
Archit Taneja1bb47832011-02-24 14:17:30 +05301859 cinfo->dsi_pll_hsdiv_dispc_clk,
1860 cinfo->regm_dispc,
Archit Taneja89a35e52011-04-12 13:52:23 +05301861 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
Tomi Valkeinen63cf28a2010-02-23 17:40:00 +02001862 "off" : "on");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001863
Archit Taneja84309f12011-12-12 11:47:41 +05301864 seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
1865 dss_feat_get_clk_source_name(dsi_module == 0 ?
1866 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
1867 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
Archit Taneja1bb47832011-02-24 14:17:30 +05301868 cinfo->dsi_pll_hsdiv_dsi_clk,
1869 cinfo->regm_dsi,
Archit Taneja89a35e52011-04-12 13:52:23 +05301870 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
Tomi Valkeinen63cf28a2010-02-23 17:40:00 +02001871 "off" : "on");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001872
Archit Taneja5a8b5722011-05-12 17:26:29 +05301873 seq_printf(s, "- DSI%d -\n", dsi_module + 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001874
Archit Taneja067a57e2011-03-02 11:57:25 +05301875 seq_printf(s, "dsi fclk source = %s (%s)\n",
1876 dss_get_generic_clk_source_name(dsi_clk_src),
1877 dss_feat_get_clk_source_name(dsi_clk_src));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001878
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301879 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001880
1881 seq_printf(s, "DDR_CLK\t\t%lu\n",
1882 cinfo->clkin4ddr / 4);
1883
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301884 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001885
1886 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1887
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001888 dsi_runtime_put(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001889}
1890
Archit Taneja5a8b5722011-05-12 17:26:29 +05301891void dsi_dump_clocks(struct seq_file *s)
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001892{
Archit Taneja5a8b5722011-05-12 17:26:29 +05301893 struct platform_device *dsidev;
1894 int i;
1895
1896 for (i = 0; i < MAX_NUM_DSI; i++) {
1897 dsidev = dsi_get_dsidev_from_id(i);
1898 if (dsidev)
1899 dsi_dump_dsidev_clocks(dsidev, s);
1900 }
1901}
1902
1903#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1904static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
1905 struct seq_file *s)
1906{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301907 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001908 unsigned long flags;
1909 struct dsi_irq_stats stats;
1910
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301911 spin_lock_irqsave(&dsi->irq_stats_lock, flags);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001912
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301913 stats = dsi->irq_stats;
1914 memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
1915 dsi->irq_stats.last_reset = jiffies;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001916
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301917 spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001918
1919 seq_printf(s, "period %u ms\n",
1920 jiffies_to_msecs(jiffies - stats.last_reset));
1921
1922 seq_printf(s, "irqs %d\n", stats.irq_count);
1923#define PIS(x) \
1924 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1925
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02001926 seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001927 PIS(VC0);
1928 PIS(VC1);
1929 PIS(VC2);
1930 PIS(VC3);
1931 PIS(WAKEUP);
1932 PIS(RESYNC);
1933 PIS(PLL_LOCK);
1934 PIS(PLL_UNLOCK);
1935 PIS(PLL_RECALL);
1936 PIS(COMPLEXIO_ERR);
1937 PIS(HS_TX_TIMEOUT);
1938 PIS(LP_RX_TIMEOUT);
1939 PIS(TE_TRIGGER);
1940 PIS(ACK_TRIGGER);
1941 PIS(SYNC_LOST);
1942 PIS(LDO_POWER_GOOD);
1943 PIS(TA_TIMEOUT);
1944#undef PIS
1945
1946#define PIS(x) \
1947 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1948 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1949 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1950 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1951 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1952
1953 seq_printf(s, "-- VC interrupts --\n");
1954 PIS(CS);
1955 PIS(ECC_CORR);
1956 PIS(PACKET_SENT);
1957 PIS(FIFO_TX_OVF);
1958 PIS(FIFO_RX_OVF);
1959 PIS(BTA);
1960 PIS(ECC_NO_CORR);
1961 PIS(FIFO_TX_UDF);
1962 PIS(PP_BUSY_CHANGE);
1963#undef PIS
1964
1965#define PIS(x) \
1966 seq_printf(s, "%-20s %10d\n", #x, \
1967 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1968
1969 seq_printf(s, "-- CIO interrupts --\n");
1970 PIS(ERRSYNCESC1);
1971 PIS(ERRSYNCESC2);
1972 PIS(ERRSYNCESC3);
1973 PIS(ERRESC1);
1974 PIS(ERRESC2);
1975 PIS(ERRESC3);
1976 PIS(ERRCONTROL1);
1977 PIS(ERRCONTROL2);
1978 PIS(ERRCONTROL3);
1979 PIS(STATEULPS1);
1980 PIS(STATEULPS2);
1981 PIS(STATEULPS3);
1982 PIS(ERRCONTENTIONLP0_1);
1983 PIS(ERRCONTENTIONLP1_1);
1984 PIS(ERRCONTENTIONLP0_2);
1985 PIS(ERRCONTENTIONLP1_2);
1986 PIS(ERRCONTENTIONLP0_3);
1987 PIS(ERRCONTENTIONLP1_3);
1988 PIS(ULPSACTIVENOT_ALL0);
1989 PIS(ULPSACTIVENOT_ALL1);
1990#undef PIS
1991}
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001992
Archit Taneja5a8b5722011-05-12 17:26:29 +05301993static void dsi1_dump_irqs(struct seq_file *s)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001994{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301995 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1996
Archit Taneja5a8b5722011-05-12 17:26:29 +05301997 dsi_dump_dsidev_irqs(dsidev, s);
1998}
1999
2000static void dsi2_dump_irqs(struct seq_file *s)
2001{
2002 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
2003
2004 dsi_dump_dsidev_irqs(dsidev, s);
2005}
Archit Taneja5a8b5722011-05-12 17:26:29 +05302006#endif
2007
2008static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
2009 struct seq_file *s)
2010{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302011#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002012
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002013 if (dsi_runtime_get(dsidev))
2014 return;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302015 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002016
2017 DUMPREG(DSI_REVISION);
2018 DUMPREG(DSI_SYSCONFIG);
2019 DUMPREG(DSI_SYSSTATUS);
2020 DUMPREG(DSI_IRQSTATUS);
2021 DUMPREG(DSI_IRQENABLE);
2022 DUMPREG(DSI_CTRL);
2023 DUMPREG(DSI_COMPLEXIO_CFG1);
2024 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
2025 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
2026 DUMPREG(DSI_CLK_CTRL);
2027 DUMPREG(DSI_TIMING1);
2028 DUMPREG(DSI_TIMING2);
2029 DUMPREG(DSI_VM_TIMING1);
2030 DUMPREG(DSI_VM_TIMING2);
2031 DUMPREG(DSI_VM_TIMING3);
2032 DUMPREG(DSI_CLK_TIMING);
2033 DUMPREG(DSI_TX_FIFO_VC_SIZE);
2034 DUMPREG(DSI_RX_FIFO_VC_SIZE);
2035 DUMPREG(DSI_COMPLEXIO_CFG2);
2036 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
2037 DUMPREG(DSI_VM_TIMING4);
2038 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
2039 DUMPREG(DSI_VM_TIMING5);
2040 DUMPREG(DSI_VM_TIMING6);
2041 DUMPREG(DSI_VM_TIMING7);
2042 DUMPREG(DSI_STOPCLK_TIMING);
2043
2044 DUMPREG(DSI_VC_CTRL(0));
2045 DUMPREG(DSI_VC_TE(0));
2046 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
2047 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
2048 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
2049 DUMPREG(DSI_VC_IRQSTATUS(0));
2050 DUMPREG(DSI_VC_IRQENABLE(0));
2051
2052 DUMPREG(DSI_VC_CTRL(1));
2053 DUMPREG(DSI_VC_TE(1));
2054 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
2055 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
2056 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
2057 DUMPREG(DSI_VC_IRQSTATUS(1));
2058 DUMPREG(DSI_VC_IRQENABLE(1));
2059
2060 DUMPREG(DSI_VC_CTRL(2));
2061 DUMPREG(DSI_VC_TE(2));
2062 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
2063 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
2064 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
2065 DUMPREG(DSI_VC_IRQSTATUS(2));
2066 DUMPREG(DSI_VC_IRQENABLE(2));
2067
2068 DUMPREG(DSI_VC_CTRL(3));
2069 DUMPREG(DSI_VC_TE(3));
2070 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
2071 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
2072 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
2073 DUMPREG(DSI_VC_IRQSTATUS(3));
2074 DUMPREG(DSI_VC_IRQENABLE(3));
2075
2076 DUMPREG(DSI_DSIPHY_CFG0);
2077 DUMPREG(DSI_DSIPHY_CFG1);
2078 DUMPREG(DSI_DSIPHY_CFG2);
2079 DUMPREG(DSI_DSIPHY_CFG5);
2080
2081 DUMPREG(DSI_PLL_CONTROL);
2082 DUMPREG(DSI_PLL_STATUS);
2083 DUMPREG(DSI_PLL_GO);
2084 DUMPREG(DSI_PLL_CONFIGURATION1);
2085 DUMPREG(DSI_PLL_CONFIGURATION2);
2086
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302087 dsi_disable_scp_clk(dsidev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002088 dsi_runtime_put(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002089#undef DUMPREG
2090}
2091
Archit Taneja5a8b5722011-05-12 17:26:29 +05302092static void dsi1_dump_regs(struct seq_file *s)
2093{
2094 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
2095
2096 dsi_dump_dsidev_regs(dsidev, s);
2097}
2098
2099static void dsi2_dump_regs(struct seq_file *s)
2100{
2101 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
2102
2103 dsi_dump_dsidev_regs(dsidev, s);
2104}
2105
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002106enum dsi_cio_power_state {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002107 DSI_COMPLEXIO_POWER_OFF = 0x0,
2108 DSI_COMPLEXIO_POWER_ON = 0x1,
2109 DSI_COMPLEXIO_POWER_ULPS = 0x2,
2110};
2111
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302112static int dsi_cio_power(struct platform_device *dsidev,
2113 enum dsi_cio_power_state state)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002114{
2115 int t = 0;
2116
2117 /* PWR_CMD */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302118 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002119
2120 /* PWR_STATUS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302121 while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
2122 26, 25) != state) {
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02002123 if (++t > 1000) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002124 DSSERR("failed to set complexio power state to "
2125 "%d\n", state);
2126 return -ENODEV;
2127 }
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02002128 udelay(1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002129 }
2130
2131 return 0;
2132}
2133
Archit Taneja0c656222011-05-16 15:17:09 +05302134static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
2135{
2136 int val;
2137
2138 /* line buffer on OMAP3 is 1024 x 24bits */
2139 /* XXX: for some reason using full buffer size causes
2140 * considerable TX slowdown with update sizes that fill the
2141 * whole buffer */
2142 if (!dss_has_feature(FEAT_DSI_GNQ))
2143 return 1023 * 3;
2144
2145 val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
2146
2147 switch (val) {
2148 case 1:
2149 return 512 * 3; /* 512x24 bits */
2150 case 2:
2151 return 682 * 3; /* 682x24 bits */
2152 case 3:
2153 return 853 * 3; /* 853x24 bits */
2154 case 4:
2155 return 1024 * 3; /* 1024x24 bits */
2156 case 5:
2157 return 1194 * 3; /* 1194x24 bits */
2158 case 6:
2159 return 1365 * 3; /* 1365x24 bits */
Tomi Valkeinen2ac80fb2012-08-22 16:00:47 +03002160 case 7:
2161 return 1920 * 3; /* 1920x24 bits */
Archit Taneja0c656222011-05-16 15:17:09 +05302162 default:
2163 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002164 return 0;
Archit Taneja0c656222011-05-16 15:17:09 +05302165 }
2166}
2167
Archit Taneja9e7e9372012-08-14 12:29:22 +05302168static int dsi_set_lane_config(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002169{
Tomi Valkeinen48368392011-10-13 11:22:39 +03002170 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2171 static const u8 offsets[] = { 0, 4, 8, 12, 16 };
2172 static const enum dsi_lane_function functions[] = {
2173 DSI_LANE_CLK,
2174 DSI_LANE_DATA1,
2175 DSI_LANE_DATA2,
2176 DSI_LANE_DATA3,
2177 DSI_LANE_DATA4,
2178 };
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002179 u32 r;
Tomi Valkeinen48368392011-10-13 11:22:39 +03002180 int i;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002181
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302182 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
Archit Taneja75d72472011-05-16 15:17:08 +05302183
Tomi Valkeinen48368392011-10-13 11:22:39 +03002184 for (i = 0; i < dsi->num_lanes_used; ++i) {
2185 unsigned offset = offsets[i];
2186 unsigned polarity, lane_number;
2187 unsigned t;
Archit Taneja75d72472011-05-16 15:17:08 +05302188
Tomi Valkeinen48368392011-10-13 11:22:39 +03002189 for (t = 0; t < dsi->num_lanes_supported; ++t)
2190 if (dsi->lanes[t].function == functions[i])
2191 break;
2192
2193 if (t == dsi->num_lanes_supported)
2194 return -EINVAL;
2195
2196 lane_number = t;
2197 polarity = dsi->lanes[t].polarity;
2198
2199 r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
2200 r = FLD_MOD(r, polarity, offset + 3, offset + 3);
Archit Taneja75d72472011-05-16 15:17:08 +05302201 }
Tomi Valkeinen48368392011-10-13 11:22:39 +03002202
2203 /* clear the unused lanes */
2204 for (; i < dsi->num_lanes_supported; ++i) {
2205 unsigned offset = offsets[i];
2206
2207 r = FLD_MOD(r, 0, offset + 2, offset);
2208 r = FLD_MOD(r, 0, offset + 3, offset + 3);
2209 }
2210
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302211 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002212
Tomi Valkeinen48368392011-10-13 11:22:39 +03002213 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002214}
2215
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302216static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002217{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302218 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2219
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002220 /* convert time in ns to ddr ticks, rounding up */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302221 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002222 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
2223}
2224
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302225static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002226{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302227 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2228
2229 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002230 return ddr * 1000 * 1000 / (ddr_clk / 1000);
2231}
2232
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302233static void dsi_cio_timings(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002234{
2235 u32 r;
2236 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
2237 u32 tlpx_half, tclk_trail, tclk_zero;
2238 u32 tclk_prepare;
2239
2240 /* calculate timings */
2241
2242 /* 1 * DDR_CLK = 2 * UI */
2243
2244 /* min 40ns + 4*UI max 85ns + 6*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302245 ths_prepare = ns2ddr(dsidev, 70) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002246
2247 /* min 145ns + 10*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302248 ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002249
2250 /* min max(8*UI, 60ns+4*UI) */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302251 ths_trail = ns2ddr(dsidev, 60) + 5;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002252
2253 /* min 100ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302254 ths_exit = ns2ddr(dsidev, 145);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002255
2256 /* tlpx min 50n */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302257 tlpx_half = ns2ddr(dsidev, 25);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002258
2259 /* min 60ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302260 tclk_trail = ns2ddr(dsidev, 60) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002261
2262 /* min 38ns, max 95ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302263 tclk_prepare = ns2ddr(dsidev, 65);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002264
2265 /* min tclk-prepare + tclk-zero = 300ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302266 tclk_zero = ns2ddr(dsidev, 260);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002267
2268 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302269 ths_prepare, ddr2ns(dsidev, ths_prepare),
2270 ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002271 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302272 ths_trail, ddr2ns(dsidev, ths_trail),
2273 ths_exit, ddr2ns(dsidev, ths_exit));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002274
2275 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
2276 "tclk_zero %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302277 tlpx_half, ddr2ns(dsidev, tlpx_half),
2278 tclk_trail, ddr2ns(dsidev, tclk_trail),
2279 tclk_zero, ddr2ns(dsidev, tclk_zero));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002280 DSSDBG("tclk_prepare %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302281 tclk_prepare, ddr2ns(dsidev, tclk_prepare));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002282
2283 /* program timings */
2284
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302285 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002286 r = FLD_MOD(r, ths_prepare, 31, 24);
2287 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
2288 r = FLD_MOD(r, ths_trail, 15, 8);
2289 r = FLD_MOD(r, ths_exit, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302290 dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002291
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302292 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
Tomi Valkeinene84dc1c2012-09-24 09:34:52 +03002293 r = FLD_MOD(r, tlpx_half, 20, 16);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002294 r = FLD_MOD(r, tclk_trail, 15, 8);
2295 r = FLD_MOD(r, tclk_zero, 7, 0);
Tomi Valkeinen77ccbfb2012-09-24 15:15:57 +03002296
2297 if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
2298 r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
2299 r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
2300 r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
2301 }
2302
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302303 dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002304
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302305 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002306 r = FLD_MOD(r, tclk_prepare, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302307 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002308}
2309
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002310/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
Archit Taneja9e7e9372012-08-14 12:29:22 +05302311static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002312 unsigned mask_p, unsigned mask_n)
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002313{
Archit Taneja75d72472011-05-16 15:17:08 +05302314 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002315 int i;
2316 u32 l;
Tomi Valkeinend9820852011-10-12 15:05:59 +03002317 u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002318
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002319 l = 0;
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002320
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002321 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2322 unsigned p = dsi->lanes[i].polarity;
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002323
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002324 if (mask_p & (1 << i))
2325 l |= 1 << (i * 2 + (p ? 0 : 1));
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002326
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002327 if (mask_n & (1 << i))
2328 l |= 1 << (i * 2 + (p ? 1 : 0));
2329 }
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002330
2331 /*
2332 * Bits in REGLPTXSCPDAT4TO0DXDY:
2333 * 17: DY0 18: DX0
2334 * 19: DY1 20: DX1
2335 * 21: DY2 22: DX2
Archit Taneja75d72472011-05-16 15:17:08 +05302336 * 23: DY3 24: DX3
2337 * 25: DY4 26: DX4
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002338 */
2339
2340 /* Set the lane override configuration */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302341
2342 /* REGLPTXSCPDAT4TO0DXDY */
Archit Taneja75d72472011-05-16 15:17:08 +05302343 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002344
2345 /* Enable lane override */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302346
2347 /* ENLPTXSCPDAT */
2348 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002349}
2350
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302351static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002352{
2353 /* Disable lane override */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302354 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002355 /* Reset the lane override configuration */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302356 /* REGLPTXSCPDAT4TO0DXDY */
2357 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002358}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002359
Archit Taneja9e7e9372012-08-14 12:29:22 +05302360static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002361{
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002362 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2363 int t, i;
2364 bool in_use[DSI_MAX_NR_LANES];
2365 static const u8 offsets_old[] = { 28, 27, 26 };
2366 static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
2367 const u8 *offsets;
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002368
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002369 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
2370 offsets = offsets_old;
2371 else
2372 offsets = offsets_new;
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002373
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002374 for (i = 0; i < dsi->num_lanes_supported; ++i)
2375 in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002376
2377 t = 100000;
2378 while (true) {
2379 u32 l;
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002380 int ok;
2381
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302382 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002383
2384 ok = 0;
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002385 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2386 if (!in_use[i] || (l & (1 << offsets[i])))
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002387 ok++;
2388 }
2389
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002390 if (ok == dsi->num_lanes_supported)
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002391 break;
2392
2393 if (--t == 0) {
Tomi Valkeinen8dc07662011-10-13 15:26:50 +03002394 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2395 if (!in_use[i] || (l & (1 << offsets[i])))
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002396 continue;
2397
2398 DSSERR("CIO TXCLKESC%d domain not coming " \
2399 "out of reset\n", i);
2400 }
2401 return -EIO;
2402 }
2403 }
2404
2405 return 0;
2406}
2407
Tomi Valkeinen85f17e82011-10-13 15:12:23 +03002408/* return bitmask of enabled lanes, lane0 being the lsb */
Archit Taneja9e7e9372012-08-14 12:29:22 +05302409static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
Tomi Valkeinen5bc416c2011-06-15 15:21:12 +03002410{
Tomi Valkeinen85f17e82011-10-13 15:12:23 +03002411 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2412 unsigned mask = 0;
2413 int i;
Tomi Valkeinen5bc416c2011-06-15 15:21:12 +03002414
Tomi Valkeinen85f17e82011-10-13 15:12:23 +03002415 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2416 if (dsi->lanes[i].function != DSI_LANE_UNUSED)
2417 mask |= 1 << i;
2418 }
Tomi Valkeinen5bc416c2011-06-15 15:21:12 +03002419
Tomi Valkeinen85f17e82011-10-13 15:12:23 +03002420 return mask;
Tomi Valkeinen5bc416c2011-06-15 15:21:12 +03002421}
2422
Archit Taneja9e7e9372012-08-14 12:29:22 +05302423static int dsi_cio_init(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002424{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302425 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002426 int r;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002427 u32 l;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002428
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002429 DSSDBGF();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002430
Archit Taneja9e7e9372012-08-14 12:29:22 +05302431 r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
Tomi Valkeinen5bc416c2011-06-15 15:21:12 +03002432 if (r)
2433 return r;
Tomi Valkeinend1f5857e2010-07-30 11:57:57 +03002434
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302435 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002436
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002437 /* A dummy read using the SCP interface to any DSIPHY register is
2438 * required after DSIPHY reset to complete the reset of the DSI complex
2439 * I/O. */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302440 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002441
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302442 if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002443 DSSERR("CIO SCP Clock domain not coming out of reset.\n");
2444 r = -EIO;
2445 goto err_scp_clk_dom;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002446 }
2447
Archit Taneja9e7e9372012-08-14 12:29:22 +05302448 r = dsi_set_lane_config(dsidev);
Tomi Valkeinen48368392011-10-13 11:22:39 +03002449 if (r)
2450 goto err_scp_clk_dom;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002451
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002452 /* set TX STOP MODE timer to maximum for this operation */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302453 l = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002454 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2455 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
2456 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
2457 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302458 dsi_write_reg(dsidev, DSI_TIMING1, l);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002459
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302460 if (dsi->ulps_enabled) {
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002461 unsigned mask_p;
2462 int i;
Archit Taneja75d72472011-05-16 15:17:08 +05302463
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002464 DSSDBG("manual ulps exit\n");
2465
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002466 /* ULPS is exited by Mark-1 state for 1ms, followed by
2467 * stop state. DSS HW cannot do this via the normal
2468 * ULPS exit sequence, as after reset the DSS HW thinks
2469 * that we are not in ULPS mode, and refuses to send the
2470 * sequence. So we need to send the ULPS exit sequence
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002471 * manually by setting positive lines high and negative lines
2472 * low for 1ms.
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002473 */
2474
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002475 mask_p = 0;
Archit Taneja75d72472011-05-16 15:17:08 +05302476
Tomi Valkeinen9b4362f2011-10-13 16:06:43 +03002477 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2478 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
2479 continue;
2480 mask_p |= 1 << i;
2481 }
Archit Taneja75d72472011-05-16 15:17:08 +05302482
Archit Taneja9e7e9372012-08-14 12:29:22 +05302483 dsi_cio_enable_lane_override(dsidev, mask_p, 0);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002484 }
2485
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302486 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002487 if (r)
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002488 goto err_cio_pwr;
2489
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302490 if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002491 DSSERR("CIO PWR clock domain not coming out of reset.\n");
2492 r = -ENODEV;
2493 goto err_cio_pwr_dom;
2494 }
2495
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302496 dsi_if_enable(dsidev, true);
2497 dsi_if_enable(dsidev, false);
2498 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002499
Archit Taneja9e7e9372012-08-14 12:29:22 +05302500 r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002501 if (r)
2502 goto err_tx_clk_esc_rst;
2503
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302504 if (dsi->ulps_enabled) {
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002505 /* Keep Mark-1 state for 1ms (as per DSI spec) */
2506 ktime_t wait = ns_to_ktime(1000 * 1000);
2507 set_current_state(TASK_UNINTERRUPTIBLE);
2508 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
2509
2510 /* Disable the override. The lanes should be set to Mark-11
2511 * state by the HW */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302512 dsi_cio_disable_lane_override(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002513 }
2514
2515 /* FORCE_TX_STOP_MODE_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302516 REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002517
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302518 dsi_cio_timings(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002519
Archit Tanejadca2b152012-08-16 18:02:00 +05302520 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Archit Taneja8af6ff02011-09-05 16:48:27 +05302521 /* DDR_CLK_ALWAYS_ON */
2522 REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
Archit Taneja0b3ffe32012-08-13 22:13:39 +05302523 dsi->vm_timings.ddr_clk_always_on, 13, 13);
Archit Taneja8af6ff02011-09-05 16:48:27 +05302524 }
2525
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302526 dsi->ulps_enabled = false;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002527
2528 DSSDBG("CIO init done\n");
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002529
2530 return 0;
2531
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002532err_tx_clk_esc_rst:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302533 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002534err_cio_pwr_dom:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302535 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002536err_cio_pwr:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302537 if (dsi->ulps_enabled)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302538 dsi_cio_disable_lane_override(dsidev);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002539err_scp_clk_dom:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302540 dsi_disable_scp_clk(dsidev);
Archit Taneja9e7e9372012-08-14 12:29:22 +05302541 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002542 return r;
2543}
2544
Archit Taneja9e7e9372012-08-14 12:29:22 +05302545static void dsi_cio_uninit(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002546{
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02002547 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302548
Archit Taneja8af6ff02011-09-05 16:48:27 +05302549 /* DDR_CLK_ALWAYS_ON */
2550 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
2551
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302552 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2553 dsi_disable_scp_clk(dsidev);
Archit Taneja9e7e9372012-08-14 12:29:22 +05302554 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002555}
2556
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302557static void dsi_config_tx_fifo(struct platform_device *dsidev,
2558 enum fifo_size size1, enum fifo_size size2,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002559 enum fifo_size size3, enum fifo_size size4)
2560{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302561 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002562 u32 r = 0;
2563 int add = 0;
2564 int i;
2565
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302566 dsi->vc[0].fifo_size = size1;
2567 dsi->vc[1].fifo_size = size2;
2568 dsi->vc[2].fifo_size = size3;
2569 dsi->vc[3].fifo_size = size4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002570
2571 for (i = 0; i < 4; i++) {
2572 u8 v;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302573 int size = dsi->vc[i].fifo_size;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002574
2575 if (add + size > 4) {
2576 DSSERR("Illegal FIFO configuration\n");
2577 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002578 return;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002579 }
2580
2581 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2582 r |= v << (8 * i);
2583 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
2584 add += size;
2585 }
2586
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302587 dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002588}
2589
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302590static void dsi_config_rx_fifo(struct platform_device *dsidev,
2591 enum fifo_size size1, enum fifo_size size2,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002592 enum fifo_size size3, enum fifo_size size4)
2593{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302594 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002595 u32 r = 0;
2596 int add = 0;
2597 int i;
2598
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302599 dsi->vc[0].fifo_size = size1;
2600 dsi->vc[1].fifo_size = size2;
2601 dsi->vc[2].fifo_size = size3;
2602 dsi->vc[3].fifo_size = size4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002603
2604 for (i = 0; i < 4; i++) {
2605 u8 v;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302606 int size = dsi->vc[i].fifo_size;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002607
2608 if (add + size > 4) {
2609 DSSERR("Illegal FIFO configuration\n");
2610 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002611 return;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002612 }
2613
2614 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2615 r |= v << (8 * i);
2616 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
2617 add += size;
2618 }
2619
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302620 dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002621}
2622
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302623static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002624{
2625 u32 r;
2626
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302627 r = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002628 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302629 dsi_write_reg(dsidev, DSI_TIMING1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002630
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302631 if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002632 DSSERR("TX_STOP bit not going down\n");
2633 return -EIO;
2634 }
2635
2636 return 0;
2637}
2638
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302639static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002640{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302641 return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002642}
2643
2644static void dsi_packet_sent_handler_vp(void *data, u32 mask)
2645{
Archit Taneja2e868db2011-05-12 17:26:28 +05302646 struct dsi_packet_sent_handler_data *vp_data =
2647 (struct dsi_packet_sent_handler_data *) data;
2648 struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302649 const int channel = dsi->update_channel;
2650 u8 bit = dsi->te_enabled ? 30 : 31;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002651
Archit Taneja2e868db2011-05-12 17:26:28 +05302652 if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
2653 complete(vp_data->completion);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002654}
2655
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302656static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002657{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302658 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja2e868db2011-05-12 17:26:28 +05302659 DECLARE_COMPLETION_ONSTACK(completion);
2660 struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
Archit Tanejacf398fb2011-03-23 09:59:34 +00002661 int r = 0;
2662 u8 bit;
2663
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302664 bit = dsi->te_enabled ? 30 : 31;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002665
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302666 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302667 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002668 if (r)
2669 goto err0;
2670
2671 /* Wait for completion only if TE_EN/TE_START is still set */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302672 if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
Archit Tanejacf398fb2011-03-23 09:59:34 +00002673 if (wait_for_completion_timeout(&completion,
2674 msecs_to_jiffies(10)) == 0) {
2675 DSSERR("Failed to complete previous frame transfer\n");
2676 r = -EIO;
2677 goto err1;
2678 }
2679 }
2680
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302681 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302682 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002683
2684 return 0;
2685err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302686 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302687 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002688err0:
2689 return r;
2690}
2691
2692static void dsi_packet_sent_handler_l4(void *data, u32 mask)
2693{
Archit Taneja2e868db2011-05-12 17:26:28 +05302694 struct dsi_packet_sent_handler_data *l4_data =
2695 (struct dsi_packet_sent_handler_data *) data;
2696 struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302697 const int channel = dsi->update_channel;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002698
Archit Taneja2e868db2011-05-12 17:26:28 +05302699 if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
2700 complete(l4_data->completion);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002701}
2702
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302703static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002704{
Archit Taneja2e868db2011-05-12 17:26:28 +05302705 DECLARE_COMPLETION_ONSTACK(completion);
2706 struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
Archit Tanejacf398fb2011-03-23 09:59:34 +00002707 int r = 0;
2708
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302709 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302710 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002711 if (r)
2712 goto err0;
2713
2714 /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302715 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
Archit Tanejacf398fb2011-03-23 09:59:34 +00002716 if (wait_for_completion_timeout(&completion,
2717 msecs_to_jiffies(10)) == 0) {
2718 DSSERR("Failed to complete previous l4 transfer\n");
2719 r = -EIO;
2720 goto err1;
2721 }
2722 }
2723
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302724 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302725 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002726
2727 return 0;
2728err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302729 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302730 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002731err0:
2732 return r;
2733}
2734
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302735static int dsi_sync_vc(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002736{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302737 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2738
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302739 WARN_ON(!dsi_bus_is_locked(dsidev));
Archit Tanejacf398fb2011-03-23 09:59:34 +00002740
2741 WARN_ON(in_interrupt());
2742
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302743 if (!dsi_vc_is_enabled(dsidev, channel))
Archit Tanejacf398fb2011-03-23 09:59:34 +00002744 return 0;
2745
Archit Tanejad6049142011-08-22 11:58:08 +05302746 switch (dsi->vc[channel].source) {
2747 case DSI_VC_SOURCE_VP:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302748 return dsi_sync_vc_vp(dsidev, channel);
Archit Tanejad6049142011-08-22 11:58:08 +05302749 case DSI_VC_SOURCE_L4:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302750 return dsi_sync_vc_l4(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002751 default:
2752 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002753 return -EINVAL;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002754 }
2755}
2756
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302757static int dsi_vc_enable(struct platform_device *dsidev, int channel,
2758 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002759{
Tomi Valkeinen446f7bf2010-01-11 16:12:31 +02002760 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
2761 channel, enable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002762
2763 enable = enable ? 1 : 0;
2764
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302765 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002766
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302767 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
2768 0, enable) != enable) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002769 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
2770 return -EIO;
2771 }
2772
2773 return 0;
2774}
2775
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302776static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002777{
2778 u32 r;
2779
2780 DSSDBGF("%d", channel);
2781
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302782 r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002783
2784 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
2785 DSSERR("VC(%d) busy when trying to configure it!\n",
2786 channel);
2787
2788 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
2789 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
2790 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
2791 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
2792 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
2793 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
2794 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
Archit Taneja9613c022011-03-22 06:33:36 -05002795 if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
2796 r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002797
2798 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
2799 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
2800
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302801 dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002802}
2803
Archit Tanejad6049142011-08-22 11:58:08 +05302804static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
2805 enum dsi_vc_source source)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002806{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302807 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2808
Archit Tanejad6049142011-08-22 11:58:08 +05302809 if (dsi->vc[channel].source == source)
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002810 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002811
2812 DSSDBGF("%d", channel);
2813
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302814 dsi_sync_vc(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002815
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302816 dsi_vc_enable(dsidev, channel, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002817
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002818 /* VC_BUSY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302819 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002820 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002821 return -EIO;
2822 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002823
Archit Tanejad6049142011-08-22 11:58:08 +05302824 /* SOURCE, 0 = L4, 1 = video port */
2825 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002826
Archit Taneja9613c022011-03-22 06:33:36 -05002827 /* DCS_CMD_ENABLE */
Archit Tanejad6049142011-08-22 11:58:08 +05302828 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
2829 bool enable = source == DSI_VC_SOURCE_VP;
2830 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
2831 }
Archit Taneja9613c022011-03-22 06:33:36 -05002832
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302833 dsi_vc_enable(dsidev, channel, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002834
Archit Tanejad6049142011-08-22 11:58:08 +05302835 dsi->vc[channel].source = source;
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002836
2837 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002838}
2839
Archit Taneja1ffefe72011-05-12 17:26:24 +05302840void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
2841 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002842{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302843 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Taneja0b3ffe32012-08-13 22:13:39 +05302844 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302845
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002846 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
2847
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302848 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen61140c92010-01-12 16:00:30 +02002849
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302850 dsi_vc_enable(dsidev, channel, 0);
2851 dsi_if_enable(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002852
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302853 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002854
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302855 dsi_vc_enable(dsidev, channel, 1);
2856 dsi_if_enable(dsidev, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002857
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302858 dsi_force_tx_stop_mode_io(dsidev);
Archit Taneja8af6ff02011-09-05 16:48:27 +05302859
2860 /* start the DDR clock by sending a NULL packet */
Archit Taneja0b3ffe32012-08-13 22:13:39 +05302861 if (dsi->vm_timings.ddr_clk_always_on && enable)
Archit Taneja8af6ff02011-09-05 16:48:27 +05302862 dsi_vc_send_null(dssdev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002863}
Tomi Valkeinen61140c92010-01-12 16:00:30 +02002864EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002865
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302866static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002867{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302868 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002869 u32 val;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302870 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002871 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
2872 (val >> 0) & 0xff,
2873 (val >> 8) & 0xff,
2874 (val >> 16) & 0xff,
2875 (val >> 24) & 0xff);
2876 }
2877}
2878
2879static void dsi_show_rx_ack_with_err(u16 err)
2880{
2881 DSSERR("\tACK with ERROR (%#x):\n", err);
2882 if (err & (1 << 0))
2883 DSSERR("\t\tSoT Error\n");
2884 if (err & (1 << 1))
2885 DSSERR("\t\tSoT Sync Error\n");
2886 if (err & (1 << 2))
2887 DSSERR("\t\tEoT Sync Error\n");
2888 if (err & (1 << 3))
2889 DSSERR("\t\tEscape Mode Entry Command Error\n");
2890 if (err & (1 << 4))
2891 DSSERR("\t\tLP Transmit Sync Error\n");
2892 if (err & (1 << 5))
2893 DSSERR("\t\tHS Receive Timeout Error\n");
2894 if (err & (1 << 6))
2895 DSSERR("\t\tFalse Control Error\n");
2896 if (err & (1 << 7))
2897 DSSERR("\t\t(reserved7)\n");
2898 if (err & (1 << 8))
2899 DSSERR("\t\tECC Error, single-bit (corrected)\n");
2900 if (err & (1 << 9))
2901 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
2902 if (err & (1 << 10))
2903 DSSERR("\t\tChecksum Error\n");
2904 if (err & (1 << 11))
2905 DSSERR("\t\tData type not recognized\n");
2906 if (err & (1 << 12))
2907 DSSERR("\t\tInvalid VC ID\n");
2908 if (err & (1 << 13))
2909 DSSERR("\t\tInvalid Transmission Length\n");
2910 if (err & (1 << 14))
2911 DSSERR("\t\t(reserved14)\n");
2912 if (err & (1 << 15))
2913 DSSERR("\t\tDSI Protocol Violation\n");
2914}
2915
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302916static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
2917 int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002918{
2919 /* RX_FIFO_NOT_EMPTY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302920 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002921 u32 val;
2922 u8 dt;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302923 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002924 DSSERR("\trawval %#08x\n", val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002925 dt = FLD_GET(val, 5, 0);
Archit Taneja7a7c48f2011-08-25 18:25:03 +05302926 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002927 u16 err = FLD_GET(val, 23, 8);
2928 dsi_show_rx_ack_with_err(err);
Archit Taneja7a7c48f2011-08-25 18:25:03 +05302929 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002930 DSSERR("\tDCS short response, 1 byte: %#x\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002931 FLD_GET(val, 23, 8));
Archit Taneja7a7c48f2011-08-25 18:25:03 +05302932 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002933 DSSERR("\tDCS short response, 2 byte: %#x\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002934 FLD_GET(val, 23, 8));
Archit Taneja7a7c48f2011-08-25 18:25:03 +05302935 } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002936 DSSERR("\tDCS long response, len %d\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002937 FLD_GET(val, 23, 8));
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302938 dsi_vc_flush_long_data(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002939 } else {
2940 DSSERR("\tunknown datatype 0x%02x\n", dt);
2941 }
2942 }
2943 return 0;
2944}
2945
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302946static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002947{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302948 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2949
2950 if (dsi->debug_write || dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002951 DSSDBG("dsi_vc_send_bta %d\n", channel);
2952
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302953 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002954
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302955 /* RX_FIFO_NOT_EMPTY */
2956 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002957 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302958 dsi_vc_flush_receive_data(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002959 }
2960
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302961 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002962
Tomi Valkeinen968f8e92011-10-12 10:13:14 +03002963 /* flush posted write */
2964 dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2965
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002966 return 0;
2967}
2968
Archit Taneja1ffefe72011-05-12 17:26:24 +05302969int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002970{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302971 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002972 DECLARE_COMPLETION_ONSTACK(completion);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002973 int r = 0;
2974 u32 err;
2975
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302976 r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002977 &completion, DSI_VC_IRQ_BTA);
2978 if (r)
2979 goto err0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002980
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302981 r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002982 DSI_IRQ_ERROR_MASK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002983 if (r)
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002984 goto err1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002985
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302986 r = dsi_vc_send_bta(dsidev, channel);
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002987 if (r)
2988 goto err2;
2989
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002990 if (wait_for_completion_timeout(&completion,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002991 msecs_to_jiffies(500)) == 0) {
2992 DSSERR("Failed to receive BTA\n");
2993 r = -EIO;
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002994 goto err2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002995 }
2996
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302997 err = dsi_get_errors(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002998 if (err) {
2999 DSSERR("Error while sending BTA: %x\n", err);
3000 r = -EIO;
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03003001 goto err2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003002 }
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03003003err2:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303004 dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03003005 DSI_IRQ_ERROR_MASK);
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02003006err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303007 dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02003008 &completion, DSI_VC_IRQ_BTA);
3009err0:
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003010 return r;
3011}
3012EXPORT_SYMBOL(dsi_vc_send_bta_sync);
3013
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303014static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
3015 int channel, u8 data_type, u16 len, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003016{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303017 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003018 u32 val;
3019 u8 data_id;
3020
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303021 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003022
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303023 data_id = data_type | dsi->vc[channel].vc_id << 6;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003024
3025 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
3026 FLD_VAL(ecc, 31, 24);
3027
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303028 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003029}
3030
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303031static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
3032 int channel, u8 b1, u8 b2, u8 b3, u8 b4)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003033{
3034 u32 val;
3035
3036 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
3037
3038/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
3039 b1, b2, b3, b4, val); */
3040
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303041 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003042}
3043
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303044static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
3045 u8 data_type, u8 *data, u16 len, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003046{
3047 /*u32 val; */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303048 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003049 int i;
3050 u8 *p;
3051 int r = 0;
3052 u8 b1, b2, b3, b4;
3053
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303054 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003055 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
3056
3057 /* len + header */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303058 if (dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003059 DSSERR("unable to send long packet: packet too long.\n");
3060 return -EINVAL;
3061 }
3062
Archit Tanejad6049142011-08-22 11:58:08 +05303063 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003064
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303065 dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003066
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003067 p = data;
3068 for (i = 0; i < len >> 2; i++) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303069 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003070 DSSDBG("\tsending full packet %d\n", i);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003071
3072 b1 = *p++;
3073 b2 = *p++;
3074 b3 = *p++;
3075 b4 = *p++;
3076
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303077 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003078 }
3079
3080 i = len % 4;
3081 if (i) {
3082 b1 = 0; b2 = 0; b3 = 0;
3083
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303084 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003085 DSSDBG("\tsending remainder bytes %d\n", i);
3086
3087 switch (i) {
3088 case 3:
3089 b1 = *p++;
3090 b2 = *p++;
3091 b3 = *p++;
3092 break;
3093 case 2:
3094 b1 = *p++;
3095 b2 = *p++;
3096 break;
3097 case 1:
3098 b1 = *p++;
3099 break;
3100 }
3101
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303102 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003103 }
3104
3105 return r;
3106}
3107
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303108static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
3109 u8 data_type, u16 data, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003110{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303111 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003112 u32 r;
3113 u8 data_id;
3114
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303115 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003116
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303117 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003118 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
3119 channel,
3120 data_type, data & 0xff, (data >> 8) & 0xff);
3121
Archit Tanejad6049142011-08-22 11:58:08 +05303122 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003123
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303124 if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003125 DSSERR("ERROR FIFO FULL, aborting transfer\n");
3126 return -EINVAL;
3127 }
3128
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303129 data_id = data_type | dsi->vc[channel].vc_id << 6;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003130
3131 r = (data_id << 0) | (data << 8) | (ecc << 24);
3132
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303133 dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003134
3135 return 0;
3136}
3137
Archit Taneja1ffefe72011-05-12 17:26:24 +05303138int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003139{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303140 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303141
Archit Taneja18b7d092011-09-05 17:01:08 +05303142 return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
3143 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003144}
3145EXPORT_SYMBOL(dsi_vc_send_null);
3146
Archit Taneja9e7e9372012-08-14 12:29:22 +05303147static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303148 int channel, u8 *data, int len, enum dss_dsi_content_type type)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003149{
3150 int r;
3151
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303152 if (len == 0) {
3153 BUG_ON(type == DSS_DSI_CONTENT_DCS);
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303154 r = dsi_vc_send_short(dsidev, channel,
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303155 MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0);
3156 } else if (len == 1) {
3157 r = dsi_vc_send_short(dsidev, channel,
3158 type == DSS_DSI_CONTENT_GENERIC ?
3159 MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303160 MIPI_DSI_DCS_SHORT_WRITE, data[0], 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003161 } else if (len == 2) {
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303162 r = dsi_vc_send_short(dsidev, channel,
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303163 type == DSS_DSI_CONTENT_GENERIC ?
3164 MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303165 MIPI_DSI_DCS_SHORT_WRITE_PARAM,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003166 data[0] | (data[1] << 8), 0);
3167 } else {
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303168 r = dsi_vc_send_long(dsidev, channel,
3169 type == DSS_DSI_CONTENT_GENERIC ?
3170 MIPI_DSI_GENERIC_LONG_WRITE :
3171 MIPI_DSI_DCS_LONG_WRITE, data, len, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003172 }
3173
3174 return r;
3175}
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303176
3177int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
3178 u8 *data, int len)
3179{
Archit Taneja9e7e9372012-08-14 12:29:22 +05303180 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3181
3182 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303183 DSS_DSI_CONTENT_DCS);
3184}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003185EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
3186
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303187int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
3188 u8 *data, int len)
3189{
Archit Taneja9e7e9372012-08-14 12:29:22 +05303190 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3191
3192 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303193 DSS_DSI_CONTENT_GENERIC);
3194}
3195EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
3196
3197static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
3198 u8 *data, int len, enum dss_dsi_content_type type)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003199{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303200 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003201 int r;
3202
Archit Taneja9e7e9372012-08-14 12:29:22 +05303203 r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003204 if (r)
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003205 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003206
Archit Taneja1ffefe72011-05-12 17:26:24 +05303207 r = dsi_vc_send_bta_sync(dssdev, channel);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003208 if (r)
3209 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003210
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303211 /* RX_FIFO_NOT_EMPTY */
3212 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinenb63ac1e2010-04-09 13:20:57 +03003213 DSSERR("rx fifo not empty after write, dumping data:\n");
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303214 dsi_vc_flush_receive_data(dsidev, channel);
Tomi Valkeinenb63ac1e2010-04-09 13:20:57 +03003215 r = -EIO;
3216 goto err;
3217 }
3218
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003219 return 0;
3220err:
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303221 DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n",
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003222 channel, data[0], len);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003223 return r;
3224}
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303225
3226int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
3227 int len)
3228{
3229 return dsi_vc_write_common(dssdev, channel, data, len,
3230 DSS_DSI_CONTENT_DCS);
3231}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003232EXPORT_SYMBOL(dsi_vc_dcs_write);
3233
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303234int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
3235 int len)
3236{
3237 return dsi_vc_write_common(dssdev, channel, data, len,
3238 DSS_DSI_CONTENT_GENERIC);
3239}
3240EXPORT_SYMBOL(dsi_vc_generic_write);
3241
Archit Taneja1ffefe72011-05-12 17:26:24 +05303242int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003243{
Archit Taneja1ffefe72011-05-12 17:26:24 +05303244 return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003245}
3246EXPORT_SYMBOL(dsi_vc_dcs_write_0);
3247
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303248int dsi_vc_generic_write_0(struct omap_dss_device *dssdev, int channel)
3249{
3250 return dsi_vc_generic_write(dssdev, channel, NULL, 0);
3251}
3252EXPORT_SYMBOL(dsi_vc_generic_write_0);
3253
Archit Taneja1ffefe72011-05-12 17:26:24 +05303254int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3255 u8 param)
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003256{
3257 u8 buf[2];
3258 buf[0] = dcs_cmd;
3259 buf[1] = param;
Archit Taneja1ffefe72011-05-12 17:26:24 +05303260 return dsi_vc_dcs_write(dssdev, channel, buf, 2);
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003261}
3262EXPORT_SYMBOL(dsi_vc_dcs_write_1);
3263
Archit Taneja6ff8aa32011-08-25 18:35:58 +05303264int dsi_vc_generic_write_1(struct omap_dss_device *dssdev, int channel,
3265 u8 param)
3266{
3267 return dsi_vc_generic_write(dssdev, channel, &param, 1);
3268}
3269EXPORT_SYMBOL(dsi_vc_generic_write_1);
3270
3271int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
3272 u8 param1, u8 param2)
3273{
3274 u8 buf[2];
3275 buf[0] = param1;
3276 buf[1] = param2;
3277 return dsi_vc_generic_write(dssdev, channel, buf, 2);
3278}
3279EXPORT_SYMBOL(dsi_vc_generic_write_2);
3280
Archit Taneja9e7e9372012-08-14 12:29:22 +05303281static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
Archit Tanejab8509752011-08-30 15:48:23 +05303282 int channel, u8 dcs_cmd)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003283{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303284 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejab8509752011-08-30 15:48:23 +05303285 int r;
3286
3287 if (dsi->debug_read)
3288 DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n",
3289 channel, dcs_cmd);
3290
3291 r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0);
3292 if (r) {
3293 DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)"
3294 " failed\n", channel, dcs_cmd);
3295 return r;
3296 }
3297
3298 return 0;
3299}
3300
Archit Taneja9e7e9372012-08-14 12:29:22 +05303301static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
Archit Tanejab3b89c02011-08-30 16:07:39 +05303302 int channel, u8 *reqdata, int reqlen)
3303{
Archit Tanejab3b89c02011-08-30 16:07:39 +05303304 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3305 u16 data;
3306 u8 data_type;
3307 int r;
3308
3309 if (dsi->debug_read)
3310 DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n",
3311 channel, reqlen);
3312
3313 if (reqlen == 0) {
3314 data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
3315 data = 0;
3316 } else if (reqlen == 1) {
3317 data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
3318 data = reqdata[0];
3319 } else if (reqlen == 2) {
3320 data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
3321 data = reqdata[0] | (reqdata[1] << 8);
3322 } else {
3323 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03003324 return -EINVAL;
Archit Tanejab3b89c02011-08-30 16:07:39 +05303325 }
3326
3327 r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
3328 if (r) {
3329 DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)"
3330 " failed\n", channel, reqlen);
3331 return r;
3332 }
3333
3334 return 0;
3335}
3336
3337static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
3338 u8 *buf, int buflen, enum dss_dsi_content_type type)
Archit Tanejab8509752011-08-30 15:48:23 +05303339{
3340 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003341 u32 val;
3342 u8 dt;
3343 int r;
3344
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003345 /* RX_FIFO_NOT_EMPTY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303346 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003347 DSSERR("RX fifo empty when trying to read.\n");
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003348 r = -EIO;
3349 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003350 }
3351
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303352 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303353 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003354 DSSDBG("\theader: %08x\n", val);
3355 dt = FLD_GET(val, 5, 0);
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303356 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003357 u16 err = FLD_GET(val, 23, 8);
3358 dsi_show_rx_ack_with_err(err);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003359 r = -EIO;
3360 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003361
Archit Tanejab3b89c02011-08-30 16:07:39 +05303362 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3363 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE :
3364 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003365 u8 data = FLD_GET(val, 15, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303366 if (dsi->debug_read)
Archit Tanejab3b89c02011-08-30 16:07:39 +05303367 DSSDBG("\t%s short response, 1 byte: %02x\n",
3368 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3369 "DCS", data);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003370
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003371 if (buflen < 1) {
3372 r = -EIO;
3373 goto err;
3374 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003375
3376 buf[0] = data;
3377
3378 return 1;
Archit Tanejab3b89c02011-08-30 16:07:39 +05303379 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3380 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE :
3381 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003382 u16 data = FLD_GET(val, 23, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303383 if (dsi->debug_read)
Archit Tanejab3b89c02011-08-30 16:07:39 +05303384 DSSDBG("\t%s short response, 2 byte: %04x\n",
3385 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3386 "DCS", data);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003387
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003388 if (buflen < 2) {
3389 r = -EIO;
3390 goto err;
3391 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003392
3393 buf[0] = data & 0xff;
3394 buf[1] = (data >> 8) & 0xff;
3395
3396 return 2;
Archit Tanejab3b89c02011-08-30 16:07:39 +05303397 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3398 MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE :
3399 MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003400 int w;
3401 int len = FLD_GET(val, 23, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303402 if (dsi->debug_read)
Archit Tanejab3b89c02011-08-30 16:07:39 +05303403 DSSDBG("\t%s long response, len %d\n",
3404 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3405 "DCS", len);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003406
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003407 if (len > buflen) {
3408 r = -EIO;
3409 goto err;
3410 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003411
3412 /* two byte checksum ends the packet, not included in len */
3413 for (w = 0; w < len + 2;) {
3414 int b;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303415 val = dsi_read_reg(dsidev,
3416 DSI_VC_SHORT_PACKET_HEADER(channel));
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303417 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003418 DSSDBG("\t\t%02x %02x %02x %02x\n",
3419 (val >> 0) & 0xff,
3420 (val >> 8) & 0xff,
3421 (val >> 16) & 0xff,
3422 (val >> 24) & 0xff);
3423
3424 for (b = 0; b < 4; ++b) {
3425 if (w < len)
3426 buf[w] = (val >> (b * 8)) & 0xff;
3427 /* we discard the 2 byte checksum */
3428 ++w;
3429 }
3430 }
3431
3432 return len;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003433 } else {
3434 DSSERR("\tunknown datatype 0x%02x\n", dt);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003435 r = -EIO;
3436 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003437 }
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003438
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003439err:
Archit Tanejab3b89c02011-08-30 16:07:39 +05303440 DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
3441 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003442
Archit Tanejab8509752011-08-30 15:48:23 +05303443 return r;
3444}
3445
3446int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3447 u8 *buf, int buflen)
3448{
3449 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3450 int r;
3451
Archit Taneja9e7e9372012-08-14 12:29:22 +05303452 r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
Archit Tanejab8509752011-08-30 15:48:23 +05303453 if (r)
3454 goto err;
3455
3456 r = dsi_vc_send_bta_sync(dssdev, channel);
3457 if (r)
3458 goto err;
3459
Archit Tanejab3b89c02011-08-30 16:07:39 +05303460 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3461 DSS_DSI_CONTENT_DCS);
Archit Tanejab8509752011-08-30 15:48:23 +05303462 if (r < 0)
3463 goto err;
3464
3465 if (r != buflen) {
3466 r = -EIO;
3467 goto err;
3468 }
3469
3470 return 0;
3471err:
3472 DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd);
3473 return r;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003474}
3475EXPORT_SYMBOL(dsi_vc_dcs_read);
3476
Archit Tanejab3b89c02011-08-30 16:07:39 +05303477static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
3478 u8 *reqdata, int reqlen, u8 *buf, int buflen)
3479{
3480 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3481 int r;
3482
Archit Taneja9e7e9372012-08-14 12:29:22 +05303483 r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
Archit Tanejab3b89c02011-08-30 16:07:39 +05303484 if (r)
3485 return r;
3486
3487 r = dsi_vc_send_bta_sync(dssdev, channel);
3488 if (r)
3489 return r;
3490
3491 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3492 DSS_DSI_CONTENT_GENERIC);
3493 if (r < 0)
3494 return r;
3495
3496 if (r != buflen) {
3497 r = -EIO;
3498 return r;
3499 }
3500
3501 return 0;
3502}
3503
3504int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf,
3505 int buflen)
3506{
3507 int r;
3508
3509 r = dsi_vc_generic_read(dssdev, channel, NULL, 0, buf, buflen);
3510 if (r) {
3511 DSSERR("dsi_vc_generic_read_0(ch %d) failed\n", channel);
3512 return r;
3513 }
3514
3515 return 0;
3516}
3517EXPORT_SYMBOL(dsi_vc_generic_read_0);
3518
3519int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param,
3520 u8 *buf, int buflen)
3521{
3522 int r;
3523
3524 r = dsi_vc_generic_read(dssdev, channel, &param, 1, buf, buflen);
3525 if (r) {
3526 DSSERR("dsi_vc_generic_read_1(ch %d) failed\n", channel);
3527 return r;
3528 }
3529
3530 return 0;
3531}
3532EXPORT_SYMBOL(dsi_vc_generic_read_1);
3533
3534int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel,
3535 u8 param1, u8 param2, u8 *buf, int buflen)
3536{
3537 int r;
3538 u8 reqdata[2];
3539
3540 reqdata[0] = param1;
3541 reqdata[1] = param2;
3542
3543 r = dsi_vc_generic_read(dssdev, channel, reqdata, 2, buf, buflen);
3544 if (r) {
3545 DSSERR("dsi_vc_generic_read_2(ch %d) failed\n", channel);
3546 return r;
3547 }
3548
3549 return 0;
3550}
3551EXPORT_SYMBOL(dsi_vc_generic_read_2);
3552
Archit Taneja1ffefe72011-05-12 17:26:24 +05303553int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
3554 u16 len)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003555{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303556 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3557
Archit Taneja7a7c48f2011-08-25 18:25:03 +05303558 return dsi_vc_send_short(dsidev, channel,
3559 MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003560}
3561EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
3562
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303563static int dsi_enter_ulps(struct platform_device *dsidev)
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003564{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303565 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003566 DECLARE_COMPLETION_ONSTACK(completion);
Tomi Valkeinen522a0c22011-10-13 16:18:52 +03003567 int r, i;
3568 unsigned mask;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003569
3570 DSSDBGF();
3571
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303572 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003573
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303574 WARN_ON(dsi->ulps_enabled);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003575
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303576 if (dsi->ulps_enabled)
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003577 return 0;
3578
Tomi Valkeinen6cc78aa2011-10-13 19:22:43 +03003579 /* DDR_CLK_ALWAYS_ON */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303580 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
Tomi Valkeinen6cc78aa2011-10-13 19:22:43 +03003581 dsi_if_enable(dsidev, 0);
3582 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
3583 dsi_if_enable(dsidev, 1);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003584 }
3585
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303586 dsi_sync_vc(dsidev, 0);
3587 dsi_sync_vc(dsidev, 1);
3588 dsi_sync_vc(dsidev, 2);
3589 dsi_sync_vc(dsidev, 3);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003590
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303591 dsi_force_tx_stop_mode_io(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003592
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303593 dsi_vc_enable(dsidev, 0, false);
3594 dsi_vc_enable(dsidev, 1, false);
3595 dsi_vc_enable(dsidev, 2, false);
3596 dsi_vc_enable(dsidev, 3, false);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003597
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303598 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003599 DSSERR("HS busy when enabling ULPS\n");
3600 return -EIO;
3601 }
3602
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303603 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003604 DSSERR("LP busy when enabling ULPS\n");
3605 return -EIO;
3606 }
3607
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303608 r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003609 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3610 if (r)
3611 return r;
3612
Tomi Valkeinen522a0c22011-10-13 16:18:52 +03003613 mask = 0;
3614
3615 for (i = 0; i < dsi->num_lanes_supported; ++i) {
3616 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
3617 continue;
3618 mask |= 1 << i;
3619 }
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003620 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
3621 /* LANEx_ULPS_SIG2 */
Tomi Valkeinen522a0c22011-10-13 16:18:52 +03003622 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003623
Tomi Valkeinena702c852011-10-12 10:10:21 +03003624 /* flush posted write and wait for SCP interface to finish the write */
3625 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003626
3627 if (wait_for_completion_timeout(&completion,
3628 msecs_to_jiffies(1000)) == 0) {
3629 DSSERR("ULPS enable timeout\n");
3630 r = -EIO;
3631 goto err;
3632 }
3633
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303634 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003635 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3636
Tomi Valkeinen8ef0e612011-05-31 16:55:47 +03003637 /* Reset LANEx_ULPS_SIG2 */
Tomi Valkeinen522a0c22011-10-13 16:18:52 +03003638 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
Tomi Valkeinen8ef0e612011-05-31 16:55:47 +03003639
Tomi Valkeinena702c852011-10-12 10:10:21 +03003640 /* flush posted write and wait for SCP interface to finish the write */
3641 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003642
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303643 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003644
3645 dsi_if_enable(dsidev, false);
3646
3647 dsi->ulps_enabled = true;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303648
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003649 return 0;
3650
3651err:
3652 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303653 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3654 return r;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003655}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003656
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003657static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
3658 unsigned ticks, bool x4, bool x16)
3659{
3660 unsigned long fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003661 unsigned long total_ticks;
3662 u32 r;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303663
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003664 BUG_ON(ticks > 0x1fff);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303665
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003666 /* ticks in DSI_FCK */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003667 fck = dsi_fclk_rate(dsidev);
3668
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003669 r = dsi_read_reg(dsidev, DSI_TIMING2);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303670 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003671 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003672 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
3673 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
3674 dsi_write_reg(dsidev, DSI_TIMING2, r);
3675
3676 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3677
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003678 DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3679 total_ticks,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303680 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3681 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003682}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003683
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003684static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
3685 bool x8, bool x16)
3686{
3687 unsigned long fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003688 unsigned long total_ticks;
3689 u32 r;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303690
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003691 BUG_ON(ticks > 0x1fff);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303692
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003693 /* ticks in DSI_FCK */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003694 fck = dsi_fclk_rate(dsidev);
3695
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003696 r = dsi_read_reg(dsidev, DSI_TIMING1);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303697 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003698 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003699 r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
3700 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
3701 dsi_write_reg(dsidev, DSI_TIMING1, r);
3702
3703 total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
3704
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003705 DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
3706 total_ticks,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303707 ticks, x8 ? " x8" : "", x16 ? " x16" : "",
3708 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003709}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003710
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003711static void dsi_set_stop_state_counter(struct platform_device *dsidev,
3712 unsigned ticks, bool x4, bool x16)
3713{
3714 unsigned long fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003715 unsigned long total_ticks;
3716 u32 r;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303717
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003718 BUG_ON(ticks > 0x1fff);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303719
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003720 /* ticks in DSI_FCK */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003721 fck = dsi_fclk_rate(dsidev);
3722
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003723 r = dsi_read_reg(dsidev, DSI_TIMING1);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303724 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003725 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003726 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
3727 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
3728 dsi_write_reg(dsidev, DSI_TIMING1, r);
3729
3730 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3731
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003732 DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
3733 total_ticks,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303734 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3735 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003736}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003737
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003738static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
3739 unsigned ticks, bool x4, bool x16)
3740{
3741 unsigned long fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003742 unsigned long total_ticks;
3743 u32 r;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303744
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003745 BUG_ON(ticks > 0x1fff);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303746
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003747 /* ticks in TxByteClkHS */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003748 fck = dsi_get_txbyteclkhs(dsidev);
3749
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003750 r = dsi_read_reg(dsidev, DSI_TIMING2);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303751 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003752 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003753 r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
3754 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
3755 dsi_write_reg(dsidev, DSI_TIMING2, r);
3756
3757 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3758
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003759 DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3760 total_ticks,
3761 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303762 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003763}
Archit Taneja8af6ff02011-09-05 16:48:27 +05303764
Archit Taneja9e7e9372012-08-14 12:29:22 +05303765static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
Archit Taneja8af6ff02011-09-05 16:48:27 +05303766{
Archit Tanejadca2b152012-08-16 18:02:00 +05303767 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja8af6ff02011-09-05 16:48:27 +05303768 int num_line_buffers;
3769
Archit Tanejadca2b152012-08-16 18:02:00 +05303770 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Archit Taneja02c39602012-08-10 15:01:33 +05303771 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
Archit Taneja8af6ff02011-09-05 16:48:27 +05303772 unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
Archit Tanejae67458a2012-08-13 14:17:30 +05303773 struct omap_video_timings *timings = &dsi->timings;
Archit Taneja8af6ff02011-09-05 16:48:27 +05303774 /*
3775 * Don't use line buffers if width is greater than the video
3776 * port's line buffer size
3777 */
3778 if (line_buf_size <= timings->x_res * bpp / 8)
3779 num_line_buffers = 0;
3780 else
3781 num_line_buffers = 2;
3782 } else {
3783 /* Use maximum number of line buffers in command mode */
3784 num_line_buffers = 2;
3785 }
3786
3787 /* LINE_BUFFER */
3788 REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
3789}
3790
Archit Taneja9e7e9372012-08-14 12:29:22 +05303791static void dsi_config_vp_sync_events(struct platform_device *dsidev)
Archit Taneja8af6ff02011-09-05 16:48:27 +05303792{
Archit Taneja0b3ffe32012-08-13 22:13:39 +05303793 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3794 bool vsync_end = dsi->vm_timings.vp_vsync_end;
3795 bool hsync_end = dsi->vm_timings.vp_hsync_end;
Archit Taneja8af6ff02011-09-05 16:48:27 +05303796 u32 r;
3797
3798 r = dsi_read_reg(dsidev, DSI_CTRL);
Archit Tanejabd5a7b12012-06-26 12:38:31 +05303799 r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
3800 r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
3801 r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
Archit Taneja8af6ff02011-09-05 16:48:27 +05303802 r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
3803 r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */
3804 r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
3805 r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */
3806 dsi_write_reg(dsidev, DSI_CTRL, r);
3807}
3808
Archit Taneja9e7e9372012-08-14 12:29:22 +05303809static void dsi_config_blanking_modes(struct platform_device *dsidev)
Archit Taneja8af6ff02011-09-05 16:48:27 +05303810{
Archit Taneja0b3ffe32012-08-13 22:13:39 +05303811 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3812 int blanking_mode = dsi->vm_timings.blanking_mode;
3813 int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
3814 int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
3815 int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
Archit Taneja8af6ff02011-09-05 16:48:27 +05303816 u32 r;
3817
3818 /*
3819 * 0 = TX FIFO packets sent or LPS in corresponding blanking periods
3820 * 1 = Long blanking packets are sent in corresponding blanking periods
3821 */
3822 r = dsi_read_reg(dsidev, DSI_CTRL);
3823 r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */
3824 r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */
3825 r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */
3826 r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */
3827 dsi_write_reg(dsidev, DSI_CTRL, r);
3828}
3829
Archit Taneja6f28c292012-05-15 11:32:18 +05303830/*
3831 * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3
3832 * results in maximum transition time for data and clock lanes to enter and
3833 * exit HS mode. Hence, this is the scenario where the least amount of command
3834 * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS
3835 * clock cycles that can be used to interleave command mode data in HS so that
3836 * all scenarios are satisfied.
3837 */
3838static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs,
3839 int exit_hs, int exiths_clk, int ddr_pre, int ddr_post)
3840{
3841 int transition;
3842
3843 /*
3844 * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition
3845 * time of data lanes only, if it isn't set, we need to consider HS
3846 * transition time of both data and clock lanes. HS transition time
3847 * of Scenario 3 is considered.
3848 */
3849 if (ddr_alwon) {
3850 transition = enter_hs + exit_hs + max(enter_hs, 2) + 1;
3851 } else {
3852 int trans1, trans2;
3853 trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1;
3854 trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre +
3855 enter_hs + 1;
3856 transition = max(trans1, trans2);
3857 }
3858
3859 return blank > transition ? blank - transition : 0;
3860}
3861
3862/*
3863 * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1
3864 * results in maximum transition time for data lanes to enter and exit LP mode.
3865 * Hence, this is the scenario where the least amount of command mode data can
3866 * be interleaved. We program the minimum amount of bytes that can be
3867 * interleaved in LP so that all scenarios are satisfied.
3868 */
3869static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
3870 int lp_clk_div, int tdsi_fclk)
3871{
3872 int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */
3873 int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */
3874 int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */
3875 int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */
3876 int lp_inter; /* cmd mode data that can be interleaved, in bytes */
3877
3878 /* maximum LP transition time according to Scenario 1 */
3879 trans_lp = exit_hs + max(enter_hs, 2) + 1;
3880
3881 /* CLKIN4DDR = 16 * TXBYTECLKHS */
3882 tlp_avail = thsbyte_clk * (blank - trans_lp);
3883
Archit Taneja2e063c32012-06-04 13:36:34 +05303884 ttxclkesc = tdsi_fclk * lp_clk_div;
Archit Taneja6f28c292012-05-15 11:32:18 +05303885
3886 lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc -
3887 26) / 16;
3888
3889 return max(lp_inter, 0);
3890}
3891
3892static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
3893{
3894 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3895 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3896 int blanking_mode;
3897 int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
3898 int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
3899 int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
3900 int tclk_trail, ths_exit, exiths_clk;
3901 bool ddr_alwon;
Archit Tanejae67458a2012-08-13 14:17:30 +05303902 struct omap_video_timings *timings = &dsi->timings;
Archit Taneja02c39602012-08-10 15:01:33 +05303903 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
Archit Taneja6f28c292012-05-15 11:32:18 +05303904 int ndl = dsi->num_lanes_used - 1;
3905 int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
3906 int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
3907 int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
3908 int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
3909 int bl_interleave_hs = 0, bl_interleave_lp = 0;
3910 u32 r;
3911
3912 r = dsi_read_reg(dsidev, DSI_CTRL);
3913 blanking_mode = FLD_GET(r, 20, 20);
3914 hfp_blanking_mode = FLD_GET(r, 21, 21);
3915 hbp_blanking_mode = FLD_GET(r, 22, 22);
3916 hsa_blanking_mode = FLD_GET(r, 23, 23);
3917
3918 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
3919 hbp = FLD_GET(r, 11, 0);
3920 hfp = FLD_GET(r, 23, 12);
3921 hsa = FLD_GET(r, 31, 24);
3922
3923 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
3924 ddr_clk_post = FLD_GET(r, 7, 0);
3925 ddr_clk_pre = FLD_GET(r, 15, 8);
3926
3927 r = dsi_read_reg(dsidev, DSI_VM_TIMING7);
3928 exit_hs_mode_lat = FLD_GET(r, 15, 0);
3929 enter_hs_mode_lat = FLD_GET(r, 31, 16);
3930
3931 r = dsi_read_reg(dsidev, DSI_CLK_CTRL);
3932 lp_clk_div = FLD_GET(r, 12, 0);
3933 ddr_alwon = FLD_GET(r, 13, 13);
3934
3935 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
3936 ths_exit = FLD_GET(r, 7, 0);
3937
3938 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
3939 tclk_trail = FLD_GET(r, 15, 8);
3940
3941 exiths_clk = ths_exit + tclk_trail;
3942
3943 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
3944 bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl);
3945
3946 if (!hsa_blanking_mode) {
3947 hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon,
3948 enter_hs_mode_lat, exit_hs_mode_lat,
3949 exiths_clk, ddr_clk_pre, ddr_clk_post);
3950 hsa_interleave_lp = dsi_compute_interleave_lp(hsa,
3951 enter_hs_mode_lat, exit_hs_mode_lat,
3952 lp_clk_div, dsi_fclk_hsdiv);
3953 }
3954
3955 if (!hfp_blanking_mode) {
3956 hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon,
3957 enter_hs_mode_lat, exit_hs_mode_lat,
3958 exiths_clk, ddr_clk_pre, ddr_clk_post);
3959 hfp_interleave_lp = dsi_compute_interleave_lp(hfp,
3960 enter_hs_mode_lat, exit_hs_mode_lat,
3961 lp_clk_div, dsi_fclk_hsdiv);
3962 }
3963
3964 if (!hbp_blanking_mode) {
3965 hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon,
3966 enter_hs_mode_lat, exit_hs_mode_lat,
3967 exiths_clk, ddr_clk_pre, ddr_clk_post);
3968
3969 hbp_interleave_lp = dsi_compute_interleave_lp(hbp,
3970 enter_hs_mode_lat, exit_hs_mode_lat,
3971 lp_clk_div, dsi_fclk_hsdiv);
3972 }
3973
3974 if (!blanking_mode) {
3975 bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon,
3976 enter_hs_mode_lat, exit_hs_mode_lat,
3977 exiths_clk, ddr_clk_pre, ddr_clk_post);
3978
3979 bl_interleave_lp = dsi_compute_interleave_lp(bllp,
3980 enter_hs_mode_lat, exit_hs_mode_lat,
3981 lp_clk_div, dsi_fclk_hsdiv);
3982 }
3983
3984 DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3985 hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs,
3986 bl_interleave_hs);
3987
3988 DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3989 hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp,
3990 bl_interleave_lp);
3991
3992 r = dsi_read_reg(dsidev, DSI_VM_TIMING4);
3993 r = FLD_MOD(r, hsa_interleave_hs, 23, 16);
3994 r = FLD_MOD(r, hfp_interleave_hs, 15, 8);
3995 r = FLD_MOD(r, hbp_interleave_hs, 7, 0);
3996 dsi_write_reg(dsidev, DSI_VM_TIMING4, r);
3997
3998 r = dsi_read_reg(dsidev, DSI_VM_TIMING5);
3999 r = FLD_MOD(r, hsa_interleave_lp, 23, 16);
4000 r = FLD_MOD(r, hfp_interleave_lp, 15, 8);
4001 r = FLD_MOD(r, hbp_interleave_lp, 7, 0);
4002 dsi_write_reg(dsidev, DSI_VM_TIMING5, r);
4003
4004 r = dsi_read_reg(dsidev, DSI_VM_TIMING6);
4005 r = FLD_MOD(r, bl_interleave_hs, 31, 15);
4006 r = FLD_MOD(r, bl_interleave_lp, 16, 0);
4007 dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
4008}
4009
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004010static int dsi_proto_config(struct omap_dss_device *dssdev)
4011{
4012 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Taneja02c39602012-08-10 15:01:33 +05304013 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004014 u32 r;
4015 int buswidth = 0;
4016
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304017 dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
Tomi Valkeinendd8079d2009-12-16 16:49:03 +02004018 DSI_FIFO_SIZE_32,
4019 DSI_FIFO_SIZE_32,
4020 DSI_FIFO_SIZE_32);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004021
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304022 dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
Tomi Valkeinendd8079d2009-12-16 16:49:03 +02004023 DSI_FIFO_SIZE_32,
4024 DSI_FIFO_SIZE_32,
4025 DSI_FIFO_SIZE_32);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004026
4027 /* XXX what values for the timeouts? */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304028 dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
4029 dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
4030 dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
4031 dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004032
Archit Taneja02c39602012-08-10 15:01:33 +05304033 switch (dsi_get_pixel_size(dsi->pix_fmt)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004034 case 16:
4035 buswidth = 0;
4036 break;
4037 case 18:
4038 buswidth = 1;
4039 break;
4040 case 24:
4041 buswidth = 2;
4042 break;
4043 default:
4044 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03004045 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004046 }
4047
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304048 r = dsi_read_reg(dsidev, DSI_CTRL);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004049 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
4050 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
4051 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
4052 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
4053 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
4054 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004055 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
4056 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
Archit Taneja9613c022011-03-22 06:33:36 -05004057 if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
4058 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
4059 /* DCS_CMD_CODE, 1=start, 0=continue */
4060 r = FLD_MOD(r, 0, 25, 25);
4061 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004062
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304063 dsi_write_reg(dsidev, DSI_CTRL, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004064
Archit Taneja9e7e9372012-08-14 12:29:22 +05304065 dsi_config_vp_num_line_buffers(dsidev);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304066
Archit Tanejadca2b152012-08-16 18:02:00 +05304067 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Archit Taneja9e7e9372012-08-14 12:29:22 +05304068 dsi_config_vp_sync_events(dsidev);
4069 dsi_config_blanking_modes(dsidev);
Archit Taneja6f28c292012-05-15 11:32:18 +05304070 dsi_config_cmd_mode_interleaving(dssdev);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304071 }
4072
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304073 dsi_vc_initial_config(dsidev, 0);
4074 dsi_vc_initial_config(dsidev, 1);
4075 dsi_vc_initial_config(dsidev, 2);
4076 dsi_vc_initial_config(dsidev, 3);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004077
4078 return 0;
4079}
4080
Archit Taneja9e7e9372012-08-14 12:29:22 +05304081static void dsi_proto_timings(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004082{
Tomi Valkeinendb186442011-10-13 16:12:29 +03004083 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004084 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
4085 unsigned tclk_pre, tclk_post;
4086 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
4087 unsigned ths_trail, ths_exit;
4088 unsigned ddr_clk_pre, ddr_clk_post;
4089 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
4090 unsigned ths_eot;
Tomi Valkeinendb186442011-10-13 16:12:29 +03004091 int ndl = dsi->num_lanes_used - 1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004092 u32 r;
4093
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304094 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004095 ths_prepare = FLD_GET(r, 31, 24);
4096 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
4097 ths_zero = ths_prepare_ths_zero - ths_prepare;
4098 ths_trail = FLD_GET(r, 15, 8);
4099 ths_exit = FLD_GET(r, 7, 0);
4100
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304101 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
Tomi Valkeinene84dc1c2012-09-24 09:34:52 +03004102 tlpx = FLD_GET(r, 20, 16) * 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004103 tclk_trail = FLD_GET(r, 15, 8);
4104 tclk_zero = FLD_GET(r, 7, 0);
4105
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304106 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004107 tclk_prepare = FLD_GET(r, 7, 0);
4108
4109 /* min 8*UI */
4110 tclk_pre = 20;
4111 /* min 60ns + 52*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304112 tclk_post = ns2ddr(dsidev, 60) + 26;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004113
Archit Taneja8af6ff02011-09-05 16:48:27 +05304114 ths_eot = DIV_ROUND_UP(4, ndl);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004115
4116 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
4117 4);
4118 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
4119
4120 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
4121 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
4122
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304123 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004124 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
4125 r = FLD_MOD(r, ddr_clk_post, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304126 dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004127
4128 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
4129 ddr_clk_pre,
4130 ddr_clk_post);
4131
4132 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
4133 DIV_ROUND_UP(ths_prepare, 4) +
4134 DIV_ROUND_UP(ths_zero + 3, 4);
4135
4136 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
4137
4138 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
4139 FLD_VAL(exit_hs_mode_lat, 15, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304140 dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004141
4142 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
4143 enter_hs_mode_lat, exit_hs_mode_lat);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304144
Archit Tanejadca2b152012-08-16 18:02:00 +05304145 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Archit Taneja8af6ff02011-09-05 16:48:27 +05304146 /* TODO: Implement a video mode check_timings function */
Archit Taneja0b3ffe32012-08-13 22:13:39 +05304147 int hsa = dsi->vm_timings.hsa;
4148 int hfp = dsi->vm_timings.hfp;
4149 int hbp = dsi->vm_timings.hbp;
4150 int vsa = dsi->vm_timings.vsa;
4151 int vfp = dsi->vm_timings.vfp;
4152 int vbp = dsi->vm_timings.vbp;
4153 int window_sync = dsi->vm_timings.window_sync;
4154 bool hsync_end = dsi->vm_timings.vp_hsync_end;
Archit Tanejae67458a2012-08-13 14:17:30 +05304155 struct omap_video_timings *timings = &dsi->timings;
Archit Taneja02c39602012-08-10 15:01:33 +05304156 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304157 int tl, t_he, width_bytes;
4158
4159 t_he = hsync_end ?
4160 ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
4161
4162 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
4163
4164 /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */
4165 tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp +
4166 DIV_ROUND_UP(width_bytes + 6, ndl) + hbp;
4167
4168 DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp,
4169 hfp, hsync_end ? hsa : 0, tl);
4170 DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp,
4171 vsa, timings->y_res);
4172
4173 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
4174 r = FLD_MOD(r, hbp, 11, 0); /* HBP */
4175 r = FLD_MOD(r, hfp, 23, 12); /* HFP */
4176 r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */
4177 dsi_write_reg(dsidev, DSI_VM_TIMING1, r);
4178
4179 r = dsi_read_reg(dsidev, DSI_VM_TIMING2);
4180 r = FLD_MOD(r, vbp, 7, 0); /* VBP */
4181 r = FLD_MOD(r, vfp, 15, 8); /* VFP */
4182 r = FLD_MOD(r, vsa, 23, 16); /* VSA */
4183 r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */
4184 dsi_write_reg(dsidev, DSI_VM_TIMING2, r);
4185
4186 r = dsi_read_reg(dsidev, DSI_VM_TIMING3);
4187 r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */
4188 r = FLD_MOD(r, tl, 31, 16); /* TL */
4189 dsi_write_reg(dsidev, DSI_VM_TIMING3, r);
4190 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004191}
4192
Tomi Valkeinene4a9e942012-03-28 15:58:56 +03004193int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
4194 const struct omap_dsi_pin_config *pin_cfg)
4195{
4196 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4197 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4198 int num_pins;
4199 const int *pins;
4200 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
4201 int num_lanes;
4202 int i;
4203
4204 static const enum dsi_lane_function functions[] = {
4205 DSI_LANE_CLK,
4206 DSI_LANE_DATA1,
4207 DSI_LANE_DATA2,
4208 DSI_LANE_DATA3,
4209 DSI_LANE_DATA4,
4210 };
4211
4212 num_pins = pin_cfg->num_pins;
4213 pins = pin_cfg->pins;
4214
4215 if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
4216 || num_pins % 2 != 0)
4217 return -EINVAL;
4218
4219 for (i = 0; i < DSI_MAX_NR_LANES; ++i)
4220 lanes[i].function = DSI_LANE_UNUSED;
4221
4222 num_lanes = 0;
4223
4224 for (i = 0; i < num_pins; i += 2) {
4225 u8 lane, pol;
4226 int dx, dy;
4227
4228 dx = pins[i];
4229 dy = pins[i + 1];
4230
4231 if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
4232 return -EINVAL;
4233
4234 if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
4235 return -EINVAL;
4236
4237 if (dx & 1) {
4238 if (dy != dx - 1)
4239 return -EINVAL;
4240 pol = 1;
4241 } else {
4242 if (dy != dx + 1)
4243 return -EINVAL;
4244 pol = 0;
4245 }
4246
4247 lane = dx / 2;
4248
4249 lanes[lane].function = functions[i / 2];
4250 lanes[lane].polarity = pol;
4251 num_lanes++;
4252 }
4253
4254 memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
4255 dsi->num_lanes_used = num_lanes;
4256
4257 return 0;
4258}
4259EXPORT_SYMBOL(omapdss_dsi_configure_pins);
4260
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004261int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
4262 unsigned long ddr_clk, unsigned long lp_clk)
4263{
4264 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4265 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4266 struct dsi_clock_info cinfo;
4267 struct dispc_clock_info dispc_cinfo;
4268 unsigned lp_clk_div;
4269 unsigned long dsi_fclk;
4270 int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
4271 unsigned long pck;
4272 int r;
4273
4274 DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
4275
4276 mutex_lock(&dsi->lock);
4277
Tomi Valkeinend66b1582012-09-24 15:15:06 +03004278 /* Calculate PLL output clock */
4279 r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004280 if (r)
4281 goto err;
4282
Tomi Valkeinend66b1582012-09-24 15:15:06 +03004283 /* Calculate PLL's DSI clock */
4284 dsi_pll_calc_dsi_fck(dsidev, &cinfo);
4285
4286 /* Calculate PLL's DISPC clock and pck & lck divs */
4287 pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
4288 DSSDBG("finding dispc dividers for pck %lu\n", pck);
4289 r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
4290 if (r)
4291 goto err;
4292
4293 /* Calculate LP clock */
4294 dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
4295 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
4296
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004297 dssdev->clocks.dsi.regn = cinfo.regn;
4298 dssdev->clocks.dsi.regm = cinfo.regm;
4299 dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
4300 dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
4301
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004302 dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
4303
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004304 dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
4305 dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
4306
Tomi Valkeinenee144e62012-08-10 16:50:51 +03004307 dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
4308
4309 dssdev->clocks.dispc.channel.lcd_clk_src =
4310 dsi->module_id == 0 ?
4311 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
4312 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
4313
4314 dssdev->clocks.dsi.dsi_fclk_src =
4315 dsi->module_id == 0 ?
4316 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
4317 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI;
4318
4319 mutex_unlock(&dsi->lock);
4320 return 0;
4321err:
4322 mutex_unlock(&dsi->lock);
4323 return r;
4324}
4325EXPORT_SYMBOL(omapdss_dsi_set_clocks);
4326
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004327int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
Archit Taneja8af6ff02011-09-05 16:48:27 +05304328{
4329 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejae67458a2012-08-13 14:17:30 +05304330 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja02c39602012-08-10 15:01:33 +05304331 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304332 u8 data_type;
4333 u16 word_count;
Tomi Valkeinen33ca2372011-11-21 13:42:58 +02004334 int r;
Archit Taneja8af6ff02011-09-05 16:48:27 +05304335
Archit Tanejadca2b152012-08-16 18:02:00 +05304336 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Archit Taneja02c39602012-08-10 15:01:33 +05304337 switch (dsi->pix_fmt) {
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004338 case OMAP_DSS_DSI_FMT_RGB888:
4339 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
4340 break;
4341 case OMAP_DSS_DSI_FMT_RGB666:
4342 data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
4343 break;
4344 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
4345 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
4346 break;
4347 case OMAP_DSS_DSI_FMT_RGB565:
4348 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
4349 break;
4350 default:
4351 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03004352 return -EINVAL;
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004353 };
Archit Taneja8af6ff02011-09-05 16:48:27 +05304354
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004355 dsi_if_enable(dsidev, false);
4356 dsi_vc_enable(dsidev, channel, false);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304357
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004358 /* MODE, 1 = video mode */
4359 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304360
Archit Tanejae67458a2012-08-13 14:17:30 +05304361 word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304362
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004363 dsi_vc_write_long_header(dsidev, channel, data_type,
4364 word_count, 0);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304365
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004366 dsi_vc_enable(dsidev, channel, true);
4367 dsi_if_enable(dsidev, true);
4368 }
Archit Taneja8af6ff02011-09-05 16:48:27 +05304369
Tomi Valkeinen33ca2372011-11-21 13:42:58 +02004370 r = dss_mgr_enable(dssdev->manager);
4371 if (r) {
Archit Tanejadca2b152012-08-16 18:02:00 +05304372 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Tomi Valkeinen33ca2372011-11-21 13:42:58 +02004373 dsi_if_enable(dsidev, false);
4374 dsi_vc_enable(dsidev, channel, false);
4375 }
4376
4377 return r;
4378 }
Archit Taneja8af6ff02011-09-05 16:48:27 +05304379
4380 return 0;
4381}
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004382EXPORT_SYMBOL(dsi_enable_video_output);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304383
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004384void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
Archit Taneja8af6ff02011-09-05 16:48:27 +05304385{
4386 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejadca2b152012-08-16 18:02:00 +05304387 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304388
Archit Tanejadca2b152012-08-16 18:02:00 +05304389 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004390 dsi_if_enable(dsidev, false);
4391 dsi_vc_enable(dsidev, channel, false);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304392
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004393 /* MODE, 0 = command mode */
4394 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304395
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004396 dsi_vc_enable(dsidev, channel, true);
4397 dsi_if_enable(dsidev, true);
4398 }
Archit Taneja8af6ff02011-09-05 16:48:27 +05304399
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02004400 dss_mgr_disable(dssdev->manager);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304401}
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02004402EXPORT_SYMBOL(dsi_disable_video_output);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304403
Archit Taneja55cd63a2012-08-09 15:41:13 +05304404static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004405{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304406 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304407 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004408 unsigned bytespp;
4409 unsigned bytespl;
4410 unsigned bytespf;
4411 unsigned total_len;
4412 unsigned packet_payload;
4413 unsigned packet_len;
4414 u32 l;
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03004415 int r;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304416 const unsigned channel = dsi->update_channel;
Archit Taneja0c656222011-05-16 15:17:09 +05304417 const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
Archit Taneja55cd63a2012-08-09 15:41:13 +05304418 u16 w = dsi->timings.x_res;
4419 u16 h = dsi->timings.y_res;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004420
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004421 DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004422
Archit Tanejad6049142011-08-22 11:58:08 +05304423 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004424
Archit Taneja02c39602012-08-10 15:01:33 +05304425 bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004426 bytespl = w * bytespp;
4427 bytespf = bytespl * h;
4428
4429 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
4430 * number of lines in a packet. See errata about VP_CLK_RATIO */
4431
4432 if (bytespf < line_buf_size)
4433 packet_payload = bytespf;
4434 else
4435 packet_payload = (line_buf_size) / bytespl * bytespl;
4436
4437 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
4438 total_len = (bytespf / packet_payload) * packet_len;
4439
4440 if (bytespf % packet_payload)
4441 total_len += (bytespf % packet_payload) + 1;
4442
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004443 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304444 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004445
Archit Taneja7a7c48f2011-08-25 18:25:03 +05304446 dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE,
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304447 packet_len, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004448
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304449 if (dsi->te_enabled)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004450 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
4451 else
4452 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304453 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004454
4455 /* We put SIDLEMODE to no-idle for the duration of the transfer,
4456 * because DSS interrupts are not capable of waking up the CPU and the
4457 * framedone interrupt could be delayed for quite a long time. I think
4458 * the same goes for any DSS interrupts, but for some reason I have not
4459 * seen the problem anywhere else than here.
4460 */
4461 dispc_disable_sidle();
4462
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304463 dsi_perf_mark_start(dsidev);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004464
Archit Taneja49dbf582011-05-16 15:17:07 +05304465 r = schedule_delayed_work(&dsi->framedone_timeout_work,
4466 msecs_to_jiffies(250));
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03004467 BUG_ON(r == 0);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004468
Archit Taneja55cd63a2012-08-09 15:41:13 +05304469 dss_mgr_set_timings(dssdev->manager, &dsi->timings);
4470
Tomi Valkeinen1cb00172011-11-18 11:14:01 +02004471 dss_mgr_start_update(dssdev->manager);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004472
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304473 if (dsi->te_enabled) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004474 /* disable LP_RX_TO, so that we can receive TE. Time to wait
4475 * for TE is longer than the timer allows */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304476 REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004477
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304478 dsi_vc_send_bta(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004479
4480#ifdef DSI_CATCH_MISSING_TE
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304481 mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004482#endif
4483 }
4484}
4485
4486#ifdef DSI_CATCH_MISSING_TE
4487static void dsi_te_timeout(unsigned long arg)
4488{
4489 DSSERR("TE not received for 250ms!\n");
4490}
4491#endif
4492
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304493static void dsi_handle_framedone(struct platform_device *dsidev, int error)
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004494{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304495 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4496
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004497 /* SIDLEMODE back to smart-idle */
4498 dispc_enable_sidle();
4499
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304500 if (dsi->te_enabled) {
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004501 /* enable LP_RX_TO again after the TE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304502 REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004503 }
4504
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304505 dsi->framedone_callback(error, dsi->framedone_data);
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004506
4507 if (!error)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304508 dsi_perf_show(dsidev, "DISPC");
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004509}
4510
4511static void dsi_framedone_timeout_work_callback(struct work_struct *work)
4512{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304513 struct dsi_data *dsi = container_of(work, struct dsi_data,
4514 framedone_timeout_work.work);
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03004515 /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
4516 * 250ms which would conflict with this timeout work. What should be
4517 * done is first cancel the transfer on the HW, and then cancel the
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004518 * possibly scheduled framedone work. However, cancelling the transfer
4519 * on the HW is buggy, and would probably require resetting the whole
4520 * DSI */
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03004521
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004522 DSSERR("Framedone not received for 250ms!\n");
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004523
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304524 dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004525}
4526
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004527static void dsi_framedone_irq_callback(void *data, u32 mask)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004528{
Archit Taneja9e7e9372012-08-14 12:29:22 +05304529 struct platform_device *dsidev = (struct platform_device *) data;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304530 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4531
Tomi Valkeinenab83b142010-06-09 15:31:01 +03004532 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
4533 * turns itself off. However, DSI still has the pixels in its buffers,
4534 * and is sending the data.
4535 */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004536
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304537 __cancel_delayed_work(&dsi->framedone_timeout_work);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004538
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304539 dsi_handle_framedone(dsidev, 0);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004540}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004541
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004542int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004543 void (*callback)(int, void *), void *data)
4544{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304545 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304546 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004547 u16 dw, dh;
4548
4549 dsi_perf_mark_setup(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304550
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304551 dsi->update_channel = channel;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004552
Tomi Valkeinen4a9e78a2011-08-15 11:22:21 +03004553 dsi->framedone_callback = callback;
4554 dsi->framedone_data = data;
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004555
Archit Tanejae3525742012-08-09 15:23:43 +05304556 dw = dsi->timings.x_res;
4557 dh = dsi->timings.y_res;
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004558
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004559#ifdef DEBUG
4560 dsi->update_bytes = dw * dh *
Archit Taneja02c39602012-08-10 15:01:33 +05304561 dsi_get_pixel_size(dsi->pix_fmt) / 8;
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004562#endif
Archit Taneja55cd63a2012-08-09 15:41:13 +05304563 dsi_update_screen_dispc(dssdev);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02004564
4565 return 0;
4566}
4567EXPORT_SYMBOL(omap_dsi_update);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004568
4569/* Display funcs */
4570
Archit Taneja7d2572f2012-06-29 14:31:07 +05304571static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
4572{
4573 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4574 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4575 struct dispc_clock_info dispc_cinfo;
4576 int r;
4577 unsigned long long fck;
4578
4579 fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
4580
4581 dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
4582 dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
4583
4584 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
4585 if (r) {
4586 DSSERR("Failed to calc dispc clocks\n");
4587 return r;
4588 }
4589
4590 dsi->mgr_config.clock_info = dispc_cinfo;
4591
4592 return 0;
4593}
4594
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004595static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
4596{
Archit Taneja7d2572f2012-06-29 14:31:07 +05304597 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4598 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja7d2572f2012-06-29 14:31:07 +05304599 int r;
4600 u32 irq = 0;
Archit Taneja5a8b5722011-05-12 17:26:29 +05304601
Archit Tanejadca2b152012-08-16 18:02:00 +05304602 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
Archit Tanejae67458a2012-08-13 14:17:30 +05304603 dsi->timings.hsw = 1;
4604 dsi->timings.hfp = 1;
4605 dsi->timings.hbp = 1;
4606 dsi->timings.vsw = 1;
4607 dsi->timings.vfp = 0;
4608 dsi->timings.vbp = 0;
Tomi Valkeinen5476e742011-11-03 16:34:20 +02004609
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05304610 irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304611
4612 r = omap_dispc_register_isr(dsi_framedone_irq_callback,
Archit Taneja9e7e9372012-08-14 12:29:22 +05304613 (void *) dsidev, irq);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304614 if (r) {
4615 DSSERR("can't get FRAMEDONE irq\n");
Archit Taneja7d2572f2012-06-29 14:31:07 +05304616 goto err;
Archit Taneja8af6ff02011-09-05 16:48:27 +05304617 }
4618
Archit Taneja7d2572f2012-06-29 14:31:07 +05304619 dsi->mgr_config.stallmode = true;
4620 dsi->mgr_config.fifohandcheck = true;
Archit Taneja8af6ff02011-09-05 16:48:27 +05304621 } else {
Archit Taneja7d2572f2012-06-29 14:31:07 +05304622 dsi->mgr_config.stallmode = false;
4623 dsi->mgr_config.fifohandcheck = false;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004624 }
4625
Archit Tanejabd5a7b12012-06-26 12:38:31 +05304626 /*
4627 * override interlace, logic level and edge related parameters in
4628 * omap_video_timings with default values
4629 */
Archit Tanejae67458a2012-08-13 14:17:30 +05304630 dsi->timings.interlace = false;
4631 dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4632 dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4633 dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
4634 dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
4635 dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
Archit Tanejabd5a7b12012-06-26 12:38:31 +05304636
Archit Tanejae67458a2012-08-13 14:17:30 +05304637 dss_mgr_set_timings(dssdev->manager, &dsi->timings);
Archit Tanejabd5a7b12012-06-26 12:38:31 +05304638
Archit Taneja7d2572f2012-06-29 14:31:07 +05304639 r = dsi_configure_dispc_clocks(dssdev);
4640 if (r)
4641 goto err1;
4642
4643 dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
4644 dsi->mgr_config.video_port_width =
Archit Taneja02c39602012-08-10 15:01:33 +05304645 dsi_get_pixel_size(dsi->pix_fmt);
Archit Taneja7d2572f2012-06-29 14:31:07 +05304646 dsi->mgr_config.lcden_sig_polarity = 0;
4647
Archit Tanejaf476ae92012-06-29 14:37:03 +05304648 dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
Archit Tanejad21f43b2012-06-21 09:45:11 +05304649
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004650 return 0;
Archit Taneja7d2572f2012-06-29 14:31:07 +05304651err1:
Archit Tanejadca2b152012-08-16 18:02:00 +05304652 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
Archit Taneja7d2572f2012-06-29 14:31:07 +05304653 omap_dispc_unregister_isr(dsi_framedone_irq_callback,
Archit Taneja9e7e9372012-08-14 12:29:22 +05304654 (void *) dsidev, irq);
Archit Taneja7d2572f2012-06-29 14:31:07 +05304655err:
4656 return r;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004657}
4658
4659static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
4660{
Archit Tanejadca2b152012-08-16 18:02:00 +05304661 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4662 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4663
4664 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
Archit Taneja8af6ff02011-09-05 16:48:27 +05304665 u32 irq;
Archit Taneja5a8b5722011-05-12 17:26:29 +05304666
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05304667 irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
Archit Taneja5a8b5722011-05-12 17:26:29 +05304668
Archit Taneja8af6ff02011-09-05 16:48:27 +05304669 omap_dispc_unregister_isr(dsi_framedone_irq_callback,
Archit Taneja9e7e9372012-08-14 12:29:22 +05304670 (void *) dsidev, irq);
Archit Taneja8af6ff02011-09-05 16:48:27 +05304671 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004672}
4673
4674static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
4675{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304676 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004677 struct dsi_clock_info cinfo;
4678 int r;
4679
Tomi Valkeinenc6940a32011-02-22 13:36:10 +02004680 cinfo.regn = dssdev->clocks.dsi.regn;
4681 cinfo.regm = dssdev->clocks.dsi.regm;
4682 cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
4683 cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
Tomi Valkeinenb6e695a2012-03-15 15:22:58 +02004684 r = dsi_calc_clock_rates(dsidev, &cinfo);
Ville Syrjäläebf0a3f2010-04-22 22:50:05 +02004685 if (r) {
4686 DSSERR("Failed to calc dsi clocks\n");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004687 return r;
Ville Syrjäläebf0a3f2010-04-22 22:50:05 +02004688 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004689
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304690 r = dsi_pll_set_clock_div(dsidev, &cinfo);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004691 if (r) {
4692 DSSERR("Failed to set dsi clocks\n");
4693 return r;
4694 }
4695
4696 return 0;
4697}
4698
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004699static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
4700{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304701 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02004702 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004703 int r;
4704
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304705 r = dsi_pll_init(dsidev, true, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004706 if (r)
4707 goto err0;
4708
4709 r = dsi_configure_dsi_clocks(dssdev);
4710 if (r)
4711 goto err1;
4712
Archit Tanejae8881662011-04-12 13:52:24 +05304713 dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02004714 dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
Archit Taneja9613c022011-03-22 06:33:36 -05004715 dss_select_lcd_clk_source(dssdev->manager->id,
Archit Tanejae8881662011-04-12 13:52:24 +05304716 dssdev->clocks.dispc.channel.lcd_clk_src);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004717
4718 DSSDBG("PLL OK\n");
4719
Archit Taneja9e7e9372012-08-14 12:29:22 +05304720 r = dsi_cio_init(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004721 if (r)
4722 goto err2;
4723
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304724 _dsi_print_reset_status(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004725
Archit Taneja9e7e9372012-08-14 12:29:22 +05304726 dsi_proto_timings(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004727 dsi_set_lp_clk_divisor(dssdev);
4728
4729 if (1)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304730 _dsi_print_reset_status(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004731
4732 r = dsi_proto_config(dssdev);
4733 if (r)
4734 goto err3;
4735
4736 /* enable interface */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304737 dsi_vc_enable(dsidev, 0, 1);
4738 dsi_vc_enable(dsidev, 1, 1);
4739 dsi_vc_enable(dsidev, 2, 1);
4740 dsi_vc_enable(dsidev, 3, 1);
4741 dsi_if_enable(dsidev, 1);
4742 dsi_force_tx_stop_mode_io(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004743
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004744 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004745err3:
Archit Taneja9e7e9372012-08-14 12:29:22 +05304746 dsi_cio_uninit(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004747err2:
Archit Taneja89a35e52011-04-12 13:52:23 +05304748 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02004749 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
Tomi Valkeinen5e785092011-08-10 11:25:36 +03004750 dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
4751
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004752err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304753 dsi_pll_uninit(dsidev, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004754err0:
4755 return r;
4756}
4757
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03004758static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004759 bool disconnect_lanes, bool enter_ulps)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004760{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304761 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304762 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304763
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304764 if (enter_ulps && !dsi->ulps_enabled)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304765 dsi_enter_ulps(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03004766
Ville Syrjäläd7370102010-04-22 22:50:09 +02004767 /* disable interface */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304768 dsi_if_enable(dsidev, 0);
4769 dsi_vc_enable(dsidev, 0, 0);
4770 dsi_vc_enable(dsidev, 1, 0);
4771 dsi_vc_enable(dsidev, 2, 0);
4772 dsi_vc_enable(dsidev, 3, 0);
Ville Syrjäläd7370102010-04-22 22:50:09 +02004773
Archit Taneja89a35e52011-04-12 13:52:23 +05304774 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02004775 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
Tomi Valkeinen5e785092011-08-10 11:25:36 +03004776 dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
Archit Taneja9e7e9372012-08-14 12:29:22 +05304777 dsi_cio_uninit(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304778 dsi_pll_uninit(dsidev, disconnect_lanes);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004779}
4780
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004781int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004782{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304783 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304784 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004785 int r = 0;
4786
4787 DSSDBG("dsi_display_enable\n");
4788
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304789 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004790
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304791 mutex_lock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004792
Tomi Valkeinen05e1d602011-06-23 16:38:21 +03004793 if (dssdev->manager == NULL) {
4794 DSSERR("failed to enable display: no manager\n");
4795 r = -ENODEV;
4796 goto err_start_dev;
4797 }
4798
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004799 r = omap_dss_start_device(dssdev);
4800 if (r) {
4801 DSSERR("failed to start device\n");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004802 goto err_start_dev;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004803 }
4804
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004805 r = dsi_runtime_get(dsidev);
4806 if (r)
4807 goto err_get_dsi;
4808
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304809 dsi_enable_pll_clock(dsidev, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004810
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004811 _dsi_initialize_irq(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004812
4813 r = dsi_display_init_dispc(dssdev);
4814 if (r)
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004815 goto err_init_dispc;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004816
4817 r = dsi_display_init_dsi(dssdev);
4818 if (r)
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004819 goto err_init_dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004820
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304821 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004822
4823 return 0;
4824
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004825err_init_dsi:
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004826 dsi_display_uninit_dispc(dssdev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004827err_init_dispc:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304828 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004829 dsi_runtime_put(dsidev);
4830err_get_dsi:
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004831 omap_dss_stop_device(dssdev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004832err_start_dev:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304833 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004834 DSSDBG("dsi_display_enable FAILED\n");
4835 return r;
4836}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004837EXPORT_SYMBOL(omapdss_dsi_display_enable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004838
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03004839void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004840 bool disconnect_lanes, bool enter_ulps)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004841{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304842 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304843 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304844
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004845 DSSDBG("dsi_display_disable\n");
4846
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304847 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004848
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304849 mutex_lock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004850
Tomi Valkeinen15ffa1d2011-06-16 14:34:06 +03004851 dsi_sync_vc(dsidev, 0);
4852 dsi_sync_vc(dsidev, 1);
4853 dsi_sync_vc(dsidev, 2);
4854 dsi_sync_vc(dsidev, 3);
4855
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004856 dsi_display_uninit_dispc(dssdev);
4857
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004858 dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004859
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004860 dsi_runtime_put(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304861 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004862
4863 omap_dss_stop_device(dssdev);
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004864
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304865 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004866}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004867EXPORT_SYMBOL(omapdss_dsi_display_disable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004868
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004869int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004870{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304871 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4872 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4873
4874 dsi->te_enabled = enable;
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004875 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004876}
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004877EXPORT_SYMBOL(omapdss_dsi_enable_te);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004878
Archit Tanejae67458a2012-08-13 14:17:30 +05304879void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
4880 struct omap_video_timings *timings)
4881{
4882 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4883 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4884
4885 mutex_lock(&dsi->lock);
4886
4887 dsi->timings = *timings;
4888
4889 mutex_unlock(&dsi->lock);
4890}
4891EXPORT_SYMBOL(omapdss_dsi_set_timings);
4892
Archit Tanejae3525742012-08-09 15:23:43 +05304893void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
4894{
4895 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4896 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4897
4898 mutex_lock(&dsi->lock);
4899
4900 dsi->timings.x_res = w;
4901 dsi->timings.y_res = h;
4902
4903 mutex_unlock(&dsi->lock);
4904}
4905EXPORT_SYMBOL(omapdss_dsi_set_size);
4906
Archit Taneja02c39602012-08-10 15:01:33 +05304907void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
4908 enum omap_dss_dsi_pixel_format fmt)
4909{
4910 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4911 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4912
4913 mutex_lock(&dsi->lock);
4914
4915 dsi->pix_fmt = fmt;
4916
4917 mutex_unlock(&dsi->lock);
4918}
4919EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
4920
Archit Tanejadca2b152012-08-16 18:02:00 +05304921void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
4922 enum omap_dss_dsi_mode mode)
4923{
4924 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4925 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4926
4927 mutex_lock(&dsi->lock);
4928
4929 dsi->mode = mode;
4930
4931 mutex_unlock(&dsi->lock);
4932}
4933EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
4934
Archit Taneja0b3ffe32012-08-13 22:13:39 +05304935void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
4936 struct omap_dss_dsi_videomode_timings *timings)
4937{
4938 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4939 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4940
4941 mutex_lock(&dsi->lock);
4942
4943 dsi->vm_timings = *timings;
4944
4945 mutex_unlock(&dsi->lock);
4946}
4947EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
4948
Tomi Valkeinen9d8232a2012-03-01 16:58:39 +02004949static int __init dsi_init_display(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004950{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304951 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4952 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4953
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004954 DSSDBG("DSI init\n");
4955
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304956 if (dsi->vdds_dsi_reg == NULL) {
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004957 struct regulator *vdds_dsi;
4958
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304959 vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004960
4961 if (IS_ERR(vdds_dsi)) {
4962 DSSERR("can't get VDDS_DSI regulator\n");
4963 return PTR_ERR(vdds_dsi);
4964 }
4965
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304966 dsi->vdds_dsi_reg = vdds_dsi;
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004967 }
4968
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004969 return 0;
4970}
4971
Archit Taneja5ee3c142011-03-02 12:35:53 +05304972int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
4973{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304974 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4975 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja5ee3c142011-03-02 12:35:53 +05304976 int i;
4977
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304978 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
4979 if (!dsi->vc[i].dssdev) {
4980 dsi->vc[i].dssdev = dssdev;
Archit Taneja5ee3c142011-03-02 12:35:53 +05304981 *channel = i;
4982 return 0;
4983 }
4984 }
4985
4986 DSSERR("cannot get VC for display %s", dssdev->name);
4987 return -ENOSPC;
4988}
4989EXPORT_SYMBOL(omap_dsi_request_vc);
4990
4991int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
4992{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304993 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4994 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4995
Archit Taneja5ee3c142011-03-02 12:35:53 +05304996 if (vc_id < 0 || vc_id > 3) {
4997 DSSERR("VC ID out of range\n");
4998 return -EINVAL;
4999 }
5000
5001 if (channel < 0 || channel > 3) {
5002 DSSERR("Virtual Channel out of range\n");
5003 return -EINVAL;
5004 }
5005
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305006 if (dsi->vc[channel].dssdev != dssdev) {
Archit Taneja5ee3c142011-03-02 12:35:53 +05305007 DSSERR("Virtual Channel not allocated to display %s\n",
5008 dssdev->name);
5009 return -EINVAL;
5010 }
5011
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305012 dsi->vc[channel].vc_id = vc_id;
Archit Taneja5ee3c142011-03-02 12:35:53 +05305013
5014 return 0;
5015}
5016EXPORT_SYMBOL(omap_dsi_set_vc_id);
5017
5018void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
5019{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305020 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5021 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5022
Archit Taneja5ee3c142011-03-02 12:35:53 +05305023 if ((channel >= 0 && channel <= 3) &&
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305024 dsi->vc[channel].dssdev == dssdev) {
5025 dsi->vc[channel].dssdev = NULL;
5026 dsi->vc[channel].vc_id = 0;
Archit Taneja5ee3c142011-03-02 12:35:53 +05305027 }
5028}
5029EXPORT_SYMBOL(omap_dsi_release_vc);
5030
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305031void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
Tomi Valkeinene406f902010-06-09 15:28:12 +03005032{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305033 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
Archit Taneja067a57e2011-03-02 11:57:25 +05305034 DSSERR("%s (%s) not active\n",
Archit Taneja89a35e52011-04-12 13:52:23 +05305035 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
5036 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
Tomi Valkeinene406f902010-06-09 15:28:12 +03005037}
5038
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305039void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
Tomi Valkeinene406f902010-06-09 15:28:12 +03005040{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305041 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
Archit Taneja067a57e2011-03-02 11:57:25 +05305042 DSSERR("%s (%s) not active\n",
Archit Taneja89a35e52011-04-12 13:52:23 +05305043 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
5044 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
Tomi Valkeinene406f902010-06-09 15:28:12 +03005045}
5046
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305047static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
Taneja, Archit49641112011-03-14 23:28:23 -05005048{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305049 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5050
5051 dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
5052 dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
5053 dsi->regm_dispc_max =
5054 dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
5055 dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
5056 dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
5057 dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
5058 dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
Taneja, Archit49641112011-03-14 23:28:23 -05005059}
5060
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005061static int dsi_get_clocks(struct platform_device *dsidev)
5062{
5063 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5064 struct clk *clk;
5065
5066 clk = clk_get(&dsidev->dev, "fck");
5067 if (IS_ERR(clk)) {
5068 DSSERR("can't get fck\n");
5069 return PTR_ERR(clk);
5070 }
5071
5072 dsi->dss_clk = clk;
5073
Tomi Valkeinenbfe4f8d2011-08-04 11:22:54 +03005074 clk = clk_get(&dsidev->dev, "sys_clk");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005075 if (IS_ERR(clk)) {
5076 DSSERR("can't get sys_clk\n");
5077 clk_put(dsi->dss_clk);
5078 dsi->dss_clk = NULL;
5079 return PTR_ERR(clk);
5080 }
5081
5082 dsi->sys_clk = clk;
5083
5084 return 0;
5085}
5086
5087static void dsi_put_clocks(struct platform_device *dsidev)
5088{
5089 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5090
5091 if (dsi->dss_clk)
5092 clk_put(dsi->dss_clk);
5093 if (dsi->sys_clk)
5094 clk_put(dsi->sys_clk);
5095}
5096
Tomi Valkeinen15216532012-09-06 14:29:31 +03005097static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03005098{
Tomi Valkeinen15216532012-09-06 14:29:31 +03005099 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
5100 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5101 const char *def_disp_name = dss_get_default_display_name();
5102 struct omap_dss_device *def_dssdev;
5103 int i;
5104
5105 def_dssdev = NULL;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03005106
5107 for (i = 0; i < pdata->num_devices; ++i) {
5108 struct omap_dss_device *dssdev = pdata->devices[i];
5109
5110 if (dssdev->type != OMAP_DISPLAY_TYPE_DSI)
5111 continue;
5112
5113 if (dssdev->phy.dsi.module != dsi->module_id)
5114 continue;
5115
Tomi Valkeinen15216532012-09-06 14:29:31 +03005116 if (def_dssdev == NULL)
5117 def_dssdev = dssdev;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03005118
Tomi Valkeinen15216532012-09-06 14:29:31 +03005119 if (def_disp_name != NULL &&
5120 strcmp(dssdev->name, def_disp_name) == 0) {
5121 def_dssdev = dssdev;
5122 break;
5123 }
5124 }
5125
5126 return def_dssdev;
5127}
5128
5129static void __init dsi_probe_pdata(struct platform_device *dsidev)
5130{
Tomi Valkeinen52744842012-09-10 13:58:29 +03005131 struct omap_dss_device *plat_dssdev;
Tomi Valkeinen15216532012-09-06 14:29:31 +03005132 struct omap_dss_device *dssdev;
5133 int r;
5134
Tomi Valkeinen52744842012-09-10 13:58:29 +03005135 plat_dssdev = dsi_find_dssdev(dsidev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03005136
Tomi Valkeinen52744842012-09-10 13:58:29 +03005137 if (!plat_dssdev)
5138 return;
5139
5140 dssdev = dss_alloc_and_init_device(&dsidev->dev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03005141 if (!dssdev)
5142 return;
5143
Tomi Valkeinen52744842012-09-10 13:58:29 +03005144 dss_copy_device_pdata(dssdev, plat_dssdev);
5145
Tomi Valkeinen15216532012-09-06 14:29:31 +03005146 r = dsi_init_display(dssdev);
5147 if (r) {
5148 DSSERR("device %s init failed: %d\n", dssdev->name, r);
Tomi Valkeinen52744842012-09-10 13:58:29 +03005149 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03005150 return;
5151 }
5152
Tomi Valkeinen52744842012-09-10 13:58:29 +03005153 r = dss_add_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03005154 if (r) {
5155 DSSERR("device %s register failed: %d\n", dssdev->name, r);
Tomi Valkeinen52744842012-09-10 13:58:29 +03005156 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03005157 return;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03005158 }
5159}
5160
Archit Taneja81b87f52012-09-26 16:30:49 +05305161static void __init dsi_init_output(struct platform_device *dsidev)
5162{
5163 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5164 struct omap_dss_output *out = &dsi->output;
5165
5166 out->pdev = dsidev;
5167 out->id = dsi->module_id == 0 ?
5168 OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
5169
5170 out->type = OMAP_DISPLAY_TYPE_DSI;
5171
5172 dss_register_output(out);
5173}
5174
5175static void __exit dsi_uninit_output(struct platform_device *dsidev)
5176{
5177 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5178 struct omap_dss_output *out = &dsi->output;
5179
5180 dss_unregister_output(out);
5181}
5182
Tomi Valkeinenb98482e2011-05-16 13:52:51 +03005183/* DSI1 HW IP initialisation */
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02005184static int __init omap_dsihw_probe(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005185{
5186 u32 rev;
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005187 int r, i;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00005188 struct resource *dsi_mem;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305189 struct dsi_data *dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005190
Julia Lawall6e2a14d2012-01-24 14:00:45 +01005191 dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL);
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005192 if (!dsi)
5193 return -ENOMEM;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305194
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005195 dsi->module_id = dsidev->id;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305196 dsi->pdev = dsidev;
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005197 dsi_pdev_map[dsi->module_id] = dsidev;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305198 dev_set_drvdata(&dsidev->dev, dsi);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305199
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305200 spin_lock_init(&dsi->irq_lock);
5201 spin_lock_init(&dsi->errors_lock);
5202 dsi->errors = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005203
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02005204#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305205 spin_lock_init(&dsi->irq_stats_lock);
5206 dsi->irq_stats.last_reset = jiffies;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02005207#endif
5208
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305209 mutex_init(&dsi->lock);
5210 sema_init(&dsi->bus_lock, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005211
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305212 INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
5213 dsi_framedone_timeout_work_callback);
5214
5215#ifdef DSI_CATCH_MISSING_TE
5216 init_timer(&dsi->te_timer);
5217 dsi->te_timer.function = dsi_te_timeout;
5218 dsi->te_timer.data = 0;
5219#endif
5220 dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
5221 if (!dsi_mem) {
5222 DSSERR("can't get IORESOURCE_MEM DSI\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005223 return -EINVAL;
archit tanejaaffe3602011-02-23 08:41:03 +00005224 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005225
Julia Lawall6e2a14d2012-01-24 14:00:45 +01005226 dsi->base = devm_ioremap(&dsidev->dev, dsi_mem->start,
5227 resource_size(dsi_mem));
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305228 if (!dsi->base) {
5229 DSSERR("can't ioremap DSI\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005230 return -ENOMEM;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305231 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005232
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305233 dsi->irq = platform_get_irq(dsi->pdev, 0);
5234 if (dsi->irq < 0) {
5235 DSSERR("platform_get_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005236 return -ENODEV;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305237 }
archit tanejaaffe3602011-02-23 08:41:03 +00005238
Julia Lawall6e2a14d2012-01-24 14:00:45 +01005239 r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler,
5240 IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev);
archit tanejaaffe3602011-02-23 08:41:03 +00005241 if (r < 0) {
5242 DSSERR("request_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005243 return r;
archit tanejaaffe3602011-02-23 08:41:03 +00005244 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005245
Archit Taneja5ee3c142011-03-02 12:35:53 +05305246 /* DSI VCs initialization */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305247 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
Archit Tanejad6049142011-08-22 11:58:08 +05305248 dsi->vc[i].source = DSI_VC_SOURCE_L4;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305249 dsi->vc[i].dssdev = NULL;
5250 dsi->vc[i].vc_id = 0;
Archit Taneja5ee3c142011-03-02 12:35:53 +05305251 }
5252
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305253 dsi_calc_clock_param_ranges(dsidev);
Taneja, Archit49641112011-03-14 23:28:23 -05005254
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005255 r = dsi_get_clocks(dsidev);
5256 if (r)
5257 return r;
5258
5259 pm_runtime_enable(&dsidev->dev);
5260
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005261 r = dsi_runtime_get(dsidev);
5262 if (r)
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005263 goto err_runtime_get;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005264
Archit Tanejaa72b64b2011-05-12 17:26:26 +05305265 rev = dsi_read_reg(dsidev, DSI_REVISION);
5266 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005267 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
5268
Tomi Valkeinend9820852011-10-12 15:05:59 +03005269 /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
5270 * of data to 3 by default */
5271 if (dss_has_feature(FEAT_DSI_GNQ))
5272 /* NB_DATA_LANES */
5273 dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
5274 else
5275 dsi->num_lanes_supported = 3;
Archit Taneja75d72472011-05-16 15:17:08 +05305276
Archit Taneja81b87f52012-09-26 16:30:49 +05305277 dsi_init_output(dsidev);
5278
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03005279 dsi_probe_pdata(dsidev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02005280
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005281 dsi_runtime_put(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005282
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005283 if (dsi->module_id == 0)
Tomi Valkeinene40402c2012-03-02 18:01:07 +02005284 dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005285 else if (dsi->module_id == 1)
Tomi Valkeinene40402c2012-03-02 18:01:07 +02005286 dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs);
5287
5288#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005289 if (dsi->module_id == 0)
Tomi Valkeinene40402c2012-03-02 18:01:07 +02005290 dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs);
Tomi Valkeinen11ee9602012-03-09 16:07:39 +02005291 else if (dsi->module_id == 1)
Tomi Valkeinene40402c2012-03-02 18:01:07 +02005292 dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
5293#endif
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005294 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005295
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005296err_runtime_get:
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005297 pm_runtime_disable(&dsidev->dev);
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02005298 dsi_put_clocks(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005299 return r;
5300}
5301
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02005302static int __exit omap_dsihw_remove(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02005303{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305304 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5305
Tomi Valkeinenb98482e2011-05-16 13:52:51 +03005306 WARN_ON(dsi->scp_clk_refcount > 0);
5307
Tomi Valkeinen52744842012-09-10 13:58:29 +03005308 dss_unregister_child_devices(&dsidev->dev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02005309
Archit Taneja81b87f52012-09-26 16:30:49 +05305310 dsi_uninit_output(dsidev);
5311
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005312 pm_runtime_disable(&dsidev->dev);
5313
5314 dsi_put_clocks(dsidev);
5315
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305316 if (dsi->vdds_dsi_reg != NULL) {
5317 if (dsi->vdds_dsi_enabled) {
5318 regulator_disable(dsi->vdds_dsi_reg);
5319 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen88257b22010-12-20 16:26:22 +02005320 }
5321
Archit Tanejaf1da39d2011-05-12 17:26:27 +05305322 regulator_put(dsi->vdds_dsi_reg);
5323 dsi->vdds_dsi_reg = NULL;
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005324 }
5325
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005326 return 0;
5327}
5328
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005329static int dsi_runtime_suspend(struct device *dev)
5330{
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005331 dispc_runtime_put();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005332
5333 return 0;
5334}
5335
5336static int dsi_runtime_resume(struct device *dev)
5337{
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005338 int r;
5339
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005340 r = dispc_runtime_get();
5341 if (r)
Tomi Valkeinen852f0832012-02-17 17:58:04 +02005342 return r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005343
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005344 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005345}
5346
5347static const struct dev_pm_ops dsi_pm_ops = {
5348 .runtime_suspend = dsi_runtime_suspend,
5349 .runtime_resume = dsi_runtime_resume,
5350};
5351
Tomi Valkeinen7c68dd92011-08-03 14:00:57 +03005352static struct platform_driver omap_dsihw_driver = {
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02005353 .remove = __exit_p(omap_dsihw_remove),
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005354 .driver = {
Tomi Valkeinen7c68dd92011-08-03 14:00:57 +03005355 .name = "omapdss_dsi",
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005356 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03005357 .pm = &dsi_pm_ops,
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005358 },
5359};
5360
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02005361int __init dsi_init_platform_driver(void)
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005362{
Tomi Valkeinen61055d42012-03-07 12:53:38 +02005363 return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe);
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005364}
5365
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02005366void __exit dsi_uninit_platform_driver(void)
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005367{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02005368 platform_driver_unregister(&omap_dsihw_driver);
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00005369}