1 // SPDX-License-Identifier: GPL-2.0-only
3 * linux/drivers/video/omap2/dss/sdi.c
5 * Copyright (C) 2009 Nokia Corporation
6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
9 #define DSS_SUBSYS_NAME "SDI"
11 #include <linux/kernel.h>
12 #include <linux/delay.h>
13 #include <linux/err.h>
14 #include <linux/regulator/consumer.h>
15 #include <linux/export.h>
16 #include <linux/platform_device.h>
17 #include <linux/string.h>
19 #include <linux/of_graph.h>
20 #include <linux/component.h>
22 #include <video/omapfb_dss.h>
26 struct platform_device
*pdev
;
29 struct regulator
*vdds_sdi_reg
;
31 struct dss_lcd_mgr_config mgr_config
;
32 struct omap_video_timings timings
;
35 struct omap_dss_device output
;
37 bool port_initialized
;
40 struct sdi_clk_calc_ctx
{
41 unsigned long pck_min
, pck_max
;
44 struct dispc_clock_info dispc_cinfo
;
47 static bool dpi_calc_dispc_cb(int lckd
, int pckd
, unsigned long lck
,
48 unsigned long pck
, void *data
)
50 struct sdi_clk_calc_ctx
*ctx
= data
;
52 ctx
->dispc_cinfo
.lck_div
= lckd
;
53 ctx
->dispc_cinfo
.pck_div
= pckd
;
54 ctx
->dispc_cinfo
.lck
= lck
;
55 ctx
->dispc_cinfo
.pck
= pck
;
60 static bool dpi_calc_dss_cb(unsigned long fck
, void *data
)
62 struct sdi_clk_calc_ctx
*ctx
= data
;
66 return dispc_div_calc(fck
, ctx
->pck_min
, ctx
->pck_max
,
67 dpi_calc_dispc_cb
, ctx
);
70 static int sdi_calc_clock_div(unsigned long pclk
,
72 struct dispc_clock_info
*dispc_cinfo
)
75 struct sdi_clk_calc_ctx ctx
;
78 * DSS fclk gives us very few possibilities, so finding a good pixel
79 * clock may not be possible. We try multiple times to find the clock,
80 * each time widening the pixel clock range we look for, up to
84 for (i
= 0; i
< 10; ++i
) {
87 memset(&ctx
, 0, sizeof(ctx
));
88 if (pclk
> 1000 * i
* i
* i
)
89 ctx
.pck_min
= max(pclk
- 1000 * i
* i
* i
, 0lu);
92 ctx
.pck_max
= pclk
+ 1000 * i
* i
* i
;
94 ok
= dss_div_calc(pclk
, ctx
.pck_min
, dpi_calc_dss_cb
, &ctx
);
97 *dispc_cinfo
= ctx
.dispc_cinfo
;
105 static void sdi_config_lcd_manager(struct omap_dss_device
*dssdev
)
107 struct omap_overlay_manager
*mgr
= sdi
.output
.manager
;
109 sdi
.mgr_config
.io_pad_mode
= DSS_IO_PAD_MODE_BYPASS
;
111 sdi
.mgr_config
.stallmode
= false;
112 sdi
.mgr_config
.fifohandcheck
= false;
114 sdi
.mgr_config
.video_port_width
= 24;
115 sdi
.mgr_config
.lcden_sig_polarity
= 1;
117 dss_mgr_set_lcd_config(mgr
, &sdi
.mgr_config
);
120 static int sdi_display_enable(struct omap_dss_device
*dssdev
)
122 struct omap_dss_device
*out
= &sdi
.output
;
123 struct omap_video_timings
*t
= &sdi
.timings
;
125 struct dispc_clock_info dispc_cinfo
;
129 if (out
->manager
== NULL
) {
130 DSSERR("failed to enable display: no output/manager\n");
134 r
= regulator_enable(sdi
.vdds_sdi_reg
);
138 r
= dispc_runtime_get();
143 t
->data_pclk_edge
= OMAPDSS_DRIVE_SIG_RISING_EDGE
;
144 t
->sync_pclk_edge
= OMAPDSS_DRIVE_SIG_RISING_EDGE
;
146 r
= sdi_calc_clock_div(t
->pixelclock
, &fck
, &dispc_cinfo
);
148 goto err_calc_clock_div
;
150 sdi
.mgr_config
.clock_info
= dispc_cinfo
;
152 pck
= fck
/ dispc_cinfo
.lck_div
/ dispc_cinfo
.pck_div
;
154 if (pck
!= t
->pixelclock
) {
155 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
162 dss_mgr_set_timings(out
->manager
, t
);
164 r
= dss_set_fck_rate(fck
);
166 goto err_set_dss_clock_div
;
168 sdi_config_lcd_manager(dssdev
);
171 * LCLK and PCLK divisors are located in shadow registers, and we
172 * normally write them to DISPC registers when enabling the output.
173 * However, SDI uses pck-free as source clock for its PLL, and pck-free
174 * is affected by the divisors. And as we need the PLL before enabling
175 * the output, we need to write the divisors early.
177 * It seems just writing to the DISPC register is enough, and we don't
178 * need to care about the shadow register mechanism for pck-free. The
179 * exact reason for this is unknown.
181 dispc_mgr_set_clock_div(out
->manager
->id
, &sdi
.mgr_config
.clock_info
);
183 dss_sdi_init(sdi
.datapairs
);
184 r
= dss_sdi_enable();
189 r
= dss_mgr_enable(out
->manager
);
198 err_set_dss_clock_div
:
202 regulator_disable(sdi
.vdds_sdi_reg
);
207 static void sdi_display_disable(struct omap_dss_device
*dssdev
)
209 struct omap_overlay_manager
*mgr
= sdi
.output
.manager
;
211 dss_mgr_disable(mgr
);
217 regulator_disable(sdi
.vdds_sdi_reg
);
220 static void sdi_set_timings(struct omap_dss_device
*dssdev
,
221 struct omap_video_timings
*timings
)
223 sdi
.timings
= *timings
;
226 static void sdi_get_timings(struct omap_dss_device
*dssdev
,
227 struct omap_video_timings
*timings
)
229 *timings
= sdi
.timings
;
232 static int sdi_check_timings(struct omap_dss_device
*dssdev
,
233 struct omap_video_timings
*timings
)
235 struct omap_overlay_manager
*mgr
= sdi
.output
.manager
;
237 if (mgr
&& !dispc_mgr_timings_ok(mgr
->id
, timings
))
240 if (timings
->pixelclock
== 0)
246 static void sdi_set_datapairs(struct omap_dss_device
*dssdev
, int datapairs
)
248 sdi
.datapairs
= datapairs
;
251 static int sdi_init_regulator(void)
253 struct regulator
*vdds_sdi
;
255 if (sdi
.vdds_sdi_reg
)
258 vdds_sdi
= devm_regulator_get(&sdi
.pdev
->dev
, "vdds_sdi");
259 if (IS_ERR(vdds_sdi
)) {
260 if (PTR_ERR(vdds_sdi
) != -EPROBE_DEFER
)
261 DSSERR("can't get VDDS_SDI regulator\n");
262 return PTR_ERR(vdds_sdi
);
265 sdi
.vdds_sdi_reg
= vdds_sdi
;
270 static int sdi_connect(struct omap_dss_device
*dssdev
,
271 struct omap_dss_device
*dst
)
273 struct omap_overlay_manager
*mgr
;
276 r
= sdi_init_regulator();
280 mgr
= omap_dss_get_overlay_manager(dssdev
->dispc_channel
);
284 r
= dss_mgr_connect(mgr
, dssdev
);
288 r
= omapdss_output_set_device(dssdev
, dst
);
290 DSSERR("failed to connect output to new device: %s\n",
292 dss_mgr_disconnect(mgr
, dssdev
);
299 static void sdi_disconnect(struct omap_dss_device
*dssdev
,
300 struct omap_dss_device
*dst
)
302 WARN_ON(dst
!= dssdev
->dst
);
304 if (dst
!= dssdev
->dst
)
307 omapdss_output_unset_device(dssdev
);
310 dss_mgr_disconnect(dssdev
->manager
, dssdev
);
313 static const struct omapdss_sdi_ops sdi_ops
= {
314 .connect
= sdi_connect
,
315 .disconnect
= sdi_disconnect
,
317 .enable
= sdi_display_enable
,
318 .disable
= sdi_display_disable
,
320 .check_timings
= sdi_check_timings
,
321 .set_timings
= sdi_set_timings
,
322 .get_timings
= sdi_get_timings
,
324 .set_datapairs
= sdi_set_datapairs
,
327 static void sdi_init_output(struct platform_device
*pdev
)
329 struct omap_dss_device
*out
= &sdi
.output
;
331 out
->dev
= &pdev
->dev
;
332 out
->id
= OMAP_DSS_OUTPUT_SDI
;
333 out
->output_type
= OMAP_DISPLAY_TYPE_SDI
;
335 out
->dispc_channel
= OMAP_DSS_CHANNEL_LCD
;
336 /* We have SDI only on OMAP3, where it's on port 1 */
338 out
->ops
.sdi
= &sdi_ops
;
339 out
->owner
= THIS_MODULE
;
341 omapdss_register_output(out
);
344 static void sdi_uninit_output(struct platform_device
*pdev
)
346 struct omap_dss_device
*out
= &sdi
.output
;
348 omapdss_unregister_output(out
);
351 static int sdi_bind(struct device
*dev
, struct device
*master
, void *data
)
353 struct platform_device
*pdev
= to_platform_device(dev
);
357 sdi_init_output(pdev
);
362 static void sdi_unbind(struct device
*dev
, struct device
*master
, void *data
)
364 struct platform_device
*pdev
= to_platform_device(dev
);
366 sdi_uninit_output(pdev
);
369 static const struct component_ops sdi_component_ops
= {
371 .unbind
= sdi_unbind
,
374 static int sdi_probe(struct platform_device
*pdev
)
376 return component_add(&pdev
->dev
, &sdi_component_ops
);
379 static void sdi_remove(struct platform_device
*pdev
)
381 component_del(&pdev
->dev
, &sdi_component_ops
);
384 static struct platform_driver omap_sdi_driver
= {
386 .remove
= sdi_remove
,
388 .name
= "omapdss_sdi",
389 .suppress_bind_attrs
= true,
393 int __init
sdi_init_platform_driver(void)
395 return platform_driver_register(&omap_sdi_driver
);
398 void sdi_uninit_platform_driver(void)
400 platform_driver_unregister(&omap_sdi_driver
);
403 int sdi_init_port(struct platform_device
*pdev
, struct device_node
*port
)
405 struct device_node
*ep
;
409 ep
= of_graph_get_next_port_endpoint(port
, NULL
);
413 r
= of_property_read_u32(ep
, "datapairs", &datapairs
);
415 DSSERR("failed to parse datapairs\n");
419 sdi
.datapairs
= datapairs
;
425 sdi_init_output(pdev
);
427 sdi
.port_initialized
= true;
437 void sdi_uninit_port(struct device_node
*port
)
439 if (!sdi
.port_initialized
)
442 sdi_uninit_output(sdi
.pdev
);