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", ®);
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", ®);
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