dsi.c 111.1 KB
Newer Older
T
Tomi Valkeinen 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * linux/drivers/video/omap2/dss/dsi.c
 *
 * Copyright (C) 2009 Nokia Corporation
 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define DSS_SUBSYS_NAME "DSI"

#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
30
#include <linux/semaphore.h>
T
Tomi Valkeinen 已提交
31 32 33 34
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/wait.h>
35
#include <linux/workqueue.h>
36
#include <linux/sched.h>
37
#include <linux/slab.h>
38
#include <linux/debugfs.h>
T
Tomi Valkeinen 已提交
39

40
#include <video/omapdss.h>
T
Tomi Valkeinen 已提交
41 42 43
#include <plat/clock.h>

#include "dss.h"
44
#include "dss_features.h"
T
Tomi Valkeinen 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

/*#define VERBOSE_IRQ*/
#define DSI_CATCH_MISSING_TE

struct dsi_reg { u16 idx; };

#define DSI_REG(idx)		((const struct dsi_reg) { idx })

#define DSI_SZ_REGS		SZ_1K
/* DSI Protocol Engine */

#define DSI_REVISION			DSI_REG(0x0000)
#define DSI_SYSCONFIG			DSI_REG(0x0010)
#define DSI_SYSSTATUS			DSI_REG(0x0014)
#define DSI_IRQSTATUS			DSI_REG(0x0018)
#define DSI_IRQENABLE			DSI_REG(0x001C)
#define DSI_CTRL			DSI_REG(0x0040)
#define DSI_COMPLEXIO_CFG1		DSI_REG(0x0048)
#define DSI_COMPLEXIO_IRQ_STATUS	DSI_REG(0x004C)
#define DSI_COMPLEXIO_IRQ_ENABLE	DSI_REG(0x0050)
#define DSI_CLK_CTRL			DSI_REG(0x0054)
#define DSI_TIMING1			DSI_REG(0x0058)
#define DSI_TIMING2			DSI_REG(0x005C)
#define DSI_VM_TIMING1			DSI_REG(0x0060)
#define DSI_VM_TIMING2			DSI_REG(0x0064)
#define DSI_VM_TIMING3			DSI_REG(0x0068)
#define DSI_CLK_TIMING			DSI_REG(0x006C)
#define DSI_TX_FIFO_VC_SIZE		DSI_REG(0x0070)
#define DSI_RX_FIFO_VC_SIZE		DSI_REG(0x0074)
#define DSI_COMPLEXIO_CFG2		DSI_REG(0x0078)
#define DSI_RX_FIFO_VC_FULLNESS		DSI_REG(0x007C)
#define DSI_VM_TIMING4			DSI_REG(0x0080)
#define DSI_TX_FIFO_VC_EMPTINESS	DSI_REG(0x0084)
#define DSI_VM_TIMING5			DSI_REG(0x0088)
#define DSI_VM_TIMING6			DSI_REG(0x008C)
#define DSI_VM_TIMING7			DSI_REG(0x0090)
#define DSI_STOPCLK_TIMING		DSI_REG(0x0094)
#define DSI_VC_CTRL(n)			DSI_REG(0x0100 + (n * 0x20))
#define DSI_VC_TE(n)			DSI_REG(0x0104 + (n * 0x20))
#define DSI_VC_LONG_PACKET_HEADER(n)	DSI_REG(0x0108 + (n * 0x20))
#define DSI_VC_LONG_PACKET_PAYLOAD(n)	DSI_REG(0x010C + (n * 0x20))
#define DSI_VC_SHORT_PACKET_HEADER(n)	DSI_REG(0x0110 + (n * 0x20))
#define DSI_VC_IRQSTATUS(n)		DSI_REG(0x0118 + (n * 0x20))
#define DSI_VC_IRQENABLE(n)		DSI_REG(0x011C + (n * 0x20))

/* DSIPHY_SCP */

#define DSI_DSIPHY_CFG0			DSI_REG(0x200 + 0x0000)
#define DSI_DSIPHY_CFG1			DSI_REG(0x200 + 0x0004)
#define DSI_DSIPHY_CFG2			DSI_REG(0x200 + 0x0008)
#define DSI_DSIPHY_CFG5			DSI_REG(0x200 + 0x0014)
96
#define DSI_DSIPHY_CFG10		DSI_REG(0x200 + 0x0028)
T
Tomi Valkeinen 已提交
97 98 99 100 101 102 103 104 105

/* DSI_PLL_CTRL_SCP */

#define DSI_PLL_CONTROL			DSI_REG(0x300 + 0x0000)
#define DSI_PLL_STATUS			DSI_REG(0x300 + 0x0004)
#define DSI_PLL_GO			DSI_REG(0x300 + 0x0008)
#define DSI_PLL_CONFIGURATION1		DSI_REG(0x300 + 0x000C)
#define DSI_PLL_CONFIGURATION2		DSI_REG(0x300 + 0x0010)

106 107
#define REG_GET(dsidev, idx, start, end) \
	FLD_GET(dsi_read_reg(dsidev, idx), start, end)
T
Tomi Valkeinen 已提交
108

109 110
#define REG_FLD_MOD(dsidev, idx, val, start, end) \
	dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
T
Tomi Valkeinen 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

/* Global interrupts */
#define DSI_IRQ_VC0		(1 << 0)
#define DSI_IRQ_VC1		(1 << 1)
#define DSI_IRQ_VC2		(1 << 2)
#define DSI_IRQ_VC3		(1 << 3)
#define DSI_IRQ_WAKEUP		(1 << 4)
#define DSI_IRQ_RESYNC		(1 << 5)
#define DSI_IRQ_PLL_LOCK	(1 << 7)
#define DSI_IRQ_PLL_UNLOCK	(1 << 8)
#define DSI_IRQ_PLL_RECALL	(1 << 9)
#define DSI_IRQ_COMPLEXIO_ERR	(1 << 10)
#define DSI_IRQ_HS_TX_TIMEOUT	(1 << 14)
#define DSI_IRQ_LP_RX_TIMEOUT	(1 << 15)
#define DSI_IRQ_TE_TRIGGER	(1 << 16)
#define DSI_IRQ_ACK_TRIGGER	(1 << 17)
#define DSI_IRQ_SYNC_LOST	(1 << 18)
#define DSI_IRQ_LDO_POWER_GOOD	(1 << 19)
#define DSI_IRQ_TA_TIMEOUT	(1 << 20)
#define DSI_IRQ_ERROR_MASK \
	(DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
	DSI_IRQ_TA_TIMEOUT)
#define DSI_IRQ_CHANNEL_MASK	0xf

/* Virtual channel interrupts */
#define DSI_VC_IRQ_CS		(1 << 0)
#define DSI_VC_IRQ_ECC_CORR	(1 << 1)
#define DSI_VC_IRQ_PACKET_SENT	(1 << 2)
#define DSI_VC_IRQ_FIFO_TX_OVF	(1 << 3)
#define DSI_VC_IRQ_FIFO_RX_OVF	(1 << 4)
#define DSI_VC_IRQ_BTA		(1 << 5)
#define DSI_VC_IRQ_ECC_NO_CORR	(1 << 6)
#define DSI_VC_IRQ_FIFO_TX_UDF	(1 << 7)
#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
#define DSI_VC_IRQ_ERROR_MASK \
	(DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
	DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
	DSI_VC_IRQ_FIFO_TX_UDF)

/* ComplexIO interrupts */
#define DSI_CIO_IRQ_ERRSYNCESC1		(1 << 0)
#define DSI_CIO_IRQ_ERRSYNCESC2		(1 << 1)
#define DSI_CIO_IRQ_ERRSYNCESC3		(1 << 2)
154 155
#define DSI_CIO_IRQ_ERRSYNCESC4		(1 << 3)
#define DSI_CIO_IRQ_ERRSYNCESC5		(1 << 4)
T
Tomi Valkeinen 已提交
156 157 158
#define DSI_CIO_IRQ_ERRESC1		(1 << 5)
#define DSI_CIO_IRQ_ERRESC2		(1 << 6)
#define DSI_CIO_IRQ_ERRESC3		(1 << 7)
159 160
#define DSI_CIO_IRQ_ERRESC4		(1 << 8)
#define DSI_CIO_IRQ_ERRESC5		(1 << 9)
T
Tomi Valkeinen 已提交
161 162 163
#define DSI_CIO_IRQ_ERRCONTROL1		(1 << 10)
#define DSI_CIO_IRQ_ERRCONTROL2		(1 << 11)
#define DSI_CIO_IRQ_ERRCONTROL3		(1 << 12)
164 165
#define DSI_CIO_IRQ_ERRCONTROL4		(1 << 13)
#define DSI_CIO_IRQ_ERRCONTROL5		(1 << 14)
T
Tomi Valkeinen 已提交
166 167 168
#define DSI_CIO_IRQ_STATEULPS1		(1 << 15)
#define DSI_CIO_IRQ_STATEULPS2		(1 << 16)
#define DSI_CIO_IRQ_STATEULPS3		(1 << 17)
169 170
#define DSI_CIO_IRQ_STATEULPS4		(1 << 18)
#define DSI_CIO_IRQ_STATEULPS5		(1 << 19)
T
Tomi Valkeinen 已提交
171 172 173 174 175 176
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1	(1 << 20)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1	(1 << 21)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2	(1 << 22)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2	(1 << 23)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3	(1 << 24)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3	(1 << 25)
177 178 179 180
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4	(1 << 26)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4	(1 << 27)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5	(1 << 28)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5	(1 << 29)
T
Tomi Valkeinen 已提交
181 182
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0	(1 << 30)
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1	(1 << 31)
183 184
#define DSI_CIO_IRQ_ERROR_MASK \
	(DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
185 186 187 188 189 190 191 192
	 DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
	 DSI_CIO_IRQ_ERRSYNCESC5 | \
	 DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
	 DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
	 DSI_CIO_IRQ_ERRESC5 | \
	 DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
	 DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
	 DSI_CIO_IRQ_ERRCONTROL5 | \
193 194
	 DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
	 DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
195 196 197
	 DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
	 DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
	 DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
T
Tomi Valkeinen 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210

#define DSI_DT_DCS_SHORT_WRITE_0	0x05
#define DSI_DT_DCS_SHORT_WRITE_1	0x15
#define DSI_DT_DCS_READ			0x06
#define DSI_DT_SET_MAX_RET_PKG_SIZE	0x37
#define DSI_DT_NULL_PACKET		0x09
#define DSI_DT_DCS_LONG_WRITE		0x39

#define DSI_DT_RX_ACK_WITH_ERR		0x02
#define DSI_DT_RX_DCS_LONG_READ		0x1c
#define DSI_DT_RX_SHORT_READ_1		0x21
#define DSI_DT_RX_SHORT_READ_2		0x22

211 212 213 214 215 216 217 218 219 220
typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);

#define DSI_MAX_NR_ISRS                2

struct dsi_isr_data {
	omap_dsi_isr_t	isr;
	void		*arg;
	u32		mask;
};

T
Tomi Valkeinen 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233
enum fifo_size {
	DSI_FIFO_SIZE_0		= 0,
	DSI_FIFO_SIZE_32	= 1,
	DSI_FIFO_SIZE_64	= 2,
	DSI_FIFO_SIZE_96	= 3,
	DSI_FIFO_SIZE_128	= 4,
};

enum dsi_vc_mode {
	DSI_VC_MODE_L4 = 0,
	DSI_VC_MODE_VP,
};

234 235 236 237 238 239 240 241 242
enum dsi_lane {
	DSI_CLK_P	= 1 << 0,
	DSI_CLK_N	= 1 << 1,
	DSI_DATA1_P	= 1 << 2,
	DSI_DATA1_N	= 1 << 3,
	DSI_DATA2_P	= 1 << 4,
	DSI_DATA2_N	= 1 << 5,
};

T
Tomi Valkeinen 已提交
243 244 245 246 247
struct dsi_update_region {
	u16 x, y, w, h;
	struct omap_dss_device *device;
};

248 249 250 251 252 253 254 255
struct dsi_irq_stats {
	unsigned long last_reset;
	unsigned irq_count;
	unsigned dsi_irqs[32];
	unsigned vc_irqs[4][32];
	unsigned cio_irqs[32];
};

256 257 258 259 260 261
struct dsi_isr_tables {
	struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
	struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
	struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
};

262
struct dsi_data {
263
	struct platform_device *pdev;
T
Tomi Valkeinen 已提交
264
	void __iomem	*base;
265
	int irq;
T
Tomi Valkeinen 已提交
266

267 268
	void (*dsi_mux_pads)(bool enable);

T
Tomi Valkeinen 已提交
269 270
	struct dsi_clock_info current_cinfo;

271
	bool vdds_dsi_enabled;
T
Tomi Valkeinen 已提交
272 273 274 275 276 277
	struct regulator *vdds_dsi_reg;

	struct {
		enum dsi_vc_mode mode;
		struct omap_dss_device *dssdev;
		enum fifo_size fifo_size;
278
		int vc_id;
T
Tomi Valkeinen 已提交
279 280 281
	} vc[4];

	struct mutex lock;
282
	struct semaphore bus_lock;
T
Tomi Valkeinen 已提交
283 284 285

	unsigned pll_locked;

286 287 288 289 290
	spinlock_t irq_lock;
	struct dsi_isr_tables isr_tables;
	/* space for a copy used by the interrupt handler */
	struct dsi_isr_tables isr_tables_copy;

291
	int update_channel;
T
Tomi Valkeinen 已提交
292 293 294
	struct dsi_update_region update_region;

	bool te_enabled;
295
	bool ulps_enabled;
T
Tomi Valkeinen 已提交
296

297 298
	struct workqueue_struct *workqueue;

299 300 301 302 303
	void (*framedone_callback)(int, void *);
	void *framedone_data;

	struct delayed_work framedone_timeout_work;

T
Tomi Valkeinen 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
#ifdef DSI_CATCH_MISSING_TE
	struct timer_list te_timer;
#endif

	unsigned long cache_req_pck;
	unsigned long cache_clk_freq;
	struct dsi_clock_info cache_cinfo;

	u32		errors;
	spinlock_t	errors_lock;
#ifdef DEBUG
	ktime_t perf_setup_time;
	ktime_t perf_start_time;
#endif
	int debug_read;
	int debug_write;
320 321 322 323 324

#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
	spinlock_t irq_stats_lock;
	struct dsi_irq_stats irq_stats;
#endif
325 326 327 328 329
	/* DSI PLL Parameter Ranges */
	unsigned long regm_max, regn_max;
	unsigned long  regm_dispc_max, regm_dsi_max;
	unsigned long  fint_min, fint_max;
	unsigned long lpdiv_max;
330 331

	unsigned scp_clk_refcount;
332
};
T
Tomi Valkeinen 已提交
333

334 335 336 337 338
struct dsi_packet_sent_handler_data {
	struct platform_device *dsidev;
	struct completion *completion;
};

339 340
static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];

T
Tomi Valkeinen 已提交
341 342 343 344 345
#ifdef DEBUG
static unsigned int dsi_perf;
module_param_named(dsi_perf, dsi_perf, bool, 0644);
#endif

346 347 348 349 350
static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
{
	return dev_get_drvdata(&dsidev->dev);
}

351 352 353 354 355 356 357 358 359 360
static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
{
	return dsi_pdev_map[dssdev->phy.dsi.module];
}

struct platform_device *dsi_get_dsidev_from_id(int module)
{
	return dsi_pdev_map[module];
}

361 362 363 364 365 366 367 368 369 370
static int dsi_get_dsidev_id(struct platform_device *dsidev)
{
	/* TEMP: Pass 0 as the dsi module index till the time the dsi platform
	 * device names aren't changed to the form "omapdss_dsi.0",
	 * "omapdss_dsi.1" and so on */
	BUG_ON(dsidev->id != -1);

	return 0;
}

371 372
static inline void dsi_write_reg(struct platform_device *dsidev,
		const struct dsi_reg idx, u32 val)
T
Tomi Valkeinen 已提交
373
{
374 375 376
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	__raw_writel(val, dsi->base + idx.idx);
T
Tomi Valkeinen 已提交
377 378
}

379 380
static inline u32 dsi_read_reg(struct platform_device *dsidev,
		const struct dsi_reg idx)
T
Tomi Valkeinen 已提交
381
{
382 383 384
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	return __raw_readl(dsi->base + idx.idx);
T
Tomi Valkeinen 已提交
385 386 387 388 389 390 391 392 393 394 395
}


void dsi_save_context(void)
{
}

void dsi_restore_context(void)
{
}

396
void dsi_bus_lock(struct omap_dss_device *dssdev)
T
Tomi Valkeinen 已提交
397
{
398 399 400 401
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	down(&dsi->bus_lock);
T
Tomi Valkeinen 已提交
402 403 404
}
EXPORT_SYMBOL(dsi_bus_lock);

405
void dsi_bus_unlock(struct omap_dss_device *dssdev)
T
Tomi Valkeinen 已提交
406
{
407 408 409 410
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	up(&dsi->bus_lock);
T
Tomi Valkeinen 已提交
411 412 413
}
EXPORT_SYMBOL(dsi_bus_unlock);

414
static bool dsi_bus_is_locked(struct platform_device *dsidev)
415
{
416 417 418
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	return dsi->bus_lock.count == 0;
419 420
}

421 422 423 424 425
static void dsi_completion_handler(void *data, u32 mask)
{
	complete((struct completion *)data);
}

426 427
static inline int wait_for_bit_change(struct platform_device *dsidev,
		const struct dsi_reg idx, int bitnum, int value)
T
Tomi Valkeinen 已提交
428 429 430
{
	int t = 100000;

431
	while (REG_GET(dsidev, idx, bitnum, bitnum) != value) {
T
Tomi Valkeinen 已提交
432 433 434 435 436 437 438 439
		if (--t == 0)
			return !value;
	}

	return value;
}

#ifdef DEBUG
440
static void dsi_perf_mark_setup(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
441
{
442 443
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
	dsi->perf_setup_time = ktime_get();
T
Tomi Valkeinen 已提交
444 445
}

446
static void dsi_perf_mark_start(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
447
{
448 449
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
	dsi->perf_start_time = ktime_get();
T
Tomi Valkeinen 已提交
450 451
}

452
static void dsi_perf_show(struct platform_device *dsidev, const char *name)
T
Tomi Valkeinen 已提交
453
{
454
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
455 456 457 458 459 460 461 462 463
	ktime_t t, setup_time, trans_time;
	u32 total_bytes;
	u32 setup_us, trans_us, total_us;

	if (!dsi_perf)
		return;

	t = ktime_get();

464
	setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
T
Tomi Valkeinen 已提交
465 466 467 468
	setup_us = (u32)ktime_to_us(setup_time);
	if (setup_us == 0)
		setup_us = 1;

469
	trans_time = ktime_sub(t, dsi->perf_start_time);
T
Tomi Valkeinen 已提交
470 471 472 473 474 475
	trans_us = (u32)ktime_to_us(trans_time);
	if (trans_us == 0)
		trans_us = 1;

	total_us = setup_us + trans_us;

476 477 478
	total_bytes = dsi->update_region.w *
		dsi->update_region.h *
		dsi->update_region.device->ctrl.pixel_size / 8;
T
Tomi Valkeinen 已提交
479

480 481 482 483 484 485 486 487 488
	printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
			"%u bytes, %u kbytes/sec\n",
			name,
			setup_us,
			trans_us,
			total_us,
			1000*1000 / total_us,
			total_bytes,
			total_bytes * 1000 / total_us);
T
Tomi Valkeinen 已提交
489 490
}
#else
491 492 493
#define dsi_perf_mark_setup(x)
#define dsi_perf_mark_start(x)
#define dsi_perf_show(x, y)
T
Tomi Valkeinen 已提交
494 495 496 497
#endif

static void print_irq_status(u32 status)
{
498 499 500
	if (status == 0)
		return;

T
Tomi Valkeinen 已提交
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
#ifndef VERBOSE_IRQ
	if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
		return;
#endif
	printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);

#define PIS(x) \
	if (status & DSI_IRQ_##x) \
		printk(#x " ");
#ifdef VERBOSE_IRQ
	PIS(VC0);
	PIS(VC1);
	PIS(VC2);
	PIS(VC3);
#endif
	PIS(WAKEUP);
	PIS(RESYNC);
	PIS(PLL_LOCK);
	PIS(PLL_UNLOCK);
	PIS(PLL_RECALL);
	PIS(COMPLEXIO_ERR);
	PIS(HS_TX_TIMEOUT);
	PIS(LP_RX_TIMEOUT);
	PIS(TE_TRIGGER);
	PIS(ACK_TRIGGER);
	PIS(SYNC_LOST);
	PIS(LDO_POWER_GOOD);
	PIS(TA_TIMEOUT);
#undef PIS

	printk("\n");
}

static void print_irq_status_vc(int channel, u32 status)
{
536 537 538
	if (status == 0)
		return;

T
Tomi Valkeinen 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
#ifndef VERBOSE_IRQ
	if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
		return;
#endif
	printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);

#define PIS(x) \
	if (status & DSI_VC_IRQ_##x) \
		printk(#x " ");
	PIS(CS);
	PIS(ECC_CORR);
#ifdef VERBOSE_IRQ
	PIS(PACKET_SENT);
#endif
	PIS(FIFO_TX_OVF);
	PIS(FIFO_RX_OVF);
	PIS(BTA);
	PIS(ECC_NO_CORR);
	PIS(FIFO_TX_UDF);
	PIS(PP_BUSY_CHANGE);
#undef PIS
	printk("\n");
}

static void print_irq_status_cio(u32 status)
{
565 566 567
	if (status == 0)
		return;

T
Tomi Valkeinen 已提交
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
	printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);

#define PIS(x) \
	if (status & DSI_CIO_IRQ_##x) \
		printk(#x " ");
	PIS(ERRSYNCESC1);
	PIS(ERRSYNCESC2);
	PIS(ERRSYNCESC3);
	PIS(ERRESC1);
	PIS(ERRESC2);
	PIS(ERRESC3);
	PIS(ERRCONTROL1);
	PIS(ERRCONTROL2);
	PIS(ERRCONTROL3);
	PIS(STATEULPS1);
	PIS(STATEULPS2);
	PIS(STATEULPS3);
	PIS(ERRCONTENTIONLP0_1);
	PIS(ERRCONTENTIONLP1_1);
	PIS(ERRCONTENTIONLP0_2);
	PIS(ERRCONTENTIONLP1_2);
	PIS(ERRCONTENTIONLP0_3);
	PIS(ERRCONTENTIONLP1_3);
	PIS(ULPSACTIVENOT_ALL0);
	PIS(ULPSACTIVENOT_ALL1);
#undef PIS

	printk("\n");
}

598
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
599 600
static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
		u32 *vcstatus, u32 ciostatus)
T
Tomi Valkeinen 已提交
601
{
602
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
603 604
	int i;

605
	spin_lock(&dsi->irq_stats_lock);
606

607 608
	dsi->irq_stats.irq_count++;
	dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
609 610

	for (i = 0; i < 4; ++i)
611
		dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
612

613
	dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
614

615
	spin_unlock(&dsi->irq_stats_lock);
616 617
}
#else
618
#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
619 620
#endif

621 622
static int debug_irq;

623 624
static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
		u32 *vcstatus, u32 ciostatus)
625
{
626
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
627 628
	int i;

T
Tomi Valkeinen 已提交
629 630 631
	if (irqstatus & DSI_IRQ_ERROR_MASK) {
		DSSERR("DSI error, irqstatus %x\n", irqstatus);
		print_irq_status(irqstatus);
632 633 634
		spin_lock(&dsi->errors_lock);
		dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
		spin_unlock(&dsi->errors_lock);
T
Tomi Valkeinen 已提交
635 636 637 638 639
	} else if (debug_irq) {
		print_irq_status(irqstatus);
	}

	for (i = 0; i < 4; ++i) {
640 641 642 643 644 645 646 647
		if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
			DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
				       i, vcstatus[i]);
			print_irq_status_vc(i, vcstatus[i]);
		} else if (debug_irq) {
			print_irq_status_vc(i, vcstatus[i]);
		}
	}
T
Tomi Valkeinen 已提交
648

649 650 651 652 653 654 655
	if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
		DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
		print_irq_status_cio(ciostatus);
	} else if (debug_irq) {
		print_irq_status_cio(ciostatus);
	}
}
T
Tomi Valkeinen 已提交
656

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
static void dsi_call_isrs(struct dsi_isr_data *isr_array,
		unsigned isr_array_size, u32 irqstatus)
{
	struct dsi_isr_data *isr_data;
	int i;

	for (i = 0; i < isr_array_size; i++) {
		isr_data = &isr_array[i];
		if (isr_data->isr && isr_data->mask & irqstatus)
			isr_data->isr(isr_data->arg, irqstatus);
	}
}

static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
		u32 irqstatus, u32 *vcstatus, u32 ciostatus)
{
	int i;

	dsi_call_isrs(isr_tables->isr_table,
			ARRAY_SIZE(isr_tables->isr_table),
			irqstatus);

	for (i = 0; i < 4; ++i) {
		if (vcstatus[i] == 0)
			continue;
		dsi_call_isrs(isr_tables->isr_table_vc[i],
				ARRAY_SIZE(isr_tables->isr_table_vc[i]),
				vcstatus[i]);
	}

	if (ciostatus != 0)
		dsi_call_isrs(isr_tables->isr_table_cio,
				ARRAY_SIZE(isr_tables->isr_table_cio),
				ciostatus);
}

693 694
static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
{
695
	struct platform_device *dsidev;
696
	struct dsi_data *dsi;
697 698
	u32 irqstatus, vcstatus[4], ciostatus;
	int i;
699

700
	dsidev = (struct platform_device *) arg;
701
	dsi = dsi_get_dsidrv_data(dsidev);
702

703
	spin_lock(&dsi->irq_lock);
704

705
	irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
T
Tomi Valkeinen 已提交
706

707
	/* IRQ is not for us */
708
	if (!irqstatus) {
709
		spin_unlock(&dsi->irq_lock);
710
		return IRQ_NONE;
711
	}
712

713
	dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
714
	/* flush posted write */
715
	dsi_read_reg(dsidev, DSI_IRQSTATUS);
716 717 718 719 720

	for (i = 0; i < 4; ++i) {
		if ((irqstatus & (1 << i)) == 0) {
			vcstatus[i] = 0;
			continue;
T
Tomi Valkeinen 已提交
721 722
		}

723
		vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
724

725
		dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
T
Tomi Valkeinen 已提交
726
		/* flush posted write */
727
		dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
T
Tomi Valkeinen 已提交
728 729 730
	}

	if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
731
		ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
T
Tomi Valkeinen 已提交
732

733
		dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
T
Tomi Valkeinen 已提交
734
		/* flush posted write */
735
		dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
736 737 738
	} else {
		ciostatus = 0;
	}
T
Tomi Valkeinen 已提交
739

740 741
#ifdef DSI_CATCH_MISSING_TE
	if (irqstatus & DSI_IRQ_TE_TRIGGER)
742
		del_timer(&dsi->te_timer);
743 744
#endif

745 746
	/* make a copy and unlock, so that isrs can unregister
	 * themselves */
747 748
	memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
		sizeof(dsi->isr_tables));
749

750
	spin_unlock(&dsi->irq_lock);
751

752
	dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
753

754
	dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
755

756
	dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
757

758
	return IRQ_HANDLED;
T
Tomi Valkeinen 已提交
759 760
}

761
/* dsi->irq_lock has to be locked by the caller */
762 763
static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
		struct dsi_isr_data *isr_array,
764 765 766
		unsigned isr_array_size, u32 default_mask,
		const struct dsi_reg enable_reg,
		const struct dsi_reg status_reg)
T
Tomi Valkeinen 已提交
767
{
768 769 770
	struct dsi_isr_data *isr_data;
	u32 mask;
	u32 old_mask;
T
Tomi Valkeinen 已提交
771 772
	int i;

773
	mask = default_mask;
T
Tomi Valkeinen 已提交
774

775 776
	for (i = 0; i < isr_array_size; i++) {
		isr_data = &isr_array[i];
T
Tomi Valkeinen 已提交
777

778 779 780 781
		if (isr_data->isr == NULL)
			continue;

		mask |= isr_data->mask;
T
Tomi Valkeinen 已提交
782 783
	}

784
	old_mask = dsi_read_reg(dsidev, enable_reg);
785
	/* clear the irqstatus for newly enabled irqs */
786 787
	dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
	dsi_write_reg(dsidev, enable_reg, mask);
788 789

	/* flush posted writes */
790 791
	dsi_read_reg(dsidev, enable_reg);
	dsi_read_reg(dsidev, status_reg);
792
}
T
Tomi Valkeinen 已提交
793

794
/* dsi->irq_lock has to be locked by the caller */
795
static void _omap_dsi_set_irqs(struct platform_device *dsidev)
796
{
797
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
798
	u32 mask = DSI_IRQ_ERROR_MASK;
T
Tomi Valkeinen 已提交
799
#ifdef DSI_CATCH_MISSING_TE
800
	mask |= DSI_IRQ_TE_TRIGGER;
T
Tomi Valkeinen 已提交
801
#endif
802 803
	_omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
			ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
804 805
			DSI_IRQENABLE, DSI_IRQSTATUS);
}
T
Tomi Valkeinen 已提交
806

807
/* dsi->irq_lock has to be locked by the caller */
808
static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
809
{
810 811 812 813
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	_omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
			ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
814 815 816 817
			DSI_VC_IRQ_ERROR_MASK,
			DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
}

818
/* dsi->irq_lock has to be locked by the caller */
819
static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
820
{
821 822 823 824
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	_omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
			ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
825 826 827 828
			DSI_CIO_IRQ_ERROR_MASK,
			DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
}

829
static void _dsi_initialize_irq(struct platform_device *dsidev)
830
{
831
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
832 833 834
	unsigned long flags;
	int vc;

835
	spin_lock_irqsave(&dsi->irq_lock, flags);
836

837
	memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
838

839
	_omap_dsi_set_irqs(dsidev);
840
	for (vc = 0; vc < 4; ++vc)
841 842
		_omap_dsi_set_irqs_vc(dsidev, vc);
	_omap_dsi_set_irqs_cio(dsidev);
843

844
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
845
}
T
Tomi Valkeinen 已提交
846

847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
		struct dsi_isr_data *isr_array, unsigned isr_array_size)
{
	struct dsi_isr_data *isr_data;
	int free_idx;
	int i;

	BUG_ON(isr == NULL);

	/* check for duplicate entry and find a free slot */
	free_idx = -1;
	for (i = 0; i < isr_array_size; i++) {
		isr_data = &isr_array[i];

		if (isr_data->isr == isr && isr_data->arg == arg &&
				isr_data->mask == mask) {
			return -EINVAL;
		}

		if (isr_data->isr == NULL && free_idx == -1)
			free_idx = i;
	}

	if (free_idx == -1)
		return -EBUSY;

	isr_data = &isr_array[free_idx];
	isr_data->isr = isr;
	isr_data->arg = arg;
	isr_data->mask = mask;

	return 0;
}

static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
		struct dsi_isr_data *isr_array, unsigned isr_array_size)
{
	struct dsi_isr_data *isr_data;
	int i;

	for (i = 0; i < isr_array_size; i++) {
		isr_data = &isr_array[i];
		if (isr_data->isr != isr || isr_data->arg != arg ||
				isr_data->mask != mask)
			continue;

		isr_data->isr = NULL;
		isr_data->arg = NULL;
		isr_data->mask = 0;

		return 0;
	}

	return -EINVAL;
}

903 904
static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
		void *arg, u32 mask)
905
{
906
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
907 908 909
	unsigned long flags;
	int r;

910
	spin_lock_irqsave(&dsi->irq_lock, flags);
911

912 913
	r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
			ARRAY_SIZE(dsi->isr_tables.isr_table));
914 915

	if (r == 0)
916
		_omap_dsi_set_irqs(dsidev);
917

918
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
919 920 921 922

	return r;
}

923 924
static int dsi_unregister_isr(struct platform_device *dsidev,
		omap_dsi_isr_t isr, void *arg, u32 mask)
925
{
926
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
927 928 929
	unsigned long flags;
	int r;

930
	spin_lock_irqsave(&dsi->irq_lock, flags);
931

932 933
	r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
			ARRAY_SIZE(dsi->isr_tables.isr_table));
934 935

	if (r == 0)
936
		_omap_dsi_set_irqs(dsidev);
937

938
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
939 940 941 942

	return r;
}

943 944
static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
		omap_dsi_isr_t isr, void *arg, u32 mask)
945
{
946
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
947 948 949
	unsigned long flags;
	int r;

950
	spin_lock_irqsave(&dsi->irq_lock, flags);
951 952

	r = _dsi_register_isr(isr, arg, mask,
953 954
			dsi->isr_tables.isr_table_vc[channel],
			ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
955 956

	if (r == 0)
957
		_omap_dsi_set_irqs_vc(dsidev, channel);
958

959
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
960 961 962 963

	return r;
}

964 965
static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
		omap_dsi_isr_t isr, void *arg, u32 mask)
966
{
967
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
968 969 970
	unsigned long flags;
	int r;

971
	spin_lock_irqsave(&dsi->irq_lock, flags);
972 973

	r = _dsi_unregister_isr(isr, arg, mask,
974 975
			dsi->isr_tables.isr_table_vc[channel],
			ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
976 977

	if (r == 0)
978
		_omap_dsi_set_irqs_vc(dsidev, channel);
979

980
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
981 982 983 984

	return r;
}

985 986
static int dsi_register_isr_cio(struct platform_device *dsidev,
		omap_dsi_isr_t isr, void *arg, u32 mask)
987
{
988
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
989 990 991
	unsigned long flags;
	int r;

992
	spin_lock_irqsave(&dsi->irq_lock, flags);
993

994 995
	r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
			ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
996 997

	if (r == 0)
998
		_omap_dsi_set_irqs_cio(dsidev);
999

1000
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
1001 1002 1003 1004

	return r;
}

1005 1006
static int dsi_unregister_isr_cio(struct platform_device *dsidev,
		omap_dsi_isr_t isr, void *arg, u32 mask)
1007
{
1008
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1009 1010 1011
	unsigned long flags;
	int r;

1012
	spin_lock_irqsave(&dsi->irq_lock, flags);
1013

1014 1015
	r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
			ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
1016 1017

	if (r == 0)
1018
		_omap_dsi_set_irqs_cio(dsidev);
1019

1020
	spin_unlock_irqrestore(&dsi->irq_lock, flags);
1021 1022

	return r;
T
Tomi Valkeinen 已提交
1023 1024
}

1025
static u32 dsi_get_errors(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1026
{
1027
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
1028 1029
	unsigned long flags;
	u32 e;
1030 1031 1032 1033
	spin_lock_irqsave(&dsi->errors_lock, flags);
	e = dsi->errors;
	dsi->errors = 0;
	spin_unlock_irqrestore(&dsi->errors_lock, flags);
T
Tomi Valkeinen 已提交
1034 1035 1036
	return e;
}

1037
/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
T
Tomi Valkeinen 已提交
1038 1039 1040
static inline void enable_clocks(bool enable)
{
	if (enable)
1041
		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
T
Tomi Valkeinen 已提交
1042
	else
1043
		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
T
Tomi Valkeinen 已提交
1044 1045 1046
}

/* source clock for DSI PLL. this could also be PCLKFREE */
1047 1048
static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
		bool enable)
T
Tomi Valkeinen 已提交
1049
{
1050 1051
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

T
Tomi Valkeinen 已提交
1052
	if (enable)
1053
		dss_clk_enable(DSS_CLK_SYSCK);
T
Tomi Valkeinen 已提交
1054
	else
1055
		dss_clk_disable(DSS_CLK_SYSCK);
T
Tomi Valkeinen 已提交
1056

1057
	if (enable && dsi->pll_locked) {
1058
		if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
T
Tomi Valkeinen 已提交
1059 1060 1061 1062 1063
			DSSERR("cannot lock PLL when enabling clocks\n");
	}
}

#ifdef DEBUG
1064
static void _dsi_print_reset_status(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1065 1066
{
	u32 l;
1067
	int b0, b1, b2;
T
Tomi Valkeinen 已提交
1068 1069 1070 1071 1072 1073 1074

	if (!dss_debug)
		return;

	/* A dummy read using the SCP interface to any DSIPHY register is
	 * required after DSIPHY reset to complete the reset of the DSI complex
	 * I/O. */
1075
	l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
T
Tomi Valkeinen 已提交
1076 1077 1078

	printk(KERN_DEBUG "DSI resets: ");

1079
	l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
T
Tomi Valkeinen 已提交
1080 1081
	printk("PLL (%d) ", FLD_GET(l, 0, 0));

1082
	l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
T
Tomi Valkeinen 已提交
1083 1084
	printk("CIO (%d) ", FLD_GET(l, 29, 29));

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
	if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
		b0 = 28;
		b1 = 27;
		b2 = 26;
	} else {
		b0 = 24;
		b1 = 25;
		b2 = 26;
	}

1095
	l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
1096 1097 1098 1099
	printk("PHY (%x%x%x, %d, %d, %d)\n",
			FLD_GET(l, b0, b0),
			FLD_GET(l, b1, b1),
			FLD_GET(l, b2, b2),
T
Tomi Valkeinen 已提交
1100 1101 1102 1103 1104
			FLD_GET(l, 29, 29),
			FLD_GET(l, 30, 30),
			FLD_GET(l, 31, 31));
}
#else
1105
#define _dsi_print_reset_status(x)
T
Tomi Valkeinen 已提交
1106 1107
#endif

1108
static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
T
Tomi Valkeinen 已提交
1109 1110 1111 1112
{
	DSSDBG("dsi_if_enable(%d)\n", enable);

	enable = enable ? 1 : 0;
1113
	REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
T
Tomi Valkeinen 已提交
1114

1115
	if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
T
Tomi Valkeinen 已提交
1116 1117 1118 1119 1120 1121 1122
			DSSERR("Failed to set dsi_if_enable to %d\n", enable);
			return -EIO;
	}

	return 0;
}

1123
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1124
{
1125 1126 1127
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
T
Tomi Valkeinen 已提交
1128 1129
}

1130
static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1131
{
1132 1133 1134
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
T
Tomi Valkeinen 已提交
1135 1136
}

1137
static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1138
{
1139 1140 1141
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	return dsi->current_cinfo.clkin4ddr / 16;
T
Tomi Valkeinen 已提交
1142 1143
}

1144
static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
1145 1146
{
	unsigned long r;
1147
	int dsi_module = dsi_get_dsidev_id(dsidev);
T
Tomi Valkeinen 已提交
1148

1149
	if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
1150
		/* DSI FCLK source is DSS_CLK_FCK */
1151
		r = dss_clk_get_rate(DSS_CLK_FCK);
T
Tomi Valkeinen 已提交
1152
	} else {
1153
		/* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
1154
		r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
T
Tomi Valkeinen 已提交
1155 1156 1157 1158 1159 1160 1161
	}

	return r;
}

static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
{
1162
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
1163
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
1164 1165 1166 1167
	unsigned long dsi_fclk;
	unsigned lp_clk_div;
	unsigned long lp_clk;

1168
	lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
T
Tomi Valkeinen 已提交
1169

1170
	if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
T
Tomi Valkeinen 已提交
1171 1172
		return -EINVAL;

1173
	dsi_fclk = dsi_fclk_rate(dsidev);
T
Tomi Valkeinen 已提交
1174 1175 1176 1177

	lp_clk = dsi_fclk / 2 / lp_clk_div;

	DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
1178 1179
	dsi->current_cinfo.lp_clk = lp_clk;
	dsi->current_cinfo.lp_clk_div = lp_clk_div;
T
Tomi Valkeinen 已提交
1180

1181 1182
	/* LP_CLK_DIVISOR */
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
T
Tomi Valkeinen 已提交
1183

1184 1185
	/* LP_RX_SYNCHRO_ENABLE */
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
T
Tomi Valkeinen 已提交
1186 1187 1188 1189

	return 0;
}

1190
static void dsi_enable_scp_clk(struct platform_device *dsidev)
1191
{
1192 1193 1194
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (dsi->scp_clk_refcount++ == 0)
1195
		REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
1196 1197
}

1198
static void dsi_disable_scp_clk(struct platform_device *dsidev)
1199
{
1200 1201 1202 1203
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	WARN_ON(dsi->scp_clk_refcount == 0);
	if (--dsi->scp_clk_refcount == 0)
1204
		REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
1205
}
T
Tomi Valkeinen 已提交
1206 1207 1208 1209 1210 1211 1212 1213

enum dsi_pll_power_state {
	DSI_PLL_POWER_OFF	= 0x0,
	DSI_PLL_POWER_ON_HSCLK	= 0x1,
	DSI_PLL_POWER_ON_ALL	= 0x2,
	DSI_PLL_POWER_ON_DIV	= 0x3,
};

1214 1215
static int dsi_pll_power(struct platform_device *dsidev,
		enum dsi_pll_power_state state)
T
Tomi Valkeinen 已提交
1216 1217 1218
{
	int t = 0;

1219 1220 1221 1222 1223
	/* DSI-PLL power command 0x3 is not working */
	if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
			state == DSI_PLL_POWER_ON_DIV)
		state = DSI_PLL_POWER_ON_ALL;

1224 1225
	/* PLL_PWR_CMD */
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
T
Tomi Valkeinen 已提交
1226 1227

	/* PLL_PWR_STATUS */
1228
	while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
1229
		if (++t > 1000) {
T
Tomi Valkeinen 已提交
1230 1231 1232 1233
			DSSERR("Failed to set DSI PLL power mode to %d\n",
					state);
			return -ENODEV;
		}
1234
		udelay(1);
T
Tomi Valkeinen 已提交
1235 1236 1237 1238 1239 1240
	}

	return 0;
}

/* calculate clock rates using dividers in cinfo */
1241 1242
static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
		struct dsi_clock_info *cinfo)
T
Tomi Valkeinen 已提交
1243
{
1244 1245 1246 1247
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
T
Tomi Valkeinen 已提交
1248 1249
		return -EINVAL;

1250
	if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
T
Tomi Valkeinen 已提交
1251 1252
		return -EINVAL;

1253
	if (cinfo->regm_dispc > dsi->regm_dispc_max)
T
Tomi Valkeinen 已提交
1254 1255
		return -EINVAL;

1256
	if (cinfo->regm_dsi > dsi->regm_dsi_max)
T
Tomi Valkeinen 已提交
1257 1258
		return -EINVAL;

1259
	if (cinfo->use_sys_clk) {
1260
		cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
T
Tomi Valkeinen 已提交
1261
		/* XXX it is unclear if highfreq should be used
1262
		 * with DSS_SYS_CLK source also */
T
Tomi Valkeinen 已提交
1263 1264
		cinfo->highfreq = 0;
	} else {
1265
		cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
T
Tomi Valkeinen 已提交
1266 1267 1268 1269 1270 1271 1272 1273 1274

		if (cinfo->clkin < 32000000)
			cinfo->highfreq = 0;
		else
			cinfo->highfreq = 1;
	}

	cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));

1275
	if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
T
Tomi Valkeinen 已提交
1276 1277 1278 1279 1280 1281 1282
		return -EINVAL;

	cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;

	if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
		return -EINVAL;

1283 1284 1285
	if (cinfo->regm_dispc > 0)
		cinfo->dsi_pll_hsdiv_dispc_clk =
			cinfo->clkin4ddr / cinfo->regm_dispc;
T
Tomi Valkeinen 已提交
1286
	else
1287
		cinfo->dsi_pll_hsdiv_dispc_clk = 0;
T
Tomi Valkeinen 已提交
1288

1289 1290 1291
	if (cinfo->regm_dsi > 0)
		cinfo->dsi_pll_hsdiv_dsi_clk =
			cinfo->clkin4ddr / cinfo->regm_dsi;
T
Tomi Valkeinen 已提交
1292
	else
1293
		cinfo->dsi_pll_hsdiv_dsi_clk = 0;
T
Tomi Valkeinen 已提交
1294 1295 1296 1297

	return 0;
}

1298 1299
int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
		unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
T
Tomi Valkeinen 已提交
1300 1301
		struct dispc_clock_info *dispc_cinfo)
{
1302
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
1303 1304 1305 1306
	struct dsi_clock_info cur, best;
	struct dispc_clock_info best_dispc;
	int min_fck_per_pck;
	int match = 0;
1307
	unsigned long dss_sys_clk, max_dss_fck;
T
Tomi Valkeinen 已提交
1308

1309
	dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
T
Tomi Valkeinen 已提交
1310

1311
	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
1312

1313 1314
	if (req_pck == dsi->cache_req_pck &&
			dsi->cache_cinfo.clkin == dss_sys_clk) {
T
Tomi Valkeinen 已提交
1315
		DSSDBG("DSI clock info found from cache\n");
1316
		*dsi_cinfo = dsi->cache_cinfo;
1317 1318
		dispc_find_clk_divs(is_tft, req_pck,
			dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
T
Tomi Valkeinen 已提交
1319 1320 1321 1322 1323 1324
		return 0;
	}

	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;

	if (min_fck_per_pck &&
1325
		req_pck * min_fck_per_pck > max_dss_fck) {
T
Tomi Valkeinen 已提交
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
		DSSERR("Requested pixel clock not possible with the current "
				"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
				"the constraint off.\n");
		min_fck_per_pck = 0;
	}

	DSSDBG("dsi_pll_calc\n");

retry:
	memset(&best, 0, sizeof(best));
	memset(&best_dispc, 0, sizeof(best_dispc));

	memset(&cur, 0, sizeof(cur));
1339 1340
	cur.clkin = dss_sys_clk;
	cur.use_sys_clk = 1;
T
Tomi Valkeinen 已提交
1341 1342 1343 1344 1345
	cur.highfreq = 0;

	/* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
	/* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
	/* To reduce PLL lock time, keep Fint high (around 2 MHz) */
1346
	for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
T
Tomi Valkeinen 已提交
1347 1348 1349 1350 1351
		if (cur.highfreq == 0)
			cur.fint = cur.clkin / cur.regn;
		else
			cur.fint = cur.clkin / (2 * cur.regn);

1352
		if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
T
Tomi Valkeinen 已提交
1353 1354 1355
			continue;

		/* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
1356
		for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
T
Tomi Valkeinen 已提交
1357 1358 1359 1360 1361 1362 1363 1364 1365
			unsigned long a, b;

			a = 2 * cur.regm * (cur.clkin/1000);
			b = cur.regn * (cur.highfreq + 1);
			cur.clkin4ddr = a / b * 1000;

			if (cur.clkin4ddr > 1800 * 1000 * 1000)
				break;

1366 1367
			/* dsi_pll_hsdiv_dispc_clk(MHz) =
			 * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
1368 1369
			for (cur.regm_dispc = 1; cur.regm_dispc <
					dsi->regm_dispc_max; ++cur.regm_dispc) {
T
Tomi Valkeinen 已提交
1370
				struct dispc_clock_info cur_dispc;
1371 1372
				cur.dsi_pll_hsdiv_dispc_clk =
					cur.clkin4ddr / cur.regm_dispc;
T
Tomi Valkeinen 已提交
1373 1374 1375 1376

				/* this will narrow down the search a bit,
				 * but still give pixclocks below what was
				 * requested */
1377
				if (cur.dsi_pll_hsdiv_dispc_clk  < req_pck)
T
Tomi Valkeinen 已提交
1378 1379
					break;

1380
				if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
T
Tomi Valkeinen 已提交
1381 1382 1383
					continue;

				if (min_fck_per_pck &&
1384
					cur.dsi_pll_hsdiv_dispc_clk <
T
Tomi Valkeinen 已提交
1385 1386 1387 1388 1389 1390
						req_pck * min_fck_per_pck)
					continue;

				match = 1;

				dispc_find_clk_divs(is_tft, req_pck,
1391
						cur.dsi_pll_hsdiv_dispc_clk,
T
Tomi Valkeinen 已提交
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
						&cur_dispc);

				if (abs(cur_dispc.pck - req_pck) <
						abs(best_dispc.pck - req_pck)) {
					best = cur;
					best_dispc = cur_dispc;

					if (cur_dispc.pck == req_pck)
						goto found;
				}
			}
		}
	}
found:
	if (!match) {
		if (min_fck_per_pck) {
			DSSERR("Could not find suitable clock settings.\n"
					"Turning FCK/PCK constraint off and"
					"trying again.\n");
			min_fck_per_pck = 0;
			goto retry;
		}

		DSSERR("Could not find suitable clock settings.\n");

		return -EINVAL;
	}

1420 1421 1422
	/* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
	best.regm_dsi = 0;
	best.dsi_pll_hsdiv_dsi_clk = 0;
T
Tomi Valkeinen 已提交
1423 1424 1425 1426 1427 1428

	if (dsi_cinfo)
		*dsi_cinfo = best;
	if (dispc_cinfo)
		*dispc_cinfo = best_dispc;

1429 1430 1431
	dsi->cache_req_pck = req_pck;
	dsi->cache_clk_freq = 0;
	dsi->cache_cinfo = best;
T
Tomi Valkeinen 已提交
1432 1433 1434 1435

	return 0;
}

1436 1437
int dsi_pll_set_clock_div(struct platform_device *dsidev,
		struct dsi_clock_info *cinfo)
T
Tomi Valkeinen 已提交
1438
{
1439
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
1440 1441
	int r = 0;
	u32 l;
1442
	int f = 0;
1443 1444
	u8 regn_start, regn_end, regm_start, regm_end;
	u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
T
Tomi Valkeinen 已提交
1445 1446 1447

	DSSDBGF();

1448 1449
	dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk;
	dsi->current_cinfo.highfreq = cinfo->highfreq;
1450

1451 1452 1453
	dsi->current_cinfo.fint = cinfo->fint;
	dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
	dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
1454
			cinfo->dsi_pll_hsdiv_dispc_clk;
1455
	dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
1456
			cinfo->dsi_pll_hsdiv_dsi_clk;
T
Tomi Valkeinen 已提交
1457

1458 1459 1460 1461
	dsi->current_cinfo.regn = cinfo->regn;
	dsi->current_cinfo.regm = cinfo->regm;
	dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
	dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
T
Tomi Valkeinen 已提交
1462 1463 1464 1465

	DSSDBG("DSI Fint %ld\n", cinfo->fint);

	DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
1466
			cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
T
Tomi Valkeinen 已提交
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
			cinfo->clkin,
			cinfo->highfreq);

	/* DSIPHY == CLKIN4DDR */
	DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
			cinfo->regm,
			cinfo->regn,
			cinfo->clkin,
			cinfo->highfreq + 1,
			cinfo->clkin4ddr);

	DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
			cinfo->clkin4ddr / 1000 / 1000 / 2);

	DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);

1483
	DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
1484 1485
		dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
		dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
1486 1487
		cinfo->dsi_pll_hsdiv_dispc_clk);
	DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
1488 1489
		dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
		dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
1490
		cinfo->dsi_pll_hsdiv_dsi_clk);
T
Tomi Valkeinen 已提交
1491

1492 1493 1494 1495 1496 1497 1498
	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
			&regm_dispc_end);
	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
			&regm_dsi_end);

1499 1500
	/* DSI_PLL_AUTOMODE = manual */
	REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
T
Tomi Valkeinen 已提交
1501

1502
	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
T
Tomi Valkeinen 已提交
1503
	l = FLD_MOD(l, 1, 0, 0);		/* DSI_PLL_STOPMODE */
1504 1505 1506 1507 1508
	/* DSI_PLL_REGN */
	l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
	/* DSI_PLL_REGM */
	l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
	/* DSI_CLOCK_DIV */
1509
	l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
1510 1511
			regm_dispc_start, regm_dispc_end);
	/* DSIPROTO_CLOCK_DIV */
1512
	l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
1513
			regm_dsi_start, regm_dsi_end);
1514
	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
T
Tomi Valkeinen 已提交
1515

1516
	BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
1517 1518 1519 1520 1521 1522 1523 1524

	if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
		f = cinfo->fint < 1000000 ? 0x3 :
			cinfo->fint < 1250000 ? 0x4 :
			cinfo->fint < 1500000 ? 0x5 :
			cinfo->fint < 1750000 ? 0x6 :
			0x7;
	}
T
Tomi Valkeinen 已提交
1525

1526
	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
1527 1528 1529

	if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
		l = FLD_MOD(l, f, 4, 1);	/* DSI_PLL_FREQSEL */
1530
	l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
T
Tomi Valkeinen 已提交
1531 1532 1533 1534 1535 1536
			11, 11);		/* DSI_PLL_CLKSEL */
	l = FLD_MOD(l, cinfo->highfreq,
			12, 12);		/* DSI_PLL_HIGHFREQ */
	l = FLD_MOD(l, 1, 13, 13);		/* DSI_PLL_REFEN */
	l = FLD_MOD(l, 0, 14, 14);		/* DSIPHY_CLKINEN */
	l = FLD_MOD(l, 1, 20, 20);		/* DSI_HSDIVBYPASS */
1537
	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
T
Tomi Valkeinen 已提交
1538

1539
	REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);	/* DSI_PLL_GO */
T
Tomi Valkeinen 已提交
1540

1541
	if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
T
Tomi Valkeinen 已提交
1542 1543 1544 1545 1546
		DSSERR("dsi pll go bit not going down.\n");
		r = -EIO;
		goto err;
	}

1547
	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
T
Tomi Valkeinen 已提交
1548 1549 1550 1551 1552
		DSSERR("cannot lock PLL\n");
		r = -EIO;
		goto err;
	}

1553
	dsi->pll_locked = 1;
T
Tomi Valkeinen 已提交
1554

1555
	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
T
Tomi Valkeinen 已提交
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
	l = FLD_MOD(l, 0, 0, 0);	/* DSI_PLL_IDLE */
	l = FLD_MOD(l, 0, 5, 5);	/* DSI_PLL_PLLLPMODE */
	l = FLD_MOD(l, 0, 6, 6);	/* DSI_PLL_LOWCURRSTBY */
	l = FLD_MOD(l, 0, 7, 7);	/* DSI_PLL_TIGHTPHASELOCK */
	l = FLD_MOD(l, 0, 8, 8);	/* DSI_PLL_DRIFTGUARDEN */
	l = FLD_MOD(l, 0, 10, 9);	/* DSI_PLL_LOCKSEL */
	l = FLD_MOD(l, 1, 13, 13);	/* DSI_PLL_REFEN */
	l = FLD_MOD(l, 1, 14, 14);	/* DSIPHY_CLKINEN */
	l = FLD_MOD(l, 0, 15, 15);	/* DSI_BYPASSEN */
	l = FLD_MOD(l, 1, 16, 16);	/* DSS_CLOCK_EN */
	l = FLD_MOD(l, 0, 17, 17);	/* DSS_CLOCK_PWDN */
	l = FLD_MOD(l, 1, 18, 18);	/* DSI_PROTO_CLOCK_EN */
	l = FLD_MOD(l, 0, 19, 19);	/* DSI_PROTO_CLOCK_PWDN */
	l = FLD_MOD(l, 0, 20, 20);	/* DSI_HSDIVBYPASS */
1570
	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
T
Tomi Valkeinen 已提交
1571 1572 1573 1574 1575 1576

	DSSDBG("PLL config done\n");
err:
	return r;
}

1577 1578
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
		bool enable_hsdiv)
T
Tomi Valkeinen 已提交
1579
{
1580
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
1581 1582 1583 1584 1585
	int r = 0;
	enum dsi_pll_power_state pwstate;

	DSSDBG("PLL init\n");

1586
	if (dsi->vdds_dsi_reg == NULL) {
1587 1588
		struct regulator *vdds_dsi;

1589
		vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
1590 1591 1592 1593 1594 1595

		if (IS_ERR(vdds_dsi)) {
			DSSERR("can't get VDDS_DSI regulator\n");
			return PTR_ERR(vdds_dsi);
		}

1596
		dsi->vdds_dsi_reg = vdds_dsi;
1597 1598
	}

T
Tomi Valkeinen 已提交
1599
	enable_clocks(1);
1600
	dsi_enable_pll_clock(dsidev, 1);
1601 1602 1603
	/*
	 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
	 */
1604
	dsi_enable_scp_clk(dsidev);
T
Tomi Valkeinen 已提交
1605

1606 1607
	if (!dsi->vdds_dsi_enabled) {
		r = regulator_enable(dsi->vdds_dsi_reg);
1608 1609
		if (r)
			goto err0;
1610
		dsi->vdds_dsi_enabled = true;
1611
	}
T
Tomi Valkeinen 已提交
1612 1613 1614 1615

	/* XXX PLL does not come out of reset without this... */
	dispc_pck_free_enable(1);

1616
	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
T
Tomi Valkeinen 已提交
1617 1618
		DSSERR("PLL not coming out of reset.\n");
		r = -ENODEV;
1619
		dispc_pck_free_enable(0);
T
Tomi Valkeinen 已提交
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
		goto err1;
	}

	/* XXX ... but if left on, we get problems when planes do not
	 * fill the whole display. No idea about this */
	dispc_pck_free_enable(0);

	if (enable_hsclk && enable_hsdiv)
		pwstate = DSI_PLL_POWER_ON_ALL;
	else if (enable_hsclk)
		pwstate = DSI_PLL_POWER_ON_HSCLK;
	else if (enable_hsdiv)
		pwstate = DSI_PLL_POWER_ON_DIV;
	else
		pwstate = DSI_PLL_POWER_OFF;

1636
	r = dsi_pll_power(dsidev, pwstate);
T
Tomi Valkeinen 已提交
1637 1638 1639 1640 1641 1642 1643 1644

	if (r)
		goto err1;

	DSSDBG("PLL init done\n");

	return 0;
err1:
1645 1646 1647
	if (dsi->vdds_dsi_enabled) {
		regulator_disable(dsi->vdds_dsi_reg);
		dsi->vdds_dsi_enabled = false;
1648
	}
T
Tomi Valkeinen 已提交
1649
err0:
1650
	dsi_disable_scp_clk(dsidev);
T
Tomi Valkeinen 已提交
1651
	enable_clocks(0);
1652
	dsi_enable_pll_clock(dsidev, 0);
T
Tomi Valkeinen 已提交
1653 1654 1655
	return r;
}

1656
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
T
Tomi Valkeinen 已提交
1657
{
1658 1659 1660
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	dsi->pll_locked = 0;
1661
	dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
1662
	if (disconnect_lanes) {
1663 1664 1665
		WARN_ON(!dsi->vdds_dsi_enabled);
		regulator_disable(dsi->vdds_dsi_reg);
		dsi->vdds_dsi_enabled = false;
1666
	}
1667

1668
	dsi_disable_scp_clk(dsidev);
1669
	enable_clocks(0);
1670
	dsi_enable_pll_clock(dsidev, 0);
1671

T
Tomi Valkeinen 已提交
1672 1673 1674
	DSSDBG("PLL uninit done\n");
}

1675 1676
static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
		struct seq_file *s)
T
Tomi Valkeinen 已提交
1677
{
1678 1679
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
	struct dsi_clock_info *cinfo = &dsi->current_cinfo;
1680
	enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
1681
	int dsi_module = dsi_get_dsidev_id(dsidev);
1682 1683

	dispc_clk_src = dss_get_dispc_clk_source();
1684
	dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
T
Tomi Valkeinen 已提交
1685 1686 1687

	enable_clocks(1);

1688
	seq_printf(s,	"- DSI%d PLL -\n", dsi_module + 1);
T
Tomi Valkeinen 已提交
1689 1690

	seq_printf(s,	"dsi pll source = %s\n",
1691
			cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
T
Tomi Valkeinen 已提交
1692 1693 1694 1695 1696 1697

	seq_printf(s,	"Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);

	seq_printf(s,	"CLKIN4DDR\t%-16luregm %u\n",
			cinfo->clkin4ddr, cinfo->regm);

1698
	seq_printf(s,	"%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
1699 1700
			dss_get_generic_clk_source_name(dispc_clk_src),
			dss_feat_get_clk_source_name(dispc_clk_src),
1701 1702
			cinfo->dsi_pll_hsdiv_dispc_clk,
			cinfo->regm_dispc,
1703
			dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1704
			"off" : "on");
T
Tomi Valkeinen 已提交
1705

1706
	seq_printf(s,	"%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
1707 1708
			dss_get_generic_clk_source_name(dsi_clk_src),
			dss_feat_get_clk_source_name(dsi_clk_src),
1709 1710
			cinfo->dsi_pll_hsdiv_dsi_clk,
			cinfo->regm_dsi,
1711
			dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1712
			"off" : "on");
T
Tomi Valkeinen 已提交
1713

1714
	seq_printf(s,	"- DSI%d -\n", dsi_module + 1);
T
Tomi Valkeinen 已提交
1715

1716 1717 1718
	seq_printf(s,	"dsi fclk source = %s (%s)\n",
			dss_get_generic_clk_source_name(dsi_clk_src),
			dss_feat_get_clk_source_name(dsi_clk_src));
T
Tomi Valkeinen 已提交
1719

1720
	seq_printf(s,	"DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
T
Tomi Valkeinen 已提交
1721 1722 1723 1724

	seq_printf(s,	"DDR_CLK\t\t%lu\n",
			cinfo->clkin4ddr / 4);

1725
	seq_printf(s,	"TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
T
Tomi Valkeinen 已提交
1726 1727 1728 1729 1730 1731

	seq_printf(s,	"LP_CLK\t\t%lu\n", cinfo->lp_clk);

	enable_clocks(0);
}

1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743
void dsi_dump_clocks(struct seq_file *s)
{
	struct platform_device *dsidev;
	int i;

	for  (i = 0; i < MAX_NUM_DSI; i++) {
		dsidev = dsi_get_dsidev_from_id(i);
		if (dsidev)
			dsi_dump_dsidev_clocks(dsidev, s);
	}
}

1744
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1745 1746
static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
		struct seq_file *s)
1747
{
1748
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1749 1750
	unsigned long flags;
	struct dsi_irq_stats stats;
1751
	int dsi_module = dsi_get_dsidev_id(dsidev);
1752

1753
	spin_lock_irqsave(&dsi->irq_stats_lock, flags);
1754

1755 1756 1757
	stats = dsi->irq_stats;
	memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
	dsi->irq_stats.last_reset = jiffies;
1758

1759
	spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
1760 1761 1762 1763 1764 1765 1766 1767

	seq_printf(s, "period %u ms\n",
			jiffies_to_msecs(jiffies - stats.last_reset));

	seq_printf(s, "irqs %d\n", stats.irq_count);
#define PIS(x) \
	seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);

1768
	seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1);
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
	PIS(VC0);
	PIS(VC1);
	PIS(VC2);
	PIS(VC3);
	PIS(WAKEUP);
	PIS(RESYNC);
	PIS(PLL_LOCK);
	PIS(PLL_UNLOCK);
	PIS(PLL_RECALL);
	PIS(COMPLEXIO_ERR);
	PIS(HS_TX_TIMEOUT);
	PIS(LP_RX_TIMEOUT);
	PIS(TE_TRIGGER);
	PIS(ACK_TRIGGER);
	PIS(SYNC_LOST);
	PIS(LDO_POWER_GOOD);
	PIS(TA_TIMEOUT);
#undef PIS

#define PIS(x) \
	seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
			stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
			stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
			stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
			stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);

	seq_printf(s, "-- VC interrupts --\n");
	PIS(CS);
	PIS(ECC_CORR);
	PIS(PACKET_SENT);
	PIS(FIFO_TX_OVF);
	PIS(FIFO_RX_OVF);
	PIS(BTA);
	PIS(ECC_NO_CORR);
	PIS(FIFO_TX_UDF);
	PIS(PP_BUSY_CHANGE);
#undef PIS

#define PIS(x) \
	seq_printf(s, "%-20s %10d\n", #x, \
			stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);

	seq_printf(s, "-- CIO interrupts --\n");
	PIS(ERRSYNCESC1);
	PIS(ERRSYNCESC2);
	PIS(ERRSYNCESC3);
	PIS(ERRESC1);
	PIS(ERRESC2);
	PIS(ERRESC3);
	PIS(ERRCONTROL1);
	PIS(ERRCONTROL2);
	PIS(ERRCONTROL3);
	PIS(STATEULPS1);
	PIS(STATEULPS2);
	PIS(STATEULPS3);
	PIS(ERRCONTENTIONLP0_1);
	PIS(ERRCONTENTIONLP1_1);
	PIS(ERRCONTENTIONLP0_2);
	PIS(ERRCONTENTIONLP1_2);
	PIS(ERRCONTENTIONLP0_3);
	PIS(ERRCONTENTIONLP1_3);
	PIS(ULPSACTIVENOT_ALL0);
	PIS(ULPSACTIVENOT_ALL1);
#undef PIS
}

1835
static void dsi1_dump_irqs(struct seq_file *s)
T
Tomi Valkeinen 已提交
1836
{
1837 1838
	struct platform_device *dsidev = dsi_get_dsidev_from_id(0);

1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868
	dsi_dump_dsidev_irqs(dsidev, s);
}

static void dsi2_dump_irqs(struct seq_file *s)
{
	struct platform_device *dsidev = dsi_get_dsidev_from_id(1);

	dsi_dump_dsidev_irqs(dsidev, s);
}

void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
		const struct file_operations *debug_fops)
{
	struct platform_device *dsidev;

	dsidev = dsi_get_dsidev_from_id(0);
	if (dsidev)
		debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir,
			&dsi1_dump_irqs, debug_fops);

	dsidev = dsi_get_dsidev_from_id(1);
	if (dsidev)
		debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir,
			&dsi2_dump_irqs, debug_fops);
}
#endif

static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
		struct seq_file *s)
{
1869
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
T
Tomi Valkeinen 已提交
1870

1871
	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
1872
	dsi_enable_scp_clk(dsidev);
T
Tomi Valkeinen 已提交
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943

	DUMPREG(DSI_REVISION);
	DUMPREG(DSI_SYSCONFIG);
	DUMPREG(DSI_SYSSTATUS);
	DUMPREG(DSI_IRQSTATUS);
	DUMPREG(DSI_IRQENABLE);
	DUMPREG(DSI_CTRL);
	DUMPREG(DSI_COMPLEXIO_CFG1);
	DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
	DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
	DUMPREG(DSI_CLK_CTRL);
	DUMPREG(DSI_TIMING1);
	DUMPREG(DSI_TIMING2);
	DUMPREG(DSI_VM_TIMING1);
	DUMPREG(DSI_VM_TIMING2);
	DUMPREG(DSI_VM_TIMING3);
	DUMPREG(DSI_CLK_TIMING);
	DUMPREG(DSI_TX_FIFO_VC_SIZE);
	DUMPREG(DSI_RX_FIFO_VC_SIZE);
	DUMPREG(DSI_COMPLEXIO_CFG2);
	DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
	DUMPREG(DSI_VM_TIMING4);
	DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
	DUMPREG(DSI_VM_TIMING5);
	DUMPREG(DSI_VM_TIMING6);
	DUMPREG(DSI_VM_TIMING7);
	DUMPREG(DSI_STOPCLK_TIMING);

	DUMPREG(DSI_VC_CTRL(0));
	DUMPREG(DSI_VC_TE(0));
	DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
	DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
	DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
	DUMPREG(DSI_VC_IRQSTATUS(0));
	DUMPREG(DSI_VC_IRQENABLE(0));

	DUMPREG(DSI_VC_CTRL(1));
	DUMPREG(DSI_VC_TE(1));
	DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
	DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
	DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
	DUMPREG(DSI_VC_IRQSTATUS(1));
	DUMPREG(DSI_VC_IRQENABLE(1));

	DUMPREG(DSI_VC_CTRL(2));
	DUMPREG(DSI_VC_TE(2));
	DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
	DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
	DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
	DUMPREG(DSI_VC_IRQSTATUS(2));
	DUMPREG(DSI_VC_IRQENABLE(2));

	DUMPREG(DSI_VC_CTRL(3));
	DUMPREG(DSI_VC_TE(3));
	DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
	DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
	DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
	DUMPREG(DSI_VC_IRQSTATUS(3));
	DUMPREG(DSI_VC_IRQENABLE(3));

	DUMPREG(DSI_DSIPHY_CFG0);
	DUMPREG(DSI_DSIPHY_CFG1);
	DUMPREG(DSI_DSIPHY_CFG2);
	DUMPREG(DSI_DSIPHY_CFG5);

	DUMPREG(DSI_PLL_CONTROL);
	DUMPREG(DSI_PLL_STATUS);
	DUMPREG(DSI_PLL_GO);
	DUMPREG(DSI_PLL_CONFIGURATION1);
	DUMPREG(DSI_PLL_CONFIGURATION2);

1944
	dsi_disable_scp_clk(dsidev);
1945
	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
T
Tomi Valkeinen 已提交
1946 1947 1948
#undef DUMPREG
}

1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977
static void dsi1_dump_regs(struct seq_file *s)
{
	struct platform_device *dsidev = dsi_get_dsidev_from_id(0);

	dsi_dump_dsidev_regs(dsidev, s);
}

static void dsi2_dump_regs(struct seq_file *s)
{
	struct platform_device *dsidev = dsi_get_dsidev_from_id(1);

	dsi_dump_dsidev_regs(dsidev, s);
}

void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
		const struct file_operations *debug_fops)
{
	struct platform_device *dsidev;

	dsidev = dsi_get_dsidev_from_id(0);
	if (dsidev)
		debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir,
			&dsi1_dump_regs, debug_fops);

	dsidev = dsi_get_dsidev_from_id(1);
	if (dsidev)
		debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir,
			&dsi2_dump_regs, debug_fops);
}
1978
enum dsi_cio_power_state {
T
Tomi Valkeinen 已提交
1979 1980 1981 1982 1983
	DSI_COMPLEXIO_POWER_OFF		= 0x0,
	DSI_COMPLEXIO_POWER_ON		= 0x1,
	DSI_COMPLEXIO_POWER_ULPS	= 0x2,
};

1984 1985
static int dsi_cio_power(struct platform_device *dsidev,
		enum dsi_cio_power_state state)
T
Tomi Valkeinen 已提交
1986 1987 1988 1989
{
	int t = 0;

	/* PWR_CMD */
1990
	REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
T
Tomi Valkeinen 已提交
1991 1992

	/* PWR_STATUS */
1993 1994
	while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
			26, 25) != state) {
1995
		if (++t > 1000) {
T
Tomi Valkeinen 已提交
1996 1997 1998 1999
			DSSERR("failed to set complexio power state to "
					"%d\n", state);
			return -ENODEV;
		}
2000
		udelay(1);
T
Tomi Valkeinen 已提交
2001 2002 2003 2004 2005
	}

	return 0;
}

2006
static void dsi_set_lane_config(struct omap_dss_device *dssdev)
T
Tomi Valkeinen 已提交
2007
{
2008
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
2009 2010 2011 2012 2013 2014 2015 2016 2017
	u32 r;

	int clk_lane   = dssdev->phy.dsi.clk_lane;
	int data1_lane = dssdev->phy.dsi.data1_lane;
	int data2_lane = dssdev->phy.dsi.data2_lane;
	int clk_pol    = dssdev->phy.dsi.clk_pol;
	int data1_pol  = dssdev->phy.dsi.data1_pol;
	int data2_pol  = dssdev->phy.dsi.data2_pol;

2018
	r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
T
Tomi Valkeinen 已提交
2019 2020 2021 2022 2023 2024
	r = FLD_MOD(r, clk_lane, 2, 0);
	r = FLD_MOD(r, clk_pol, 3, 3);
	r = FLD_MOD(r, data1_lane, 6, 4);
	r = FLD_MOD(r, data1_pol, 7, 7);
	r = FLD_MOD(r, data2_lane, 10, 8);
	r = FLD_MOD(r, data2_pol, 11, 11);
2025
	dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
T
Tomi Valkeinen 已提交
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038

	/* The configuration of the DSI complex I/O (number of data lanes,
	   position, differential order) should not be changed while
	   DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
	   the hardware to take into account a new configuration of the complex
	   I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
	   follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
	   then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
	   DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
	   DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
	   DSI complex I/O configuration is unknown. */

	/*
2039 2040 2041 2042
	REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
	REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
	REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
T
Tomi Valkeinen 已提交
2043 2044 2045
	*/
}

2046
static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
T
Tomi Valkeinen 已提交
2047
{
2048 2049
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

T
Tomi Valkeinen 已提交
2050
	/* convert time in ns to ddr ticks, rounding up */
2051
	unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
T
Tomi Valkeinen 已提交
2052 2053 2054
	return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
}

2055
static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
T
Tomi Valkeinen 已提交
2056
{
2057 2058 2059
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
T
Tomi Valkeinen 已提交
2060 2061 2062
	return ddr * 1000 * 1000 / (ddr_clk / 1000);
}

2063
static void dsi_cio_timings(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
{
	u32 r;
	u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
	u32 tlpx_half, tclk_trail, tclk_zero;
	u32 tclk_prepare;

	/* calculate timings */

	/* 1 * DDR_CLK = 2 * UI */

	/* min 40ns + 4*UI	max 85ns + 6*UI */
2075
	ths_prepare = ns2ddr(dsidev, 70) + 2;
T
Tomi Valkeinen 已提交
2076 2077

	/* min 145ns + 10*UI */
2078
	ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
T
Tomi Valkeinen 已提交
2079 2080

	/* min max(8*UI, 60ns+4*UI) */
2081
	ths_trail = ns2ddr(dsidev, 60) + 5;
T
Tomi Valkeinen 已提交
2082 2083

	/* min 100ns */
2084
	ths_exit = ns2ddr(dsidev, 145);
T
Tomi Valkeinen 已提交
2085 2086

	/* tlpx min 50n */
2087
	tlpx_half = ns2ddr(dsidev, 25);
T
Tomi Valkeinen 已提交
2088 2089

	/* min 60ns */
2090
	tclk_trail = ns2ddr(dsidev, 60) + 2;
T
Tomi Valkeinen 已提交
2091 2092

	/* min 38ns, max 95ns */
2093
	tclk_prepare = ns2ddr(dsidev, 65);
T
Tomi Valkeinen 已提交
2094 2095

	/* min tclk-prepare + tclk-zero = 300ns */
2096
	tclk_zero = ns2ddr(dsidev, 260);
T
Tomi Valkeinen 已提交
2097 2098

	DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
2099 2100
		ths_prepare, ddr2ns(dsidev, ths_prepare),
		ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
T
Tomi Valkeinen 已提交
2101
	DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
2102 2103
			ths_trail, ddr2ns(dsidev, ths_trail),
			ths_exit, ddr2ns(dsidev, ths_exit));
T
Tomi Valkeinen 已提交
2104 2105 2106

	DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
			"tclk_zero %u (%uns)\n",
2107 2108 2109
			tlpx_half, ddr2ns(dsidev, tlpx_half),
			tclk_trail, ddr2ns(dsidev, tclk_trail),
			tclk_zero, ddr2ns(dsidev, tclk_zero));
T
Tomi Valkeinen 已提交
2110
	DSSDBG("tclk_prepare %u (%uns)\n",
2111
			tclk_prepare, ddr2ns(dsidev, tclk_prepare));
T
Tomi Valkeinen 已提交
2112 2113 2114

	/* program timings */

2115
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
T
Tomi Valkeinen 已提交
2116 2117 2118 2119
	r = FLD_MOD(r, ths_prepare, 31, 24);
	r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
	r = FLD_MOD(r, ths_trail, 15, 8);
	r = FLD_MOD(r, ths_exit, 7, 0);
2120
	dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
T
Tomi Valkeinen 已提交
2121

2122
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
T
Tomi Valkeinen 已提交
2123 2124 2125
	r = FLD_MOD(r, tlpx_half, 22, 16);
	r = FLD_MOD(r, tclk_trail, 15, 8);
	r = FLD_MOD(r, tclk_zero, 7, 0);
2126
	dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
T
Tomi Valkeinen 已提交
2127

2128
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
T
Tomi Valkeinen 已提交
2129
	r = FLD_MOD(r, tclk_prepare, 7, 0);
2130
	dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
T
Tomi Valkeinen 已提交
2131 2132
}

2133
static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
2134 2135
		enum dsi_lane lanes)
{
2136
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
	int clk_lane   = dssdev->phy.dsi.clk_lane;
	int data1_lane = dssdev->phy.dsi.data1_lane;
	int data2_lane = dssdev->phy.dsi.data2_lane;
	int clk_pol    = dssdev->phy.dsi.clk_pol;
	int data1_pol  = dssdev->phy.dsi.data1_pol;
	int data2_pol  = dssdev->phy.dsi.data2_pol;

	u32 l = 0;

	if (lanes & DSI_CLK_P)
		l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
	if (lanes & DSI_CLK_N)
		l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));

	if (lanes & DSI_DATA1_P)
		l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
	if (lanes & DSI_DATA1_N)
		l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));

	if (lanes & DSI_DATA2_P)
		l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
	if (lanes & DSI_DATA2_N)
		l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));

	/*
	 * Bits in REGLPTXSCPDAT4TO0DXDY:
	 * 17: DY0 18: DX0
	 * 19: DY1 20: DX1
	 * 21: DY2 22: DX2
	 */

	/* Set the lane override configuration */
2169 2170 2171

	/* REGLPTXSCPDAT4TO0DXDY */
	REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, 22, 17);
2172 2173

	/* Enable lane override */
2174 2175 2176

	/* ENLPTXSCPDAT */
	REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
2177 2178
}

2179
static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
2180 2181
{
	/* Disable lane override */
2182
	REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
2183
	/* Reset the lane override configuration */
2184 2185
	/* REGLPTXSCPDAT4TO0DXDY */
	REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
2186
}
T
Tomi Valkeinen 已提交
2187

2188 2189
static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
{
2190
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
	int t;
	int bits[3];
	bool in_use[3];

	if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
		bits[0] = 28;
		bits[1] = 27;
		bits[2] = 26;
	} else {
		bits[0] = 24;
		bits[1] = 25;
		bits[2] = 26;
	}

	in_use[0] = false;
	in_use[1] = false;
	in_use[2] = false;

	if (dssdev->phy.dsi.clk_lane != 0)
		in_use[dssdev->phy.dsi.clk_lane - 1] = true;
	if (dssdev->phy.dsi.data1_lane != 0)
		in_use[dssdev->phy.dsi.data1_lane - 1] = true;
	if (dssdev->phy.dsi.data2_lane != 0)
		in_use[dssdev->phy.dsi.data2_lane - 1] = true;

	t = 100000;
	while (true) {
		u32 l;
		int i;
		int ok;

2222
		l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247

		ok = 0;
		for (i = 0; i < 3; ++i) {
			if (!in_use[i] || (l & (1 << bits[i])))
				ok++;
		}

		if (ok == 3)
			break;

		if (--t == 0) {
			for (i = 0; i < 3; ++i) {
				if (!in_use[i] || (l & (1 << bits[i])))
					continue;

				DSSERR("CIO TXCLKESC%d domain not coming " \
						"out of reset\n", i);
			}
			return -EIO;
		}
	}

	return 0;
}

2248
static int dsi_cio_init(struct omap_dss_device *dssdev)
T
Tomi Valkeinen 已提交
2249
{
2250
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2251
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2252
	int r;
2253
	u32 l;
T
Tomi Valkeinen 已提交
2254

2255
	DSSDBGF();
T
Tomi Valkeinen 已提交
2256

2257 2258
	if (dsi->dsi_mux_pads)
		dsi->dsi_mux_pads(true);
2259

2260
	dsi_enable_scp_clk(dsidev);
2261

T
Tomi Valkeinen 已提交
2262 2263 2264
	/* A dummy read using the SCP interface to any DSIPHY register is
	 * required after DSIPHY reset to complete the reset of the DSI complex
	 * I/O. */
2265
	dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
T
Tomi Valkeinen 已提交
2266

2267
	if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
2268 2269 2270
		DSSERR("CIO SCP Clock domain not coming out of reset.\n");
		r = -EIO;
		goto err_scp_clk_dom;
T
Tomi Valkeinen 已提交
2271 2272
	}

2273
	dsi_set_lane_config(dssdev);
T
Tomi Valkeinen 已提交
2274

2275
	/* set TX STOP MODE timer to maximum for this operation */
2276
	l = dsi_read_reg(dsidev, DSI_TIMING1);
2277 2278 2279 2280
	l = FLD_MOD(l, 1, 15, 15);	/* FORCE_TX_STOP_MODE_IO */
	l = FLD_MOD(l, 1, 14, 14);	/* STOP_STATE_X16_IO */
	l = FLD_MOD(l, 1, 13, 13);	/* STOP_STATE_X4_IO */
	l = FLD_MOD(l, 0x1fff, 12, 0);	/* STOP_STATE_COUNTER_IO */
2281
	dsi_write_reg(dsidev, DSI_TIMING1, l);
2282

2283
	if (dsi->ulps_enabled) {
2284 2285
		DSSDBG("manual ulps exit\n");

2286 2287 2288 2289 2290 2291 2292 2293
		/* ULPS is exited by Mark-1 state for 1ms, followed by
		 * stop state. DSS HW cannot do this via the normal
		 * ULPS exit sequence, as after reset the DSS HW thinks
		 * that we are not in ULPS mode, and refuses to send the
		 * sequence. So we need to send the ULPS exit sequence
		 * manually.
		 */

2294
		dsi_cio_enable_lane_override(dssdev,
2295 2296
				DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P);
	}
T
Tomi Valkeinen 已提交
2297

2298
	r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
T
Tomi Valkeinen 已提交
2299
	if (r)
2300 2301
		goto err_cio_pwr;

2302
	if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
2303 2304 2305 2306 2307
		DSSERR("CIO PWR clock domain not coming out of reset.\n");
		r = -ENODEV;
		goto err_cio_pwr_dom;
	}

2308 2309 2310
	dsi_if_enable(dsidev, true);
	dsi_if_enable(dsidev, false);
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
T
Tomi Valkeinen 已提交
2311

2312 2313 2314 2315
	r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
	if (r)
		goto err_tx_clk_esc_rst;

2316
	if (dsi->ulps_enabled) {
2317 2318 2319 2320 2321 2322 2323
		/* Keep Mark-1 state for 1ms (as per DSI spec) */
		ktime_t wait = ns_to_ktime(1000 * 1000);
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_hrtimeout(&wait, HRTIMER_MODE_REL);

		/* Disable the override. The lanes should be set to Mark-11
		 * state by the HW */
2324
		dsi_cio_disable_lane_override(dsidev);
2325 2326 2327
	}

	/* FORCE_TX_STOP_MODE_IO */
2328
	REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
2329

2330
	dsi_cio_timings(dsidev);
T
Tomi Valkeinen 已提交
2331

2332
	dsi->ulps_enabled = false;
T
Tomi Valkeinen 已提交
2333 2334

	DSSDBG("CIO init done\n");
2335 2336 2337

	return 0;

2338
err_tx_clk_esc_rst:
2339
	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
2340
err_cio_pwr_dom:
2341
	dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2342
err_cio_pwr:
2343
	if (dsi->ulps_enabled)
2344
		dsi_cio_disable_lane_override(dsidev);
2345
err_scp_clk_dom:
2346
	dsi_disable_scp_clk(dsidev);
2347 2348
	if (dsi->dsi_mux_pads)
		dsi->dsi_mux_pads(false);
T
Tomi Valkeinen 已提交
2349 2350 2351
	return r;
}

2352
static void dsi_cio_uninit(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
2353
{
2354 2355
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

2356 2357
	dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
	dsi_disable_scp_clk(dsidev);
2358 2359
	if (dsi->dsi_mux_pads)
		dsi->dsi_mux_pads(false);
T
Tomi Valkeinen 已提交
2360 2361
}

2362
static int _dsi_wait_reset(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
2363
{
2364
	int t = 0;
T
Tomi Valkeinen 已提交
2365

2366
	while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
2367
		if (++t > 5) {
T
Tomi Valkeinen 已提交
2368 2369 2370 2371 2372 2373 2374 2375 2376
			DSSERR("soft reset failed\n");
			return -ENODEV;
		}
		udelay(1);
	}

	return 0;
}

2377
static int _dsi_reset(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
2378 2379
{
	/* Soft reset */
2380 2381
	REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
	return _dsi_wait_reset(dsidev);
T
Tomi Valkeinen 已提交
2382 2383
}

2384 2385
static void dsi_config_tx_fifo(struct platform_device *dsidev,
		enum fifo_size size1, enum fifo_size size2,
T
Tomi Valkeinen 已提交
2386 2387
		enum fifo_size size3, enum fifo_size size4)
{
2388
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
2389 2390 2391 2392
	u32 r = 0;
	int add = 0;
	int i;

2393 2394 2395 2396
	dsi->vc[0].fifo_size = size1;
	dsi->vc[1].fifo_size = size2;
	dsi->vc[2].fifo_size = size3;
	dsi->vc[3].fifo_size = size4;
T
Tomi Valkeinen 已提交
2397 2398 2399

	for (i = 0; i < 4; i++) {
		u8 v;
2400
		int size = dsi->vc[i].fifo_size;
T
Tomi Valkeinen 已提交
2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412

		if (add + size > 4) {
			DSSERR("Illegal FIFO configuration\n");
			BUG();
		}

		v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
		r |= v << (8 * i);
		/*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
		add += size;
	}

2413
	dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
T
Tomi Valkeinen 已提交
2414 2415
}

2416 2417
static void dsi_config_rx_fifo(struct platform_device *dsidev,
		enum fifo_size size1, enum fifo_size size2,
T
Tomi Valkeinen 已提交
2418 2419
		enum fifo_size size3, enum fifo_size size4)
{
2420
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
2421 2422 2423 2424
	u32 r = 0;
	int add = 0;
	int i;

2425 2426 2427 2428
	dsi->vc[0].fifo_size = size1;
	dsi->vc[1].fifo_size = size2;
	dsi->vc[2].fifo_size = size3;
	dsi->vc[3].fifo_size = size4;
T
Tomi Valkeinen 已提交
2429 2430 2431

	for (i = 0; i < 4; i++) {
		u8 v;
2432
		int size = dsi->vc[i].fifo_size;
T
Tomi Valkeinen 已提交
2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444

		if (add + size > 4) {
			DSSERR("Illegal FIFO configuration\n");
			BUG();
		}

		v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
		r |= v << (8 * i);
		/*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
		add += size;
	}

2445
	dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
T
Tomi Valkeinen 已提交
2446 2447
}

2448
static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
2449 2450 2451
{
	u32 r;

2452
	r = dsi_read_reg(dsidev, DSI_TIMING1);
T
Tomi Valkeinen 已提交
2453
	r = FLD_MOD(r, 1, 15, 15);	/* FORCE_TX_STOP_MODE_IO */
2454
	dsi_write_reg(dsidev, DSI_TIMING1, r);
T
Tomi Valkeinen 已提交
2455

2456
	if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
T
Tomi Valkeinen 已提交
2457 2458 2459 2460 2461 2462 2463
		DSSERR("TX_STOP bit not going down\n");
		return -EIO;
	}

	return 0;
}

2464
static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
2465
{
2466
	return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
2467 2468 2469 2470
}

static void dsi_packet_sent_handler_vp(void *data, u32 mask)
{
2471 2472 2473
	struct dsi_packet_sent_handler_data *vp_data =
		(struct dsi_packet_sent_handler_data *) data;
	struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
2474 2475
	const int channel = dsi->update_channel;
	u8 bit = dsi->te_enabled ? 30 : 31;
2476

2477 2478
	if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
		complete(vp_data->completion);
2479 2480
}

2481
static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
2482
{
2483
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2484 2485
	DECLARE_COMPLETION_ONSTACK(completion);
	struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
2486 2487 2488
	int r = 0;
	u8 bit;

2489
	bit = dsi->te_enabled ? 30 : 31;
2490

2491
	r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2492
		&vp_data, DSI_VC_IRQ_PACKET_SENT);
2493 2494 2495 2496
	if (r)
		goto err0;

	/* Wait for completion only if TE_EN/TE_START is still set */
2497
	if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
2498 2499 2500 2501 2502 2503 2504 2505
		if (wait_for_completion_timeout(&completion,
				msecs_to_jiffies(10)) == 0) {
			DSSERR("Failed to complete previous frame transfer\n");
			r = -EIO;
			goto err1;
		}
	}

2506
	dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2507
		&vp_data, DSI_VC_IRQ_PACKET_SENT);
2508 2509 2510

	return 0;
err1:
2511
	dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2512
		&vp_data, DSI_VC_IRQ_PACKET_SENT);
2513 2514 2515 2516 2517 2518
err0:
	return r;
}

static void dsi_packet_sent_handler_l4(void *data, u32 mask)
{
2519 2520 2521
	struct dsi_packet_sent_handler_data *l4_data =
		(struct dsi_packet_sent_handler_data *) data;
	struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
2522
	const int channel = dsi->update_channel;
2523

2524 2525
	if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
		complete(l4_data->completion);
2526 2527
}

2528
static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
2529 2530
{
	DECLARE_COMPLETION_ONSTACK(completion);
2531 2532
	struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
	int r = 0;
2533

2534
	r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2535
		&l4_data, DSI_VC_IRQ_PACKET_SENT);
2536 2537 2538 2539
	if (r)
		goto err0;

	/* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
2540
	if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
2541 2542 2543 2544 2545 2546 2547 2548
		if (wait_for_completion_timeout(&completion,
				msecs_to_jiffies(10)) == 0) {
			DSSERR("Failed to complete previous l4 transfer\n");
			r = -EIO;
			goto err1;
		}
	}

2549
	dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2550
		&l4_data, DSI_VC_IRQ_PACKET_SENT);
2551 2552 2553

	return 0;
err1:
2554
	dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2555
		&l4_data, DSI_VC_IRQ_PACKET_SENT);
2556 2557 2558 2559
err0:
	return r;
}

2560
static int dsi_sync_vc(struct platform_device *dsidev, int channel)
2561
{
2562 2563
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

2564
	WARN_ON(!dsi_bus_is_locked(dsidev));
2565 2566 2567

	WARN_ON(in_interrupt());

2568
	if (!dsi_vc_is_enabled(dsidev, channel))
2569 2570
		return 0;

2571
	switch (dsi->vc[channel].mode) {
2572
	case DSI_VC_MODE_VP:
2573
		return dsi_sync_vc_vp(dsidev, channel);
2574
	case DSI_VC_MODE_L4:
2575
		return dsi_sync_vc_l4(dsidev, channel);
2576 2577 2578 2579 2580
	default:
		BUG();
	}
}

2581 2582
static int dsi_vc_enable(struct platform_device *dsidev, int channel,
		bool enable)
T
Tomi Valkeinen 已提交
2583
{
2584 2585
	DSSDBG("dsi_vc_enable channel %d, enable %d\n",
			channel, enable);
T
Tomi Valkeinen 已提交
2586 2587 2588

	enable = enable ? 1 : 0;

2589
	REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
T
Tomi Valkeinen 已提交
2590

2591 2592
	if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
		0, enable) != enable) {
T
Tomi Valkeinen 已提交
2593 2594 2595 2596 2597 2598 2599
			DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
			return -EIO;
	}

	return 0;
}

2600
static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
T
Tomi Valkeinen 已提交
2601 2602 2603 2604 2605
{
	u32 r;

	DSSDBGF("%d", channel);

2606
	r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
T
Tomi Valkeinen 已提交
2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618

	if (FLD_GET(r, 15, 15)) /* VC_BUSY */
		DSSERR("VC(%d) busy when trying to configure it!\n",
				channel);

	r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
	r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN  */
	r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
	r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
	r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
	r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
	r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
2619 2620
	if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
		r = FLD_MOD(r, 3, 11, 10);	/* OCP_WIDTH = 32 bit */
T
Tomi Valkeinen 已提交
2621 2622 2623 2624

	r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
	r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */

2625
	dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
T
Tomi Valkeinen 已提交
2626 2627
}

2628
static int dsi_vc_config_l4(struct platform_device *dsidev, int channel)
T
Tomi Valkeinen 已提交
2629
{
2630 2631 2632
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (dsi->vc[channel].mode == DSI_VC_MODE_L4)
2633
		return 0;
T
Tomi Valkeinen 已提交
2634 2635 2636

	DSSDBGF("%d", channel);

2637
	dsi_sync_vc(dsidev, channel);
2638

2639
	dsi_vc_enable(dsidev, channel, 0);
T
Tomi Valkeinen 已提交
2640

2641
	/* VC_BUSY */
2642
	if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
T
Tomi Valkeinen 已提交
2643
		DSSERR("vc(%d) busy when trying to config for L4\n", channel);
2644 2645
		return -EIO;
	}
T
Tomi Valkeinen 已提交
2646

2647
	REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
T
Tomi Valkeinen 已提交
2648

2649 2650
	/* DCS_CMD_ENABLE */
	if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
2651
		REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30);
2652

2653
	dsi_vc_enable(dsidev, channel, 1);
T
Tomi Valkeinen 已提交
2654

2655
	dsi->vc[channel].mode = DSI_VC_MODE_L4;
2656 2657

	return 0;
T
Tomi Valkeinen 已提交
2658 2659
}

2660
static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
T
Tomi Valkeinen 已提交
2661
{
2662 2663 2664
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (dsi->vc[channel].mode == DSI_VC_MODE_VP)
2665
		return 0;
T
Tomi Valkeinen 已提交
2666 2667 2668

	DSSDBGF("%d", channel);

2669
	dsi_sync_vc(dsidev, channel);
2670

2671
	dsi_vc_enable(dsidev, channel, 0);
T
Tomi Valkeinen 已提交
2672

2673
	/* VC_BUSY */
2674
	if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
T
Tomi Valkeinen 已提交
2675
		DSSERR("vc(%d) busy when trying to config for VP\n", channel);
2676 2677
		return -EIO;
	}
T
Tomi Valkeinen 已提交
2678

2679 2680
	/* SOURCE, 1 = video port */
	REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1);
T
Tomi Valkeinen 已提交
2681

2682 2683
	/* DCS_CMD_ENABLE */
	if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
2684
		REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30);
2685

2686
	dsi_vc_enable(dsidev, channel, 1);
T
Tomi Valkeinen 已提交
2687

2688
	dsi->vc[channel].mode = DSI_VC_MODE_VP;
2689 2690

	return 0;
T
Tomi Valkeinen 已提交
2691 2692 2693
}


2694 2695
void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
		bool enable)
T
Tomi Valkeinen 已提交
2696
{
2697 2698
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);

T
Tomi Valkeinen 已提交
2699 2700
	DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);

2701
	WARN_ON(!dsi_bus_is_locked(dsidev));
2702

2703 2704
	dsi_vc_enable(dsidev, channel, 0);
	dsi_if_enable(dsidev, 0);
T
Tomi Valkeinen 已提交
2705

2706
	REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
T
Tomi Valkeinen 已提交
2707

2708 2709
	dsi_vc_enable(dsidev, channel, 1);
	dsi_if_enable(dsidev, 1);
T
Tomi Valkeinen 已提交
2710

2711
	dsi_force_tx_stop_mode_io(dsidev);
T
Tomi Valkeinen 已提交
2712
}
2713
EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
T
Tomi Valkeinen 已提交
2714

2715
static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
T
Tomi Valkeinen 已提交
2716
{
2717
	while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
T
Tomi Valkeinen 已提交
2718
		u32 val;
2719
		val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
T
Tomi Valkeinen 已提交
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764
		DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
				(val >> 0) & 0xff,
				(val >> 8) & 0xff,
				(val >> 16) & 0xff,
				(val >> 24) & 0xff);
	}
}

static void dsi_show_rx_ack_with_err(u16 err)
{
	DSSERR("\tACK with ERROR (%#x):\n", err);
	if (err & (1 << 0))
		DSSERR("\t\tSoT Error\n");
	if (err & (1 << 1))
		DSSERR("\t\tSoT Sync Error\n");
	if (err & (1 << 2))
		DSSERR("\t\tEoT Sync Error\n");
	if (err & (1 << 3))
		DSSERR("\t\tEscape Mode Entry Command Error\n");
	if (err & (1 << 4))
		DSSERR("\t\tLP Transmit Sync Error\n");
	if (err & (1 << 5))
		DSSERR("\t\tHS Receive Timeout Error\n");
	if (err & (1 << 6))
		DSSERR("\t\tFalse Control Error\n");
	if (err & (1 << 7))
		DSSERR("\t\t(reserved7)\n");
	if (err & (1 << 8))
		DSSERR("\t\tECC Error, single-bit (corrected)\n");
	if (err & (1 << 9))
		DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
	if (err & (1 << 10))
		DSSERR("\t\tChecksum Error\n");
	if (err & (1 << 11))
		DSSERR("\t\tData type not recognized\n");
	if (err & (1 << 12))
		DSSERR("\t\tInvalid VC ID\n");
	if (err & (1 << 13))
		DSSERR("\t\tInvalid Transmission Length\n");
	if (err & (1 << 14))
		DSSERR("\t\t(reserved14)\n");
	if (err & (1 << 15))
		DSSERR("\t\tDSI Protocol Violation\n");
}

2765 2766
static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
		int channel)
T
Tomi Valkeinen 已提交
2767 2768
{
	/* RX_FIFO_NOT_EMPTY */
2769
	while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
T
Tomi Valkeinen 已提交
2770 2771
		u32 val;
		u8 dt;
2772
		val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2773
		DSSERR("\trawval %#08x\n", val);
T
Tomi Valkeinen 已提交
2774 2775 2776 2777 2778
		dt = FLD_GET(val, 5, 0);
		if (dt == DSI_DT_RX_ACK_WITH_ERR) {
			u16 err = FLD_GET(val, 23, 8);
			dsi_show_rx_ack_with_err(err);
		} else if (dt == DSI_DT_RX_SHORT_READ_1) {
2779
			DSSERR("\tDCS short response, 1 byte: %#x\n",
T
Tomi Valkeinen 已提交
2780 2781
					FLD_GET(val, 23, 8));
		} else if (dt == DSI_DT_RX_SHORT_READ_2) {
2782
			DSSERR("\tDCS short response, 2 byte: %#x\n",
T
Tomi Valkeinen 已提交
2783 2784
					FLD_GET(val, 23, 8));
		} else if (dt == DSI_DT_RX_DCS_LONG_READ) {
2785
			DSSERR("\tDCS long response, len %d\n",
T
Tomi Valkeinen 已提交
2786
					FLD_GET(val, 23, 8));
2787
			dsi_vc_flush_long_data(dsidev, channel);
T
Tomi Valkeinen 已提交
2788 2789 2790 2791 2792 2793 2794
		} else {
			DSSERR("\tunknown datatype 0x%02x\n", dt);
		}
	}
	return 0;
}

2795
static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
T
Tomi Valkeinen 已提交
2796
{
2797 2798 2799
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (dsi->debug_write || dsi->debug_read)
T
Tomi Valkeinen 已提交
2800 2801
		DSSDBG("dsi_vc_send_bta %d\n", channel);

2802
	WARN_ON(!dsi_bus_is_locked(dsidev));
T
Tomi Valkeinen 已提交
2803

2804 2805
	/* RX_FIFO_NOT_EMPTY */
	if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
T
Tomi Valkeinen 已提交
2806
		DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
2807
		dsi_vc_flush_receive_data(dsidev, channel);
T
Tomi Valkeinen 已提交
2808 2809
	}

2810
	REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
T
Tomi Valkeinen 已提交
2811 2812 2813 2814

	return 0;
}

2815
int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
T
Tomi Valkeinen 已提交
2816
{
2817
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2818
	DECLARE_COMPLETION_ONSTACK(completion);
T
Tomi Valkeinen 已提交
2819 2820 2821
	int r = 0;
	u32 err;

2822
	r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
2823 2824 2825
			&completion, DSI_VC_IRQ_BTA);
	if (r)
		goto err0;
T
Tomi Valkeinen 已提交
2826

2827
	r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
2828
			DSI_IRQ_ERROR_MASK);
T
Tomi Valkeinen 已提交
2829
	if (r)
2830
		goto err1;
T
Tomi Valkeinen 已提交
2831

2832
	r = dsi_vc_send_bta(dsidev, channel);
2833 2834 2835
	if (r)
		goto err2;

2836
	if (wait_for_completion_timeout(&completion,
T
Tomi Valkeinen 已提交
2837 2838 2839
				msecs_to_jiffies(500)) == 0) {
		DSSERR("Failed to receive BTA\n");
		r = -EIO;
2840
		goto err2;
T
Tomi Valkeinen 已提交
2841 2842
	}

2843
	err = dsi_get_errors(dsidev);
T
Tomi Valkeinen 已提交
2844 2845 2846
	if (err) {
		DSSERR("Error while sending BTA: %x\n", err);
		r = -EIO;
2847
		goto err2;
T
Tomi Valkeinen 已提交
2848
	}
2849
err2:
2850
	dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
2851
			DSI_IRQ_ERROR_MASK);
2852
err1:
2853
	dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
2854 2855
			&completion, DSI_VC_IRQ_BTA);
err0:
T
Tomi Valkeinen 已提交
2856 2857 2858 2859
	return r;
}
EXPORT_SYMBOL(dsi_vc_send_bta_sync);

2860 2861
static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
		int channel, u8 data_type, u16 len, u8 ecc)
T
Tomi Valkeinen 已提交
2862
{
2863
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
2864 2865 2866
	u32 val;
	u8 data_id;

2867
	WARN_ON(!dsi_bus_is_locked(dsidev));
T
Tomi Valkeinen 已提交
2868

2869
	data_id = data_type | dsi->vc[channel].vc_id << 6;
T
Tomi Valkeinen 已提交
2870 2871 2872 2873

	val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
		FLD_VAL(ecc, 31, 24);

2874
	dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
T
Tomi Valkeinen 已提交
2875 2876
}

2877 2878
static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
		int channel, u8 b1, u8 b2, u8 b3, u8 b4)
T
Tomi Valkeinen 已提交
2879 2880 2881 2882 2883 2884 2885 2886
{
	u32 val;

	val = b4 << 24 | b3 << 16 | b2 << 8  | b1 << 0;

/*	DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
			b1, b2, b3, b4, val); */

2887
	dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
T
Tomi Valkeinen 已提交
2888 2889
}

2890 2891
static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
		u8 data_type, u8 *data, u16 len, u8 ecc)
T
Tomi Valkeinen 已提交
2892 2893
{
	/*u32 val; */
2894
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
2895 2896 2897 2898 2899
	int i;
	u8 *p;
	int r = 0;
	u8 b1, b2, b3, b4;

2900
	if (dsi->debug_write)
T
Tomi Valkeinen 已提交
2901 2902 2903
		DSSDBG("dsi_vc_send_long, %d bytes\n", len);

	/* len + header */
2904
	if (dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
T
Tomi Valkeinen 已提交
2905 2906 2907 2908
		DSSERR("unable to send long packet: packet too long.\n");
		return -EINVAL;
	}

2909
	dsi_vc_config_l4(dsidev, channel);
T
Tomi Valkeinen 已提交
2910

2911
	dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
T
Tomi Valkeinen 已提交
2912 2913 2914

	p = data;
	for (i = 0; i < len >> 2; i++) {
2915
		if (dsi->debug_write)
T
Tomi Valkeinen 已提交
2916 2917 2918 2919 2920 2921 2922
			DSSDBG("\tsending full packet %d\n", i);

		b1 = *p++;
		b2 = *p++;
		b3 = *p++;
		b4 = *p++;

2923
		dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
T
Tomi Valkeinen 已提交
2924 2925 2926 2927 2928 2929
	}

	i = len % 4;
	if (i) {
		b1 = 0; b2 = 0; b3 = 0;

2930
		if (dsi->debug_write)
T
Tomi Valkeinen 已提交
2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947
			DSSDBG("\tsending remainder bytes %d\n", i);

		switch (i) {
		case 3:
			b1 = *p++;
			b2 = *p++;
			b3 = *p++;
			break;
		case 2:
			b1 = *p++;
			b2 = *p++;
			break;
		case 1:
			b1 = *p++;
			break;
		}

2948
		dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
T
Tomi Valkeinen 已提交
2949 2950 2951 2952 2953
	}

	return r;
}

2954 2955
static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
		u8 data_type, u16 data, u8 ecc)
T
Tomi Valkeinen 已提交
2956
{
2957
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
2958 2959 2960
	u32 r;
	u8 data_id;

2961
	WARN_ON(!dsi_bus_is_locked(dsidev));
T
Tomi Valkeinen 已提交
2962

2963
	if (dsi->debug_write)
T
Tomi Valkeinen 已提交
2964 2965 2966 2967
		DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
				channel,
				data_type, data & 0xff, (data >> 8) & 0xff);

2968
	dsi_vc_config_l4(dsidev, channel);
T
Tomi Valkeinen 已提交
2969

2970
	if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
T
Tomi Valkeinen 已提交
2971 2972 2973 2974
		DSSERR("ERROR FIFO FULL, aborting transfer\n");
		return -EINVAL;
	}

2975
	data_id = data_type | dsi->vc[channel].vc_id << 6;
T
Tomi Valkeinen 已提交
2976 2977 2978

	r = (data_id << 0) | (data << 8) | (ecc << 24);

2979
	dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
T
Tomi Valkeinen 已提交
2980 2981 2982 2983

	return 0;
}

2984
int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
T
Tomi Valkeinen 已提交
2985
{
2986
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
2987
	u8 nullpkg[] = {0, 0, 0, 0};
2988 2989 2990

	return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg,
		4, 0);
T
Tomi Valkeinen 已提交
2991 2992 2993
}
EXPORT_SYMBOL(dsi_vc_send_null);

2994 2995
int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
		u8 *data, int len)
T
Tomi Valkeinen 已提交
2996
{
2997
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
2998 2999 3000 3001 3002
	int r;

	BUG_ON(len == 0);

	if (len == 1) {
3003
		r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0,
T
Tomi Valkeinen 已提交
3004 3005
				data[0], 0);
	} else if (len == 2) {
3006
		r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1,
T
Tomi Valkeinen 已提交
3007 3008 3009
				data[0] | (data[1] << 8), 0);
	} else {
		/* 0x39 = DCS Long Write */
3010
		r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
T
Tomi Valkeinen 已提交
3011 3012 3013 3014 3015 3016 3017
				data, len, 0);
	}

	return r;
}
EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);

3018 3019
int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
		int len)
T
Tomi Valkeinen 已提交
3020
{
3021
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
3022 3023
	int r;

3024
	r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len);
T
Tomi Valkeinen 已提交
3025
	if (r)
3026
		goto err;
T
Tomi Valkeinen 已提交
3027

3028
	r = dsi_vc_send_bta_sync(dssdev, channel);
3029 3030
	if (r)
		goto err;
T
Tomi Valkeinen 已提交
3031

3032 3033
	/* RX_FIFO_NOT_EMPTY */
	if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
3034
		DSSERR("rx fifo not empty after write, dumping data:\n");
3035
		dsi_vc_flush_receive_data(dsidev, channel);
3036 3037 3038 3039
		r = -EIO;
		goto err;
	}

3040 3041 3042 3043
	return 0;
err:
	DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
			channel, data[0], len);
T
Tomi Valkeinen 已提交
3044 3045 3046 3047
	return r;
}
EXPORT_SYMBOL(dsi_vc_dcs_write);

3048
int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
3049
{
3050
	return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
3051 3052 3053
}
EXPORT_SYMBOL(dsi_vc_dcs_write_0);

3054 3055
int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
		u8 param)
3056 3057 3058 3059
{
	u8 buf[2];
	buf[0] = dcs_cmd;
	buf[1] = param;
3060
	return dsi_vc_dcs_write(dssdev, channel, buf, 2);
3061 3062 3063
}
EXPORT_SYMBOL(dsi_vc_dcs_write_1);

3064 3065
int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
		u8 *buf, int buflen)
T
Tomi Valkeinen 已提交
3066
{
3067
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3068
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
3069 3070 3071 3072
	u32 val;
	u8 dt;
	int r;

3073
	if (dsi->debug_read)
3074
		DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
T
Tomi Valkeinen 已提交
3075

3076
	r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
T
Tomi Valkeinen 已提交
3077
	if (r)
3078
		goto err;
T
Tomi Valkeinen 已提交
3079

3080
	r = dsi_vc_send_bta_sync(dssdev, channel);
T
Tomi Valkeinen 已提交
3081
	if (r)
3082
		goto err;
T
Tomi Valkeinen 已提交
3083 3084

	/* RX_FIFO_NOT_EMPTY */
3085
	if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
T
Tomi Valkeinen 已提交
3086
		DSSERR("RX fifo empty when trying to read.\n");
3087 3088
		r = -EIO;
		goto err;
T
Tomi Valkeinen 已提交
3089 3090
	}

3091
	val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
3092
	if (dsi->debug_read)
T
Tomi Valkeinen 已提交
3093 3094 3095 3096 3097
		DSSDBG("\theader: %08x\n", val);
	dt = FLD_GET(val, 5, 0);
	if (dt == DSI_DT_RX_ACK_WITH_ERR) {
		u16 err = FLD_GET(val, 23, 8);
		dsi_show_rx_ack_with_err(err);
3098 3099
		r = -EIO;
		goto err;
T
Tomi Valkeinen 已提交
3100 3101 3102

	} else if (dt == DSI_DT_RX_SHORT_READ_1) {
		u8 data = FLD_GET(val, 15, 8);
3103
		if (dsi->debug_read)
T
Tomi Valkeinen 已提交
3104 3105
			DSSDBG("\tDCS short response, 1 byte: %02x\n", data);

3106 3107 3108 3109
		if (buflen < 1) {
			r = -EIO;
			goto err;
		}
T
Tomi Valkeinen 已提交
3110 3111 3112 3113 3114 3115

		buf[0] = data;

		return 1;
	} else if (dt == DSI_DT_RX_SHORT_READ_2) {
		u16 data = FLD_GET(val, 23, 8);
3116
		if (dsi->debug_read)
T
Tomi Valkeinen 已提交
3117 3118
			DSSDBG("\tDCS short response, 2 byte: %04x\n", data);

3119 3120 3121 3122
		if (buflen < 2) {
			r = -EIO;
			goto err;
		}
T
Tomi Valkeinen 已提交
3123 3124 3125 3126 3127 3128 3129 3130

		buf[0] = data & 0xff;
		buf[1] = (data >> 8) & 0xff;

		return 2;
	} else if (dt == DSI_DT_RX_DCS_LONG_READ) {
		int w;
		int len = FLD_GET(val, 23, 8);
3131
		if (dsi->debug_read)
T
Tomi Valkeinen 已提交
3132 3133
			DSSDBG("\tDCS long response, len %d\n", len);

3134 3135 3136 3137
		if (len > buflen) {
			r = -EIO;
			goto err;
		}
T
Tomi Valkeinen 已提交
3138 3139 3140 3141

		/* two byte checksum ends the packet, not included in len */
		for (w = 0; w < len + 2;) {
			int b;
3142 3143
			val = dsi_read_reg(dsidev,
				DSI_VC_SHORT_PACKET_HEADER(channel));
3144
			if (dsi->debug_read)
T
Tomi Valkeinen 已提交
3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161
				DSSDBG("\t\t%02x %02x %02x %02x\n",
						(val >> 0) & 0xff,
						(val >> 8) & 0xff,
						(val >> 16) & 0xff,
						(val >> 24) & 0xff);

			for (b = 0; b < 4; ++b) {
				if (w < len)
					buf[w] = (val >> (b * 8)) & 0xff;
				/* we discard the 2 byte checksum */
				++w;
			}
		}

		return len;
	} else {
		DSSERR("\tunknown datatype 0x%02x\n", dt);
3162 3163
		r = -EIO;
		goto err;
T
Tomi Valkeinen 已提交
3164
	}
3165 3166 3167 3168 3169 3170 3171

	BUG();
err:
	DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
			channel, dcs_cmd);
	return r;

T
Tomi Valkeinen 已提交
3172 3173 3174
}
EXPORT_SYMBOL(dsi_vc_dcs_read);

3175 3176
int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
		u8 *data)
3177 3178 3179
{
	int r;

3180
	r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1);
3181 3182 3183 3184 3185 3186 3187 3188 3189 3190

	if (r < 0)
		return r;

	if (r != 1)
		return -EIO;

	return 0;
}
EXPORT_SYMBOL(dsi_vc_dcs_read_1);
T
Tomi Valkeinen 已提交
3191

3192 3193
int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
		u8 *data1, u8 *data2)
3194
{
3195
	u8 buf[2];
3196 3197
	int r;

3198
	r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2);
3199 3200 3201 3202 3203 3204 3205

	if (r < 0)
		return r;

	if (r != 2)
		return -EIO;

3206 3207 3208
	*data1 = buf[0];
	*data2 = buf[1];

3209 3210 3211 3212
	return 0;
}
EXPORT_SYMBOL(dsi_vc_dcs_read_2);

3213 3214
int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
		u16 len)
T
Tomi Valkeinen 已提交
3215
{
3216 3217 3218
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);

	return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
T
Tomi Valkeinen 已提交
3219 3220 3221 3222
			len, 0);
}
EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);

3223
static int dsi_enter_ulps(struct platform_device *dsidev)
3224
{
3225
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3226 3227 3228 3229 3230
	DECLARE_COMPLETION_ONSTACK(completion);
	int r;

	DSSDBGF();

3231
	WARN_ON(!dsi_bus_is_locked(dsidev));
3232

3233
	WARN_ON(dsi->ulps_enabled);
3234

3235
	if (dsi->ulps_enabled)
3236 3237
		return 0;

3238
	if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
3239 3240 3241 3242
		DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
		return -EIO;
	}

3243 3244 3245 3246
	dsi_sync_vc(dsidev, 0);
	dsi_sync_vc(dsidev, 1);
	dsi_sync_vc(dsidev, 2);
	dsi_sync_vc(dsidev, 3);
3247

3248
	dsi_force_tx_stop_mode_io(dsidev);
3249

3250 3251 3252 3253
	dsi_vc_enable(dsidev, 0, false);
	dsi_vc_enable(dsidev, 1, false);
	dsi_vc_enable(dsidev, 2, false);
	dsi_vc_enable(dsidev, 3, false);
3254

3255
	if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) {	/* HS_BUSY */
3256 3257 3258 3259
		DSSERR("HS busy when enabling ULPS\n");
		return -EIO;
	}

3260
	if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) {	/* LP_BUSY */
3261 3262 3263 3264
		DSSERR("LP busy when enabling ULPS\n");
		return -EIO;
	}

3265
	r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
3266 3267 3268 3269 3270 3271
			DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
	if (r)
		return r;

	/* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
	/* LANEx_ULPS_SIG2 */
3272 3273
	REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2),
		7, 5);
3274 3275 3276 3277 3278 3279 3280 3281

	if (wait_for_completion_timeout(&completion,
				msecs_to_jiffies(1000)) == 0) {
		DSSERR("ULPS enable timeout\n");
		r = -EIO;
		goto err;
	}

3282
	dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3283 3284
			DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);

3285
	dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
3286

3287
	dsi_if_enable(dsidev, false);
3288

3289
	dsi->ulps_enabled = true;
3290 3291 3292 3293

	return 0;

err:
3294
	dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3295 3296 3297 3298
			DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
	return r;
}

3299 3300
static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
		unsigned ticks, bool x4, bool x16)
T
Tomi Valkeinen 已提交
3301 3302
{
	unsigned long fck;
3303 3304
	unsigned long total_ticks;
	u32 r;
T
Tomi Valkeinen 已提交
3305

3306
	BUG_ON(ticks > 0x1fff);
T
Tomi Valkeinen 已提交
3307

3308
	/* ticks in DSI_FCK */
3309
	fck = dsi_fclk_rate(dsidev);
T
Tomi Valkeinen 已提交
3310

3311
	r = dsi_read_reg(dsidev, DSI_TIMING2);
T
Tomi Valkeinen 已提交
3312
	r = FLD_MOD(r, 1, 15, 15);	/* LP_RX_TO */
3313 3314
	r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);	/* LP_RX_TO_X16 */
	r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);	/* LP_RX_TO_X4 */
T
Tomi Valkeinen 已提交
3315
	r = FLD_MOD(r, ticks, 12, 0);	/* LP_RX_COUNTER */
3316
	dsi_write_reg(dsidev, DSI_TIMING2, r);
T
Tomi Valkeinen 已提交
3317

3318 3319 3320 3321 3322 3323
	total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);

	DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
			total_ticks,
			ticks, x4 ? " x4" : "", x16 ? " x16" : "",
			(total_ticks * 1000) / (fck / 1000 / 1000));
T
Tomi Valkeinen 已提交
3324 3325
}

3326 3327
static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
		bool x8, bool x16)
T
Tomi Valkeinen 已提交
3328 3329
{
	unsigned long fck;
3330 3331 3332 3333
	unsigned long total_ticks;
	u32 r;

	BUG_ON(ticks > 0x1fff);
T
Tomi Valkeinen 已提交
3334 3335

	/* ticks in DSI_FCK */
3336
	fck = dsi_fclk_rate(dsidev);
T
Tomi Valkeinen 已提交
3337

3338
	r = dsi_read_reg(dsidev, DSI_TIMING1);
T
Tomi Valkeinen 已提交
3339
	r = FLD_MOD(r, 1, 31, 31);	/* TA_TO */
3340 3341
	r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);	/* TA_TO_X16 */
	r = FLD_MOD(r, x8 ? 1 : 0, 29, 29);	/* TA_TO_X8 */
T
Tomi Valkeinen 已提交
3342
	r = FLD_MOD(r, ticks, 28, 16);	/* TA_TO_COUNTER */
3343
	dsi_write_reg(dsidev, DSI_TIMING1, r);
T
Tomi Valkeinen 已提交
3344

3345 3346 3347 3348 3349 3350
	total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);

	DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
			total_ticks,
			ticks, x8 ? " x8" : "", x16 ? " x16" : "",
			(total_ticks * 1000) / (fck / 1000 / 1000));
T
Tomi Valkeinen 已提交
3351 3352
}

3353 3354
static void dsi_set_stop_state_counter(struct platform_device *dsidev,
		unsigned ticks, bool x4, bool x16)
T
Tomi Valkeinen 已提交
3355 3356
{
	unsigned long fck;
3357 3358
	unsigned long total_ticks;
	u32 r;
T
Tomi Valkeinen 已提交
3359

3360
	BUG_ON(ticks > 0x1fff);
T
Tomi Valkeinen 已提交
3361

3362
	/* ticks in DSI_FCK */
3363
	fck = dsi_fclk_rate(dsidev);
T
Tomi Valkeinen 已提交
3364

3365
	r = dsi_read_reg(dsidev, DSI_TIMING1);
T
Tomi Valkeinen 已提交
3366
	r = FLD_MOD(r, 1, 15, 15);	/* FORCE_TX_STOP_MODE_IO */
3367 3368
	r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);	/* STOP_STATE_X16_IO */
	r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);	/* STOP_STATE_X4_IO */
T
Tomi Valkeinen 已提交
3369
	r = FLD_MOD(r, ticks, 12, 0);	/* STOP_STATE_COUNTER_IO */
3370
	dsi_write_reg(dsidev, DSI_TIMING1, r);
T
Tomi Valkeinen 已提交
3371

3372 3373 3374 3375 3376 3377
	total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);

	DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
			total_ticks,
			ticks, x4 ? " x4" : "", x16 ? " x16" : "",
			(total_ticks * 1000) / (fck / 1000 / 1000));
T
Tomi Valkeinen 已提交
3378 3379
}

3380 3381
static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
		unsigned ticks, bool x4, bool x16)
T
Tomi Valkeinen 已提交
3382 3383
{
	unsigned long fck;
3384 3385
	unsigned long total_ticks;
	u32 r;
T
Tomi Valkeinen 已提交
3386

3387
	BUG_ON(ticks > 0x1fff);
T
Tomi Valkeinen 已提交
3388

3389
	/* ticks in TxByteClkHS */
3390
	fck = dsi_get_txbyteclkhs(dsidev);
T
Tomi Valkeinen 已提交
3391

3392
	r = dsi_read_reg(dsidev, DSI_TIMING2);
T
Tomi Valkeinen 已提交
3393
	r = FLD_MOD(r, 1, 31, 31);	/* HS_TX_TO */
3394 3395
	r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);	/* HS_TX_TO_X16 */
	r = FLD_MOD(r, x4 ? 1 : 0, 29, 29);	/* HS_TX_TO_X8 (4 really) */
T
Tomi Valkeinen 已提交
3396
	r = FLD_MOD(r, ticks, 28, 16);	/* HS_TX_TO_COUNTER */
3397
	dsi_write_reg(dsidev, DSI_TIMING2, r);
T
Tomi Valkeinen 已提交
3398

3399 3400 3401 3402 3403 3404
	total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);

	DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
			total_ticks,
			ticks, x4 ? " x4" : "", x16 ? " x16" : "",
			(total_ticks * 1000) / (fck / 1000 / 1000));
T
Tomi Valkeinen 已提交
3405 3406 3407
}
static int dsi_proto_config(struct omap_dss_device *dssdev)
{
3408
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
3409 3410 3411
	u32 r;
	int buswidth = 0;

3412
	dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
3413 3414 3415
			DSI_FIFO_SIZE_32,
			DSI_FIFO_SIZE_32,
			DSI_FIFO_SIZE_32);
T
Tomi Valkeinen 已提交
3416

3417
	dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
3418 3419 3420
			DSI_FIFO_SIZE_32,
			DSI_FIFO_SIZE_32,
			DSI_FIFO_SIZE_32);
T
Tomi Valkeinen 已提交
3421 3422

	/* XXX what values for the timeouts? */
3423 3424 3425 3426
	dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
	dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
	dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
	dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
T
Tomi Valkeinen 已提交
3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441

	switch (dssdev->ctrl.pixel_size) {
	case 16:
		buswidth = 0;
		break;
	case 18:
		buswidth = 1;
		break;
	case 24:
		buswidth = 2;
		break;
	default:
		BUG();
	}

3442
	r = dsi_read_reg(dsidev, DSI_CTRL);
T
Tomi Valkeinen 已提交
3443 3444 3445 3446 3447 3448 3449 3450 3451
	r = FLD_MOD(r, 1, 1, 1);	/* CS_RX_EN */
	r = FLD_MOD(r, 1, 2, 2);	/* ECC_RX_EN */
	r = FLD_MOD(r, 1, 3, 3);	/* TX_FIFO_ARBITRATION */
	r = FLD_MOD(r, 1, 4, 4);	/* VP_CLK_RATIO, always 1, see errata*/
	r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
	r = FLD_MOD(r, 0, 8, 8);	/* VP_CLK_POL */
	r = FLD_MOD(r, 2, 13, 12);	/* LINE_BUFFER, 2 lines */
	r = FLD_MOD(r, 1, 14, 14);	/* TRIGGER_RESET_MODE */
	r = FLD_MOD(r, 1, 19, 19);	/* EOT_ENABLE */
3452 3453 3454 3455 3456
	if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
		r = FLD_MOD(r, 1, 24, 24);	/* DCS_CMD_ENABLE */
		/* DCS_CMD_CODE, 1=start, 0=continue */
		r = FLD_MOD(r, 0, 25, 25);
	}
T
Tomi Valkeinen 已提交
3457

3458
	dsi_write_reg(dsidev, DSI_CTRL, r);
T
Tomi Valkeinen 已提交
3459

3460 3461 3462 3463
	dsi_vc_initial_config(dsidev, 0);
	dsi_vc_initial_config(dsidev, 1);
	dsi_vc_initial_config(dsidev, 2);
	dsi_vc_initial_config(dsidev, 3);
T
Tomi Valkeinen 已提交
3464 3465 3466 3467 3468 3469

	return 0;
}

static void dsi_proto_timings(struct omap_dss_device *dssdev)
{
3470
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
3471 3472 3473 3474 3475 3476 3477 3478 3479
	unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
	unsigned tclk_pre, tclk_post;
	unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
	unsigned ths_trail, ths_exit;
	unsigned ddr_clk_pre, ddr_clk_post;
	unsigned enter_hs_mode_lat, exit_hs_mode_lat;
	unsigned ths_eot;
	u32 r;

3480
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
T
Tomi Valkeinen 已提交
3481 3482 3483 3484 3485 3486
	ths_prepare = FLD_GET(r, 31, 24);
	ths_prepare_ths_zero = FLD_GET(r, 23, 16);
	ths_zero = ths_prepare_ths_zero - ths_prepare;
	ths_trail = FLD_GET(r, 15, 8);
	ths_exit = FLD_GET(r, 7, 0);

3487
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
T
Tomi Valkeinen 已提交
3488 3489 3490 3491
	tlpx = FLD_GET(r, 22, 16) * 2;
	tclk_trail = FLD_GET(r, 15, 8);
	tclk_zero = FLD_GET(r, 7, 0);

3492
	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
T
Tomi Valkeinen 已提交
3493 3494 3495 3496 3497
	tclk_prepare = FLD_GET(r, 7, 0);

	/* min 8*UI */
	tclk_pre = 20;
	/* min 60ns + 52*UI */
3498
	tclk_post = ns2ddr(dsidev, 60) + 26;
T
Tomi Valkeinen 已提交
3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513

	/* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
	if (dssdev->phy.dsi.data1_lane != 0 &&
			dssdev->phy.dsi.data2_lane != 0)
		ths_eot = 2;
	else
		ths_eot = 4;

	ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
			4);
	ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;

	BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
	BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);

3514
	r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
T
Tomi Valkeinen 已提交
3515 3516
	r = FLD_MOD(r, ddr_clk_pre, 15, 8);
	r = FLD_MOD(r, ddr_clk_post, 7, 0);
3517
	dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
T
Tomi Valkeinen 已提交
3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530

	DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
			ddr_clk_pre,
			ddr_clk_post);

	enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
		DIV_ROUND_UP(ths_prepare, 4) +
		DIV_ROUND_UP(ths_zero + 3, 4);

	exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;

	r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
		FLD_VAL(exit_hs_mode_lat, 15, 0);
3531
	dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
T
Tomi Valkeinen 已提交
3532 3533 3534 3535 3536 3537 3538 3539 3540

	DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
			enter_hs_mode_lat, exit_hs_mode_lat);
}


#define DSI_DECL_VARS \
	int __dsi_cb = 0; u32 __dsi_cv = 0;

3541
#define DSI_FLUSH(dsidev, ch) \
T
Tomi Valkeinen 已提交
3542 3543
	if (__dsi_cb > 0) { \
		/*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
3544
		dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
T
Tomi Valkeinen 已提交
3545 3546 3547
		__dsi_cb = __dsi_cv = 0; \
	}

3548
#define DSI_PUSH(dsidev, ch, data) \
T
Tomi Valkeinen 已提交
3549 3550 3551 3552
	do { \
		__dsi_cv |= (data) << (__dsi_cb * 8); \
		/*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
		if (++__dsi_cb > 3) \
3553
			DSI_FLUSH(dsidev, ch); \
T
Tomi Valkeinen 已提交
3554 3555 3556 3557 3558 3559
	} while (0)

static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
			int x, int y, int w, int h)
{
	/* Note: supports only 24bit colors in 32bit container */
3560
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3561
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599
	int first = 1;
	int fifo_stalls = 0;
	int max_dsi_packet_size;
	int max_data_per_packet;
	int max_pixels_per_packet;
	int pixels_left;
	int bytespp = dssdev->ctrl.pixel_size / 8;
	int scr_width;
	u32 __iomem *data;
	int start_offset;
	int horiz_inc;
	int current_x;
	struct omap_overlay *ovl;

	debug_irq = 0;

	DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
			x, y, w, h);

	ovl = dssdev->manager->overlays[0];

	if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
		return -EINVAL;

	if (dssdev->ctrl.pixel_size != 24)
		return -EINVAL;

	scr_width = ovl->info.screen_width;
	data = ovl->info.vaddr;

	start_offset = scr_width * y + x;
	horiz_inc = scr_width - w;
	current_x = x;

	/* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
	 * in fifo */

	/* When using CPU, max long packet size is TX buffer size */
3600
	max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4;
T
Tomi Valkeinen 已提交
3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628

	/* we seem to get better perf if we divide the tx fifo to half,
	   and while the other half is being sent, we fill the other half
	   max_dsi_packet_size /= 2; */

	max_data_per_packet = max_dsi_packet_size - 4 - 1;

	max_pixels_per_packet = max_data_per_packet / bytespp;

	DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);

	pixels_left = w * h;

	DSSDBG("total pixels %d\n", pixels_left);

	data += start_offset;

	while (pixels_left > 0) {
		/* 0x2c = write_memory_start */
		/* 0x3c = write_memory_continue */
		u8 dcs_cmd = first ? 0x2c : 0x3c;
		int pixels;
		DSI_DECL_VARS;
		first = 0;

#if 1
		/* using fifo not empty */
		/* TX_FIFO_NOT_EMPTY */
3629
		while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) {
T
Tomi Valkeinen 已提交
3630 3631 3632 3633
			fifo_stalls++;
			if (fifo_stalls > 0xfffff) {
				DSSERR("fifo stalls overflow, pixels left %d\n",
						pixels_left);
3634
				dsi_if_enable(dsidev, 0);
T
Tomi Valkeinen 已提交
3635 3636
				return -EIO;
			}
3637
			udelay(1);
T
Tomi Valkeinen 已提交
3638 3639 3640
		}
#elif 1
		/* using fifo emptiness */
3641
		while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
T
Tomi Valkeinen 已提交
3642 3643 3644 3645 3646
				max_dsi_packet_size) {
			fifo_stalls++;
			if (fifo_stalls > 0xfffff) {
				DSSERR("fifo stalls overflow, pixels left %d\n",
					       pixels_left);
3647
				dsi_if_enable(dsidev, 0);
T
Tomi Valkeinen 已提交
3648 3649 3650 3651
				return -EIO;
			}
		}
#else
3652 3653
		while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS,
				7, 0) + 1) * 4 == 0) {
T
Tomi Valkeinen 已提交
3654 3655 3656 3657
			fifo_stalls++;
			if (fifo_stalls > 0xfffff) {
				DSSERR("fifo stalls overflow, pixels left %d\n",
					       pixels_left);
3658
				dsi_if_enable(dsidev, 0);
T
Tomi Valkeinen 已提交
3659 3660 3661 3662 3663 3664 3665 3666
				return -EIO;
			}
		}
#endif
		pixels = min(max_pixels_per_packet, pixels_left);

		pixels_left -= pixels;

3667
		dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE,
T
Tomi Valkeinen 已提交
3668 3669
				1 + pixels * bytespp, 0);

3670
		DSI_PUSH(dsidev, 0, dcs_cmd);
T
Tomi Valkeinen 已提交
3671 3672 3673 3674

		while (pixels-- > 0) {
			u32 pix = __raw_readl(data++);

3675 3676 3677
			DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff);
			DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff);
			DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff);
T
Tomi Valkeinen 已提交
3678 3679 3680 3681 3682 3683 3684 3685

			current_x++;
			if (current_x == x+w) {
				current_x = x;
				data += horiz_inc;
			}
		}

3686
		DSI_FLUSH(dsidev, 0);
T
Tomi Valkeinen 已提交
3687 3688 3689 3690 3691 3692 3693 3694
	}

	return 0;
}

static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
		u16 x, u16 y, u16 w, u16 h)
{
3695
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3696
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
3697 3698 3699 3700 3701 3702 3703
	unsigned bytespp;
	unsigned bytespl;
	unsigned bytespf;
	unsigned total_len;
	unsigned packet_payload;
	unsigned packet_len;
	u32 l;
3704
	int r;
3705
	const unsigned channel = dsi->update_channel;
T
Tomi Valkeinen 已提交
3706 3707 3708 3709 3710
	/* line buffer is 1024 x 24bits */
	/* XXX: for some reason using full buffer size causes considerable TX
	 * slowdown with update sizes that fill the whole buffer */
	const unsigned line_buf_size = 1023 * 3;

3711 3712
	DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
			x, y, w, h);
T
Tomi Valkeinen 已提交
3713

3714
	dsi_vc_config_vp(dsidev, channel);
3715

T
Tomi Valkeinen 已提交
3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734
	bytespp	= dssdev->ctrl.pixel_size / 8;
	bytespl = w * bytespp;
	bytespf = bytespl * h;

	/* NOTE: packet_payload has to be equal to N * bytespl, where N is
	 * number of lines in a packet.  See errata about VP_CLK_RATIO */

	if (bytespf < line_buf_size)
		packet_payload = bytespf;
	else
		packet_payload = (line_buf_size) / bytespl * bytespl;

	packet_len = packet_payload + 1;	/* 1 byte for DCS cmd */
	total_len = (bytespf / packet_payload) * packet_len;

	if (bytespf % packet_payload)
		total_len += (bytespf % packet_payload) + 1;

	l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
3735
	dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
T
Tomi Valkeinen 已提交
3736

3737 3738
	dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
		packet_len, 0);
T
Tomi Valkeinen 已提交
3739

3740
	if (dsi->te_enabled)
T
Tomi Valkeinen 已提交
3741 3742 3743
		l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
	else
		l = FLD_MOD(l, 1, 31, 31); /* TE_START */
3744
	dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
T
Tomi Valkeinen 已提交
3745 3746 3747 3748 3749 3750 3751 3752 3753

	/* We put SIDLEMODE to no-idle for the duration of the transfer,
	 * because DSS interrupts are not capable of waking up the CPU and the
	 * framedone interrupt could be delayed for quite a long time. I think
	 * the same goes for any DSS interrupts, but for some reason I have not
	 * seen the problem anywhere else than here.
	 */
	dispc_disable_sidle();

3754
	dsi_perf_mark_start(dsidev);
3755

3756
	r = queue_delayed_work(dsi->workqueue, &dsi->framedone_timeout_work,
3757
			msecs_to_jiffies(250));
3758
	BUG_ON(r == 0);
3759

T
Tomi Valkeinen 已提交
3760 3761
	dss_start_update(dssdev);

3762
	if (dsi->te_enabled) {
T
Tomi Valkeinen 已提交
3763 3764
		/* disable LP_RX_TO, so that we can receive TE.  Time to wait
		 * for TE is longer than the timer allows */
3765
		REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
T
Tomi Valkeinen 已提交
3766

3767
		dsi_vc_send_bta(dsidev, channel);
T
Tomi Valkeinen 已提交
3768 3769

#ifdef DSI_CATCH_MISSING_TE
3770
		mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
T
Tomi Valkeinen 已提交
3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781
#endif
	}
}

#ifdef DSI_CATCH_MISSING_TE
static void dsi_te_timeout(unsigned long arg)
{
	DSSERR("TE not received for 250ms!\n");
}
#endif

3782
static void dsi_handle_framedone(struct platform_device *dsidev, int error)
T
Tomi Valkeinen 已提交
3783
{
3784 3785
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

T
Tomi Valkeinen 已提交
3786 3787 3788
	/* SIDLEMODE back to smart-idle */
	dispc_enable_sidle();

3789
	if (dsi->te_enabled) {
3790
		/* enable LP_RX_TO again after the TE */
3791
		REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
T
Tomi Valkeinen 已提交
3792 3793
	}

3794
	dsi->framedone_callback(error, dsi->framedone_data);
3795 3796

	if (!error)
3797
		dsi_perf_show(dsidev, "DISPC");
3798
}
T
Tomi Valkeinen 已提交
3799

3800
static void dsi_framedone_timeout_work_callback(struct work_struct *work)
3801
{
3802 3803
	struct dsi_data *dsi = container_of(work, struct dsi_data,
			framedone_timeout_work.work);
3804 3805 3806 3807 3808 3809
	/* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
	 * 250ms which would conflict with this timeout work. What should be
	 * done is first cancel the transfer on the HW, and then cancel the
	 * possibly scheduled framedone work. However, cancelling the transfer
	 * on the HW is buggy, and would probably require resetting the whole
	 * DSI */
3810

3811
	DSSERR("Framedone not received for 250ms!\n");
T
Tomi Valkeinen 已提交
3812

3813
	dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
T
Tomi Valkeinen 已提交
3814 3815
}

3816
static void dsi_framedone_irq_callback(void *data, u32 mask)
T
Tomi Valkeinen 已提交
3817
{
3818 3819
	struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3820 3821
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

3822 3823 3824 3825
	/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
	 * turns itself off. However, DSI still has the pixels in its buffers,
	 * and is sending the data.
	 */
T
Tomi Valkeinen 已提交
3826

3827
	__cancel_delayed_work(&dsi->framedone_timeout_work);
T
Tomi Valkeinen 已提交
3828

3829
	dsi_handle_framedone(dsidev, 0);
T
Tomi Valkeinen 已提交
3830

3831 3832 3833
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
	dispc_fake_vsync_irq();
#endif
3834
}
T
Tomi Valkeinen 已提交
3835

3836
int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
3837 3838
				    u16 *x, u16 *y, u16 *w, u16 *h,
				    bool enlarge_update_area)
3839
{
3840
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3841
	u16 dw, dh;
T
Tomi Valkeinen 已提交
3842

3843
	dssdev->driver->get_resolution(dssdev, &dw, &dh);
T
Tomi Valkeinen 已提交
3844

3845 3846
	if  (*x > dw || *y > dh)
		return -EINVAL;
T
Tomi Valkeinen 已提交
3847

3848 3849
	if (*x + *w > dw)
		return -EINVAL;
T
Tomi Valkeinen 已提交
3850

3851 3852
	if (*y + *h > dh)
		return -EINVAL;
T
Tomi Valkeinen 已提交
3853

3854 3855
	if (*w == 1)
		return -EINVAL;
T
Tomi Valkeinen 已提交
3856

3857 3858
	if (*w == 0 || *h == 0)
		return -EINVAL;
T
Tomi Valkeinen 已提交
3859

3860
	dsi_perf_mark_setup(dsidev);
T
Tomi Valkeinen 已提交
3861

3862
	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
3863 3864
		dss_setup_partial_planes(dssdev, x, y, w, h,
				enlarge_update_area);
3865
		dispc_set_lcd_size(dssdev->manager->id, *w, *h);
3866
	}
T
Tomi Valkeinen 已提交
3867

3868 3869 3870
	return 0;
}
EXPORT_SYMBOL(omap_dsi_prepare_update);
T
Tomi Valkeinen 已提交
3871

3872 3873 3874 3875 3876
int omap_dsi_update(struct omap_dss_device *dssdev,
		int channel,
		u16 x, u16 y, u16 w, u16 h,
		void (*callback)(int, void *), void *data)
{
3877
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3878
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3879

3880
	dsi->update_channel = channel;
T
Tomi Valkeinen 已提交
3881

3882 3883 3884 3885 3886 3887
	/* OMAP DSS cannot send updates of odd widths.
	 * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
	 * here to make sure we catch erroneous updates. Otherwise we'll only
	 * see rather obscure HW error happening, as DSS halts. */
	BUG_ON(x % 2 == 1);

3888
	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
3889 3890
		dsi->framedone_callback = callback;
		dsi->framedone_data = data;
T
Tomi Valkeinen 已提交
3891

3892 3893 3894 3895 3896
		dsi->update_region.x = x;
		dsi->update_region.y = y;
		dsi->update_region.w = w;
		dsi->update_region.h = h;
		dsi->update_region.device = dssdev;
T
Tomi Valkeinen 已提交
3897

3898 3899
		dsi_update_screen_dispc(dssdev, x, y, w, h);
	} else {
3900 3901 3902 3903 3904 3905
		int r;

		r = dsi_update_screen_l4(dssdev, x, y, w, h);
		if (r)
			return r;

3906
		dsi_perf_show(dsidev, "L4");
3907
		callback(0, data);
T
Tomi Valkeinen 已提交
3908 3909 3910 3911
	}

	return 0;
}
3912
EXPORT_SYMBOL(omap_dsi_update);
T
Tomi Valkeinen 已提交
3913 3914 3915 3916 3917 3918

/* Display funcs */

static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
{
	int r;
3919 3920 3921 3922
	u32 irq;

	irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
		DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
T
Tomi Valkeinen 已提交
3923

3924
	r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev,
3925
			irq);
T
Tomi Valkeinen 已提交
3926 3927 3928 3929 3930
	if (r) {
		DSSERR("can't get FRAMEDONE irq\n");
		return r;
	}

3931 3932
	dispc_set_lcd_display_type(dssdev->manager->id,
			OMAP_DSS_LCD_DISPLAY_TFT);
T
Tomi Valkeinen 已提交
3933

3934 3935 3936
	dispc_set_parallel_interface_mode(dssdev->manager->id,
			OMAP_DSS_PARALLELMODE_DSI);
	dispc_enable_fifohandcheck(dssdev->manager->id, 1);
T
Tomi Valkeinen 已提交
3937

3938
	dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
T
Tomi Valkeinen 已提交
3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949

	{
		struct omap_video_timings timings = {
			.hsw		= 1,
			.hfp		= 1,
			.hbp		= 1,
			.vsw		= 1,
			.vfp		= 0,
			.vbp		= 0,
		};

3950
		dispc_set_lcd_timings(dssdev->manager->id, &timings);
T
Tomi Valkeinen 已提交
3951 3952 3953 3954 3955 3956 3957
	}

	return 0;
}

static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
{
3958 3959 3960 3961 3962
	u32 irq;

	irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
		DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;

3963
	omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev,
3964
			irq);
T
Tomi Valkeinen 已提交
3965 3966 3967 3968
}

static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
{
3969
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
3970 3971 3972
	struct dsi_clock_info cinfo;
	int r;

3973 3974
	/* we always use DSS_CLK_SYSCK as input clock */
	cinfo.use_sys_clk = true;
3975 3976 3977 3978
	cinfo.regn  = dssdev->clocks.dsi.regn;
	cinfo.regm  = dssdev->clocks.dsi.regm;
	cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
	cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
3979
	r = dsi_calc_clock_rates(dssdev, &cinfo);
3980 3981
	if (r) {
		DSSERR("Failed to calc dsi clocks\n");
T
Tomi Valkeinen 已提交
3982
		return r;
3983
	}
T
Tomi Valkeinen 已提交
3984

3985
	r = dsi_pll_set_clock_div(dsidev, &cinfo);
T
Tomi Valkeinen 已提交
3986 3987 3988 3989 3990 3991 3992 3993 3994 3995
	if (r) {
		DSSERR("Failed to set dsi clocks\n");
		return r;
	}

	return 0;
}

static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
{
3996
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
T
Tomi Valkeinen 已提交
3997 3998 3999 4000
	struct dispc_clock_info dispc_cinfo;
	int r;
	unsigned long long fck;

4001
	fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
T
Tomi Valkeinen 已提交
4002

4003 4004
	dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
	dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
T
Tomi Valkeinen 已提交
4005 4006 4007 4008 4009 4010 4011

	r = dispc_calc_clock_rates(fck, &dispc_cinfo);
	if (r) {
		DSSERR("Failed to calc dispc clocks\n");
		return r;
	}

4012
	r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
T
Tomi Valkeinen 已提交
4013 4014 4015 4016 4017 4018 4019 4020 4021 4022
	if (r) {
		DSSERR("Failed to set dispc clocks\n");
		return r;
	}

	return 0;
}

static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
{
4023
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4024
	int dsi_module = dsi_get_dsidev_id(dsidev);
T
Tomi Valkeinen 已提交
4025 4026
	int r;

4027
	r = dsi_pll_init(dsidev, true, true);
T
Tomi Valkeinen 已提交
4028 4029 4030 4031 4032 4033 4034
	if (r)
		goto err0;

	r = dsi_configure_dsi_clocks(dssdev);
	if (r)
		goto err1;

4035
	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
4036
	dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src);
4037
	dss_select_lcd_clk_source(dssdev->manager->id,
4038
			dssdev->clocks.dispc.channel.lcd_clk_src);
T
Tomi Valkeinen 已提交
4039 4040 4041 4042 4043 4044 4045

	DSSDBG("PLL OK\n");

	r = dsi_configure_dispc_clocks(dssdev);
	if (r)
		goto err2;

4046
	r = dsi_cio_init(dssdev);
T
Tomi Valkeinen 已提交
4047 4048 4049
	if (r)
		goto err2;

4050
	_dsi_print_reset_status(dsidev);
T
Tomi Valkeinen 已提交
4051 4052 4053 4054 4055

	dsi_proto_timings(dssdev);
	dsi_set_lp_clk_divisor(dssdev);

	if (1)
4056
		_dsi_print_reset_status(dsidev);
T
Tomi Valkeinen 已提交
4057 4058 4059 4060 4061 4062

	r = dsi_proto_config(dssdev);
	if (r)
		goto err3;

	/* enable interface */
4063 4064 4065 4066 4067 4068
	dsi_vc_enable(dsidev, 0, 1);
	dsi_vc_enable(dsidev, 1, 1);
	dsi_vc_enable(dsidev, 2, 1);
	dsi_vc_enable(dsidev, 3, 1);
	dsi_if_enable(dsidev, 1);
	dsi_force_tx_stop_mode_io(dsidev);
T
Tomi Valkeinen 已提交
4069 4070 4071

	return 0;
err3:
4072
	dsi_cio_uninit(dsidev);
T
Tomi Valkeinen 已提交
4073
err2:
4074
	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
4075
	dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
T
Tomi Valkeinen 已提交
4076
err1:
4077
	dsi_pll_uninit(dsidev, true);
T
Tomi Valkeinen 已提交
4078 4079 4080 4081
err0:
	return r;
}

4082
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
4083
		bool disconnect_lanes, bool enter_ulps)
T
Tomi Valkeinen 已提交
4084
{
4085
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4086
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4087
	int dsi_module = dsi_get_dsidev_id(dsidev);
4088

4089
	if (enter_ulps && !dsi->ulps_enabled)
4090
		dsi_enter_ulps(dsidev);
4091

4092
	/* disable interface */
4093 4094 4095 4096 4097
	dsi_if_enable(dsidev, 0);
	dsi_vc_enable(dsidev, 0, 0);
	dsi_vc_enable(dsidev, 1, 0);
	dsi_vc_enable(dsidev, 2, 0);
	dsi_vc_enable(dsidev, 3, 0);
4098

4099
	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
4100
	dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
4101 4102
	dsi_cio_uninit(dsidev);
	dsi_pll_uninit(dsidev, disconnect_lanes);
T
Tomi Valkeinen 已提交
4103 4104
}

4105
static int dsi_core_init(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
4106 4107
{
	/* Autoidle */
4108
	REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
T
Tomi Valkeinen 已提交
4109 4110

	/* ENWAKEUP */
4111
	REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
T
Tomi Valkeinen 已提交
4112 4113

	/* SIDLEMODE smart-idle */
4114
	REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
T
Tomi Valkeinen 已提交
4115

4116
	_dsi_initialize_irq(dsidev);
T
Tomi Valkeinen 已提交
4117 4118 4119 4120

	return 0;
}

4121
int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
T
Tomi Valkeinen 已提交
4122
{
4123
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4124
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
T
Tomi Valkeinen 已提交
4125 4126 4127 4128
	int r = 0;

	DSSDBG("dsi_display_enable\n");

4129
	WARN_ON(!dsi_bus_is_locked(dsidev));
4130

4131
	mutex_lock(&dsi->lock);
T
Tomi Valkeinen 已提交
4132 4133 4134 4135 4136 4137 4138 4139

	r = omap_dss_start_device(dssdev);
	if (r) {
		DSSERR("failed to start device\n");
		goto err0;
	}

	enable_clocks(1);
4140
	dsi_enable_pll_clock(dsidev, 1);
T
Tomi Valkeinen 已提交
4141

4142
	r = _dsi_reset(dsidev);
T
Tomi Valkeinen 已提交
4143
	if (r)
4144
		goto err1;
T
Tomi Valkeinen 已提交
4145

4146
	dsi_core_init(dsidev);
T
Tomi Valkeinen 已提交
4147 4148 4149

	r = dsi_display_init_dispc(dssdev);
	if (r)
4150
		goto err1;
T
Tomi Valkeinen 已提交
4151 4152 4153

	r = dsi_display_init_dsi(dssdev);
	if (r)
4154
		goto err2;
T
Tomi Valkeinen 已提交
4155

4156
	mutex_unlock(&dsi->lock);
T
Tomi Valkeinen 已提交
4157 4158 4159 4160

	return 0;

err2:
4161 4162
	dsi_display_uninit_dispc(dssdev);
err1:
T
Tomi Valkeinen 已提交
4163
	enable_clocks(0);
4164
	dsi_enable_pll_clock(dsidev, 0);
T
Tomi Valkeinen 已提交
4165 4166
	omap_dss_stop_device(dssdev);
err0:
4167
	mutex_unlock(&dsi->lock);
T
Tomi Valkeinen 已提交
4168 4169 4170
	DSSDBG("dsi_display_enable FAILED\n");
	return r;
}
4171
EXPORT_SYMBOL(omapdss_dsi_display_enable);
T
Tomi Valkeinen 已提交
4172

4173
void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
4174
		bool disconnect_lanes, bool enter_ulps)
T
Tomi Valkeinen 已提交
4175
{
4176
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4177
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4178

T
Tomi Valkeinen 已提交
4179 4180
	DSSDBG("dsi_display_disable\n");

4181
	WARN_ON(!dsi_bus_is_locked(dsidev));
T
Tomi Valkeinen 已提交
4182

4183
	mutex_lock(&dsi->lock);
T
Tomi Valkeinen 已提交
4184 4185 4186

	dsi_display_uninit_dispc(dssdev);

4187
	dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
T
Tomi Valkeinen 已提交
4188 4189

	enable_clocks(0);
4190
	dsi_enable_pll_clock(dsidev, 0);
T
Tomi Valkeinen 已提交
4191

4192
	omap_dss_stop_device(dssdev);
T
Tomi Valkeinen 已提交
4193

4194
	mutex_unlock(&dsi->lock);
T
Tomi Valkeinen 已提交
4195
}
4196
EXPORT_SYMBOL(omapdss_dsi_display_disable);
T
Tomi Valkeinen 已提交
4197

4198
int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
T
Tomi Valkeinen 已提交
4199
{
4200 4201 4202 4203
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	dsi->te_enabled = enable;
4204
	return 0;
T
Tomi Valkeinen 已提交
4205
}
4206
EXPORT_SYMBOL(omapdss_dsi_enable_te);
T
Tomi Valkeinen 已提交
4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217

void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
		u32 fifo_size, enum omap_burst_size *burst_size,
		u32 *fifo_low, u32 *fifo_high)
{
	unsigned burst_size_bytes;

	*burst_size = OMAP_DSS_BURST_16x32;
	burst_size_bytes = 16 * 32 / 8;

	*fifo_high = fifo_size - burst_size_bytes;
4218
	*fifo_low = fifo_size - burst_size_bytes * 2;
T
Tomi Valkeinen 已提交
4219 4220 4221 4222
}

int dsi_init_display(struct omap_dss_device *dssdev)
{
4223 4224 4225
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

T
Tomi Valkeinen 已提交
4226 4227 4228 4229 4230 4231
	DSSDBG("DSI init\n");

	/* XXX these should be figured out dynamically */
	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
		OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;

4232
	if (dsi->vdds_dsi_reg == NULL) {
4233 4234
		struct regulator *vdds_dsi;

4235
		vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
4236 4237 4238 4239 4240 4241

		if (IS_ERR(vdds_dsi)) {
			DSSERR("can't get VDDS_DSI regulator\n");
			return PTR_ERR(vdds_dsi);
		}

4242
		dsi->vdds_dsi_reg = vdds_dsi;
4243 4244
	}

T
Tomi Valkeinen 已提交
4245 4246 4247
	return 0;
}

4248 4249
int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
{
4250 4251
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4252 4253
	int i;

4254 4255 4256
	for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
		if (!dsi->vc[i].dssdev) {
			dsi->vc[i].dssdev = dssdev;
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268
			*channel = i;
			return 0;
		}
	}

	DSSERR("cannot get VC for display %s", dssdev->name);
	return -ENOSPC;
}
EXPORT_SYMBOL(omap_dsi_request_vc);

int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
{
4269 4270 4271
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

4272 4273 4274 4275 4276 4277 4278 4279 4280 4281
	if (vc_id < 0 || vc_id > 3) {
		DSSERR("VC ID out of range\n");
		return -EINVAL;
	}

	if (channel < 0 || channel > 3) {
		DSSERR("Virtual Channel out of range\n");
		return -EINVAL;
	}

4282
	if (dsi->vc[channel].dssdev != dssdev) {
4283 4284 4285 4286 4287
		DSSERR("Virtual Channel not allocated to display %s\n",
			dssdev->name);
		return -EINVAL;
	}

4288
	dsi->vc[channel].vc_id = vc_id;
4289 4290 4291 4292 4293 4294 4295

	return 0;
}
EXPORT_SYMBOL(omap_dsi_set_vc_id);

void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
{
4296 4297 4298
	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

4299
	if ((channel >= 0 && channel <= 3) &&
4300 4301 4302
		dsi->vc[channel].dssdev == dssdev) {
		dsi->vc[channel].dssdev = NULL;
		dsi->vc[channel].vc_id = 0;
4303 4304 4305 4306
	}
}
EXPORT_SYMBOL(omap_dsi_release_vc);

4307
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
4308
{
4309
	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
4310
		DSSERR("%s (%s) not active\n",
4311 4312
			dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
			dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
4313 4314
}

4315
void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
4316
{
4317
	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
4318
		DSSERR("%s (%s) not active\n",
4319 4320
			dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
			dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
4321 4322
}

4323
static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
4324
{
4325 4326 4327 4328 4329 4330 4331 4332 4333 4334
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
	dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
	dsi->regm_dispc_max =
		dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
	dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
	dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
	dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
	dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
4335 4336
}

4337
static int dsi_init(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
4338
{
4339 4340
	struct omap_display_platform_data *dss_plat_data;
	struct omap_dss_board_info *board_info;
T
Tomi Valkeinen 已提交
4341
	u32 rev;
4342
	int r, i, dsi_module = dsi_get_dsidev_id(dsidev);
4343
	struct resource *dsi_mem;
4344 4345 4346 4347 4348 4349 4350
	struct dsi_data *dsi;

	dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
	if (!dsi) {
		r = -ENOMEM;
		goto err0;
	}
T
Tomi Valkeinen 已提交
4351

4352 4353 4354
	dsi->pdev = dsidev;
	dsi_pdev_map[dsi_module] = dsidev;
	dev_set_drvdata(&dsidev->dev, dsi);
4355 4356

	dss_plat_data = dsidev->dev.platform_data;
4357
	board_info = dss_plat_data->board_data;
4358
	dsi->dsi_mux_pads = board_info->dsi_mux_pads;
4359

4360 4361 4362
	spin_lock_init(&dsi->irq_lock);
	spin_lock_init(&dsi->errors_lock);
	dsi->errors = 0;
T
Tomi Valkeinen 已提交
4363

4364
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
4365 4366
	spin_lock_init(&dsi->irq_stats_lock);
	dsi->irq_stats.last_reset = jiffies;
4367 4368
#endif

4369 4370
	mutex_init(&dsi->lock);
	sema_init(&dsi->bus_lock, 1);
T
Tomi Valkeinen 已提交
4371

4372 4373 4374 4375 4376
	dsi->workqueue = create_singlethread_workqueue(dev_name(&dsidev->dev));
	if (dsi->workqueue == NULL) {
		r = -ENOMEM;
		goto err1;
	}
4377

4378
	INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
4379 4380
			dsi_framedone_timeout_work_callback);

T
Tomi Valkeinen 已提交
4381
#ifdef DSI_CATCH_MISSING_TE
4382 4383 4384
	init_timer(&dsi->te_timer);
	dsi->te_timer.function = dsi_te_timeout;
	dsi->te_timer.data = 0;
T
Tomi Valkeinen 已提交
4385
#endif
4386
	dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
4387 4388 4389
	if (!dsi_mem) {
		DSSERR("can't get IORESOURCE_MEM DSI\n");
		r = -EINVAL;
4390
		goto err2;
4391
	}
4392 4393
	dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
	if (!dsi->base) {
T
Tomi Valkeinen 已提交
4394 4395
		DSSERR("can't ioremap DSI\n");
		r = -ENOMEM;
4396
		goto err2;
T
Tomi Valkeinen 已提交
4397
	}
4398 4399
	dsi->irq = platform_get_irq(dsi->pdev, 0);
	if (dsi->irq < 0) {
4400 4401
		DSSERR("platform_get_irq failed\n");
		r = -ENODEV;
4402
		goto err3;
4403 4404
	}

4405 4406
	r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
		dev_name(&dsidev->dev), dsi->pdev);
4407 4408
	if (r < 0) {
		DSSERR("request_irq failed\n");
4409
		goto err3;
4410
	}
T
Tomi Valkeinen 已提交
4411

4412
	/* DSI VCs initialization */
4413 4414 4415 4416
	for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
		dsi->vc[i].mode = DSI_VC_MODE_L4;
		dsi->vc[i].dssdev = NULL;
		dsi->vc[i].vc_id = 0;
4417 4418
	}

4419
	dsi_calc_clock_param_ranges(dsidev);
4420

T
Tomi Valkeinen 已提交
4421 4422
	enable_clocks(1);

4423 4424
	rev = dsi_read_reg(dsidev, DSI_REVISION);
	dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
T
Tomi Valkeinen 已提交
4425 4426 4427 4428 4429
	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));

	enable_clocks(0);

	return 0;
4430 4431
err3:
	iounmap(dsi->base);
4432
err2:
4433
	destroy_workqueue(dsi->workqueue);
T
Tomi Valkeinen 已提交
4434
err1:
4435 4436
	kfree(dsi);
err0:
T
Tomi Valkeinen 已提交
4437 4438 4439
	return r;
}

4440
static void dsi_exit(struct platform_device *dsidev)
T
Tomi Valkeinen 已提交
4441
{
4442 4443 4444 4445 4446 4447
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

	if (dsi->vdds_dsi_reg != NULL) {
		if (dsi->vdds_dsi_enabled) {
			regulator_disable(dsi->vdds_dsi_reg);
			dsi->vdds_dsi_enabled = false;
4448 4449
		}

4450 4451
		regulator_put(dsi->vdds_dsi_reg);
		dsi->vdds_dsi_reg = NULL;
4452 4453
	}

4454 4455
	free_irq(dsi->irq, dsi->pdev);
	iounmap(dsi->base);
T
Tomi Valkeinen 已提交
4456

4457 4458
	destroy_workqueue(dsi->workqueue);
	kfree(dsi);
4459

T
Tomi Valkeinen 已提交
4460 4461 4462
	DSSDBG("omap_dsi_exit\n");
}

4463
/* DSI1 HW IP initialisation */
4464
static int omap_dsi1hw_probe(struct platform_device *dsidev)
4465 4466
{
	int r;
4467

4468
	r = dsi_init(dsidev);
4469 4470 4471 4472 4473 4474 4475 4476
	if (r) {
		DSSERR("Failed to initialize DSI\n");
		goto err_dsi;
	}
err_dsi:
	return r;
}

4477
static int omap_dsi1hw_remove(struct platform_device *dsidev)
4478
{
4479 4480
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

4481
	dsi_exit(dsidev);
4482
	WARN_ON(dsi->scp_clk_refcount > 0);
4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503
	return 0;
}

static struct platform_driver omap_dsi1hw_driver = {
	.probe          = omap_dsi1hw_probe,
	.remove         = omap_dsi1hw_remove,
	.driver         = {
		.name   = "omapdss_dsi1",
		.owner  = THIS_MODULE,
	},
};

int dsi_init_platform_driver(void)
{
	return platform_driver_register(&omap_dsi1hw_driver);
}

void dsi_uninit_platform_driver(void)
{
	return platform_driver_unregister(&omap_dsi1hw_driver);
}