blob: 762b0fe1dc1930ae80d2db2629493be824a0e8aa [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>
Tomi Valkeinenb9eb5d72010-01-11 16:33:56 +020030#include <linux/semaphore.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020031#include <linux/seq_file.h>
32#include <linux/platform_device.h>
33#include <linux/regulator/consumer.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020034#include <linux/wait.h>
Tomi Valkeinen18946f62010-01-12 14:16:41 +020035#include <linux/workqueue.h>
Tomi Valkeinen40885ab2010-07-28 15:53:38 +030036#include <linux/sched.h>
Archit Tanejaf1da39d2011-05-12 17:26:27 +053037#include <linux/slab.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020038
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030039#include <video/omapdss.h>
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020040#include <plat/clock.h>
41
42#include "dss.h"
Archit Taneja819d8072011-03-01 11:54:00 +053043#include "dss_features.h"
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020044
45/*#define VERBOSE_IRQ*/
46#define DSI_CATCH_MISSING_TE
47
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020048struct dsi_reg { u16 idx; };
49
50#define DSI_REG(idx) ((const struct dsi_reg) { idx })
51
52#define DSI_SZ_REGS SZ_1K
53/* DSI Protocol Engine */
54
55#define DSI_REVISION DSI_REG(0x0000)
56#define DSI_SYSCONFIG DSI_REG(0x0010)
57#define DSI_SYSSTATUS DSI_REG(0x0014)
58#define DSI_IRQSTATUS DSI_REG(0x0018)
59#define DSI_IRQENABLE DSI_REG(0x001C)
60#define DSI_CTRL DSI_REG(0x0040)
61#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
62#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
63#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
64#define DSI_CLK_CTRL DSI_REG(0x0054)
65#define DSI_TIMING1 DSI_REG(0x0058)
66#define DSI_TIMING2 DSI_REG(0x005C)
67#define DSI_VM_TIMING1 DSI_REG(0x0060)
68#define DSI_VM_TIMING2 DSI_REG(0x0064)
69#define DSI_VM_TIMING3 DSI_REG(0x0068)
70#define DSI_CLK_TIMING DSI_REG(0x006C)
71#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
72#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
73#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
74#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
75#define DSI_VM_TIMING4 DSI_REG(0x0080)
76#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
77#define DSI_VM_TIMING5 DSI_REG(0x0088)
78#define DSI_VM_TIMING6 DSI_REG(0x008C)
79#define DSI_VM_TIMING7 DSI_REG(0x0090)
80#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
81#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
82#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
83#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
84#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
85#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
86#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
87#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
88
89/* DSIPHY_SCP */
90
91#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
92#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
93#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
94#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +030095#define DSI_DSIPHY_CFG10 DSI_REG(0x200 + 0x0028)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +020096
97/* DSI_PLL_CTRL_SCP */
98
99#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
100#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
101#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
102#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
103#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
104
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530105#define REG_GET(dsidev, idx, start, end) \
106 FLD_GET(dsi_read_reg(dsidev, idx), start, end)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200107
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530108#define REG_FLD_MOD(dsidev, idx, val, start, end) \
109 dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200110
111/* Global interrupts */
112#define DSI_IRQ_VC0 (1 << 0)
113#define DSI_IRQ_VC1 (1 << 1)
114#define DSI_IRQ_VC2 (1 << 2)
115#define DSI_IRQ_VC3 (1 << 3)
116#define DSI_IRQ_WAKEUP (1 << 4)
117#define DSI_IRQ_RESYNC (1 << 5)
118#define DSI_IRQ_PLL_LOCK (1 << 7)
119#define DSI_IRQ_PLL_UNLOCK (1 << 8)
120#define DSI_IRQ_PLL_RECALL (1 << 9)
121#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
122#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
123#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
124#define DSI_IRQ_TE_TRIGGER (1 << 16)
125#define DSI_IRQ_ACK_TRIGGER (1 << 17)
126#define DSI_IRQ_SYNC_LOST (1 << 18)
127#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
128#define DSI_IRQ_TA_TIMEOUT (1 << 20)
129#define DSI_IRQ_ERROR_MASK \
130 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
131 DSI_IRQ_TA_TIMEOUT)
132#define DSI_IRQ_CHANNEL_MASK 0xf
133
134/* Virtual channel interrupts */
135#define DSI_VC_IRQ_CS (1 << 0)
136#define DSI_VC_IRQ_ECC_CORR (1 << 1)
137#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
138#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
139#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
140#define DSI_VC_IRQ_BTA (1 << 5)
141#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
142#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
143#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
144#define DSI_VC_IRQ_ERROR_MASK \
145 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
146 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
147 DSI_VC_IRQ_FIFO_TX_UDF)
148
149/* ComplexIO interrupts */
150#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
151#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
152#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200153#define DSI_CIO_IRQ_ERRSYNCESC4 (1 << 3)
154#define DSI_CIO_IRQ_ERRSYNCESC5 (1 << 4)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200155#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
156#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
157#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200158#define DSI_CIO_IRQ_ERRESC4 (1 << 8)
159#define DSI_CIO_IRQ_ERRESC5 (1 << 9)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200160#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
161#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
162#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200163#define DSI_CIO_IRQ_ERRCONTROL4 (1 << 13)
164#define DSI_CIO_IRQ_ERRCONTROL5 (1 << 14)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200165#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
166#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
167#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200168#define DSI_CIO_IRQ_STATEULPS4 (1 << 18)
169#define DSI_CIO_IRQ_STATEULPS5 (1 << 19)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200170#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
171#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
172#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
173#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
174#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
175#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
Tomi Valkeinen67056152011-03-24 16:30:17 +0200176#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
177#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
178#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
179#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200180#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
181#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
Tomi Valkeinenbbecb502010-05-10 14:35:33 +0300182#define DSI_CIO_IRQ_ERROR_MASK \
183 (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
Tomi Valkeinen67056152011-03-24 16:30:17 +0200184 DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
185 DSI_CIO_IRQ_ERRSYNCESC5 | \
186 DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
187 DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
188 DSI_CIO_IRQ_ERRESC5 | \
189 DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
190 DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
191 DSI_CIO_IRQ_ERRCONTROL5 | \
Tomi Valkeinenbbecb502010-05-10 14:35:33 +0300192 DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
193 DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
Tomi Valkeinen67056152011-03-24 16:30:17 +0200194 DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
195 DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
196 DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200197
198#define DSI_DT_DCS_SHORT_WRITE_0 0x05
199#define DSI_DT_DCS_SHORT_WRITE_1 0x15
200#define DSI_DT_DCS_READ 0x06
201#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37
202#define DSI_DT_NULL_PACKET 0x09
203#define DSI_DT_DCS_LONG_WRITE 0x39
204
205#define DSI_DT_RX_ACK_WITH_ERR 0x02
206#define DSI_DT_RX_DCS_LONG_READ 0x1c
207#define DSI_DT_RX_SHORT_READ_1 0x21
208#define DSI_DT_RX_SHORT_READ_2 0x22
209
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200210typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
211
212#define DSI_MAX_NR_ISRS 2
213
214struct dsi_isr_data {
215 omap_dsi_isr_t isr;
216 void *arg;
217 u32 mask;
218};
219
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200220enum fifo_size {
221 DSI_FIFO_SIZE_0 = 0,
222 DSI_FIFO_SIZE_32 = 1,
223 DSI_FIFO_SIZE_64 = 2,
224 DSI_FIFO_SIZE_96 = 3,
225 DSI_FIFO_SIZE_128 = 4,
226};
227
228enum dsi_vc_mode {
229 DSI_VC_MODE_L4 = 0,
230 DSI_VC_MODE_VP,
231};
232
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +0300233enum dsi_lane {
234 DSI_CLK_P = 1 << 0,
235 DSI_CLK_N = 1 << 1,
236 DSI_DATA1_P = 1 << 2,
237 DSI_DATA1_N = 1 << 3,
238 DSI_DATA2_P = 1 << 4,
239 DSI_DATA2_N = 1 << 5,
240};
241
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200242struct dsi_update_region {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200243 u16 x, y, w, h;
244 struct omap_dss_device *device;
245};
246
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200247struct dsi_irq_stats {
248 unsigned long last_reset;
249 unsigned irq_count;
250 unsigned dsi_irqs[32];
251 unsigned vc_irqs[4][32];
252 unsigned cio_irqs[32];
253};
254
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200255struct dsi_isr_tables {
256 struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
257 struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
258 struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
259};
260
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530261struct dsi_data {
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +0000262 struct platform_device *pdev;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200263 void __iomem *base;
archit tanejaaffe3602011-02-23 08:41:03 +0000264 int irq;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200265
Tomi Valkeinend1f58572010-07-30 11:57:57 +0300266 void (*dsi_mux_pads)(bool enable);
267
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200268 struct dsi_clock_info current_cinfo;
269
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +0300270 bool vdds_dsi_enabled;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200271 struct regulator *vdds_dsi_reg;
272
273 struct {
274 enum dsi_vc_mode mode;
275 struct omap_dss_device *dssdev;
276 enum fifo_size fifo_size;
Archit Taneja5ee3c142011-03-02 12:35:53 +0530277 int vc_id;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200278 } vc[4];
279
280 struct mutex lock;
Tomi Valkeinenb9eb5d72010-01-11 16:33:56 +0200281 struct semaphore bus_lock;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200282
283 unsigned pll_locked;
284
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200285 spinlock_t irq_lock;
286 struct dsi_isr_tables isr_tables;
287 /* space for a copy used by the interrupt handler */
288 struct dsi_isr_tables isr_tables_copy;
289
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200290 int update_channel;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200291 struct dsi_update_region update_region;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200292
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200293 bool te_enabled;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +0300294 bool ulps_enabled;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200295
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +0300296 struct workqueue_struct *workqueue;
297
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200298 void (*framedone_callback)(int, void *);
299 void *framedone_data;
300
301 struct delayed_work framedone_timeout_work;
302
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200303#ifdef DSI_CATCH_MISSING_TE
304 struct timer_list te_timer;
305#endif
306
307 unsigned long cache_req_pck;
308 unsigned long cache_clk_freq;
309 struct dsi_clock_info cache_cinfo;
310
311 u32 errors;
312 spinlock_t errors_lock;
313#ifdef DEBUG
314 ktime_t perf_setup_time;
315 ktime_t perf_start_time;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200316#endif
317 int debug_read;
318 int debug_write;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200319
320#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
321 spinlock_t irq_stats_lock;
322 struct dsi_irq_stats irq_stats;
323#endif
Taneja, Archit49641112011-03-14 23:28:23 -0500324 /* DSI PLL Parameter Ranges */
325 unsigned long regm_max, regn_max;
326 unsigned long regm_dispc_max, regm_dsi_max;
327 unsigned long fint_min, fint_max;
328 unsigned long lpdiv_max;
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +0300329
330 unsigned scp_clk_refcount;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530331};
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200332
Archit Taneja2e868db2011-05-12 17:26:28 +0530333struct dsi_packet_sent_handler_data {
334 struct platform_device *dsidev;
335 struct completion *completion;
336};
337
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530338static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
339
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200340#ifdef DEBUG
341static unsigned int dsi_perf;
342module_param_named(dsi_perf, dsi_perf, bool, 0644);
343#endif
344
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530345static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
346{
347 return dev_get_drvdata(&dsidev->dev);
348}
349
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530350static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
351{
352 return dsi_pdev_map[dssdev->phy.dsi.module];
353}
354
355struct platform_device *dsi_get_dsidev_from_id(int module)
356{
357 return dsi_pdev_map[module];
358}
359
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530360static int dsi_get_dsidev_id(struct platform_device *dsidev)
361{
362 /* TEMP: Pass 0 as the dsi module index till the time the dsi platform
363 * device names aren't changed to the form "omapdss_dsi.0",
364 * "omapdss_dsi.1" and so on */
365 BUG_ON(dsidev->id != -1);
366
367 return 0;
368}
369
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530370static 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
386
387void dsi_save_context(void)
388{
389}
390
391void dsi_restore_context(void)
392{
393}
394
Archit Taneja1ffefe72011-05-12 17:26:24 +0530395void dsi_bus_lock(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 down(&dsi->bus_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200401}
402EXPORT_SYMBOL(dsi_bus_lock);
403
Archit Taneja1ffefe72011-05-12 17:26:24 +0530404void dsi_bus_unlock(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200405{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530406 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
407 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
408
409 up(&dsi->bus_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200410}
411EXPORT_SYMBOL(dsi_bus_unlock);
412
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530413static bool dsi_bus_is_locked(struct platform_device *dsidev)
Tomi Valkeinen4f765022010-01-18 16:27:52 +0200414{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530415 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
416
417 return dsi->bus_lock.count == 0;
Tomi Valkeinen4f765022010-01-18 16:27:52 +0200418}
419
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +0200420static void dsi_completion_handler(void *data, u32 mask)
421{
422 complete((struct completion *)data);
423}
424
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530425static inline int wait_for_bit_change(struct platform_device *dsidev,
426 const struct dsi_reg idx, int bitnum, int value)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200427{
428 int t = 100000;
429
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530430 while (REG_GET(dsidev, idx, bitnum, bitnum) != value) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200431 if (--t == 0)
432 return !value;
433 }
434
435 return value;
436}
437
438#ifdef DEBUG
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530439static void dsi_perf_mark_setup(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200440{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530441 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
442 dsi->perf_setup_time = ktime_get();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200443}
444
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530445static void dsi_perf_mark_start(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200446{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530447 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
448 dsi->perf_start_time = ktime_get();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200449}
450
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530451static void dsi_perf_show(struct platform_device *dsidev, const char *name)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200452{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530453 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200454 ktime_t t, setup_time, trans_time;
455 u32 total_bytes;
456 u32 setup_us, trans_us, total_us;
457
458 if (!dsi_perf)
459 return;
460
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200461 t = ktime_get();
462
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530463 setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200464 setup_us = (u32)ktime_to_us(setup_time);
465 if (setup_us == 0)
466 setup_us = 1;
467
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530468 trans_time = ktime_sub(t, dsi->perf_start_time);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200469 trans_us = (u32)ktime_to_us(trans_time);
470 if (trans_us == 0)
471 trans_us = 1;
472
473 total_us = setup_us + trans_us;
474
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530475 total_bytes = dsi->update_region.w *
476 dsi->update_region.h *
477 dsi->update_region.device->ctrl.pixel_size / 8;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200478
Tomi Valkeinen1bbb2752010-01-11 16:41:10 +0200479 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
480 "%u bytes, %u kbytes/sec\n",
481 name,
482 setup_us,
483 trans_us,
484 total_us,
485 1000*1000 / total_us,
486 total_bytes,
487 total_bytes * 1000 / total_us);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200488}
489#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530490#define dsi_perf_mark_setup(x)
491#define dsi_perf_mark_start(x)
492#define dsi_perf_show(x, y)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200493#endif
494
495static void print_irq_status(u32 status)
496{
Tomi Valkeinend80d4992011-03-02 15:53:07 +0200497 if (status == 0)
498 return;
499
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200500#ifndef VERBOSE_IRQ
501 if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
502 return;
503#endif
504 printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
505
506#define PIS(x) \
507 if (status & DSI_IRQ_##x) \
508 printk(#x " ");
509#ifdef VERBOSE_IRQ
510 PIS(VC0);
511 PIS(VC1);
512 PIS(VC2);
513 PIS(VC3);
514#endif
515 PIS(WAKEUP);
516 PIS(RESYNC);
517 PIS(PLL_LOCK);
518 PIS(PLL_UNLOCK);
519 PIS(PLL_RECALL);
520 PIS(COMPLEXIO_ERR);
521 PIS(HS_TX_TIMEOUT);
522 PIS(LP_RX_TIMEOUT);
523 PIS(TE_TRIGGER);
524 PIS(ACK_TRIGGER);
525 PIS(SYNC_LOST);
526 PIS(LDO_POWER_GOOD);
527 PIS(TA_TIMEOUT);
528#undef PIS
529
530 printk("\n");
531}
532
533static void print_irq_status_vc(int channel, u32 status)
534{
Tomi Valkeinend80d4992011-03-02 15:53:07 +0200535 if (status == 0)
536 return;
537
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200538#ifndef VERBOSE_IRQ
539 if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
540 return;
541#endif
542 printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
543
544#define PIS(x) \
545 if (status & DSI_VC_IRQ_##x) \
546 printk(#x " ");
547 PIS(CS);
548 PIS(ECC_CORR);
549#ifdef VERBOSE_IRQ
550 PIS(PACKET_SENT);
551#endif
552 PIS(FIFO_TX_OVF);
553 PIS(FIFO_RX_OVF);
554 PIS(BTA);
555 PIS(ECC_NO_CORR);
556 PIS(FIFO_TX_UDF);
557 PIS(PP_BUSY_CHANGE);
558#undef PIS
559 printk("\n");
560}
561
562static void print_irq_status_cio(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 printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
568
569#define PIS(x) \
570 if (status & DSI_CIO_IRQ_##x) \
571 printk(#x " ");
572 PIS(ERRSYNCESC1);
573 PIS(ERRSYNCESC2);
574 PIS(ERRSYNCESC3);
575 PIS(ERRESC1);
576 PIS(ERRESC2);
577 PIS(ERRESC3);
578 PIS(ERRCONTROL1);
579 PIS(ERRCONTROL2);
580 PIS(ERRCONTROL3);
581 PIS(STATEULPS1);
582 PIS(STATEULPS2);
583 PIS(STATEULPS3);
584 PIS(ERRCONTENTIONLP0_1);
585 PIS(ERRCONTENTIONLP1_1);
586 PIS(ERRCONTENTIONLP0_2);
587 PIS(ERRCONTENTIONLP1_2);
588 PIS(ERRCONTENTIONLP0_3);
589 PIS(ERRCONTENTIONLP1_3);
590 PIS(ULPSACTIVENOT_ALL0);
591 PIS(ULPSACTIVENOT_ALL1);
592#undef PIS
593
594 printk("\n");
595}
596
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200597#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530598static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
599 u32 *vcstatus, u32 ciostatus)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200600{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530601 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200602 int i;
603
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530604 spin_lock(&dsi->irq_stats_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200605
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530606 dsi->irq_stats.irq_count++;
607 dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200608
609 for (i = 0; i < 4; ++i)
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530610 dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200611
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530612 dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200613
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530614 spin_unlock(&dsi->irq_stats_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200615}
616#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530617#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200618#endif
619
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200620static int debug_irq;
621
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530622static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
623 u32 *vcstatus, u32 ciostatus)
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200624{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530625 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200626 int i;
627
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200628 if (irqstatus & DSI_IRQ_ERROR_MASK) {
629 DSSERR("DSI error, irqstatus %x\n", irqstatus);
630 print_irq_status(irqstatus);
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530631 spin_lock(&dsi->errors_lock);
632 dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
633 spin_unlock(&dsi->errors_lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200634 } else if (debug_irq) {
635 print_irq_status(irqstatus);
636 }
637
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200638 for (i = 0; i < 4; ++i) {
639 if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
640 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
641 i, vcstatus[i]);
642 print_irq_status_vc(i, vcstatus[i]);
643 } else if (debug_irq) {
644 print_irq_status_vc(i, vcstatus[i]);
645 }
646 }
647
648 if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
649 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
650 print_irq_status_cio(ciostatus);
651 } else if (debug_irq) {
652 print_irq_status_cio(ciostatus);
653 }
654}
655
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200656static void dsi_call_isrs(struct dsi_isr_data *isr_array,
657 unsigned isr_array_size, u32 irqstatus)
658{
659 struct dsi_isr_data *isr_data;
660 int i;
661
662 for (i = 0; i < isr_array_size; i++) {
663 isr_data = &isr_array[i];
664 if (isr_data->isr && isr_data->mask & irqstatus)
665 isr_data->isr(isr_data->arg, irqstatus);
666 }
667}
668
669static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
670 u32 irqstatus, u32 *vcstatus, u32 ciostatus)
671{
672 int i;
673
674 dsi_call_isrs(isr_tables->isr_table,
675 ARRAY_SIZE(isr_tables->isr_table),
676 irqstatus);
677
678 for (i = 0; i < 4; ++i) {
679 if (vcstatus[i] == 0)
680 continue;
681 dsi_call_isrs(isr_tables->isr_table_vc[i],
682 ARRAY_SIZE(isr_tables->isr_table_vc[i]),
683 vcstatus[i]);
684 }
685
686 if (ciostatus != 0)
687 dsi_call_isrs(isr_tables->isr_table_cio,
688 ARRAY_SIZE(isr_tables->isr_table_cio),
689 ciostatus);
690}
691
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200692static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
693{
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530694 struct platform_device *dsidev;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530695 struct dsi_data *dsi;
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200696 u32 irqstatus, vcstatus[4], ciostatus;
697 int i;
698
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530699 dsidev = (struct platform_device *) arg;
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530700 dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530701
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530702 spin_lock(&dsi->irq_lock);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200703
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530704 irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200705
706 /* IRQ is not for us */
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200707 if (!irqstatus) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530708 spin_unlock(&dsi->irq_lock);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200709 return IRQ_NONE;
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200710 }
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200711
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530712 dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200713 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530714 dsi_read_reg(dsidev, DSI_IRQSTATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200715
716 for (i = 0; i < 4; ++i) {
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200717 if ((irqstatus & (1 << i)) == 0) {
718 vcstatus[i] = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200719 continue;
Tomi Valkeinenab83b142010-06-09 15:31:01 +0300720 }
721
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530722 vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200723
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530724 dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200725 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530726 dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200727 }
728
729 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530730 ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200731
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530732 dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200733 /* flush posted write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530734 dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200735 } else {
736 ciostatus = 0;
737 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200738
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200739#ifdef DSI_CATCH_MISSING_TE
740 if (irqstatus & DSI_IRQ_TE_TRIGGER)
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530741 del_timer(&dsi->te_timer);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200742#endif
743
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200744 /* make a copy and unlock, so that isrs can unregister
745 * themselves */
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530746 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
747 sizeof(dsi->isr_tables));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200748
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530749 spin_unlock(&dsi->irq_lock);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200750
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530751 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200752
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530753 dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200754
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530755 dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
Tomi Valkeinen69b281a2011-03-02 14:44:27 +0200756
archit tanejaaffe3602011-02-23 08:41:03 +0000757 return IRQ_HANDLED;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200758}
759
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530760/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530761static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
762 struct dsi_isr_data *isr_array,
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200763 unsigned isr_array_size, u32 default_mask,
764 const struct dsi_reg enable_reg,
765 const struct dsi_reg status_reg)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200766{
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200767 struct dsi_isr_data *isr_data;
768 u32 mask;
769 u32 old_mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200770 int i;
771
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200772 mask = default_mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200773
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200774 for (i = 0; i < isr_array_size; i++) {
775 isr_data = &isr_array[i];
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200776
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200777 if (isr_data->isr == NULL)
778 continue;
779
780 mask |= isr_data->mask;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200781 }
782
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530783 old_mask = dsi_read_reg(dsidev, enable_reg);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200784 /* clear the irqstatus for newly enabled irqs */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530785 dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
786 dsi_write_reg(dsidev, enable_reg, mask);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200787
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200788 /* flush posted writes */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530789 dsi_read_reg(dsidev, enable_reg);
790 dsi_read_reg(dsidev, status_reg);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200791}
792
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530793/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530794static void _omap_dsi_set_irqs(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200795{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530796 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200797 u32 mask = DSI_IRQ_ERROR_MASK;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200798#ifdef DSI_CATCH_MISSING_TE
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200799 mask |= DSI_IRQ_TE_TRIGGER;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200800#endif
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530801 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
802 ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200803 DSI_IRQENABLE, DSI_IRQSTATUS);
804}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200805
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530806/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530807static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200808{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530809 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
810
811 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
812 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200813 DSI_VC_IRQ_ERROR_MASK,
814 DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
815}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +0200816
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530817/* dsi->irq_lock has to be locked by the caller */
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530818static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200819{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530820 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
821
822 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
823 ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200824 DSI_CIO_IRQ_ERROR_MASK,
825 DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
826}
827
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530828static void _dsi_initialize_irq(struct platform_device *dsidev)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200829{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530830 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200831 unsigned long flags;
832 int vc;
833
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530834 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200835
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530836 memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200837
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530838 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200839 for (vc = 0; vc < 4; ++vc)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530840 _omap_dsi_set_irqs_vc(dsidev, vc);
841 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200842
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530843 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200844}
845
846static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
847 struct dsi_isr_data *isr_array, unsigned isr_array_size)
848{
849 struct dsi_isr_data *isr_data;
850 int free_idx;
851 int i;
852
853 BUG_ON(isr == NULL);
854
855 /* check for duplicate entry and find a free slot */
856 free_idx = -1;
857 for (i = 0; i < isr_array_size; i++) {
858 isr_data = &isr_array[i];
859
860 if (isr_data->isr == isr && isr_data->arg == arg &&
861 isr_data->mask == mask) {
862 return -EINVAL;
863 }
864
865 if (isr_data->isr == NULL && free_idx == -1)
866 free_idx = i;
867 }
868
869 if (free_idx == -1)
870 return -EBUSY;
871
872 isr_data = &isr_array[free_idx];
873 isr_data->isr = isr;
874 isr_data->arg = arg;
875 isr_data->mask = mask;
876
877 return 0;
878}
879
880static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
881 struct dsi_isr_data *isr_array, unsigned isr_array_size)
882{
883 struct dsi_isr_data *isr_data;
884 int i;
885
886 for (i = 0; i < isr_array_size; i++) {
887 isr_data = &isr_array[i];
888 if (isr_data->isr != isr || isr_data->arg != arg ||
889 isr_data->mask != mask)
890 continue;
891
892 isr_data->isr = NULL;
893 isr_data->arg = NULL;
894 isr_data->mask = 0;
895
896 return 0;
897 }
898
899 return -EINVAL;
900}
901
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530902static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
903 void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200904{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530905 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200906 unsigned long flags;
907 int r;
908
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530909 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200910
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530911 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
912 ARRAY_SIZE(dsi->isr_tables.isr_table));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200913
914 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530915 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200916
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530917 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200918
919 return r;
920}
921
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530922static int dsi_unregister_isr(struct platform_device *dsidev,
923 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200924{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530925 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200926 unsigned long flags;
927 int r;
928
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530929 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200930
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530931 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
932 ARRAY_SIZE(dsi->isr_tables.isr_table));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200933
934 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530935 _omap_dsi_set_irqs(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200936
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530937 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200938
939 return r;
940}
941
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530942static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
943 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200944{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530945 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200946 unsigned long flags;
947 int r;
948
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530949 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200950
951 r = _dsi_register_isr(isr, arg, mask,
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530952 dsi->isr_tables.isr_table_vc[channel],
953 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200954
955 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530956 _omap_dsi_set_irqs_vc(dsidev, channel);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200957
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530958 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200959
960 return r;
961}
962
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530963static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
964 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200965{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530966 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200967 unsigned long flags;
968 int r;
969
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530970 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200971
972 r = _dsi_unregister_isr(isr, arg, mask,
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530973 dsi->isr_tables.isr_table_vc[channel],
974 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200975
976 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530977 _omap_dsi_set_irqs_vc(dsidev, channel);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200978
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530979 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200980
981 return r;
982}
983
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530984static int dsi_register_isr_cio(struct platform_device *dsidev,
985 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200986{
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530987 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200988 unsigned long flags;
989 int r;
990
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530991 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200992
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530993 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
994 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200995
996 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +0530997 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +0200998
Archit Tanejaf1da39d2011-05-12 17:26:27 +0530999 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001000
1001 return r;
1002}
1003
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301004static int dsi_unregister_isr_cio(struct platform_device *dsidev,
1005 omap_dsi_isr_t isr, void *arg, u32 mask)
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001006{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301007 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001008 unsigned long flags;
1009 int r;
1010
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301011 spin_lock_irqsave(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001012
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301013 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1014 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001015
1016 if (r == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301017 _omap_dsi_set_irqs_cio(dsidev);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001018
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301019 spin_unlock_irqrestore(&dsi->irq_lock, flags);
Tomi Valkeinen4ae2ddd2011-03-02 14:47:04 +02001020
1021 return r;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001022}
1023
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301024static u32 dsi_get_errors(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001025{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301026 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001027 unsigned long flags;
1028 u32 e;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301029 spin_lock_irqsave(&dsi->errors_lock, flags);
1030 e = dsi->errors;
1031 dsi->errors = 0;
1032 spin_unlock_irqrestore(&dsi->errors_lock, flags);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001033 return e;
1034}
1035
Archit Taneja1bb47832011-02-24 14:17:30 +05301036/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001037static inline void enable_clocks(bool enable)
1038{
1039 if (enable)
Archit Taneja6af9cd12011-01-31 16:27:44 +00001040 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001041 else
Archit Taneja6af9cd12011-01-31 16:27:44 +00001042 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001043}
1044
1045/* source clock for DSI PLL. this could also be PCLKFREE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301046static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
1047 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001048{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301049 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1050
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001051 if (enable)
Archit Taneja6af9cd12011-01-31 16:27:44 +00001052 dss_clk_enable(DSS_CLK_SYSCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001053 else
Archit Taneja6af9cd12011-01-31 16:27:44 +00001054 dss_clk_disable(DSS_CLK_SYSCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001055
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301056 if (enable && dsi->pll_locked) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301057 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001058 DSSERR("cannot lock PLL when enabling clocks\n");
1059 }
1060}
1061
1062#ifdef DEBUG
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301063static void _dsi_print_reset_status(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001064{
1065 u32 l;
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001066 int b0, b1, b2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001067
1068 if (!dss_debug)
1069 return;
1070
1071 /* A dummy read using the SCP interface to any DSIPHY register is
1072 * required after DSIPHY reset to complete the reset of the DSI complex
1073 * I/O. */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301074 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001075
1076 printk(KERN_DEBUG "DSI resets: ");
1077
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301078 l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001079 printk("PLL (%d) ", FLD_GET(l, 0, 0));
1080
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301081 l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001082 printk("CIO (%d) ", FLD_GET(l, 29, 29));
1083
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001084 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
1085 b0 = 28;
1086 b1 = 27;
1087 b2 = 26;
1088 } else {
1089 b0 = 24;
1090 b1 = 25;
1091 b2 = 26;
1092 }
1093
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301094 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinenc335cbf2010-10-07 13:27:42 +03001095 printk("PHY (%x%x%x, %d, %d, %d)\n",
1096 FLD_GET(l, b0, b0),
1097 FLD_GET(l, b1, b1),
1098 FLD_GET(l, b2, b2),
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001099 FLD_GET(l, 29, 29),
1100 FLD_GET(l, 30, 30),
1101 FLD_GET(l, 31, 31));
1102}
1103#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301104#define _dsi_print_reset_status(x)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001105#endif
1106
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301107static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001108{
1109 DSSDBG("dsi_if_enable(%d)\n", enable);
1110
1111 enable = enable ? 1 : 0;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301112 REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001113
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301114 if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001115 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
1116 return -EIO;
1117 }
1118
1119 return 0;
1120}
1121
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301122unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001123{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301124 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1125
1126 return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001127}
1128
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301129static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001130{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301131 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1132
1133 return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001134}
1135
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301136static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001137{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301138 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1139
1140 return dsi->current_cinfo.clkin4ddr / 16;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001141}
1142
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301143static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001144{
1145 unsigned long r;
1146
Archit Taneja89a35e52011-04-12 13:52:23 +05301147 if (dss_get_dsi_clk_source() == OMAP_DSS_CLK_SRC_FCK) {
Archit Taneja1bb47832011-02-24 14:17:30 +05301148 /* DSI FCLK source is DSS_CLK_FCK */
Archit Taneja6af9cd12011-01-31 16:27:44 +00001149 r = dss_clk_get_rate(DSS_CLK_FCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001150 } else {
Archit Taneja1bb47832011-02-24 14:17:30 +05301151 /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301152 r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001153 }
1154
1155 return r;
1156}
1157
1158static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
1159{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301160 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301161 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001162 unsigned long dsi_fclk;
1163 unsigned lp_clk_div;
1164 unsigned long lp_clk;
1165
Tomi Valkeinenc6940a32011-02-22 13:36:10 +02001166 lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001167
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301168 if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001169 return -EINVAL;
1170
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301171 dsi_fclk = dsi_fclk_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001172
1173 lp_clk = dsi_fclk / 2 / lp_clk_div;
1174
1175 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301176 dsi->current_cinfo.lp_clk = lp_clk;
1177 dsi->current_cinfo.lp_clk_div = lp_clk_div;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001178
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301179 /* LP_CLK_DIVISOR */
1180 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001181
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301182 /* LP_RX_SYNCHRO_ENABLE */
1183 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001184
1185 return 0;
1186}
1187
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301188static void dsi_enable_scp_clk(struct platform_device *dsidev)
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001189{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301190 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1191
1192 if (dsi->scp_clk_refcount++ == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301193 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001194}
1195
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301196static void dsi_disable_scp_clk(struct platform_device *dsidev)
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001197{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301198 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1199
1200 WARN_ON(dsi->scp_clk_refcount == 0);
1201 if (--dsi->scp_clk_refcount == 0)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301202 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001203}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001204
1205enum dsi_pll_power_state {
1206 DSI_PLL_POWER_OFF = 0x0,
1207 DSI_PLL_POWER_ON_HSCLK = 0x1,
1208 DSI_PLL_POWER_ON_ALL = 0x2,
1209 DSI_PLL_POWER_ON_DIV = 0x3,
1210};
1211
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301212static int dsi_pll_power(struct platform_device *dsidev,
1213 enum dsi_pll_power_state state)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001214{
1215 int t = 0;
1216
Tomi Valkeinenc94dfe02011-04-15 10:42:59 +03001217 /* DSI-PLL power command 0x3 is not working */
1218 if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
1219 state == DSI_PLL_POWER_ON_DIV)
1220 state = DSI_PLL_POWER_ON_ALL;
1221
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301222 /* PLL_PWR_CMD */
1223 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001224
1225 /* PLL_PWR_STATUS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301226 while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001227 if (++t > 1000) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001228 DSSERR("Failed to set DSI PLL power mode to %d\n",
1229 state);
1230 return -ENODEV;
1231 }
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001232 udelay(1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001233 }
1234
1235 return 0;
1236}
1237
1238/* calculate clock rates using dividers in cinfo */
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001239static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
1240 struct dsi_clock_info *cinfo)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001241{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301242 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
1243 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1244
1245 if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001246 return -EINVAL;
1247
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301248 if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001249 return -EINVAL;
1250
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301251 if (cinfo->regm_dispc > dsi->regm_dispc_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001252 return -EINVAL;
1253
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301254 if (cinfo->regm_dsi > dsi->regm_dsi_max)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001255 return -EINVAL;
1256
Archit Taneja1bb47832011-02-24 14:17:30 +05301257 if (cinfo->use_sys_clk) {
Archit Taneja6af9cd12011-01-31 16:27:44 +00001258 cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001259 /* XXX it is unclear if highfreq should be used
Archit Taneja1bb47832011-02-24 14:17:30 +05301260 * with DSS_SYS_CLK source also */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001261 cinfo->highfreq = 0;
1262 } else {
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001263 cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001264
1265 if (cinfo->clkin < 32000000)
1266 cinfo->highfreq = 0;
1267 else
1268 cinfo->highfreq = 1;
1269 }
1270
1271 cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
1272
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301273 if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001274 return -EINVAL;
1275
1276 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
1277
1278 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
1279 return -EINVAL;
1280
Archit Taneja1bb47832011-02-24 14:17:30 +05301281 if (cinfo->regm_dispc > 0)
1282 cinfo->dsi_pll_hsdiv_dispc_clk =
1283 cinfo->clkin4ddr / cinfo->regm_dispc;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001284 else
Archit Taneja1bb47832011-02-24 14:17:30 +05301285 cinfo->dsi_pll_hsdiv_dispc_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001286
Archit Taneja1bb47832011-02-24 14:17:30 +05301287 if (cinfo->regm_dsi > 0)
1288 cinfo->dsi_pll_hsdiv_dsi_clk =
1289 cinfo->clkin4ddr / cinfo->regm_dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001290 else
Archit Taneja1bb47832011-02-24 14:17:30 +05301291 cinfo->dsi_pll_hsdiv_dsi_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001292
1293 return 0;
1294}
1295
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301296int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
1297 unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001298 struct dispc_clock_info *dispc_cinfo)
1299{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301300 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001301 struct dsi_clock_info cur, best;
1302 struct dispc_clock_info best_dispc;
1303 int min_fck_per_pck;
1304 int match = 0;
Archit Taneja1bb47832011-02-24 14:17:30 +05301305 unsigned long dss_sys_clk, max_dss_fck;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001306
Archit Taneja1bb47832011-02-24 14:17:30 +05301307 dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001308
Taneja, Archit31ef8232011-03-14 23:28:22 -05001309 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
Archit Taneja819d8072011-03-01 11:54:00 +05301310
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301311 if (req_pck == dsi->cache_req_pck &&
1312 dsi->cache_cinfo.clkin == dss_sys_clk) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001313 DSSDBG("DSI clock info found from cache\n");
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301314 *dsi_cinfo = dsi->cache_cinfo;
Archit Taneja1bb47832011-02-24 14:17:30 +05301315 dispc_find_clk_divs(is_tft, req_pck,
1316 dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001317 return 0;
1318 }
1319
1320 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
1321
1322 if (min_fck_per_pck &&
Archit Taneja819d8072011-03-01 11:54:00 +05301323 req_pck * min_fck_per_pck > max_dss_fck) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001324 DSSERR("Requested pixel clock not possible with the current "
1325 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
1326 "the constraint off.\n");
1327 min_fck_per_pck = 0;
1328 }
1329
1330 DSSDBG("dsi_pll_calc\n");
1331
1332retry:
1333 memset(&best, 0, sizeof(best));
1334 memset(&best_dispc, 0, sizeof(best_dispc));
1335
1336 memset(&cur, 0, sizeof(cur));
Archit Taneja1bb47832011-02-24 14:17:30 +05301337 cur.clkin = dss_sys_clk;
1338 cur.use_sys_clk = 1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001339 cur.highfreq = 0;
1340
1341 /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
1342 /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
1343 /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301344 for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001345 if (cur.highfreq == 0)
1346 cur.fint = cur.clkin / cur.regn;
1347 else
1348 cur.fint = cur.clkin / (2 * cur.regn);
1349
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301350 if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001351 continue;
1352
1353 /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301354 for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001355 unsigned long a, b;
1356
1357 a = 2 * cur.regm * (cur.clkin/1000);
1358 b = cur.regn * (cur.highfreq + 1);
1359 cur.clkin4ddr = a / b * 1000;
1360
1361 if (cur.clkin4ddr > 1800 * 1000 * 1000)
1362 break;
1363
Archit Taneja1bb47832011-02-24 14:17:30 +05301364 /* dsi_pll_hsdiv_dispc_clk(MHz) =
1365 * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301366 for (cur.regm_dispc = 1; cur.regm_dispc <
1367 dsi->regm_dispc_max; ++cur.regm_dispc) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001368 struct dispc_clock_info cur_dispc;
Archit Taneja1bb47832011-02-24 14:17:30 +05301369 cur.dsi_pll_hsdiv_dispc_clk =
1370 cur.clkin4ddr / cur.regm_dispc;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001371
1372 /* this will narrow down the search a bit,
1373 * but still give pixclocks below what was
1374 * requested */
Archit Taneja1bb47832011-02-24 14:17:30 +05301375 if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001376 break;
1377
Archit Taneja1bb47832011-02-24 14:17:30 +05301378 if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001379 continue;
1380
1381 if (min_fck_per_pck &&
Archit Taneja1bb47832011-02-24 14:17:30 +05301382 cur.dsi_pll_hsdiv_dispc_clk <
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001383 req_pck * min_fck_per_pck)
1384 continue;
1385
1386 match = 1;
1387
1388 dispc_find_clk_divs(is_tft, req_pck,
Archit Taneja1bb47832011-02-24 14:17:30 +05301389 cur.dsi_pll_hsdiv_dispc_clk,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001390 &cur_dispc);
1391
1392 if (abs(cur_dispc.pck - req_pck) <
1393 abs(best_dispc.pck - req_pck)) {
1394 best = cur;
1395 best_dispc = cur_dispc;
1396
1397 if (cur_dispc.pck == req_pck)
1398 goto found;
1399 }
1400 }
1401 }
1402 }
1403found:
1404 if (!match) {
1405 if (min_fck_per_pck) {
1406 DSSERR("Could not find suitable clock settings.\n"
1407 "Turning FCK/PCK constraint off and"
1408 "trying again.\n");
1409 min_fck_per_pck = 0;
1410 goto retry;
1411 }
1412
1413 DSSERR("Could not find suitable clock settings.\n");
1414
1415 return -EINVAL;
1416 }
1417
Archit Taneja1bb47832011-02-24 14:17:30 +05301418 /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
1419 best.regm_dsi = 0;
1420 best.dsi_pll_hsdiv_dsi_clk = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001421
1422 if (dsi_cinfo)
1423 *dsi_cinfo = best;
1424 if (dispc_cinfo)
1425 *dispc_cinfo = best_dispc;
1426
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301427 dsi->cache_req_pck = req_pck;
1428 dsi->cache_clk_freq = 0;
1429 dsi->cache_cinfo = best;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001430
1431 return 0;
1432}
1433
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301434int dsi_pll_set_clock_div(struct platform_device *dsidev,
1435 struct dsi_clock_info *cinfo)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001436{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301437 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001438 int r = 0;
1439 u32 l;
Archit Taneja9613c022011-03-22 06:33:36 -05001440 int f = 0;
Taneja, Archit49641112011-03-14 23:28:23 -05001441 u8 regn_start, regn_end, regm_start, regm_end;
1442 u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001443
1444 DSSDBGF();
1445
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301446 dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk;
1447 dsi->current_cinfo.highfreq = cinfo->highfreq;
Tomi Valkeinenb2765092011-04-07 15:28:47 +03001448
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301449 dsi->current_cinfo.fint = cinfo->fint;
1450 dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
1451 dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
Archit Taneja1bb47832011-02-24 14:17:30 +05301452 cinfo->dsi_pll_hsdiv_dispc_clk;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301453 dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
Archit Taneja1bb47832011-02-24 14:17:30 +05301454 cinfo->dsi_pll_hsdiv_dsi_clk;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001455
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301456 dsi->current_cinfo.regn = cinfo->regn;
1457 dsi->current_cinfo.regm = cinfo->regm;
1458 dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
1459 dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001460
1461 DSSDBG("DSI Fint %ld\n", cinfo->fint);
1462
1463 DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
Archit Taneja1bb47832011-02-24 14:17:30 +05301464 cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001465 cinfo->clkin,
1466 cinfo->highfreq);
1467
1468 /* DSIPHY == CLKIN4DDR */
1469 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
1470 cinfo->regm,
1471 cinfo->regn,
1472 cinfo->clkin,
1473 cinfo->highfreq + 1,
1474 cinfo->clkin4ddr);
1475
1476 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
1477 cinfo->clkin4ddr / 1000 / 1000 / 2);
1478
1479 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1480
Archit Taneja1bb47832011-02-24 14:17:30 +05301481 DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
Archit Taneja89a35e52011-04-12 13:52:23 +05301482 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
1483 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
Archit Taneja1bb47832011-02-24 14:17:30 +05301484 cinfo->dsi_pll_hsdiv_dispc_clk);
1485 DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
Archit Taneja89a35e52011-04-12 13:52:23 +05301486 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
1487 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
Archit Taneja1bb47832011-02-24 14:17:30 +05301488 cinfo->dsi_pll_hsdiv_dsi_clk);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001489
Taneja, Archit49641112011-03-14 23:28:23 -05001490 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
1491 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
1492 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
1493 &regm_dispc_end);
1494 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
1495 &regm_dsi_end);
1496
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301497 /* DSI_PLL_AUTOMODE = manual */
1498 REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001499
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301500 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001501 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
Taneja, Archit49641112011-03-14 23:28:23 -05001502 /* DSI_PLL_REGN */
1503 l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
1504 /* DSI_PLL_REGM */
1505 l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
1506 /* DSI_CLOCK_DIV */
Archit Taneja1bb47832011-02-24 14:17:30 +05301507 l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
Taneja, Archit49641112011-03-14 23:28:23 -05001508 regm_dispc_start, regm_dispc_end);
1509 /* DSIPROTO_CLOCK_DIV */
Archit Taneja1bb47832011-02-24 14:17:30 +05301510 l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
Taneja, Archit49641112011-03-14 23:28:23 -05001511 regm_dsi_start, regm_dsi_end);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301512 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001513
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301514 BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
Archit Taneja9613c022011-03-22 06:33:36 -05001515
1516 if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
1517 f = cinfo->fint < 1000000 ? 0x3 :
1518 cinfo->fint < 1250000 ? 0x4 :
1519 cinfo->fint < 1500000 ? 0x5 :
1520 cinfo->fint < 1750000 ? 0x6 :
1521 0x7;
1522 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001523
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301524 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
Archit Taneja9613c022011-03-22 06:33:36 -05001525
1526 if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
1527 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
Archit Taneja1bb47832011-02-24 14:17:30 +05301528 l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001529 11, 11); /* DSI_PLL_CLKSEL */
1530 l = FLD_MOD(l, cinfo->highfreq,
1531 12, 12); /* DSI_PLL_HIGHFREQ */
1532 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1533 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1534 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301535 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001536
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301537 REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001538
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301539 if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001540 DSSERR("dsi pll go bit not going down.\n");
1541 r = -EIO;
1542 goto err;
1543 }
1544
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301545 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001546 DSSERR("cannot lock PLL\n");
1547 r = -EIO;
1548 goto err;
1549 }
1550
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301551 dsi->pll_locked = 1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001552
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301553 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001554 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1555 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1556 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1557 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1558 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1559 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1560 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1561 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1562 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1563 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1564 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1565 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1566 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1567 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301568 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001569
1570 DSSDBG("PLL config done\n");
1571err:
1572 return r;
1573}
1574
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301575int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
1576 bool enable_hsdiv)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001577{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301578 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001579 int r = 0;
1580 enum dsi_pll_power_state pwstate;
1581
1582 DSSDBG("PLL init\n");
1583
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301584 if (dsi->vdds_dsi_reg == NULL) {
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001585 struct regulator *vdds_dsi;
1586
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301587 vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001588
1589 if (IS_ERR(vdds_dsi)) {
1590 DSSERR("can't get VDDS_DSI regulator\n");
1591 return PTR_ERR(vdds_dsi);
1592 }
1593
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301594 dsi->vdds_dsi_reg = vdds_dsi;
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001595 }
Tomi Valkeinenf2988ab2011-03-02 10:06:48 +02001596
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001597 enable_clocks(1);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301598 dsi_enable_pll_clock(dsidev, 1);
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001599 /*
1600 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
1601 */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301602 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001603
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301604 if (!dsi->vdds_dsi_enabled) {
1605 r = regulator_enable(dsi->vdds_dsi_reg);
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001606 if (r)
1607 goto err0;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301608 dsi->vdds_dsi_enabled = true;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001609 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001610
1611 /* XXX PLL does not come out of reset without this... */
1612 dispc_pck_free_enable(1);
1613
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301614 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001615 DSSERR("PLL not coming out of reset.\n");
1616 r = -ENODEV;
Ville Syrjälä481dfa02010-04-22 22:50:04 +02001617 dispc_pck_free_enable(0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001618 goto err1;
1619 }
1620
1621 /* XXX ... but if left on, we get problems when planes do not
1622 * fill the whole display. No idea about this */
1623 dispc_pck_free_enable(0);
1624
1625 if (enable_hsclk && enable_hsdiv)
1626 pwstate = DSI_PLL_POWER_ON_ALL;
1627 else if (enable_hsclk)
1628 pwstate = DSI_PLL_POWER_ON_HSCLK;
1629 else if (enable_hsdiv)
1630 pwstate = DSI_PLL_POWER_ON_DIV;
1631 else
1632 pwstate = DSI_PLL_POWER_OFF;
1633
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301634 r = dsi_pll_power(dsidev, pwstate);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001635
1636 if (r)
1637 goto err1;
1638
1639 DSSDBG("PLL init done\n");
1640
1641 return 0;
1642err1:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301643 if (dsi->vdds_dsi_enabled) {
1644 regulator_disable(dsi->vdds_dsi_reg);
1645 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001646 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001647err0:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301648 dsi_disable_scp_clk(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001649 enable_clocks(0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301650 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001651 return r;
1652}
1653
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301654void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001655{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301656 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1657
1658 dsi->pll_locked = 0;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301659 dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001660 if (disconnect_lanes) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301661 WARN_ON(!dsi->vdds_dsi_enabled);
1662 regulator_disable(dsi->vdds_dsi_reg);
1663 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03001664 }
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001665
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301666 dsi_disable_scp_clk(dsidev);
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001667 enable_clocks(0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301668 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen24c1ae42011-04-13 17:12:52 +03001669
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001670 DSSDBG("PLL uninit done\n");
1671}
1672
1673void dsi_dump_clocks(struct seq_file *s)
1674{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301675 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301676 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1677 struct dsi_clock_info *cinfo = &dsi->current_cinfo;
Archit Taneja89a35e52011-04-12 13:52:23 +05301678 enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
Archit Taneja067a57e2011-03-02 11:57:25 +05301679
1680 dispc_clk_src = dss_get_dispc_clk_source();
1681 dsi_clk_src = dss_get_dsi_clk_source();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001682
1683 enable_clocks(1);
1684
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001685 seq_printf(s, "- DSI PLL -\n");
1686
1687 seq_printf(s, "dsi pll source = %s\n",
Tomi Valkeinena9a65002011-04-04 10:02:53 +03001688 cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001689
1690 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1691
1692 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1693 cinfo->clkin4ddr, cinfo->regm);
1694
Archit Taneja1bb47832011-02-24 14:17:30 +05301695 seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
Archit Taneja067a57e2011-03-02 11:57:25 +05301696 dss_get_generic_clk_source_name(dispc_clk_src),
1697 dss_feat_get_clk_source_name(dispc_clk_src),
Archit Taneja1bb47832011-02-24 14:17:30 +05301698 cinfo->dsi_pll_hsdiv_dispc_clk,
1699 cinfo->regm_dispc,
Archit Taneja89a35e52011-04-12 13:52:23 +05301700 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
Tomi Valkeinen63cf28a2010-02-23 17:40:00 +02001701 "off" : "on");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001702
Archit Taneja1bb47832011-02-24 14:17:30 +05301703 seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
Archit Taneja067a57e2011-03-02 11:57:25 +05301704 dss_get_generic_clk_source_name(dsi_clk_src),
1705 dss_feat_get_clk_source_name(dsi_clk_src),
Archit Taneja1bb47832011-02-24 14:17:30 +05301706 cinfo->dsi_pll_hsdiv_dsi_clk,
1707 cinfo->regm_dsi,
Archit Taneja89a35e52011-04-12 13:52:23 +05301708 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
Tomi Valkeinen63cf28a2010-02-23 17:40:00 +02001709 "off" : "on");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001710
1711 seq_printf(s, "- DSI -\n");
1712
Archit Taneja067a57e2011-03-02 11:57:25 +05301713 seq_printf(s, "dsi fclk source = %s (%s)\n",
1714 dss_get_generic_clk_source_name(dsi_clk_src),
1715 dss_feat_get_clk_source_name(dsi_clk_src));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001716
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301717 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001718
1719 seq_printf(s, "DDR_CLK\t\t%lu\n",
1720 cinfo->clkin4ddr / 4);
1721
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301722 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001723
1724 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1725
1726 seq_printf(s, "VP_CLK\t\t%lu\n"
1727 "VP_PCLK\t\t%lu\n",
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001728 dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
1729 dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001730
1731 enable_clocks(0);
1732}
1733
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001734#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1735void dsi_dump_irqs(struct seq_file *s)
1736{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301737 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1738 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001739 unsigned long flags;
1740 struct dsi_irq_stats stats;
1741
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301742 spin_lock_irqsave(&dsi->irq_stats_lock, flags);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001743
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301744 stats = dsi->irq_stats;
1745 memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
1746 dsi->irq_stats.last_reset = jiffies;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001747
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301748 spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02001749
1750 seq_printf(s, "period %u ms\n",
1751 jiffies_to_msecs(jiffies - stats.last_reset));
1752
1753 seq_printf(s, "irqs %d\n", stats.irq_count);
1754#define PIS(x) \
1755 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1756
1757 seq_printf(s, "-- DSI interrupts --\n");
1758 PIS(VC0);
1759 PIS(VC1);
1760 PIS(VC2);
1761 PIS(VC3);
1762 PIS(WAKEUP);
1763 PIS(RESYNC);
1764 PIS(PLL_LOCK);
1765 PIS(PLL_UNLOCK);
1766 PIS(PLL_RECALL);
1767 PIS(COMPLEXIO_ERR);
1768 PIS(HS_TX_TIMEOUT);
1769 PIS(LP_RX_TIMEOUT);
1770 PIS(TE_TRIGGER);
1771 PIS(ACK_TRIGGER);
1772 PIS(SYNC_LOST);
1773 PIS(LDO_POWER_GOOD);
1774 PIS(TA_TIMEOUT);
1775#undef PIS
1776
1777#define PIS(x) \
1778 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1779 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1780 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1781 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1782 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1783
1784 seq_printf(s, "-- VC interrupts --\n");
1785 PIS(CS);
1786 PIS(ECC_CORR);
1787 PIS(PACKET_SENT);
1788 PIS(FIFO_TX_OVF);
1789 PIS(FIFO_RX_OVF);
1790 PIS(BTA);
1791 PIS(ECC_NO_CORR);
1792 PIS(FIFO_TX_UDF);
1793 PIS(PP_BUSY_CHANGE);
1794#undef PIS
1795
1796#define PIS(x) \
1797 seq_printf(s, "%-20s %10d\n", #x, \
1798 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1799
1800 seq_printf(s, "-- CIO interrupts --\n");
1801 PIS(ERRSYNCESC1);
1802 PIS(ERRSYNCESC2);
1803 PIS(ERRSYNCESC3);
1804 PIS(ERRESC1);
1805 PIS(ERRESC2);
1806 PIS(ERRESC3);
1807 PIS(ERRCONTROL1);
1808 PIS(ERRCONTROL2);
1809 PIS(ERRCONTROL3);
1810 PIS(STATEULPS1);
1811 PIS(STATEULPS2);
1812 PIS(STATEULPS3);
1813 PIS(ERRCONTENTIONLP0_1);
1814 PIS(ERRCONTENTIONLP1_1);
1815 PIS(ERRCONTENTIONLP0_2);
1816 PIS(ERRCONTENTIONLP1_2);
1817 PIS(ERRCONTENTIONLP0_3);
1818 PIS(ERRCONTENTIONLP1_3);
1819 PIS(ULPSACTIVENOT_ALL0);
1820 PIS(ULPSACTIVENOT_ALL1);
1821#undef PIS
1822}
1823#endif
1824
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001825void dsi_dump_regs(struct seq_file *s)
1826{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301827 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1828
1829#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001830
Archit Taneja6af9cd12011-01-31 16:27:44 +00001831 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301832 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001833
1834 DUMPREG(DSI_REVISION);
1835 DUMPREG(DSI_SYSCONFIG);
1836 DUMPREG(DSI_SYSSTATUS);
1837 DUMPREG(DSI_IRQSTATUS);
1838 DUMPREG(DSI_IRQENABLE);
1839 DUMPREG(DSI_CTRL);
1840 DUMPREG(DSI_COMPLEXIO_CFG1);
1841 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1842 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1843 DUMPREG(DSI_CLK_CTRL);
1844 DUMPREG(DSI_TIMING1);
1845 DUMPREG(DSI_TIMING2);
1846 DUMPREG(DSI_VM_TIMING1);
1847 DUMPREG(DSI_VM_TIMING2);
1848 DUMPREG(DSI_VM_TIMING3);
1849 DUMPREG(DSI_CLK_TIMING);
1850 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1851 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1852 DUMPREG(DSI_COMPLEXIO_CFG2);
1853 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1854 DUMPREG(DSI_VM_TIMING4);
1855 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1856 DUMPREG(DSI_VM_TIMING5);
1857 DUMPREG(DSI_VM_TIMING6);
1858 DUMPREG(DSI_VM_TIMING7);
1859 DUMPREG(DSI_STOPCLK_TIMING);
1860
1861 DUMPREG(DSI_VC_CTRL(0));
1862 DUMPREG(DSI_VC_TE(0));
1863 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1864 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1865 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1866 DUMPREG(DSI_VC_IRQSTATUS(0));
1867 DUMPREG(DSI_VC_IRQENABLE(0));
1868
1869 DUMPREG(DSI_VC_CTRL(1));
1870 DUMPREG(DSI_VC_TE(1));
1871 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1872 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1873 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1874 DUMPREG(DSI_VC_IRQSTATUS(1));
1875 DUMPREG(DSI_VC_IRQENABLE(1));
1876
1877 DUMPREG(DSI_VC_CTRL(2));
1878 DUMPREG(DSI_VC_TE(2));
1879 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1880 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1881 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1882 DUMPREG(DSI_VC_IRQSTATUS(2));
1883 DUMPREG(DSI_VC_IRQENABLE(2));
1884
1885 DUMPREG(DSI_VC_CTRL(3));
1886 DUMPREG(DSI_VC_TE(3));
1887 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1888 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1889 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1890 DUMPREG(DSI_VC_IRQSTATUS(3));
1891 DUMPREG(DSI_VC_IRQENABLE(3));
1892
1893 DUMPREG(DSI_DSIPHY_CFG0);
1894 DUMPREG(DSI_DSIPHY_CFG1);
1895 DUMPREG(DSI_DSIPHY_CFG2);
1896 DUMPREG(DSI_DSIPHY_CFG5);
1897
1898 DUMPREG(DSI_PLL_CONTROL);
1899 DUMPREG(DSI_PLL_STATUS);
1900 DUMPREG(DSI_PLL_GO);
1901 DUMPREG(DSI_PLL_CONFIGURATION1);
1902 DUMPREG(DSI_PLL_CONFIGURATION2);
1903
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301904 dsi_disable_scp_clk(dsidev);
Archit Taneja6af9cd12011-01-31 16:27:44 +00001905 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001906#undef DUMPREG
1907}
1908
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03001909enum dsi_cio_power_state {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001910 DSI_COMPLEXIO_POWER_OFF = 0x0,
1911 DSI_COMPLEXIO_POWER_ON = 0x1,
1912 DSI_COMPLEXIO_POWER_ULPS = 0x2,
1913};
1914
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301915static int dsi_cio_power(struct platform_device *dsidev,
1916 enum dsi_cio_power_state state)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001917{
1918 int t = 0;
1919
1920 /* PWR_CMD */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301921 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001922
1923 /* PWR_STATUS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301924 while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
1925 26, 25) != state) {
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001926 if (++t > 1000) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001927 DSSERR("failed to set complexio power state to "
1928 "%d\n", state);
1929 return -ENODEV;
1930 }
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02001931 udelay(1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001932 }
1933
1934 return 0;
1935}
1936
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03001937static void dsi_set_lane_config(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001938{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301939 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001940 u32 r;
1941
1942 int clk_lane = dssdev->phy.dsi.clk_lane;
1943 int data1_lane = dssdev->phy.dsi.data1_lane;
1944 int data2_lane = dssdev->phy.dsi.data2_lane;
1945 int clk_pol = dssdev->phy.dsi.clk_pol;
1946 int data1_pol = dssdev->phy.dsi.data1_pol;
1947 int data2_pol = dssdev->phy.dsi.data2_pol;
1948
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301949 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001950 r = FLD_MOD(r, clk_lane, 2, 0);
1951 r = FLD_MOD(r, clk_pol, 3, 3);
1952 r = FLD_MOD(r, data1_lane, 6, 4);
1953 r = FLD_MOD(r, data1_pol, 7, 7);
1954 r = FLD_MOD(r, data2_lane, 10, 8);
1955 r = FLD_MOD(r, data2_pol, 11, 11);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301956 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001957
1958 /* The configuration of the DSI complex I/O (number of data lanes,
1959 position, differential order) should not be changed while
1960 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
1961 the hardware to take into account a new configuration of the complex
1962 I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
1963 follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
1964 then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
1965 DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
1966 DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
1967 DSI complex I/O configuration is unknown. */
1968
1969 /*
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301970 REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
1971 REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
1972 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
1973 REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001974 */
1975}
1976
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301977static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001978{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301979 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1980
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001981 /* convert time in ns to ddr ticks, rounding up */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301982 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001983 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
1984}
1985
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301986static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001987{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05301988 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1989
1990 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001991 return ddr * 1000 * 1000 / (ddr_clk / 1000);
1992}
1993
Archit Tanejaa72b64b2011-05-12 17:26:26 +05301994static void dsi_cio_timings(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02001995{
1996 u32 r;
1997 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
1998 u32 tlpx_half, tclk_trail, tclk_zero;
1999 u32 tclk_prepare;
2000
2001 /* calculate timings */
2002
2003 /* 1 * DDR_CLK = 2 * UI */
2004
2005 /* min 40ns + 4*UI max 85ns + 6*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302006 ths_prepare = ns2ddr(dsidev, 70) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002007
2008 /* min 145ns + 10*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302009 ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002010
2011 /* min max(8*UI, 60ns+4*UI) */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302012 ths_trail = ns2ddr(dsidev, 60) + 5;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002013
2014 /* min 100ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302015 ths_exit = ns2ddr(dsidev, 145);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002016
2017 /* tlpx min 50n */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302018 tlpx_half = ns2ddr(dsidev, 25);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002019
2020 /* min 60ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302021 tclk_trail = ns2ddr(dsidev, 60) + 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002022
2023 /* min 38ns, max 95ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302024 tclk_prepare = ns2ddr(dsidev, 65);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002025
2026 /* min tclk-prepare + tclk-zero = 300ns */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302027 tclk_zero = ns2ddr(dsidev, 260);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002028
2029 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302030 ths_prepare, ddr2ns(dsidev, ths_prepare),
2031 ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002032 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302033 ths_trail, ddr2ns(dsidev, ths_trail),
2034 ths_exit, ddr2ns(dsidev, ths_exit));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002035
2036 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
2037 "tclk_zero %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302038 tlpx_half, ddr2ns(dsidev, tlpx_half),
2039 tclk_trail, ddr2ns(dsidev, tclk_trail),
2040 tclk_zero, ddr2ns(dsidev, tclk_zero));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002041 DSSDBG("tclk_prepare %u (%uns)\n",
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302042 tclk_prepare, ddr2ns(dsidev, tclk_prepare));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002043
2044 /* program timings */
2045
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302046 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002047 r = FLD_MOD(r, ths_prepare, 31, 24);
2048 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
2049 r = FLD_MOD(r, ths_trail, 15, 8);
2050 r = FLD_MOD(r, ths_exit, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302051 dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002052
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302053 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002054 r = FLD_MOD(r, tlpx_half, 22, 16);
2055 r = FLD_MOD(r, tclk_trail, 15, 8);
2056 r = FLD_MOD(r, tclk_zero, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302057 dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002058
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302059 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002060 r = FLD_MOD(r, tclk_prepare, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302061 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002062}
2063
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002064static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002065 enum dsi_lane lanes)
2066{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302067 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002068 int clk_lane = dssdev->phy.dsi.clk_lane;
2069 int data1_lane = dssdev->phy.dsi.data1_lane;
2070 int data2_lane = dssdev->phy.dsi.data2_lane;
2071 int clk_pol = dssdev->phy.dsi.clk_pol;
2072 int data1_pol = dssdev->phy.dsi.data1_pol;
2073 int data2_pol = dssdev->phy.dsi.data2_pol;
2074
2075 u32 l = 0;
2076
2077 if (lanes & DSI_CLK_P)
2078 l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
2079 if (lanes & DSI_CLK_N)
2080 l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));
2081
2082 if (lanes & DSI_DATA1_P)
2083 l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
2084 if (lanes & DSI_DATA1_N)
2085 l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));
2086
2087 if (lanes & DSI_DATA2_P)
2088 l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
2089 if (lanes & DSI_DATA2_N)
2090 l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
2091
2092 /*
2093 * Bits in REGLPTXSCPDAT4TO0DXDY:
2094 * 17: DY0 18: DX0
2095 * 19: DY1 20: DX1
2096 * 21: DY2 22: DX2
2097 */
2098
2099 /* Set the lane override configuration */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302100
2101 /* REGLPTXSCPDAT4TO0DXDY */
2102 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, 22, 17);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002103
2104 /* Enable lane override */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302105
2106 /* ENLPTXSCPDAT */
2107 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002108}
2109
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302110static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002111{
2112 /* Disable lane override */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302113 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002114 /* Reset the lane override configuration */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302115 /* REGLPTXSCPDAT4TO0DXDY */
2116 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
Tomi Valkeinen0a0ee462010-07-27 11:11:48 +03002117}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002118
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002119static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
2120{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302121 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002122 int t;
2123 int bits[3];
2124 bool in_use[3];
2125
2126 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
2127 bits[0] = 28;
2128 bits[1] = 27;
2129 bits[2] = 26;
2130 } else {
2131 bits[0] = 24;
2132 bits[1] = 25;
2133 bits[2] = 26;
2134 }
2135
2136 in_use[0] = false;
2137 in_use[1] = false;
2138 in_use[2] = false;
2139
2140 if (dssdev->phy.dsi.clk_lane != 0)
2141 in_use[dssdev->phy.dsi.clk_lane - 1] = true;
2142 if (dssdev->phy.dsi.data1_lane != 0)
2143 in_use[dssdev->phy.dsi.data1_lane - 1] = true;
2144 if (dssdev->phy.dsi.data2_lane != 0)
2145 in_use[dssdev->phy.dsi.data2_lane - 1] = true;
2146
2147 t = 100000;
2148 while (true) {
2149 u32 l;
2150 int i;
2151 int ok;
2152
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302153 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002154
2155 ok = 0;
2156 for (i = 0; i < 3; ++i) {
2157 if (!in_use[i] || (l & (1 << bits[i])))
2158 ok++;
2159 }
2160
2161 if (ok == 3)
2162 break;
2163
2164 if (--t == 0) {
2165 for (i = 0; i < 3; ++i) {
2166 if (!in_use[i] || (l & (1 << bits[i])))
2167 continue;
2168
2169 DSSERR("CIO TXCLKESC%d domain not coming " \
2170 "out of reset\n", i);
2171 }
2172 return -EIO;
2173 }
2174 }
2175
2176 return 0;
2177}
2178
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002179static int dsi_cio_init(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002180{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302181 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302182 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002183 int r;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002184 u32 l;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002185
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002186 DSSDBGF();
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002187
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302188 if (dsi->dsi_mux_pads)
2189 dsi->dsi_mux_pads(true);
Tomi Valkeinend1f58572010-07-30 11:57:57 +03002190
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302191 dsi_enable_scp_clk(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002192
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002193 /* A dummy read using the SCP interface to any DSIPHY register is
2194 * required after DSIPHY reset to complete the reset of the DSI complex
2195 * I/O. */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302196 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002197
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302198 if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002199 DSSERR("CIO SCP Clock domain not coming out of reset.\n");
2200 r = -EIO;
2201 goto err_scp_clk_dom;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002202 }
2203
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002204 dsi_set_lane_config(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002205
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002206 /* set TX STOP MODE timer to maximum for this operation */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302207 l = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002208 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2209 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
2210 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
2211 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302212 dsi_write_reg(dsidev, DSI_TIMING1, l);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002213
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302214 if (dsi->ulps_enabled) {
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002215 DSSDBG("manual ulps exit\n");
2216
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002217 /* ULPS is exited by Mark-1 state for 1ms, followed by
2218 * stop state. DSS HW cannot do this via the normal
2219 * ULPS exit sequence, as after reset the DSS HW thinks
2220 * that we are not in ULPS mode, and refuses to send the
2221 * sequence. So we need to send the ULPS exit sequence
2222 * manually.
2223 */
2224
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03002225 dsi_cio_enable_lane_override(dssdev,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002226 DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P);
2227 }
2228
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302229 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002230 if (r)
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002231 goto err_cio_pwr;
2232
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302233 if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002234 DSSERR("CIO PWR clock domain not coming out of reset.\n");
2235 r = -ENODEV;
2236 goto err_cio_pwr_dom;
2237 }
2238
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302239 dsi_if_enable(dsidev, true);
2240 dsi_if_enable(dsidev, false);
2241 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002242
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002243 r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
2244 if (r)
2245 goto err_tx_clk_esc_rst;
2246
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302247 if (dsi->ulps_enabled) {
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002248 /* Keep Mark-1 state for 1ms (as per DSI spec) */
2249 ktime_t wait = ns_to_ktime(1000 * 1000);
2250 set_current_state(TASK_UNINTERRUPTIBLE);
2251 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
2252
2253 /* Disable the override. The lanes should be set to Mark-11
2254 * state by the HW */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302255 dsi_cio_disable_lane_override(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002256 }
2257
2258 /* FORCE_TX_STOP_MODE_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302259 REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03002260
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302261 dsi_cio_timings(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002262
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302263 dsi->ulps_enabled = false;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002264
2265 DSSDBG("CIO init done\n");
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002266
2267 return 0;
2268
Tomi Valkeinen03329ac2010-10-07 13:59:22 +03002269err_tx_clk_esc_rst:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302270 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002271err_cio_pwr_dom:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302272 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002273err_cio_pwr:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302274 if (dsi->ulps_enabled)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302275 dsi_cio_disable_lane_override(dsidev);
Tomi Valkeinen65c62bb2011-04-15 11:58:41 +03002276err_scp_clk_dom:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302277 dsi_disable_scp_clk(dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302278 if (dsi->dsi_mux_pads)
2279 dsi->dsi_mux_pads(false);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002280 return r;
2281}
2282
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302283static void dsi_cio_uninit(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002284{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302285 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2286
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302287 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2288 dsi_disable_scp_clk(dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302289 if (dsi->dsi_mux_pads)
2290 dsi->dsi_mux_pads(false);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002291}
2292
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302293static int _dsi_wait_reset(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002294{
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02002295 int t = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002296
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302297 while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02002298 if (++t > 5) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002299 DSSERR("soft reset failed\n");
2300 return -ENODEV;
2301 }
2302 udelay(1);
2303 }
2304
2305 return 0;
2306}
2307
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302308static int _dsi_reset(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002309{
2310 /* Soft reset */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302311 REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
2312 return _dsi_wait_reset(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002313}
2314
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302315static void dsi_config_tx_fifo(struct platform_device *dsidev,
2316 enum fifo_size size1, enum fifo_size size2,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002317 enum fifo_size size3, enum fifo_size size4)
2318{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302319 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002320 u32 r = 0;
2321 int add = 0;
2322 int i;
2323
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302324 dsi->vc[0].fifo_size = size1;
2325 dsi->vc[1].fifo_size = size2;
2326 dsi->vc[2].fifo_size = size3;
2327 dsi->vc[3].fifo_size = size4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002328
2329 for (i = 0; i < 4; i++) {
2330 u8 v;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302331 int size = dsi->vc[i].fifo_size;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002332
2333 if (add + size > 4) {
2334 DSSERR("Illegal FIFO configuration\n");
2335 BUG();
2336 }
2337
2338 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2339 r |= v << (8 * i);
2340 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
2341 add += size;
2342 }
2343
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302344 dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002345}
2346
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302347static void dsi_config_rx_fifo(struct platform_device *dsidev,
2348 enum fifo_size size1, enum fifo_size size2,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002349 enum fifo_size size3, enum fifo_size size4)
2350{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302351 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002352 u32 r = 0;
2353 int add = 0;
2354 int i;
2355
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302356 dsi->vc[0].fifo_size = size1;
2357 dsi->vc[1].fifo_size = size2;
2358 dsi->vc[2].fifo_size = size3;
2359 dsi->vc[3].fifo_size = size4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002360
2361 for (i = 0; i < 4; i++) {
2362 u8 v;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302363 int size = dsi->vc[i].fifo_size;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002364
2365 if (add + size > 4) {
2366 DSSERR("Illegal FIFO configuration\n");
2367 BUG();
2368 }
2369
2370 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2371 r |= v << (8 * i);
2372 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
2373 add += size;
2374 }
2375
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302376 dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002377}
2378
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302379static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002380{
2381 u32 r;
2382
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302383 r = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002384 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302385 dsi_write_reg(dsidev, DSI_TIMING1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002386
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302387 if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002388 DSSERR("TX_STOP bit not going down\n");
2389 return -EIO;
2390 }
2391
2392 return 0;
2393}
2394
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302395static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002396{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302397 return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002398}
2399
2400static void dsi_packet_sent_handler_vp(void *data, u32 mask)
2401{
Archit Taneja2e868db2011-05-12 17:26:28 +05302402 struct dsi_packet_sent_handler_data *vp_data =
2403 (struct dsi_packet_sent_handler_data *) data;
2404 struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302405 const int channel = dsi->update_channel;
2406 u8 bit = dsi->te_enabled ? 30 : 31;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002407
Archit Taneja2e868db2011-05-12 17:26:28 +05302408 if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
2409 complete(vp_data->completion);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002410}
2411
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302412static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002413{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302414 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja2e868db2011-05-12 17:26:28 +05302415 DECLARE_COMPLETION_ONSTACK(completion);
2416 struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
Archit Tanejacf398fb2011-03-23 09:59:34 +00002417 int r = 0;
2418 u8 bit;
2419
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302420 bit = dsi->te_enabled ? 30 : 31;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002421
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302422 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302423 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002424 if (r)
2425 goto err0;
2426
2427 /* Wait for completion only if TE_EN/TE_START is still set */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302428 if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
Archit Tanejacf398fb2011-03-23 09:59:34 +00002429 if (wait_for_completion_timeout(&completion,
2430 msecs_to_jiffies(10)) == 0) {
2431 DSSERR("Failed to complete previous frame transfer\n");
2432 r = -EIO;
2433 goto err1;
2434 }
2435 }
2436
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302437 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302438 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002439
2440 return 0;
2441err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302442 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
Archit Taneja2e868db2011-05-12 17:26:28 +05302443 &vp_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002444err0:
2445 return r;
2446}
2447
2448static void dsi_packet_sent_handler_l4(void *data, u32 mask)
2449{
Archit Taneja2e868db2011-05-12 17:26:28 +05302450 struct dsi_packet_sent_handler_data *l4_data =
2451 (struct dsi_packet_sent_handler_data *) data;
2452 struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302453 const int channel = dsi->update_channel;
Archit Tanejacf398fb2011-03-23 09:59:34 +00002454
Archit Taneja2e868db2011-05-12 17:26:28 +05302455 if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
2456 complete(l4_data->completion);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002457}
2458
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302459static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002460{
Archit Taneja2e868db2011-05-12 17:26:28 +05302461 DECLARE_COMPLETION_ONSTACK(completion);
2462 struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
Archit Tanejacf398fb2011-03-23 09:59:34 +00002463 int r = 0;
2464
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302465 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302466 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002467 if (r)
2468 goto err0;
2469
2470 /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302471 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
Archit Tanejacf398fb2011-03-23 09:59:34 +00002472 if (wait_for_completion_timeout(&completion,
2473 msecs_to_jiffies(10)) == 0) {
2474 DSSERR("Failed to complete previous l4 transfer\n");
2475 r = -EIO;
2476 goto err1;
2477 }
2478 }
2479
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302480 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302481 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002482
2483 return 0;
2484err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302485 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
Archit Taneja2e868db2011-05-12 17:26:28 +05302486 &l4_data, DSI_VC_IRQ_PACKET_SENT);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002487err0:
2488 return r;
2489}
2490
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302491static int dsi_sync_vc(struct platform_device *dsidev, int channel)
Archit Tanejacf398fb2011-03-23 09:59:34 +00002492{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302493 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2494
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302495 WARN_ON(!dsi_bus_is_locked(dsidev));
Archit Tanejacf398fb2011-03-23 09:59:34 +00002496
2497 WARN_ON(in_interrupt());
2498
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302499 if (!dsi_vc_is_enabled(dsidev, channel))
Archit Tanejacf398fb2011-03-23 09:59:34 +00002500 return 0;
2501
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302502 switch (dsi->vc[channel].mode) {
Archit Tanejacf398fb2011-03-23 09:59:34 +00002503 case DSI_VC_MODE_VP:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302504 return dsi_sync_vc_vp(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002505 case DSI_VC_MODE_L4:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302506 return dsi_sync_vc_l4(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002507 default:
2508 BUG();
2509 }
2510}
2511
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302512static int dsi_vc_enable(struct platform_device *dsidev, int channel,
2513 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002514{
Tomi Valkeinen446f7bf2010-01-11 16:12:31 +02002515 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
2516 channel, enable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002517
2518 enable = enable ? 1 : 0;
2519
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302520 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002521
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302522 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
2523 0, enable) != enable) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002524 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
2525 return -EIO;
2526 }
2527
2528 return 0;
2529}
2530
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302531static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002532{
2533 u32 r;
2534
2535 DSSDBGF("%d", channel);
2536
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302537 r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002538
2539 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
2540 DSSERR("VC(%d) busy when trying to configure it!\n",
2541 channel);
2542
2543 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
2544 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
2545 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
2546 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
2547 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
2548 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
2549 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
Archit Taneja9613c022011-03-22 06:33:36 -05002550 if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
2551 r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002552
2553 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
2554 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
2555
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302556 dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002557}
2558
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302559static int dsi_vc_config_l4(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002560{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302561 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2562
2563 if (dsi->vc[channel].mode == DSI_VC_MODE_L4)
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002564 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002565
2566 DSSDBGF("%d", channel);
2567
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302568 dsi_sync_vc(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002569
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302570 dsi_vc_enable(dsidev, channel, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002571
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002572 /* VC_BUSY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302573 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002574 DSSERR("vc(%d) busy when trying to config for L4\n", channel);
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002575 return -EIO;
2576 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002577
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302578 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002579
Archit Taneja9613c022011-03-22 06:33:36 -05002580 /* DCS_CMD_ENABLE */
2581 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302582 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30);
Archit Taneja9613c022011-03-22 06:33:36 -05002583
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302584 dsi_vc_enable(dsidev, channel, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002585
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302586 dsi->vc[channel].mode = DSI_VC_MODE_L4;
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002587
2588 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002589}
2590
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302591static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002592{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302593 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2594
2595 if (dsi->vc[channel].mode == DSI_VC_MODE_VP)
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002596 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002597
2598 DSSDBGF("%d", channel);
2599
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302600 dsi_sync_vc(dsidev, channel);
Archit Tanejacf398fb2011-03-23 09:59:34 +00002601
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302602 dsi_vc_enable(dsidev, channel, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002603
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002604 /* VC_BUSY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302605 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002606 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002607 return -EIO;
2608 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002609
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302610 /* SOURCE, 1 = video port */
2611 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002612
Archit Taneja9613c022011-03-22 06:33:36 -05002613 /* DCS_CMD_ENABLE */
2614 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302615 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30);
Archit Taneja9613c022011-03-22 06:33:36 -05002616
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302617 dsi_vc_enable(dsidev, channel, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002618
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302619 dsi->vc[channel].mode = DSI_VC_MODE_VP;
Tomi Valkeinen9ecd9682010-04-30 11:24:33 +03002620
2621 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002622}
2623
2624
Archit Taneja1ffefe72011-05-12 17:26:24 +05302625void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
2626 bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002627{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302628 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2629
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002630 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
2631
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302632 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen61140c92010-01-12 16:00:30 +02002633
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302634 dsi_vc_enable(dsidev, channel, 0);
2635 dsi_if_enable(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002636
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302637 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002638
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302639 dsi_vc_enable(dsidev, channel, 1);
2640 dsi_if_enable(dsidev, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002641
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302642 dsi_force_tx_stop_mode_io(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002643}
Tomi Valkeinen61140c92010-01-12 16:00:30 +02002644EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002645
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302646static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002647{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302648 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002649 u32 val;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302650 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002651 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
2652 (val >> 0) & 0xff,
2653 (val >> 8) & 0xff,
2654 (val >> 16) & 0xff,
2655 (val >> 24) & 0xff);
2656 }
2657}
2658
2659static void dsi_show_rx_ack_with_err(u16 err)
2660{
2661 DSSERR("\tACK with ERROR (%#x):\n", err);
2662 if (err & (1 << 0))
2663 DSSERR("\t\tSoT Error\n");
2664 if (err & (1 << 1))
2665 DSSERR("\t\tSoT Sync Error\n");
2666 if (err & (1 << 2))
2667 DSSERR("\t\tEoT Sync Error\n");
2668 if (err & (1 << 3))
2669 DSSERR("\t\tEscape Mode Entry Command Error\n");
2670 if (err & (1 << 4))
2671 DSSERR("\t\tLP Transmit Sync Error\n");
2672 if (err & (1 << 5))
2673 DSSERR("\t\tHS Receive Timeout Error\n");
2674 if (err & (1 << 6))
2675 DSSERR("\t\tFalse Control Error\n");
2676 if (err & (1 << 7))
2677 DSSERR("\t\t(reserved7)\n");
2678 if (err & (1 << 8))
2679 DSSERR("\t\tECC Error, single-bit (corrected)\n");
2680 if (err & (1 << 9))
2681 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
2682 if (err & (1 << 10))
2683 DSSERR("\t\tChecksum Error\n");
2684 if (err & (1 << 11))
2685 DSSERR("\t\tData type not recognized\n");
2686 if (err & (1 << 12))
2687 DSSERR("\t\tInvalid VC ID\n");
2688 if (err & (1 << 13))
2689 DSSERR("\t\tInvalid Transmission Length\n");
2690 if (err & (1 << 14))
2691 DSSERR("\t\t(reserved14)\n");
2692 if (err & (1 << 15))
2693 DSSERR("\t\tDSI Protocol Violation\n");
2694}
2695
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302696static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
2697 int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002698{
2699 /* RX_FIFO_NOT_EMPTY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302700 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002701 u32 val;
2702 u8 dt;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302703 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002704 DSSERR("\trawval %#08x\n", val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002705 dt = FLD_GET(val, 5, 0);
2706 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
2707 u16 err = FLD_GET(val, 23, 8);
2708 dsi_show_rx_ack_with_err(err);
2709 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002710 DSSERR("\tDCS short response, 1 byte: %#x\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002711 FLD_GET(val, 23, 8));
2712 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002713 DSSERR("\tDCS short response, 2 byte: %#x\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002714 FLD_GET(val, 23, 8));
2715 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
Tomi Valkeinen86a78672010-03-16 16:19:06 +02002716 DSSERR("\tDCS long response, len %d\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002717 FLD_GET(val, 23, 8));
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302718 dsi_vc_flush_long_data(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002719 } else {
2720 DSSERR("\tunknown datatype 0x%02x\n", dt);
2721 }
2722 }
2723 return 0;
2724}
2725
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302726static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002727{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302728 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2729
2730 if (dsi->debug_write || dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002731 DSSDBG("dsi_vc_send_bta %d\n", channel);
2732
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302733 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002734
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302735 /* RX_FIFO_NOT_EMPTY */
2736 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002737 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302738 dsi_vc_flush_receive_data(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002739 }
2740
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302741 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002742
2743 return 0;
2744}
2745
Archit Taneja1ffefe72011-05-12 17:26:24 +05302746int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002747{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302748 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002749 DECLARE_COMPLETION_ONSTACK(completion);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002750 int r = 0;
2751 u32 err;
2752
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302753 r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002754 &completion, DSI_VC_IRQ_BTA);
2755 if (r)
2756 goto err0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002757
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302758 r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002759 DSI_IRQ_ERROR_MASK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002760 if (r)
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002761 goto err1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002762
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302763 r = dsi_vc_send_bta(dsidev, channel);
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002764 if (r)
2765 goto err2;
2766
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002767 if (wait_for_completion_timeout(&completion,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002768 msecs_to_jiffies(500)) == 0) {
2769 DSSERR("Failed to receive BTA\n");
2770 r = -EIO;
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002771 goto err2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002772 }
2773
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302774 err = dsi_get_errors(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002775 if (err) {
2776 DSSERR("Error while sending BTA: %x\n", err);
2777 r = -EIO;
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002778 goto err2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002779 }
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002780err2:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302781 dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen773b30b2010-10-08 16:15:25 +03002782 DSI_IRQ_ERROR_MASK);
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002783err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302784 dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
Tomi Valkeinenf36a06e2011-03-02 14:48:41 +02002785 &completion, DSI_VC_IRQ_BTA);
2786err0:
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002787 return r;
2788}
2789EXPORT_SYMBOL(dsi_vc_send_bta_sync);
2790
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302791static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
2792 int channel, u8 data_type, u16 len, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002793{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302794 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002795 u32 val;
2796 u8 data_id;
2797
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302798 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002799
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302800 data_id = data_type | dsi->vc[channel].vc_id << 6;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002801
2802 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
2803 FLD_VAL(ecc, 31, 24);
2804
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302805 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002806}
2807
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302808static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
2809 int channel, u8 b1, u8 b2, u8 b3, u8 b4)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002810{
2811 u32 val;
2812
2813 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
2814
2815/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
2816 b1, b2, b3, b4, val); */
2817
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302818 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002819}
2820
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302821static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
2822 u8 data_type, u8 *data, u16 len, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002823{
2824 /*u32 val; */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302825 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002826 int i;
2827 u8 *p;
2828 int r = 0;
2829 u8 b1, b2, b3, b4;
2830
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302831 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002832 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
2833
2834 /* len + header */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302835 if (dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002836 DSSERR("unable to send long packet: packet too long.\n");
2837 return -EINVAL;
2838 }
2839
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302840 dsi_vc_config_l4(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002841
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302842 dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002843
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002844 p = data;
2845 for (i = 0; i < len >> 2; i++) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302846 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002847 DSSDBG("\tsending full packet %d\n", i);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002848
2849 b1 = *p++;
2850 b2 = *p++;
2851 b3 = *p++;
2852 b4 = *p++;
2853
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302854 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002855 }
2856
2857 i = len % 4;
2858 if (i) {
2859 b1 = 0; b2 = 0; b3 = 0;
2860
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302861 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002862 DSSDBG("\tsending remainder bytes %d\n", i);
2863
2864 switch (i) {
2865 case 3:
2866 b1 = *p++;
2867 b2 = *p++;
2868 b3 = *p++;
2869 break;
2870 case 2:
2871 b1 = *p++;
2872 b2 = *p++;
2873 break;
2874 case 1:
2875 b1 = *p++;
2876 break;
2877 }
2878
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302879 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002880 }
2881
2882 return r;
2883}
2884
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302885static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
2886 u8 data_type, u16 data, u8 ecc)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002887{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302888 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002889 u32 r;
2890 u8 data_id;
2891
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302892 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002893
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302894 if (dsi->debug_write)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002895 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
2896 channel,
2897 data_type, data & 0xff, (data >> 8) & 0xff);
2898
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302899 dsi_vc_config_l4(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002900
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302901 if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002902 DSSERR("ERROR FIFO FULL, aborting transfer\n");
2903 return -EINVAL;
2904 }
2905
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302906 data_id = data_type | dsi->vc[channel].vc_id << 6;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002907
2908 r = (data_id << 0) | (data << 8) | (ecc << 24);
2909
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302910 dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002911
2912 return 0;
2913}
2914
Archit Taneja1ffefe72011-05-12 17:26:24 +05302915int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002916{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302917 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002918 u8 nullpkg[] = {0, 0, 0, 0};
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302919
2920 return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg,
2921 4, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002922}
2923EXPORT_SYMBOL(dsi_vc_send_null);
2924
Archit Taneja1ffefe72011-05-12 17:26:24 +05302925int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
2926 u8 *data, int len)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002927{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302928 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002929 int r;
2930
2931 BUG_ON(len == 0);
2932
2933 if (len == 1) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302934 r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002935 data[0], 0);
2936 } else if (len == 2) {
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302937 r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002938 data[0] | (data[1] << 8), 0);
2939 } else {
2940 /* 0x39 = DCS Long Write */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302941 r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002942 data, len, 0);
2943 }
2944
2945 return r;
2946}
2947EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
2948
Archit Taneja1ffefe72011-05-12 17:26:24 +05302949int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
2950 int len)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002951{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302952 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002953 int r;
2954
Archit Taneja1ffefe72011-05-12 17:26:24 +05302955 r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002956 if (r)
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02002957 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002958
Archit Taneja1ffefe72011-05-12 17:26:24 +05302959 r = dsi_vc_send_bta_sync(dssdev, channel);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02002960 if (r)
2961 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002962
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302963 /* RX_FIFO_NOT_EMPTY */
2964 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
Tomi Valkeinenb63ac1e2010-04-09 13:20:57 +03002965 DSSERR("rx fifo not empty after write, dumping data:\n");
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302966 dsi_vc_flush_receive_data(dsidev, channel);
Tomi Valkeinenb63ac1e2010-04-09 13:20:57 +03002967 r = -EIO;
2968 goto err;
2969 }
2970
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02002971 return 0;
2972err:
2973 DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
2974 channel, data[0], len);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002975 return r;
2976}
2977EXPORT_SYMBOL(dsi_vc_dcs_write);
2978
Archit Taneja1ffefe72011-05-12 17:26:24 +05302979int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02002980{
Archit Taneja1ffefe72011-05-12 17:26:24 +05302981 return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02002982}
2983EXPORT_SYMBOL(dsi_vc_dcs_write_0);
2984
Archit Taneja1ffefe72011-05-12 17:26:24 +05302985int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
2986 u8 param)
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02002987{
2988 u8 buf[2];
2989 buf[0] = dcs_cmd;
2990 buf[1] = param;
Archit Taneja1ffefe72011-05-12 17:26:24 +05302991 return dsi_vc_dcs_write(dssdev, channel, buf, 2);
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02002992}
2993EXPORT_SYMBOL(dsi_vc_dcs_write_1);
2994
Archit Taneja1ffefe72011-05-12 17:26:24 +05302995int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
2996 u8 *buf, int buflen)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02002997{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302998 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05302999 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003000 u32 val;
3001 u8 dt;
3002 int r;
3003
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303004 if (dsi->debug_read)
Tomi Valkeinenff90a342009-12-03 13:38:04 +02003005 DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003006
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303007 r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003008 if (r)
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003009 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003010
Archit Taneja1ffefe72011-05-12 17:26:24 +05303011 r = dsi_vc_send_bta_sync(dssdev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003012 if (r)
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003013 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003014
3015 /* RX_FIFO_NOT_EMPTY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303016 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003017 DSSERR("RX fifo empty when trying to read.\n");
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003018 r = -EIO;
3019 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003020 }
3021
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303022 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303023 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003024 DSSDBG("\theader: %08x\n", val);
3025 dt = FLD_GET(val, 5, 0);
3026 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
3027 u16 err = FLD_GET(val, 23, 8);
3028 dsi_show_rx_ack_with_err(err);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003029 r = -EIO;
3030 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003031
3032 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
3033 u8 data = FLD_GET(val, 15, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303034 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003035 DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
3036
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003037 if (buflen < 1) {
3038 r = -EIO;
3039 goto err;
3040 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003041
3042 buf[0] = data;
3043
3044 return 1;
3045 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
3046 u16 data = FLD_GET(val, 23, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303047 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003048 DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
3049
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003050 if (buflen < 2) {
3051 r = -EIO;
3052 goto err;
3053 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003054
3055 buf[0] = data & 0xff;
3056 buf[1] = (data >> 8) & 0xff;
3057
3058 return 2;
3059 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
3060 int w;
3061 int len = FLD_GET(val, 23, 8);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303062 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003063 DSSDBG("\tDCS long response, len %d\n", len);
3064
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003065 if (len > buflen) {
3066 r = -EIO;
3067 goto err;
3068 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003069
3070 /* two byte checksum ends the packet, not included in len */
3071 for (w = 0; w < len + 2;) {
3072 int b;
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303073 val = dsi_read_reg(dsidev,
3074 DSI_VC_SHORT_PACKET_HEADER(channel));
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303075 if (dsi->debug_read)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003076 DSSDBG("\t\t%02x %02x %02x %02x\n",
3077 (val >> 0) & 0xff,
3078 (val >> 8) & 0xff,
3079 (val >> 16) & 0xff,
3080 (val >> 24) & 0xff);
3081
3082 for (b = 0; b < 4; ++b) {
3083 if (w < len)
3084 buf[w] = (val >> (b * 8)) & 0xff;
3085 /* we discard the 2 byte checksum */
3086 ++w;
3087 }
3088 }
3089
3090 return len;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003091 } else {
3092 DSSERR("\tunknown datatype 0x%02x\n", dt);
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003093 r = -EIO;
3094 goto err;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003095 }
Tomi Valkeinen5d68e032010-02-26 11:32:56 +02003096
3097 BUG();
3098err:
3099 DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
3100 channel, dcs_cmd);
3101 return r;
3102
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003103}
3104EXPORT_SYMBOL(dsi_vc_dcs_read);
3105
Archit Taneja1ffefe72011-05-12 17:26:24 +05303106int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3107 u8 *data)
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003108{
3109 int r;
3110
Archit Taneja1ffefe72011-05-12 17:26:24 +05303111 r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1);
Tomi Valkeinen828c48f2009-12-16 14:53:15 +02003112
3113 if (r < 0)
3114 return r;
3115
3116 if (r != 1)
3117 return -EIO;
3118
3119 return 0;
3120}
3121EXPORT_SYMBOL(dsi_vc_dcs_read_1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003122
Archit Taneja1ffefe72011-05-12 17:26:24 +05303123int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3124 u8 *data1, u8 *data2)
Tomi Valkeinen53055aa2010-02-25 11:38:13 +02003125{
Tomi Valkeinen0c244f72010-06-09 15:19:29 +03003126 u8 buf[2];
Tomi Valkeinen53055aa2010-02-25 11:38:13 +02003127 int r;
3128
Archit Taneja1ffefe72011-05-12 17:26:24 +05303129 r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2);
Tomi Valkeinen53055aa2010-02-25 11:38:13 +02003130
3131 if (r < 0)
3132 return r;
3133
3134 if (r != 2)
3135 return -EIO;
3136
Tomi Valkeinen0c244f72010-06-09 15:19:29 +03003137 *data1 = buf[0];
3138 *data2 = buf[1];
3139
Tomi Valkeinen53055aa2010-02-25 11:38:13 +02003140 return 0;
3141}
3142EXPORT_SYMBOL(dsi_vc_dcs_read_2);
3143
Archit Taneja1ffefe72011-05-12 17:26:24 +05303144int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
3145 u16 len)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003146{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303147 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3148
3149 return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003150 len, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003151}
3152EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
3153
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303154static int dsi_enter_ulps(struct platform_device *dsidev)
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003155{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303156 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003157 DECLARE_COMPLETION_ONSTACK(completion);
3158 int r;
3159
3160 DSSDBGF();
3161
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303162 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003163
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303164 WARN_ON(dsi->ulps_enabled);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003165
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303166 if (dsi->ulps_enabled)
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003167 return 0;
3168
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303169 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003170 DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
3171 return -EIO;
3172 }
3173
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303174 dsi_sync_vc(dsidev, 0);
3175 dsi_sync_vc(dsidev, 1);
3176 dsi_sync_vc(dsidev, 2);
3177 dsi_sync_vc(dsidev, 3);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003178
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303179 dsi_force_tx_stop_mode_io(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003180
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303181 dsi_vc_enable(dsidev, 0, false);
3182 dsi_vc_enable(dsidev, 1, false);
3183 dsi_vc_enable(dsidev, 2, false);
3184 dsi_vc_enable(dsidev, 3, false);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003185
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303186 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003187 DSSERR("HS busy when enabling ULPS\n");
3188 return -EIO;
3189 }
3190
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303191 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003192 DSSERR("LP busy when enabling ULPS\n");
3193 return -EIO;
3194 }
3195
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303196 r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003197 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3198 if (r)
3199 return r;
3200
3201 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
3202 /* LANEx_ULPS_SIG2 */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303203 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2),
3204 7, 5);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003205
3206 if (wait_for_completion_timeout(&completion,
3207 msecs_to_jiffies(1000)) == 0) {
3208 DSSERR("ULPS enable timeout\n");
3209 r = -EIO;
3210 goto err;
3211 }
3212
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303213 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003214 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3215
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303216 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003217
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303218 dsi_if_enable(dsidev, false);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003219
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303220 dsi->ulps_enabled = true;
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003221
3222 return 0;
3223
3224err:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303225 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03003226 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3227 return r;
3228}
3229
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303230static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
3231 unsigned ticks, bool x4, bool x16)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003232{
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003233 unsigned long fck;
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003234 unsigned long total_ticks;
3235 u32 r;
3236
3237 BUG_ON(ticks > 0x1fff);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003238
3239 /* ticks in DSI_FCK */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303240 fck = dsi_fclk_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003241
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303242 r = dsi_read_reg(dsidev, DSI_TIMING2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003243 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003244 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
3245 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003246 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303247 dsi_write_reg(dsidev, DSI_TIMING2, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003248
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003249 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3250
3251 DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3252 total_ticks,
3253 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3254 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003255}
3256
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303257static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
3258 bool x8, bool x16)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003259{
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003260 unsigned long fck;
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003261 unsigned long total_ticks;
3262 u32 r;
3263
3264 BUG_ON(ticks > 0x1fff);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003265
3266 /* ticks in DSI_FCK */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303267 fck = dsi_fclk_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003268
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303269 r = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003270 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003271 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
3272 r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003273 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303274 dsi_write_reg(dsidev, DSI_TIMING1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003275
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003276 total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
3277
3278 DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
3279 total_ticks,
3280 ticks, x8 ? " x8" : "", x16 ? " x16" : "",
3281 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003282}
3283
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303284static void dsi_set_stop_state_counter(struct platform_device *dsidev,
3285 unsigned ticks, bool x4, bool x16)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003286{
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003287 unsigned long fck;
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003288 unsigned long total_ticks;
3289 u32 r;
3290
3291 BUG_ON(ticks > 0x1fff);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003292
3293 /* ticks in DSI_FCK */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303294 fck = dsi_fclk_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003295
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303296 r = dsi_read_reg(dsidev, DSI_TIMING1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003297 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003298 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
3299 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003300 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303301 dsi_write_reg(dsidev, DSI_TIMING1, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003302
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003303 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3304
3305 DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
3306 total_ticks,
3307 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3308 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003309}
3310
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303311static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
3312 unsigned ticks, bool x4, bool x16)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003313{
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003314 unsigned long fck;
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003315 unsigned long total_ticks;
3316 u32 r;
3317
3318 BUG_ON(ticks > 0x1fff);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003319
3320 /* ticks in TxByteClkHS */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303321 fck = dsi_get_txbyteclkhs(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003322
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303323 r = dsi_read_reg(dsidev, DSI_TIMING2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003324 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003325 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
3326 r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003327 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303328 dsi_write_reg(dsidev, DSI_TIMING2, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003329
Tomi Valkeinen4ffa3572010-04-12 10:40:12 +03003330 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3331
3332 DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3333 total_ticks,
3334 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3335 (total_ticks * 1000) / (fck / 1000 / 1000));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003336}
3337static int dsi_proto_config(struct omap_dss_device *dssdev)
3338{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303339 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003340 u32 r;
3341 int buswidth = 0;
3342
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303343 dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
Tomi Valkeinendd8079d2009-12-16 16:49:03 +02003344 DSI_FIFO_SIZE_32,
3345 DSI_FIFO_SIZE_32,
3346 DSI_FIFO_SIZE_32);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003347
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303348 dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
Tomi Valkeinendd8079d2009-12-16 16:49:03 +02003349 DSI_FIFO_SIZE_32,
3350 DSI_FIFO_SIZE_32,
3351 DSI_FIFO_SIZE_32);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003352
3353 /* XXX what values for the timeouts? */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303354 dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
3355 dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
3356 dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
3357 dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003358
3359 switch (dssdev->ctrl.pixel_size) {
3360 case 16:
3361 buswidth = 0;
3362 break;
3363 case 18:
3364 buswidth = 1;
3365 break;
3366 case 24:
3367 buswidth = 2;
3368 break;
3369 default:
3370 BUG();
3371 }
3372
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303373 r = dsi_read_reg(dsidev, DSI_CTRL);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003374 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
3375 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
3376 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
3377 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
3378 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
3379 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
3380 r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
3381 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
3382 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
Archit Taneja9613c022011-03-22 06:33:36 -05003383 if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
3384 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
3385 /* DCS_CMD_CODE, 1=start, 0=continue */
3386 r = FLD_MOD(r, 0, 25, 25);
3387 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003388
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303389 dsi_write_reg(dsidev, DSI_CTRL, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003390
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303391 dsi_vc_initial_config(dsidev, 0);
3392 dsi_vc_initial_config(dsidev, 1);
3393 dsi_vc_initial_config(dsidev, 2);
3394 dsi_vc_initial_config(dsidev, 3);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003395
3396 return 0;
3397}
3398
3399static void dsi_proto_timings(struct omap_dss_device *dssdev)
3400{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303401 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003402 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
3403 unsigned tclk_pre, tclk_post;
3404 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
3405 unsigned ths_trail, ths_exit;
3406 unsigned ddr_clk_pre, ddr_clk_post;
3407 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
3408 unsigned ths_eot;
3409 u32 r;
3410
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303411 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003412 ths_prepare = FLD_GET(r, 31, 24);
3413 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
3414 ths_zero = ths_prepare_ths_zero - ths_prepare;
3415 ths_trail = FLD_GET(r, 15, 8);
3416 ths_exit = FLD_GET(r, 7, 0);
3417
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303418 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003419 tlpx = FLD_GET(r, 22, 16) * 2;
3420 tclk_trail = FLD_GET(r, 15, 8);
3421 tclk_zero = FLD_GET(r, 7, 0);
3422
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303423 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003424 tclk_prepare = FLD_GET(r, 7, 0);
3425
3426 /* min 8*UI */
3427 tclk_pre = 20;
3428 /* min 60ns + 52*UI */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303429 tclk_post = ns2ddr(dsidev, 60) + 26;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003430
3431 /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
3432 if (dssdev->phy.dsi.data1_lane != 0 &&
3433 dssdev->phy.dsi.data2_lane != 0)
3434 ths_eot = 2;
3435 else
3436 ths_eot = 4;
3437
3438 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
3439 4);
3440 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
3441
3442 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
3443 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
3444
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303445 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003446 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
3447 r = FLD_MOD(r, ddr_clk_post, 7, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303448 dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003449
3450 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
3451 ddr_clk_pre,
3452 ddr_clk_post);
3453
3454 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
3455 DIV_ROUND_UP(ths_prepare, 4) +
3456 DIV_ROUND_UP(ths_zero + 3, 4);
3457
3458 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
3459
3460 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
3461 FLD_VAL(exit_hs_mode_lat, 15, 0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303462 dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003463
3464 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
3465 enter_hs_mode_lat, exit_hs_mode_lat);
3466}
3467
3468
3469#define DSI_DECL_VARS \
3470 int __dsi_cb = 0; u32 __dsi_cv = 0;
3471
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303472#define DSI_FLUSH(dsidev, ch) \
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003473 if (__dsi_cb > 0) { \
3474 /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303475 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003476 __dsi_cb = __dsi_cv = 0; \
3477 }
3478
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303479#define DSI_PUSH(dsidev, ch, data) \
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003480 do { \
3481 __dsi_cv |= (data) << (__dsi_cb * 8); \
3482 /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
3483 if (++__dsi_cb > 3) \
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303484 DSI_FLUSH(dsidev, ch); \
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003485 } while (0)
3486
3487static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
3488 int x, int y, int w, int h)
3489{
3490 /* Note: supports only 24bit colors in 32bit container */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303491 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303492 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003493 int first = 1;
3494 int fifo_stalls = 0;
3495 int max_dsi_packet_size;
3496 int max_data_per_packet;
3497 int max_pixels_per_packet;
3498 int pixels_left;
3499 int bytespp = dssdev->ctrl.pixel_size / 8;
3500 int scr_width;
3501 u32 __iomem *data;
3502 int start_offset;
3503 int horiz_inc;
3504 int current_x;
3505 struct omap_overlay *ovl;
3506
3507 debug_irq = 0;
3508
3509 DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
3510 x, y, w, h);
3511
3512 ovl = dssdev->manager->overlays[0];
3513
3514 if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
3515 return -EINVAL;
3516
3517 if (dssdev->ctrl.pixel_size != 24)
3518 return -EINVAL;
3519
3520 scr_width = ovl->info.screen_width;
3521 data = ovl->info.vaddr;
3522
3523 start_offset = scr_width * y + x;
3524 horiz_inc = scr_width - w;
3525 current_x = x;
3526
3527 /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
3528 * in fifo */
3529
3530 /* When using CPU, max long packet size is TX buffer size */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303531 max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003532
3533 /* we seem to get better perf if we divide the tx fifo to half,
3534 and while the other half is being sent, we fill the other half
3535 max_dsi_packet_size /= 2; */
3536
3537 max_data_per_packet = max_dsi_packet_size - 4 - 1;
3538
3539 max_pixels_per_packet = max_data_per_packet / bytespp;
3540
3541 DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
3542
3543 pixels_left = w * h;
3544
3545 DSSDBG("total pixels %d\n", pixels_left);
3546
3547 data += start_offset;
3548
3549 while (pixels_left > 0) {
3550 /* 0x2c = write_memory_start */
3551 /* 0x3c = write_memory_continue */
3552 u8 dcs_cmd = first ? 0x2c : 0x3c;
3553 int pixels;
3554 DSI_DECL_VARS;
3555 first = 0;
3556
3557#if 1
3558 /* using fifo not empty */
3559 /* TX_FIFO_NOT_EMPTY */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303560 while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003561 fifo_stalls++;
3562 if (fifo_stalls > 0xfffff) {
3563 DSSERR("fifo stalls overflow, pixels left %d\n",
3564 pixels_left);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303565 dsi_if_enable(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003566 return -EIO;
3567 }
Tomi Valkeinen24be78b2010-01-07 14:19:48 +02003568 udelay(1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003569 }
3570#elif 1
3571 /* using fifo emptiness */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303572 while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003573 max_dsi_packet_size) {
3574 fifo_stalls++;
3575 if (fifo_stalls > 0xfffff) {
3576 DSSERR("fifo stalls overflow, pixels left %d\n",
3577 pixels_left);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303578 dsi_if_enable(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003579 return -EIO;
3580 }
3581 }
3582#else
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303583 while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS,
3584 7, 0) + 1) * 4 == 0) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003585 fifo_stalls++;
3586 if (fifo_stalls > 0xfffff) {
3587 DSSERR("fifo stalls overflow, pixels left %d\n",
3588 pixels_left);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303589 dsi_if_enable(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003590 return -EIO;
3591 }
3592 }
3593#endif
3594 pixels = min(max_pixels_per_packet, pixels_left);
3595
3596 pixels_left -= pixels;
3597
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303598 dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003599 1 + pixels * bytespp, 0);
3600
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303601 DSI_PUSH(dsidev, 0, dcs_cmd);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003602
3603 while (pixels-- > 0) {
3604 u32 pix = __raw_readl(data++);
3605
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303606 DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff);
3607 DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff);
3608 DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003609
3610 current_x++;
3611 if (current_x == x+w) {
3612 current_x = x;
3613 data += horiz_inc;
3614 }
3615 }
3616
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303617 DSI_FLUSH(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003618 }
3619
3620 return 0;
3621}
3622
3623static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
3624 u16 x, u16 y, u16 w, u16 h)
3625{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303626 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303627 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003628 unsigned bytespp;
3629 unsigned bytespl;
3630 unsigned bytespf;
3631 unsigned total_len;
3632 unsigned packet_payload;
3633 unsigned packet_len;
3634 u32 l;
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03003635 int r;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303636 const unsigned channel = dsi->update_channel;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003637 /* line buffer is 1024 x 24bits */
3638 /* XXX: for some reason using full buffer size causes considerable TX
3639 * slowdown with update sizes that fill the whole buffer */
3640 const unsigned line_buf_size = 1023 * 3;
3641
Tomi Valkeinen446f7bf2010-01-11 16:12:31 +02003642 DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
3643 x, y, w, h);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003644
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303645 dsi_vc_config_vp(dsidev, channel);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003646
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003647 bytespp = dssdev->ctrl.pixel_size / 8;
3648 bytespl = w * bytespp;
3649 bytespf = bytespl * h;
3650
3651 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
3652 * number of lines in a packet. See errata about VP_CLK_RATIO */
3653
3654 if (bytespf < line_buf_size)
3655 packet_payload = bytespf;
3656 else
3657 packet_payload = (line_buf_size) / bytespl * bytespl;
3658
3659 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
3660 total_len = (bytespf / packet_payload) * packet_len;
3661
3662 if (bytespf % packet_payload)
3663 total_len += (bytespf % packet_payload) + 1;
3664
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003665 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303666 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003667
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303668 dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
3669 packet_len, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003670
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303671 if (dsi->te_enabled)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003672 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
3673 else
3674 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303675 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003676
3677 /* We put SIDLEMODE to no-idle for the duration of the transfer,
3678 * because DSS interrupts are not capable of waking up the CPU and the
3679 * framedone interrupt could be delayed for quite a long time. I think
3680 * the same goes for any DSS interrupts, but for some reason I have not
3681 * seen the problem anywhere else than here.
3682 */
3683 dispc_disable_sidle();
3684
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303685 dsi_perf_mark_start(dsidev);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003686
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303687 r = queue_delayed_work(dsi->workqueue, &dsi->framedone_timeout_work,
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003688 msecs_to_jiffies(250));
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03003689 BUG_ON(r == 0);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003690
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003691 dss_start_update(dssdev);
3692
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303693 if (dsi->te_enabled) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003694 /* disable LP_RX_TO, so that we can receive TE. Time to wait
3695 * for TE is longer than the timer allows */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303696 REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003697
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303698 dsi_vc_send_bta(dsidev, channel);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003699
3700#ifdef DSI_CATCH_MISSING_TE
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303701 mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003702#endif
3703 }
3704}
3705
3706#ifdef DSI_CATCH_MISSING_TE
3707static void dsi_te_timeout(unsigned long arg)
3708{
3709 DSSERR("TE not received for 250ms!\n");
3710}
3711#endif
3712
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303713static void dsi_handle_framedone(struct platform_device *dsidev, int error)
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003714{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303715 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3716
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003717 /* SIDLEMODE back to smart-idle */
3718 dispc_enable_sidle();
3719
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303720 if (dsi->te_enabled) {
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003721 /* enable LP_RX_TO again after the TE */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303722 REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003723 }
3724
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303725 dsi->framedone_callback(error, dsi->framedone_data);
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003726
3727 if (!error)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303728 dsi_perf_show(dsidev, "DISPC");
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003729}
3730
3731static void dsi_framedone_timeout_work_callback(struct work_struct *work)
3732{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303733 struct dsi_data *dsi = container_of(work, struct dsi_data,
3734 framedone_timeout_work.work);
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03003735 /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
3736 * 250ms which would conflict with this timeout work. What should be
3737 * done is first cancel the transfer on the HW, and then cancel the
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003738 * possibly scheduled framedone work. However, cancelling the transfer
3739 * on the HW is buggy, and would probably require resetting the whole
3740 * DSI */
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03003741
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003742 DSSERR("Framedone not received for 250ms!\n");
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003743
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303744 dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003745}
3746
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003747static void dsi_framedone_irq_callback(void *data, u32 mask)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003748{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303749 struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
3750 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303751 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3752
Tomi Valkeinenab83b142010-06-09 15:31:01 +03003753 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
3754 * turns itself off. However, DSI still has the pixels in its buffers,
3755 * and is sending the data.
3756 */
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003757
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303758 __cancel_delayed_work(&dsi->framedone_timeout_work);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003759
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303760 dsi_handle_framedone(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003761
Archit Tanejacf398fb2011-03-23 09:59:34 +00003762#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3763 dispc_fake_vsync_irq();
3764#endif
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003765}
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003766
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003767int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
Tomi Valkeinen26a8c252010-06-09 15:31:34 +03003768 u16 *x, u16 *y, u16 *w, u16 *h,
3769 bool enlarge_update_area)
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003770{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303771 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003772 u16 dw, dh;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003773
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003774 dssdev->driver->get_resolution(dssdev, &dw, &dh);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003775
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003776 if (*x > dw || *y > dh)
3777 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003778
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003779 if (*x + *w > dw)
3780 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003781
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003782 if (*y + *h > dh)
3783 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003784
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003785 if (*w == 1)
3786 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003787
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003788 if (*w == 0 || *h == 0)
3789 return -EINVAL;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003790
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303791 dsi_perf_mark_setup(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003792
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003793 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
Tomi Valkeinen26a8c252010-06-09 15:31:34 +03003794 dss_setup_partial_planes(dssdev, x, y, w, h,
3795 enlarge_update_area);
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003796 dispc_set_lcd_size(dssdev->manager->id, *w, *h);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003797 }
3798
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003799 return 0;
3800}
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003801EXPORT_SYMBOL(omap_dsi_prepare_update);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003802
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003803int omap_dsi_update(struct omap_dss_device *dssdev,
3804 int channel,
3805 u16 x, u16 y, u16 w, u16 h,
3806 void (*callback)(int, void *), void *data)
3807{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303808 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303809 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303810
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303811 dsi->update_channel = channel;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003812
Tomi Valkeinena6027712010-05-25 17:01:28 +03003813 /* OMAP DSS cannot send updates of odd widths.
3814 * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
3815 * here to make sure we catch erroneous updates. Otherwise we'll only
3816 * see rather obscure HW error happening, as DSS halts. */
3817 BUG_ON(x % 2 == 1);
3818
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003819 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303820 dsi->framedone_callback = callback;
3821 dsi->framedone_data = data;
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003822
Archit Tanejaf1da39d2011-05-12 17:26:27 +05303823 dsi->update_region.x = x;
3824 dsi->update_region.y = y;
3825 dsi->update_region.w = w;
3826 dsi->update_region.h = h;
3827 dsi->update_region.device = dssdev;
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003828
3829 dsi_update_screen_dispc(dssdev, x, y, w, h);
3830 } else {
Archit Tanejae9c31af2010-07-14 14:11:50 +02003831 int r;
3832
3833 r = dsi_update_screen_l4(dssdev, x, y, w, h);
3834 if (r)
3835 return r;
3836
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303837 dsi_perf_show(dsidev, "L4");
Tomi Valkeinen18946f62010-01-12 14:16:41 +02003838 callback(0, data);
3839 }
3840
3841 return 0;
3842}
3843EXPORT_SYMBOL(omap_dsi_update);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003844
3845/* Display funcs */
3846
3847static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
3848{
3849 int r;
3850
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303851 r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003852 DISPC_IRQ_FRAMEDONE);
3853 if (r) {
3854 DSSERR("can't get FRAMEDONE irq\n");
3855 return r;
3856 }
3857
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003858 dispc_set_lcd_display_type(dssdev->manager->id,
3859 OMAP_DSS_LCD_DISPLAY_TFT);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003860
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003861 dispc_set_parallel_interface_mode(dssdev->manager->id,
3862 OMAP_DSS_PARALLELMODE_DSI);
3863 dispc_enable_fifohandcheck(dssdev->manager->id, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003864
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003865 dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003866
3867 {
3868 struct omap_video_timings timings = {
3869 .hsw = 1,
3870 .hfp = 1,
3871 .hbp = 1,
3872 .vsw = 1,
3873 .vfp = 0,
3874 .vbp = 0,
3875 };
3876
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003877 dispc_set_lcd_timings(dssdev->manager->id, &timings);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003878 }
3879
3880 return 0;
3881}
3882
3883static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
3884{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303885 omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev,
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003886 DISPC_IRQ_FRAMEDONE);
3887}
3888
3889static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
3890{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303891 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003892 struct dsi_clock_info cinfo;
3893 int r;
3894
Archit Taneja1bb47832011-02-24 14:17:30 +05303895 /* we always use DSS_CLK_SYSCK as input clock */
3896 cinfo.use_sys_clk = true;
Tomi Valkeinenc6940a32011-02-22 13:36:10 +02003897 cinfo.regn = dssdev->clocks.dsi.regn;
3898 cinfo.regm = dssdev->clocks.dsi.regm;
3899 cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
3900 cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003901 r = dsi_calc_clock_rates(dssdev, &cinfo);
Ville Syrjäläebf0a3f2010-04-22 22:50:05 +02003902 if (r) {
3903 DSSERR("Failed to calc dsi clocks\n");
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003904 return r;
Ville Syrjäläebf0a3f2010-04-22 22:50:05 +02003905 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003906
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303907 r = dsi_pll_set_clock_div(dsidev, &cinfo);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003908 if (r) {
3909 DSSERR("Failed to set dsi clocks\n");
3910 return r;
3911 }
3912
3913 return 0;
3914}
3915
3916static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
3917{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303918 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003919 struct dispc_clock_info dispc_cinfo;
3920 int r;
3921 unsigned long long fck;
3922
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303923 fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003924
Archit Tanejae8881662011-04-12 13:52:24 +05303925 dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
3926 dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003927
3928 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
3929 if (r) {
3930 DSSERR("Failed to calc dispc clocks\n");
3931 return r;
3932 }
3933
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003934 r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003935 if (r) {
3936 DSSERR("Failed to set dispc clocks\n");
3937 return r;
3938 }
3939
3940 return 0;
3941}
3942
3943static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
3944{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303945 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003946 int r;
3947
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303948 r = dsi_pll_init(dsidev, true, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003949 if (r)
3950 goto err0;
3951
3952 r = dsi_configure_dsi_clocks(dssdev);
3953 if (r)
3954 goto err1;
3955
Archit Tanejae8881662011-04-12 13:52:24 +05303956 dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
3957 dss_select_dsi_clk_source(dssdev->clocks.dsi.dsi_fclk_src);
Archit Taneja9613c022011-03-22 06:33:36 -05003958 dss_select_lcd_clk_source(dssdev->manager->id,
Archit Tanejae8881662011-04-12 13:52:24 +05303959 dssdev->clocks.dispc.channel.lcd_clk_src);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003960
3961 DSSDBG("PLL OK\n");
3962
3963 r = dsi_configure_dispc_clocks(dssdev);
3964 if (r)
3965 goto err2;
3966
Tomi Valkeinencc5c1852010-10-06 15:18:13 +03003967 r = dsi_cio_init(dssdev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003968 if (r)
3969 goto err2;
3970
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303971 _dsi_print_reset_status(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003972
3973 dsi_proto_timings(dssdev);
3974 dsi_set_lp_clk_divisor(dssdev);
3975
3976 if (1)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303977 _dsi_print_reset_status(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003978
3979 r = dsi_proto_config(dssdev);
3980 if (r)
3981 goto err3;
3982
3983 /* enable interface */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303984 dsi_vc_enable(dsidev, 0, 1);
3985 dsi_vc_enable(dsidev, 1, 1);
3986 dsi_vc_enable(dsidev, 2, 1);
3987 dsi_vc_enable(dsidev, 3, 1);
3988 dsi_if_enable(dsidev, 1);
3989 dsi_force_tx_stop_mode_io(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003990
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003991 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003992err3:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303993 dsi_cio_uninit(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003994err2:
Archit Taneja89a35e52011-04-12 13:52:23 +05303995 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
3996 dss_select_dsi_clk_source(OMAP_DSS_CLK_SRC_FCK);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003997err1:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05303998 dsi_pll_uninit(dsidev, true);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02003999err0:
4000 return r;
4001}
4002
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03004003static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004004 bool disconnect_lanes, bool enter_ulps)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004005{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304006 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304007 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304008
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304009 if (enter_ulps && !dsi->ulps_enabled)
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304010 dsi_enter_ulps(dsidev);
Tomi Valkeinen40885ab2010-07-28 15:53:38 +03004011
Ville Syrjäläd7370102010-04-22 22:50:09 +02004012 /* disable interface */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304013 dsi_if_enable(dsidev, 0);
4014 dsi_vc_enable(dsidev, 0, 0);
4015 dsi_vc_enable(dsidev, 1, 0);
4016 dsi_vc_enable(dsidev, 2, 0);
4017 dsi_vc_enable(dsidev, 3, 0);
Ville Syrjäläd7370102010-04-22 22:50:09 +02004018
Archit Taneja89a35e52011-04-12 13:52:23 +05304019 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
4020 dss_select_dsi_clk_source(OMAP_DSS_CLK_SRC_FCK);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304021 dsi_cio_uninit(dsidev);
4022 dsi_pll_uninit(dsidev, disconnect_lanes);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004023}
4024
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304025static int dsi_core_init(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004026{
4027 /* Autoidle */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304028 REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004029
4030 /* ENWAKEUP */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304031 REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004032
4033 /* SIDLEMODE smart-idle */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304034 REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004035
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304036 _dsi_initialize_irq(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004037
4038 return 0;
4039}
4040
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004041int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004042{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304043 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304044 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004045 int r = 0;
4046
4047 DSSDBG("dsi_display_enable\n");
4048
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304049 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004050
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304051 mutex_lock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004052
4053 r = omap_dss_start_device(dssdev);
4054 if (r) {
4055 DSSERR("failed to start device\n");
4056 goto err0;
4057 }
4058
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004059 enable_clocks(1);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304060 dsi_enable_pll_clock(dsidev, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004061
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304062 r = _dsi_reset(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004063 if (r)
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004064 goto err1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004065
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304066 dsi_core_init(dsidev);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004067
4068 r = dsi_display_init_dispc(dssdev);
4069 if (r)
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004070 goto err1;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004071
4072 r = dsi_display_init_dsi(dssdev);
4073 if (r)
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004074 goto err2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004075
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304076 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004077
4078 return 0;
4079
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004080err2:
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004081 dsi_display_uninit_dispc(dssdev);
4082err1:
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004083 enable_clocks(0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304084 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004085 omap_dss_stop_device(dssdev);
4086err0:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304087 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004088 DSSDBG("dsi_display_enable FAILED\n");
4089 return r;
4090}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004091EXPORT_SYMBOL(omapdss_dsi_display_enable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004092
Tomi Valkeinen2a89dc12010-07-30 12:39:34 +03004093void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004094 bool disconnect_lanes, bool enter_ulps)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004095{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304096 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304097 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304098
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004099 DSSDBG("dsi_display_disable\n");
4100
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304101 WARN_ON(!dsi_bus_is_locked(dsidev));
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004102
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304103 mutex_lock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004104
4105 dsi_display_uninit_dispc(dssdev);
4106
Tomi Valkeinen22d6d672010-10-11 11:33:30 +03004107 dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004108
4109 enable_clocks(0);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304110 dsi_enable_pll_clock(dsidev, 0);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004111
4112 omap_dss_stop_device(dssdev);
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004113
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304114 mutex_unlock(&dsi->lock);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004115}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +02004116EXPORT_SYMBOL(omapdss_dsi_display_disable);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004117
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004118int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004119{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304120 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4121 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4122
4123 dsi->te_enabled = enable;
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004124 return 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004125}
Tomi Valkeinen225b6502010-01-11 15:11:01 +02004126EXPORT_SYMBOL(omapdss_dsi_enable_te);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004127
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004128void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
4129 u32 fifo_size, enum omap_burst_size *burst_size,
4130 u32 *fifo_low, u32 *fifo_high)
4131{
4132 unsigned burst_size_bytes;
4133
4134 *burst_size = OMAP_DSS_BURST_16x32;
4135 burst_size_bytes = 16 * 32 / 8;
4136
4137 *fifo_high = fifo_size - burst_size_bytes;
Tomi Valkeinen36194b42010-05-18 13:35:37 +03004138 *fifo_low = fifo_size - burst_size_bytes * 2;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004139}
4140
4141int dsi_init_display(struct omap_dss_device *dssdev)
4142{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304143 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4144 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4145
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004146 DSSDBG("DSI init\n");
4147
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004148 /* XXX these should be figured out dynamically */
4149 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
4150 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
4151
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304152 if (dsi->vdds_dsi_reg == NULL) {
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004153 struct regulator *vdds_dsi;
4154
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304155 vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004156
4157 if (IS_ERR(vdds_dsi)) {
4158 DSSERR("can't get VDDS_DSI regulator\n");
4159 return PTR_ERR(vdds_dsi);
4160 }
4161
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304162 dsi->vdds_dsi_reg = vdds_dsi;
Tomi Valkeinen5f42f2c2011-02-22 15:53:46 +02004163 }
4164
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004165 return 0;
4166}
4167
Archit Taneja5ee3c142011-03-02 12:35:53 +05304168int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
4169{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304170 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4171 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
Archit Taneja5ee3c142011-03-02 12:35:53 +05304172 int i;
4173
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304174 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
4175 if (!dsi->vc[i].dssdev) {
4176 dsi->vc[i].dssdev = dssdev;
Archit Taneja5ee3c142011-03-02 12:35:53 +05304177 *channel = i;
4178 return 0;
4179 }
4180 }
4181
4182 DSSERR("cannot get VC for display %s", dssdev->name);
4183 return -ENOSPC;
4184}
4185EXPORT_SYMBOL(omap_dsi_request_vc);
4186
4187int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
4188{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304189 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4190 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4191
Archit Taneja5ee3c142011-03-02 12:35:53 +05304192 if (vc_id < 0 || vc_id > 3) {
4193 DSSERR("VC ID out of range\n");
4194 return -EINVAL;
4195 }
4196
4197 if (channel < 0 || channel > 3) {
4198 DSSERR("Virtual Channel out of range\n");
4199 return -EINVAL;
4200 }
4201
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304202 if (dsi->vc[channel].dssdev != dssdev) {
Archit Taneja5ee3c142011-03-02 12:35:53 +05304203 DSSERR("Virtual Channel not allocated to display %s\n",
4204 dssdev->name);
4205 return -EINVAL;
4206 }
4207
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304208 dsi->vc[channel].vc_id = vc_id;
Archit Taneja5ee3c142011-03-02 12:35:53 +05304209
4210 return 0;
4211}
4212EXPORT_SYMBOL(omap_dsi_set_vc_id);
4213
4214void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
4215{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304216 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4217 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4218
Archit Taneja5ee3c142011-03-02 12:35:53 +05304219 if ((channel >= 0 && channel <= 3) &&
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304220 dsi->vc[channel].dssdev == dssdev) {
4221 dsi->vc[channel].dssdev = NULL;
4222 dsi->vc[channel].vc_id = 0;
Archit Taneja5ee3c142011-03-02 12:35:53 +05304223 }
4224}
4225EXPORT_SYMBOL(omap_dsi_release_vc);
4226
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304227void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
Tomi Valkeinene406f902010-06-09 15:28:12 +03004228{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304229 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
Archit Taneja067a57e2011-03-02 11:57:25 +05304230 DSSERR("%s (%s) not active\n",
Archit Taneja89a35e52011-04-12 13:52:23 +05304231 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
4232 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
Tomi Valkeinene406f902010-06-09 15:28:12 +03004233}
4234
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304235void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
Tomi Valkeinene406f902010-06-09 15:28:12 +03004236{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304237 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
Archit Taneja067a57e2011-03-02 11:57:25 +05304238 DSSERR("%s (%s) not active\n",
Archit Taneja89a35e52011-04-12 13:52:23 +05304239 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
4240 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
Tomi Valkeinene406f902010-06-09 15:28:12 +03004241}
4242
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304243static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
Taneja, Archit49641112011-03-14 23:28:23 -05004244{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304245 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4246
4247 dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
4248 dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
4249 dsi->regm_dispc_max =
4250 dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
4251 dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
4252 dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
4253 dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
4254 dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
Taneja, Archit49641112011-03-14 23:28:23 -05004255}
4256
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304257static int dsi_init(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004258{
Tomi Valkeinend1f58572010-07-30 11:57:57 +03004259 struct omap_display_platform_data *dss_plat_data;
4260 struct omap_dss_board_info *board_info;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004261 u32 rev;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304262 int r, i, dsi_module = dsi_get_dsidev_id(dsidev);
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004263 struct resource *dsi_mem;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304264 struct dsi_data *dsi;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004265
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304266 dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
4267 if (!dsi) {
4268 r = -ENOMEM;
4269 goto err0;
4270 }
4271
4272 dsi->pdev = dsidev;
4273 dsi_pdev_map[dsi_module] = dsidev;
4274 dev_set_drvdata(&dsidev->dev, dsi);
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304275
4276 dss_plat_data = dsidev->dev.platform_data;
Tomi Valkeinend1f58572010-07-30 11:57:57 +03004277 board_info = dss_plat_data->board_data;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304278 dsi->dsi_mux_pads = board_info->dsi_mux_pads;
Tomi Valkeinend1f58572010-07-30 11:57:57 +03004279
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304280 spin_lock_init(&dsi->irq_lock);
4281 spin_lock_init(&dsi->errors_lock);
4282 dsi->errors = 0;
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004283
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02004284#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304285 spin_lock_init(&dsi->irq_stats_lock);
4286 dsi->irq_stats.last_reset = jiffies;
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02004287#endif
4288
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304289 mutex_init(&dsi->lock);
4290 sema_init(&dsi->bus_lock, 1);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004291
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304292 dsi->workqueue = create_singlethread_workqueue(dev_name(&dsidev->dev));
4293 if (dsi->workqueue == NULL) {
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004294 r = -ENOMEM;
4295 goto err1;
4296 }
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304297
4298 INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
4299 dsi_framedone_timeout_work_callback);
4300
4301#ifdef DSI_CATCH_MISSING_TE
4302 init_timer(&dsi->te_timer);
4303 dsi->te_timer.function = dsi_te_timeout;
4304 dsi->te_timer.data = 0;
4305#endif
4306 dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
4307 if (!dsi_mem) {
4308 DSSERR("can't get IORESOURCE_MEM DSI\n");
4309 r = -EINVAL;
archit tanejaaffe3602011-02-23 08:41:03 +00004310 goto err2;
4311 }
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304312 dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
4313 if (!dsi->base) {
4314 DSSERR("can't ioremap DSI\n");
4315 r = -ENOMEM;
4316 goto err2;
4317 }
4318 dsi->irq = platform_get_irq(dsi->pdev, 0);
4319 if (dsi->irq < 0) {
4320 DSSERR("platform_get_irq failed\n");
4321 r = -ENODEV;
4322 goto err3;
4323 }
archit tanejaaffe3602011-02-23 08:41:03 +00004324
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304325 r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
4326 dev_name(&dsidev->dev), dsi->pdev);
archit tanejaaffe3602011-02-23 08:41:03 +00004327 if (r < 0) {
4328 DSSERR("request_irq failed\n");
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304329 goto err3;
archit tanejaaffe3602011-02-23 08:41:03 +00004330 }
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004331
Archit Taneja5ee3c142011-03-02 12:35:53 +05304332 /* DSI VCs initialization */
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304333 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
4334 dsi->vc[i].mode = DSI_VC_MODE_L4;
4335 dsi->vc[i].dssdev = NULL;
4336 dsi->vc[i].vc_id = 0;
Archit Taneja5ee3c142011-03-02 12:35:53 +05304337 }
4338
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304339 dsi_calc_clock_param_ranges(dsidev);
Taneja, Archit49641112011-03-14 23:28:23 -05004340
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004341 enable_clocks(1);
4342
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304343 rev = dsi_read_reg(dsidev, DSI_REVISION);
4344 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004345 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4346
4347 enable_clocks(0);
4348
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004349 return 0;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304350err3:
4351 iounmap(dsi->base);
archit tanejaaffe3602011-02-23 08:41:03 +00004352err2:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304353 destroy_workqueue(dsi->workqueue);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004354err1:
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304355 kfree(dsi);
4356err0:
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004357 return r;
4358}
4359
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304360static void dsi_exit(struct platform_device *dsidev)
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004361{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304362 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4363
4364 if (dsi->vdds_dsi_reg != NULL) {
4365 if (dsi->vdds_dsi_enabled) {
4366 regulator_disable(dsi->vdds_dsi_reg);
4367 dsi->vdds_dsi_enabled = false;
Tomi Valkeinen88257b22010-12-20 16:26:22 +02004368 }
4369
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304370 regulator_put(dsi->vdds_dsi_reg);
4371 dsi->vdds_dsi_reg = NULL;
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004372 }
4373
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304374 free_irq(dsi->irq, dsi->pdev);
4375 iounmap(dsi->base);
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004376
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304377 destroy_workqueue(dsi->workqueue);
4378 kfree(dsi);
Tomi Valkeinen0f16aa02010-04-12 09:57:19 +03004379
Tomi Valkeinen3de7a1d2009-10-28 11:59:56 +02004380 DSSDBG("omap_dsi_exit\n");
4381}
4382
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004383/* DSI1 HW IP initialisation */
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304384static int omap_dsi1hw_probe(struct platform_device *dsidev)
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004385{
4386 int r;
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304387
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304388 r = dsi_init(dsidev);
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004389 if (r) {
4390 DSSERR("Failed to initialize DSI\n");
4391 goto err_dsi;
4392 }
4393err_dsi:
4394 return r;
4395}
4396
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304397static int omap_dsi1hw_remove(struct platform_device *dsidev)
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004398{
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304399 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4400
Archit Tanejaa72b64b2011-05-12 17:26:26 +05304401 dsi_exit(dsidev);
Archit Tanejaf1da39d2011-05-12 17:26:27 +05304402 WARN_ON(dsi->scp_clk_refcount > 0);
Senthilvadivu Guruswamyc8aac012011-01-24 06:22:02 +00004403 return 0;
4404}
4405
4406static struct platform_driver omap_dsi1hw_driver = {
4407 .probe = omap_dsi1hw_probe,
4408 .remove = omap_dsi1hw_remove,
4409 .driver = {
4410 .name = "omapdss_dsi1",
4411 .owner = THIS_MODULE,
4412 },
4413};
4414
4415int dsi_init_platform_driver(void)
4416{
4417 return platform_driver_register(&omap_dsi1hw_driver);
4418}
4419
4420void dsi_uninit_platform_driver(void)
4421{
4422 return platform_driver_unregister(&omap_dsi1hw_driver);
4423}