aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-14 18:11:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-14 18:11:19 -0500
commit51be08419dc86c72486ac556aa39bc01026a403d (patch)
tree50ac35ac89f207d2a732b67eb2f1e9b671e5c064 /drivers/video/omap2
parentec8013beddd717d1740cfefb1a9b900deef85462 (diff)
parentf787f32e67e00b072f46b2ae3c454d2c0a1fcdb7 (diff)
Merge branch 'fbdev-next' of git://github.com/schandinat/linux-2.6
* 'fbdev-next' of git://github.com/schandinat/linux-2.6: (175 commits) module_param: make bool parameters really bool (drivers/video/i810) Revert "atmel_lcdfb: Adjust HFP calculation so it matches the manual." OMAPDSS: HDMI: Disable DDC internal pull up OMAPDSS: HDMI: Move duplicate code from boardfile OMAPDSS: add OrtusTech COM43H4M10XTC display support OMAP: DSS2: Support for UMSH-8173MD TFT panel ASoC: OMAP: HDMI: Move HDMI codec trigger function to generic HDMI driver OMAPDSS: HDMI: Create function to enable HDMI audio ASoC: OMAP: HDMI: Correct signature of ASoC functions ASoC: OMAP: HDMI: Introduce driver data for audio codec grvga: fix section mismatch warnings video: s3c-fb: Don't keep device runtime active when open video: s3c-fb: Hold runtime PM references when touching registers video: s3c-fb: Take a runtime PM reference when unblanked video: s3c-fb: Disable runtime PM in error paths from probe video: s3c-fb: Use s3c_fb_enable() to enable the framebuffer video: s3c-fb: Make runtime PM functional again drivers/video: fsl-diu-fb: merge fsl_diu_alloc() into map_video_memory() drivers/video: fsl-diu-fb: add default platform ops functions drivers/video: fsl-diu-fb: remove broken reference count enabling the display ...
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/displays/Kconfig2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c1
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c66
-rw-r--r--drivers/video/omap2/displays/panel-n8x0.c1
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c62
-rw-r--r--drivers/video/omap2/displays/panel-taal.c38
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c1
-rw-r--r--drivers/video/omap2/dss/Makefile3
-rw-r--r--drivers/video/omap2/dss/apply.c1324
-rw-r--r--drivers/video/omap2/dss/core.c2
-rw-r--r--drivers/video/omap2/dss/dispc.c407
-rw-r--r--drivers/video/omap2/dss/dispc.h11
-rw-r--r--drivers/video/omap2/dss/dispc_coefs.c326
-rw-r--r--drivers/video/omap2/dss/dpi.c7
-rw-r--r--drivers/video/omap2/dss/dsi.c612
-rw-r--r--drivers/video/omap2/dss/dss.h74
-rw-r--r--drivers/video/omap2/dss/dss_features.c11
-rw-r--r--drivers/video/omap2/dss/dss_features.h1
-rw-r--r--drivers/video/omap2/dss/hdmi.c59
-rw-r--r--drivers/video/omap2/dss/manager.c1221
-rw-r--r--drivers/video/omap2/dss/overlay.c435
-rw-r--r--drivers/video/omap2/dss/rfbi.c1
-rw-r--r--drivers/video/omap2/dss/sdi.c8
-rw-r--r--drivers/video/omap2/dss/ti_hdmi.h10
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c37
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h3
-rw-r--r--drivers/video/omap2/dss/venc.c28
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c42
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c14
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c4
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h11
31 files changed, 2760 insertions, 2062 deletions
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 8d8e1fe1901c..74d29b552901 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B
41 41
42config PANEL_PICODLP 42config PANEL_PICODLP
43 tristate "TI PICO DLP mini-projector" 43 tristate "TI PICO DLP mini-projector"
44 depends on OMAP2_DSS && I2C 44 depends on OMAP2_DSS_DPI && I2C
45 help 45 help
46 A mini-projector used in TI's SDP4430 and EVM boards 46 A mini-projector used in TI's SDP4430 and EVM boards
47 For more info please visit http://www.dlp.com/projector/ 47 For more info please visit http://www.dlp.com/projector/
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index dbd59b8e5b36..51a87e149e24 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -803,7 +803,6 @@ static int acx565akm_spi_remove(struct spi_device *spi)
803static struct spi_driver acx565akm_spi_driver = { 803static struct spi_driver acx565akm_spi_driver = {
804 .driver = { 804 .driver = {
805 .name = "acx565akm", 805 .name = "acx565akm",
806 .bus = &spi_bus_type,
807 .owner = THIS_MODULE, 806 .owner = THIS_MODULE,
808 }, 807 },
809 .probe = acx565akm_spi_probe, 808 .probe = acx565akm_spi_probe,
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 519c47d2057f..28b9a6d61b0f 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = {
297 297
298 .name = "apollon", 298 .name = "apollon",
299 }, 299 },
300 /* FocalTech ETM070003DH6 */
301 {
302 {
303 .x_res = 800,
304 .y_res = 480,
305
306 .pixel_clock = 28000,
307
308 .hsw = 48,
309 .hfp = 40,
310 .hbp = 40,
311
312 .vsw = 3,
313 .vfp = 13,
314 .vbp = 29,
315 },
316 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
317 OMAP_DSS_LCD_IHS,
318 .name = "focaltech_etm070003dh6",
319 },
320
321 /* Microtips Technologies - UMSH-8173MD */
322 {
323 {
324 .x_res = 800,
325 .y_res = 480,
326
327 .pixel_clock = 34560,
328
329 .hsw = 13,
330 .hfp = 101,
331 .hbp = 101,
332
333 .vsw = 23,
334 .vfp = 1,
335 .vbp = 1,
336 },
337 .acbi = 0x0,
338 .acb = 0x0,
339 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
340 OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
341 .power_on_delay = 0,
342 .power_off_delay = 0,
343 .name = "microtips_umsh_8173md",
344 },
345
346 /* OrtusTech COM43H4M10XTC */
347 {
348 {
349 .x_res = 480,
350 .y_res = 272,
351
352 .pixel_clock = 8000,
353
354 .hsw = 41,
355 .hfp = 8,
356 .hbp = 4,
357
358 .vsw = 10,
359 .vfp = 4,
360 .vbp = 2,
361 },
362 .config = OMAP_DSS_LCD_TFT,
363
364 .name = "ortustech_com43h4m10xtc",
365 },
300}; 366};
301 367
302struct panel_drv_data { 368struct panel_drv_data {
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c
index 150e8bae35a1..dc9408dc93d1 100644
--- a/drivers/video/omap2/displays/panel-n8x0.c
+++ b/drivers/video/omap2/displays/panel-n8x0.c
@@ -708,7 +708,6 @@ static int mipid_spi_remove(struct spi_device *spi)
708static struct spi_driver mipid_spi_driver = { 708static struct spi_driver mipid_spi_driver = {
709 .driver = { 709 .driver = {
710 .name = "lcd_mipid", 710 .name = "lcd_mipid",
711 .bus = &spi_bus_type,
712 .owner = THIS_MODULE, 711 .owner = THIS_MODULE,
713 }, 712 },
714 .probe = mipid_spi_probe, 713 .probe = mipid_spi_probe,
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
index 2ba9d0ca187c..0eb31caddca8 100644
--- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
163 kfree(necd); 163 kfree(necd);
164} 164}
165 165
166static int nec_8048_panel_enable(struct omap_dss_device *dssdev) 166static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
167{ 167{
168 int r = 0; 168 int r;
169 struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); 169 struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
170 struct backlight_device *bl = necd->bl; 170 struct backlight_device *bl = necd->bl;
171 171
172 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
173 return 0;
174
175 r = omapdss_dpi_display_enable(dssdev);
176 if (r)
177 goto err0;
178
172 if (dssdev->platform_enable) { 179 if (dssdev->platform_enable) {
173 r = dssdev->platform_enable(dssdev); 180 r = dssdev->platform_enable(dssdev);
174 if (r) 181 if (r)
175 return r; 182 goto err1;
176 } 183 }
177 184
178 r = nec_8048_bl_update_status(bl); 185 r = nec_8048_bl_update_status(bl);
179 if (r < 0) 186 if (r < 0)
180 dev_err(&dssdev->dev, "failed to set lcd brightness\n"); 187 dev_err(&dssdev->dev, "failed to set lcd brightness\n");
181 188
182 r = omapdss_dpi_display_enable(dssdev); 189 return 0;
183 190err1:
191 omapdss_dpi_display_disable(dssdev);
192err0:
184 return r; 193 return r;
185} 194}
186 195
187static void nec_8048_panel_disable(struct omap_dss_device *dssdev) 196static void nec_8048_panel_power_off(struct omap_dss_device *dssdev)
188{ 197{
189 struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); 198 struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
190 struct backlight_device *bl = necd->bl; 199 struct backlight_device *bl = necd->bl;
191 200
192 omapdss_dpi_display_disable(dssdev); 201 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
202 return;
193 203
194 bl->props.brightness = 0; 204 bl->props.brightness = 0;
195 nec_8048_bl_update_status(bl); 205 nec_8048_bl_update_status(bl);
196 206
197 if (dssdev->platform_disable) 207 if (dssdev->platform_disable)
198 dssdev->platform_disable(dssdev); 208 dssdev->platform_disable(dssdev);
209
210 omapdss_dpi_display_disable(dssdev);
211}
212
213static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
214{
215 int r;
216
217 r = nec_8048_panel_power_on(dssdev);
218 if (r)
219 return r;
220
221 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
222
223 return 0;
224}
225
226static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
227{
228 nec_8048_panel_power_off(dssdev);
229
230 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
199} 231}
200 232
201static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) 233static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
202{ 234{
203 nec_8048_panel_disable(dssdev); 235 nec_8048_panel_power_off(dssdev);
236
237 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
238
204 return 0; 239 return 0;
205} 240}
206 241
207static int nec_8048_panel_resume(struct omap_dss_device *dssdev) 242static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
208{ 243{
209 return nec_8048_panel_enable(dssdev); 244 int r;
245
246 r = nec_8048_panel_power_on(dssdev);
247 if (r)
248 return r;
249
250 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
251
252 return 0;
210} 253}
211 254
212static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) 255static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
@@ -303,7 +346,6 @@ static struct spi_driver nec_8048_spi_driver = {
303 .resume = nec_8048_spi_resume, 346 .resume = nec_8048_spi_resume,
304 .driver = { 347 .driver = {
305 .name = "nec_8048_spi", 348 .name = "nec_8048_spi",
306 .bus = &spi_bus_type,
307 .owner = THIS_MODULE, 349 .owner = THIS_MODULE,
308 }, 350 },
309}; 351};
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 80c3f6ab1a94..00c5c615585f 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -198,12 +198,6 @@ struct taal_data {
198 bool te_enabled; 198 bool te_enabled;
199 199
200 atomic_t do_update; 200 atomic_t do_update;
201 struct {
202 u16 x;
203 u16 y;
204 u16 w;
205 u16 h;
206 } update_region;
207 int channel; 201 int channel;
208 202
209 struct delayed_work te_timeout_work; 203 struct delayed_work te_timeout_work;
@@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev)
1188 if (r) 1182 if (r)
1189 goto err; 1183 goto err;
1190 1184
1185 r = dsi_enable_video_output(dssdev, td->channel);
1186 if (r)
1187 goto err;
1188
1191 td->enabled = 1; 1189 td->enabled = 1;
1192 1190
1193 if (!td->intro_printed) { 1191 if (!td->intro_printed) {
@@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
1217 struct taal_data *td = dev_get_drvdata(&dssdev->dev); 1215 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
1218 int r; 1216 int r;
1219 1217
1218 dsi_disable_video_output(dssdev, td->channel);
1219
1220 r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); 1220 r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF);
1221 if (!r) 1221 if (!r)
1222 r = taal_sleep_in(td); 1222 r = taal_sleep_in(td);
@@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data)
1394 if (old) { 1394 if (old) {
1395 cancel_delayed_work(&td->te_timeout_work); 1395 cancel_delayed_work(&td->te_timeout_work);
1396 1396
1397 r = omap_dsi_update(dssdev, td->channel, 1397 r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb,
1398 td->update_region.x, 1398 dssdev);
1399 td->update_region.y,
1400 td->update_region.w,
1401 td->update_region.h,
1402 taal_framedone_cb, dssdev);
1403 if (r) 1399 if (r)
1404 goto err; 1400 goto err;
1405 } 1401 }
@@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev,
1444 goto err; 1440 goto err;
1445 } 1441 }
1446 1442
1447 r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); 1443 /* XXX no need to send this every frame, but dsi break if not done */
1448 if (r) 1444 r = taal_set_update_window(td, 0, 0,
1449 goto err; 1445 td->panel_config->timings.x_res,
1450 1446 td->panel_config->timings.y_res);
1451 r = taal_set_update_window(td, x, y, w, h);
1452 if (r) 1447 if (r)
1453 goto err; 1448 goto err;
1454 1449
1455 if (td->te_enabled && panel_data->use_ext_te) { 1450 if (td->te_enabled && panel_data->use_ext_te) {
1456 td->update_region.x = x;
1457 td->update_region.y = y;
1458 td->update_region.w = w;
1459 td->update_region.h = h;
1460 barrier();
1461 schedule_delayed_work(&td->te_timeout_work, 1451 schedule_delayed_work(&td->te_timeout_work,
1462 msecs_to_jiffies(250)); 1452 msecs_to_jiffies(250));
1463 atomic_set(&td->do_update, 1); 1453 atomic_set(&td->do_update, 1);
1464 } else { 1454 } else {
1465 r = omap_dsi_update(dssdev, td->channel, x, y, w, h, 1455 r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb,
1466 taal_framedone_cb, dssdev); 1456 dssdev);
1467 if (r) 1457 if (r)
1468 goto err; 1458 goto err;
1469 } 1459 }
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index 2462b9ec6662..e6649aa89591 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -512,7 +512,6 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
512static struct spi_driver tpo_td043_spi_driver = { 512static struct spi_driver tpo_td043_spi_driver = {
513 .driver = { 513 .driver = {
514 .name = "tpo_td043mtea1_panel_spi", 514 .name = "tpo_td043mtea1_panel_spi",
515 .bus = &spi_bus_type,
516 .owner = THIS_MODULE, 515 .owner = THIS_MODULE,
517 }, 516 },
518 .probe = tpo_td043_spi_probe, 517 .probe = tpo_td043_spi_probe,
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index bd34ac5b2026..5c450b0f94d0 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,6 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o 1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o 2omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
3 manager.o overlay.o apply.o
3omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o 4omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
4omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o 5omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
5omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o 6omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
new file mode 100644
index 000000000000..052dc874cd3d
--- /dev/null
+++ b/drivers/video/omap2/dss/apply.c
@@ -0,0 +1,1324 @@
1/*
2 * Copyright (C) 2011 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define DSS_SUBSYS_NAME "APPLY"
19
20#include <linux/kernel.h>
21#include <linux/slab.h>
22#include <linux/spinlock.h>
23#include <linux/jiffies.h>
24
25#include <video/omapdss.h>
26
27#include "dss.h"
28#include "dss_features.h"
29
30/*
31 * We have 4 levels of cache for the dispc settings. First two are in SW and
32 * the latter two in HW.
33 *
34 * set_info()
35 * v
36 * +--------------------+
37 * | user_info |
38 * +--------------------+
39 * v
40 * apply()
41 * v
42 * +--------------------+
43 * | info |
44 * +--------------------+
45 * v
46 * write_regs()
47 * v
48 * +--------------------+
49 * | shadow registers |
50 * +--------------------+
51 * v
52 * VFP or lcd/digit_enable
53 * v
54 * +--------------------+
55 * | registers |
56 * +--------------------+
57 */
58
59struct ovl_priv_data {
60
61 bool user_info_dirty;
62 struct omap_overlay_info user_info;
63
64 bool info_dirty;
65 struct omap_overlay_info info;
66
67 bool shadow_info_dirty;
68
69 bool extra_info_dirty;
70 bool shadow_extra_info_dirty;
71
72 bool enabled;
73 enum omap_channel channel;
74 u32 fifo_low, fifo_high;
75
76 /*
77 * True if overlay is to be enabled. Used to check and calculate configs
78 * for the overlay before it is enabled in the HW.
79 */
80 bool enabling;
81};
82
83struct mgr_priv_data {
84
85 bool user_info_dirty;
86 struct omap_overlay_manager_info user_info;
87
88 bool info_dirty;
89 struct omap_overlay_manager_info info;
90
91 bool shadow_info_dirty;
92
93 /* If true, GO bit is up and shadow registers cannot be written.
94 * Never true for manual update displays */
95 bool busy;
96
97 /* If true, dispc output is enabled */
98 bool updating;
99
100 /* If true, a display is enabled using this manager */
101 bool enabled;
102};
103
104static struct {
105 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
106 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
107
108 bool irq_enabled;
109} dss_data;
110
111/* protects dss_data */
112static spinlock_t data_lock;
113/* lock for blocking functions */
114static DEFINE_MUTEX(apply_lock);
115static DECLARE_COMPLETION(extra_updated_completion);
116
117static void dss_register_vsync_isr(void);
118
119static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
120{
121 return &dss_data.ovl_priv_data_array[ovl->id];
122}
123
124static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
125{
126 return &dss_data.mgr_priv_data_array[mgr->id];
127}
128
129void dss_apply_init(void)
130{
131 const int num_ovls = dss_feat_get_num_ovls();
132 int i;
133
134 spin_lock_init(&data_lock);
135
136 for (i = 0; i < num_ovls; ++i) {
137 struct ovl_priv_data *op;
138
139 op = &dss_data.ovl_priv_data_array[i];
140
141 op->info.global_alpha = 255;
142
143 switch (i) {
144 case 0:
145 op->info.zorder = 0;
146 break;
147 case 1:
148 op->info.zorder =
149 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
150 break;
151 case 2:
152 op->info.zorder =
153 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
154 break;
155 case 3:
156 op->info.zorder =
157 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
158 break;
159 }
160
161 op->user_info = op->info;
162 }
163}
164
165static bool ovl_manual_update(struct omap_overlay *ovl)
166{
167 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
168}
169
170static bool mgr_manual_update(struct omap_overlay_manager *mgr)
171{
172 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
173}
174
175static int dss_check_settings_low(struct omap_overlay_manager *mgr,
176 struct omap_dss_device *dssdev, bool applying)
177{
178 struct omap_overlay_info *oi;
179 struct omap_overlay_manager_info *mi;
180 struct omap_overlay *ovl;
181 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
182 struct ovl_priv_data *op;
183 struct mgr_priv_data *mp;
184
185 mp = get_mgr_priv(mgr);
186
187 if (applying && mp->user_info_dirty)
188 mi = &mp->user_info;
189 else
190 mi = &mp->info;
191
192 /* collect the infos to be tested into the array */
193 list_for_each_entry(ovl, &mgr->overlays, list) {
194 op = get_ovl_priv(ovl);
195
196 if (!op->enabled && !op->enabling)
197 oi = NULL;
198 else if (applying && op->user_info_dirty)
199 oi = &op->user_info;
200 else
201 oi = &op->info;
202
203 ois[ovl->id] = oi;
204 }
205
206 return dss_mgr_check(mgr, dssdev, mi, ois);
207}
208
209/*
210 * check manager and overlay settings using overlay_info from data->info
211 */
212static int dss_check_settings(struct omap_overlay_manager *mgr,
213 struct omap_dss_device *dssdev)
214{
215 return dss_check_settings_low(mgr, dssdev, false);
216}
217
218/*
219 * check manager and overlay settings using overlay_info from ovl->info if
220 * dirty and from data->info otherwise
221 */
222static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
223 struct omap_dss_device *dssdev)
224{
225 return dss_check_settings_low(mgr, dssdev, true);
226}
227
228static bool need_isr(void)
229{
230 const int num_mgrs = dss_feat_get_num_mgrs();
231 int i;
232
233 for (i = 0; i < num_mgrs; ++i) {
234 struct omap_overlay_manager *mgr;
235 struct mgr_priv_data *mp;
236 struct omap_overlay *ovl;
237
238 mgr = omap_dss_get_overlay_manager(i);
239 mp = get_mgr_priv(mgr);
240
241 if (!mp->enabled)
242 continue;
243
244 if (mgr_manual_update(mgr)) {
245 /* to catch FRAMEDONE */
246 if (mp->updating)
247 return true;
248 } else {
249 /* to catch GO bit going down */
250 if (mp->busy)
251 return true;
252
253 /* to write new values to registers */
254 if (mp->info_dirty)
255 return true;
256
257 /* to set GO bit */
258 if (mp->shadow_info_dirty)
259 return true;
260
261 list_for_each_entry(ovl, &mgr->overlays, list) {
262 struct ovl_priv_data *op;
263
264 op = get_ovl_priv(ovl);
265
266 /*
267 * NOTE: we check extra_info flags even for
268 * disabled overlays, as extra_infos need to be
269 * always written.
270 */
271
272 /* to write new values to registers */
273 if (op->extra_info_dirty)
274 return true;
275
276 /* to set GO bit */
277 if (op->shadow_extra_info_dirty)
278 return true;
279
280 if (!op->enabled)
281 continue;
282
283 /* to write new values to registers */
284 if (op->info_dirty)
285 return true;
286
287 /* to set GO bit */
288 if (op->shadow_info_dirty)
289 return true;
290 }
291 }
292 }
293
294 return false;
295}
296
297static bool need_go(struct omap_overlay_manager *mgr)
298{
299 struct omap_overlay *ovl;
300 struct mgr_priv_data *mp;
301 struct ovl_priv_data *op;
302
303 mp = get_mgr_priv(mgr);
304
305 if (mp->shadow_info_dirty)
306 return true;
307
308 list_for_each_entry(ovl, &mgr->overlays, list) {
309 op = get_ovl_priv(ovl);
310 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
311 return true;
312 }
313
314 return false;
315}
316
317/* returns true if an extra_info field is currently being updated */
318static bool extra_info_update_ongoing(void)
319{
320 const int num_ovls = omap_dss_get_num_overlays();
321 struct ovl_priv_data *op;
322 struct omap_overlay *ovl;
323 struct mgr_priv_data *mp;
324 int i;
325
326 for (i = 0; i < num_ovls; ++i) {
327 ovl = omap_dss_get_overlay(i);
328 op = get_ovl_priv(ovl);
329
330 if (!ovl->manager)
331 continue;
332
333 mp = get_mgr_priv(ovl->manager);
334
335 if (!mp->enabled)
336 continue;
337
338 if (!mp->updating)
339 continue;
340
341 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
342 return true;
343 }
344
345 return false;
346}
347
348/* wait until no extra_info updates are pending */
349static void wait_pending_extra_info_updates(void)
350{
351 bool updating;
352 unsigned long flags;
353 unsigned long t;
354
355 spin_lock_irqsave(&data_lock, flags);
356
357 updating = extra_info_update_ongoing();
358
359 if (!updating) {
360 spin_unlock_irqrestore(&data_lock, flags);
361 return;
362 }
363
364 init_completion(&extra_updated_completion);
365
366 spin_unlock_irqrestore(&data_lock, flags);
367
368 t = msecs_to_jiffies(500);
369 wait_for_completion_timeout(&extra_updated_completion, t);
370
371 updating = extra_info_update_ongoing();
372
373 WARN_ON(updating);
374}
375
376int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
377{
378 unsigned long timeout = msecs_to_jiffies(500);
379 struct mgr_priv_data *mp;
380 u32 irq;
381 int r;
382 int i;
383 struct omap_dss_device *dssdev = mgr->device;
384
385 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
386 return 0;
387
388 if (mgr_manual_update(mgr))
389 return 0;
390
391 irq = dispc_mgr_get_vsync_irq(mgr->id);
392
393 mp = get_mgr_priv(mgr);
394 i = 0;
395 while (1) {
396 unsigned long flags;
397 bool shadow_dirty, dirty;
398
399 spin_lock_irqsave(&data_lock, flags);
400 dirty = mp->info_dirty;
401 shadow_dirty = mp->shadow_info_dirty;
402 spin_unlock_irqrestore(&data_lock, flags);
403
404 if (!dirty && !shadow_dirty) {
405 r = 0;
406 break;
407 }
408
409 /* 4 iterations is the worst case:
410 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
411 * 2 - first VSYNC, dirty = true
412 * 3 - dirty = false, shadow_dirty = true
413 * 4 - shadow_dirty = false */
414 if (i++ == 3) {
415 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
416 mgr->id);
417 r = 0;
418 break;
419 }
420
421 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
422 if (r == -ERESTARTSYS)
423 break;
424
425 if (r) {
426 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
427 break;
428 }
429 }
430
431 return r;
432}
433
434int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
435{
436 unsigned long timeout = msecs_to_jiffies(500);
437 struct ovl_priv_data *op;
438 struct omap_dss_device *dssdev;
439 u32 irq;
440 int r;
441 int i;
442
443 if (!ovl->manager)
444 return 0;
445
446 dssdev = ovl->manager->device;
447
448 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
449 return 0;
450
451 if (ovl_manual_update(ovl))
452 return 0;
453
454 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
455
456 op = get_ovl_priv(ovl);
457 i = 0;
458 while (1) {
459 unsigned long flags;
460 bool shadow_dirty, dirty;
461
462 spin_lock_irqsave(&data_lock, flags);
463 dirty = op->info_dirty;
464 shadow_dirty = op->shadow_info_dirty;
465 spin_unlock_irqrestore(&data_lock, flags);
466
467 if (!dirty && !shadow_dirty) {
468 r = 0;
469 break;
470 }
471
472 /* 4 iterations is the worst case:
473 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
474 * 2 - first VSYNC, dirty = true
475 * 3 - dirty = false, shadow_dirty = true
476 * 4 - shadow_dirty = false */
477 if (i++ == 3) {
478 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
479 ovl->id);
480 r = 0;
481 break;
482 }
483
484 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
485 if (r == -ERESTARTSYS)
486 break;
487
488 if (r) {
489 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
490 break;
491 }
492 }
493
494 return r;
495}
496
497static void dss_ovl_write_regs(struct omap_overlay *ovl)
498{
499 struct ovl_priv_data *op = get_ovl_priv(ovl);
500 struct omap_overlay_info *oi;
501 bool ilace, replication;
502 struct mgr_priv_data *mp;
503 int r;
504
505 DSSDBGF("%d", ovl->id);
506
507 if (!op->enabled || !op->info_dirty)
508 return;
509
510 oi = &op->info;
511
512 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
513
514 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
515
516 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
517 if (r) {
518 /*
519 * We can't do much here, as this function can be called from
520 * vsync interrupt.
521 */
522 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
523
524 /* This will leave fifo configurations in a nonoptimal state */
525 op->enabled = false;
526 dispc_ovl_enable(ovl->id, false);
527 return;
528 }
529
530 mp = get_mgr_priv(ovl->manager);
531
532 op->info_dirty = false;
533 if (mp->updating)
534 op->shadow_info_dirty = true;
535}
536
537static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
538{
539 struct ovl_priv_data *op = get_ovl_priv(ovl);
540 struct mgr_priv_data *mp;
541
542 DSSDBGF("%d", ovl->id);
543
544 if (!op->extra_info_dirty)
545 return;
546
547 /* note: write also when op->enabled == false, so that the ovl gets
548 * disabled */
549
550 dispc_ovl_enable(ovl->id, op->enabled);
551 dispc_ovl_set_channel_out(ovl->id, op->channel);
552 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
553
554 mp = get_mgr_priv(ovl->manager);
555
556 op->extra_info_dirty = false;
557 if (mp->updating)
558 op->shadow_extra_info_dirty = true;
559}
560
561static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
562{
563 struct mgr_priv_data *mp = get_mgr_priv(mgr);
564 struct omap_overlay *ovl;
565
566 DSSDBGF("%d", mgr->id);
567
568 if (!mp->enabled)
569 return;
570
571 WARN_ON(mp->busy);
572
573 /* Commit overlay settings */
574 list_for_each_entry(ovl, &mgr->overlays, list) {
575 dss_ovl_write_regs(ovl);
576 dss_ovl_write_regs_extra(ovl);
577 }
578
579 if (mp->info_dirty) {
580 dispc_mgr_setup(mgr->id, &mp->info);
581
582 mp->info_dirty = false;
583 if (mp->updating)
584 mp->shadow_info_dirty = true;
585 }
586}
587
588static void dss_write_regs(void)
589{
590 const int num_mgrs = omap_dss_get_num_overlay_managers();
591 int i;
592
593 for (i = 0; i < num_mgrs; ++i) {
594 struct omap_overlay_manager *mgr;
595 struct mgr_priv_data *mp;
596 int r;
597
598 mgr = omap_dss_get_overlay_manager(i);
599 mp = get_mgr_priv(mgr);
600
601 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
602 continue;
603
604 r = dss_check_settings(mgr, mgr->device);
605 if (r) {
606 DSSERR("cannot write registers for manager %s: "
607 "illegal configuration\n", mgr->name);
608 continue;
609 }
610
611 dss_mgr_write_regs(mgr);
612 }
613}
614
615static void dss_set_go_bits(void)
616{
617 const int num_mgrs = omap_dss_get_num_overlay_managers();
618 int i;
619
620 for (i = 0; i < num_mgrs; ++i) {
621 struct omap_overlay_manager *mgr;
622 struct mgr_priv_data *mp;
623
624 mgr = omap_dss_get_overlay_manager(i);
625 mp = get_mgr_priv(mgr);
626
627 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
628 continue;
629
630 if (!need_go(mgr))
631 continue;
632
633 mp->busy = true;
634
635 if (!dss_data.irq_enabled && need_isr())
636 dss_register_vsync_isr();
637
638 dispc_mgr_go(mgr->id);
639 }
640
641}
642
643void dss_mgr_start_update(struct omap_overlay_manager *mgr)
644{
645 struct mgr_priv_data *mp = get_mgr_priv(mgr);
646 unsigned long flags;
647 int r;
648
649 spin_lock_irqsave(&data_lock, flags);
650
651 WARN_ON(mp->updating);
652
653 r = dss_check_settings(mgr, mgr->device);
654 if (r) {
655 DSSERR("cannot start manual update: illegal configuration\n");
656 spin_unlock_irqrestore(&data_lock, flags);
657 return;
658 }
659
660 dss_mgr_write_regs(mgr);
661
662 mp->updating = true;
663
664 if (!dss_data.irq_enabled && need_isr())
665 dss_register_vsync_isr();
666
667 dispc_mgr_enable(mgr->id, true);
668
669 spin_unlock_irqrestore(&data_lock, flags);
670}
671
672static void dss_apply_irq_handler(void *data, u32 mask);
673
674static void dss_register_vsync_isr(void)
675{
676 const int num_mgrs = dss_feat_get_num_mgrs();
677 u32 mask;
678 int r, i;
679
680 mask = 0;
681 for (i = 0; i < num_mgrs; ++i)
682 mask |= dispc_mgr_get_vsync_irq(i);
683
684 for (i = 0; i < num_mgrs; ++i)
685 mask |= dispc_mgr_get_framedone_irq(i);
686
687 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
688 WARN_ON(r);
689
690 dss_data.irq_enabled = true;
691}
692
693static void dss_unregister_vsync_isr(void)
694{
695 const int num_mgrs = dss_feat_get_num_mgrs();
696 u32 mask;
697 int r, i;
698
699 mask = 0;
700 for (i = 0; i < num_mgrs; ++i)
701 mask |= dispc_mgr_get_vsync_irq(i);
702
703 for (i = 0; i < num_mgrs; ++i)
704 mask |= dispc_mgr_get_framedone_irq(i);
705
706 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
707 WARN_ON(r);
708
709 dss_data.irq_enabled = false;
710}
711
712static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
713{
714 struct omap_overlay *ovl;
715 struct mgr_priv_data *mp;
716 struct ovl_priv_data *op;
717
718 mp = get_mgr_priv(mgr);
719 mp->shadow_info_dirty = false;
720
721 list_for_each_entry(ovl, &mgr->overlays, list) {
722 op = get_ovl_priv(ovl);
723 op->shadow_info_dirty = false;
724 op->shadow_extra_info_dirty = false;
725 }
726}
727
728static void dss_apply_irq_handler(void *data, u32 mask)
729{
730 const int num_mgrs = dss_feat_get_num_mgrs();
731 int i;
732 bool extra_updating;
733
734 spin_lock(&data_lock);
735
736 /* clear busy, updating flags, shadow_dirty flags */
737 for (i = 0; i < num_mgrs; i++) {
738 struct omap_overlay_manager *mgr;
739 struct mgr_priv_data *mp;
740 bool was_updating;
741
742 mgr = omap_dss_get_overlay_manager(i);
743 mp = get_mgr_priv(mgr);
744
745 if (!mp->enabled)
746 continue;
747
748 was_updating = mp->updating;
749 mp->updating = dispc_mgr_is_enabled(i);
750
751 if (!mgr_manual_update(mgr)) {
752 bool was_busy = mp->busy;
753 mp->busy = dispc_mgr_go_busy(i);
754
755 if (was_busy && !mp->busy)
756 mgr_clear_shadow_dirty(mgr);
757 } else {
758 if (was_updating && !mp->updating)
759 mgr_clear_shadow_dirty(mgr);
760 }
761 }
762
763 dss_write_regs();
764 dss_set_go_bits();
765
766 extra_updating = extra_info_update_ongoing();
767 if (!extra_updating)
768 complete_all(&extra_updated_completion);
769
770 if (!need_isr())
771 dss_unregister_vsync_isr();
772
773 spin_unlock(&data_lock);
774}
775
776static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
777{
778 struct ovl_priv_data *op;
779
780 op = get_ovl_priv(ovl);
781
782 if (!op->user_info_dirty)
783 return;
784
785 op->user_info_dirty = false;
786 op->info_dirty = true;
787 op->info = op->user_info;
788}
789
790static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
791{
792 struct mgr_priv_data *mp;
793
794 mp = get_mgr_priv(mgr);
795
796 if (!mp->user_info_dirty)
797 return;
798
799 mp->user_info_dirty = false;
800 mp->info_dirty = true;
801 mp->info = mp->user_info;
802}
803
804int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
805{
806 unsigned long flags;
807 struct omap_overlay *ovl;
808 int r;
809
810 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
811
812 spin_lock_irqsave(&data_lock, flags);
813
814 r = dss_check_settings_apply(mgr, mgr->device);
815 if (r) {
816 spin_unlock_irqrestore(&data_lock, flags);
817 DSSERR("failed to apply settings: illegal configuration.\n");
818 return r;
819 }
820
821 /* Configure overlays */
822 list_for_each_entry(ovl, &mgr->overlays, list)
823 omap_dss_mgr_apply_ovl(ovl);
824
825 /* Configure manager */
826 omap_dss_mgr_apply_mgr(mgr);
827
828 dss_write_regs();
829 dss_set_go_bits();
830
831 spin_unlock_irqrestore(&data_lock, flags);
832
833 return 0;
834}
835
836static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
837{
838 struct ovl_priv_data *op;
839
840 op = get_ovl_priv(ovl);
841
842 if (op->enabled == enable)
843 return;
844
845 op->enabled = enable;
846 op->extra_info_dirty = true;
847}
848
849static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
850 u32 fifo_low, u32 fifo_high)
851{
852 struct ovl_priv_data *op = get_ovl_priv(ovl);
853
854 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
855 return;
856
857 op->fifo_low = fifo_low;
858 op->fifo_high = fifo_high;
859 op->extra_info_dirty = true;
860}
861
862static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
863{
864 struct ovl_priv_data *op = get_ovl_priv(ovl);
865 struct omap_dss_device *dssdev;
866 u32 size, burst_size;
867 u32 fifo_low, fifo_high;
868
869 if (!op->enabled && !op->enabling)
870 return;
871
872 dssdev = ovl->manager->device;
873
874 size = dispc_ovl_get_fifo_size(ovl->id);
875
876 burst_size = dispc_ovl_get_burst_size(ovl->id);
877
878 switch (dssdev->type) {
879 case OMAP_DISPLAY_TYPE_DPI:
880 case OMAP_DISPLAY_TYPE_DBI:
881 case OMAP_DISPLAY_TYPE_SDI:
882 case OMAP_DISPLAY_TYPE_VENC:
883 case OMAP_DISPLAY_TYPE_HDMI:
884 default_get_overlay_fifo_thresholds(ovl->id, size,
885 burst_size, &fifo_low, &fifo_high);
886 break;
887#ifdef CONFIG_OMAP2_DSS_DSI
888 case OMAP_DISPLAY_TYPE_DSI:
889 dsi_get_overlay_fifo_thresholds(ovl->id, size,
890 burst_size, &fifo_low, &fifo_high);
891 break;
892#endif
893 default:
894 BUG();
895 }
896
897 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
898}
899
900static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
901{
902 struct omap_overlay *ovl;
903 struct mgr_priv_data *mp;
904
905 mp = get_mgr_priv(mgr);
906
907 if (!mp->enabled)
908 return;
909
910 list_for_each_entry(ovl, &mgr->overlays, list)
911 dss_ovl_setup_fifo(ovl);
912}
913
914static void dss_setup_fifos(void)
915{
916 const int num_mgrs = omap_dss_get_num_overlay_managers();
917 struct omap_overlay_manager *mgr;
918 int i;
919
920 for (i = 0; i < num_mgrs; ++i) {
921 mgr = omap_dss_get_overlay_manager(i);
922 dss_mgr_setup_fifos(mgr);
923 }
924}
925
926int dss_mgr_enable(struct omap_overlay_manager *mgr)
927{
928 struct mgr_priv_data *mp = get_mgr_priv(mgr);
929 unsigned long flags;
930 int r;
931
932 mutex_lock(&apply_lock);
933
934 if (mp->enabled)
935 goto out;
936
937 spin_lock_irqsave(&data_lock, flags);
938
939 mp->enabled = true;
940
941 r = dss_check_settings(mgr, mgr->device);
942 if (r) {
943 DSSERR("failed to enable manager %d: check_settings failed\n",
944 mgr->id);
945 goto err;
946 }
947
948 dss_setup_fifos();
949
950 dss_write_regs();
951 dss_set_go_bits();
952
953 if (!mgr_manual_update(mgr))
954 mp->updating = true;
955
956 spin_unlock_irqrestore(&data_lock, flags);
957
958 if (!mgr_manual_update(mgr))
959 dispc_mgr_enable(mgr->id, true);
960
961out:
962 mutex_unlock(&apply_lock);
963
964 return 0;
965
966err:
967 mp->enabled = false;
968 spin_unlock_irqrestore(&data_lock, flags);
969 mutex_unlock(&apply_lock);
970 return r;
971}
972
973void dss_mgr_disable(struct omap_overlay_manager *mgr)
974{
975 struct mgr_priv_data *mp = get_mgr_priv(mgr);
976 unsigned long flags;
977
978 mutex_lock(&apply_lock);
979
980 if (!mp->enabled)
981 goto out;
982
983 if (!mgr_manual_update(mgr))
984 dispc_mgr_enable(mgr->id, false);
985
986 spin_lock_irqsave(&data_lock, flags);
987
988 mp->updating = false;
989 mp->enabled = false;
990
991 spin_unlock_irqrestore(&data_lock, flags);
992
993out:
994 mutex_unlock(&apply_lock);
995}
996
997int dss_mgr_set_info(struct omap_overlay_manager *mgr,
998 struct omap_overlay_manager_info *info)
999{
1000 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1001 unsigned long flags;
1002 int r;
1003
1004 r = dss_mgr_simple_check(mgr, info);
1005 if (r)
1006 return r;
1007
1008 spin_lock_irqsave(&data_lock, flags);
1009
1010 mp->user_info = *info;
1011 mp->user_info_dirty = true;
1012
1013 spin_unlock_irqrestore(&data_lock, flags);
1014
1015 return 0;
1016}
1017
1018void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1019 struct omap_overlay_manager_info *info)
1020{
1021 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1022 unsigned long flags;
1023
1024 spin_lock_irqsave(&data_lock, flags);
1025
1026 *info = mp->user_info;
1027
1028 spin_unlock_irqrestore(&data_lock, flags);
1029}
1030
1031int dss_mgr_set_device(struct omap_overlay_manager *mgr,
1032 struct omap_dss_device *dssdev)
1033{
1034 int r;
1035
1036 mutex_lock(&apply_lock);
1037
1038 if (dssdev->manager) {
1039 DSSERR("display '%s' already has a manager '%s'\n",
1040 dssdev->name, dssdev->manager->name);
1041 r = -EINVAL;
1042 goto err;
1043 }
1044
1045 if ((mgr->supported_displays & dssdev->type) == 0) {
1046 DSSERR("display '%s' does not support manager '%s'\n",
1047 dssdev->name, mgr->name);
1048 r = -EINVAL;
1049 goto err;
1050 }
1051
1052 dssdev->manager = mgr;
1053 mgr->device = dssdev;
1054
1055 mutex_unlock(&apply_lock);
1056
1057 return 0;
1058err:
1059 mutex_unlock(&apply_lock);
1060 return r;
1061}
1062
1063int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
1064{
1065 int r;
1066
1067 mutex_lock(&apply_lock);
1068
1069 if (!mgr->device) {
1070 DSSERR("failed to unset display, display not set.\n");
1071 r = -EINVAL;
1072 goto err;
1073 }
1074
1075 /*
1076 * Don't allow currently enabled displays to have the overlay manager
1077 * pulled out from underneath them
1078 */
1079 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
1080 r = -EINVAL;
1081 goto err;
1082 }
1083
1084 mgr->device->manager = NULL;
1085 mgr->device = NULL;
1086
1087 mutex_unlock(&apply_lock);
1088
1089 return 0;
1090err:
1091 mutex_unlock(&apply_lock);
1092 return r;
1093}
1094
1095
1096int dss_ovl_set_info(struct omap_overlay *ovl,
1097 struct omap_overlay_info *info)
1098{
1099 struct ovl_priv_data *op = get_ovl_priv(ovl);
1100 unsigned long flags;
1101 int r;
1102
1103 r = dss_ovl_simple_check(ovl, info);
1104 if (r)
1105 return r;
1106
1107 spin_lock_irqsave(&data_lock, flags);
1108
1109 op->user_info = *info;
1110 op->user_info_dirty = true;
1111
1112 spin_unlock_irqrestore(&data_lock, flags);
1113
1114 return 0;
1115}
1116
1117void dss_ovl_get_info(struct omap_overlay *ovl,
1118 struct omap_overlay_info *info)
1119{
1120 struct ovl_priv_data *op = get_ovl_priv(ovl);
1121 unsigned long flags;
1122
1123 spin_lock_irqsave(&data_lock, flags);
1124
1125 *info = op->user_info;
1126
1127 spin_unlock_irqrestore(&data_lock, flags);
1128}
1129
1130int dss_ovl_set_manager(struct omap_overlay *ovl,
1131 struct omap_overlay_manager *mgr)
1132{
1133 struct ovl_priv_data *op = get_ovl_priv(ovl);
1134 unsigned long flags;
1135 int r;
1136
1137 if (!mgr)
1138 return -EINVAL;
1139
1140 mutex_lock(&apply_lock);
1141
1142 if (ovl->manager) {
1143 DSSERR("overlay '%s' already has a manager '%s'\n",
1144 ovl->name, ovl->manager->name);
1145 r = -EINVAL;
1146 goto err;
1147 }
1148
1149 spin_lock_irqsave(&data_lock, flags);
1150
1151 if (op->enabled) {
1152 spin_unlock_irqrestore(&data_lock, flags);
1153 DSSERR("overlay has to be disabled to change the manager\n");
1154 r = -EINVAL;
1155 goto err;
1156 }
1157
1158 op->channel = mgr->id;
1159 op->extra_info_dirty = true;
1160
1161 ovl->manager = mgr;
1162 list_add_tail(&ovl->list, &mgr->overlays);
1163
1164 spin_unlock_irqrestore(&data_lock, flags);
1165
1166 /* XXX: When there is an overlay on a DSI manual update display, and
1167 * the overlay is first disabled, then moved to tv, and enabled, we
1168 * seem to get SYNC_LOST_DIGIT error.
1169 *
1170 * Waiting doesn't seem to help, but updating the manual update display
1171 * after disabling the overlay seems to fix this. This hints that the
1172 * overlay is perhaps somehow tied to the LCD output until the output
1173 * is updated.
1174 *
1175 * Userspace workaround for this is to update the LCD after disabling
1176 * the overlay, but before moving the overlay to TV.
1177 */
1178
1179 mutex_unlock(&apply_lock);
1180
1181 return 0;
1182err:
1183 mutex_unlock(&apply_lock);
1184 return r;
1185}
1186
1187int dss_ovl_unset_manager(struct omap_overlay *ovl)
1188{
1189 struct ovl_priv_data *op = get_ovl_priv(ovl);
1190 unsigned long flags;
1191 int r;
1192
1193 mutex_lock(&apply_lock);
1194
1195 if (!ovl->manager) {
1196 DSSERR("failed to detach overlay: manager not set\n");
1197 r = -EINVAL;
1198 goto err;
1199 }
1200
1201 spin_lock_irqsave(&data_lock, flags);
1202
1203 if (op->enabled) {
1204 spin_unlock_irqrestore(&data_lock, flags);
1205 DSSERR("overlay has to be disabled to unset the manager\n");
1206 r = -EINVAL;
1207 goto err;
1208 }
1209
1210 op->channel = -1;
1211
1212 ovl->manager = NULL;
1213 list_del(&ovl->list);
1214
1215 spin_unlock_irqrestore(&data_lock, flags);
1216
1217 mutex_unlock(&apply_lock);
1218
1219 return 0;
1220err:
1221 mutex_unlock(&apply_lock);
1222 return r;
1223}
1224
1225bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1226{
1227 struct ovl_priv_data *op = get_ovl_priv(ovl);
1228 unsigned long flags;
1229 bool e;
1230
1231 spin_lock_irqsave(&data_lock, flags);
1232
1233 e = op->enabled;
1234
1235 spin_unlock_irqrestore(&data_lock, flags);
1236
1237 return e;
1238}
1239
1240int dss_ovl_enable(struct omap_overlay *ovl)
1241{
1242 struct ovl_priv_data *op = get_ovl_priv(ovl);
1243 unsigned long flags;
1244 int r;
1245
1246 mutex_lock(&apply_lock);
1247
1248 if (op->enabled) {
1249 r = 0;
1250 goto err1;
1251 }
1252
1253 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1254 r = -EINVAL;
1255 goto err1;
1256 }
1257
1258 spin_lock_irqsave(&data_lock, flags);
1259
1260 op->enabling = true;
1261
1262 r = dss_check_settings(ovl->manager, ovl->manager->device);
1263 if (r) {
1264 DSSERR("failed to enable overlay %d: check_settings failed\n",
1265 ovl->id);
1266 goto err2;
1267 }
1268
1269 dss_setup_fifos();
1270
1271 op->enabling = false;
1272 dss_apply_ovl_enable(ovl, true);
1273
1274 dss_write_regs();
1275 dss_set_go_bits();
1276
1277 spin_unlock_irqrestore(&data_lock, flags);
1278
1279 mutex_unlock(&apply_lock);
1280
1281 return 0;
1282err2:
1283 op->enabling = false;
1284 spin_unlock_irqrestore(&data_lock, flags);
1285err1:
1286 mutex_unlock(&apply_lock);
1287 return r;
1288}
1289
1290int dss_ovl_disable(struct omap_overlay *ovl)
1291{
1292 struct ovl_priv_data *op = get_ovl_priv(ovl);
1293 unsigned long flags;
1294 int r;
1295
1296 mutex_lock(&apply_lock);
1297
1298 if (!op->enabled) {
1299 r = 0;
1300 goto err;
1301 }
1302
1303 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1304 r = -EINVAL;
1305 goto err;
1306 }
1307
1308 spin_lock_irqsave(&data_lock, flags);
1309
1310 dss_apply_ovl_enable(ovl, false);
1311 dss_write_regs();
1312 dss_set_go_bits();
1313
1314 spin_unlock_irqrestore(&data_lock, flags);
1315
1316 mutex_unlock(&apply_lock);
1317
1318 return 0;
1319
1320err:
1321 mutex_unlock(&apply_lock);
1322 return r;
1323}
1324
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index da7b18576549..8613f86fb56d 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev)
178 178
179 dss_features_init(); 179 dss_features_init();
180 180
181 dss_apply_init();
182
181 dss_init_overlay_managers(pdev); 183 dss_init_overlay_managers(pdev);
182 dss_init_overlays(pdev); 184 dss_init_overlays(pdev);
183 185
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 5c81533eacaa..a5ec7f37c185 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -64,22 +64,6 @@ struct omap_dispc_isr_data {
64 u32 mask; 64 u32 mask;
65}; 65};
66 66
67struct dispc_h_coef {
68 s8 hc4;
69 s8 hc3;
70 u8 hc2;
71 s8 hc1;
72 s8 hc0;
73};
74
75struct dispc_v_coef {
76 s8 vc22;
77 s8 vc2;
78 u8 vc1;
79 s8 vc0;
80 s8 vc00;
81};
82
83enum omap_burst_size { 67enum omap_burst_size {
84 BURST_SIZE_X2 = 0, 68 BURST_SIZE_X2 = 0,
85 BURST_SIZE_X4 = 1, 69 BURST_SIZE_X4 = 1,
@@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel)
438 return mgr ? mgr->device : NULL; 422 return mgr ? mgr->device : NULL;
439} 423}
440 424
425u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
426{
427 switch (channel) {
428 case OMAP_DSS_CHANNEL_LCD:
429 return DISPC_IRQ_VSYNC;
430 case OMAP_DSS_CHANNEL_LCD2:
431 return DISPC_IRQ_VSYNC2;
432 case OMAP_DSS_CHANNEL_DIGIT:
433 return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
434 default:
435 BUG();
436 }
437}
438
439u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
440{
441 switch (channel) {
442 case OMAP_DSS_CHANNEL_LCD:
443 return DISPC_IRQ_FRAMEDONE;
444 case OMAP_DSS_CHANNEL_LCD2:
445 return DISPC_IRQ_FRAMEDONE2;
446 case OMAP_DSS_CHANNEL_DIGIT:
447 return 0;
448 default:
449 BUG();
450 }
451}
452
441bool dispc_mgr_go_busy(enum omap_channel channel) 453bool dispc_mgr_go_busy(enum omap_channel channel)
442{ 454{
443 int bit; 455 int bit;
@@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
533 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); 545 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
534} 546}
535 547
536static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, 548static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
537 int vscaleup, int five_taps, 549 int fir_vinc, int five_taps,
538 enum omap_color_component color_comp) 550 enum omap_color_component color_comp)
539{ 551{
540 /* Coefficients for horizontal up-sampling */ 552 const struct dispc_coef *h_coef, *v_coef;
541 static const struct dispc_h_coef coef_hup[8] = {
542 { 0, 0, 128, 0, 0 },
543 { -1, 13, 124, -8, 0 },
544 { -2, 30, 112, -11, -1 },
545 { -5, 51, 95, -11, -2 },
546 { 0, -9, 73, 73, -9 },
547 { -2, -11, 95, 51, -5 },
548 { -1, -11, 112, 30, -2 },
549 { 0, -8, 124, 13, -1 },
550 };
551
552 /* Coefficients for vertical up-sampling */
553 static const struct dispc_v_coef coef_vup_3tap[8] = {
554 { 0, 0, 128, 0, 0 },
555 { 0, 3, 123, 2, 0 },
556 { 0, 12, 111, 5, 0 },
557 { 0, 32, 89, 7, 0 },
558 { 0, 0, 64, 64, 0 },
559 { 0, 7, 89, 32, 0 },
560 { 0, 5, 111, 12, 0 },
561 { 0, 2, 123, 3, 0 },
562 };
563
564 static const struct dispc_v_coef coef_vup_5tap[8] = {
565 { 0, 0, 128, 0, 0 },
566 { -1, 13, 124, -8, 0 },
567 { -2, 30, 112, -11, -1 },
568 { -5, 51, 95, -11, -2 },
569 { 0, -9, 73, 73, -9 },
570 { -2, -11, 95, 51, -5 },
571 { -1, -11, 112, 30, -2 },
572 { 0, -8, 124, 13, -1 },
573 };
574
575 /* Coefficients for horizontal down-sampling */
576 static const struct dispc_h_coef coef_hdown[8] = {
577 { 0, 36, 56, 36, 0 },
578 { 4, 40, 55, 31, -2 },
579 { 8, 44, 54, 27, -5 },
580 { 12, 48, 53, 22, -7 },
581 { -9, 17, 52, 51, 17 },
582 { -7, 22, 53, 48, 12 },
583 { -5, 27, 54, 44, 8 },
584 { -2, 31, 55, 40, 4 },
585 };
586
587 /* Coefficients for vertical down-sampling */
588 static const struct dispc_v_coef coef_vdown_3tap[8] = {
589 { 0, 36, 56, 36, 0 },
590 { 0, 40, 57, 31, 0 },
591 { 0, 45, 56, 27, 0 },
592 { 0, 50, 55, 23, 0 },
593 { 0, 18, 55, 55, 0 },
594 { 0, 23, 55, 50, 0 },
595 { 0, 27, 56, 45, 0 },
596 { 0, 31, 57, 40, 0 },
597 };
598
599 static const struct dispc_v_coef coef_vdown_5tap[8] = {
600 { 0, 36, 56, 36, 0 },
601 { 4, 40, 55, 31, -2 },
602 { 8, 44, 54, 27, -5 },
603 { 12, 48, 53, 22, -7 },
604 { -9, 17, 52, 51, 17 },
605 { -7, 22, 53, 48, 12 },
606 { -5, 27, 54, 44, 8 },
607 { -2, 31, 55, 40, 4 },
608 };
609
610 const struct dispc_h_coef *h_coef;
611 const struct dispc_v_coef *v_coef;
612 int i; 553 int i;
613 554
614 if (hscaleup) 555 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
615 h_coef = coef_hup; 556 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
616 else
617 h_coef = coef_hdown;
618
619 if (vscaleup)
620 v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
621 else
622 v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
623 557
624 for (i = 0; i < 8; i++) { 558 for (i = 0; i < 8; i++) {
625 u32 h, hv; 559 u32 h, hv;
626 560
627 h = FLD_VAL(h_coef[i].hc0, 7, 0) 561 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
628 | FLD_VAL(h_coef[i].hc1, 15, 8) 562 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
629 | FLD_VAL(h_coef[i].hc2, 23, 16) 563 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
630 | FLD_VAL(h_coef[i].hc3, 31, 24); 564 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
631 hv = FLD_VAL(h_coef[i].hc4, 7, 0) 565 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
632 | FLD_VAL(v_coef[i].vc0, 15, 8) 566 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
633 | FLD_VAL(v_coef[i].vc1, 23, 16) 567 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
634 | FLD_VAL(v_coef[i].vc2, 31, 24); 568 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
635 569
636 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { 570 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
637 dispc_ovl_write_firh_reg(plane, i, h); 571 dispc_ovl_write_firh_reg(plane, i, h);
@@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
646 if (five_taps) { 580 if (five_taps) {
647 for (i = 0; i < 8; i++) { 581 for (i = 0; i < 8; i++) {
648 u32 v; 582 u32 v;
649 v = FLD_VAL(v_coef[i].vc00, 7, 0) 583 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
650 | FLD_VAL(v_coef[i].vc22, 15, 8); 584 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
651 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) 585 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
652 dispc_ovl_write_firv_reg(plane, i, v); 586 dispc_ovl_write_firv_reg(plane, i, v);
653 else 587 else
@@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane,
875 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); 809 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
876} 810}
877 811
878static void dispc_ovl_set_channel_out(enum omap_plane plane, 812void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
879 enum omap_channel channel)
880{ 813{
881 int shift; 814 int shift;
882 u32 val; 815 u32 val;
@@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane,
923 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); 856 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
924} 857}
925 858
859static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
860{
861 int shift;
862 u32 val;
863 enum omap_channel channel;
864
865 switch (plane) {
866 case OMAP_DSS_GFX:
867 shift = 8;
868 break;
869 case OMAP_DSS_VIDEO1:
870 case OMAP_DSS_VIDEO2:
871 case OMAP_DSS_VIDEO3:
872 shift = 16;
873 break;
874 default:
875 BUG();
876 }
877
878 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
879
880 if (dss_has_feature(FEAT_MGR_LCD2)) {
881 if (FLD_GET(val, 31, 30) == 0)
882 channel = FLD_GET(val, shift, shift);
883 else
884 channel = OMAP_DSS_CHANNEL_LCD2;
885 } else {
886 channel = FLD_GET(val, shift, shift);
887 }
888
889 return channel;
890}
891
926static void dispc_ovl_set_burst_size(enum omap_plane plane, 892static void dispc_ovl_set_burst_size(enum omap_plane plane,
927 enum omap_burst_size burst_size) 893 enum omap_burst_size burst_size)
928{ 894{
@@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable)
964 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); 930 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
965} 931}
966 932
967void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) 933static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
968{ 934{
969 u16 reg; 935 u16 reg;
970 936
@@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
978 REG_FLD_MOD(reg, enable, 15, 15); 944 REG_FLD_MOD(reg, enable, 15, 15);
979} 945}
980 946
981void dispc_mgr_set_cpr_coef(enum omap_channel channel, 947static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
982 struct omap_dss_cpr_coefs *coefs) 948 struct omap_dss_cpr_coefs *coefs)
983{ 949{
984 u32 coef_r, coef_g, coef_b; 950 u32 coef_r, coef_g, coef_b;
@@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
1057 return dispc.fifo_size[plane]; 1023 return dispc.fifo_size[plane];
1058} 1024}
1059 1025
1060static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, 1026void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
1061 u32 high)
1062{ 1027{
1063 u8 hi_start, hi_end, lo_start, lo_end; 1028 u8 hi_start, hi_end, lo_start, lo_end;
1064 u32 unit; 1029 u32 unit;
@@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane,
1169 enum omap_color_component color_comp) 1134 enum omap_color_component color_comp)
1170{ 1135{
1171 int fir_hinc, fir_vinc; 1136 int fir_hinc, fir_vinc;
1172 int hscaleup, vscaleup;
1173
1174 hscaleup = orig_width <= out_width;
1175 vscaleup = orig_height <= out_height;
1176
1177 dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps,
1178 color_comp);
1179 1137
1180 fir_hinc = 1024 * orig_width / out_width; 1138 fir_hinc = 1024 * orig_width / out_width;
1181 fir_vinc = 1024 * orig_height / out_height; 1139 fir_vinc = 1024 * orig_height / out_height;
1182 1140
1141 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1142 color_comp);
1183 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); 1143 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
1184} 1144}
1185 1145
@@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
1654 u32 fclk = 0; 1614 u32 fclk = 0;
1655 u64 tmp, pclk = dispc_mgr_pclk_rate(channel); 1615 u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
1656 1616
1617 if (height <= out_height && width <= out_width)
1618 return (unsigned long) pclk;
1619
1657 if (height > out_height) { 1620 if (height > out_height) {
1658 struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); 1621 struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
1659 unsigned int ppl = dssdev->panel.timings.x_res; 1622 unsigned int ppl = dssdev->panel.timings.x_res;
@@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
1708 else 1671 else
1709 vf = 1; 1672 vf = 1;
1710 1673
1711 return dispc_mgr_pclk_rate(channel) * vf * hf; 1674 if (cpu_is_omap24xx()) {
1675 if (vf > 1 && hf > 1)
1676 return dispc_mgr_pclk_rate(channel) * 4;
1677 else
1678 return dispc_mgr_pclk_rate(channel) * 2;
1679 } else if (cpu_is_omap34xx()) {
1680 return dispc_mgr_pclk_rate(channel) * vf * hf;
1681 } else {
1682 return dispc_mgr_pclk_rate(channel) * hf;
1683 }
1712} 1684}
1713 1685
1714static int dispc_ovl_calc_scaling(enum omap_plane plane, 1686static int dispc_ovl_calc_scaling(enum omap_plane plane,
@@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
1718{ 1690{
1719 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 1691 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
1720 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); 1692 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
1693 const int maxsinglelinewidth =
1694 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
1721 unsigned long fclk = 0; 1695 unsigned long fclk = 0;
1722 1696
1723 if (width == out_width && height == out_height) 1697 if (width == out_width && height == out_height)
@@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
1734 out_height > height * 8) 1708 out_height > height * 8)
1735 return -EINVAL; 1709 return -EINVAL;
1736 1710
1737 /* Must use 5-tap filter? */ 1711 if (cpu_is_omap24xx()) {
1738 *five_taps = height > out_height * 2; 1712 if (width > maxsinglelinewidth)
1739 1713 DSSERR("Cannot scale max input width exceeded");
1740 if (!*five_taps) { 1714 *five_taps = false;
1715 fclk = calc_fclk(channel, width, height, out_width,
1716 out_height);
1717 } else if (cpu_is_omap34xx()) {
1718 if (width > (maxsinglelinewidth * 2)) {
1719 DSSERR("Cannot setup scaling");
1720 DSSERR("width exceeds maximum width possible");
1721 return -EINVAL;
1722 }
1723 fclk = calc_fclk_five_taps(channel, width, height, out_width,
1724 out_height, color_mode);
1725 if (width > maxsinglelinewidth) {
1726 if (height > out_height && height < out_height * 2)
1727 *five_taps = false;
1728 else {
1729 DSSERR("cannot setup scaling with five taps");
1730 return -EINVAL;
1731 }
1732 }
1733 if (!*five_taps)
1734 fclk = calc_fclk(channel, width, height, out_width,
1735 out_height);
1736 } else {
1737 if (width > maxsinglelinewidth) {
1738 DSSERR("Cannot scale width exceeds max line width");
1739 return -EINVAL;
1740 }
1741 fclk = calc_fclk(channel, width, height, out_width, 1741 fclk = calc_fclk(channel, width, height, out_width,
1742 out_height); 1742 out_height);
1743
1744 /* Try 5-tap filter if 3-tap fclk is too high */
1745 if (cpu_is_omap34xx() && height > out_height &&
1746 fclk > dispc_fclk_rate())
1747 *five_taps = true;
1748 }
1749
1750 if (width > (2048 >> *five_taps)) {
1751 DSSERR("failed to set up scaling, fclk too low\n");
1752 return -EINVAL;
1753 } 1743 }
1754 1744
1755 if (*five_taps)
1756 fclk = calc_fclk_five_taps(channel, width, height,
1757 out_width, out_height, color_mode);
1758
1759 DSSDBG("required fclk rate = %lu Hz\n", fclk); 1745 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1760 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); 1746 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1761 1747
@@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
1771} 1757}
1772 1758
1773int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, 1759int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1774 bool ilace, enum omap_channel channel, bool replication, 1760 bool ilace, bool replication)
1775 u32 fifo_low, u32 fifo_high)
1776{ 1761{
1777 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 1762 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
1778 bool five_taps = false; 1763 bool five_taps = true;
1779 bool fieldmode = 0; 1764 bool fieldmode = 0;
1780 int r, cconv = 0; 1765 int r, cconv = 0;
1781 unsigned offset0, offset1; 1766 unsigned offset0, offset1;
@@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1783 s32 pix_inc; 1768 s32 pix_inc;
1784 u16 frame_height = oi->height; 1769 u16 frame_height = oi->height;
1785 unsigned int field_offset = 0; 1770 unsigned int field_offset = 0;
1771 u16 outw, outh;
1772 enum omap_channel channel;
1773
1774 channel = dispc_ovl_get_channel_out(plane);
1786 1775
1787 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " 1776 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
1788 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d " 1777 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
1789 "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, 1778 plane, oi->paddr, oi->p_uv_addr,
1790 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, 1779 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
1791 oi->out_width, oi->out_height, oi->color_mode, oi->rotation, 1780 oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
1792 oi->mirror, ilace, channel, replication, fifo_low, fifo_high); 1781 oi->mirror, ilace, channel, replication);
1793 1782
1794 if (oi->paddr == 0) 1783 if (oi->paddr == 0)
1795 return -EINVAL; 1784 return -EINVAL;
1796 1785
1797 if (ilace && oi->height == oi->out_height) 1786 outw = oi->out_width == 0 ? oi->width : oi->out_width;
1787 outh = oi->out_height == 0 ? oi->height : oi->out_height;
1788
1789 if (ilace && oi->height == outh)
1798 fieldmode = 1; 1790 fieldmode = 1;
1799 1791
1800 if (ilace) { 1792 if (ilace) {
1801 if (fieldmode) 1793 if (fieldmode)
1802 oi->height /= 2; 1794 oi->height /= 2;
1803 oi->pos_y /= 2; 1795 oi->pos_y /= 2;
1804 oi->out_height /= 2; 1796 outh /= 2;
1805 1797
1806 DSSDBG("adjusting for ilace: height %d, pos_y %d, " 1798 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1807 "out_height %d\n", 1799 "out_height %d\n",
1808 oi->height, oi->pos_y, oi->out_height); 1800 oi->height, oi->pos_y, outh);
1809 } 1801 }
1810 1802
1811 if (!dss_feat_color_mode_supported(plane, oi->color_mode)) 1803 if (!dss_feat_color_mode_supported(plane, oi->color_mode))
1812 return -EINVAL; 1804 return -EINVAL;
1813 1805
1814 r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, 1806 r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
1815 oi->out_width, oi->out_height, oi->color_mode, 1807 outw, outh, oi->color_mode,
1816 &five_taps); 1808 &five_taps);
1817 if (r) 1809 if (r)
1818 return r; 1810 return r;
@@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1830 * so the integer part must be added to the base address of the 1822 * so the integer part must be added to the base address of the
1831 * bottom field. 1823 * bottom field.
1832 */ 1824 */
1833 if (!oi->height || oi->height == oi->out_height) 1825 if (!oi->height || oi->height == outh)
1834 field_offset = 0; 1826 field_offset = 0;
1835 else 1827 else
1836 field_offset = oi->height / oi->out_height / 2; 1828 field_offset = oi->height / outh / 2;
1837 } 1829 }
1838 1830
1839 /* Fields are independent but interleaved in memory. */ 1831 /* Fields are independent but interleaved in memory. */
@@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1869 dispc_ovl_set_pix_inc(plane, pix_inc); 1861 dispc_ovl_set_pix_inc(plane, pix_inc);
1870 1862
1871 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, 1863 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width,
1872 oi->height, oi->out_width, oi->out_height); 1864 oi->height, outw, outh);
1873 1865
1874 dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); 1866 dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
1875 1867
@@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1877 1869
1878 if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { 1870 if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
1879 dispc_ovl_set_scaling(plane, oi->width, oi->height, 1871 dispc_ovl_set_scaling(plane, oi->width, oi->height,
1880 oi->out_width, oi->out_height, 1872 outw, outh,
1881 ilace, five_taps, fieldmode, 1873 ilace, five_taps, fieldmode,
1882 oi->color_mode, oi->rotation); 1874 oi->color_mode, oi->rotation);
1883 dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); 1875 dispc_ovl_set_vid_size(plane, outw, outh);
1884 dispc_ovl_set_vid_color_conv(plane, cconv); 1876 dispc_ovl_set_vid_color_conv(plane, cconv);
1885 } 1877 }
1886 1878
@@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
1891 dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); 1883 dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
1892 dispc_ovl_setup_global_alpha(plane, oi->global_alpha); 1884 dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
1893 1885
1894 dispc_ovl_set_channel_out(plane, channel);
1895
1896 dispc_ovl_enable_replication(plane, replication); 1886 dispc_ovl_enable_replication(plane, replication);
1897 dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high);
1898 1887
1899 return 0; 1888 return 0;
1900} 1889}
@@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask)
1916 1905
1917static void _enable_lcd_out(enum omap_channel channel, bool enable) 1906static void _enable_lcd_out(enum omap_channel channel, bool enable)
1918{ 1907{
1919 if (channel == OMAP_DSS_CHANNEL_LCD2) 1908 if (channel == OMAP_DSS_CHANNEL_LCD2) {
1920 REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); 1909 REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
1921 else 1910 /* flush posted write */
1911 dispc_read_reg(DISPC_CONTROL2);
1912 } else {
1922 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); 1913 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1914 dispc_read_reg(DISPC_CONTROL);
1915 }
1923} 1916}
1924 1917
1925static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) 1918static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
@@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
1967static void _enable_digit_out(bool enable) 1960static void _enable_digit_out(bool enable)
1968{ 1961{
1969 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); 1962 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1963 /* flush posted write */
1964 dispc_read_reg(DISPC_CONTROL);
1970} 1965}
1971 1966
1972static void dispc_mgr_enable_digit_out(bool enable) 1967static void dispc_mgr_enable_digit_out(bool enable)
@@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
2124} 2119}
2125 2120
2126 2121
2127void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) 2122static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
2128{ 2123{
2129 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); 2124 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
2130} 2125}
2131 2126
2132u32 dispc_mgr_get_default_color(enum omap_channel channel) 2127static void dispc_mgr_set_trans_key(enum omap_channel ch,
2133{
2134 u32 l;
2135
2136 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
2137 channel != OMAP_DSS_CHANNEL_LCD &&
2138 channel != OMAP_DSS_CHANNEL_LCD2);
2139
2140 l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
2141
2142 return l;
2143}
2144
2145void dispc_mgr_set_trans_key(enum omap_channel ch,
2146 enum omap_dss_trans_key_type type, 2128 enum omap_dss_trans_key_type type,
2147 u32 trans_key) 2129 u32 trans_key)
2148{ 2130{
@@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch,
2156 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); 2138 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
2157} 2139}
2158 2140
2159void dispc_mgr_get_trans_key(enum omap_channel ch, 2141static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2160 enum omap_dss_trans_key_type *type,
2161 u32 *trans_key)
2162{
2163 if (type) {
2164 if (ch == OMAP_DSS_CHANNEL_LCD)
2165 *type = REG_GET(DISPC_CONFIG, 11, 11);
2166 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2167 *type = REG_GET(DISPC_CONFIG, 13, 13);
2168 else if (ch == OMAP_DSS_CHANNEL_LCD2)
2169 *type = REG_GET(DISPC_CONFIG2, 11, 11);
2170 else
2171 BUG();
2172 }
2173
2174 if (trans_key)
2175 *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
2176}
2177
2178void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2179{ 2142{
2180 if (ch == OMAP_DSS_CHANNEL_LCD) 2143 if (ch == OMAP_DSS_CHANNEL_LCD)
2181 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); 2144 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
@@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2185 REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); 2148 REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
2186} 2149}
2187 2150
2188void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) 2151static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2152 bool enable)
2189{ 2153{
2190 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) 2154 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
2191 return; 2155 return;
@@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable)
2196 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); 2160 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2197} 2161}
2198 2162
2199bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) 2163void dispc_mgr_setup(enum omap_channel channel,
2200{ 2164 struct omap_overlay_manager_info *info)
2201 bool enabled;
2202
2203 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
2204 return false;
2205
2206 if (ch == OMAP_DSS_CHANNEL_LCD)
2207 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2208 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2209 enabled = REG_GET(DISPC_CONFIG, 19, 19);
2210 else
2211 BUG();
2212
2213 return enabled;
2214}
2215
2216bool dispc_mgr_trans_key_enabled(enum omap_channel ch)
2217{ 2165{
2218 bool enabled; 2166 dispc_mgr_set_default_color(channel, info->default_color);
2219 2167 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2220 if (ch == OMAP_DSS_CHANNEL_LCD) 2168 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2221 enabled = REG_GET(DISPC_CONFIG, 10, 10); 2169 dispc_mgr_enable_alpha_fixed_zorder(channel,
2222 else if (ch == OMAP_DSS_CHANNEL_DIGIT) 2170 info->partial_alpha_enabled);
2223 enabled = REG_GET(DISPC_CONFIG, 12, 12); 2171 if (dss_has_feature(FEAT_CPR)) {
2224 else if (ch == OMAP_DSS_CHANNEL_LCD2) 2172 dispc_mgr_enable_cpr(channel, info->cpr_enable);
2225 enabled = REG_GET(DISPC_CONFIG2, 10, 10); 2173 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2226 else 2174 }
2227 BUG();
2228
2229 return enabled;
2230} 2175}
2231 2176
2232
2233void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) 2177void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
2234{ 2178{
2235 int code; 2179 int code;
@@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work)
3184 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { 3128 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3185 struct omap_overlay_manager *mgr; 3129 struct omap_overlay_manager *mgr;
3186 mgr = omap_dss_get_overlay_manager(i); 3130 mgr = omap_dss_get_overlay_manager(i);
3187 mgr->device->driver->disable(mgr->device); 3131 if (mgr->device && mgr->device->driver)
3132 mgr->device->driver->disable(mgr->device);
3188 } 3133 }
3189 } 3134 }
3190 3135
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index c06efc38983e..5836bd1650f9 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -97,6 +97,17 @@
97#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ 97#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
98 DISPC_PRELOAD_OFFSET(n)) 98 DISPC_PRELOAD_OFFSET(n))
99 99
100/* DISPC up/downsampling FIR filter coefficient structure */
101struct dispc_coef {
102 s8 hc4_vc22;
103 s8 hc3_vc2;
104 u8 hc2_vc1;
105 s8 hc1_vc0;
106 s8 hc0_vc00;
107};
108
109const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
110
100/* DISPC manager/channel specific registers */ 111/* DISPC manager/channel specific registers */
101static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) 112static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
102{ 113{
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c
new file mode 100644
index 000000000000..069bccbb3f12
--- /dev/null
+++ b/drivers/video/omap2/dss/dispc_coefs.c
@@ -0,0 +1,326 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc_coefs.c
3 *
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/kernel.h>
21#include <video/omapdss.h>
22#include "dispc.h"
23
24#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
25
26static const struct dispc_coef coef3_M8[8] = {
27 { 0, 0, 128, 0, 0 },
28 { 0, -4, 123, 9, 0 },
29 { 0, -4, 108, 87, 0 },
30 { 0, -2, 87, 43, 0 },
31 { 0, 64, 64, 0, 0 },
32 { 0, 43, 87, -2, 0 },
33 { 0, 24, 108, -4, 0 },
34 { 0, 9, 123, -4, 0 },
35};
36
37static const struct dispc_coef coef3_M9[8] = {
38 { 0, 6, 116, 6, 0 },
39 { 0, 0, 112, 16, 0 },
40 { 0, -2, 100, 30, 0 },
41 { 0, -2, 83, 47, 0 },
42 { 0, 64, 64, 0, 0 },
43 { 0, 47, 83, -2, 0 },
44 { 0, 30, 100, -2, 0 },
45 { 0, 16, 112, 0, 0 },
46};
47
48static const struct dispc_coef coef3_M10[8] = {
49 { 0, 10, 108, 10, 0 },
50 { 0, 3, 104, 21, 0 },
51 { 0, 0, 94, 34, 0 },
52 { 0, -1, 80, 49, 0 },
53 { 0, 64, 64, 0, 0 },
54 { 0, 49, 80, -1, 0 },
55 { 0, 34, 94, 0, 0 },
56 { 0, 21, 104, 3, 0 },
57};
58
59static const struct dispc_coef coef3_M11[8] = {
60 { 0, 14, 100, 14, 0 },
61 { 0, 6, 98, 24, 0 },
62 { 0, 2, 90, 36, 0 },
63 { 0, 0, 78, 50, 0 },
64 { 0, 64, 64, 0, 0 },
65 { 0, 50, 78, 0, 0 },
66 { 0, 36, 90, 2, 0 },
67 { 0, 24, 98, 6, 0 },
68};
69
70static const struct dispc_coef coef3_M12[8] = {
71 { 0, 16, 96, 16, 0 },
72 { 0, 9, 93, 26, 0 },
73 { 0, 4, 86, 38, 0 },
74 { 0, 1, 76, 51, 0 },
75 { 0, 64, 64, 0, 0 },
76 { 0, 51, 76, 1, 0 },
77 { 0, 38, 86, 4, 0 },
78 { 0, 26, 93, 9, 0 },
79};
80
81static const struct dispc_coef coef3_M13[8] = {
82 { 0, 18, 92, 18, 0 },
83 { 0, 10, 90, 28, 0 },
84 { 0, 5, 83, 40, 0 },
85 { 0, 1, 75, 52, 0 },
86 { 0, 64, 64, 0, 0 },
87 { 0, 52, 75, 1, 0 },
88 { 0, 40, 83, 5, 0 },
89 { 0, 28, 90, 10, 0 },
90};
91
92static const struct dispc_coef coef3_M14[8] = {
93 { 0, 20, 88, 20, 0 },
94 { 0, 12, 86, 30, 0 },
95 { 0, 6, 81, 41, 0 },
96 { 0, 2, 74, 52, 0 },
97 { 0, 64, 64, 0, 0 },
98 { 0, 52, 74, 2, 0 },
99 { 0, 41, 81, 6, 0 },
100 { 0, 30, 86, 12, 0 },
101};
102
103static const struct dispc_coef coef3_M16[8] = {
104 { 0, 22, 84, 22, 0 },
105 { 0, 14, 82, 32, 0 },
106 { 0, 8, 78, 42, 0 },
107 { 0, 3, 72, 53, 0 },
108 { 0, 64, 64, 0, 0 },
109 { 0, 53, 72, 3, 0 },
110 { 0, 42, 78, 8, 0 },
111 { 0, 32, 82, 14, 0 },
112};
113
114static const struct dispc_coef coef3_M19[8] = {
115 { 0, 24, 80, 24, 0 },
116 { 0, 16, 79, 33, 0 },
117 { 0, 9, 76, 43, 0 },
118 { 0, 4, 70, 54, 0 },
119 { 0, 64, 64, 0, 0 },
120 { 0, 54, 70, 4, 0 },
121 { 0, 43, 76, 9, 0 },
122 { 0, 33, 79, 16, 0 },
123};
124
125static const struct dispc_coef coef3_M22[8] = {
126 { 0, 25, 78, 25, 0 },
127 { 0, 17, 77, 34, 0 },
128 { 0, 10, 74, 44, 0 },
129 { 0, 5, 69, 54, 0 },
130 { 0, 64, 64, 0, 0 },
131 { 0, 54, 69, 5, 0 },
132 { 0, 44, 74, 10, 0 },
133 { 0, 34, 77, 17, 0 },
134};
135
136static const struct dispc_coef coef3_M26[8] = {
137 { 0, 26, 76, 26, 0 },
138 { 0, 19, 74, 35, 0 },
139 { 0, 11, 72, 45, 0 },
140 { 0, 5, 69, 54, 0 },
141 { 0, 64, 64, 0, 0 },
142 { 0, 54, 69, 5, 0 },
143 { 0, 45, 72, 11, 0 },
144 { 0, 35, 74, 19, 0 },
145};
146
147static const struct dispc_coef coef3_M32[8] = {
148 { 0, 27, 74, 27, 0 },
149 { 0, 19, 73, 36, 0 },
150 { 0, 12, 71, 45, 0 },
151 { 0, 6, 68, 54, 0 },
152 { 0, 64, 64, 0, 0 },
153 { 0, 54, 68, 6, 0 },
154 { 0, 45, 71, 12, 0 },
155 { 0, 36, 73, 19, 0 },
156};
157
158static const struct dispc_coef coef5_M8[8] = {
159 { 0, 0, 128, 0, 0 },
160 { -2, 14, 125, -10, 1 },
161 { -6, 33, 114, -15, 2 },
162 { -10, 55, 98, -16, 1 },
163 { 0, -14, 78, 78, -14 },
164 { 1, -16, 98, 55, -10 },
165 { 2, -15, 114, 33, -6 },
166 { 1, -10, 125, 14, -2 },
167};
168
169static const struct dispc_coef coef5_M9[8] = {
170 { -3, 10, 114, 10, -3 },
171 { -6, 24, 110, 0, -1 },
172 { -8, 40, 103, -7, 0 },
173 { -11, 58, 91, -11, 1 },
174 { 0, -12, 76, 76, -12 },
175 { 1, -11, 91, 58, -11 },
176 { 0, -7, 103, 40, -8 },
177 { -1, 0, 111, 24, -6 },
178};
179
180static const struct dispc_coef coef5_M10[8] = {
181 { -4, 18, 100, 18, -4 },
182 { -6, 30, 99, 8, -3 },
183 { -8, 44, 93, 0, -1 },
184 { -9, 58, 84, -5, 0 },
185 { 0, -8, 72, 72, -8 },
186 { 0, -5, 84, 58, -9 },
187 { -1, 0, 93, 44, -8 },
188 { -3, 8, 99, 30, -6 },
189};
190
191static const struct dispc_coef coef5_M11[8] = {
192 { -5, 23, 92, 23, -5 },
193 { -6, 34, 90, 13, -3 },
194 { -6, 45, 85, 6, -2 },
195 { -6, 57, 78, 0, -1 },
196 { 0, -4, 68, 68, -4 },
197 { -1, 0, 78, 57, -6 },
198 { -2, 6, 85, 45, -6 },
199 { -3, 13, 90, 34, -6 },
200};
201
202static const struct dispc_coef coef5_M12[8] = {
203 { -4, 26, 84, 26, -4 },
204 { -5, 36, 82, 18, -3 },
205 { -4, 46, 78, 10, -2 },
206 { -3, 55, 72, 5, -1 },
207 { 0, 0, 64, 64, 0 },
208 { -1, 5, 72, 55, -3 },
209 { -2, 10, 78, 46, -4 },
210 { -3, 18, 82, 36, -5 },
211};
212
213static const struct dispc_coef coef5_M13[8] = {
214 { -3, 28, 78, 28, -3 },
215 { -3, 37, 76, 21, -3 },
216 { -2, 45, 73, 14, -2 },
217 { 0, 53, 68, 8, -1 },
218 { 0, 3, 61, 61, 3 },
219 { -1, 8, 68, 53, 0 },
220 { -2, 14, 73, 45, -2 },
221 { -3, 21, 76, 37, -3 },
222};
223
224static const struct dispc_coef coef5_M14[8] = {
225 { -2, 30, 72, 30, -2 },
226 { -1, 37, 71, 23, -2 },
227 { 0, 45, 69, 16, -2 },
228 { 3, 52, 64, 10, -1 },
229 { 0, 6, 58, 58, 6 },
230 { -1, 10, 64, 52, 3 },
231 { -2, 16, 69, 45, 0 },
232 { -2, 23, 71, 37, -1 },
233};
234
235static const struct dispc_coef coef5_M16[8] = {
236 { 0, 31, 66, 31, 0 },
237 { 1, 38, 65, 25, -1 },
238 { 3, 44, 62, 20, -1 },
239 { 6, 49, 59, 14, 0 },
240 { 0, 10, 54, 54, 10 },
241 { 0, 14, 59, 49, 6 },
242 { -1, 20, 62, 44, 3 },
243 { -1, 25, 65, 38, 1 },
244};
245
246static const struct dispc_coef coef5_M19[8] = {
247 { 3, 32, 58, 32, 3 },
248 { 4, 38, 58, 27, 1 },
249 { 7, 42, 55, 23, 1 },
250 { 10, 46, 54, 18, 0 },
251 { 0, 14, 50, 50, 14 },
252 { 0, 18, 54, 46, 10 },
253 { 1, 23, 55, 42, 7 },
254 { 1, 27, 58, 38, 4 },
255};
256
257static const struct dispc_coef coef5_M22[8] = {
258 { 4, 33, 54, 33, 4 },
259 { 6, 37, 54, 28, 3 },
260 { 9, 41, 53, 24, 1 },
261 { 12, 45, 51, 20, 0 },
262 { 0, 16, 48, 48, 16 },
263 { 0, 20, 51, 45, 12 },
264 { 1, 24, 53, 41, 9 },
265 { 3, 28, 54, 37, 6 },
266};
267
268static const struct dispc_coef coef5_M26[8] = {
269 { 6, 33, 50, 33, 6 },
270 { 8, 36, 51, 29, 4 },
271 { 11, 40, 50, 25, 2 },
272 { 14, 43, 48, 22, 1 },
273 { 0, 18, 46, 46, 18 },
274 { 1, 22, 48, 43, 14 },
275 { 2, 25, 50, 40, 11 },
276 { 4, 29, 51, 36, 8 },
277};
278
279static const struct dispc_coef coef5_M32[8] = {
280 { 7, 33, 48, 33, 7 },
281 { 10, 36, 48, 29, 5 },
282 { 13, 39, 47, 26, 3 },
283 { 16, 42, 46, 23, 1 },
284 { 0, 19, 45, 45, 19 },
285 { 1, 23, 46, 42, 16 },
286 { 3, 26, 47, 39, 13 },
287 { 5, 29, 48, 36, 10 },
288};
289
290const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
291{
292 int i;
293 static const struct {
294 int Mmin;
295 int Mmax;
296 const struct dispc_coef *coef_3;
297 const struct dispc_coef *coef_5;
298 } coefs[] = {
299 { 27, 32, coef3_M32, coef5_M32 },
300 { 23, 26, coef3_M26, coef5_M26 },
301 { 20, 22, coef3_M22, coef5_M22 },
302 { 17, 19, coef3_M19, coef5_M19 },
303 { 15, 16, coef3_M16, coef5_M16 },
304 { 14, 14, coef3_M14, coef5_M14 },
305 { 13, 13, coef3_M13, coef5_M13 },
306 { 12, 12, coef3_M12, coef5_M12 },
307 { 11, 11, coef3_M11, coef5_M11 },
308 { 10, 10, coef3_M10, coef5_M10 },
309 { 9, 9, coef3_M9, coef5_M9 },
310 { 4, 8, coef3_M8, coef5_M8 },
311 /*
312 * When upscaling more than two times, blockiness and outlines
313 * around the image are observed when M8 tables are used. M11,
314 * M16 and M19 tables are used to prevent this.
315 */
316 { 3, 3, coef3_M11, coef5_M11 },
317 { 2, 2, coef3_M16, coef5_M16 },
318 { 0, 1, coef3_M19, coef5_M19 },
319 };
320
321 inc /= 128;
322 for (i = 0; i < ARRAY_LEN(coefs); ++i)
323 if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
324 return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
325 return NULL;
326}
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 976ac23dcd0c..395d658a94fc 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
223 223
224 mdelay(2); 224 mdelay(2);
225 225
226 dssdev->manager->enable(dssdev->manager); 226 r = dss_mgr_enable(dssdev->manager);
227 if (r)
228 goto err_mgr_enable;
227 229
228 return 0; 230 return 0;
229 231
232err_mgr_enable:
230err_set_mode: 233err_set_mode:
231 if (dpi_use_dsi_pll(dssdev)) 234 if (dpi_use_dsi_pll(dssdev))
232 dsi_pll_uninit(dpi.dsidev, true); 235 dsi_pll_uninit(dpi.dsidev, true);
@@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
249 252
250void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) 253void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
251{ 254{
252 dssdev->manager->disable(dssdev->manager); 255 dss_mgr_disable(dssdev->manager);
253 256
254 if (dpi_use_dsi_pll(dssdev)) { 257 if (dpi_use_dsi_pll(dssdev)) {
255 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); 258 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 46f37883e499..d4d676c82c12 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; };
203typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); 203typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
204 204
205#define DSI_MAX_NR_ISRS 2 205#define DSI_MAX_NR_ISRS 2
206#define DSI_MAX_NR_LANES 5
207
208enum dsi_lane_function {
209 DSI_LANE_UNUSED = 0,
210 DSI_LANE_CLK,
211 DSI_LANE_DATA1,
212 DSI_LANE_DATA2,
213 DSI_LANE_DATA3,
214 DSI_LANE_DATA4,
215};
216
217struct dsi_lane_config {
218 enum dsi_lane_function function;
219 u8 polarity;
220};
206 221
207struct dsi_isr_data { 222struct dsi_isr_data {
208 omap_dsi_isr_t isr; 223 omap_dsi_isr_t isr;
@@ -223,24 +238,6 @@ enum dsi_vc_source {
223 DSI_VC_SOURCE_VP, 238 DSI_VC_SOURCE_VP,
224}; 239};
225 240
226enum dsi_lane {
227 DSI_CLK_P = 1 << 0,
228 DSI_CLK_N = 1 << 1,
229 DSI_DATA1_P = 1 << 2,
230 DSI_DATA1_N = 1 << 3,
231 DSI_DATA2_P = 1 << 4,
232 DSI_DATA2_N = 1 << 5,
233 DSI_DATA3_P = 1 << 6,
234 DSI_DATA3_N = 1 << 7,
235 DSI_DATA4_P = 1 << 8,
236 DSI_DATA4_N = 1 << 9,
237};
238
239struct dsi_update_region {
240 u16 x, y, w, h;
241 struct omap_dss_device *device;
242};
243
244struct dsi_irq_stats { 241struct dsi_irq_stats {
245 unsigned long last_reset; 242 unsigned long last_reset;
246 unsigned irq_count; 243 unsigned irq_count;
@@ -290,7 +287,9 @@ struct dsi_data {
290 struct dsi_isr_tables isr_tables_copy; 287 struct dsi_isr_tables isr_tables_copy;
291 288
292 int update_channel; 289 int update_channel;
293 struct dsi_update_region update_region; 290#ifdef DEBUG
291 unsigned update_bytes;
292#endif
294 293
295 bool te_enabled; 294 bool te_enabled;
296 bool ulps_enabled; 295 bool ulps_enabled;
@@ -327,7 +326,10 @@ struct dsi_data {
327 unsigned long fint_min, fint_max; 326 unsigned long fint_min, fint_max;
328 unsigned long lpdiv_max; 327 unsigned long lpdiv_max;
329 328
330 int num_data_lanes; 329 unsigned num_lanes_supported;
330
331 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
332 unsigned num_lanes_used;
331 333
332 unsigned scp_clk_refcount; 334 unsigned scp_clk_refcount;
333}; 335};
@@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask)
413static inline int wait_for_bit_change(struct platform_device *dsidev, 415static inline int wait_for_bit_change(struct platform_device *dsidev,
414 const struct dsi_reg idx, int bitnum, int value) 416 const struct dsi_reg idx, int bitnum, int value)
415{ 417{
416 int t = 100000; 418 unsigned long timeout;
419 ktime_t wait;
420 int t;
417 421
418 while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { 422 /* first busyloop to see if the bit changes right away */
419 if (--t == 0) 423 t = 100;
420 return !value; 424 while (t-- > 0) {
425 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
426 return value;
421 } 427 }
422 428
423 return value; 429 /* then loop for 500ms, sleeping for 1ms in between */
430 timeout = jiffies + msecs_to_jiffies(500);
431 while (time_before(jiffies, timeout)) {
432 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
433 return value;
434
435 wait = ns_to_ktime(1000 * 1000);
436 set_current_state(TASK_UNINTERRUPTIBLE);
437 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
438 }
439
440 return !value;
424} 441}
425 442
426u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) 443u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
@@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev)
454static void dsi_perf_show(struct platform_device *dsidev, const char *name) 471static void dsi_perf_show(struct platform_device *dsidev, const char *name)
455{ 472{
456 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 473 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
457 struct omap_dss_device *dssdev = dsi->update_region.device;
458 ktime_t t, setup_time, trans_time; 474 ktime_t t, setup_time, trans_time;
459 u32 total_bytes; 475 u32 total_bytes;
460 u32 setup_us, trans_us, total_us; 476 u32 setup_us, trans_us, total_us;
@@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
476 492
477 total_us = setup_us + trans_us; 493 total_us = setup_us + trans_us;
478 494
479 total_bytes = dsi->update_region.w * 495 total_bytes = dsi->update_bytes;
480 dsi->update_region.h *
481 dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
482 496
483 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " 497 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
484 "%u bytes, %u kbytes/sec\n", 498 "%u bytes, %u kbytes/sec\n",
@@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
1720 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", 1734 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1721 cinfo->clkin4ddr, cinfo->regm); 1735 cinfo->clkin4ddr, cinfo->regm);
1722 1736
1723 seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", 1737 seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
1724 dss_get_generic_clk_source_name(dispc_clk_src), 1738 dss_feat_get_clk_source_name(dsi_module == 0 ?
1725 dss_feat_get_clk_source_name(dispc_clk_src), 1739 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
1740 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
1726 cinfo->dsi_pll_hsdiv_dispc_clk, 1741 cinfo->dsi_pll_hsdiv_dispc_clk,
1727 cinfo->regm_dispc, 1742 cinfo->regm_dispc,
1728 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? 1743 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1729 "off" : "on"); 1744 "off" : "on");
1730 1745
1731 seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", 1746 seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
1732 dss_get_generic_clk_source_name(dsi_clk_src), 1747 dss_feat_get_clk_source_name(dsi_module == 0 ?
1733 dss_feat_get_clk_source_name(dsi_clk_src), 1748 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
1749 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
1734 cinfo->dsi_pll_hsdiv_dsi_clk, 1750 cinfo->dsi_pll_hsdiv_dsi_clk,
1735 cinfo->regm_dsi, 1751 cinfo->regm_dsi,
1736 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? 1752 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
@@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev,
2029 return 0; 2045 return 0;
2030} 2046}
2031 2047
2032/* Number of data lanes present on DSI interface */
2033static inline int dsi_get_num_data_lanes(struct platform_device *dsidev)
2034{
2035 /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
2036 * of data lanes as 2 by default */
2037 if (dss_has_feature(FEAT_DSI_GNQ))
2038 return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */
2039 else
2040 return 2;
2041}
2042
2043/* Number of data lanes used by the dss device */
2044static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev)
2045{
2046 int num_data_lanes = 0;
2047
2048 if (dssdev->phy.dsi.data1_lane != 0)
2049 num_data_lanes++;
2050 if (dssdev->phy.dsi.data2_lane != 0)
2051 num_data_lanes++;
2052 if (dssdev->phy.dsi.data3_lane != 0)
2053 num_data_lanes++;
2054 if (dssdev->phy.dsi.data4_lane != 0)
2055 num_data_lanes++;
2056
2057 return num_data_lanes;
2058}
2059
2060static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) 2048static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
2061{ 2049{
2062 int val; 2050 int val;
@@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
2088 } 2076 }
2089} 2077}
2090 2078
2091static void dsi_set_lane_config(struct omap_dss_device *dssdev) 2079static int dsi_parse_lane_config(struct omap_dss_device *dssdev)
2092{ 2080{
2093 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 2081 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2094 u32 r; 2082 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2095 int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); 2083 u8 lanes[DSI_MAX_NR_LANES];
2084 u8 polarities[DSI_MAX_NR_LANES];
2085 int num_lanes, i;
2086
2087 static const enum dsi_lane_function functions[] = {
2088 DSI_LANE_CLK,
2089 DSI_LANE_DATA1,
2090 DSI_LANE_DATA2,
2091 DSI_LANE_DATA3,
2092 DSI_LANE_DATA4,
2093 };
2094
2095 lanes[0] = dssdev->phy.dsi.clk_lane;
2096 lanes[1] = dssdev->phy.dsi.data1_lane;
2097 lanes[2] = dssdev->phy.dsi.data2_lane;
2098 lanes[3] = dssdev->phy.dsi.data3_lane;
2099 lanes[4] = dssdev->phy.dsi.data4_lane;
2100 polarities[0] = dssdev->phy.dsi.clk_pol;
2101 polarities[1] = dssdev->phy.dsi.data1_pol;
2102 polarities[2] = dssdev->phy.dsi.data2_pol;
2103 polarities[3] = dssdev->phy.dsi.data3_pol;
2104 polarities[4] = dssdev->phy.dsi.data4_pol;
2096 2105
2097 int clk_lane = dssdev->phy.dsi.clk_lane; 2106 num_lanes = 0;
2098 int data1_lane = dssdev->phy.dsi.data1_lane; 2107
2099 int data2_lane = dssdev->phy.dsi.data2_lane; 2108 for (i = 0; i < dsi->num_lanes_supported; ++i)
2100 int clk_pol = dssdev->phy.dsi.clk_pol; 2109 dsi->lanes[i].function = DSI_LANE_UNUSED;
2101 int data1_pol = dssdev->phy.dsi.data1_pol; 2110
2102 int data2_pol = dssdev->phy.dsi.data2_pol; 2111 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2112 int num;
2113
2114 if (lanes[i] == DSI_LANE_UNUSED)
2115 break;
2116
2117 num = lanes[i] - 1;
2118
2119 if (num >= dsi->num_lanes_supported)
2120 return -EINVAL;
2121
2122 if (dsi->lanes[num].function != DSI_LANE_UNUSED)
2123 return -EINVAL;
2124
2125 dsi->lanes[num].function = functions[i];
2126 dsi->lanes[num].polarity = polarities[i];
2127 num_lanes++;
2128 }
2129
2130 if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported)
2131 return -EINVAL;
2132
2133 dsi->num_lanes_used = num_lanes;
2134
2135 return 0;
2136}
2137
2138static int dsi_set_lane_config(struct omap_dss_device *dssdev)
2139{
2140 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2141 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2142 static const u8 offsets[] = { 0, 4, 8, 12, 16 };
2143 static const enum dsi_lane_function functions[] = {
2144 DSI_LANE_CLK,
2145 DSI_LANE_DATA1,
2146 DSI_LANE_DATA2,
2147 DSI_LANE_DATA3,
2148 DSI_LANE_DATA4,
2149 };
2150 u32 r;
2151 int i;
2103 2152
2104 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); 2153 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
2105 r = FLD_MOD(r, clk_lane, 2, 0); 2154
2106 r = FLD_MOD(r, clk_pol, 3, 3); 2155 for (i = 0; i < dsi->num_lanes_used; ++i) {
2107 r = FLD_MOD(r, data1_lane, 6, 4); 2156 unsigned offset = offsets[i];
2108 r = FLD_MOD(r, data1_pol, 7, 7); 2157 unsigned polarity, lane_number;
2109 r = FLD_MOD(r, data2_lane, 10, 8); 2158 unsigned t;
2110 r = FLD_MOD(r, data2_pol, 11, 11); 2159
2111 if (num_data_lanes_dssdev > 2) { 2160 for (t = 0; t < dsi->num_lanes_supported; ++t)
2112 int data3_lane = dssdev->phy.dsi.data3_lane; 2161 if (dsi->lanes[t].function == functions[i])
2113 int data3_pol = dssdev->phy.dsi.data3_pol; 2162 break;
2114 2163
2115 r = FLD_MOD(r, data3_lane, 14, 12); 2164 if (t == dsi->num_lanes_supported)
2116 r = FLD_MOD(r, data3_pol, 15, 15); 2165 return -EINVAL;
2166
2167 lane_number = t;
2168 polarity = dsi->lanes[t].polarity;
2169
2170 r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
2171 r = FLD_MOD(r, polarity, offset + 3, offset + 3);
2117 } 2172 }
2118 if (num_data_lanes_dssdev > 3) {
2119 int data4_lane = dssdev->phy.dsi.data4_lane;
2120 int data4_pol = dssdev->phy.dsi.data4_pol;
2121 2173
2122 r = FLD_MOD(r, data4_lane, 18, 16); 2174 /* clear the unused lanes */
2123 r = FLD_MOD(r, data4_pol, 19, 19); 2175 for (; i < dsi->num_lanes_supported; ++i) {
2176 unsigned offset = offsets[i];
2177
2178 r = FLD_MOD(r, 0, offset + 2, offset);
2179 r = FLD_MOD(r, 0, offset + 3, offset + 3);
2124 } 2180 }
2125 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
2126 2181
2127 /* The configuration of the DSI complex I/O (number of data lanes, 2182 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
2128 position, differential order) should not be changed while
2129 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
2130 the hardware to take into account a new configuration of the complex
2131 I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
2132 follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
2133 then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
2134 DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
2135 DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
2136 DSI complex I/O configuration is unknown. */
2137 2183
2138 /* 2184 return 0;
2139 REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
2140 REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
2141 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
2142 REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
2143 */
2144} 2185}
2145 2186
2146static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) 2187static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
@@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev)
2230 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); 2271 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
2231} 2272}
2232 2273
2274/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
2233static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, 2275static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
2234 enum dsi_lane lanes) 2276 unsigned mask_p, unsigned mask_n)
2235{ 2277{
2236 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 2278 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2237 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 2279 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2238 int clk_lane = dssdev->phy.dsi.clk_lane; 2280 int i;
2239 int data1_lane = dssdev->phy.dsi.data1_lane; 2281 u32 l;
2240 int data2_lane = dssdev->phy.dsi.data2_lane; 2282 u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
2241 int data3_lane = dssdev->phy.dsi.data3_lane; 2283
2242 int data4_lane = dssdev->phy.dsi.data4_lane; 2284 l = 0;
2243 int clk_pol = dssdev->phy.dsi.clk_pol; 2285
2244 int data1_pol = dssdev->phy.dsi.data1_pol; 2286 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2245 int data2_pol = dssdev->phy.dsi.data2_pol; 2287 unsigned p = dsi->lanes[i].polarity;
2246 int data3_pol = dssdev->phy.dsi.data3_pol; 2288
2247 int data4_pol = dssdev->phy.dsi.data4_pol; 2289 if (mask_p & (1 << i))
2248 2290 l |= 1 << (i * 2 + (p ? 0 : 1));
2249 u32 l = 0; 2291
2250 u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; 2292 if (mask_n & (1 << i))
2251 2293 l |= 1 << (i * 2 + (p ? 1 : 0));
2252 if (lanes & DSI_CLK_P) 2294 }
2253 l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); 2295
2254 if (lanes & DSI_CLK_N)
2255 l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));
2256
2257 if (lanes & DSI_DATA1_P)
2258 l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
2259 if (lanes & DSI_DATA1_N)
2260 l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));
2261
2262 if (lanes & DSI_DATA2_P)
2263 l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
2264 if (lanes & DSI_DATA2_N)
2265 l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
2266
2267 if (lanes & DSI_DATA3_P)
2268 l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1));
2269 if (lanes & DSI_DATA3_N)
2270 l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0));
2271
2272 if (lanes & DSI_DATA4_P)
2273 l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1));
2274 if (lanes & DSI_DATA4_N)
2275 l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0));
2276 /* 2296 /*
2277 * Bits in REGLPTXSCPDAT4TO0DXDY: 2297 * Bits in REGLPTXSCPDAT4TO0DXDY:
2278 * 17: DY0 18: DX0 2298 * 17: DY0 18: DX0
@@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
2305static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) 2325static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
2306{ 2326{
2307 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 2327 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2308 int t; 2328 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2309 int bits[3]; 2329 int t, i;
2310 bool in_use[3]; 2330 bool in_use[DSI_MAX_NR_LANES];
2311 2331 static const u8 offsets_old[] = { 28, 27, 26 };
2312 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { 2332 static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
2313 bits[0] = 28; 2333 const u8 *offsets;
2314 bits[1] = 27; 2334
2315 bits[2] = 26; 2335 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
2316 } else { 2336 offsets = offsets_old;
2317 bits[0] = 24; 2337 else
2318 bits[1] = 25; 2338 offsets = offsets_new;
2319 bits[2] = 26;
2320 }
2321
2322 in_use[0] = false;
2323 in_use[1] = false;
2324 in_use[2] = false;
2325 2339
2326 if (dssdev->phy.dsi.clk_lane != 0) 2340 for (i = 0; i < dsi->num_lanes_supported; ++i)
2327 in_use[dssdev->phy.dsi.clk_lane - 1] = true; 2341 in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
2328 if (dssdev->phy.dsi.data1_lane != 0)
2329 in_use[dssdev->phy.dsi.data1_lane - 1] = true;
2330 if (dssdev->phy.dsi.data2_lane != 0)
2331 in_use[dssdev->phy.dsi.data2_lane - 1] = true;
2332 2342
2333 t = 100000; 2343 t = 100000;
2334 while (true) { 2344 while (true) {
2335 u32 l; 2345 u32 l;
2336 int i;
2337 int ok; 2346 int ok;
2338 2347
2339 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); 2348 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2340 2349
2341 ok = 0; 2350 ok = 0;
2342 for (i = 0; i < 3; ++i) { 2351 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2343 if (!in_use[i] || (l & (1 << bits[i]))) 2352 if (!in_use[i] || (l & (1 << offsets[i])))
2344 ok++; 2353 ok++;
2345 } 2354 }
2346 2355
2347 if (ok == 3) 2356 if (ok == dsi->num_lanes_supported)
2348 break; 2357 break;
2349 2358
2350 if (--t == 0) { 2359 if (--t == 0) {
2351 for (i = 0; i < 3; ++i) { 2360 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2352 if (!in_use[i] || (l & (1 << bits[i]))) 2361 if (!in_use[i] || (l & (1 << offsets[i])))
2353 continue; 2362 continue;
2354 2363
2355 DSSERR("CIO TXCLKESC%d domain not coming " \ 2364 DSSERR("CIO TXCLKESC%d domain not coming " \
@@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
2362 return 0; 2371 return 0;
2363} 2372}
2364 2373
2374/* return bitmask of enabled lanes, lane0 being the lsb */
2365static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) 2375static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
2366{ 2376{
2367 unsigned lanes = 0; 2377 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2378 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2379 unsigned mask = 0;
2380 int i;
2368 2381
2369 if (dssdev->phy.dsi.clk_lane != 0) 2382 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2370 lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); 2383 if (dsi->lanes[i].function != DSI_LANE_UNUSED)
2371 if (dssdev->phy.dsi.data1_lane != 0) 2384 mask |= 1 << i;
2372 lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); 2385 }
2373 if (dssdev->phy.dsi.data2_lane != 0)
2374 lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1);
2375 if (dssdev->phy.dsi.data3_lane != 0)
2376 lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1);
2377 if (dssdev->phy.dsi.data4_lane != 0)
2378 lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1);
2379 2386
2380 return lanes; 2387 return mask;
2381} 2388}
2382 2389
2383static int dsi_cio_init(struct omap_dss_device *dssdev) 2390static int dsi_cio_init(struct omap_dss_device *dssdev)
@@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
2385 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 2392 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2386 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 2393 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2387 int r; 2394 int r;
2388 int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
2389 u32 l; 2395 u32 l;
2390 2396
2391 DSSDBGF(); 2397 DSSDBGF();
@@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
2407 goto err_scp_clk_dom; 2413 goto err_scp_clk_dom;
2408 } 2414 }
2409 2415
2410 dsi_set_lane_config(dssdev); 2416 r = dsi_set_lane_config(dssdev);
2417 if (r)
2418 goto err_scp_clk_dom;
2411 2419
2412 /* set TX STOP MODE timer to maximum for this operation */ 2420 /* set TX STOP MODE timer to maximum for this operation */
2413 l = dsi_read_reg(dsidev, DSI_TIMING1); 2421 l = dsi_read_reg(dsidev, DSI_TIMING1);
@@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
2418 dsi_write_reg(dsidev, DSI_TIMING1, l); 2426 dsi_write_reg(dsidev, DSI_TIMING1, l);
2419 2427
2420 if (dsi->ulps_enabled) { 2428 if (dsi->ulps_enabled) {
2421 u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; 2429 unsigned mask_p;
2430 int i;
2422 2431
2423 DSSDBG("manual ulps exit\n"); 2432 DSSDBG("manual ulps exit\n");
2424 2433
@@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
2427 * ULPS exit sequence, as after reset the DSS HW thinks 2436 * ULPS exit sequence, as after reset the DSS HW thinks
2428 * that we are not in ULPS mode, and refuses to send the 2437 * that we are not in ULPS mode, and refuses to send the
2429 * sequence. So we need to send the ULPS exit sequence 2438 * sequence. So we need to send the ULPS exit sequence
2430 * manually. 2439 * manually by setting positive lines high and negative lines
2440 * low for 1ms.
2431 */ 2441 */
2432 2442
2433 if (num_data_lanes_dssdev > 2) 2443 mask_p = 0;
2434 lane_mask |= DSI_DATA3_P;
2435 2444
2436 if (num_data_lanes_dssdev > 3) 2445 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2437 lane_mask |= DSI_DATA4_P; 2446 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
2447 continue;
2448 mask_p |= 1 << i;
2449 }
2438 2450
2439 dsi_cio_enable_lane_override(dssdev, lane_mask); 2451 dsi_cio_enable_lane_override(dssdev, mask_p, 0);
2440 } 2452 }
2441 2453
2442 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); 2454 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
2913 2925
2914 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ 2926 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
2915 2927
2928 /* flush posted write */
2929 dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2930
2916 return 0; 2931 return 0;
2917} 2932}
2918 2933
@@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
3513{ 3528{
3514 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 3529 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3515 DECLARE_COMPLETION_ONSTACK(completion); 3530 DECLARE_COMPLETION_ONSTACK(completion);
3516 int r; 3531 int r, i;
3532 unsigned mask;
3517 3533
3518 DSSDBGF(); 3534 DSSDBGF();
3519 3535
@@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
3524 if (dsi->ulps_enabled) 3540 if (dsi->ulps_enabled)
3525 return 0; 3541 return 0;
3526 3542
3543 /* DDR_CLK_ALWAYS_ON */
3527 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { 3544 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
3528 DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); 3545 dsi_if_enable(dsidev, 0);
3529 return -EIO; 3546 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
3547 dsi_if_enable(dsidev, 1);
3530 } 3548 }
3531 3549
3532 dsi_sync_vc(dsidev, 0); 3550 dsi_sync_vc(dsidev, 0);
@@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
3556 if (r) 3574 if (r)
3557 return r; 3575 return r;
3558 3576
3577 mask = 0;
3578
3579 for (i = 0; i < dsi->num_lanes_supported; ++i) {
3580 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
3581 continue;
3582 mask |= 1 << i;
3583 }
3559 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ 3584 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
3560 /* LANEx_ULPS_SIG2 */ 3585 /* LANEx_ULPS_SIG2 */
3561 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), 3586 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
3562 7, 5); 3587
3588 /* flush posted write and wait for SCP interface to finish the write */
3589 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3563 3590
3564 if (wait_for_completion_timeout(&completion, 3591 if (wait_for_completion_timeout(&completion,
3565 msecs_to_jiffies(1000)) == 0) { 3592 msecs_to_jiffies(1000)) == 0) {
@@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
3572 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); 3599 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3573 3600
3574 /* Reset LANEx_ULPS_SIG2 */ 3601 /* Reset LANEx_ULPS_SIG2 */
3575 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), 3602 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
3576 7, 5); 3603
3604 /* flush posted write and wait for SCP interface to finish the write */
3605 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3577 3606
3578 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); 3607 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
3579 3608
@@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
3836static void dsi_proto_timings(struct omap_dss_device *dssdev) 3865static void dsi_proto_timings(struct omap_dss_device *dssdev)
3837{ 3866{
3838 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 3867 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3868 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3839 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; 3869 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
3840 unsigned tclk_pre, tclk_post; 3870 unsigned tclk_pre, tclk_post;
3841 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; 3871 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
@@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
3843 unsigned ddr_clk_pre, ddr_clk_post; 3873 unsigned ddr_clk_pre, ddr_clk_post;
3844 unsigned enter_hs_mode_lat, exit_hs_mode_lat; 3874 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
3845 unsigned ths_eot; 3875 unsigned ths_eot;
3846 int ndl = dsi_get_num_data_lanes_dssdev(dssdev); 3876 int ndl = dsi->num_lanes_used - 1;
3847 u32 r; 3877 u32 r;
3848 3878
3849 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); 3879 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
@@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
3945 } 3975 }
3946} 3976}
3947 3977
3948int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) 3978int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
3949{ 3979{
3950 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 3980 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3951 int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); 3981 int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
3952 u8 data_type; 3982 u8 data_type;
3953 u16 word_count; 3983 u16 word_count;
3984 int r;
3954 3985
3955 switch (dssdev->panel.dsi_pix_fmt) { 3986 if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
3956 case OMAP_DSS_DSI_FMT_RGB888: 3987 switch (dssdev->panel.dsi_pix_fmt) {
3957 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; 3988 case OMAP_DSS_DSI_FMT_RGB888:
3958 break; 3989 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
3959 case OMAP_DSS_DSI_FMT_RGB666: 3990 break;
3960 data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; 3991 case OMAP_DSS_DSI_FMT_RGB666:
3961 break; 3992 data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
3962 case OMAP_DSS_DSI_FMT_RGB666_PACKED: 3993 break;
3963 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; 3994 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
3964 break; 3995 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
3965 case OMAP_DSS_DSI_FMT_RGB565: 3996 break;
3966 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; 3997 case OMAP_DSS_DSI_FMT_RGB565:
3967 break; 3998 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
3968 default: 3999 break;
3969 BUG(); 4000 default:
3970 }; 4001 BUG();
4002 };
3971 4003
3972 dsi_if_enable(dsidev, false); 4004 dsi_if_enable(dsidev, false);
3973 dsi_vc_enable(dsidev, channel, false); 4005 dsi_vc_enable(dsidev, channel, false);
3974 4006
3975 /* MODE, 1 = video mode */ 4007 /* MODE, 1 = video mode */
3976 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); 4008 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
3977 4009
3978 word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); 4010 word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
3979 4011
3980 dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); 4012 dsi_vc_write_long_header(dsidev, channel, data_type,
4013 word_count, 0);
3981 4014
3982 dsi_vc_enable(dsidev, channel, true); 4015 dsi_vc_enable(dsidev, channel, true);
3983 dsi_if_enable(dsidev, true); 4016 dsi_if_enable(dsidev, true);
4017 }
3984 4018
3985 dssdev->manager->enable(dssdev->manager); 4019 r = dss_mgr_enable(dssdev->manager);
4020 if (r) {
4021 if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
4022 dsi_if_enable(dsidev, false);
4023 dsi_vc_enable(dsidev, channel, false);
4024 }
4025
4026 return r;
4027 }
3986 4028
3987 return 0; 4029 return 0;
3988} 4030}
3989EXPORT_SYMBOL(dsi_video_mode_enable); 4031EXPORT_SYMBOL(dsi_enable_video_output);
3990 4032
3991void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) 4033void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
3992{ 4034{
3993 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 4035 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3994 4036
3995 dsi_if_enable(dsidev, false); 4037 if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
3996 dsi_vc_enable(dsidev, channel, false); 4038 dsi_if_enable(dsidev, false);
4039 dsi_vc_enable(dsidev, channel, false);
3997 4040
3998 /* MODE, 0 = command mode */ 4041 /* MODE, 0 = command mode */
3999 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); 4042 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
4000 4043
4001 dsi_vc_enable(dsidev, channel, true); 4044 dsi_vc_enable(dsidev, channel, true);
4002 dsi_if_enable(dsidev, true); 4045 dsi_if_enable(dsidev, true);
4046 }
4003 4047
4004 dssdev->manager->disable(dssdev->manager); 4048 dss_mgr_disable(dssdev->manager);
4005} 4049}
4006EXPORT_SYMBOL(dsi_video_mode_disable); 4050EXPORT_SYMBOL(dsi_disable_video_output);
4007 4051
4008static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, 4052static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
4009 u16 x, u16 y, u16 w, u16 h) 4053 u16 w, u16 h)
4010{ 4054{
4011 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 4055 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4012 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 4056 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
4021 const unsigned channel = dsi->update_channel; 4065 const unsigned channel = dsi->update_channel;
4022 const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); 4066 const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
4023 4067
4024 DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", 4068 DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
4025 x, y, w, h);
4026 4069
4027 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); 4070 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
4028 4071
@@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
4070 msecs_to_jiffies(250)); 4113 msecs_to_jiffies(250));
4071 BUG_ON(r == 0); 4114 BUG_ON(r == 0);
4072 4115
4073 dss_start_update(dssdev); 4116 dss_mgr_start_update(dssdev->manager);
4074 4117
4075 if (dsi->te_enabled) { 4118 if (dsi->te_enabled) {
4076 /* disable LP_RX_TO, so that we can receive TE. Time to wait 4119 /* disable LP_RX_TO, so that we can receive TE. Time to wait
@@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
4146#endif 4189#endif
4147} 4190}
4148 4191
4149int omap_dsi_prepare_update(struct omap_dss_device *dssdev, 4192int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
4150 u16 *x, u16 *y, u16 *w, u16 *h, 4193 void (*callback)(int, void *), void *data)
4151 bool enlarge_update_area)
4152{ 4194{
4153 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 4195 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4196 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4154 u16 dw, dh; 4197 u16 dw, dh;
4155 4198
4156 dssdev->driver->get_resolution(dssdev, &dw, &dh);
4157
4158 if (*x > dw || *y > dh)
4159 return -EINVAL;
4160
4161 if (*x + *w > dw)
4162 return -EINVAL;
4163
4164 if (*y + *h > dh)
4165 return -EINVAL;
4166
4167 if (*w == 1)
4168 return -EINVAL;
4169
4170 if (*w == 0 || *h == 0)
4171 return -EINVAL;
4172
4173 dsi_perf_mark_setup(dsidev); 4199 dsi_perf_mark_setup(dsidev);
4174 4200
4175 dss_setup_partial_planes(dssdev, x, y, w, h,
4176 enlarge_update_area);
4177 dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
4178
4179 return 0;
4180}
4181EXPORT_SYMBOL(omap_dsi_prepare_update);
4182
4183int omap_dsi_update(struct omap_dss_device *dssdev,
4184 int channel,
4185 u16 x, u16 y, u16 w, u16 h,
4186 void (*callback)(int, void *), void *data)
4187{
4188 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4189 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4190
4191 dsi->update_channel = channel; 4201 dsi->update_channel = channel;
4192 4202
4193 /* OMAP DSS cannot send updates of odd widths.
4194 * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
4195 * here to make sure we catch erroneous updates. Otherwise we'll only
4196 * see rather obscure HW error happening, as DSS halts. */
4197 BUG_ON(x % 2 == 1);
4198
4199 dsi->framedone_callback = callback; 4203 dsi->framedone_callback = callback;
4200 dsi->framedone_data = data; 4204 dsi->framedone_data = data;
4201 4205
4202 dsi->update_region.x = x; 4206 dssdev->driver->get_resolution(dssdev, &dw, &dh);
4203 dsi->update_region.y = y;
4204 dsi->update_region.w = w;
4205 dsi->update_region.h = h;
4206 dsi->update_region.device = dssdev;
4207 4207
4208 dsi_update_screen_dispc(dssdev, x, y, w, h); 4208#ifdef DEBUG
4209 dsi->update_bytes = dw * dh *
4210 dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
4211#endif
4212 dsi_update_screen_dispc(dssdev, dw, dh);
4209 4213
4210 return 0; 4214 return 0;
4211} 4215}
@@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
4218 int r; 4222 int r;
4219 4223
4220 if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { 4224 if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
4225 u16 dw, dh;
4221 u32 irq; 4226 u32 irq;
4222 struct omap_video_timings timings = { 4227 struct omap_video_timings timings = {
4223 .hsw = 1, 4228 .hsw = 1,
@@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
4228 .vbp = 0, 4233 .vbp = 0,
4229 }; 4234 };
4230 4235
4236 dssdev->driver->get_resolution(dssdev, &dw, &dh);
4237 timings.x_res = dw;
4238 timings.y_res = dh;
4239
4231 irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? 4240 irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
4232 DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; 4241 DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
4233 4242
@@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
4330 int dsi_module = dsi_get_dsidev_id(dsidev); 4339 int dsi_module = dsi_get_dsidev_id(dsidev);
4331 int r; 4340 int r;
4332 4341
4342 r = dsi_parse_lane_config(dssdev);
4343 if (r) {
4344 DSSERR("illegal lane config");
4345 goto err0;
4346 }
4347
4333 r = dsi_pll_init(dsidev, true, true); 4348 r = dsi_pll_init(dsidev, true, true);
4334 if (r) 4349 if (r)
4335 goto err0; 4350 goto err0;
@@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
4521{ 4536{
4522 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); 4537 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4523 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 4538 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4524 int dsi_module = dsi_get_dsidev_id(dsidev);
4525 4539
4526 DSSDBG("DSI init\n"); 4540 DSSDBG("DSI init\n");
4527 4541
@@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
4543 dsi->vdds_dsi_reg = vdds_dsi; 4557 dsi->vdds_dsi_reg = vdds_dsi;
4544 } 4558 }
4545 4559
4546 if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) {
4547 DSSERR("DSI%d can't support more than %d data lanes\n",
4548 dsi_module + 1, dsi->num_data_lanes);
4549 return -EINVAL;
4550 }
4551
4552 return 0; 4560 return 0;
4553} 4561}
4554 4562
@@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
4771 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", 4779 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
4772 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 4780 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4773 4781
4774 dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); 4782 /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
4783 * of data to 3 by default */
4784 if (dss_has_feature(FEAT_DSI_GNQ))
4785 /* NB_DATA_LANES */
4786 dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
4787 else
4788 dsi->num_lanes_supported = 3;
4775 4789
4776 dsi_runtime_put(dsidev); 4790 dsi_runtime_put(dsidev);
4777 4791
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 57a52eecee91..32ff69fb3333 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void);
163struct regulator *dss_get_vdds_dsi(void); 163struct regulator *dss_get_vdds_dsi(void);
164struct regulator *dss_get_vdds_sdi(void); 164struct regulator *dss_get_vdds_sdi(void);
165 165
166/* apply */
167void dss_apply_init(void);
168int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr);
169int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
170void dss_mgr_start_update(struct omap_overlay_manager *mgr);
171int omap_dss_mgr_apply(struct omap_overlay_manager *mgr);
172
173int dss_mgr_enable(struct omap_overlay_manager *mgr);
174void dss_mgr_disable(struct omap_overlay_manager *mgr);
175int dss_mgr_set_info(struct omap_overlay_manager *mgr,
176 struct omap_overlay_manager_info *info);
177void dss_mgr_get_info(struct omap_overlay_manager *mgr,
178 struct omap_overlay_manager_info *info);
179int dss_mgr_set_device(struct omap_overlay_manager *mgr,
180 struct omap_dss_device *dssdev);
181int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
182
183bool dss_ovl_is_enabled(struct omap_overlay *ovl);
184int dss_ovl_enable(struct omap_overlay *ovl);
185int dss_ovl_disable(struct omap_overlay *ovl);
186int dss_ovl_set_info(struct omap_overlay *ovl,
187 struct omap_overlay_info *info);
188void dss_ovl_get_info(struct omap_overlay *ovl,
189 struct omap_overlay_info *info);
190int dss_ovl_set_manager(struct omap_overlay *ovl,
191 struct omap_overlay_manager *mgr);
192int dss_ovl_unset_manager(struct omap_overlay *ovl);
193
166/* display */ 194/* display */
167int dss_suspend_all_devices(void); 195int dss_suspend_all_devices(void);
168int dss_resume_all_devices(void); 196int dss_resume_all_devices(void);
@@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
181/* manager */ 209/* manager */
182int dss_init_overlay_managers(struct platform_device *pdev); 210int dss_init_overlay_managers(struct platform_device *pdev);
183void dss_uninit_overlay_managers(struct platform_device *pdev); 211void dss_uninit_overlay_managers(struct platform_device *pdev);
184int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); 212int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
185void dss_setup_partial_planes(struct omap_dss_device *dssdev, 213 const struct omap_overlay_manager_info *info);
186 u16 *x, u16 *y, u16 *w, u16 *h, 214int dss_mgr_check(struct omap_overlay_manager *mgr,
187 bool enlarge_update_area); 215 struct omap_dss_device *dssdev,
188void dss_start_update(struct omap_dss_device *dssdev); 216 struct omap_overlay_manager_info *info,
217 struct omap_overlay_info **overlay_infos);
189 218
190/* overlay */ 219/* overlay */
191void dss_init_overlays(struct platform_device *pdev); 220void dss_init_overlays(struct platform_device *pdev);
192void dss_uninit_overlays(struct platform_device *pdev); 221void dss_uninit_overlays(struct platform_device *pdev);
193int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
194void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); 222void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
195#ifdef L4_EXAMPLE
196void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
197#endif
198void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); 223void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
224int dss_ovl_simple_check(struct omap_overlay *ovl,
225 const struct omap_overlay_info *info);
226int dss_ovl_check(struct omap_overlay *ovl,
227 struct omap_overlay_info *info, struct omap_dss_device *dssdev);
199 228
200/* DSS */ 229/* DSS */
201int dss_init_platform_driver(void); 230int dss_init_platform_driver(void);
@@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
399 struct dispc_clock_info *cinfo); 428 struct dispc_clock_info *cinfo);
400 429
401 430
431void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
402u32 dispc_ovl_get_fifo_size(enum omap_plane plane); 432u32 dispc_ovl_get_fifo_size(enum omap_plane plane);
403u32 dispc_ovl_get_burst_size(enum omap_plane plane); 433u32 dispc_ovl_get_burst_size(enum omap_plane plane);
404int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, 434int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
405 bool ilace, enum omap_channel channel, bool replication, 435 bool ilace, bool replication);
406 u32 fifo_low, u32 fifo_high);
407int dispc_ovl_enable(enum omap_plane plane, bool enable); 436int dispc_ovl_enable(enum omap_plane plane, bool enable);
408 437void dispc_ovl_set_channel_out(enum omap_plane plane,
438 enum omap_channel channel);
409 439
410void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); 440void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable);
411void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); 441void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
412void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); 442u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
413void dispc_mgr_set_cpr_coef(enum omap_channel channel, 443u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
414 struct omap_dss_cpr_coefs *coefs);
415bool dispc_mgr_go_busy(enum omap_channel channel); 444bool dispc_mgr_go_busy(enum omap_channel channel);
416void dispc_mgr_go(enum omap_channel channel); 445void dispc_mgr_go(enum omap_channel channel);
446bool dispc_mgr_is_enabled(enum omap_channel channel);
417void dispc_mgr_enable(enum omap_channel channel, bool enable); 447void dispc_mgr_enable(enum omap_channel channel, bool enable);
418bool dispc_mgr_is_channel_enabled(enum omap_channel channel); 448bool dispc_mgr_is_channel_enabled(enum omap_channel channel);
419void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); 449void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode);
@@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);
421void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); 451void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
422void dispc_mgr_set_lcd_display_type(enum omap_channel channel, 452void dispc_mgr_set_lcd_display_type(enum omap_channel channel,
423 enum omap_lcd_display_type type); 453 enum omap_lcd_display_type type);
424void dispc_mgr_set_default_color(enum omap_channel channel, u32 color);
425u32 dispc_mgr_get_default_color(enum omap_channel channel);
426void dispc_mgr_set_trans_key(enum omap_channel ch,
427 enum omap_dss_trans_key_type type,
428 u32 trans_key);
429void dispc_mgr_get_trans_key(enum omap_channel ch,
430 enum omap_dss_trans_key_type *type,
431 u32 *trans_key);
432void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable);
433void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable);
434bool dispc_mgr_trans_key_enabled(enum omap_channel ch);
435bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch);
436void dispc_mgr_set_lcd_timings(enum omap_channel channel, 454void dispc_mgr_set_lcd_timings(enum omap_channel channel,
437 struct omap_video_timings *timings); 455 struct omap_video_timings *timings);
438void dispc_mgr_set_pol_freq(enum omap_channel channel, 456void dispc_mgr_set_pol_freq(enum omap_channel channel,
@@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel,
443 struct dispc_clock_info *cinfo); 461 struct dispc_clock_info *cinfo);
444int dispc_mgr_get_clock_div(enum omap_channel channel, 462int dispc_mgr_get_clock_div(enum omap_channel channel,
445 struct dispc_clock_info *cinfo); 463 struct dispc_clock_info *cinfo);
464void dispc_mgr_setup(enum omap_channel channel,
465 struct omap_overlay_manager_info *info);
446 466
447/* VENC */ 467/* VENC */
448#ifdef CONFIG_OMAP2_DSS_VENC 468#ifdef CONFIG_OMAP2_DSS_VENC
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index b402699168a5..afcb59301c37 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = {
304 [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, 304 [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
305 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, 305 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
306 [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, 306 [FEAT_PARAM_DOWNSCALE] = { 1, 2 },
307 /*
308 * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
309 * scaler cannot scale a image with width more than 768.
310 */
311 [FEAT_PARAM_LINEWIDTH] = { 1, 768 },
307}; 312};
308 313
309static const struct dss_param_range omap3_dss_param_range[] = { 314static const struct dss_param_range omap3_dss_param_range[] = {
@@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
316 [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, 321 [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
317 [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, 322 [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
318 [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, 323 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
324 [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
319}; 325};
320 326
321static const struct dss_param_range omap4_dss_param_range[] = { 327static const struct dss_param_range omap4_dss_param_range[] = {
@@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
328 [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, 334 [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
329 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, 335 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
330 [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, 336 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
337 [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
331}; 338};
332 339
333/* OMAP2 DSS Features */ 340/* OMAP2 DSS Features */
@@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
465 .dump_core = ti_hdmi_4xxx_core_dump, 472 .dump_core = ti_hdmi_4xxx_core_dump,
466 .dump_pll = ti_hdmi_4xxx_pll_dump, 473 .dump_pll = ti_hdmi_4xxx_pll_dump,
467 .dump_phy = ti_hdmi_4xxx_phy_dump, 474 .dump_phy = ti_hdmi_4xxx_phy_dump,
475#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
476 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
477 .audio_enable = ti_hdmi_4xxx_wp_audio_enable,
478#endif
468 479
469}; 480};
470 481
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 6a6c05dd45ce..cd833bbaac3d 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -86,6 +86,7 @@ enum dss_range_param {
86 FEAT_PARAM_DSIPLL_FINT, 86 FEAT_PARAM_DSIPLL_FINT,
87 FEAT_PARAM_DSIPLL_LPDIV, 87 FEAT_PARAM_DSIPLL_LPDIV,
88 FEAT_PARAM_DOWNSCALE, 88 FEAT_PARAM_DOWNSCALE,
89 FEAT_PARAM_LINEWIDTH,
89}; 90};
90 91
91/* DSS Feature Functions */ 92/* DSS Feature Functions */
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index c56378c555b0..b4c270edb915 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
333 if (r) 333 if (r)
334 return r; 334 return r;
335 335
336 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); 336 dss_mgr_disable(dssdev->manager);
337 337
338 p = &dssdev->panel.timings; 338 p = &dssdev->panel.timings;
339 339
@@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
387 387
388 hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); 388 hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1);
389 389
390 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); 390 r = dss_mgr_enable(dssdev->manager);
391 if (r)
392 goto err_mgr_enable;
391 393
392 return 0; 394 return 0;
395
396err_mgr_enable:
397 hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
398 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
399 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
393err: 400err:
394 hdmi_runtime_put(); 401 hdmi_runtime_put();
395 return -EIO; 402 return -EIO;
@@ -397,7 +404,7 @@ err:
397 404
398static void hdmi_power_off(struct omap_dss_device *dssdev) 405static void hdmi_power_off(struct omap_dss_device *dssdev)
399{ 406{
400 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); 407 dss_mgr_disable(dssdev->manager);
401 408
402 hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); 409 hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
403 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); 410 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
@@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
554#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ 561#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
555 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) 562 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
556 563
557static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, 564static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
558 struct snd_pcm_substream *substream, 565 struct snd_soc_dai *dai)
566{
567 struct snd_soc_pcm_runtime *rtd = substream->private_data;
568 struct snd_soc_codec *codec = rtd->codec;
569 struct platform_device *pdev = to_platform_device(codec->dev);
570 struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
571 int err = 0;
572
573 if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) {
574 dev_err(&pdev->dev, "Cannot enable/disable audio\n");
575 return -ENODEV;
576 }
577
578 switch (cmd) {
579 case SNDRV_PCM_TRIGGER_START:
580 case SNDRV_PCM_TRIGGER_RESUME:
581 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
582 ip_data->ops->audio_enable(ip_data, true);
583 break;
584 case SNDRV_PCM_TRIGGER_STOP:
585 case SNDRV_PCM_TRIGGER_SUSPEND:
586 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
587 ip_data->ops->audio_enable(ip_data, false);
588 break;
589 default:
590 err = -EINVAL;
591 }
592 return err;
593}
594
595static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
559 struct snd_pcm_hw_params *params, 596 struct snd_pcm_hw_params *params,
560 struct snd_soc_dai *dai) 597 struct snd_soc_dai *dai)
561{ 598{
599 struct snd_soc_pcm_runtime *rtd = substream->private_data;
600 struct snd_soc_codec *codec = rtd->codec;
601 struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
562 struct hdmi_audio_format audio_format; 602 struct hdmi_audio_format audio_format;
563 struct hdmi_audio_dma audio_dma; 603 struct hdmi_audio_dma audio_dma;
564 struct hdmi_core_audio_config core_cfg; 604 struct hdmi_core_audio_config core_cfg;
@@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream,
698 return 0; 738 return 0;
699} 739}
700 740
741static int hdmi_audio_codec_probe(struct snd_soc_codec *codec)
742{
743 struct hdmi_ip_data *priv = &hdmi.ip_data;
744
745 snd_soc_codec_set_drvdata(codec, priv);
746 return 0;
747}
748
701static struct snd_soc_codec_driver hdmi_audio_codec_drv = { 749static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
750 .probe = hdmi_audio_codec_probe,
702}; 751};
703 752
704static struct snd_soc_dai_ops hdmi_audio_codec_ops = { 753static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 6e63845cc7d7..d1858e71c64e 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -26,17 +26,15 @@
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/spinlock.h>
30#include <linux/jiffies.h> 29#include <linux/jiffies.h>
31 30
32#include <video/omapdss.h> 31#include <video/omapdss.h>
33#include <plat/cpu.h>
34 32
35#include "dss.h" 33#include "dss.h"
36#include "dss_features.h" 34#include "dss_features.h"
37 35
38static int num_managers; 36static int num_managers;
39static struct list_head manager_list; 37static struct omap_overlay_manager *managers;
40 38
41static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) 39static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
42{ 40{
@@ -106,7 +104,11 @@ put_device:
106static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, 104static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
107 char *buf) 105 char *buf)
108{ 106{
109 return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); 107 struct omap_overlay_manager_info info;
108
109 mgr->get_manager_info(mgr, &info);
110
111 return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
110} 112}
111 113
112static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, 114static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
@@ -144,8 +146,11 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
144 char *buf) 146 char *buf)
145{ 147{
146 enum omap_dss_trans_key_type key_type; 148 enum omap_dss_trans_key_type key_type;
149 struct omap_overlay_manager_info info;
150
151 mgr->get_manager_info(mgr, &info);
147 152
148 key_type = mgr->info.trans_key_type; 153 key_type = info.trans_key_type;
149 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); 154 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
150 155
151 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); 156 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
@@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
185static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, 190static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
186 char *buf) 191 char *buf)
187{ 192{
188 return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); 193 struct omap_overlay_manager_info info;
194
195 mgr->get_manager_info(mgr, &info);
196
197 return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
189} 198}
190 199
191static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, 200static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
@@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
217static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, 226static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
218 char *buf) 227 char *buf)
219{ 228{
220 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); 229 struct omap_overlay_manager_info info;
230
231 mgr->get_manager_info(mgr, &info);
232
233 return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
221} 234}
222 235
223static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, 236static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
@@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
249static ssize_t manager_alpha_blending_enabled_show( 262static ssize_t manager_alpha_blending_enabled_show(
250 struct omap_overlay_manager *mgr, char *buf) 263 struct omap_overlay_manager *mgr, char *buf)
251{ 264{
265 struct omap_overlay_manager_info info;
266
267 mgr->get_manager_info(mgr, &info);
268
252 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); 269 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
253 270
254 return snprintf(buf, PAGE_SIZE, "%d\n", 271 return snprintf(buf, PAGE_SIZE, "%d\n",
255 mgr->info.partial_alpha_enabled); 272 info.partial_alpha_enabled);
256} 273}
257 274
258static ssize_t manager_alpha_blending_enabled_store( 275static ssize_t manager_alpha_blending_enabled_store(
@@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store(
287static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, 304static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
288 char *buf) 305 char *buf)
289{ 306{
290 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); 307 struct omap_overlay_manager_info info;
308
309 mgr->get_manager_info(mgr, &info);
310
311 return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
291} 312}
292 313
293static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, 314static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
@@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = {
469 .default_attrs = manager_sysfs_attrs, 490 .default_attrs = manager_sysfs_attrs,
470}; 491};
471 492
472/*
473 * We have 4 levels of cache for the dispc settings. First two are in SW and
474 * the latter two in HW.
475 *
476 * +--------------------+
477 * |overlay/manager_info|
478 * +--------------------+
479 * v
480 * apply()
481 * v
482 * +--------------------+
483 * | dss_cache |
484 * +--------------------+
485 * v
486 * configure()
487 * v
488 * +--------------------+
489 * | shadow registers |
490 * +--------------------+
491 * v
492 * VFP or lcd/digit_enable
493 * v
494 * +--------------------+
495 * | registers |
496 * +--------------------+
497 */
498
499struct overlay_cache_data {
500 /* If true, cache changed, but not written to shadow registers. Set
501 * in apply(), cleared when registers written. */
502 bool dirty;
503 /* If true, shadow registers contain changed values not yet in real
504 * registers. Set when writing to shadow registers, cleared at
505 * VSYNC/EVSYNC */
506 bool shadow_dirty;
507
508 bool enabled;
509
510 struct omap_overlay_info info;
511
512 enum omap_channel channel;
513 bool replication;
514 bool ilace;
515
516 u32 fifo_low;
517 u32 fifo_high;
518};
519
520struct manager_cache_data {
521 /* If true, cache changed, but not written to shadow registers. Set
522 * in apply(), cleared when registers written. */
523 bool dirty;
524 /* If true, shadow registers contain changed values not yet in real
525 * registers. Set when writing to shadow registers, cleared at
526 * VSYNC/EVSYNC */
527 bool shadow_dirty;
528
529 struct omap_overlay_manager_info info;
530
531 bool manual_update;
532 bool do_manual_update;
533
534 /* manual update region */
535 u16 x, y, w, h;
536
537 /* enlarge the update area if the update area contains scaled
538 * overlays */
539 bool enlarge_update_area;
540};
541
542static struct {
543 spinlock_t lock;
544 struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
545 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
546
547 bool irq_enabled;
548} dss_cache;
549
550
551
552static int omap_dss_set_device(struct omap_overlay_manager *mgr,
553 struct omap_dss_device *dssdev)
554{
555 int i;
556 int r;
557
558 if (dssdev->manager) {
559 DSSERR("display '%s' already has a manager '%s'\n",
560 dssdev->name, dssdev->manager->name);
561 return -EINVAL;
562 }
563
564 if ((mgr->supported_displays & dssdev->type) == 0) {
565 DSSERR("display '%s' does not support manager '%s'\n",
566 dssdev->name, mgr->name);
567 return -EINVAL;
568 }
569
570 for (i = 0; i < mgr->num_overlays; i++) {
571 struct omap_overlay *ovl = mgr->overlays[i];
572
573 if (ovl->manager != mgr || !ovl->info.enabled)
574 continue;
575
576 r = dss_check_overlay(ovl, dssdev);
577 if (r)
578 return r;
579 }
580
581 dssdev->manager = mgr;
582 mgr->device = dssdev;
583 mgr->device_changed = true;
584
585 return 0;
586}
587
588static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
589{
590 if (!mgr->device) {
591 DSSERR("failed to unset display, display not set.\n");
592 return -EINVAL;
593 }
594
595 /*
596 * Don't allow currently enabled displays to have the overlay manager
597 * pulled out from underneath them
598 */
599 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED)
600 return -EINVAL;
601
602 mgr->device->manager = NULL;
603 mgr->device = NULL;
604 mgr->device_changed = true;
605
606 return 0;
607}
608
609static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) 493static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
610{ 494{
611 unsigned long timeout = msecs_to_jiffies(500); 495 unsigned long timeout = msecs_to_jiffies(500);
@@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
624 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 508 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
625} 509}
626 510
627static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) 511int dss_init_overlay_managers(struct platform_device *pdev)
628{
629 unsigned long timeout = msecs_to_jiffies(500);
630 struct manager_cache_data *mc;
631 u32 irq;
632 int r;
633 int i;
634 struct omap_dss_device *dssdev = mgr->device;
635
636 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
637 return 0;
638
639 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
640 return 0;
641
642 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
643 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
644 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
645 } else {
646 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
647 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
648 }
649
650 mc = &dss_cache.manager_cache[mgr->id];
651 i = 0;
652 while (1) {
653 unsigned long flags;
654 bool shadow_dirty, dirty;
655
656 spin_lock_irqsave(&dss_cache.lock, flags);
657 dirty = mc->dirty;
658 shadow_dirty = mc->shadow_dirty;
659 spin_unlock_irqrestore(&dss_cache.lock, flags);
660
661 if (!dirty && !shadow_dirty) {
662 r = 0;
663 break;
664 }
665
666 /* 4 iterations is the worst case:
667 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
668 * 2 - first VSYNC, dirty = true
669 * 3 - dirty = false, shadow_dirty = true
670 * 4 - shadow_dirty = false */
671 if (i++ == 3) {
672 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
673 mgr->id);
674 r = 0;
675 break;
676 }
677
678 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
679 if (r == -ERESTARTSYS)
680 break;
681
682 if (r) {
683 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
684 break;
685 }
686 }
687
688 return r;
689}
690
691int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
692{
693 unsigned long timeout = msecs_to_jiffies(500);
694 struct overlay_cache_data *oc;
695 struct omap_dss_device *dssdev;
696 u32 irq;
697 int r;
698 int i;
699
700 if (!ovl->manager)
701 return 0;
702
703 dssdev = ovl->manager->device;
704
705 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
706 return 0;
707
708 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
709 return 0;
710
711 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
712 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
713 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
714 } else {
715 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
716 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
717 }
718
719 oc = &dss_cache.overlay_cache[ovl->id];
720 i = 0;
721 while (1) {
722 unsigned long flags;
723 bool shadow_dirty, dirty;
724
725 spin_lock_irqsave(&dss_cache.lock, flags);
726 dirty = oc->dirty;
727 shadow_dirty = oc->shadow_dirty;
728 spin_unlock_irqrestore(&dss_cache.lock, flags);
729
730 if (!dirty && !shadow_dirty) {
731 r = 0;
732 break;
733 }
734
735 /* 4 iterations is the worst case:
736 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
737 * 2 - first VSYNC, dirty = true
738 * 3 - dirty = false, shadow_dirty = true
739 * 4 - shadow_dirty = false */
740 if (i++ == 3) {
741 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
742 ovl->id);
743 r = 0;
744 break;
745 }
746
747 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
748 if (r == -ERESTARTSYS)
749 break;
750
751 if (r) {
752 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
753 break;
754 }
755 }
756
757 return r;
758}
759
760static int overlay_enabled(struct omap_overlay *ovl)
761{
762 return ovl->info.enabled && ovl->manager && ovl->manager->device;
763}
764
765/* Is rect1 a subset of rect2? */
766static bool rectangle_subset(int x1, int y1, int w1, int h1,
767 int x2, int y2, int w2, int h2)
768{
769 if (x1 < x2 || y1 < y2)
770 return false;
771
772 if (x1 + w1 > x2 + w2)
773 return false;
774
775 if (y1 + h1 > y2 + h2)
776 return false;
777
778 return true;
779}
780
781/* Do rect1 and rect2 overlap? */
782static bool rectangle_intersects(int x1, int y1, int w1, int h1,
783 int x2, int y2, int w2, int h2)
784{
785 if (x1 >= x2 + w2)
786 return false;
787
788 if (x2 >= x1 + w1)
789 return false;
790
791 if (y1 >= y2 + h2)
792 return false;
793
794 if (y2 >= y1 + h1)
795 return false;
796
797 return true;
798}
799
800static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
801{
802 struct omap_overlay_info *oi = &oc->info;
803
804 if (oi->out_width != 0 && oi->width != oi->out_width)
805 return true;
806
807 if (oi->out_height != 0 && oi->height != oi->out_height)
808 return true;
809
810 return false;
811}
812
813static int configure_overlay(enum omap_plane plane)
814{ 512{
815 struct overlay_cache_data *c; 513 int i, r;
816 struct manager_cache_data *mc;
817 struct omap_overlay_info *oi, new_oi;
818 struct omap_overlay_manager_info *mi;
819 u16 outw, outh;
820 u16 x, y, w, h;
821 u32 paddr;
822 int r;
823 u16 orig_w, orig_h, orig_outw, orig_outh;
824 514
825 DSSDBGF("%d", plane); 515 num_managers = dss_feat_get_num_mgrs();
826 516
827 c = &dss_cache.overlay_cache[plane]; 517 managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
828 oi = &c->info; 518 GFP_KERNEL);
829 519
830 if (!c->enabled) { 520 BUG_ON(managers == NULL);
831 dispc_ovl_enable(plane, 0);
832 return 0;
833 }
834 521
835 mc = &dss_cache.manager_cache[c->channel]; 522 for (i = 0; i < num_managers; ++i) {
836 mi = &mc->info; 523 struct omap_overlay_manager *mgr = &managers[i];
837
838 x = oi->pos_x;
839 y = oi->pos_y;
840 w = oi->width;
841 h = oi->height;
842 outw = oi->out_width == 0 ? oi->width : oi->out_width;
843 outh = oi->out_height == 0 ? oi->height : oi->out_height;
844 paddr = oi->paddr;
845
846 orig_w = w;
847 orig_h = h;
848 orig_outw = outw;
849 orig_outh = outh;
850
851 if (mc->manual_update && mc->do_manual_update) {
852 unsigned bpp;
853 unsigned scale_x_m = w, scale_x_d = outw;
854 unsigned scale_y_m = h, scale_y_d = outh;
855
856 /* If the overlay is outside the update region, disable it */
857 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
858 x, y, outw, outh)) {
859 dispc_ovl_enable(plane, 0);
860 return 0;
861 }
862 524
863 switch (oi->color_mode) { 525 switch (i) {
864 case OMAP_DSS_COLOR_NV12: 526 case 0:
865 bpp = 8; 527 mgr->name = "lcd";
866 break; 528 mgr->id = OMAP_DSS_CHANNEL_LCD;
867 case OMAP_DSS_COLOR_RGB16:
868 case OMAP_DSS_COLOR_ARGB16:
869 case OMAP_DSS_COLOR_YUV2:
870 case OMAP_DSS_COLOR_UYVY:
871 case OMAP_DSS_COLOR_RGBA16:
872 case OMAP_DSS_COLOR_RGBX16:
873 case OMAP_DSS_COLOR_ARGB16_1555:
874 case OMAP_DSS_COLOR_XRGB16_1555:
875 bpp = 16;
876 break; 529 break;
877 530 case 1:
878 case OMAP_DSS_COLOR_RGB24P: 531 mgr->name = "tv";
879 bpp = 24; 532 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
880 break; 533 break;
881 534 case 2:
882 case OMAP_DSS_COLOR_RGB24U: 535 mgr->name = "lcd2";
883 case OMAP_DSS_COLOR_ARGB32: 536 mgr->id = OMAP_DSS_CHANNEL_LCD2;
884 case OMAP_DSS_COLOR_RGBA32:
885 case OMAP_DSS_COLOR_RGBX32:
886 bpp = 32;
887 break; 537 break;
888
889 default:
890 BUG();
891 } 538 }
892 539
893 if (mc->x > oi->pos_x) { 540 mgr->set_device = &dss_mgr_set_device;
894 x = 0; 541 mgr->unset_device = &dss_mgr_unset_device;
895 outw -= (mc->x - oi->pos_x); 542 mgr->apply = &omap_dss_mgr_apply;
896 paddr += (mc->x - oi->pos_x) * 543 mgr->set_manager_info = &dss_mgr_set_info;
897 scale_x_m / scale_x_d * bpp / 8; 544 mgr->get_manager_info = &dss_mgr_get_info;
898 } else { 545 mgr->wait_for_go = &dss_mgr_wait_for_go;
899 x = oi->pos_x - mc->x; 546 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
900 }
901
902 if (mc->y > oi->pos_y) {
903 y = 0;
904 outh -= (mc->y - oi->pos_y);
905 paddr += (mc->y - oi->pos_y) *
906 scale_y_m / scale_y_d *
907 oi->screen_width * bpp / 8;
908 } else {
909 y = oi->pos_y - mc->y;
910 }
911
912 if (mc->w < (x + outw))
913 outw -= (x + outw) - (mc->w);
914
915 if (mc->h < (y + outh))
916 outh -= (y + outh) - (mc->h);
917
918 w = w * outw / orig_outw;
919 h = h * outh / orig_outh;
920
921 /* YUV mode overlay's input width has to be even and the
922 * algorithm above may adjust the width to be odd.
923 *
924 * Here we adjust the width if needed, preferring to increase
925 * the width if the original width was bigger.
926 */
927 if ((w & 1) &&
928 (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
929 oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
930 if (orig_w > w)
931 w += 1;
932 else
933 w -= 1;
934 }
935 }
936
937 new_oi = *oi;
938
939 /* update new_oi members which could have been possibly updated */
940 new_oi.pos_x = x;
941 new_oi.pos_y = y;
942 new_oi.width = w;
943 new_oi.height = h;
944 new_oi.out_width = outw;
945 new_oi.out_height = outh;
946 new_oi.paddr = paddr;
947
948 r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel,
949 c->replication, c->fifo_low, c->fifo_high);
950 if (r) {
951 /* this shouldn't happen */
952 DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
953 dispc_ovl_enable(plane, 0);
954 return r;
955 }
956
957 dispc_ovl_enable(plane, 1);
958
959 return 0;
960}
961
962static void configure_manager(enum omap_channel channel)
963{
964 struct omap_overlay_manager_info *mi;
965
966 DSSDBGF("%d", channel);
967
968 /* picking info from the cache */
969 mi = &dss_cache.manager_cache[channel].info;
970
971 dispc_mgr_set_default_color(channel, mi->default_color);
972 dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
973 dispc_mgr_enable_trans_key(channel, mi->trans_enabled);
974 dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled);
975 if (dss_has_feature(FEAT_CPR)) {
976 dispc_mgr_enable_cpr(channel, mi->cpr_enable);
977 dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs);
978 }
979}
980
981/* configure_dispc() tries to write values from cache to shadow registers.
982 * It writes only to those managers/overlays that are not busy.
983 * returns 0 if everything could be written to shadow registers.
984 * returns 1 if not everything could be written to shadow registers. */
985static int configure_dispc(void)
986{
987 struct overlay_cache_data *oc;
988 struct manager_cache_data *mc;
989 const int num_ovls = dss_feat_get_num_ovls();
990 const int num_mgrs = dss_feat_get_num_mgrs();
991 int i;
992 int r;
993 bool mgr_busy[MAX_DSS_MANAGERS];
994 bool mgr_go[MAX_DSS_MANAGERS];
995 bool busy;
996
997 r = 0;
998 busy = false;
999
1000 for (i = 0; i < num_mgrs; i++) {
1001 mgr_busy[i] = dispc_mgr_go_busy(i);
1002 mgr_go[i] = false;
1003 }
1004
1005 /* Commit overlay settings */
1006 for (i = 0; i < num_ovls; ++i) {
1007 oc = &dss_cache.overlay_cache[i];
1008 mc = &dss_cache.manager_cache[oc->channel];
1009 547
1010 if (!oc->dirty) 548 mgr->caps = 0;
1011 continue; 549 mgr->supported_displays =
550 dss_feat_get_supported_displays(mgr->id);
1012 551
1013 if (mc->manual_update && !mc->do_manual_update) 552 INIT_LIST_HEAD(&mgr->overlays);
1014 continue;
1015 553
1016 if (mgr_busy[oc->channel]) { 554 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1017 busy = true; 555 &pdev->dev.kobj, "manager%d", i);
1018 continue;
1019 }
1020 556
1021 r = configure_overlay(i);
1022 if (r) 557 if (r)
1023 DSSERR("configure_overlay %d failed\n", i); 558 DSSERR("failed to create sysfs file\n");
1024
1025 oc->dirty = false;
1026 oc->shadow_dirty = true;
1027 mgr_go[oc->channel] = true;
1028 }
1029
1030 /* Commit manager settings */
1031 for (i = 0; i < num_mgrs; ++i) {
1032 mc = &dss_cache.manager_cache[i];
1033
1034 if (!mc->dirty)
1035 continue;
1036
1037 if (mc->manual_update && !mc->do_manual_update)
1038 continue;
1039
1040 if (mgr_busy[i]) {
1041 busy = true;
1042 continue;
1043 }
1044
1045 configure_manager(i);
1046 mc->dirty = false;
1047 mc->shadow_dirty = true;
1048 mgr_go[i] = true;
1049 }
1050
1051 /* set GO */
1052 for (i = 0; i < num_mgrs; ++i) {
1053 mc = &dss_cache.manager_cache[i];
1054
1055 if (!mgr_go[i])
1056 continue;
1057
1058 /* We don't need GO with manual update display. LCD iface will
1059 * always be turned off after frame, and new settings will be
1060 * taken in to use at next update */
1061 if (!mc->manual_update)
1062 dispc_mgr_go(i);
1063 }
1064
1065 if (busy)
1066 r = 1;
1067 else
1068 r = 0;
1069
1070 return r;
1071}
1072
1073/* Make the coordinates even. There are some strange problems with OMAP and
1074 * partial DSI update when the update widths are odd. */
1075static void make_even(u16 *x, u16 *w)
1076{
1077 u16 x1, x2;
1078
1079 x1 = *x;
1080 x2 = *x + *w;
1081
1082 x1 &= ~1;
1083 x2 = ALIGN(x2, 2);
1084
1085 *x = x1;
1086 *w = x2 - x1;
1087}
1088
1089/* Configure dispc for partial update. Return possibly modified update
1090 * area */
1091void dss_setup_partial_planes(struct omap_dss_device *dssdev,
1092 u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
1093{
1094 struct overlay_cache_data *oc;
1095 struct manager_cache_data *mc;
1096 struct omap_overlay_info *oi;
1097 const int num_ovls = dss_feat_get_num_ovls();
1098 struct omap_overlay_manager *mgr;
1099 int i;
1100 u16 x, y, w, h;
1101 unsigned long flags;
1102 bool area_changed;
1103
1104 x = *xi;
1105 y = *yi;
1106 w = *wi;
1107 h = *hi;
1108
1109 DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
1110 *xi, *yi, *wi, *hi);
1111
1112 mgr = dssdev->manager;
1113
1114 if (!mgr) {
1115 DSSDBG("no manager\n");
1116 return;
1117 } 559 }
1118 560
1119 make_even(&x, &w); 561 return 0;
1120
1121 spin_lock_irqsave(&dss_cache.lock, flags);
1122
1123 /*
1124 * Execute the outer loop until the inner loop has completed
1125 * once without increasing the update area. This will ensure that
1126 * all scaled overlays end up completely within the update area.
1127 */
1128 do {
1129 area_changed = false;
1130
1131 /* We need to show the whole overlay if it is scaled. So look
1132 * for those, and make the update area larger if found.
1133 * Also mark the overlay cache dirty */
1134 for (i = 0; i < num_ovls; ++i) {
1135 unsigned x1, y1, x2, y2;
1136 unsigned outw, outh;
1137
1138 oc = &dss_cache.overlay_cache[i];
1139 oi = &oc->info;
1140
1141 if (oc->channel != mgr->id)
1142 continue;
1143
1144 oc->dirty = true;
1145
1146 if (!enlarge_update_area)
1147 continue;
1148
1149 if (!oc->enabled)
1150 continue;
1151
1152 if (!dispc_is_overlay_scaled(oc))
1153 continue;
1154
1155 outw = oi->out_width == 0 ?
1156 oi->width : oi->out_width;
1157 outh = oi->out_height == 0 ?
1158 oi->height : oi->out_height;
1159
1160 /* is the overlay outside the update region? */
1161 if (!rectangle_intersects(x, y, w, h,
1162 oi->pos_x, oi->pos_y,
1163 outw, outh))
1164 continue;
1165
1166 /* if the overlay totally inside the update region? */
1167 if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
1168 x, y, w, h))
1169 continue;
1170
1171 if (x > oi->pos_x)
1172 x1 = oi->pos_x;
1173 else
1174 x1 = x;
1175
1176 if (y > oi->pos_y)
1177 y1 = oi->pos_y;
1178 else
1179 y1 = y;
1180
1181 if ((x + w) < (oi->pos_x + outw))
1182 x2 = oi->pos_x + outw;
1183 else
1184 x2 = x + w;
1185
1186 if ((y + h) < (oi->pos_y + outh))
1187 y2 = oi->pos_y + outh;
1188 else
1189 y2 = y + h;
1190
1191 x = x1;
1192 y = y1;
1193 w = x2 - x1;
1194 h = y2 - y1;
1195
1196 make_even(&x, &w);
1197
1198 DSSDBG("changing upd area due to ovl(%d) "
1199 "scaling %d,%d %dx%d\n",
1200 i, x, y, w, h);
1201
1202 area_changed = true;
1203 }
1204 } while (area_changed);
1205
1206 mc = &dss_cache.manager_cache[mgr->id];
1207 mc->do_manual_update = true;
1208 mc->enlarge_update_area = enlarge_update_area;
1209 mc->x = x;
1210 mc->y = y;
1211 mc->w = w;
1212 mc->h = h;
1213
1214 configure_dispc();
1215
1216 mc->do_manual_update = false;
1217
1218 spin_unlock_irqrestore(&dss_cache.lock, flags);
1219
1220 *xi = x;
1221 *yi = y;
1222 *wi = w;
1223 *hi = h;
1224} 562}
1225 563
1226void dss_start_update(struct omap_dss_device *dssdev) 564void dss_uninit_overlay_managers(struct platform_device *pdev)
1227{ 565{
1228 struct manager_cache_data *mc;
1229 struct overlay_cache_data *oc;
1230 const int num_ovls = dss_feat_get_num_ovls();
1231 const int num_mgrs = dss_feat_get_num_mgrs();
1232 struct omap_overlay_manager *mgr;
1233 int i; 566 int i;
1234 567
1235 mgr = dssdev->manager; 568 for (i = 0; i < num_managers; ++i) {
569 struct omap_overlay_manager *mgr = &managers[i];
1236 570
1237 for (i = 0; i < num_ovls; ++i) { 571 kobject_del(&mgr->kobj);
1238 oc = &dss_cache.overlay_cache[i]; 572 kobject_put(&mgr->kobj);
1239 if (oc->channel != mgr->id)
1240 continue;
1241
1242 oc->shadow_dirty = false;
1243 }
1244
1245 for (i = 0; i < num_mgrs; ++i) {
1246 mc = &dss_cache.manager_cache[i];
1247 if (mgr->id != i)
1248 continue;
1249
1250 mc->shadow_dirty = false;
1251 } 573 }
1252 574
1253 dssdev->manager->enable(dssdev->manager); 575 kfree(managers);
576 managers = NULL;
577 num_managers = 0;
1254} 578}
1255 579
1256static void dss_apply_irq_handler(void *data, u32 mask) 580int omap_dss_get_num_overlay_managers(void)
1257{ 581{
1258 struct manager_cache_data *mc; 582 return num_managers;
1259 struct overlay_cache_data *oc;
1260 const int num_ovls = dss_feat_get_num_ovls();
1261 const int num_mgrs = dss_feat_get_num_mgrs();
1262 int i, r;
1263 bool mgr_busy[MAX_DSS_MANAGERS];
1264 u32 irq_mask;
1265
1266 for (i = 0; i < num_mgrs; i++)
1267 mgr_busy[i] = dispc_mgr_go_busy(i);
1268
1269 spin_lock(&dss_cache.lock);
1270
1271 for (i = 0; i < num_ovls; ++i) {
1272 oc = &dss_cache.overlay_cache[i];
1273 if (!mgr_busy[oc->channel])
1274 oc->shadow_dirty = false;
1275 }
1276
1277 for (i = 0; i < num_mgrs; ++i) {
1278 mc = &dss_cache.manager_cache[i];
1279 if (!mgr_busy[i])
1280 mc->shadow_dirty = false;
1281 }
1282
1283 r = configure_dispc();
1284 if (r == 1)
1285 goto end;
1286
1287 /* re-read busy flags */
1288 for (i = 0; i < num_mgrs; i++)
1289 mgr_busy[i] = dispc_mgr_go_busy(i);
1290
1291 /* keep running as long as there are busy managers, so that
1292 * we can collect overlay-applied information */
1293 for (i = 0; i < num_mgrs; ++i) {
1294 if (mgr_busy[i])
1295 goto end;
1296 }
1297
1298 irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1299 DISPC_IRQ_EVSYNC_EVEN;
1300 if (dss_has_feature(FEAT_MGR_LCD2))
1301 irq_mask |= DISPC_IRQ_VSYNC2;
1302
1303 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
1304 dss_cache.irq_enabled = false;
1305
1306end:
1307 spin_unlock(&dss_cache.lock);
1308} 583}
584EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1309 585
1310static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) 586struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1311{ 587{
1312 struct overlay_cache_data *oc; 588 if (num >= num_managers)
1313 struct manager_cache_data *mc; 589 return NULL;
1314 int i;
1315 struct omap_overlay *ovl;
1316 int num_planes_enabled = 0;
1317 bool use_fifomerge;
1318 unsigned long flags;
1319 int r;
1320
1321 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1322
1323 r = dispc_runtime_get();
1324 if (r)
1325 return r;
1326
1327 spin_lock_irqsave(&dss_cache.lock, flags);
1328
1329 /* Configure overlays */
1330 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1331 struct omap_dss_device *dssdev;
1332
1333 ovl = omap_dss_get_overlay(i);
1334
1335 oc = &dss_cache.overlay_cache[ovl->id];
1336
1337 if (ovl->manager_changed) {
1338 ovl->manager_changed = false;
1339 ovl->info_dirty = true;
1340 }
1341
1342 if (!overlay_enabled(ovl)) {
1343 if (oc->enabled) {
1344 oc->enabled = false;
1345 oc->dirty = true;
1346 }
1347 continue;
1348 }
1349
1350 if (!ovl->info_dirty) {
1351 if (oc->enabled)
1352 ++num_planes_enabled;
1353 continue;
1354 }
1355
1356 dssdev = ovl->manager->device;
1357
1358 if (dss_check_overlay(ovl, dssdev)) {
1359 if (oc->enabled) {
1360 oc->enabled = false;
1361 oc->dirty = true;
1362 }
1363 continue;
1364 }
1365
1366 ovl->info_dirty = false;
1367 oc->dirty = true;
1368 oc->info = ovl->info;
1369
1370 oc->replication =
1371 dss_use_replication(dssdev, ovl->info.color_mode);
1372
1373 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1374
1375 oc->channel = ovl->manager->id;
1376
1377 oc->enabled = true;
1378
1379 ++num_planes_enabled;
1380 }
1381
1382 /* Configure managers */
1383 list_for_each_entry(mgr, &manager_list, list) {
1384 struct omap_dss_device *dssdev;
1385 590
1386 mc = &dss_cache.manager_cache[mgr->id]; 591 return &managers[num];
1387
1388 if (mgr->device_changed) {
1389 mgr->device_changed = false;
1390 mgr->info_dirty = true;
1391 }
1392
1393 if (!mgr->info_dirty)
1394 continue;
1395
1396 if (!mgr->device)
1397 continue;
1398
1399 dssdev = mgr->device;
1400
1401 mgr->info_dirty = false;
1402 mc->dirty = true;
1403 mc->info = mgr->info;
1404
1405 mc->manual_update =
1406 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1407 }
1408
1409 /* XXX TODO: Try to get fifomerge working. The problem is that it
1410 * affects both managers, not individually but at the same time. This
1411 * means the change has to be well synchronized. I guess the proper way
1412 * is to have a two step process for fifo merge:
1413 * fifomerge enable:
1414 * 1. disable other planes, leaving one plane enabled
1415 * 2. wait until the planes are disabled on HW
1416 * 3. config merged fifo thresholds, enable fifomerge
1417 * fifomerge disable:
1418 * 1. config unmerged fifo thresholds, disable fifomerge
1419 * 2. wait until fifo changes are in HW
1420 * 3. enable planes
1421 */
1422 use_fifomerge = false;
1423
1424 /* Configure overlay fifos */
1425 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1426 struct omap_dss_device *dssdev;
1427 u32 size, burst_size;
1428
1429 ovl = omap_dss_get_overlay(i);
1430
1431 oc = &dss_cache.overlay_cache[ovl->id];
1432
1433 if (!oc->enabled)
1434 continue;
1435
1436 dssdev = ovl->manager->device;
1437
1438 size = dispc_ovl_get_fifo_size(ovl->id);
1439 if (use_fifomerge)
1440 size *= 3;
1441
1442 burst_size = dispc_ovl_get_burst_size(ovl->id);
1443
1444 switch (dssdev->type) {
1445 case OMAP_DISPLAY_TYPE_DPI:
1446 case OMAP_DISPLAY_TYPE_DBI:
1447 case OMAP_DISPLAY_TYPE_SDI:
1448 case OMAP_DISPLAY_TYPE_VENC:
1449 case OMAP_DISPLAY_TYPE_HDMI:
1450 default_get_overlay_fifo_thresholds(ovl->id, size,
1451 burst_size, &oc->fifo_low,
1452 &oc->fifo_high);
1453 break;
1454#ifdef CONFIG_OMAP2_DSS_DSI
1455 case OMAP_DISPLAY_TYPE_DSI:
1456 dsi_get_overlay_fifo_thresholds(ovl->id, size,
1457 burst_size, &oc->fifo_low,
1458 &oc->fifo_high);
1459 break;
1460#endif
1461 default:
1462 BUG();
1463 }
1464 }
1465
1466 r = 0;
1467 if (!dss_cache.irq_enabled) {
1468 u32 mask;
1469
1470 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1471 DISPC_IRQ_EVSYNC_EVEN;
1472 if (dss_has_feature(FEAT_MGR_LCD2))
1473 mask |= DISPC_IRQ_VSYNC2;
1474
1475 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
1476 dss_cache.irq_enabled = true;
1477 }
1478 configure_dispc();
1479
1480 spin_unlock_irqrestore(&dss_cache.lock, flags);
1481
1482 dispc_runtime_put();
1483
1484 return r;
1485} 592}
593EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1486 594
1487static int dss_check_manager(struct omap_overlay_manager *mgr) 595int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
596 const struct omap_overlay_manager_info *info)
1488{ 597{
1489 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { 598 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1490 /* 599 /*
1491 * OMAP3 supports only graphics source transparency color key 600 * OMAP3 supports only graphics source transparency color key
1492 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 601 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1493 * Alpha Mode 602 * Alpha Mode.
1494 */ 603 */
1495 if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled 604 if (info->partial_alpha_enabled && info->trans_enabled
1496 && mgr->info.trans_key_type != 605 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
1497 OMAP_DSS_COLOR_KEY_GFX_DST) 606 DSSERR("check_manager: illegal transparency key\n");
1498 return -EINVAL; 607 return -EINVAL;
608 }
1499 } 609 }
1500 610
1501 return 0; 611 return 0;
1502} 612}
1503 613
1504static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, 614static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
1505 struct omap_overlay_manager_info *info) 615 struct omap_overlay_info **overlay_infos)
1506{
1507 int r;
1508 struct omap_overlay_manager_info old_info;
1509
1510 old_info = mgr->info;
1511 mgr->info = *info;
1512
1513 r = dss_check_manager(mgr);
1514 if (r) {
1515 mgr->info = old_info;
1516 return r;
1517 }
1518
1519 mgr->info_dirty = true;
1520
1521 return 0;
1522}
1523
1524static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1525 struct omap_overlay_manager_info *info)
1526{ 616{
1527 *info = mgr->info; 617 struct omap_overlay *ovl1, *ovl2;
1528} 618 struct omap_overlay_info *info1, *info2;
1529 619
1530static int dss_mgr_enable(struct omap_overlay_manager *mgr) 620 list_for_each_entry(ovl1, &mgr->overlays, list) {
1531{ 621 info1 = overlay_infos[ovl1->id];
1532 dispc_mgr_enable(mgr->id, 1);
1533 return 0;
1534}
1535 622
1536static int dss_mgr_disable(struct omap_overlay_manager *mgr) 623 if (info1 == NULL)
1537{ 624 continue;
1538 dispc_mgr_enable(mgr->id, 0);
1539 return 0;
1540}
1541
1542static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1543{
1544 ++num_managers;
1545 list_add_tail(&manager->list, &manager_list);
1546}
1547
1548int dss_init_overlay_managers(struct platform_device *pdev)
1549{
1550 int i, r;
1551
1552 spin_lock_init(&dss_cache.lock);
1553
1554 INIT_LIST_HEAD(&manager_list);
1555
1556 num_managers = 0;
1557
1558 for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
1559 struct omap_overlay_manager *mgr;
1560 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1561
1562 BUG_ON(mgr == NULL);
1563
1564 switch (i) {
1565 case 0:
1566 mgr->name = "lcd";
1567 mgr->id = OMAP_DSS_CHANNEL_LCD;
1568 break;
1569 case 1:
1570 mgr->name = "tv";
1571 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1572 break;
1573 case 2:
1574 mgr->name = "lcd2";
1575 mgr->id = OMAP_DSS_CHANNEL_LCD2;
1576 break;
1577 }
1578
1579 mgr->set_device = &omap_dss_set_device;
1580 mgr->unset_device = &omap_dss_unset_device;
1581 mgr->apply = &omap_dss_mgr_apply;
1582 mgr->set_manager_info = &omap_dss_mgr_set_info;
1583 mgr->get_manager_info = &omap_dss_mgr_get_info;
1584 mgr->wait_for_go = &dss_mgr_wait_for_go;
1585 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1586
1587 mgr->enable = &dss_mgr_enable;
1588 mgr->disable = &dss_mgr_disable;
1589
1590 mgr->caps = 0;
1591 mgr->supported_displays =
1592 dss_feat_get_supported_displays(mgr->id);
1593 625
1594 dss_overlay_setup_dispc_manager(mgr); 626 list_for_each_entry(ovl2, &mgr->overlays, list) {
627 if (ovl1 == ovl2)
628 continue;
1595 629
1596 omap_dss_add_overlay_manager(mgr); 630 info2 = overlay_infos[ovl2->id];
1597 631
1598 r = kobject_init_and_add(&mgr->kobj, &manager_ktype, 632 if (info2 == NULL)
1599 &pdev->dev.kobj, "manager%d", i); 633 continue;
1600 634
1601 if (r) { 635 if (info1->zorder == info2->zorder) {
1602 DSSERR("failed to create sysfs file\n"); 636 DSSERR("overlays %d and %d have the same "
1603 continue; 637 "zorder %d\n",
638 ovl1->id, ovl2->id, info1->zorder);
639 return -EINVAL;
640 }
1604 } 641 }
1605 } 642 }
1606 643
1607 return 0; 644 return 0;
1608} 645}
1609 646
1610void dss_uninit_overlay_managers(struct platform_device *pdev) 647int dss_mgr_check(struct omap_overlay_manager *mgr,
648 struct omap_dss_device *dssdev,
649 struct omap_overlay_manager_info *info,
650 struct omap_overlay_info **overlay_infos)
1611{ 651{
1612 struct omap_overlay_manager *mgr; 652 struct omap_overlay *ovl;
653 int r;
1613 654
1614 while (!list_empty(&manager_list)) { 655 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
1615 mgr = list_first_entry(&manager_list, 656 r = dss_mgr_check_zorder(mgr, overlay_infos);
1616 struct omap_overlay_manager, list); 657 if (r)
1617 list_del(&mgr->list); 658 return r;
1618 kobject_del(&mgr->kobj);
1619 kobject_put(&mgr->kobj);
1620 kfree(mgr);
1621 } 659 }
1622 660
1623 num_managers = 0; 661 list_for_each_entry(ovl, &mgr->overlays, list) {
1624} 662 struct omap_overlay_info *oi;
663 int r;
1625 664
1626int omap_dss_get_num_overlay_managers(void) 665 oi = overlay_infos[ovl->id];
1627{
1628 return num_managers;
1629}
1630EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1631 666
1632struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) 667 if (oi == NULL)
1633{ 668 continue;
1634 int i = 0;
1635 struct omap_overlay_manager *mgr;
1636 669
1637 list_for_each_entry(mgr, &manager_list, list) { 670 r = dss_ovl_check(ovl, oi, dssdev);
1638 if (i++ == num) 671 if (r)
1639 return mgr; 672 return r;
1640 } 673 }
1641 674
1642 return NULL; 675 return 0;
1643} 676}
1644EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1645
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index ab8e40e48759..6e821810deec 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -38,7 +38,7 @@
38#include "dss_features.h" 38#include "dss_features.h"
39 39
40static int num_overlays; 40static int num_overlays;
41static struct list_head overlay_list; 41static struct omap_overlay *overlays;
42 42
43static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) 43static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
44{ 44{
@@ -124,19 +124,31 @@ err:
124 124
125static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) 125static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
126{ 126{
127 struct omap_overlay_info info;
128
129 ovl->get_overlay_info(ovl, &info);
130
127 return snprintf(buf, PAGE_SIZE, "%d,%d\n", 131 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
128 ovl->info.width, ovl->info.height); 132 info.width, info.height);
129} 133}
130 134
131static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) 135static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
132{ 136{
133 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); 137 struct omap_overlay_info info;
138
139 ovl->get_overlay_info(ovl, &info);
140
141 return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
134} 142}
135 143
136static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) 144static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
137{ 145{
146 struct omap_overlay_info info;
147
148 ovl->get_overlay_info(ovl, &info);
149
138 return snprintf(buf, PAGE_SIZE, "%d,%d\n", 150 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
139 ovl->info.pos_x, ovl->info.pos_y); 151 info.pos_x, info.pos_y);
140} 152}
141 153
142static ssize_t overlay_position_store(struct omap_overlay *ovl, 154static ssize_t overlay_position_store(struct omap_overlay *ovl,
@@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl,
170 182
171static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) 183static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
172{ 184{
185 struct omap_overlay_info info;
186
187 ovl->get_overlay_info(ovl, &info);
188
173 return snprintf(buf, PAGE_SIZE, "%d,%d\n", 189 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
174 ovl->info.out_width, ovl->info.out_height); 190 info.out_width, info.out_height);
175} 191}
176 192
177static ssize_t overlay_output_size_store(struct omap_overlay *ovl, 193static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
@@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
205 221
206static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) 222static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
207{ 223{
208 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); 224 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
209} 225}
210 226
211static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, 227static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
@@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
213{ 229{
214 int r; 230 int r;
215 bool enable; 231 bool enable;
216 struct omap_overlay_info info;
217
218 ovl->get_overlay_info(ovl, &info);
219 232
220 r = strtobool(buf, &enable); 233 r = strtobool(buf, &enable);
221 if (r) 234 if (r)
222 return r; 235 return r;
223 236
224 info.enabled = enable; 237 if (enable)
238 r = ovl->enable(ovl);
239 else
240 r = ovl->disable(ovl);
225 241
226 r = ovl->set_overlay_info(ovl, &info);
227 if (r) 242 if (r)
228 return r; 243 return r;
229 244
230 if (ovl->manager) {
231 r = ovl->manager->apply(ovl->manager);
232 if (r)
233 return r;
234 }
235
236 return size; 245 return size;
237} 246}
238 247
239static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) 248static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
240{ 249{
250 struct omap_overlay_info info;
251
252 ovl->get_overlay_info(ovl, &info);
253
241 return snprintf(buf, PAGE_SIZE, "%d\n", 254 return snprintf(buf, PAGE_SIZE, "%d\n",
242 ovl->info.global_alpha); 255 info.global_alpha);
243} 256}
244 257
245static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, 258static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
@@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
276static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, 289static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
277 char *buf) 290 char *buf)
278{ 291{
292 struct omap_overlay_info info;
293
294 ovl->get_overlay_info(ovl, &info);
295
279 return snprintf(buf, PAGE_SIZE, "%d\n", 296 return snprintf(buf, PAGE_SIZE, "%d\n",
280 ovl->info.pre_mult_alpha); 297 info.pre_mult_alpha);
281} 298}
282 299
283static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, 300static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
@@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
313 330
314static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) 331static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
315{ 332{
316 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); 333 struct omap_overlay_info info;
334
335 ovl->get_overlay_info(ovl, &info);
336
337 return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
317} 338}
318 339
319static ssize_t overlay_zorder_store(struct omap_overlay *ovl, 340static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
@@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = {
430 .default_attrs = overlay_sysfs_attrs, 451 .default_attrs = overlay_sysfs_attrs,
431}; 452};
432 453
433/* Check if overlay parameters are compatible with display */
434int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
435{
436 struct omap_overlay_info *info;
437 u16 outw, outh;
438 u16 dw, dh;
439 int i;
440
441 if (!dssdev)
442 return 0;
443
444 if (!ovl->info.enabled)
445 return 0;
446
447 info = &ovl->info;
448
449 if (info->paddr == 0) {
450 DSSDBG("check_overlay failed: paddr 0\n");
451 return -EINVAL;
452 }
453
454 dssdev->driver->get_resolution(dssdev, &dw, &dh);
455
456 DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
457 ovl->id,
458 info->pos_x, info->pos_y,
459 info->width, info->height,
460 info->out_width, info->out_height,
461 dw, dh);
462
463 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
464 outw = info->width;
465 outh = info->height;
466 } else {
467 if (info->out_width == 0)
468 outw = info->width;
469 else
470 outw = info->out_width;
471
472 if (info->out_height == 0)
473 outh = info->height;
474 else
475 outh = info->out_height;
476 }
477
478 if (dw < info->pos_x + outw) {
479 DSSDBG("check_overlay failed 1: %d < %d + %d\n",
480 dw, info->pos_x, outw);
481 return -EINVAL;
482 }
483
484 if (dh < info->pos_y + outh) {
485 DSSDBG("check_overlay failed 2: %d < %d + %d\n",
486 dh, info->pos_y, outh);
487 return -EINVAL;
488 }
489
490 if ((ovl->supported_modes & info->color_mode) == 0) {
491 DSSERR("overlay doesn't support mode %d\n", info->color_mode);
492 return -EINVAL;
493 }
494
495 if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) {
496 if (info->zorder < 0 || info->zorder > 3) {
497 DSSERR("zorder out of range: %d\n",
498 info->zorder);
499 return -EINVAL;
500 }
501 /*
502 * Check that zorder doesn't match with zorder of any other
503 * overlay which is enabled and is also connected to the same
504 * manager
505 */
506 for (i = 0; i < omap_dss_get_num_overlays(); i++) {
507 struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i);
508
509 if (tmp_ovl->id != ovl->id &&
510 tmp_ovl->manager == ovl->manager &&
511 tmp_ovl->info.enabled == true &&
512 tmp_ovl->info.zorder == info->zorder) {
513 DSSERR("%s and %s have same zorder: %d\n",
514 ovl->name, tmp_ovl->name, info->zorder);
515 return -EINVAL;
516 }
517 }
518 }
519
520 return 0;
521}
522
523static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
524 struct omap_overlay_info *info)
525{
526 int r;
527 struct omap_overlay_info old_info;
528
529 old_info = ovl->info;
530 ovl->info = *info;
531
532 if (ovl->manager) {
533 r = dss_check_overlay(ovl, ovl->manager->device);
534 if (r) {
535 ovl->info = old_info;
536 return r;
537 }
538 }
539
540 ovl->info_dirty = true;
541
542 return 0;
543}
544
545static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
546 struct omap_overlay_info *info)
547{
548 *info = ovl->info;
549}
550
551static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
552{
553 return dss_mgr_wait_for_go_ovl(ovl);
554}
555
556static int omap_dss_set_manager(struct omap_overlay *ovl,
557 struct omap_overlay_manager *mgr)
558{
559 if (!mgr)
560 return -EINVAL;
561
562 if (ovl->manager) {
563 DSSERR("overlay '%s' already has a manager '%s'\n",
564 ovl->name, ovl->manager->name);
565 return -EINVAL;
566 }
567
568 if (ovl->info.enabled) {
569 DSSERR("overlay has to be disabled to change the manager\n");
570 return -EINVAL;
571 }
572
573 ovl->manager = mgr;
574 ovl->manager_changed = true;
575
576 /* XXX: When there is an overlay on a DSI manual update display, and
577 * the overlay is first disabled, then moved to tv, and enabled, we
578 * seem to get SYNC_LOST_DIGIT error.
579 *
580 * Waiting doesn't seem to help, but updating the manual update display
581 * after disabling the overlay seems to fix this. This hints that the
582 * overlay is perhaps somehow tied to the LCD output until the output
583 * is updated.
584 *
585 * Userspace workaround for this is to update the LCD after disabling
586 * the overlay, but before moving the overlay to TV.
587 */
588
589 return 0;
590}
591
592static int omap_dss_unset_manager(struct omap_overlay *ovl)
593{
594 if (!ovl->manager) {
595 DSSERR("failed to detach overlay: manager not set\n");
596 return -EINVAL;
597 }
598
599 if (ovl->info.enabled) {
600 DSSERR("overlay has to be disabled to unset the manager\n");
601 return -EINVAL;
602 }
603
604 ovl->manager = NULL;
605 ovl->manager_changed = true;
606
607 return 0;
608}
609
610int omap_dss_get_num_overlays(void) 454int omap_dss_get_num_overlays(void)
611{ 455{
612 return num_overlays; 456 return num_overlays;
@@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays);
615 459
616struct omap_overlay *omap_dss_get_overlay(int num) 460struct omap_overlay *omap_dss_get_overlay(int num)
617{ 461{
618 int i = 0; 462 if (num >= num_overlays)
619 struct omap_overlay *ovl; 463 return NULL;
620 464
621 list_for_each_entry(ovl, &overlay_list, list) { 465 return &overlays[num];
622 if (i++ == num)
623 return ovl;
624 }
625
626 return NULL;
627} 466}
628EXPORT_SYMBOL(omap_dss_get_overlay); 467EXPORT_SYMBOL(omap_dss_get_overlay);
629 468
630static void omap_dss_add_overlay(struct omap_overlay *overlay)
631{
632 ++num_overlays;
633 list_add_tail(&overlay->list, &overlay_list);
634}
635
636static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS];
637
638void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
639{
640 mgr->num_overlays = dss_feat_get_num_ovls();
641 mgr->overlays = dispc_overlays;
642}
643
644#ifdef L4_EXAMPLE
645static struct omap_overlay *l4_overlays[1];
646void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
647{
648 mgr->num_overlays = 1;
649 mgr->overlays = l4_overlays;
650}
651#endif
652
653void dss_init_overlays(struct platform_device *pdev) 469void dss_init_overlays(struct platform_device *pdev)
654{ 470{
655 int i, r; 471 int i, r;
656 472
657 INIT_LIST_HEAD(&overlay_list); 473 num_overlays = dss_feat_get_num_ovls();
658 474
659 num_overlays = 0; 475 overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
476 GFP_KERNEL);
660 477
661 for (i = 0; i < dss_feat_get_num_ovls(); ++i) { 478 BUG_ON(overlays == NULL);
662 struct omap_overlay *ovl;
663 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
664 479
665 BUG_ON(ovl == NULL); 480 for (i = 0; i < num_overlays; ++i) {
481 struct omap_overlay *ovl = &overlays[i];
666 482
667 switch (i) { 483 switch (i) {
668 case 0: 484 case 0:
669 ovl->name = "gfx"; 485 ovl->name = "gfx";
670 ovl->id = OMAP_DSS_GFX; 486 ovl->id = OMAP_DSS_GFX;
671 ovl->info.global_alpha = 255;
672 ovl->info.zorder = 0;
673 break; 487 break;
674 case 1: 488 case 1:
675 ovl->name = "vid1"; 489 ovl->name = "vid1";
676 ovl->id = OMAP_DSS_VIDEO1; 490 ovl->id = OMAP_DSS_VIDEO1;
677 ovl->info.global_alpha = 255;
678 ovl->info.zorder =
679 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
680 break; 491 break;
681 case 2: 492 case 2:
682 ovl->name = "vid2"; 493 ovl->name = "vid2";
683 ovl->id = OMAP_DSS_VIDEO2; 494 ovl->id = OMAP_DSS_VIDEO2;
684 ovl->info.global_alpha = 255;
685 ovl->info.zorder =
686 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
687 break; 495 break;
688 case 3: 496 case 3:
689 ovl->name = "vid3"; 497 ovl->name = "vid3";
690 ovl->id = OMAP_DSS_VIDEO3; 498 ovl->id = OMAP_DSS_VIDEO3;
691 ovl->info.global_alpha = 255;
692 ovl->info.zorder =
693 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
694 break; 499 break;
695 } 500 }
696 501
697 ovl->set_manager = &omap_dss_set_manager; 502 ovl->is_enabled = &dss_ovl_is_enabled;
698 ovl->unset_manager = &omap_dss_unset_manager; 503 ovl->enable = &dss_ovl_enable;
699 ovl->set_overlay_info = &dss_ovl_set_overlay_info; 504 ovl->disable = &dss_ovl_disable;
700 ovl->get_overlay_info = &dss_ovl_get_overlay_info; 505 ovl->set_manager = &dss_ovl_set_manager;
701 ovl->wait_for_go = &dss_ovl_wait_for_go; 506 ovl->unset_manager = &dss_ovl_unset_manager;
507 ovl->set_overlay_info = &dss_ovl_set_info;
508 ovl->get_overlay_info = &dss_ovl_get_info;
509 ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
702 510
703 ovl->caps = dss_feat_get_overlay_caps(ovl->id); 511 ovl->caps = dss_feat_get_overlay_caps(ovl->id);
704 ovl->supported_modes = 512 ovl->supported_modes =
705 dss_feat_get_supported_color_modes(ovl->id); 513 dss_feat_get_supported_color_modes(ovl->id);
706 514
707 omap_dss_add_overlay(ovl);
708
709 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, 515 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
710 &pdev->dev.kobj, "overlay%d", i); 516 &pdev->dev.kobj, "overlay%d", i);
711 517
712 if (r) {
713 DSSERR("failed to create sysfs file\n");
714 continue;
715 }
716
717 dispc_overlays[i] = ovl;
718 }
719
720#ifdef L4_EXAMPLE
721 {
722 struct omap_overlay *ovl;
723 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
724
725 BUG_ON(ovl == NULL);
726
727 ovl->name = "l4";
728 ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
729
730 ovl->set_manager = &omap_dss_set_manager;
731 ovl->unset_manager = &omap_dss_unset_manager;
732 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
733 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
734
735 omap_dss_add_overlay(ovl);
736
737 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
738 &pdev->dev.kobj, "overlayl4");
739
740 if (r) 518 if (r)
741 DSSERR("failed to create sysfs file\n"); 519 DSSERR("failed to create sysfs file\n");
742
743 l4_overlays[0] = ovl;
744 } 520 }
745#endif
746} 521}
747 522
748/* connect overlays to the new device, if not already connected. if force 523/* connect overlays to the new device, if not already connected. if force
@@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
795 ovl = omap_dss_get_overlay(i); 570 ovl = omap_dss_get_overlay(i);
796 if (!ovl->manager || force) { 571 if (!ovl->manager || force) {
797 if (ovl->manager) 572 if (ovl->manager)
798 omap_dss_unset_manager(ovl); 573 ovl->unset_manager(ovl);
799 omap_dss_set_manager(ovl, mgr); 574 ovl->set_manager(ovl, mgr);
800 } 575 }
801 } 576 }
802 577
@@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
806 581
807void dss_uninit_overlays(struct platform_device *pdev) 582void dss_uninit_overlays(struct platform_device *pdev)
808{ 583{
809 struct omap_overlay *ovl; 584 int i;
585
586 for (i = 0; i < num_overlays; ++i) {
587 struct omap_overlay *ovl = &overlays[i];
810 588
811 while (!list_empty(&overlay_list)) {
812 ovl = list_first_entry(&overlay_list,
813 struct omap_overlay, list);
814 list_del(&ovl->list);
815 kobject_del(&ovl->kobj); 589 kobject_del(&ovl->kobj);
816 kobject_put(&ovl->kobj); 590 kobject_put(&ovl->kobj);
817 kfree(ovl);
818 } 591 }
819 592
593 kfree(overlays);
594 overlays = NULL;
820 num_overlays = 0; 595 num_overlays = 0;
821} 596}
822 597
598int dss_ovl_simple_check(struct omap_overlay *ovl,
599 const struct omap_overlay_info *info)
600{
601 if (info->paddr == 0) {
602 DSSERR("check_overlay: paddr cannot be 0\n");
603 return -EINVAL;
604 }
605
606 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
607 if (info->out_width != 0 && info->width != info->out_width) {
608 DSSERR("check_overlay: overlay %d doesn't support "
609 "scaling\n", ovl->id);
610 return -EINVAL;
611 }
612
613 if (info->out_height != 0 && info->height != info->out_height) {
614 DSSERR("check_overlay: overlay %d doesn't support "
615 "scaling\n", ovl->id);
616 return -EINVAL;
617 }
618 }
619
620 if ((ovl->supported_modes & info->color_mode) == 0) {
621 DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
622 ovl->id, info->color_mode);
623 return -EINVAL;
624 }
625
626 if (info->zorder >= omap_dss_get_num_overlays()) {
627 DSSERR("check_overlay: zorder %d too high\n", info->zorder);
628 return -EINVAL;
629 }
630
631 return 0;
632}
633
634int dss_ovl_check(struct omap_overlay *ovl,
635 struct omap_overlay_info *info, struct omap_dss_device *dssdev)
636{
637 u16 outw, outh;
638 u16 dw, dh;
639
640 if (dssdev == NULL)
641 return 0;
642
643 dssdev->driver->get_resolution(dssdev, &dw, &dh);
644
645 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
646 outw = info->width;
647 outh = info->height;
648 } else {
649 if (info->out_width == 0)
650 outw = info->width;
651 else
652 outw = info->out_width;
653
654 if (info->out_height == 0)
655 outh = info->height;
656 else
657 outh = info->out_height;
658 }
659
660 if (dw < info->pos_x + outw) {
661 DSSERR("overlay %d horizontally not inside the display area "
662 "(%d + %d >= %d)\n",
663 ovl->id, info->pos_x, outw, dw);
664 return -EINVAL;
665 }
666
667 if (dh < info->pos_y + outh) {
668 DSSERR("overlay %d vertically not inside the display area "
669 "(%d + %d >= %d)\n",
670 ovl->id, info->pos_y, outh, dh);
671 return -EINVAL;
672 }
673
674 return 0;
675}
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 1130c608a561..814bb9500dca 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
784 if (*w == 0 || *h == 0) 784 if (*w == 0 || *h == 0)
785 return -EINVAL; 785 return -EINVAL;
786 786
787 dss_setup_partial_planes(dssdev, x, y, w, h, true);
788 dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); 787 dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
789 788
790 return 0; 789 return 0;
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 40305ad7841e..8266ca0d666b 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
123 goto err_sdi_enable; 123 goto err_sdi_enable;
124 mdelay(2); 124 mdelay(2);
125 125
126 dssdev->manager->enable(dssdev->manager); 126 r = dss_mgr_enable(dssdev->manager);
127 if (r)
128 goto err_mgr_enable;
127 129
128 return 0; 130 return 0;
129 131
132err_mgr_enable:
133 dss_sdi_disable();
130err_sdi_enable: 134err_sdi_enable:
131err_set_dispc_clock_div: 135err_set_dispc_clock_div:
132err_set_dss_clock_div: 136err_set_dss_clock_div:
@@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
145 149
146void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) 150void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
147{ 151{
148 dssdev->manager->disable(dssdev->manager); 152 dss_mgr_disable(dssdev->manager);
149 153
150 dss_sdi_disable(); 154 dss_sdi_disable();
151 155
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index 2c3443dabb14..7503f7f619a7 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops {
110 110
111 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); 111 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
112 112
113#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
114 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
115 void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start);
116#endif
117
113}; 118};
114 119
115struct hdmi_ip_data { 120struct hdmi_ip_data {
@@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
134void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 139void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
135void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 140void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
136void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 141void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
137 142#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
143 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
144void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable);
145#endif
138#endif 146#endif
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index e1a6ce518af6..9af81f18f163 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
1204 return 0; 1204 return 0;
1205} 1205}
1206 1206
1207int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, 1207void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable)
1208 struct snd_pcm_substream *substream, int cmd,
1209 struct snd_soc_dai *dai)
1210{ 1208{
1211 int err = 0; 1209 REG_FLD_MOD(hdmi_av_base(ip_data),
1212 switch (cmd) { 1210 HDMI_CORE_AV_AUD_MODE, enable, 0, 0);
1213 case SNDRV_PCM_TRIGGER_START: 1211 REG_FLD_MOD(hdmi_wp_base(ip_data),
1214 case SNDRV_PCM_TRIGGER_RESUME: 1212 HDMI_WP_AUDIO_CTRL, enable, 31, 31);
1215 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1213 REG_FLD_MOD(hdmi_wp_base(ip_data),
1216 REG_FLD_MOD(hdmi_av_base(ip_data), 1214 HDMI_WP_AUDIO_CTRL, enable, 30, 30);
1217 HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
1218 REG_FLD_MOD(hdmi_wp_base(ip_data),
1219 HDMI_WP_AUDIO_CTRL, 1, 31, 31);
1220 REG_FLD_MOD(hdmi_wp_base(ip_data),
1221 HDMI_WP_AUDIO_CTRL, 1, 30, 30);
1222 break;
1223
1224 case SNDRV_PCM_TRIGGER_STOP:
1225 case SNDRV_PCM_TRIGGER_SUSPEND:
1226 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1227 REG_FLD_MOD(hdmi_av_base(ip_data),
1228 HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
1229 REG_FLD_MOD(hdmi_wp_base(ip_data),
1230 HDMI_WP_AUDIO_CTRL, 0, 30, 30);
1231 REG_FLD_MOD(hdmi_wp_base(ip_data),
1232 HDMI_WP_AUDIO_CTRL, 0, 31, 31);
1233 break;
1234 default:
1235 err = -EINVAL;
1236 }
1237 return err;
1238} 1215}
1239#endif 1216#endif
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
index 204095632d27..a442998980f1 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
@@ -576,9 +576,6 @@ struct hdmi_core_audio_config {
576 576
577#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ 577#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
578 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) 578 defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
579int hdmi_audio_trigger(struct hdmi_ip_data *ip_data,
580 struct snd_pcm_substream *substream, int cmd,
581 struct snd_soc_dai *dai);
582int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, 579int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
583 u32 sample_freq, u32 *n, u32 *cts); 580 u32 sample_freq, u32 *n, u32 *cts);
584void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, 581void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 7533458ba4d2..b3e9f9091581 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config(
417 BUG(); 417 BUG();
418} 418}
419 419
420static void venc_power_on(struct omap_dss_device *dssdev) 420static int venc_power_on(struct omap_dss_device *dssdev)
421{ 421{
422 u32 l; 422 u32 l;
423 int r;
423 424
424 venc_reset(); 425 venc_reset();
425 venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); 426 venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
@@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev)
447 if (dssdev->platform_enable) 448 if (dssdev->platform_enable)
448 dssdev->platform_enable(dssdev); 449 dssdev->platform_enable(dssdev);
449 450
450 dssdev->manager->enable(dssdev->manager); 451 r = dss_mgr_enable(dssdev->manager);
452 if (r)
453 goto err;
454
455 return 0;
456
457err:
458 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
459 dss_set_dac_pwrdn_bgz(0);
460
461 if (dssdev->platform_disable)
462 dssdev->platform_disable(dssdev);
463
464 regulator_disable(venc.vdda_dac_reg);
465
466 return r;
451} 467}
452 468
453static void venc_power_off(struct omap_dss_device *dssdev) 469static void venc_power_off(struct omap_dss_device *dssdev)
@@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev)
455 venc_write_reg(VENC_OUTPUT_CONTROL, 0); 471 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
456 dss_set_dac_pwrdn_bgz(0); 472 dss_set_dac_pwrdn_bgz(0);
457 473
458 dssdev->manager->disable(dssdev->manager); 474 dss_mgr_disable(dssdev->manager);
459 475
460 if (dssdev->platform_disable) 476 if (dssdev->platform_disable)
461 dssdev->platform_disable(dssdev); 477 dssdev->platform_disable(dssdev);
@@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
504 if (r) 520 if (r)
505 goto err1; 521 goto err1;
506 522
507 venc_power_on(dssdev); 523 r = venc_power_on(dssdev);
524 if (r)
525 goto err2;
508 526
509 venc.wss_data = 0; 527 venc.wss_data = 0;
510 528
@@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
512 530
513 mutex_unlock(&venc.venc_lock); 531 mutex_unlock(&venc.venc_lock);
514 return 0; 532 return 0;
533err2:
534 venc_runtime_put();
515err1: 535err1:
516 omap_dss_stop_device(dssdev); 536 omap_dss_stop_device(dssdev);
517err0: 537err0:
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index df7bcce5b107..16ba6196f330 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
111 set_fb_fix(fbi); 111 set_fb_fix(fbi);
112 } 112 }
113 113
114 if (pi->enabled) { 114 if (!pi->enabled) {
115 struct omap_overlay_info info; 115 r = ovl->disable(ovl);
116 if (r)
117 goto undo;
118 }
116 119
120 if (pi->enabled) {
117 r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, 121 r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
118 pi->out_width, pi->out_height); 122 pi->out_width, pi->out_height);
119 if (r) 123 if (r)
120 goto undo; 124 goto undo;
121
122 ovl->get_overlay_info(ovl, &info);
123
124 if (!info.enabled) {
125 info.enabled = pi->enabled;
126 r = ovl->set_overlay_info(ovl, &info);
127 if (r)
128 goto undo;
129 }
130 } else { 125 } else {
131 struct omap_overlay_info info; 126 struct omap_overlay_info info;
132 127
133 ovl->get_overlay_info(ovl, &info); 128 ovl->get_overlay_info(ovl, &info);
134 129
135 info.enabled = pi->enabled;
136 info.pos_x = pi->pos_x; 130 info.pos_x = pi->pos_x;
137 info.pos_y = pi->pos_y; 131 info.pos_y = pi->pos_y;
138 info.out_width = pi->out_width; 132 info.out_width = pi->out_width;
@@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
146 if (ovl->manager) 140 if (ovl->manager)
147 ovl->manager->apply(ovl->manager); 141 ovl->manager->apply(ovl->manager);
148 142
143 if (pi->enabled) {
144 r = ovl->enable(ovl);
145 if (r)
146 goto undo;
147 }
148
149 /* Release the locks in a specific order to keep lockdep happy */ 149 /* Release the locks in a specific order to keep lockdep happy */
150 if (old_rg->id > new_rg->id) { 150 if (old_rg->id > new_rg->id) {
151 omapfb_put_mem_region(old_rg); 151 omapfb_put_mem_region(old_rg);
@@ -189,19 +189,19 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
189 memset(pi, 0, sizeof(*pi)); 189 memset(pi, 0, sizeof(*pi));
190 } else { 190 } else {
191 struct omap_overlay *ovl; 191 struct omap_overlay *ovl;
192 struct omap_overlay_info *ovli; 192 struct omap_overlay_info ovli;
193 193
194 ovl = ofbi->overlays[0]; 194 ovl = ofbi->overlays[0];
195 ovli = &ovl->info; 195 ovl->get_overlay_info(ovl, &ovli);
196 196
197 pi->pos_x = ovli->pos_x; 197 pi->pos_x = ovli.pos_x;
198 pi->pos_y = ovli->pos_y; 198 pi->pos_y = ovli.pos_y;
199 pi->enabled = ovli->enabled; 199 pi->enabled = ovl->is_enabled(ovl);
200 pi->channel_out = 0; /* xxx */ 200 pi->channel_out = 0; /* xxx */
201 pi->mirror = 0; 201 pi->mirror = 0;
202 pi->mem_idx = get_mem_idx(ofbi); 202 pi->mem_idx = get_mem_idx(ofbi);
203 pi->out_width = ovli->out_width; 203 pi->out_width = ovli.out_width;
204 pi->out_height = ovli->out_height; 204 pi->out_height = ovli.out_height;
205 } 205 }
206 206
207 return 0; 207 return 0;
@@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
238 continue; 238 continue;
239 239
240 for (j = 0; j < ofbi2->num_overlays; j++) { 240 for (j = 0; j < ofbi2->num_overlays; j++) {
241 if (ofbi2->overlays[j]->info.enabled) { 241 struct omap_overlay *ovl;
242 ovl = ofbi2->overlays[j];
243 if (ovl->is_enabled(ovl)) {
242 r = -EBUSY; 244 r = -EBUSY;
243 goto out; 245 goto out;
244 } 246 }
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 68ba1f800082..ce158311ff59 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -970,16 +970,20 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
970 outh = var->yres; 970 outh = var->yres;
971 } 971 }
972 } else { 972 } else {
973 outw = ovl->info.out_width; 973 struct omap_overlay_info info;
974 outh = ovl->info.out_height; 974 ovl->get_overlay_info(ovl, &info);
975 outw = info.out_width;
976 outh = info.out_height;
975 } 977 }
976 978
977 if (init) { 979 if (init) {
978 posx = 0; 980 posx = 0;
979 posy = 0; 981 posy = 0;
980 } else { 982 } else {
981 posx = ovl->info.pos_x; 983 struct omap_overlay_info info;
982 posy = ovl->info.pos_y; 984 ovl->get_overlay_info(ovl, &info);
985 posx = info.pos_x;
986 posy = info.pos_y;
983 } 987 }
984 988
985 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); 989 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
@@ -2067,6 +2071,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
2067 if (ofbi->num_overlays > 0) { 2071 if (ofbi->num_overlays > 0) {
2068 struct omap_overlay *ovl = ofbi->overlays[0]; 2072 struct omap_overlay *ovl = ofbi->overlays[0];
2069 2073
2074 ovl->manager->apply(ovl->manager);
2075
2070 r = omapfb_overlay_enable(ovl, 1); 2076 r = omapfb_overlay_enable(ovl, 1);
2071 2077
2072 if (r) { 2078 if (r) {
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 1694d5148f32..e8d8cc76a435 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
473 continue; 473 continue;
474 474
475 for (j = 0; j < ofbi2->num_overlays; j++) { 475 for (j = 0; j < ofbi2->num_overlays; j++) {
476 if (ofbi2->overlays[j]->info.enabled) { 476 struct omap_overlay *ovl;
477 ovl = ofbi2->overlays[j];
478 if (ovl->is_enabled(ovl)) {
477 r = -EBUSY; 479 r = -EBUSY;
478 goto out; 480 goto out;
479 } 481 }
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index e12d384ea520..c0bdc9b54ecf 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev)
181static inline int omapfb_overlay_enable(struct omap_overlay *ovl, 181static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
182 int enable) 182 int enable)
183{ 183{
184 struct omap_overlay_info info; 184 if (enable)
185 185 return ovl->enable(ovl);
186 ovl->get_overlay_info(ovl, &info); 186 else
187 if (info.enabled == enable) 187 return ovl->disable(ovl);
188 return 0;
189 info.enabled = enable;
190 return ovl->set_overlay_info(ovl, &info);
191} 188}
192 189
193static inline struct omapfb2_mem_region * 190static inline struct omapfb2_mem_region *