diff options
Diffstat (limited to 'drivers/video/omap2/dss/sdi.c')
-rw-r--r-- | drivers/video/omap2/dss/sdi.c | 228 |
1 files changed, 42 insertions, 186 deletions
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 62b5374ce43..3a688c871a4 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -23,9 +23,6 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/regulator/consumer.h> | 25 | #include <linux/regulator/consumer.h> |
26 | #include <linux/export.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/string.h> | ||
29 | 26 | ||
30 | #include <video/omapdss.h> | 27 | #include <video/omapdss.h> |
31 | #include "dss.h" | 28 | #include "dss.h" |
@@ -33,43 +30,31 @@ | |||
33 | static struct { | 30 | static struct { |
34 | bool update_enabled; | 31 | bool update_enabled; |
35 | struct regulator *vdds_sdi_reg; | 32 | struct regulator *vdds_sdi_reg; |
36 | |||
37 | struct dss_lcd_mgr_config mgr_config; | ||
38 | struct omap_video_timings timings; | ||
39 | int datapairs; | ||
40 | |||
41 | struct omap_dss_output output; | ||
42 | } sdi; | 33 | } sdi; |
43 | 34 | ||
44 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | 35 | static void sdi_basic_init(struct omap_dss_device *dssdev) |
45 | { | ||
46 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
47 | 36 | ||
48 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 37 | { |
49 | 38 | dispc_set_parallel_interface_mode(dssdev->manager->id, | |
50 | sdi.mgr_config.stallmode = false; | 39 | OMAP_DSS_PARALLELMODE_BYPASS); |
51 | sdi.mgr_config.fifohandcheck = false; | ||
52 | 40 | ||
53 | sdi.mgr_config.video_port_width = 24; | 41 | dispc_set_lcd_display_type(dssdev->manager->id, |
54 | sdi.mgr_config.lcden_sig_polarity = 1; | 42 | OMAP_DSS_LCD_DISPLAY_TFT); |
55 | 43 | ||
56 | dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); | 44 | dispc_set_tft_data_lines(dssdev->manager->id, 24); |
45 | dispc_lcd_enable_signal_polarity(1); | ||
57 | } | 46 | } |
58 | 47 | ||
59 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | 48 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) |
60 | { | 49 | { |
61 | struct omap_dss_output *out = dssdev->output; | 50 | struct omap_video_timings *t = &dssdev->panel.timings; |
62 | struct omap_video_timings *t = &sdi.timings; | ||
63 | struct dss_clock_info dss_cinfo; | 51 | struct dss_clock_info dss_cinfo; |
64 | struct dispc_clock_info dispc_cinfo; | 52 | struct dispc_clock_info dispc_cinfo; |
53 | u16 lck_div, pck_div; | ||
54 | unsigned long fck; | ||
65 | unsigned long pck; | 55 | unsigned long pck; |
66 | int r; | 56 | int r; |
67 | 57 | ||
68 | if (out == NULL || out->manager == NULL) { | ||
69 | DSSERR("failed to enable display: no output/manager\n"); | ||
70 | return -ENODEV; | ||
71 | } | ||
72 | |||
73 | r = omap_dss_start_device(dssdev); | 58 | r = omap_dss_start_device(dssdev); |
74 | if (r) { | 59 | if (r) { |
75 | DSSERR("failed to start device\n"); | 60 | DSSERR("failed to start device\n"); |
@@ -80,21 +65,32 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
80 | if (r) | 65 | if (r) |
81 | goto err_reg_enable; | 66 | goto err_reg_enable; |
82 | 67 | ||
68 | r = dss_runtime_get(); | ||
69 | if (r) | ||
70 | goto err_get_dss; | ||
71 | |||
83 | r = dispc_runtime_get(); | 72 | r = dispc_runtime_get(); |
84 | if (r) | 73 | if (r) |
85 | goto err_get_dispc; | 74 | goto err_get_dispc; |
86 | 75 | ||
76 | sdi_basic_init(dssdev); | ||
77 | |||
87 | /* 15.5.9.1.2 */ | 78 | /* 15.5.9.1.2 */ |
88 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 79 | dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; |
89 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 80 | |
81 | dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, | ||
82 | dssdev->panel.acbi, dssdev->panel.acb); | ||
90 | 83 | ||
91 | r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); | 84 | r = dss_calc_clock_div(1, t->pixel_clock * 1000, |
85 | &dss_cinfo, &dispc_cinfo); | ||
92 | if (r) | 86 | if (r) |
93 | goto err_calc_clock_div; | 87 | goto err_calc_clock_div; |
94 | 88 | ||
95 | sdi.mgr_config.clock_info = dispc_cinfo; | 89 | fck = dss_cinfo.fck; |
90 | lck_div = dispc_cinfo.lck_div; | ||
91 | pck_div = dispc_cinfo.pck_div; | ||
96 | 92 | ||
97 | pck = dss_cinfo.fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000; | 93 | pck = fck / lck_div / pck_div / 1000; |
98 | 94 | ||
99 | if (pck != t->pixel_clock) { | 95 | if (pck != t->pixel_clock) { |
100 | DSSWARN("Could not find exact pixel clock. Requested %d kHz, " | 96 | DSSWARN("Could not find exact pixel clock. Requested %d kHz, " |
@@ -105,46 +101,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
105 | } | 101 | } |
106 | 102 | ||
107 | 103 | ||
108 | dss_mgr_set_timings(out->manager, t); | 104 | dispc_set_lcd_timings(dssdev->manager->id, t); |
109 | 105 | ||
110 | r = dss_set_clock_div(&dss_cinfo); | 106 | r = dss_set_clock_div(&dss_cinfo); |
111 | if (r) | 107 | if (r) |
112 | goto err_set_dss_clock_div; | 108 | goto err_set_dss_clock_div; |
113 | 109 | ||
114 | sdi_config_lcd_manager(dssdev); | 110 | r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); |
115 | 111 | if (r) | |
116 | /* | 112 | goto err_set_dispc_clock_div; |
117 | * LCLK and PCLK divisors are located in shadow registers, and we | 113 | |
118 | * normally write them to DISPC registers when enabling the output. | 114 | dss_sdi_init(dssdev->phy.sdi.datapairs); |
119 | * However, SDI uses pck-free as source clock for its PLL, and pck-free | ||
120 | * is affected by the divisors. And as we need the PLL before enabling | ||
121 | * the output, we need to write the divisors early. | ||
122 | * | ||
123 | * It seems just writing to the DISPC register is enough, and we don't | ||
124 | * need to care about the shadow register mechanism for pck-free. The | ||
125 | * exact reason for this is unknown. | ||
126 | */ | ||
127 | dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); | ||
128 | |||
129 | dss_sdi_init(sdi.datapairs); | ||
130 | r = dss_sdi_enable(); | 115 | r = dss_sdi_enable(); |
131 | if (r) | 116 | if (r) |
132 | goto err_sdi_enable; | 117 | goto err_sdi_enable; |
133 | mdelay(2); | 118 | mdelay(2); |
134 | 119 | ||
135 | r = dss_mgr_enable(out->manager); | 120 | dssdev->manager->enable(dssdev->manager); |
136 | if (r) | ||
137 | goto err_mgr_enable; | ||
138 | 121 | ||
139 | return 0; | 122 | return 0; |
140 | 123 | ||
141 | err_mgr_enable: | ||
142 | dss_sdi_disable(); | ||
143 | err_sdi_enable: | 124 | err_sdi_enable: |
125 | err_set_dispc_clock_div: | ||
144 | err_set_dss_clock_div: | 126 | err_set_dss_clock_div: |
145 | err_calc_clock_div: | 127 | err_calc_clock_div: |
146 | dispc_runtime_put(); | 128 | dispc_runtime_put(); |
147 | err_get_dispc: | 129 | err_get_dispc: |
130 | dss_runtime_put(); | ||
131 | err_get_dss: | ||
148 | regulator_disable(sdi.vdds_sdi_reg); | 132 | regulator_disable(sdi.vdds_sdi_reg); |
149 | err_reg_enable: | 133 | err_reg_enable: |
150 | omap_dss_stop_device(dssdev); | 134 | omap_dss_stop_device(dssdev); |
@@ -155,13 +139,12 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); | |||
155 | 139 | ||
156 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 140 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
157 | { | 141 | { |
158 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 142 | dssdev->manager->disable(dssdev->manager); |
159 | |||
160 | dss_mgr_disable(mgr); | ||
161 | 143 | ||
162 | dss_sdi_disable(); | 144 | dss_sdi_disable(); |
163 | 145 | ||
164 | dispc_runtime_put(); | 146 | dispc_runtime_put(); |
147 | dss_runtime_put(); | ||
165 | 148 | ||
166 | regulator_disable(sdi.vdds_sdi_reg); | 149 | regulator_disable(sdi.vdds_sdi_reg); |
167 | 150 | ||
@@ -169,20 +152,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
169 | } | 152 | } |
170 | EXPORT_SYMBOL(omapdss_sdi_display_disable); | 153 | EXPORT_SYMBOL(omapdss_sdi_display_disable); |
171 | 154 | ||
172 | void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, | 155 | int sdi_init_display(struct omap_dss_device *dssdev) |
173 | struct omap_video_timings *timings) | ||
174 | { | ||
175 | sdi.timings = *timings; | ||
176 | } | ||
177 | EXPORT_SYMBOL(omapdss_sdi_set_timings); | ||
178 | |||
179 | void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) | ||
180 | { | ||
181 | sdi.datapairs = datapairs; | ||
182 | } | ||
183 | EXPORT_SYMBOL(omapdss_sdi_set_datapairs); | ||
184 | |||
185 | static int __init sdi_init_display(struct omap_dss_device *dssdev) | ||
186 | { | 156 | { |
187 | DSSDBG("SDI init\n"); | 157 | DSSDBG("SDI init\n"); |
188 | 158 | ||
@@ -202,125 +172,11 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) | |||
202 | return 0; | 172 | return 0; |
203 | } | 173 | } |
204 | 174 | ||
205 | static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) | 175 | int sdi_init(void) |
206 | { | ||
207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
208 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
209 | struct omap_dss_device *def_dssdev; | ||
210 | int i; | ||
211 | |||
212 | def_dssdev = NULL; | ||
213 | |||
214 | for (i = 0; i < pdata->num_devices; ++i) { | ||
215 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
216 | |||
217 | if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) | ||
218 | continue; | ||
219 | |||
220 | if (def_dssdev == NULL) | ||
221 | def_dssdev = dssdev; | ||
222 | |||
223 | if (def_disp_name != NULL && | ||
224 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
225 | def_dssdev = dssdev; | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return def_dssdev; | ||
231 | } | ||
232 | |||
233 | static void __init sdi_probe_pdata(struct platform_device *sdidev) | ||
234 | { | 176 | { |
235 | struct omap_dss_device *plat_dssdev; | ||
236 | struct omap_dss_device *dssdev; | ||
237 | int r; | ||
238 | |||
239 | plat_dssdev = sdi_find_dssdev(sdidev); | ||
240 | |||
241 | if (!plat_dssdev) | ||
242 | return; | ||
243 | |||
244 | dssdev = dss_alloc_and_init_device(&sdidev->dev); | ||
245 | if (!dssdev) | ||
246 | return; | ||
247 | |||
248 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
249 | |||
250 | r = sdi_init_display(dssdev); | ||
251 | if (r) { | ||
252 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
253 | dss_put_device(dssdev); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | r = omapdss_output_set_device(&sdi.output, dssdev); | ||
258 | if (r) { | ||
259 | DSSERR("failed to connect output to new device: %s\n", | ||
260 | dssdev->name); | ||
261 | dss_put_device(dssdev); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | r = dss_add_device(dssdev); | ||
266 | if (r) { | ||
267 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
268 | omapdss_output_unset_device(&sdi.output); | ||
269 | dss_put_device(dssdev); | ||
270 | return; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static void __init sdi_init_output(struct platform_device *pdev) | ||
275 | { | ||
276 | struct omap_dss_output *out = &sdi.output; | ||
277 | |||
278 | out->pdev = pdev; | ||
279 | out->id = OMAP_DSS_OUTPUT_SDI; | ||
280 | out->type = OMAP_DISPLAY_TYPE_SDI; | ||
281 | |||
282 | dss_register_output(out); | ||
283 | } | ||
284 | |||
285 | static void __exit sdi_uninit_output(struct platform_device *pdev) | ||
286 | { | ||
287 | struct omap_dss_output *out = &sdi.output; | ||
288 | |||
289 | dss_unregister_output(out); | ||
290 | } | ||
291 | |||
292 | static int __init omap_sdi_probe(struct platform_device *pdev) | ||
293 | { | ||
294 | sdi_init_output(pdev); | ||
295 | |||
296 | sdi_probe_pdata(pdev); | ||
297 | |||
298 | return 0; | 177 | return 0; |
299 | } | 178 | } |
300 | 179 | ||
301 | static int __exit omap_sdi_remove(struct platform_device *pdev) | 180 | void sdi_exit(void) |
302 | { | ||
303 | dss_unregister_child_devices(&pdev->dev); | ||
304 | |||
305 | sdi_uninit_output(pdev); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static struct platform_driver omap_sdi_driver = { | ||
311 | .remove = __exit_p(omap_sdi_remove), | ||
312 | .driver = { | ||
313 | .name = "omapdss_sdi", | ||
314 | .owner = THIS_MODULE, | ||
315 | }, | ||
316 | }; | ||
317 | |||
318 | int __init sdi_init_platform_driver(void) | ||
319 | { | ||
320 | return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe); | ||
321 | } | ||
322 | |||
323 | void __exit sdi_uninit_platform_driver(void) | ||
324 | { | 181 | { |
325 | platform_driver_unregister(&omap_sdi_driver); | ||
326 | } | 182 | } |