1/*
2 * linux/drivers/video/omap2/dss/dss.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DSS"
24
25#include <linux/kernel.h>
26#include <linux/io.h>
27#include <linux/export.h>
28#include <linux/err.h>
29#include <linux/delay.h>
30#include <linux/seq_file.h>
31#include <linux/clk.h>
32#include <linux/platform_device.h>
33#include <linux/pm_runtime.h>
34
35#include <video/omapdss.h>
36
37#include <plat/cpu.h>
38#include <plat/clock.h>
39
40#include "dss.h"
41#include "dss_features.h"
42
43#define DSS_SZ_REGS			SZ_512
44
45struct dss_reg {
46	u16 idx;
47};
48
49#define DSS_REG(idx)			((const struct dss_reg) { idx })
50
51#define DSS_REVISION			DSS_REG(0x0000)
52#define DSS_SYSCONFIG			DSS_REG(0x0010)
53#define DSS_SYSSTATUS			DSS_REG(0x0014)
54#define DSS_CONTROL			DSS_REG(0x0040)
55#define DSS_SDI_CONTROL			DSS_REG(0x0044)
56#define DSS_PLL_CONTROL			DSS_REG(0x0048)
57#define DSS_SDI_STATUS			DSS_REG(0x005C)
58
59#define REG_GET(idx, start, end) \
60	FLD_GET(dss_read_reg(idx), start, end)
61
62#define REG_FLD_MOD(idx, val, start, end) \
63	dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
64
65static struct {
66	struct platform_device *pdev;
67	void __iomem    *base;
68
69	struct clk	*dpll4_m4_ck;
70	struct clk	*dss_clk;
71
72	unsigned long	cache_req_pck;
73	unsigned long	cache_prate;
74	struct dss_clock_info cache_dss_cinfo;
75	struct dispc_clock_info cache_dispc_cinfo;
76
77	enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
78	enum omap_dss_clk_source dispc_clk_source;
79	enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
80
81	bool		ctx_valid;
82	u32		ctx[DSS_SZ_REGS / sizeof(u32)];
83} dss;
84
85static const char * const dss_generic_clk_source_names[] = {
86	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI_PLL_HSDIV_DISPC",
87	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "DSI_PLL_HSDIV_DSI",
88	[OMAP_DSS_CLK_SRC_FCK]			= "DSS_FCK",
89};
90
91static inline void dss_write_reg(const struct dss_reg idx, u32 val)
92{
93	__raw_writel(val, dss.base + idx.idx);
94}
95
96static inline u32 dss_read_reg(const struct dss_reg idx)
97{
98	return __raw_readl(dss.base + idx.idx);
99}
100
101#define SR(reg) \
102	dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
103#define RR(reg) \
104	dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
105
106static void dss_save_context(void)
107{
108	DSSDBG("dss_save_context\n");
109
110	SR(CONTROL);
111
112	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
113			OMAP_DISPLAY_TYPE_SDI) {
114		SR(SDI_CONTROL);
115		SR(PLL_CONTROL);
116	}
117
118	dss.ctx_valid = true;
119
120	DSSDBG("context saved\n");
121}
122
123static void dss_restore_context(void)
124{
125	DSSDBG("dss_restore_context\n");
126
127	if (!dss.ctx_valid)
128		return;
129
130	RR(CONTROL);
131
132	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
133			OMAP_DISPLAY_TYPE_SDI) {
134		RR(SDI_CONTROL);
135		RR(PLL_CONTROL);
136	}
137
138	DSSDBG("context restored\n");
139}
140
141#undef SR
142#undef RR
143
144void dss_sdi_init(u8 datapairs)
145{
146	u32 l;
147
148	BUG_ON(datapairs > 3 || datapairs < 1);
149
150	l = dss_read_reg(DSS_SDI_CONTROL);
151	l = FLD_MOD(l, 0xf, 19, 15);		/* SDI_PDIV */
152	l = FLD_MOD(l, datapairs-1, 3, 2);	/* SDI_PRSEL */
153	l = FLD_MOD(l, 2, 1, 0);		/* SDI_BWSEL */
154	dss_write_reg(DSS_SDI_CONTROL, l);
155
156	l = dss_read_reg(DSS_PLL_CONTROL);
157	l = FLD_MOD(l, 0x7, 25, 22);	/* SDI_PLL_FREQSEL */
158	l = FLD_MOD(l, 0xb, 16, 11);	/* SDI_PLL_REGN */
159	l = FLD_MOD(l, 0xb4, 10, 1);	/* SDI_PLL_REGM */
160	dss_write_reg(DSS_PLL_CONTROL, l);
161}
162
163int dss_sdi_enable(void)
164{
165	unsigned long timeout;
166
167	dispc_pck_free_enable(1);
168
169	/* Reset SDI PLL */
170	REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
171	udelay(1);	/* wait 2x PCLK */
172
173	/* Lock SDI PLL */
174	REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
175
176	/* Waiting for PLL lock request to complete */
177	timeout = jiffies + msecs_to_jiffies(500);
178	while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
179		if (time_after_eq(jiffies, timeout)) {
180			DSSERR("PLL lock request timed out\n");
181			goto err1;
182		}
183	}
184
185	/* Clearing PLL_GO bit */
186	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
187
188	/* Waiting for PLL to lock */
189	timeout = jiffies + msecs_to_jiffies(500);
190	while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
191		if (time_after_eq(jiffies, timeout)) {
192			DSSERR("PLL lock timed out\n");
193			goto err1;
194		}
195	}
196
197	dispc_lcd_enable_signal(1);
198
199	/* Waiting for SDI reset to complete */
200	timeout = jiffies + msecs_to_jiffies(500);
201	while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
202		if (time_after_eq(jiffies, timeout)) {
203			DSSERR("SDI reset timed out\n");
204			goto err2;
205		}
206	}
207
208	return 0;
209
210 err2:
211	dispc_lcd_enable_signal(0);
212 err1:
213	/* Reset SDI PLL */
214	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
215
216	dispc_pck_free_enable(0);
217
218	return -ETIMEDOUT;
219}
220
221void dss_sdi_disable(void)
222{
223	dispc_lcd_enable_signal(0);
224
225	dispc_pck_free_enable(0);
226
227	/* Reset SDI PLL */
228	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
229}
230
231const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
232{
233	return dss_generic_clk_source_names[clk_src];
234}
235
236
237void dss_dump_clocks(struct seq_file *s)
238{
239	unsigned long dpll4_ck_rate;
240	unsigned long dpll4_m4_ck_rate;
241	const char *fclk_name, *fclk_real_name;
242	unsigned long fclk_rate;
243
244	if (dss_runtime_get())
245		return;
246
247	seq_printf(s, "- DSS -\n");
248
249	fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
250	fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
251	fclk_rate = clk_get_rate(dss.dss_clk);
252
253	if (dss.dpll4_m4_ck) {
254		dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
255		dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
256
257		seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
258
259		if (cpu_is_omap3630() || cpu_is_omap44xx())
260			seq_printf(s, "%s (%s) = %lu / %lu  = %lu\n",
261					fclk_name, fclk_real_name,
262					dpll4_ck_rate,
263					dpll4_ck_rate / dpll4_m4_ck_rate,
264					fclk_rate);
265		else
266			seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
267					fclk_name, fclk_real_name,
268					dpll4_ck_rate,
269					dpll4_ck_rate / dpll4_m4_ck_rate,
270					fclk_rate);
271	} else {
272		seq_printf(s, "%s (%s) = %lu\n",
273				fclk_name, fclk_real_name,
274				fclk_rate);
275	}
276
277	dss_runtime_put();
278}
279
280void dss_dump_regs(struct seq_file *s)
281{
282#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
283
284	if (dss_runtime_get())
285		return;
286
287	DUMPREG(DSS_REVISION);
288	DUMPREG(DSS_SYSCONFIG);
289	DUMPREG(DSS_SYSSTATUS);
290	DUMPREG(DSS_CONTROL);
291
292	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
293			OMAP_DISPLAY_TYPE_SDI) {
294		DUMPREG(DSS_SDI_CONTROL);
295		DUMPREG(DSS_PLL_CONTROL);
296		DUMPREG(DSS_SDI_STATUS);
297	}
298
299	dss_runtime_put();
300#undef DUMPREG
301}
302
303void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
304{
305	struct platform_device *dsidev;
306	int b;
307	u8 start, end;
308
309	switch (clk_src) {
310	case OMAP_DSS_CLK_SRC_FCK:
311		b = 0;
312		break;
313	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
314		b = 1;
315		dsidev = dsi_get_dsidev_from_id(0);
316		dsi_wait_pll_hsdiv_dispc_active(dsidev);
317		break;
318	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
319		b = 2;
320		dsidev = dsi_get_dsidev_from_id(1);
321		dsi_wait_pll_hsdiv_dispc_active(dsidev);
322		break;
323	default:
324		BUG();
325	}
326
327	dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
328
329	REG_FLD_MOD(DSS_CONTROL, b, start, end);	/* DISPC_CLK_SWITCH */
330
331	dss.dispc_clk_source = clk_src;
332}
333
334void dss_select_dsi_clk_source(int dsi_module,
335		enum omap_dss_clk_source clk_src)
336{
337	struct platform_device *dsidev;
338	int b;
339
340	switch (clk_src) {
341	case OMAP_DSS_CLK_SRC_FCK:
342		b = 0;
343		break;
344	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
345		BUG_ON(dsi_module != 0);
346		b = 1;
347		dsidev = dsi_get_dsidev_from_id(0);
348		dsi_wait_pll_hsdiv_dsi_active(dsidev);
349		break;
350	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
351		BUG_ON(dsi_module != 1);
352		b = 1;
353		dsidev = dsi_get_dsidev_from_id(1);
354		dsi_wait_pll_hsdiv_dsi_active(dsidev);
355		break;
356	default:
357		BUG();
358	}
359
360	REG_FLD_MOD(DSS_CONTROL, b, 1, 1);	/* DSI_CLK_SWITCH */
361
362	dss.dsi_clk_source[dsi_module] = clk_src;
363}
364
365void dss_select_lcd_clk_source(enum omap_channel channel,
366		enum omap_dss_clk_source clk_src)
367{
368	struct platform_device *dsidev;
369	int b, ix, pos;
370
371	if (!dss_has_feature(FEAT_LCD_CLK_SRC))
372		return;
373
374	switch (clk_src) {
375	case OMAP_DSS_CLK_SRC_FCK:
376		b = 0;
377		break;
378	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
379		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
380		b = 1;
381		dsidev = dsi_get_dsidev_from_id(0);
382		dsi_wait_pll_hsdiv_dispc_active(dsidev);
383		break;
384	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
385		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
386		b = 1;
387		dsidev = dsi_get_dsidev_from_id(1);
388		dsi_wait_pll_hsdiv_dispc_active(dsidev);
389		break;
390	default:
391		BUG();
392	}
393
394	pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
395	REG_FLD_MOD(DSS_CONTROL, b, pos, pos);	/* LCDx_CLK_SWITCH */
396
397	ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
398	dss.lcd_clk_source[ix] = clk_src;
399}
400
401enum omap_dss_clk_source dss_get_dispc_clk_source(void)
402{
403	return dss.dispc_clk_source;
404}
405
406enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
407{
408	return dss.dsi_clk_source[dsi_module];
409}
410
411enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
412{
413	if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
414		int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
415		return dss.lcd_clk_source[ix];
416	} else {
417		/* LCD_CLK source is the same as DISPC_FCLK source for
418		 * OMAP2 and OMAP3 */
419		return dss.dispc_clk_source;
420	}
421}
422
423/* calculate clock rates using dividers in cinfo */
424int dss_calc_clock_rates(struct dss_clock_info *cinfo)
425{
426	if (dss.dpll4_m4_ck) {
427		unsigned long prate;
428		u16 fck_div_max = 16;
429
430		if (cpu_is_omap3630() || cpu_is_omap44xx())
431			fck_div_max = 32;
432
433		if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
434			return -EINVAL;
435
436		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
437
438		cinfo->fck = prate / cinfo->fck_div;
439	} else {
440		if (cinfo->fck_div != 0)
441			return -EINVAL;
442		cinfo->fck = clk_get_rate(dss.dss_clk);
443	}
444
445	return 0;
446}
447
448int dss_set_clock_div(struct dss_clock_info *cinfo)
449{
450	if (dss.dpll4_m4_ck) {
451		unsigned long prate;
452		int r;
453
454		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
455		DSSDBG("dpll4_m4 = %ld\n", prate);
456
457		r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
458		if (r)
459			return r;
460	} else {
461		if (cinfo->fck_div != 0)
462			return -EINVAL;
463	}
464
465	DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
466
467	return 0;
468}
469
470int dss_get_clock_div(struct dss_clock_info *cinfo)
471{
472	cinfo->fck = clk_get_rate(dss.dss_clk);
473
474	if (dss.dpll4_m4_ck) {
475		unsigned long prate;
476
477		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
478
479		if (cpu_is_omap3630() || cpu_is_omap44xx())
480			cinfo->fck_div = prate / (cinfo->fck);
481		else
482			cinfo->fck_div = prate / (cinfo->fck / 2);
483	} else {
484		cinfo->fck_div = 0;
485	}
486
487	return 0;
488}
489
490unsigned long dss_get_dpll4_rate(void)
491{
492	if (dss.dpll4_m4_ck)
493		return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
494	else
495		return 0;
496}
497
498int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
499		struct dss_clock_info *dss_cinfo,
500		struct dispc_clock_info *dispc_cinfo)
501{
502	unsigned long prate;
503	struct dss_clock_info best_dss;
504	struct dispc_clock_info best_dispc;
505
506	unsigned long fck, max_dss_fck;
507
508	u16 fck_div, fck_div_max = 16;
509
510	int match = 0;
511	int min_fck_per_pck;
512
513	prate = dss_get_dpll4_rate();
514
515	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
516
517	fck = clk_get_rate(dss.dss_clk);
518	if (req_pck == dss.cache_req_pck &&
519			((cpu_is_omap34xx() && prate == dss.cache_prate) ||
520			 dss.cache_dss_cinfo.fck == fck)) {
521		DSSDBG("dispc clock info found from cache.\n");
522		*dss_cinfo = dss.cache_dss_cinfo;
523		*dispc_cinfo = dss.cache_dispc_cinfo;
524		return 0;
525	}
526
527	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
528
529	if (min_fck_per_pck &&
530		req_pck * min_fck_per_pck > max_dss_fck) {
531		DSSERR("Requested pixel clock not possible with the current "
532				"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
533				"the constraint off.\n");
534		min_fck_per_pck = 0;
535	}
536
537retry:
538	memset(&best_dss, 0, sizeof(best_dss));
539	memset(&best_dispc, 0, sizeof(best_dispc));
540
541	if (dss.dpll4_m4_ck == NULL) {
542		struct dispc_clock_info cur_dispc;
543		/* XXX can we change the clock on omap2? */
544		fck = clk_get_rate(dss.dss_clk);
545		fck_div = 1;
546
547		dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
548		match = 1;
549
550		best_dss.fck = fck;
551		best_dss.fck_div = fck_div;
552
553		best_dispc = cur_dispc;
554
555		goto found;
556	} else {
557		if (cpu_is_omap3630() || cpu_is_omap44xx())
558			fck_div_max = 32;
559
560		for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
561			struct dispc_clock_info cur_dispc;
562
563			if (fck_div_max == 32)
564				fck = prate / fck_div;
565			else
566				fck = prate / fck_div * 2;
567
568			if (fck > max_dss_fck)
569				continue;
570
571			if (min_fck_per_pck &&
572					fck < req_pck * min_fck_per_pck)
573				continue;
574
575			match = 1;
576
577			dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
578
579			if (abs(cur_dispc.pck - req_pck) <
580					abs(best_dispc.pck - req_pck)) {
581
582				best_dss.fck = fck;
583				best_dss.fck_div = fck_div;
584
585				best_dispc = cur_dispc;
586
587				if (cur_dispc.pck == req_pck)
588					goto found;
589			}
590		}
591	}
592
593found:
594	if (!match) {
595		if (min_fck_per_pck) {
596			DSSERR("Could not find suitable clock settings.\n"
597					"Turning FCK/PCK constraint off and"
598					"trying again.\n");
599			min_fck_per_pck = 0;
600			goto retry;
601		}
602
603		DSSERR("Could not find suitable clock settings.\n");
604
605		return -EINVAL;
606	}
607
608	if (dss_cinfo)
609		*dss_cinfo = best_dss;
610	if (dispc_cinfo)
611		*dispc_cinfo = best_dispc;
612
613	dss.cache_req_pck = req_pck;
614	dss.cache_prate = prate;
615	dss.cache_dss_cinfo = best_dss;
616	dss.cache_dispc_cinfo = best_dispc;
617
618	return 0;
619}
620
621void dss_set_venc_output(enum omap_dss_venc_type type)
622{
623	int l = 0;
624
625	if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
626		l = 0;
627	else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
628		l = 1;
629	else
630		BUG();
631
632	/* venc out selection. 0 = comp, 1 = svideo */
633	REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
634}
635
636void dss_set_dac_pwrdn_bgz(bool enable)
637{
638	REG_FLD_MOD(DSS_CONTROL, enable, 5, 5);	/* DAC Power-Down Control */
639}
640
641void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
642{
643	REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15);	/* VENC_HDMI_SWITCH */
644}
645
646enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
647{
648	enum omap_display_type displays;
649
650	displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
651	if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
652		return DSS_VENC_TV_CLK;
653
654	return REG_GET(DSS_CONTROL, 15, 15);
655}
656
657static int dss_get_clocks(void)
658{
659	struct clk *clk;
660	int r;
661
662	clk = clk_get(&dss.pdev->dev, "fck");
663	if (IS_ERR(clk)) {
664		DSSERR("can't get clock fck\n");
665		r = PTR_ERR(clk);
666		goto err;
667	}
668
669	dss.dss_clk = clk;
670
671	if (cpu_is_omap34xx()) {
672		clk = clk_get(NULL, "dpll4_m4_ck");
673		if (IS_ERR(clk)) {
674			DSSERR("Failed to get dpll4_m4_ck\n");
675			r = PTR_ERR(clk);
676			goto err;
677		}
678	} else if (cpu_is_omap44xx()) {
679		clk = clk_get(NULL, "dpll_per_m5x2_ck");
680		if (IS_ERR(clk)) {
681			DSSERR("Failed to get dpll_per_m5x2_ck\n");
682			r = PTR_ERR(clk);
683			goto err;
684		}
685	} else { /* omap24xx */
686		clk = NULL;
687	}
688
689	dss.dpll4_m4_ck = clk;
690
691	return 0;
692
693err:
694	if (dss.dss_clk)
695		clk_put(dss.dss_clk);
696	if (dss.dpll4_m4_ck)
697		clk_put(dss.dpll4_m4_ck);
698
699	return r;
700}
701
702static void dss_put_clocks(void)
703{
704	if (dss.dpll4_m4_ck)
705		clk_put(dss.dpll4_m4_ck);
706	clk_put(dss.dss_clk);
707}
708
709int dss_runtime_get(void)
710{
711	int r;
712
713	DSSDBG("dss_runtime_get\n");
714
715	r = pm_runtime_get_sync(&dss.pdev->dev);
716	WARN_ON(r < 0);
717	return r < 0 ? r : 0;
718}
719
720void dss_runtime_put(void)
721{
722	int r;
723
724	DSSDBG("dss_runtime_put\n");
725
726	r = pm_runtime_put_sync(&dss.pdev->dev);
727	WARN_ON(r < 0);
728}
729
730/* DEBUGFS */
731#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
732void dss_debug_dump_clocks(struct seq_file *s)
733{
734	dss_dump_clocks(s);
735	dispc_dump_clocks(s);
736#ifdef CONFIG_OMAP2_DSS_DSI
737	dsi_dump_clocks(s);
738#endif
739}
740#endif
741
742/* DSS HW IP initialisation */
743static int omap_dsshw_probe(struct platform_device *pdev)
744{
745	struct resource *dss_mem;
746	u32 rev;
747	int r;
748
749	dss.pdev = pdev;
750
751	dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
752	if (!dss_mem) {
753		DSSERR("can't get IORESOURCE_MEM DSS\n");
754		return -EINVAL;
755	}
756
757	dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
758				resource_size(dss_mem));
759	if (!dss.base) {
760		DSSERR("can't ioremap DSS\n");
761		return -ENOMEM;
762	}
763
764	r = dss_get_clocks();
765	if (r)
766		return r;
767
768	pm_runtime_enable(&pdev->dev);
769
770	r = dss_runtime_get();
771	if (r)
772		goto err_runtime_get;
773
774	/* Select DPLL */
775	REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
776
777#ifdef CONFIG_OMAP2_DSS_VENC
778	REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);	/* venc dac demen */
779	REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);	/* venc clock 4x enable */
780	REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);	/* venc clock mode = normal */
781#endif
782	dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
783	dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
784	dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
785	dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
786	dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
787
788	r = dpi_init();
789	if (r) {
790		DSSERR("Failed to initialize DPI\n");
791		goto err_dpi;
792	}
793
794	r = sdi_init();
795	if (r) {
796		DSSERR("Failed to initialize SDI\n");
797		goto err_sdi;
798	}
799
800	rev = dss_read_reg(DSS_REVISION);
801	printk(KERN_INFO "OMAP DSS rev %d.%d\n",
802			FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
803
804	dss_runtime_put();
805
806	return 0;
807err_sdi:
808	dpi_exit();
809err_dpi:
810	dss_runtime_put();
811err_runtime_get:
812	pm_runtime_disable(&pdev->dev);
813	dss_put_clocks();
814	return r;
815}
816
817static int omap_dsshw_remove(struct platform_device *pdev)
818{
819	dpi_exit();
820	sdi_exit();
821
822	pm_runtime_disable(&pdev->dev);
823
824	dss_put_clocks();
825
826	return 0;
827}
828
829static int dss_runtime_suspend(struct device *dev)
830{
831	dss_save_context();
832	return 0;
833}
834
835static int dss_runtime_resume(struct device *dev)
836{
837	dss_restore_context();
838	return 0;
839}
840
841static const struct dev_pm_ops dss_pm_ops = {
842	.runtime_suspend = dss_runtime_suspend,
843	.runtime_resume = dss_runtime_resume,
844};
845
846static struct platform_driver omap_dsshw_driver = {
847	.probe          = omap_dsshw_probe,
848	.remove         = omap_dsshw_remove,
849	.driver         = {
850		.name   = "omapdss_dss",
851		.owner  = THIS_MODULE,
852		.pm	= &dss_pm_ops,
853	},
854};
855
856int dss_init_platform_driver(void)
857{
858	return platform_driver_register(&omap_dsshw_driver);
859}
860
861void dss_uninit_platform_driver(void)
862{
863	return platform_driver_unregister(&omap_dsshw_driver);
864}
865