xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/omap2/omapfb/dss/dss.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * linux/drivers/video/omap2/dss/dss.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 Nokia Corporation
6*4882a593Smuzhiyun  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Some code and ideas taken from drivers/video/omap/ driver
9*4882a593Smuzhiyun  * by Imre Deak.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define DSS_SUBSYS_NAME "DSS"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/io.h>
17*4882a593Smuzhiyun #include <linux/export.h>
18*4882a593Smuzhiyun #include <linux/err.h>
19*4882a593Smuzhiyun #include <linux/delay.h>
20*4882a593Smuzhiyun #include <linux/seq_file.h>
21*4882a593Smuzhiyun #include <linux/clk.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/pm_runtime.h>
24*4882a593Smuzhiyun #include <linux/gfp.h>
25*4882a593Smuzhiyun #include <linux/sizes.h>
26*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
27*4882a593Smuzhiyun #include <linux/regmap.h>
28*4882a593Smuzhiyun #include <linux/of.h>
29*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
30*4882a593Smuzhiyun #include <linux/suspend.h>
31*4882a593Smuzhiyun #include <linux/component.h>
32*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include <video/omapfb_dss.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #include "dss.h"
37*4882a593Smuzhiyun #include "dss_features.h"
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define DSS_SZ_REGS			SZ_512
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun struct dss_reg {
42*4882a593Smuzhiyun 	u16 idx;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define DSS_REG(idx)			((const struct dss_reg) { idx })
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define DSS_REVISION			DSS_REG(0x0000)
48*4882a593Smuzhiyun #define DSS_SYSCONFIG			DSS_REG(0x0010)
49*4882a593Smuzhiyun #define DSS_SYSSTATUS			DSS_REG(0x0014)
50*4882a593Smuzhiyun #define DSS_CONTROL			DSS_REG(0x0040)
51*4882a593Smuzhiyun #define DSS_SDI_CONTROL			DSS_REG(0x0044)
52*4882a593Smuzhiyun #define DSS_PLL_CONTROL			DSS_REG(0x0048)
53*4882a593Smuzhiyun #define DSS_SDI_STATUS			DSS_REG(0x005C)
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define REG_GET(idx, start, end) \
56*4882a593Smuzhiyun 	FLD_GET(dss_read_reg(idx), start, end)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define REG_FLD_MOD(idx, val, start, end) \
59*4882a593Smuzhiyun 	dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun struct dss_features {
62*4882a593Smuzhiyun 	u8 fck_div_max;
63*4882a593Smuzhiyun 	u8 dss_fck_multiplier;
64*4882a593Smuzhiyun 	const char *parent_clk_name;
65*4882a593Smuzhiyun 	const enum omap_display_type *ports;
66*4882a593Smuzhiyun 	int num_ports;
67*4882a593Smuzhiyun 	int (*dpi_select_source)(int port, enum omap_channel channel);
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun static struct {
71*4882a593Smuzhiyun 	struct platform_device *pdev;
72*4882a593Smuzhiyun 	void __iomem    *base;
73*4882a593Smuzhiyun 	struct regmap	*syscon_pll_ctrl;
74*4882a593Smuzhiyun 	u32		syscon_pll_ctrl_offset;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	struct clk	*parent_clk;
77*4882a593Smuzhiyun 	struct clk	*dss_clk;
78*4882a593Smuzhiyun 	unsigned long	dss_clk_rate;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	unsigned long	cache_req_pck;
81*4882a593Smuzhiyun 	unsigned long	cache_prate;
82*4882a593Smuzhiyun 	struct dispc_clock_info cache_dispc_cinfo;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
85*4882a593Smuzhiyun 	enum omap_dss_clk_source dispc_clk_source;
86*4882a593Smuzhiyun 	enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	bool		ctx_valid;
89*4882a593Smuzhiyun 	u32		ctx[DSS_SZ_REGS / sizeof(u32)];
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	const struct dss_features *feat;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	struct dss_pll	*video1_pll;
94*4882a593Smuzhiyun 	struct dss_pll	*video2_pll;
95*4882a593Smuzhiyun } dss;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static const char * const dss_generic_clk_source_names[] = {
98*4882a593Smuzhiyun 	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]	= "DSI_PLL_HSDIV_DISPC",
99*4882a593Smuzhiyun 	[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]	= "DSI_PLL_HSDIV_DSI",
100*4882a593Smuzhiyun 	[OMAP_DSS_CLK_SRC_FCK]			= "DSS_FCK",
101*4882a593Smuzhiyun 	[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC]	= "DSI_PLL2_HSDIV_DISPC",
102*4882a593Smuzhiyun 	[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI]	= "DSI_PLL2_HSDIV_DSI",
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun static bool dss_initialized;
106*4882a593Smuzhiyun 
omapdss_is_initialized(void)107*4882a593Smuzhiyun bool omapdss_is_initialized(void)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	return dss_initialized;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_is_initialized);
112*4882a593Smuzhiyun 
dss_write_reg(const struct dss_reg idx,u32 val)113*4882a593Smuzhiyun static inline void dss_write_reg(const struct dss_reg idx, u32 val)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	__raw_writel(val, dss.base + idx.idx);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
dss_read_reg(const struct dss_reg idx)118*4882a593Smuzhiyun static inline u32 dss_read_reg(const struct dss_reg idx)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	return __raw_readl(dss.base + idx.idx);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun #define SR(reg) \
124*4882a593Smuzhiyun 	dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
125*4882a593Smuzhiyun #define RR(reg) \
126*4882a593Smuzhiyun 	dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
127*4882a593Smuzhiyun 
dss_save_context(void)128*4882a593Smuzhiyun static void dss_save_context(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	DSSDBG("dss_save_context\n");
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	SR(CONTROL);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
135*4882a593Smuzhiyun 			OMAP_DISPLAY_TYPE_SDI) {
136*4882a593Smuzhiyun 		SR(SDI_CONTROL);
137*4882a593Smuzhiyun 		SR(PLL_CONTROL);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	dss.ctx_valid = true;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	DSSDBG("context saved\n");
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
dss_restore_context(void)145*4882a593Smuzhiyun static void dss_restore_context(void)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	DSSDBG("dss_restore_context\n");
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (!dss.ctx_valid)
150*4882a593Smuzhiyun 		return;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	RR(CONTROL);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
155*4882a593Smuzhiyun 			OMAP_DISPLAY_TYPE_SDI) {
156*4882a593Smuzhiyun 		RR(SDI_CONTROL);
157*4882a593Smuzhiyun 		RR(PLL_CONTROL);
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	DSSDBG("context restored\n");
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun #undef SR
164*4882a593Smuzhiyun #undef RR
165*4882a593Smuzhiyun 
dss_ctrl_pll_enable(enum dss_pll_id pll_id,bool enable)166*4882a593Smuzhiyun void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	unsigned shift;
169*4882a593Smuzhiyun 	unsigned val;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (!dss.syscon_pll_ctrl)
172*4882a593Smuzhiyun 		return;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	val = !enable;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	switch (pll_id) {
177*4882a593Smuzhiyun 	case DSS_PLL_VIDEO1:
178*4882a593Smuzhiyun 		shift = 0;
179*4882a593Smuzhiyun 		break;
180*4882a593Smuzhiyun 	case DSS_PLL_VIDEO2:
181*4882a593Smuzhiyun 		shift = 1;
182*4882a593Smuzhiyun 		break;
183*4882a593Smuzhiyun 	case DSS_PLL_HDMI:
184*4882a593Smuzhiyun 		shift = 2;
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	default:
187*4882a593Smuzhiyun 		DSSERR("illegal DSS PLL ID %d\n", pll_id);
188*4882a593Smuzhiyun 		return;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
192*4882a593Smuzhiyun 		1 << shift, val << shift);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,enum omap_channel channel)195*4882a593Smuzhiyun void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
196*4882a593Smuzhiyun 	enum omap_channel channel)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	unsigned shift, val;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (!dss.syscon_pll_ctrl)
201*4882a593Smuzhiyun 		return;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	switch (channel) {
204*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD:
205*4882a593Smuzhiyun 		shift = 3;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		switch (pll_id) {
208*4882a593Smuzhiyun 		case DSS_PLL_VIDEO1:
209*4882a593Smuzhiyun 			val = 0; break;
210*4882a593Smuzhiyun 		case DSS_PLL_HDMI:
211*4882a593Smuzhiyun 			val = 1; break;
212*4882a593Smuzhiyun 		default:
213*4882a593Smuzhiyun 			DSSERR("error in PLL mux config for LCD\n");
214*4882a593Smuzhiyun 			return;
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 		break;
218*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD2:
219*4882a593Smuzhiyun 		shift = 5;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 		switch (pll_id) {
222*4882a593Smuzhiyun 		case DSS_PLL_VIDEO1:
223*4882a593Smuzhiyun 			val = 0; break;
224*4882a593Smuzhiyun 		case DSS_PLL_VIDEO2:
225*4882a593Smuzhiyun 			val = 1; break;
226*4882a593Smuzhiyun 		case DSS_PLL_HDMI:
227*4882a593Smuzhiyun 			val = 2; break;
228*4882a593Smuzhiyun 		default:
229*4882a593Smuzhiyun 			DSSERR("error in PLL mux config for LCD2\n");
230*4882a593Smuzhiyun 			return;
231*4882a593Smuzhiyun 		}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		break;
234*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD3:
235*4882a593Smuzhiyun 		shift = 7;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 		switch (pll_id) {
238*4882a593Smuzhiyun 		case DSS_PLL_VIDEO1:
239*4882a593Smuzhiyun 			val = 1; break;
240*4882a593Smuzhiyun 		case DSS_PLL_VIDEO2:
241*4882a593Smuzhiyun 			val = 0; break;
242*4882a593Smuzhiyun 		case DSS_PLL_HDMI:
243*4882a593Smuzhiyun 			val = 2; break;
244*4882a593Smuzhiyun 		default:
245*4882a593Smuzhiyun 			DSSERR("error in PLL mux config for LCD3\n");
246*4882a593Smuzhiyun 			return;
247*4882a593Smuzhiyun 		}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 	default:
251*4882a593Smuzhiyun 		DSSERR("error in PLL mux config\n");
252*4882a593Smuzhiyun 		return;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
256*4882a593Smuzhiyun 		0x3 << shift, val << shift);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
dss_sdi_init(int datapairs)259*4882a593Smuzhiyun void dss_sdi_init(int datapairs)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	u32 l;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	BUG_ON(datapairs > 3 || datapairs < 1);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	l = dss_read_reg(DSS_SDI_CONTROL);
266*4882a593Smuzhiyun 	l = FLD_MOD(l, 0xf, 19, 15);		/* SDI_PDIV */
267*4882a593Smuzhiyun 	l = FLD_MOD(l, datapairs-1, 3, 2);	/* SDI_PRSEL */
268*4882a593Smuzhiyun 	l = FLD_MOD(l, 2, 1, 0);		/* SDI_BWSEL */
269*4882a593Smuzhiyun 	dss_write_reg(DSS_SDI_CONTROL, l);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	l = dss_read_reg(DSS_PLL_CONTROL);
272*4882a593Smuzhiyun 	l = FLD_MOD(l, 0x7, 25, 22);	/* SDI_PLL_FREQSEL */
273*4882a593Smuzhiyun 	l = FLD_MOD(l, 0xb, 16, 11);	/* SDI_PLL_REGN */
274*4882a593Smuzhiyun 	l = FLD_MOD(l, 0xb4, 10, 1);	/* SDI_PLL_REGM */
275*4882a593Smuzhiyun 	dss_write_reg(DSS_PLL_CONTROL, l);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
dss_sdi_enable(void)278*4882a593Smuzhiyun int dss_sdi_enable(void)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	unsigned long timeout;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	dispc_pck_free_enable(1);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Reset SDI PLL */
285*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
286*4882a593Smuzhiyun 	udelay(1);	/* wait 2x PCLK */
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* Lock SDI PLL */
289*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* Waiting for PLL lock request to complete */
292*4882a593Smuzhiyun 	timeout = jiffies + msecs_to_jiffies(500);
293*4882a593Smuzhiyun 	while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
294*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
295*4882a593Smuzhiyun 			DSSERR("PLL lock request timed out\n");
296*4882a593Smuzhiyun 			goto err1;
297*4882a593Smuzhiyun 		}
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	/* Clearing PLL_GO bit */
301*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* Waiting for PLL to lock */
304*4882a593Smuzhiyun 	timeout = jiffies + msecs_to_jiffies(500);
305*4882a593Smuzhiyun 	while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
306*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
307*4882a593Smuzhiyun 			DSSERR("PLL lock timed out\n");
308*4882a593Smuzhiyun 			goto err1;
309*4882a593Smuzhiyun 		}
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	dispc_lcd_enable_signal(1);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* Waiting for SDI reset to complete */
315*4882a593Smuzhiyun 	timeout = jiffies + msecs_to_jiffies(500);
316*4882a593Smuzhiyun 	while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
317*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
318*4882a593Smuzhiyun 			DSSERR("SDI reset timed out\n");
319*4882a593Smuzhiyun 			goto err2;
320*4882a593Smuzhiyun 		}
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	return 0;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun  err2:
326*4882a593Smuzhiyun 	dispc_lcd_enable_signal(0);
327*4882a593Smuzhiyun  err1:
328*4882a593Smuzhiyun 	/* Reset SDI PLL */
329*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	dispc_pck_free_enable(0);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	return -ETIMEDOUT;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
dss_sdi_disable(void)336*4882a593Smuzhiyun void dss_sdi_disable(void)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	dispc_lcd_enable_signal(0);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	dispc_pck_free_enable(0);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	/* Reset SDI PLL */
343*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)346*4882a593Smuzhiyun const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	return dss_generic_clk_source_names[clk_src];
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
dss_dump_clocks(struct seq_file * s)351*4882a593Smuzhiyun void dss_dump_clocks(struct seq_file *s)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	const char *fclk_name, *fclk_real_name;
354*4882a593Smuzhiyun 	unsigned long fclk_rate;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (dss_runtime_get())
357*4882a593Smuzhiyun 		return;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	seq_printf(s, "- DSS -\n");
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
362*4882a593Smuzhiyun 	fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
363*4882a593Smuzhiyun 	fclk_rate = clk_get_rate(dss.dss_clk);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	seq_printf(s, "%s (%s) = %lu\n",
366*4882a593Smuzhiyun 			fclk_name, fclk_real_name,
367*4882a593Smuzhiyun 			fclk_rate);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	dss_runtime_put();
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
dss_dump_regs(struct seq_file * s)372*4882a593Smuzhiyun static void dss_dump_regs(struct seq_file *s)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (dss_runtime_get())
377*4882a593Smuzhiyun 		return;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	DUMPREG(DSS_REVISION);
380*4882a593Smuzhiyun 	DUMPREG(DSS_SYSCONFIG);
381*4882a593Smuzhiyun 	DUMPREG(DSS_SYSSTATUS);
382*4882a593Smuzhiyun 	DUMPREG(DSS_CONTROL);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
385*4882a593Smuzhiyun 			OMAP_DISPLAY_TYPE_SDI) {
386*4882a593Smuzhiyun 		DUMPREG(DSS_SDI_CONTROL);
387*4882a593Smuzhiyun 		DUMPREG(DSS_PLL_CONTROL);
388*4882a593Smuzhiyun 		DUMPREG(DSS_SDI_STATUS);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	dss_runtime_put();
392*4882a593Smuzhiyun #undef DUMPREG
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun 
dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)395*4882a593Smuzhiyun static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun 	int b;
398*4882a593Smuzhiyun 	u8 start, end;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	switch (clk_src) {
401*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_FCK:
402*4882a593Smuzhiyun 		b = 0;
403*4882a593Smuzhiyun 		break;
404*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
405*4882a593Smuzhiyun 		b = 1;
406*4882a593Smuzhiyun 		break;
407*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
408*4882a593Smuzhiyun 		b = 2;
409*4882a593Smuzhiyun 		break;
410*4882a593Smuzhiyun 	default:
411*4882a593Smuzhiyun 		BUG();
412*4882a593Smuzhiyun 		return;
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, b, start, end);	/* DISPC_CLK_SWITCH */
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	dss.dispc_clk_source = clk_src;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
dss_select_dsi_clk_source(int dsi_module,enum omap_dss_clk_source clk_src)422*4882a593Smuzhiyun void dss_select_dsi_clk_source(int dsi_module,
423*4882a593Smuzhiyun 		enum omap_dss_clk_source clk_src)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	int b, pos;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	switch (clk_src) {
428*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_FCK:
429*4882a593Smuzhiyun 		b = 0;
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
432*4882a593Smuzhiyun 		BUG_ON(dsi_module != 0);
433*4882a593Smuzhiyun 		b = 1;
434*4882a593Smuzhiyun 		break;
435*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
436*4882a593Smuzhiyun 		BUG_ON(dsi_module != 1);
437*4882a593Smuzhiyun 		b = 1;
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun 	default:
440*4882a593Smuzhiyun 		BUG();
441*4882a593Smuzhiyun 		return;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	pos = dsi_module == 0 ? 1 : 10;
445*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, b, pos, pos);	/* DSIx_CLK_SWITCH */
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	dss.dsi_clk_source[dsi_module] = clk_src;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
dss_select_lcd_clk_source(enum omap_channel channel,enum omap_dss_clk_source clk_src)450*4882a593Smuzhiyun void dss_select_lcd_clk_source(enum omap_channel channel,
451*4882a593Smuzhiyun 		enum omap_dss_clk_source clk_src)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	int b, ix, pos;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
456*4882a593Smuzhiyun 		dss_select_dispc_clk_source(clk_src);
457*4882a593Smuzhiyun 		return;
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	switch (clk_src) {
461*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_FCK:
462*4882a593Smuzhiyun 		b = 0;
463*4882a593Smuzhiyun 		break;
464*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
465*4882a593Smuzhiyun 		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
466*4882a593Smuzhiyun 		b = 1;
467*4882a593Smuzhiyun 		break;
468*4882a593Smuzhiyun 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
469*4882a593Smuzhiyun 		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
470*4882a593Smuzhiyun 		       channel != OMAP_DSS_CHANNEL_LCD3);
471*4882a593Smuzhiyun 		b = 1;
472*4882a593Smuzhiyun 		break;
473*4882a593Smuzhiyun 	default:
474*4882a593Smuzhiyun 		BUG();
475*4882a593Smuzhiyun 		return;
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
479*4882a593Smuzhiyun 	     (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
480*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, b, pos, pos);	/* LCDx_CLK_SWITCH */
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
483*4882a593Smuzhiyun 	    (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
484*4882a593Smuzhiyun 	dss.lcd_clk_source[ix] = clk_src;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
dss_get_dispc_clk_source(void)487*4882a593Smuzhiyun enum omap_dss_clk_source dss_get_dispc_clk_source(void)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun 	return dss.dispc_clk_source;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
dss_get_dsi_clk_source(int dsi_module)492*4882a593Smuzhiyun enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	return dss.dsi_clk_source[dsi_module];
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
dss_get_lcd_clk_source(enum omap_channel channel)497*4882a593Smuzhiyun enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
500*4882a593Smuzhiyun 		int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
501*4882a593Smuzhiyun 			(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
502*4882a593Smuzhiyun 		return dss.lcd_clk_source[ix];
503*4882a593Smuzhiyun 	} else {
504*4882a593Smuzhiyun 		/* LCD_CLK source is the same as DISPC_FCLK source for
505*4882a593Smuzhiyun 		 * OMAP2 and OMAP3 */
506*4882a593Smuzhiyun 		return dss.dispc_clk_source;
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
dss_div_calc(unsigned long pck,unsigned long fck_min,dss_div_calc_func func,void * data)510*4882a593Smuzhiyun bool dss_div_calc(unsigned long pck, unsigned long fck_min,
511*4882a593Smuzhiyun 		dss_div_calc_func func, void *data)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun 	int fckd, fckd_start, fckd_stop;
514*4882a593Smuzhiyun 	unsigned long fck;
515*4882a593Smuzhiyun 	unsigned long fck_hw_max;
516*4882a593Smuzhiyun 	unsigned long fckd_hw_max;
517*4882a593Smuzhiyun 	unsigned long prate;
518*4882a593Smuzhiyun 	unsigned m;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	if (dss.parent_clk == NULL) {
523*4882a593Smuzhiyun 		unsigned pckd;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 		pckd = fck_hw_max / pck;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 		fck = pck * pckd;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 		fck = clk_round_rate(dss.dss_clk, fck);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 		return func(fck, data);
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	fckd_hw_max = dss.feat->fck_div_max;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	m = dss.feat->dss_fck_multiplier;
537*4882a593Smuzhiyun 	prate = clk_get_rate(dss.parent_clk);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	fck_min = fck_min ? fck_min : 1;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	fckd_start = min(prate * m / fck_min, fckd_hw_max);
542*4882a593Smuzhiyun 	fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
545*4882a593Smuzhiyun 		fck = DIV_ROUND_UP(prate, fckd) * m;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 		if (func(fck, data))
548*4882a593Smuzhiyun 			return true;
549*4882a593Smuzhiyun 	}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	return false;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
dss_set_fck_rate(unsigned long rate)554*4882a593Smuzhiyun int dss_set_fck_rate(unsigned long rate)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	int r;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	DSSDBG("set fck to %lu\n", rate);
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	r = clk_set_rate(dss.dss_clk, rate);
561*4882a593Smuzhiyun 	if (r)
562*4882a593Smuzhiyun 		return r;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	WARN_ONCE(dss.dss_clk_rate != rate,
567*4882a593Smuzhiyun 			"clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
568*4882a593Smuzhiyun 			rate);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	return 0;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
dss_get_dispc_clk_rate(void)573*4882a593Smuzhiyun unsigned long dss_get_dispc_clk_rate(void)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	return dss.dss_clk_rate;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
dss_setup_default_clock(void)578*4882a593Smuzhiyun static int dss_setup_default_clock(void)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	unsigned long max_dss_fck, prate;
581*4882a593Smuzhiyun 	unsigned long fck;
582*4882a593Smuzhiyun 	unsigned fck_div;
583*4882a593Smuzhiyun 	int r;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if (dss.parent_clk == NULL) {
588*4882a593Smuzhiyun 		fck = clk_round_rate(dss.dss_clk, max_dss_fck);
589*4882a593Smuzhiyun 	} else {
590*4882a593Smuzhiyun 		prate = clk_get_rate(dss.parent_clk);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
593*4882a593Smuzhiyun 				max_dss_fck);
594*4882a593Smuzhiyun 		fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	r = dss_set_fck_rate(fck);
598*4882a593Smuzhiyun 	if (r)
599*4882a593Smuzhiyun 		return r;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return 0;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
dss_set_venc_output(enum omap_dss_venc_type type)604*4882a593Smuzhiyun void dss_set_venc_output(enum omap_dss_venc_type type)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	int l = 0;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
609*4882a593Smuzhiyun 		l = 0;
610*4882a593Smuzhiyun 	else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
611*4882a593Smuzhiyun 		l = 1;
612*4882a593Smuzhiyun 	else
613*4882a593Smuzhiyun 		BUG();
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	/* venc out selection. 0 = comp, 1 = svideo */
616*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
dss_set_dac_pwrdn_bgz(bool enable)619*4882a593Smuzhiyun void dss_set_dac_pwrdn_bgz(bool enable)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, enable, 5, 5);	/* DAC Power-Down Control */
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)624*4882a593Smuzhiyun void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun 	enum omap_display_type dp;
627*4882a593Smuzhiyun 	dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	/* Complain about invalid selections */
630*4882a593Smuzhiyun 	WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
631*4882a593Smuzhiyun 	WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	/* Select only if we have options */
634*4882a593Smuzhiyun 	if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
635*4882a593Smuzhiyun 		REG_FLD_MOD(DSS_CONTROL, src, 15, 15);	/* VENC_HDMI_SWITCH */
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun 
dss_get_hdmi_venc_clk_source(void)638*4882a593Smuzhiyun enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	enum omap_display_type displays;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
643*4882a593Smuzhiyun 	if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
644*4882a593Smuzhiyun 		return DSS_VENC_TV_CLK;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
647*4882a593Smuzhiyun 		return DSS_HDMI_M_PCLK;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	return REG_GET(DSS_CONTROL, 15, 15);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
dss_dpi_select_source_omap2_omap3(int port,enum omap_channel channel)652*4882a593Smuzhiyun static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	if (channel != OMAP_DSS_CHANNEL_LCD)
655*4882a593Smuzhiyun 		return -EINVAL;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
dss_dpi_select_source_omap4(int port,enum omap_channel channel)660*4882a593Smuzhiyun static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun 	int val;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	switch (channel) {
665*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD2:
666*4882a593Smuzhiyun 		val = 0;
667*4882a593Smuzhiyun 		break;
668*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_DIGIT:
669*4882a593Smuzhiyun 		val = 1;
670*4882a593Smuzhiyun 		break;
671*4882a593Smuzhiyun 	default:
672*4882a593Smuzhiyun 		return -EINVAL;
673*4882a593Smuzhiyun 	}
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	return 0;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun 
dss_dpi_select_source_omap5(int port,enum omap_channel channel)680*4882a593Smuzhiyun static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun 	int val;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	switch (channel) {
685*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD:
686*4882a593Smuzhiyun 		val = 1;
687*4882a593Smuzhiyun 		break;
688*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD2:
689*4882a593Smuzhiyun 		val = 2;
690*4882a593Smuzhiyun 		break;
691*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_LCD3:
692*4882a593Smuzhiyun 		val = 3;
693*4882a593Smuzhiyun 		break;
694*4882a593Smuzhiyun 	case OMAP_DSS_CHANNEL_DIGIT:
695*4882a593Smuzhiyun 		val = 0;
696*4882a593Smuzhiyun 		break;
697*4882a593Smuzhiyun 	default:
698*4882a593Smuzhiyun 		return -EINVAL;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	return 0;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
dss_dpi_select_source_dra7xx(int port,enum omap_channel channel)706*4882a593Smuzhiyun static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	switch (port) {
709*4882a593Smuzhiyun 	case 0:
710*4882a593Smuzhiyun 		return dss_dpi_select_source_omap5(port, channel);
711*4882a593Smuzhiyun 	case 1:
712*4882a593Smuzhiyun 		if (channel != OMAP_DSS_CHANNEL_LCD2)
713*4882a593Smuzhiyun 			return -EINVAL;
714*4882a593Smuzhiyun 		break;
715*4882a593Smuzhiyun 	case 2:
716*4882a593Smuzhiyun 		if (channel != OMAP_DSS_CHANNEL_LCD3)
717*4882a593Smuzhiyun 			return -EINVAL;
718*4882a593Smuzhiyun 		break;
719*4882a593Smuzhiyun 	default:
720*4882a593Smuzhiyun 		return -EINVAL;
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	return 0;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
dss_dpi_select_source(int port,enum omap_channel channel)726*4882a593Smuzhiyun int dss_dpi_select_source(int port, enum omap_channel channel)
727*4882a593Smuzhiyun {
728*4882a593Smuzhiyun 	return dss.feat->dpi_select_source(port, channel);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
dss_get_clocks(void)731*4882a593Smuzhiyun static int dss_get_clocks(void)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun 	struct clk *clk;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	clk = devm_clk_get(&dss.pdev->dev, "fck");
736*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
737*4882a593Smuzhiyun 		DSSERR("can't get clock fck\n");
738*4882a593Smuzhiyun 		return PTR_ERR(clk);
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	dss.dss_clk = clk;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (dss.feat->parent_clk_name) {
744*4882a593Smuzhiyun 		clk = clk_get(NULL, dss.feat->parent_clk_name);
745*4882a593Smuzhiyun 		if (IS_ERR(clk)) {
746*4882a593Smuzhiyun 			DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
747*4882a593Smuzhiyun 			return PTR_ERR(clk);
748*4882a593Smuzhiyun 		}
749*4882a593Smuzhiyun 	} else {
750*4882a593Smuzhiyun 		clk = NULL;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	dss.parent_clk = clk;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	return 0;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun 
dss_put_clocks(void)758*4882a593Smuzhiyun static void dss_put_clocks(void)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun 	if (dss.parent_clk)
761*4882a593Smuzhiyun 		clk_put(dss.parent_clk);
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun 
dss_runtime_get(void)764*4882a593Smuzhiyun int dss_runtime_get(void)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	int r;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	DSSDBG("dss_runtime_get\n");
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	r = pm_runtime_get_sync(&dss.pdev->dev);
771*4882a593Smuzhiyun 	if (WARN_ON(r < 0)) {
772*4882a593Smuzhiyun 		pm_runtime_put_sync(&dss.pdev->dev);
773*4882a593Smuzhiyun 		return r;
774*4882a593Smuzhiyun 	}
775*4882a593Smuzhiyun 	return 0;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
dss_runtime_put(void)778*4882a593Smuzhiyun void dss_runtime_put(void)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	int r;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	DSSDBG("dss_runtime_put\n");
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	r = pm_runtime_put_sync(&dss.pdev->dev);
785*4882a593Smuzhiyun 	WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun /* DEBUGFS */
789*4882a593Smuzhiyun #if defined(CONFIG_FB_OMAP2_DSS_DEBUGFS)
dss_debug_dump_clocks(struct seq_file * s)790*4882a593Smuzhiyun void dss_debug_dump_clocks(struct seq_file *s)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	dss_dump_clocks(s);
793*4882a593Smuzhiyun 	dispc_dump_clocks(s);
794*4882a593Smuzhiyun #ifdef CONFIG_FB_OMAP2_DSS_DSI
795*4882a593Smuzhiyun 	dsi_dump_clocks(s);
796*4882a593Smuzhiyun #endif
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun #endif
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun static const enum omap_display_type omap2plus_ports[] = {
802*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_DPI,
803*4882a593Smuzhiyun };
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun static const enum omap_display_type omap34xx_ports[] = {
806*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_DPI,
807*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_SDI,
808*4882a593Smuzhiyun };
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun static const enum omap_display_type dra7xx_ports[] = {
811*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_DPI,
812*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_DPI,
813*4882a593Smuzhiyun 	OMAP_DISPLAY_TYPE_DPI,
814*4882a593Smuzhiyun };
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun static const struct dss_features omap24xx_dss_feats = {
817*4882a593Smuzhiyun 	/*
818*4882a593Smuzhiyun 	 * fck div max is really 16, but the divider range has gaps. The range
819*4882a593Smuzhiyun 	 * from 1 to 6 has no gaps, so let's use that as a max.
820*4882a593Smuzhiyun 	 */
821*4882a593Smuzhiyun 	.fck_div_max		=	6,
822*4882a593Smuzhiyun 	.dss_fck_multiplier	=	2,
823*4882a593Smuzhiyun 	.parent_clk_name	=	"core_ck",
824*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
825*4882a593Smuzhiyun 	.ports			=	omap2plus_ports,
826*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
827*4882a593Smuzhiyun };
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun static const struct dss_features omap34xx_dss_feats = {
830*4882a593Smuzhiyun 	.fck_div_max		=	16,
831*4882a593Smuzhiyun 	.dss_fck_multiplier	=	2,
832*4882a593Smuzhiyun 	.parent_clk_name	=	"dpll4_ck",
833*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
834*4882a593Smuzhiyun 	.ports			=	omap34xx_ports,
835*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap34xx_ports),
836*4882a593Smuzhiyun };
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun static const struct dss_features omap3630_dss_feats = {
839*4882a593Smuzhiyun 	.fck_div_max		=	31,
840*4882a593Smuzhiyun 	.dss_fck_multiplier	=	1,
841*4882a593Smuzhiyun 	.parent_clk_name	=	"dpll4_ck",
842*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
843*4882a593Smuzhiyun 	.ports			=	omap2plus_ports,
844*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
845*4882a593Smuzhiyun };
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun static const struct dss_features omap44xx_dss_feats = {
848*4882a593Smuzhiyun 	.fck_div_max		=	32,
849*4882a593Smuzhiyun 	.dss_fck_multiplier	=	1,
850*4882a593Smuzhiyun 	.parent_clk_name	=	"dpll_per_x2_ck",
851*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap4,
852*4882a593Smuzhiyun 	.ports			=	omap2plus_ports,
853*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
854*4882a593Smuzhiyun };
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun static const struct dss_features omap54xx_dss_feats = {
857*4882a593Smuzhiyun 	.fck_div_max		=	64,
858*4882a593Smuzhiyun 	.dss_fck_multiplier	=	1,
859*4882a593Smuzhiyun 	.parent_clk_name	=	"dpll_per_x2_ck",
860*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap5,
861*4882a593Smuzhiyun 	.ports			=	omap2plus_ports,
862*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
863*4882a593Smuzhiyun };
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun static const struct dss_features am43xx_dss_feats = {
866*4882a593Smuzhiyun 	.fck_div_max		=	0,
867*4882a593Smuzhiyun 	.dss_fck_multiplier	=	0,
868*4882a593Smuzhiyun 	.parent_clk_name	=	NULL,
869*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
870*4882a593Smuzhiyun 	.ports			=	omap2plus_ports,
871*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
872*4882a593Smuzhiyun };
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun static const struct dss_features dra7xx_dss_feats = {
875*4882a593Smuzhiyun 	.fck_div_max		=	64,
876*4882a593Smuzhiyun 	.dss_fck_multiplier	=	1,
877*4882a593Smuzhiyun 	.parent_clk_name	=	"dpll_per_x2_ck",
878*4882a593Smuzhiyun 	.dpi_select_source	=	&dss_dpi_select_source_dra7xx,
879*4882a593Smuzhiyun 	.ports			=	dra7xx_ports,
880*4882a593Smuzhiyun 	.num_ports		=	ARRAY_SIZE(dra7xx_ports),
881*4882a593Smuzhiyun };
882*4882a593Smuzhiyun 
dss_get_features(void)883*4882a593Smuzhiyun static const struct dss_features *dss_get_features(void)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun 	switch (omapdss_get_version()) {
886*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP24xx:
887*4882a593Smuzhiyun 		return &omap24xx_dss_feats;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP34xx_ES1:
890*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP34xx_ES3:
891*4882a593Smuzhiyun 	case OMAPDSS_VER_AM35xx:
892*4882a593Smuzhiyun 		return &omap34xx_dss_feats;
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP3630:
895*4882a593Smuzhiyun 		return &omap3630_dss_feats;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP4430_ES1:
898*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP4430_ES2:
899*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP4:
900*4882a593Smuzhiyun 		return &omap44xx_dss_feats;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	case OMAPDSS_VER_OMAP5:
903*4882a593Smuzhiyun 		return &omap54xx_dss_feats;
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	case OMAPDSS_VER_AM43xx:
906*4882a593Smuzhiyun 		return &am43xx_dss_feats;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	case OMAPDSS_VER_DRA7xx:
909*4882a593Smuzhiyun 		return &dra7xx_dss_feats;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	default:
912*4882a593Smuzhiyun 		return NULL;
913*4882a593Smuzhiyun 	}
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun static void dss_uninit_ports(struct platform_device *pdev);
917*4882a593Smuzhiyun 
dss_init_ports(struct platform_device * pdev)918*4882a593Smuzhiyun static int dss_init_ports(struct platform_device *pdev)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun 	struct device_node *parent = pdev->dev.of_node;
921*4882a593Smuzhiyun 	struct device_node *port;
922*4882a593Smuzhiyun 	int r, ret = 0;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	if (parent == NULL)
925*4882a593Smuzhiyun 		return 0;
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	port = omapdss_of_get_next_port(parent, NULL);
928*4882a593Smuzhiyun 	if (!port)
929*4882a593Smuzhiyun 		return 0;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	if (dss.feat->num_ports == 0)
932*4882a593Smuzhiyun 		return 0;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	do {
935*4882a593Smuzhiyun 		enum omap_display_type port_type;
936*4882a593Smuzhiyun 		u32 reg;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		r = of_property_read_u32(port, "reg", &reg);
939*4882a593Smuzhiyun 		if (r)
940*4882a593Smuzhiyun 			reg = 0;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 		if (reg >= dss.feat->num_ports)
943*4882a593Smuzhiyun 			continue;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 		port_type = dss.feat->ports[reg];
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 		switch (port_type) {
948*4882a593Smuzhiyun 		case OMAP_DISPLAY_TYPE_DPI:
949*4882a593Smuzhiyun 			ret = dpi_init_port(pdev, port);
950*4882a593Smuzhiyun 			break;
951*4882a593Smuzhiyun 		case OMAP_DISPLAY_TYPE_SDI:
952*4882a593Smuzhiyun 			ret = sdi_init_port(pdev, port);
953*4882a593Smuzhiyun 			break;
954*4882a593Smuzhiyun 		default:
955*4882a593Smuzhiyun 			break;
956*4882a593Smuzhiyun 		}
957*4882a593Smuzhiyun 	} while (!ret &&
958*4882a593Smuzhiyun 		 (port = omapdss_of_get_next_port(parent, port)) != NULL);
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	if (ret)
961*4882a593Smuzhiyun 		dss_uninit_ports(pdev);
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	return ret;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun 
dss_uninit_ports(struct platform_device * pdev)966*4882a593Smuzhiyun static void dss_uninit_ports(struct platform_device *pdev)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun 	struct device_node *parent = pdev->dev.of_node;
969*4882a593Smuzhiyun 	struct device_node *port;
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	if (parent == NULL)
972*4882a593Smuzhiyun 		return;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	port = omapdss_of_get_next_port(parent, NULL);
975*4882a593Smuzhiyun 	if (!port)
976*4882a593Smuzhiyun 		return;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	if (dss.feat->num_ports == 0)
979*4882a593Smuzhiyun 		return;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	do {
982*4882a593Smuzhiyun 		enum omap_display_type port_type;
983*4882a593Smuzhiyun 		u32 reg;
984*4882a593Smuzhiyun 		int r;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 		r = of_property_read_u32(port, "reg", &reg);
987*4882a593Smuzhiyun 		if (r)
988*4882a593Smuzhiyun 			reg = 0;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 		if (reg >= dss.feat->num_ports)
991*4882a593Smuzhiyun 			continue;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 		port_type = dss.feat->ports[reg];
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 		switch (port_type) {
996*4882a593Smuzhiyun 		case OMAP_DISPLAY_TYPE_DPI:
997*4882a593Smuzhiyun 			dpi_uninit_port(port);
998*4882a593Smuzhiyun 			break;
999*4882a593Smuzhiyun 		case OMAP_DISPLAY_TYPE_SDI:
1000*4882a593Smuzhiyun 			sdi_uninit_port(port);
1001*4882a593Smuzhiyun 			break;
1002*4882a593Smuzhiyun 		default:
1003*4882a593Smuzhiyun 			break;
1004*4882a593Smuzhiyun 		}
1005*4882a593Smuzhiyun 	} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun 
dss_video_pll_probe(struct platform_device * pdev)1008*4882a593Smuzhiyun static int dss_video_pll_probe(struct platform_device *pdev)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
1011*4882a593Smuzhiyun 	struct regulator *pll_regulator;
1012*4882a593Smuzhiyun 	int r;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	if (!np)
1015*4882a593Smuzhiyun 		return 0;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	if (of_property_read_bool(np, "syscon-pll-ctrl")) {
1018*4882a593Smuzhiyun 		dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
1019*4882a593Smuzhiyun 			"syscon-pll-ctrl");
1020*4882a593Smuzhiyun 		if (IS_ERR(dss.syscon_pll_ctrl)) {
1021*4882a593Smuzhiyun 			dev_err(&pdev->dev,
1022*4882a593Smuzhiyun 				"failed to get syscon-pll-ctrl regmap\n");
1023*4882a593Smuzhiyun 			return PTR_ERR(dss.syscon_pll_ctrl);
1024*4882a593Smuzhiyun 		}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 		if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
1027*4882a593Smuzhiyun 				&dss.syscon_pll_ctrl_offset)) {
1028*4882a593Smuzhiyun 			dev_err(&pdev->dev,
1029*4882a593Smuzhiyun 				"failed to get syscon-pll-ctrl offset\n");
1030*4882a593Smuzhiyun 			return -EINVAL;
1031*4882a593Smuzhiyun 		}
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
1035*4882a593Smuzhiyun 	if (IS_ERR(pll_regulator)) {
1036*4882a593Smuzhiyun 		r = PTR_ERR(pll_regulator);
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		switch (r) {
1039*4882a593Smuzhiyun 		case -ENOENT:
1040*4882a593Smuzhiyun 			pll_regulator = NULL;
1041*4882a593Smuzhiyun 			break;
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 		case -EPROBE_DEFER:
1044*4882a593Smuzhiyun 			return -EPROBE_DEFER;
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 		default:
1047*4882a593Smuzhiyun 			DSSERR("can't get DPLL VDDA regulator\n");
1048*4882a593Smuzhiyun 			return r;
1049*4882a593Smuzhiyun 		}
1050*4882a593Smuzhiyun 	}
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
1053*4882a593Smuzhiyun 		dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
1054*4882a593Smuzhiyun 		if (IS_ERR(dss.video1_pll))
1055*4882a593Smuzhiyun 			return PTR_ERR(dss.video1_pll);
1056*4882a593Smuzhiyun 	}
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 	if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
1059*4882a593Smuzhiyun 		dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
1060*4882a593Smuzhiyun 		if (IS_ERR(dss.video2_pll)) {
1061*4882a593Smuzhiyun 			dss_video_pll_uninit(dss.video1_pll);
1062*4882a593Smuzhiyun 			return PTR_ERR(dss.video2_pll);
1063*4882a593Smuzhiyun 		}
1064*4882a593Smuzhiyun 	}
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	return 0;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun /* DSS HW IP initialisation */
dss_bind(struct device * dev)1070*4882a593Smuzhiyun static int dss_bind(struct device *dev)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
1073*4882a593Smuzhiyun 	struct resource *dss_mem;
1074*4882a593Smuzhiyun 	u32 rev;
1075*4882a593Smuzhiyun 	int r;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	dss.pdev = pdev;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	dss.feat = dss_get_features();
1080*4882a593Smuzhiyun 	if (!dss.feat)
1081*4882a593Smuzhiyun 		return -ENODEV;
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
1084*4882a593Smuzhiyun 	if (!dss_mem) {
1085*4882a593Smuzhiyun 		DSSERR("can't get IORESOURCE_MEM DSS\n");
1086*4882a593Smuzhiyun 		return -EINVAL;
1087*4882a593Smuzhiyun 	}
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
1090*4882a593Smuzhiyun 				resource_size(dss_mem));
1091*4882a593Smuzhiyun 	if (!dss.base) {
1092*4882a593Smuzhiyun 		DSSERR("can't ioremap DSS\n");
1093*4882a593Smuzhiyun 		return -ENOMEM;
1094*4882a593Smuzhiyun 	}
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	r = dss_get_clocks();
1097*4882a593Smuzhiyun 	if (r)
1098*4882a593Smuzhiyun 		return r;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	r = dss_setup_default_clock();
1101*4882a593Smuzhiyun 	if (r)
1102*4882a593Smuzhiyun 		goto err_setup_clocks;
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	r = dss_video_pll_probe(pdev);
1105*4882a593Smuzhiyun 	if (r)
1106*4882a593Smuzhiyun 		goto err_pll_init;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	r = dss_init_ports(pdev);
1109*4882a593Smuzhiyun 	if (r)
1110*4882a593Smuzhiyun 		goto err_init_ports;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	pm_runtime_enable(&pdev->dev);
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 	r = dss_runtime_get();
1115*4882a593Smuzhiyun 	if (r)
1116*4882a593Smuzhiyun 		goto err_runtime_get;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	/* Select DPLL */
1121*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun #ifdef CONFIG_FB_OMAP2_DSS_VENC
1126*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);	/* venc dac demen */
1127*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);	/* venc clock 4x enable */
1128*4882a593Smuzhiyun 	REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);	/* venc clock mode = normal */
1129*4882a593Smuzhiyun #endif
1130*4882a593Smuzhiyun 	dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
1131*4882a593Smuzhiyun 	dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
1132*4882a593Smuzhiyun 	dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
1133*4882a593Smuzhiyun 	dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
1134*4882a593Smuzhiyun 	dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	rev = dss_read_reg(DSS_REVISION);
1137*4882a593Smuzhiyun 	printk(KERN_INFO "OMAP DSS rev %d.%d\n",
1138*4882a593Smuzhiyun 			FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	dss_runtime_put();
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	r = component_bind_all(&pdev->dev, NULL);
1143*4882a593Smuzhiyun 	if (r)
1144*4882a593Smuzhiyun 		goto err_component;
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	dss_debugfs_create_file("dss", dss_dump_regs);
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 	pm_set_vt_switch(0);
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	dss_initialized = true;
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	return 0;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun err_component:
1155*4882a593Smuzhiyun err_runtime_get:
1156*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
1157*4882a593Smuzhiyun 	dss_uninit_ports(pdev);
1158*4882a593Smuzhiyun err_init_ports:
1159*4882a593Smuzhiyun 	if (dss.video1_pll)
1160*4882a593Smuzhiyun 		dss_video_pll_uninit(dss.video1_pll);
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	if (dss.video2_pll)
1163*4882a593Smuzhiyun 		dss_video_pll_uninit(dss.video2_pll);
1164*4882a593Smuzhiyun err_pll_init:
1165*4882a593Smuzhiyun err_setup_clocks:
1166*4882a593Smuzhiyun 	dss_put_clocks();
1167*4882a593Smuzhiyun 	return r;
1168*4882a593Smuzhiyun }
1169*4882a593Smuzhiyun 
dss_unbind(struct device * dev)1170*4882a593Smuzhiyun static void dss_unbind(struct device *dev)
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	dss_initialized = false;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	component_unbind_all(&pdev->dev, NULL);
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	if (dss.video1_pll)
1179*4882a593Smuzhiyun 		dss_video_pll_uninit(dss.video1_pll);
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 	if (dss.video2_pll)
1182*4882a593Smuzhiyun 		dss_video_pll_uninit(dss.video2_pll);
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	dss_uninit_ports(pdev);
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	dss_put_clocks();
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun static const struct component_master_ops dss_component_ops = {
1192*4882a593Smuzhiyun 	.bind = dss_bind,
1193*4882a593Smuzhiyun 	.unbind = dss_unbind,
1194*4882a593Smuzhiyun };
1195*4882a593Smuzhiyun 
dss_component_compare(struct device * dev,void * data)1196*4882a593Smuzhiyun static int dss_component_compare(struct device *dev, void *data)
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun 	struct device *child = data;
1199*4882a593Smuzhiyun 	return dev == child;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun 
dss_add_child_component(struct device * dev,void * data)1202*4882a593Smuzhiyun static int dss_add_child_component(struct device *dev, void *data)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun 	struct component_match **match = data;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	/*
1207*4882a593Smuzhiyun 	 * HACK
1208*4882a593Smuzhiyun 	 * We don't have a working driver for rfbi, so skip it here always.
1209*4882a593Smuzhiyun 	 * Otherwise dss will never get probed successfully, as it will wait
1210*4882a593Smuzhiyun 	 * for rfbi to get probed.
1211*4882a593Smuzhiyun 	 */
1212*4882a593Smuzhiyun 	if (strstr(dev_name(dev), "rfbi"))
1213*4882a593Smuzhiyun 		return 0;
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	component_match_add(dev->parent, match, dss_component_compare, dev);
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	return 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
dss_probe(struct platform_device * pdev)1220*4882a593Smuzhiyun static int dss_probe(struct platform_device *pdev)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	struct component_match *match = NULL;
1223*4882a593Smuzhiyun 	int r;
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	/* add all the child devices as components */
1226*4882a593Smuzhiyun 	device_for_each_child(&pdev->dev, &match, dss_add_child_component);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
1229*4882a593Smuzhiyun 	if (r)
1230*4882a593Smuzhiyun 		return r;
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	return 0;
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun 
dss_remove(struct platform_device * pdev)1235*4882a593Smuzhiyun static int dss_remove(struct platform_device *pdev)
1236*4882a593Smuzhiyun {
1237*4882a593Smuzhiyun 	component_master_del(&pdev->dev, &dss_component_ops);
1238*4882a593Smuzhiyun 	return 0;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun 
dss_runtime_suspend(struct device * dev)1241*4882a593Smuzhiyun static int dss_runtime_suspend(struct device *dev)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun 	dss_save_context();
1244*4882a593Smuzhiyun 	dss_set_min_bus_tput(dev, 0);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	pinctrl_pm_select_sleep_state(dev);
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 	return 0;
1249*4882a593Smuzhiyun }
1250*4882a593Smuzhiyun 
dss_runtime_resume(struct device * dev)1251*4882a593Smuzhiyun static int dss_runtime_resume(struct device *dev)
1252*4882a593Smuzhiyun {
1253*4882a593Smuzhiyun 	int r;
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	pinctrl_pm_select_default_state(dev);
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	/*
1258*4882a593Smuzhiyun 	 * Set an arbitrarily high tput request to ensure OPP100.
1259*4882a593Smuzhiyun 	 * What we should really do is to make a request to stay in OPP100,
1260*4882a593Smuzhiyun 	 * without any tput requirements, but that is not currently possible
1261*4882a593Smuzhiyun 	 * via the PM layer.
1262*4882a593Smuzhiyun 	 */
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	r = dss_set_min_bus_tput(dev, 1000000000);
1265*4882a593Smuzhiyun 	if (r)
1266*4882a593Smuzhiyun 		return r;
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	dss_restore_context();
1269*4882a593Smuzhiyun 	return 0;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun static const struct dev_pm_ops dss_pm_ops = {
1273*4882a593Smuzhiyun 	.runtime_suspend = dss_runtime_suspend,
1274*4882a593Smuzhiyun 	.runtime_resume = dss_runtime_resume,
1275*4882a593Smuzhiyun };
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun static const struct of_device_id dss_of_match[] = {
1278*4882a593Smuzhiyun 	{ .compatible = "ti,omap2-dss", },
1279*4882a593Smuzhiyun 	{ .compatible = "ti,omap3-dss", },
1280*4882a593Smuzhiyun 	{ .compatible = "ti,omap4-dss", },
1281*4882a593Smuzhiyun 	{ .compatible = "ti,omap5-dss", },
1282*4882a593Smuzhiyun 	{ .compatible = "ti,dra7-dss", },
1283*4882a593Smuzhiyun 	{},
1284*4882a593Smuzhiyun };
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, dss_of_match);
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun static struct platform_driver omap_dsshw_driver = {
1289*4882a593Smuzhiyun 	.probe		= dss_probe,
1290*4882a593Smuzhiyun 	.remove		= dss_remove,
1291*4882a593Smuzhiyun 	.driver         = {
1292*4882a593Smuzhiyun 		.name   = "omapdss_dss",
1293*4882a593Smuzhiyun 		.pm	= &dss_pm_ops,
1294*4882a593Smuzhiyun 		.of_match_table = dss_of_match,
1295*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
1296*4882a593Smuzhiyun 	},
1297*4882a593Smuzhiyun };
1298*4882a593Smuzhiyun 
dss_init_platform_driver(void)1299*4882a593Smuzhiyun int __init dss_init_platform_driver(void)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun 	return platform_driver_register(&omap_dsshw_driver);
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun 
dss_uninit_platform_driver(void)1304*4882a593Smuzhiyun void dss_uninit_platform_driver(void)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun 	platform_driver_unregister(&omap_dsshw_driver);
1307*4882a593Smuzhiyun }
1308