summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-09 13:26:00 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-12-29 04:07:48 -0500
commit9960aa7cb58caadef8edf3a2582e30664a6b68dd (patch)
treeff7cfe2855cca84c59beccba9f2ca7cea36541c2 /drivers/gpu
parent5ca28914b8b4371cfa56b6ee2dec68debb99718f (diff)
drm/omap: move omapdss & displays under omapdrm
Now that omapfb has its own copy of omapdss and display drivers, we can move omapdss and display drivers which omapdrm uses to omapdrm's directory. We also need to change the main drm Makefile so that omapdrm directory is always entered, because omapdss has a file that can't be built as a module. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Dave Airlie <airlied@gmail.com> Acked-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/omapdrm/Kconfig3
-rw-r--r--drivers/gpu/drm/omapdrm/Makefile3
-rw-r--r--drivers/gpu/drm/omapdrm/displays/Kconfig86
-rw-r--r--drivers/gpu/drm/omapdrm/displays/Makefile14
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c320
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-dvi.c398
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-hdmi.c348
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-opa362.c278
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c320
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c379
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dpi.c328
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c1388
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c404
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c437
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c415
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c917
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c511
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c686
-rw-r--r--drivers/gpu/drm/omapdrm/dss/Kconfig135
-rw-r--r--drivers/gpu/drm/omapdrm/dss/Makefile18
-rw-r--r--drivers/gpu/drm/omapdrm/dss/apply.c1702
-rw-r--r--drivers/gpu/drm/omapdrm/dss/core.c343
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc-compat.c667
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc-compat.h30
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c4234
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.h918
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc_coefs.c325
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display-sysfs.c356
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display.c338
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dpi.c899
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c5607
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss-of.c183
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.c1329
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.h468
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss_features.c951
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss_features.h108
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi.h370
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c839
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.c904
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.h273
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c876
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.c916
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.h304
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_common.c148
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_phy.c247
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_pll.c255
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_wp.c282
-rw-r--r--drivers/gpu/drm/omapdrm/dss/manager-sysfs.c531
-rw-r--r--drivers/gpu/drm/omapdrm/dss/manager.c263
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c225
-rw-r--r--drivers/gpu/drm/omapdrm/dss/output.c267
-rw-r--r--drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c456
-rw-r--r--drivers/gpu/drm/omapdrm/dss/overlay.c202
-rw-r--r--drivers/gpu/drm/omapdrm/dss/pll.c389
-rw-r--r--drivers/gpu/drm/omapdrm/dss/rfbi.c1078
-rw-r--r--drivers/gpu/drm/omapdrm/dss/sdi.c454
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c997
-rw-r--r--drivers/gpu/drm/omapdrm/dss/video-pll.c211
59 files changed, 36333 insertions, 2 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1e9ff4c3e3db..db6245f4b961 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -62,7 +62,7 @@ obj-$(CONFIG_DRM_ARMADA) += armada/
62obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ 62obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
63obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ 63obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
64obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ 64obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
65obj-$(CONFIG_DRM_OMAP) += omapdrm/ 65obj-y += omapdrm/
66obj-y += tilcdc/ 66obj-y += tilcdc/
67obj-$(CONFIG_DRM_QXL) += qxl/ 67obj-$(CONFIG_DRM_QXL) += qxl/
68obj-$(CONFIG_DRM_BOCHS) += bochs/ 68obj-$(CONFIG_DRM_BOCHS) += bochs/
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index 6c220cd3497a..49b5b7df6ba4 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -1,4 +1,3 @@
1
2config DRM_OMAP 1config DRM_OMAP
3 tristate "OMAP DRM" 2 tristate "OMAP DRM"
4 depends on DRM 3 depends on DRM
@@ -24,3 +23,5 @@ config DRM_OMAP_NUM_CRTCS
24 Select the number of video overlays which can be used as framebuffers. 23 Select the number of video overlays which can be used as framebuffers.
25 The remaining overlays are reserved for video. 24 The remaining overlays are reserved for video.
26 25
26source "drivers/gpu/drm/omapdrm/dss/Kconfig"
27source "drivers/gpu/drm/omapdrm/displays/Kconfig"
diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile
index 778372b062ad..d48d97f80e8c 100644
--- a/drivers/gpu/drm/omapdrm/Makefile
+++ b/drivers/gpu/drm/omapdrm/Makefile
@@ -3,6 +3,9 @@
3# Direct Rendering Infrastructure (DRI) 3# Direct Rendering Infrastructure (DRI)
4# 4#
5 5
6obj-y += dss/
7obj-y += displays/
8
6ccflags-y := -Iinclude/drm -Werror 9ccflags-y := -Iinclude/drm -Werror
7omapdrm-y := omap_drv.o \ 10omapdrm-y := omap_drv.o \
8 omap_irq.o \ 11 omap_irq.o \
diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig
new file mode 100644
index 000000000000..574710141a61
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/Kconfig
@@ -0,0 +1,86 @@
1menu "OMAP Display Device Drivers (new device model)"
2 depends on OMAP2_DSS
3
4config DISPLAY_ENCODER_OPA362
5 tristate "OPA362 external analog amplifier"
6 help
7 Driver for OPA362 external analog TV amplifier controlled
8 through a GPIO.
9
10config DISPLAY_ENCODER_TFP410
11 tristate "TFP410 DPI to DVI Encoder"
12 help
13 Driver for TFP410 DPI to DVI encoder.
14
15config DISPLAY_ENCODER_TPD12S015
16 tristate "TPD12S015 HDMI ESD protection and level shifter"
17 help
18 Driver for TPD12S015, which offers HDMI ESD protection and level
19 shifting.
20
21config DISPLAY_CONNECTOR_DVI
22 tristate "DVI Connector"
23 depends on I2C
24 help
25 Driver for a generic DVI connector.
26
27config DISPLAY_CONNECTOR_HDMI
28 tristate "HDMI Connector"
29 help
30 Driver for a generic HDMI connector.
31
32config DISPLAY_CONNECTOR_ANALOG_TV
33 tristate "Analog TV Connector"
34 help
35 Driver for a generic analog TV connector.
36
37config DISPLAY_PANEL_DPI
38 tristate "Generic DPI panel"
39 help
40 Driver for generic DPI panels.
41
42config DISPLAY_PANEL_DSI_CM
43 tristate "Generic DSI Command Mode Panel"
44 depends on BACKLIGHT_CLASS_DEVICE
45 help
46 Driver for generic DSI command mode panels.
47
48config DISPLAY_PANEL_SONY_ACX565AKM
49 tristate "ACX565AKM Panel"
50 depends on SPI && BACKLIGHT_CLASS_DEVICE
51 help
52 This is the LCD panel used on Nokia N900
53
54config DISPLAY_PANEL_LGPHILIPS_LB035Q02
55 tristate "LG.Philips LB035Q02 LCD Panel"
56 depends on SPI
57 help
58 LCD Panel used on the Gumstix Overo Palo35
59
60config DISPLAY_PANEL_SHARP_LS037V7DW01
61 tristate "Sharp LS037V7DW01 LCD Panel"
62 depends on BACKLIGHT_CLASS_DEVICE
63 help
64 LCD Panel used in TI's SDP3430 and EVM boards
65
66config DISPLAY_PANEL_TPO_TD028TTEC1
67 tristate "TPO TD028TTEC1 LCD Panel"
68 depends on SPI
69 help
70 LCD panel used in Openmoko.
71
72config DISPLAY_PANEL_TPO_TD043MTEA1
73 tristate "TPO TD043MTEA1 LCD Panel"
74 depends on SPI
75 help
76 LCD Panel used in OMAP3 Pandora
77
78config DISPLAY_PANEL_NEC_NL8048HL11
79 tristate "NEC NL8048HL11 Panel"
80 depends on SPI
81 depends on BACKLIGHT_CLASS_DEVICE
82 help
83 This NEC NL8048HL11 panel is TFT LCD used in the
84 Zoom2/3/3630 sdp boards.
85
86endmenu
diff --git a/drivers/gpu/drm/omapdrm/displays/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile
new file mode 100644
index 000000000000..9aa176bfbf2e
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/Makefile
@@ -0,0 +1,14 @@
1obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
2obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
3obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
4obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
5obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
6obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
7obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o
8obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
9obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
10obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
11obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
12obj-$(CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
13obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
14obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
new file mode 100644
index 000000000000..8511c648a15c
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
@@ -0,0 +1,320 @@
1/*
2 * Analog TV Connector driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/slab.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/of.h>
16
17#include <video/omapdss.h>
18#include <video/omap-panel-data.h>
19
20struct panel_drv_data {
21 struct omap_dss_device dssdev;
22 struct omap_dss_device *in;
23
24 struct device *dev;
25
26 struct omap_video_timings timings;
27
28 enum omap_dss_venc_type connector_type;
29 bool invert_polarity;
30};
31
32static const struct omap_video_timings tvc_pal_timings = {
33 .x_res = 720,
34 .y_res = 574,
35 .pixelclock = 13500000,
36 .hsw = 64,
37 .hfp = 12,
38 .hbp = 68,
39 .vsw = 5,
40 .vfp = 5,
41 .vbp = 41,
42
43 .interlace = true,
44};
45
46static const struct of_device_id tvc_of_match[];
47
48struct tvc_of_data {
49 enum omap_dss_venc_type connector_type;
50};
51
52#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
53
54static int tvc_connect(struct omap_dss_device *dssdev)
55{
56 struct panel_drv_data *ddata = to_panel_data(dssdev);
57 struct omap_dss_device *in = ddata->in;
58 int r;
59
60 dev_dbg(ddata->dev, "connect\n");
61
62 if (omapdss_device_is_connected(dssdev))
63 return 0;
64
65 r = in->ops.atv->connect(in, dssdev);
66 if (r)
67 return r;
68
69 return 0;
70}
71
72static void tvc_disconnect(struct omap_dss_device *dssdev)
73{
74 struct panel_drv_data *ddata = to_panel_data(dssdev);
75 struct omap_dss_device *in = ddata->in;
76
77 dev_dbg(ddata->dev, "disconnect\n");
78
79 if (!omapdss_device_is_connected(dssdev))
80 return;
81
82 in->ops.atv->disconnect(in, dssdev);
83}
84
85static int tvc_enable(struct omap_dss_device *dssdev)
86{
87 struct panel_drv_data *ddata = to_panel_data(dssdev);
88 struct omap_dss_device *in = ddata->in;
89 int r;
90
91 dev_dbg(ddata->dev, "enable\n");
92
93 if (!omapdss_device_is_connected(dssdev))
94 return -ENODEV;
95
96 if (omapdss_device_is_enabled(dssdev))
97 return 0;
98
99 in->ops.atv->set_timings(in, &ddata->timings);
100
101 if (!ddata->dev->of_node) {
102 in->ops.atv->set_type(in, ddata->connector_type);
103
104 in->ops.atv->invert_vid_out_polarity(in,
105 ddata->invert_polarity);
106 }
107
108 r = in->ops.atv->enable(in);
109 if (r)
110 return r;
111
112 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
113
114 return r;
115}
116
117static void tvc_disable(struct omap_dss_device *dssdev)
118{
119 struct panel_drv_data *ddata = to_panel_data(dssdev);
120 struct omap_dss_device *in = ddata->in;
121
122 dev_dbg(ddata->dev, "disable\n");
123
124 if (!omapdss_device_is_enabled(dssdev))
125 return;
126
127 in->ops.atv->disable(in);
128
129 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
130}
131
132static void tvc_set_timings(struct omap_dss_device *dssdev,
133 struct omap_video_timings *timings)
134{
135 struct panel_drv_data *ddata = to_panel_data(dssdev);
136 struct omap_dss_device *in = ddata->in;
137
138 ddata->timings = *timings;
139 dssdev->panel.timings = *timings;
140
141 in->ops.atv->set_timings(in, timings);
142}
143
144static void tvc_get_timings(struct omap_dss_device *dssdev,
145 struct omap_video_timings *timings)
146{
147 struct panel_drv_data *ddata = to_panel_data(dssdev);
148
149 *timings = ddata->timings;
150}
151
152static int tvc_check_timings(struct omap_dss_device *dssdev,
153 struct omap_video_timings *timings)
154{
155 struct panel_drv_data *ddata = to_panel_data(dssdev);
156 struct omap_dss_device *in = ddata->in;
157
158 return in->ops.atv->check_timings(in, timings);
159}
160
161static u32 tvc_get_wss(struct omap_dss_device *dssdev)
162{
163 struct panel_drv_data *ddata = to_panel_data(dssdev);
164 struct omap_dss_device *in = ddata->in;
165
166 return in->ops.atv->get_wss(in);
167}
168
169static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
170{
171 struct panel_drv_data *ddata = to_panel_data(dssdev);
172 struct omap_dss_device *in = ddata->in;
173
174 return in->ops.atv->set_wss(in, wss);
175}
176
177static struct omap_dss_driver tvc_driver = {
178 .connect = tvc_connect,
179 .disconnect = tvc_disconnect,
180
181 .enable = tvc_enable,
182 .disable = tvc_disable,
183
184 .set_timings = tvc_set_timings,
185 .get_timings = tvc_get_timings,
186 .check_timings = tvc_check_timings,
187
188 .get_resolution = omapdss_default_get_resolution,
189
190 .get_wss = tvc_get_wss,
191 .set_wss = tvc_set_wss,
192};
193
194static int tvc_probe_pdata(struct platform_device *pdev)
195{
196 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
197 struct connector_atv_platform_data *pdata;
198 struct omap_dss_device *in, *dssdev;
199
200 pdata = dev_get_platdata(&pdev->dev);
201
202 in = omap_dss_find_output(pdata->source);
203 if (in == NULL) {
204 dev_err(&pdev->dev, "Failed to find video source\n");
205 return -EPROBE_DEFER;
206 }
207
208 ddata->in = in;
209
210 ddata->connector_type = pdata->connector_type;
211 ddata->invert_polarity = pdata->invert_polarity;
212
213 dssdev = &ddata->dssdev;
214 dssdev->name = pdata->name;
215
216 return 0;
217}
218
219static int tvc_probe_of(struct platform_device *pdev)
220{
221 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
222 struct device_node *node = pdev->dev.of_node;
223 struct omap_dss_device *in;
224
225 in = omapdss_of_find_source_for_first_ep(node);
226 if (IS_ERR(in)) {
227 dev_err(&pdev->dev, "failed to find video source\n");
228 return PTR_ERR(in);
229 }
230
231 ddata->in = in;
232
233 return 0;
234}
235
236static int tvc_probe(struct platform_device *pdev)
237{
238 struct panel_drv_data *ddata;
239 struct omap_dss_device *dssdev;
240 int r;
241
242 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
243 if (!ddata)
244 return -ENOMEM;
245
246 platform_set_drvdata(pdev, ddata);
247 ddata->dev = &pdev->dev;
248
249 if (dev_get_platdata(&pdev->dev)) {
250 r = tvc_probe_pdata(pdev);
251 if (r)
252 return r;
253 } else if (pdev->dev.of_node) {
254 r = tvc_probe_of(pdev);
255 if (r)
256 return r;
257 } else {
258 return -ENODEV;
259 }
260
261 ddata->timings = tvc_pal_timings;
262
263 dssdev = &ddata->dssdev;
264 dssdev->driver = &tvc_driver;
265 dssdev->dev = &pdev->dev;
266 dssdev->type = OMAP_DISPLAY_TYPE_VENC;
267 dssdev->owner = THIS_MODULE;
268 dssdev->panel.timings = tvc_pal_timings;
269
270 r = omapdss_register_display(dssdev);
271 if (r) {
272 dev_err(&pdev->dev, "Failed to register panel\n");
273 goto err_reg;
274 }
275
276 return 0;
277err_reg:
278 omap_dss_put_device(ddata->in);
279 return r;
280}
281
282static int __exit tvc_remove(struct platform_device *pdev)
283{
284 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
285 struct omap_dss_device *dssdev = &ddata->dssdev;
286 struct omap_dss_device *in = ddata->in;
287
288 omapdss_unregister_display(&ddata->dssdev);
289
290 tvc_disable(dssdev);
291 tvc_disconnect(dssdev);
292
293 omap_dss_put_device(in);
294
295 return 0;
296}
297
298static const struct of_device_id tvc_of_match[] = {
299 { .compatible = "omapdss,svideo-connector", },
300 { .compatible = "omapdss,composite-video-connector", },
301 {},
302};
303
304MODULE_DEVICE_TABLE(of, tvc_of_match);
305
306static struct platform_driver tvc_connector_driver = {
307 .probe = tvc_probe,
308 .remove = __exit_p(tvc_remove),
309 .driver = {
310 .name = "connector-analog-tv",
311 .of_match_table = tvc_of_match,
312 .suppress_bind_attrs = true,
313 },
314};
315
316module_platform_driver(tvc_connector_driver);
317
318MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
319MODULE_DESCRIPTION("Analog TV Connector driver");
320MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c
new file mode 100644
index 000000000000..d811e6dcaef7
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c
@@ -0,0 +1,398 @@
1/*
2 * Generic DVI Connector driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/i2c.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16
17#include <drm/drm_edid.h>
18
19#include <video/omapdss.h>
20#include <video/omap-panel-data.h>
21
22static const struct omap_video_timings dvic_default_timings = {
23 .x_res = 640,
24 .y_res = 480,
25
26 .pixelclock = 23500000,
27
28 .hfp = 48,
29 .hsw = 32,
30 .hbp = 80,
31
32 .vfp = 3,
33 .vsw = 4,
34 .vbp = 7,
35
36 .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
37 .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
38 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
39 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
40 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
41};
42
43struct panel_drv_data {
44 struct omap_dss_device dssdev;
45 struct omap_dss_device *in;
46
47 struct omap_video_timings timings;
48
49 struct i2c_adapter *i2c_adapter;
50};
51
52#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
53
54static int dvic_connect(struct omap_dss_device *dssdev)
55{
56 struct panel_drv_data *ddata = to_panel_data(dssdev);
57 struct omap_dss_device *in = ddata->in;
58 int r;
59
60 if (omapdss_device_is_connected(dssdev))
61 return 0;
62
63 r = in->ops.dvi->connect(in, dssdev);
64 if (r)
65 return r;
66
67 return 0;
68}
69
70static void dvic_disconnect(struct omap_dss_device *dssdev)
71{
72 struct panel_drv_data *ddata = to_panel_data(dssdev);
73 struct omap_dss_device *in = ddata->in;
74
75 if (!omapdss_device_is_connected(dssdev))
76 return;
77
78 in->ops.dvi->disconnect(in, dssdev);
79}
80
81static int dvic_enable(struct omap_dss_device *dssdev)
82{
83 struct panel_drv_data *ddata = to_panel_data(dssdev);
84 struct omap_dss_device *in = ddata->in;
85 int r;
86
87 if (!omapdss_device_is_connected(dssdev))
88 return -ENODEV;
89
90 if (omapdss_device_is_enabled(dssdev))
91 return 0;
92
93 in->ops.dvi->set_timings(in, &ddata->timings);
94
95 r = in->ops.dvi->enable(in);
96 if (r)
97 return r;
98
99 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
100
101 return 0;
102}
103
104static void dvic_disable(struct omap_dss_device *dssdev)
105{
106 struct panel_drv_data *ddata = to_panel_data(dssdev);
107 struct omap_dss_device *in = ddata->in;
108
109 if (!omapdss_device_is_enabled(dssdev))
110 return;
111
112 in->ops.dvi->disable(in);
113
114 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
115}
116
117static void dvic_set_timings(struct omap_dss_device *dssdev,
118 struct omap_video_timings *timings)
119{
120 struct panel_drv_data *ddata = to_panel_data(dssdev);
121 struct omap_dss_device *in = ddata->in;
122
123 ddata->timings = *timings;
124 dssdev->panel.timings = *timings;
125
126 in->ops.dvi->set_timings(in, timings);
127}
128
129static void dvic_get_timings(struct omap_dss_device *dssdev,
130 struct omap_video_timings *timings)
131{
132 struct panel_drv_data *ddata = to_panel_data(dssdev);
133
134 *timings = ddata->timings;
135}
136
137static int dvic_check_timings(struct omap_dss_device *dssdev,
138 struct omap_video_timings *timings)
139{
140 struct panel_drv_data *ddata = to_panel_data(dssdev);
141 struct omap_dss_device *in = ddata->in;
142
143 return in->ops.dvi->check_timings(in, timings);
144}
145
146static int dvic_ddc_read(struct i2c_adapter *adapter,
147 unsigned char *buf, u16 count, u8 offset)
148{
149 int r, retries;
150
151 for (retries = 3; retries > 0; retries--) {
152 struct i2c_msg msgs[] = {
153 {
154 .addr = DDC_ADDR,
155 .flags = 0,
156 .len = 1,
157 .buf = &offset,
158 }, {
159 .addr = DDC_ADDR,
160 .flags = I2C_M_RD,
161 .len = count,
162 .buf = buf,
163 }
164 };
165
166 r = i2c_transfer(adapter, msgs, 2);
167 if (r == 2)
168 return 0;
169
170 if (r != -EAGAIN)
171 break;
172 }
173
174 return r < 0 ? r : -EIO;
175}
176
177static int dvic_read_edid(struct omap_dss_device *dssdev,
178 u8 *edid, int len)
179{
180 struct panel_drv_data *ddata = to_panel_data(dssdev);
181 int r, l, bytes_read;
182
183 if (!ddata->i2c_adapter)
184 return -ENODEV;
185
186 l = min(EDID_LENGTH, len);
187 r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
188 if (r)
189 return r;
190
191 bytes_read = l;
192
193 /* if there are extensions, read second block */
194 if (len > EDID_LENGTH && edid[0x7e] > 0) {
195 l = min(EDID_LENGTH, len - EDID_LENGTH);
196
197 r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
198 l, EDID_LENGTH);
199 if (r)
200 return r;
201
202 bytes_read += l;
203 }
204
205 return bytes_read;
206}
207
208static bool dvic_detect(struct omap_dss_device *dssdev)
209{
210 struct panel_drv_data *ddata = to_panel_data(dssdev);
211 unsigned char out;
212 int r;
213
214 if (!ddata->i2c_adapter)
215 return true;
216
217 r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0);
218
219 return r == 0;
220}
221
222static struct omap_dss_driver dvic_driver = {
223 .connect = dvic_connect,
224 .disconnect = dvic_disconnect,
225
226 .enable = dvic_enable,
227 .disable = dvic_disable,
228
229 .set_timings = dvic_set_timings,
230 .get_timings = dvic_get_timings,
231 .check_timings = dvic_check_timings,
232
233 .get_resolution = omapdss_default_get_resolution,
234
235 .read_edid = dvic_read_edid,
236 .detect = dvic_detect,
237};
238
239static int dvic_probe_pdata(struct platform_device *pdev)
240{
241 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
242 struct connector_dvi_platform_data *pdata;
243 struct omap_dss_device *in, *dssdev;
244 int i2c_bus_num;
245
246 pdata = dev_get_platdata(&pdev->dev);
247 i2c_bus_num = pdata->i2c_bus_num;
248
249 if (i2c_bus_num != -1) {
250 struct i2c_adapter *adapter;
251
252 adapter = i2c_get_adapter(i2c_bus_num);
253 if (!adapter) {
254 dev_err(&pdev->dev,
255 "Failed to get I2C adapter, bus %d\n",
256 i2c_bus_num);
257 return -EPROBE_DEFER;
258 }
259
260 ddata->i2c_adapter = adapter;
261 }
262
263 in = omap_dss_find_output(pdata->source);
264 if (in == NULL) {
265 i2c_put_adapter(ddata->i2c_adapter);
266
267 dev_err(&pdev->dev, "Failed to find video source\n");
268 return -EPROBE_DEFER;
269 }
270
271 ddata->in = in;
272
273 dssdev = &ddata->dssdev;
274 dssdev->name = pdata->name;
275
276 return 0;
277}
278
279static int dvic_probe_of(struct platform_device *pdev)
280{
281 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
282 struct device_node *node = pdev->dev.of_node;
283 struct omap_dss_device *in;
284 struct device_node *adapter_node;
285 struct i2c_adapter *adapter;
286
287 in = omapdss_of_find_source_for_first_ep(node);
288 if (IS_ERR(in)) {
289 dev_err(&pdev->dev, "failed to find video source\n");
290 return PTR_ERR(in);
291 }
292
293 ddata->in = in;
294
295 adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
296 if (adapter_node) {
297 adapter = of_get_i2c_adapter_by_node(adapter_node);
298 if (adapter == NULL) {
299 dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
300 omap_dss_put_device(ddata->in);
301 return -EPROBE_DEFER;
302 }
303
304 ddata->i2c_adapter = adapter;
305 }
306
307 return 0;
308}
309
310static int dvic_probe(struct platform_device *pdev)
311{
312 struct panel_drv_data *ddata;
313 struct omap_dss_device *dssdev;
314 int r;
315
316 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
317 if (!ddata)
318 return -ENOMEM;
319
320 platform_set_drvdata(pdev, ddata);
321
322 if (dev_get_platdata(&pdev->dev)) {
323 r = dvic_probe_pdata(pdev);
324 if (r)
325 return r;
326 } else if (pdev->dev.of_node) {
327 r = dvic_probe_of(pdev);
328 if (r)
329 return r;
330 } else {
331 return -ENODEV;
332 }
333
334 ddata->timings = dvic_default_timings;
335
336 dssdev = &ddata->dssdev;
337 dssdev->driver = &dvic_driver;
338 dssdev->dev = &pdev->dev;
339 dssdev->type = OMAP_DISPLAY_TYPE_DVI;
340 dssdev->owner = THIS_MODULE;
341 dssdev->panel.timings = dvic_default_timings;
342
343 r = omapdss_register_display(dssdev);
344 if (r) {
345 dev_err(&pdev->dev, "Failed to register panel\n");
346 goto err_reg;
347 }
348
349 return 0;
350
351err_reg:
352 omap_dss_put_device(ddata->in);
353
354 i2c_put_adapter(ddata->i2c_adapter);
355
356 return r;
357}
358
359static int __exit dvic_remove(struct platform_device *pdev)
360{
361 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
362 struct omap_dss_device *dssdev = &ddata->dssdev;
363 struct omap_dss_device *in = ddata->in;
364
365 omapdss_unregister_display(&ddata->dssdev);
366
367 dvic_disable(dssdev);
368 dvic_disconnect(dssdev);
369
370 omap_dss_put_device(in);
371
372 i2c_put_adapter(ddata->i2c_adapter);
373
374 return 0;
375}
376
377static const struct of_device_id dvic_of_match[] = {
378 { .compatible = "omapdss,dvi-connector", },
379 {},
380};
381
382MODULE_DEVICE_TABLE(of, dvic_of_match);
383
384static struct platform_driver dvi_connector_driver = {
385 .probe = dvic_probe,
386 .remove = __exit_p(dvic_remove),
387 .driver = {
388 .name = "connector-dvi",
389 .of_match_table = dvic_of_match,
390 .suppress_bind_attrs = true,
391 },
392};
393
394module_platform_driver(dvi_connector_driver);
395
396MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
397MODULE_DESCRIPTION("Generic DVI Connector driver");
398MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
new file mode 100644
index 000000000000..6ee4129bc0c0
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
@@ -0,0 +1,348 @@
1/*
2 * HDMI Connector driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/slab.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/of.h>
16#include <linux/of_gpio.h>
17
18#include <drm/drm_edid.h>
19
20#include <video/omapdss.h>
21#include <video/omap-panel-data.h>
22
23static const struct omap_video_timings hdmic_default_timings = {
24 .x_res = 640,
25 .y_res = 480,
26 .pixelclock = 25175000,
27 .hsw = 96,
28 .hfp = 16,
29 .hbp = 48,
30 .vsw = 2,
31 .vfp = 11,
32 .vbp = 31,
33
34 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
35 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
36
37 .interlace = false,
38};
39
40struct panel_drv_data {
41 struct omap_dss_device dssdev;
42 struct omap_dss_device *in;
43
44 struct device *dev;
45
46 struct omap_video_timings timings;
47
48 int hpd_gpio;
49};
50
51#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
52
53static int hdmic_connect(struct omap_dss_device *dssdev)
54{
55 struct panel_drv_data *ddata = to_panel_data(dssdev);
56 struct omap_dss_device *in = ddata->in;
57 int r;
58
59 dev_dbg(ddata->dev, "connect\n");
60
61 if (omapdss_device_is_connected(dssdev))
62 return 0;
63
64 r = in->ops.hdmi->connect(in, dssdev);
65 if (r)
66 return r;
67
68 return 0;
69}
70
71static void hdmic_disconnect(struct omap_dss_device *dssdev)
72{
73 struct panel_drv_data *ddata = to_panel_data(dssdev);
74 struct omap_dss_device *in = ddata->in;
75
76 dev_dbg(ddata->dev, "disconnect\n");
77
78 if (!omapdss_device_is_connected(dssdev))
79 return;
80
81 in->ops.hdmi->disconnect(in, dssdev);
82}
83
84static int hdmic_enable(struct omap_dss_device *dssdev)
85{
86 struct panel_drv_data *ddata = to_panel_data(dssdev);
87 struct omap_dss_device *in = ddata->in;
88 int r;
89
90 dev_dbg(ddata->dev, "enable\n");
91
92 if (!omapdss_device_is_connected(dssdev))
93 return -ENODEV;
94
95 if (omapdss_device_is_enabled(dssdev))
96 return 0;
97
98 in->ops.hdmi->set_timings(in, &ddata->timings);
99
100 r = in->ops.hdmi->enable(in);
101 if (r)
102 return r;
103
104 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
105
106 return r;
107}
108
109static void hdmic_disable(struct omap_dss_device *dssdev)
110{
111 struct panel_drv_data *ddata = to_panel_data(dssdev);
112 struct omap_dss_device *in = ddata->in;
113
114 dev_dbg(ddata->dev, "disable\n");
115
116 if (!omapdss_device_is_enabled(dssdev))
117 return;
118
119 in->ops.hdmi->disable(in);
120
121 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
122}
123
124static void hdmic_set_timings(struct omap_dss_device *dssdev,
125 struct omap_video_timings *timings)
126{
127 struct panel_drv_data *ddata = to_panel_data(dssdev);
128 struct omap_dss_device *in = ddata->in;
129
130 ddata->timings = *timings;
131 dssdev->panel.timings = *timings;
132
133 in->ops.hdmi->set_timings(in, timings);
134}
135
136static void hdmic_get_timings(struct omap_dss_device *dssdev,
137 struct omap_video_timings *timings)
138{
139 struct panel_drv_data *ddata = to_panel_data(dssdev);
140
141 *timings = ddata->timings;
142}
143
144static int hdmic_check_timings(struct omap_dss_device *dssdev,
145 struct omap_video_timings *timings)
146{
147 struct panel_drv_data *ddata = to_panel_data(dssdev);
148 struct omap_dss_device *in = ddata->in;
149
150 return in->ops.hdmi->check_timings(in, timings);
151}
152
153static int hdmic_read_edid(struct omap_dss_device *dssdev,
154 u8 *edid, int len)
155{
156 struct panel_drv_data *ddata = to_panel_data(dssdev);
157 struct omap_dss_device *in = ddata->in;
158
159 return in->ops.hdmi->read_edid(in, edid, len);
160}
161
162static bool hdmic_detect(struct omap_dss_device *dssdev)
163{
164 struct panel_drv_data *ddata = to_panel_data(dssdev);
165 struct omap_dss_device *in = ddata->in;
166
167 if (gpio_is_valid(ddata->hpd_gpio))
168 return gpio_get_value_cansleep(ddata->hpd_gpio);
169 else
170 return in->ops.hdmi->detect(in);
171}
172
173static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
174{
175 struct panel_drv_data *ddata = to_panel_data(dssdev);
176 struct omap_dss_device *in = ddata->in;
177
178 return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
179}
180
181static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
182 const struct hdmi_avi_infoframe *avi)
183{
184 struct panel_drv_data *ddata = to_panel_data(dssdev);
185 struct omap_dss_device *in = ddata->in;
186
187 return in->ops.hdmi->set_infoframe(in, avi);
188}
189
190static struct omap_dss_driver hdmic_driver = {
191 .connect = hdmic_connect,
192 .disconnect = hdmic_disconnect,
193
194 .enable = hdmic_enable,
195 .disable = hdmic_disable,
196
197 .set_timings = hdmic_set_timings,
198 .get_timings = hdmic_get_timings,
199 .check_timings = hdmic_check_timings,
200
201 .get_resolution = omapdss_default_get_resolution,
202
203 .read_edid = hdmic_read_edid,
204 .detect = hdmic_detect,
205 .set_hdmi_mode = hdmic_set_hdmi_mode,
206 .set_hdmi_infoframe = hdmic_set_infoframe,
207};
208
209static int hdmic_probe_pdata(struct platform_device *pdev)
210{
211 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
212 struct connector_hdmi_platform_data *pdata;
213 struct omap_dss_device *in, *dssdev;
214
215 pdata = dev_get_platdata(&pdev->dev);
216
217 ddata->hpd_gpio = -ENODEV;
218
219 in = omap_dss_find_output(pdata->source);
220 if (in == NULL) {
221 dev_err(&pdev->dev, "Failed to find video source\n");
222 return -EPROBE_DEFER;
223 }
224
225 ddata->in = in;
226
227 dssdev = &ddata->dssdev;
228 dssdev->name = pdata->name;
229
230 return 0;
231}
232
233static int hdmic_probe_of(struct platform_device *pdev)
234{
235 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
236 struct device_node *node = pdev->dev.of_node;
237 struct omap_dss_device *in;
238 int gpio;
239
240 /* HPD GPIO */
241 gpio = of_get_named_gpio(node, "hpd-gpios", 0);
242 if (gpio_is_valid(gpio))
243 ddata->hpd_gpio = gpio;
244 else
245 ddata->hpd_gpio = -ENODEV;
246
247 in = omapdss_of_find_source_for_first_ep(node);
248 if (IS_ERR(in)) {
249 dev_err(&pdev->dev, "failed to find video source\n");
250 return PTR_ERR(in);
251 }
252
253 ddata->in = in;
254
255 return 0;
256}
257
258static int hdmic_probe(struct platform_device *pdev)
259{
260 struct panel_drv_data *ddata;
261 struct omap_dss_device *dssdev;
262 int r;
263
264 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
265 if (!ddata)
266 return -ENOMEM;
267
268 platform_set_drvdata(pdev, ddata);
269 ddata->dev = &pdev->dev;
270
271 if (dev_get_platdata(&pdev->dev)) {
272 r = hdmic_probe_pdata(pdev);
273 if (r)
274 return r;
275 } else if (pdev->dev.of_node) {
276 r = hdmic_probe_of(pdev);
277 if (r)
278 return r;
279 } else {
280 return -ENODEV;
281 }
282
283 if (gpio_is_valid(ddata->hpd_gpio)) {
284 r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
285 GPIOF_DIR_IN, "hdmi_hpd");
286 if (r)
287 goto err_reg;
288 }
289
290 ddata->timings = hdmic_default_timings;
291
292 dssdev = &ddata->dssdev;
293 dssdev->driver = &hdmic_driver;
294 dssdev->dev = &pdev->dev;
295 dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
296 dssdev->owner = THIS_MODULE;
297 dssdev->panel.timings = hdmic_default_timings;
298
299 r = omapdss_register_display(dssdev);
300 if (r) {
301 dev_err(&pdev->dev, "Failed to register panel\n");
302 goto err_reg;
303 }
304
305 return 0;
306err_reg:
307 omap_dss_put_device(ddata->in);
308 return r;
309}
310
311static int __exit hdmic_remove(struct platform_device *pdev)
312{
313 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
314 struct omap_dss_device *dssdev = &ddata->dssdev;
315 struct omap_dss_device *in = ddata->in;
316
317 omapdss_unregister_display(&ddata->dssdev);
318
319 hdmic_disable(dssdev);
320 hdmic_disconnect(dssdev);
321
322 omap_dss_put_device(in);
323
324 return 0;
325}
326
327static const struct of_device_id hdmic_of_match[] = {
328 { .compatible = "omapdss,hdmi-connector", },
329 {},
330};
331
332MODULE_DEVICE_TABLE(of, hdmic_of_match);
333
334static struct platform_driver hdmi_connector_driver = {
335 .probe = hdmic_probe,
336 .remove = __exit_p(hdmic_remove),
337 .driver = {
338 .name = "connector-hdmi",
339 .of_match_table = hdmic_of_match,
340 .suppress_bind_attrs = true,
341 },
342};
343
344module_platform_driver(hdmi_connector_driver);
345
346MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
347MODULE_DESCRIPTION("HDMI Connector driver");
348MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
new file mode 100644
index 000000000000..8c246c213e06
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
@@ -0,0 +1,278 @@
1/*
2 * OPA362 analog video amplifier with output/power control
3 *
4 * Copyright (C) 2014 Golden Delicious Computers
5 * Author: H. Nikolaus Schaller <hns@goldelico.com>
6 *
7 * based on encoder-tfp410
8 *
9 * Copyright (C) 2013 Texas Instruments
10 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 */
16
17#include <linux/gpio.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/of_gpio.h>
22
23#include <video/omapdss.h>
24
25struct panel_drv_data {
26 struct omap_dss_device dssdev;
27 struct omap_dss_device *in;
28
29 struct gpio_desc *enable_gpio;
30
31 struct omap_video_timings timings;
32};
33
34#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
35
36static int opa362_connect(struct omap_dss_device *dssdev,
37 struct omap_dss_device *dst)
38{
39 struct panel_drv_data *ddata = to_panel_data(dssdev);
40 struct omap_dss_device *in = ddata->in;
41 int r;
42
43 dev_dbg(dssdev->dev, "connect\n");
44
45 if (omapdss_device_is_connected(dssdev))
46 return -EBUSY;
47
48 r = in->ops.atv->connect(in, dssdev);
49 if (r)
50 return r;
51
52 dst->src = dssdev;
53 dssdev->dst = dst;
54
55 return 0;
56}
57
58static void opa362_disconnect(struct omap_dss_device *dssdev,
59 struct omap_dss_device *dst)
60{
61 struct panel_drv_data *ddata = to_panel_data(dssdev);
62 struct omap_dss_device *in = ddata->in;
63
64 dev_dbg(dssdev->dev, "disconnect\n");
65
66 WARN_ON(!omapdss_device_is_connected(dssdev));
67 if (!omapdss_device_is_connected(dssdev))
68 return;
69
70 WARN_ON(dst != dssdev->dst);
71 if (dst != dssdev->dst)
72 return;
73
74 dst->src = NULL;
75 dssdev->dst = NULL;
76
77 in->ops.atv->disconnect(in, &ddata->dssdev);
78}
79
80static int opa362_enable(struct omap_dss_device *dssdev)
81{
82 struct panel_drv_data *ddata = to_panel_data(dssdev);
83 struct omap_dss_device *in = ddata->in;
84 int r;
85
86 dev_dbg(dssdev->dev, "enable\n");
87
88 if (!omapdss_device_is_connected(dssdev))
89 return -ENODEV;
90
91 if (omapdss_device_is_enabled(dssdev))
92 return 0;
93
94 in->ops.atv->set_timings(in, &ddata->timings);
95
96 r = in->ops.atv->enable(in);
97 if (r)
98 return r;
99
100 if (ddata->enable_gpio)
101 gpiod_set_value_cansleep(ddata->enable_gpio, 1);
102
103 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
104
105 return 0;
106}
107
108static void opa362_disable(struct omap_dss_device *dssdev)
109{
110 struct panel_drv_data *ddata = to_panel_data(dssdev);
111 struct omap_dss_device *in = ddata->in;
112
113 dev_dbg(dssdev->dev, "disable\n");
114
115 if (!omapdss_device_is_enabled(dssdev))
116 return;
117
118 if (ddata->enable_gpio)
119 gpiod_set_value_cansleep(ddata->enable_gpio, 0);
120
121 in->ops.atv->disable(in);
122
123 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
124}
125
126static void opa362_set_timings(struct omap_dss_device *dssdev,
127 struct omap_video_timings *timings)
128{
129 struct panel_drv_data *ddata = to_panel_data(dssdev);
130 struct omap_dss_device *in = ddata->in;
131
132 dev_dbg(dssdev->dev, "set_timings\n");
133
134 ddata->timings = *timings;
135 dssdev->panel.timings = *timings;
136
137 in->ops.atv->set_timings(in, timings);
138}
139
140static void opa362_get_timings(struct omap_dss_device *dssdev,
141 struct omap_video_timings *timings)
142{
143 struct panel_drv_data *ddata = to_panel_data(dssdev);
144
145 dev_dbg(dssdev->dev, "get_timings\n");
146
147 *timings = ddata->timings;
148}
149
150static int opa362_check_timings(struct omap_dss_device *dssdev,
151 struct omap_video_timings *timings)
152{
153 struct panel_drv_data *ddata = to_panel_data(dssdev);
154 struct omap_dss_device *in = ddata->in;
155
156 dev_dbg(dssdev->dev, "check_timings\n");
157
158 return in->ops.atv->check_timings(in, timings);
159}
160
161static void opa362_set_type(struct omap_dss_device *dssdev,
162 enum omap_dss_venc_type type)
163{
164 /* we can only drive a COMPOSITE output */
165 WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
166
167}
168
169static const struct omapdss_atv_ops opa362_atv_ops = {
170 .connect = opa362_connect,
171 .disconnect = opa362_disconnect,
172
173 .enable = opa362_enable,
174 .disable = opa362_disable,
175
176 .check_timings = opa362_check_timings,
177 .set_timings = opa362_set_timings,
178 .get_timings = opa362_get_timings,
179
180 .set_type = opa362_set_type,
181};
182
183static int opa362_probe(struct platform_device *pdev)
184{
185 struct device_node *node = pdev->dev.of_node;
186 struct panel_drv_data *ddata;
187 struct omap_dss_device *dssdev, *in;
188 struct gpio_desc *gpio;
189 int r;
190
191 dev_dbg(&pdev->dev, "probe\n");
192
193 if (node == NULL) {
194 dev_err(&pdev->dev, "Unable to find device tree\n");
195 return -EINVAL;
196 }
197
198 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
199 if (!ddata)
200 return -ENOMEM;
201
202 platform_set_drvdata(pdev, ddata);
203
204 gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
205 if (IS_ERR(gpio))
206 return PTR_ERR(gpio);
207
208 ddata->enable_gpio = gpio;
209
210 in = omapdss_of_find_source_for_first_ep(node);
211 if (IS_ERR(in)) {
212 dev_err(&pdev->dev, "failed to find video source\n");
213 return PTR_ERR(in);
214 }
215
216 ddata->in = in;
217
218 dssdev = &ddata->dssdev;
219 dssdev->ops.atv = &opa362_atv_ops;
220 dssdev->dev = &pdev->dev;
221 dssdev->type = OMAP_DISPLAY_TYPE_VENC;
222 dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
223 dssdev->owner = THIS_MODULE;
224
225 r = omapdss_register_output(dssdev);
226 if (r) {
227 dev_err(&pdev->dev, "Failed to register output\n");
228 goto err_reg;
229 }
230
231 return 0;
232err_reg:
233 omap_dss_put_device(ddata->in);
234 return r;
235}
236
237static int __exit opa362_remove(struct platform_device *pdev)
238{
239 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
240 struct omap_dss_device *dssdev = &ddata->dssdev;
241 struct omap_dss_device *in = ddata->in;
242
243 omapdss_unregister_output(&ddata->dssdev);
244
245 WARN_ON(omapdss_device_is_enabled(dssdev));
246 if (omapdss_device_is_enabled(dssdev))
247 opa362_disable(dssdev);
248
249 WARN_ON(omapdss_device_is_connected(dssdev));
250 if (omapdss_device_is_connected(dssdev))
251 opa362_disconnect(dssdev, dssdev->dst);
252
253 omap_dss_put_device(in);
254
255 return 0;
256}
257
258static const struct of_device_id opa362_of_match[] = {
259 { .compatible = "omapdss,ti,opa362", },
260 {},
261};
262MODULE_DEVICE_TABLE(of, opa362_of_match);
263
264static struct platform_driver opa362_driver = {
265 .probe = opa362_probe,
266 .remove = __exit_p(opa362_remove),
267 .driver = {
268 .name = "amplifier-opa362",
269 .of_match_table = opa362_of_match,
270 .suppress_bind_attrs = true,
271 },
272};
273
274module_platform_driver(opa362_driver);
275
276MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
277MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
278MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
new file mode 100644
index 000000000000..d9048b3df495
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
@@ -0,0 +1,320 @@
1/*
2 * TFP410 DPI-to-DVI encoder driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/gpio.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/of_gpio.h>
17
18#include <video/omapdss.h>
19#include <video/omap-panel-data.h>
20
21struct panel_drv_data {
22 struct omap_dss_device dssdev;
23 struct omap_dss_device *in;
24
25 int pd_gpio;
26 int data_lines;
27
28 struct omap_video_timings timings;
29};
30
31#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
32
33static int tfp410_connect(struct omap_dss_device *dssdev,
34 struct omap_dss_device *dst)
35{
36 struct panel_drv_data *ddata = to_panel_data(dssdev);
37 struct omap_dss_device *in = ddata->in;
38 int r;
39
40 if (omapdss_device_is_connected(dssdev))
41 return -EBUSY;
42
43 r = in->ops.dpi->connect(in, dssdev);
44 if (r)
45 return r;
46
47 dst->src = dssdev;
48 dssdev->dst = dst;
49
50 return 0;
51}
52
53static void tfp410_disconnect(struct omap_dss_device *dssdev,
54 struct omap_dss_device *dst)
55{
56 struct panel_drv_data *ddata = to_panel_data(dssdev);
57 struct omap_dss_device *in = ddata->in;
58
59 WARN_ON(!omapdss_device_is_connected(dssdev));
60 if (!omapdss_device_is_connected(dssdev))
61 return;
62
63 WARN_ON(dst != dssdev->dst);
64 if (dst != dssdev->dst)
65 return;
66
67 dst->src = NULL;
68 dssdev->dst = NULL;
69
70 in->ops.dpi->disconnect(in, &ddata->dssdev);
71}
72
73static int tfp410_enable(struct omap_dss_device *dssdev)
74{
75 struct panel_drv_data *ddata = to_panel_data(dssdev);
76 struct omap_dss_device *in = ddata->in;
77 int r;
78
79 if (!omapdss_device_is_connected(dssdev))
80 return -ENODEV;
81
82 if (omapdss_device_is_enabled(dssdev))
83 return 0;
84
85 in->ops.dpi->set_timings(in, &ddata->timings);
86 if (ddata->data_lines)
87 in->ops.dpi->set_data_lines(in, ddata->data_lines);
88
89 r = in->ops.dpi->enable(in);
90 if (r)
91 return r;
92
93 if (gpio_is_valid(ddata->pd_gpio))
94 gpio_set_value_cansleep(ddata->pd_gpio, 1);
95
96 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
97
98 return 0;
99}
100
101static void tfp410_disable(struct omap_dss_device *dssdev)
102{
103 struct panel_drv_data *ddata = to_panel_data(dssdev);
104 struct omap_dss_device *in = ddata->in;
105
106 if (!omapdss_device_is_enabled(dssdev))
107 return;
108
109 if (gpio_is_valid(ddata->pd_gpio))
110 gpio_set_value_cansleep(ddata->pd_gpio, 0);
111
112 in->ops.dpi->disable(in);
113
114 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
115}
116
117static void tfp410_fix_timings(struct omap_video_timings *timings)
118{
119 timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
120 timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
121 timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
122}
123
124static void tfp410_set_timings(struct omap_dss_device *dssdev,
125 struct omap_video_timings *timings)
126{
127 struct panel_drv_data *ddata = to_panel_data(dssdev);
128 struct omap_dss_device *in = ddata->in;
129
130 tfp410_fix_timings(timings);
131
132 ddata->timings = *timings;
133 dssdev->panel.timings = *timings;
134
135 in->ops.dpi->set_timings(in, timings);
136}
137
138static void tfp410_get_timings(struct omap_dss_device *dssdev,
139 struct omap_video_timings *timings)
140{
141 struct panel_drv_data *ddata = to_panel_data(dssdev);
142
143 *timings = ddata->timings;
144}
145
146static int tfp410_check_timings(struct omap_dss_device *dssdev,
147 struct omap_video_timings *timings)
148{
149 struct panel_drv_data *ddata = to_panel_data(dssdev);
150 struct omap_dss_device *in = ddata->in;
151
152 tfp410_fix_timings(timings);
153
154 return in->ops.dpi->check_timings(in, timings);
155}
156
157static const struct omapdss_dvi_ops tfp410_dvi_ops = {
158 .connect = tfp410_connect,
159 .disconnect = tfp410_disconnect,
160
161 .enable = tfp410_enable,
162 .disable = tfp410_disable,
163
164 .check_timings = tfp410_check_timings,
165 .set_timings = tfp410_set_timings,
166 .get_timings = tfp410_get_timings,
167};
168
169static int tfp410_probe_pdata(struct platform_device *pdev)
170{
171 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
172 struct encoder_tfp410_platform_data *pdata;
173 struct omap_dss_device *dssdev, *in;
174
175 pdata = dev_get_platdata(&pdev->dev);
176
177 ddata->pd_gpio = pdata->power_down_gpio;
178
179 ddata->data_lines = pdata->data_lines;
180
181 in = omap_dss_find_output(pdata->source);
182 if (in == NULL) {
183 dev_err(&pdev->dev, "Failed to find video source\n");
184 return -ENODEV;
185 }
186
187 ddata->in = in;
188
189 dssdev = &ddata->dssdev;
190 dssdev->name = pdata->name;
191
192 return 0;
193}
194
195static int tfp410_probe_of(struct platform_device *pdev)
196{
197 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
198 struct device_node *node = pdev->dev.of_node;
199 struct omap_dss_device *in;
200 int gpio;
201
202 gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
203
204 if (gpio_is_valid(gpio) || gpio == -ENOENT) {
205 ddata->pd_gpio = gpio;
206 } else {
207 dev_err(&pdev->dev, "failed to parse PD gpio\n");
208 return gpio;
209 }
210
211 in = omapdss_of_find_source_for_first_ep(node);
212 if (IS_ERR(in)) {
213 dev_err(&pdev->dev, "failed to find video source\n");
214 return PTR_ERR(in);
215 }
216
217 ddata->in = in;
218
219 return 0;
220}
221
222static int tfp410_probe(struct platform_device *pdev)
223{
224 struct panel_drv_data *ddata;
225 struct omap_dss_device *dssdev;
226 int r;
227
228 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
229 if (!ddata)
230 return -ENOMEM;
231
232 platform_set_drvdata(pdev, ddata);
233
234 if (dev_get_platdata(&pdev->dev)) {
235 r = tfp410_probe_pdata(pdev);
236 if (r)
237 return r;
238 } else if (pdev->dev.of_node) {
239 r = tfp410_probe_of(pdev);
240 if (r)
241 return r;
242 } else {
243 return -ENODEV;
244 }
245
246 if (gpio_is_valid(ddata->pd_gpio)) {
247 r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
248 GPIOF_OUT_INIT_LOW, "tfp410 PD");
249 if (r) {
250 dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
251 ddata->pd_gpio);
252 goto err_gpio;
253 }
254 }
255
256 dssdev = &ddata->dssdev;
257 dssdev->ops.dvi = &tfp410_dvi_ops;
258 dssdev->dev = &pdev->dev;
259 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
260 dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
261 dssdev->owner = THIS_MODULE;
262 dssdev->phy.dpi.data_lines = ddata->data_lines;
263 dssdev->port_num = 1;
264
265 r = omapdss_register_output(dssdev);
266 if (r) {
267 dev_err(&pdev->dev, "Failed to register output\n");
268 goto err_reg;
269 }
270
271 return 0;
272err_reg:
273err_gpio:
274 omap_dss_put_device(ddata->in);
275 return r;
276}
277
278static int __exit tfp410_remove(struct platform_device *pdev)
279{
280 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
281 struct omap_dss_device *dssdev = &ddata->dssdev;
282 struct omap_dss_device *in = ddata->in;
283
284 omapdss_unregister_output(&ddata->dssdev);
285
286 WARN_ON(omapdss_device_is_enabled(dssdev));
287 if (omapdss_device_is_enabled(dssdev))
288 tfp410_disable(dssdev);
289
290 WARN_ON(omapdss_device_is_connected(dssdev));
291 if (omapdss_device_is_connected(dssdev))
292 tfp410_disconnect(dssdev, dssdev->dst);
293
294 omap_dss_put_device(in);
295
296 return 0;
297}
298
299static const struct of_device_id tfp410_of_match[] = {
300 { .compatible = "omapdss,ti,tfp410", },
301 {},
302};
303
304MODULE_DEVICE_TABLE(of, tfp410_of_match);
305
306static struct platform_driver tfp410_driver = {
307 .probe = tfp410_probe,
308 .remove = __exit_p(tfp410_remove),
309 .driver = {
310 .name = "tfp410",
311 .of_match_table = tfp410_of_match,
312 .suppress_bind_attrs = true,
313 },
314};
315
316module_platform_driver(tfp410_driver);
317
318MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
319MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
320MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
new file mode 100644
index 000000000000..990af6baeb0f
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
@@ -0,0 +1,379 @@
1/*
2 * TPD12S015 HDMI ESD protection & level shifter chip driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/completion.h>
13#include <linux/delay.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/gpio.h>
17#include <linux/platform_device.h>
18#include <linux/of_gpio.h>
19
20#include <video/omapdss.h>
21#include <video/omap-panel-data.h>
22
23struct panel_drv_data {
24 struct omap_dss_device dssdev;
25 struct omap_dss_device *in;
26
27 int ct_cp_hpd_gpio;
28 int ls_oe_gpio;
29 int hpd_gpio;
30
31 struct omap_video_timings timings;
32};
33
34#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
35
36static int tpd_connect(struct omap_dss_device *dssdev,
37 struct omap_dss_device *dst)
38{
39 struct panel_drv_data *ddata = to_panel_data(dssdev);
40 struct omap_dss_device *in = ddata->in;
41 int r;
42
43 r = in->ops.hdmi->connect(in, dssdev);
44 if (r)
45 return r;
46
47 dst->src = dssdev;
48 dssdev->dst = dst;
49
50 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
51 /* DC-DC converter needs at max 300us to get to 90% of 5V */
52 udelay(300);
53
54 return 0;
55}
56
57static void tpd_disconnect(struct omap_dss_device *dssdev,
58 struct omap_dss_device *dst)
59{
60 struct panel_drv_data *ddata = to_panel_data(dssdev);
61 struct omap_dss_device *in = ddata->in;
62
63 WARN_ON(dst != dssdev->dst);
64
65 if (dst != dssdev->dst)
66 return;
67
68 gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
69
70 dst->src = NULL;
71 dssdev->dst = NULL;
72
73 in->ops.hdmi->disconnect(in, &ddata->dssdev);
74}
75
76static int tpd_enable(struct omap_dss_device *dssdev)
77{
78 struct panel_drv_data *ddata = to_panel_data(dssdev);
79 struct omap_dss_device *in = ddata->in;
80 int r;
81
82 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
83 return 0;
84
85 in->ops.hdmi->set_timings(in, &ddata->timings);
86
87 r = in->ops.hdmi->enable(in);
88 if (r)
89 return r;
90
91 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
92
93 return r;
94}
95
96static void tpd_disable(struct omap_dss_device *dssdev)
97{
98 struct panel_drv_data *ddata = to_panel_data(dssdev);
99 struct omap_dss_device *in = ddata->in;
100
101 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
102 return;
103
104 in->ops.hdmi->disable(in);
105
106 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
107}
108
109static void tpd_set_timings(struct omap_dss_device *dssdev,
110 struct omap_video_timings *timings)
111{
112 struct panel_drv_data *ddata = to_panel_data(dssdev);
113 struct omap_dss_device *in = ddata->in;
114
115 ddata->timings = *timings;
116 dssdev->panel.timings = *timings;
117
118 in->ops.hdmi->set_timings(in, timings);
119}
120
121static void tpd_get_timings(struct omap_dss_device *dssdev,
122 struct omap_video_timings *timings)
123{
124 struct panel_drv_data *ddata = to_panel_data(dssdev);
125
126 *timings = ddata->timings;
127}
128
129static int tpd_check_timings(struct omap_dss_device *dssdev,
130 struct omap_video_timings *timings)
131{
132 struct panel_drv_data *ddata = to_panel_data(dssdev);
133 struct omap_dss_device *in = ddata->in;
134 int r;
135
136 r = in->ops.hdmi->check_timings(in, timings);
137
138 return r;
139}
140
141static int tpd_read_edid(struct omap_dss_device *dssdev,
142 u8 *edid, int len)
143{
144 struct panel_drv_data *ddata = to_panel_data(dssdev);
145 struct omap_dss_device *in = ddata->in;
146 int r;
147
148 if (!gpio_get_value_cansleep(ddata->hpd_gpio))
149 return -ENODEV;
150
151 if (gpio_is_valid(ddata->ls_oe_gpio))
152 gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
153
154 r = in->ops.hdmi->read_edid(in, edid, len);
155
156 if (gpio_is_valid(ddata->ls_oe_gpio))
157 gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
158
159 return r;
160}
161
162static bool tpd_detect(struct omap_dss_device *dssdev)
163{
164 struct panel_drv_data *ddata = to_panel_data(dssdev);
165
166 return gpio_get_value_cansleep(ddata->hpd_gpio);
167}
168
169static int tpd_set_infoframe(struct omap_dss_device *dssdev,
170 const struct hdmi_avi_infoframe *avi)
171{
172 struct panel_drv_data *ddata = to_panel_data(dssdev);
173 struct omap_dss_device *in = ddata->in;
174
175 return in->ops.hdmi->set_infoframe(in, avi);
176}
177
178static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
179 bool hdmi_mode)
180{
181 struct panel_drv_data *ddata = to_panel_data(dssdev);
182 struct omap_dss_device *in = ddata->in;
183
184 return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
185}
186
187static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
188 .connect = tpd_connect,
189 .disconnect = tpd_disconnect,
190
191 .enable = tpd_enable,
192 .disable = tpd_disable,
193
194 .check_timings = tpd_check_timings,
195 .set_timings = tpd_set_timings,
196 .get_timings = tpd_get_timings,
197
198 .read_edid = tpd_read_edid,
199 .detect = tpd_detect,
200 .set_infoframe = tpd_set_infoframe,
201 .set_hdmi_mode = tpd_set_hdmi_mode,
202};
203
204static int tpd_probe_pdata(struct platform_device *pdev)
205{
206 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
207 struct encoder_tpd12s015_platform_data *pdata;
208 struct omap_dss_device *dssdev, *in;
209
210 pdata = dev_get_platdata(&pdev->dev);
211
212 ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio;
213 ddata->ls_oe_gpio = pdata->ls_oe_gpio;
214 ddata->hpd_gpio = pdata->hpd_gpio;
215
216 in = omap_dss_find_output(pdata->source);
217 if (in == NULL) {
218 dev_err(&pdev->dev, "Failed to find video source\n");
219 return -ENODEV;
220 }
221
222 ddata->in = in;
223
224 dssdev = &ddata->dssdev;
225 dssdev->name = pdata->name;
226
227 return 0;
228}
229
230static int tpd_probe_of(struct platform_device *pdev)
231{
232 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
233 struct device_node *node = pdev->dev.of_node;
234 struct omap_dss_device *in;
235 int gpio;
236
237 /* CT CP HPD GPIO */
238 gpio = of_get_gpio(node, 0);
239 if (!gpio_is_valid(gpio)) {
240 dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n");
241 return gpio;
242 }
243 ddata->ct_cp_hpd_gpio = gpio;
244
245 /* LS OE GPIO */
246 gpio = of_get_gpio(node, 1);
247 if (gpio_is_valid(gpio) || gpio == -ENOENT) {
248 ddata->ls_oe_gpio = gpio;
249 } else {
250 dev_err(&pdev->dev, "failed to parse LS OE gpio\n");
251 return gpio;
252 }
253
254 /* HPD GPIO */
255 gpio = of_get_gpio(node, 2);
256 if (!gpio_is_valid(gpio)) {
257 dev_err(&pdev->dev, "failed to parse HPD gpio\n");
258 return gpio;
259 }
260 ddata->hpd_gpio = gpio;
261
262 in = omapdss_of_find_source_for_first_ep(node);
263 if (IS_ERR(in)) {
264 dev_err(&pdev->dev, "failed to find video source\n");
265 return PTR_ERR(in);
266 }
267
268 ddata->in = in;
269
270 return 0;
271}
272
273static int tpd_probe(struct platform_device *pdev)
274{
275 struct omap_dss_device *in, *dssdev;
276 struct panel_drv_data *ddata;
277 int r;
278
279 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
280 if (!ddata)
281 return -ENOMEM;
282
283 platform_set_drvdata(pdev, ddata);
284
285 if (dev_get_platdata(&pdev->dev)) {
286 r = tpd_probe_pdata(pdev);
287 if (r)
288 return r;
289 } else if (pdev->dev.of_node) {
290 r = tpd_probe_of(pdev);
291 if (r)
292 return r;
293 } else {
294 return -ENODEV;
295 }
296
297 r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio,
298 GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd");
299 if (r)
300 goto err_gpio;
301
302 if (gpio_is_valid(ddata->ls_oe_gpio)) {
303 r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio,
304 GPIOF_OUT_INIT_LOW, "hdmi_ls_oe");
305 if (r)
306 goto err_gpio;
307 }
308
309 r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
310 GPIOF_DIR_IN, "hdmi_hpd");
311 if (r)
312 goto err_gpio;
313
314 dssdev = &ddata->dssdev;
315 dssdev->ops.hdmi = &tpd_hdmi_ops;
316 dssdev->dev = &pdev->dev;
317 dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
318 dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
319 dssdev->owner = THIS_MODULE;
320 dssdev->port_num = 1;
321
322 in = ddata->in;
323
324 r = omapdss_register_output(dssdev);
325 if (r) {
326 dev_err(&pdev->dev, "Failed to register output\n");
327 goto err_reg;
328 }
329
330 return 0;
331err_reg:
332err_gpio:
333 omap_dss_put_device(ddata->in);
334 return r;
335}
336
337static int __exit tpd_remove(struct platform_device *pdev)
338{
339 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
340 struct omap_dss_device *dssdev = &ddata->dssdev;
341 struct omap_dss_device *in = ddata->in;
342
343 omapdss_unregister_output(&ddata->dssdev);
344
345 WARN_ON(omapdss_device_is_enabled(dssdev));
346 if (omapdss_device_is_enabled(dssdev))
347 tpd_disable(dssdev);
348
349 WARN_ON(omapdss_device_is_connected(dssdev));
350 if (omapdss_device_is_connected(dssdev))
351 tpd_disconnect(dssdev, dssdev->dst);
352
353 omap_dss_put_device(in);
354
355 return 0;
356}
357
358static const struct of_device_id tpd_of_match[] = {
359 { .compatible = "omapdss,ti,tpd12s015", },
360 {},
361};
362
363MODULE_DEVICE_TABLE(of, tpd_of_match);
364
365static struct platform_driver tpd_driver = {
366 .probe = tpd_probe,
367 .remove = __exit_p(tpd_remove),
368 .driver = {
369 .name = "tpd12s015",
370 .of_match_table = tpd_of_match,
371 .suppress_bind_attrs = true,
372 },
373};
374
375module_platform_driver(tpd_driver);
376
377MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
378MODULE_DESCRIPTION("TPD12S015 driver");
379MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
new file mode 100644
index 000000000000..e780fd4f8b46
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
@@ -0,0 +1,328 @@
1/*
2 * Generic MIPI DPI Panel Driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/gpio.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/of.h>
17#include <linux/of_gpio.h>
18
19#include <video/omapdss.h>
20#include <video/omap-panel-data.h>
21#include <video/of_display_timing.h>
22
23struct panel_drv_data {
24 struct omap_dss_device dssdev;
25 struct omap_dss_device *in;
26
27 int data_lines;
28
29 struct omap_video_timings videomode;
30
31 /* used for non-DT boot, to be removed */
32 int backlight_gpio;
33
34 struct gpio_desc *enable_gpio;
35};
36
37#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
38
39static int panel_dpi_connect(struct omap_dss_device *dssdev)
40{
41 struct panel_drv_data *ddata = to_panel_data(dssdev);
42 struct omap_dss_device *in = ddata->in;
43 int r;
44
45 if (omapdss_device_is_connected(dssdev))
46 return 0;
47
48 r = in->ops.dpi->connect(in, dssdev);
49 if (r)
50 return r;
51
52 return 0;
53}
54
55static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
56{
57 struct panel_drv_data *ddata = to_panel_data(dssdev);
58 struct omap_dss_device *in = ddata->in;
59
60 if (!omapdss_device_is_connected(dssdev))
61 return;
62
63 in->ops.dpi->disconnect(in, dssdev);
64}
65
66static int panel_dpi_enable(struct omap_dss_device *dssdev)
67{
68 struct panel_drv_data *ddata = to_panel_data(dssdev);
69 struct omap_dss_device *in = ddata->in;
70 int r;
71
72 if (!omapdss_device_is_connected(dssdev))
73 return -ENODEV;
74
75 if (omapdss_device_is_enabled(dssdev))
76 return 0;
77
78 if (ddata->data_lines)
79 in->ops.dpi->set_data_lines(in, ddata->data_lines);
80 in->ops.dpi->set_timings(in, &ddata->videomode);
81
82 r = in->ops.dpi->enable(in);
83 if (r)
84 return r;
85
86 gpiod_set_value_cansleep(ddata->enable_gpio, 1);
87
88 if (gpio_is_valid(ddata->backlight_gpio))
89 gpio_set_value_cansleep(ddata->backlight_gpio, 1);
90
91 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
92
93 return 0;
94}
95
96static void panel_dpi_disable(struct omap_dss_device *dssdev)
97{
98 struct panel_drv_data *ddata = to_panel_data(dssdev);
99 struct omap_dss_device *in = ddata->in;
100
101 if (!omapdss_device_is_enabled(dssdev))
102 return;
103
104 if (gpio_is_valid(ddata->backlight_gpio))
105 gpio_set_value_cansleep(ddata->backlight_gpio, 0);
106
107 gpiod_set_value_cansleep(ddata->enable_gpio, 0);
108
109 in->ops.dpi->disable(in);
110
111 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
112}
113
114static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
115 struct omap_video_timings *timings)
116{
117 struct panel_drv_data *ddata = to_panel_data(dssdev);
118 struct omap_dss_device *in = ddata->in;
119
120 ddata->videomode = *timings;
121 dssdev->panel.timings = *timings;
122
123 in->ops.dpi->set_timings(in, timings);
124}
125
126static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
127 struct omap_video_timings *timings)
128{
129 struct panel_drv_data *ddata = to_panel_data(dssdev);
130
131 *timings = ddata->videomode;
132}
133
134static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
135 struct omap_video_timings *timings)
136{
137 struct panel_drv_data *ddata = to_panel_data(dssdev);
138 struct omap_dss_device *in = ddata->in;
139
140 return in->ops.dpi->check_timings(in, timings);
141}
142
143static struct omap_dss_driver panel_dpi_ops = {
144 .connect = panel_dpi_connect,
145 .disconnect = panel_dpi_disconnect,
146
147 .enable = panel_dpi_enable,
148 .disable = panel_dpi_disable,
149
150 .set_timings = panel_dpi_set_timings,
151 .get_timings = panel_dpi_get_timings,
152 .check_timings = panel_dpi_check_timings,
153
154 .get_resolution = omapdss_default_get_resolution,
155};
156
157static int panel_dpi_probe_pdata(struct platform_device *pdev)
158{
159 const struct panel_dpi_platform_data *pdata;
160 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
161 struct omap_dss_device *dssdev, *in;
162 struct videomode vm;
163 int r;
164
165 pdata = dev_get_platdata(&pdev->dev);
166
167 in = omap_dss_find_output(pdata->source);
168 if (in == NULL) {
169 dev_err(&pdev->dev, "failed to find video source '%s'\n",
170 pdata->source);
171 return -EPROBE_DEFER;
172 }
173
174 ddata->in = in;
175
176 ddata->data_lines = pdata->data_lines;
177
178 videomode_from_timing(pdata->display_timing, &vm);
179 videomode_to_omap_video_timings(&vm, &ddata->videomode);
180
181 dssdev = &ddata->dssdev;
182 dssdev->name = pdata->name;
183
184 r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
185 GPIOF_OUT_INIT_LOW, "panel enable");
186 if (r)
187 goto err_gpio;
188
189 ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
190
191 ddata->backlight_gpio = pdata->backlight_gpio;
192
193 return 0;
194
195err_gpio:
196 omap_dss_put_device(ddata->in);
197 return r;
198}
199
200static int panel_dpi_probe_of(struct platform_device *pdev)
201{
202 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
203 struct device_node *node = pdev->dev.of_node;
204 struct omap_dss_device *in;
205 int r;
206 struct display_timing timing;
207 struct videomode vm;
208 struct gpio_desc *gpio;
209
210 gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
211 if (IS_ERR(gpio))
212 return PTR_ERR(gpio);
213
214 ddata->enable_gpio = gpio;
215
216 ddata->backlight_gpio = -ENOENT;
217
218 r = of_get_display_timing(node, "panel-timing", &timing);
219 if (r) {
220 dev_err(&pdev->dev, "failed to get video timing\n");
221 return r;
222 }
223
224 videomode_from_timing(&timing, &vm);
225 videomode_to_omap_video_timings(&vm, &ddata->videomode);
226
227 in = omapdss_of_find_source_for_first_ep(node);
228 if (IS_ERR(in)) {
229 dev_err(&pdev->dev, "failed to find video source\n");
230 return PTR_ERR(in);
231 }
232
233 ddata->in = in;
234
235 return 0;
236}
237
238static int panel_dpi_probe(struct platform_device *pdev)
239{
240 struct panel_drv_data *ddata;
241 struct omap_dss_device *dssdev;
242 int r;
243
244 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
245 if (ddata == NULL)
246 return -ENOMEM;
247
248 platform_set_drvdata(pdev, ddata);
249
250 if (dev_get_platdata(&pdev->dev)) {
251 r = panel_dpi_probe_pdata(pdev);
252 if (r)
253 return r;
254 } else if (pdev->dev.of_node) {
255 r = panel_dpi_probe_of(pdev);
256 if (r)
257 return r;
258 } else {
259 return -ENODEV;
260 }
261
262 if (gpio_is_valid(ddata->backlight_gpio)) {
263 r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
264 GPIOF_OUT_INIT_LOW, "panel backlight");
265 if (r)
266 goto err_gpio;
267 }
268
269 dssdev = &ddata->dssdev;
270 dssdev->dev = &pdev->dev;
271 dssdev->driver = &panel_dpi_ops;
272 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
273 dssdev->owner = THIS_MODULE;
274 dssdev->panel.timings = ddata->videomode;
275 dssdev->phy.dpi.data_lines = ddata->data_lines;
276
277 r = omapdss_register_display(dssdev);
278 if (r) {
279 dev_err(&pdev->dev, "Failed to register panel\n");
280 goto err_reg;
281 }
282
283 return 0;
284
285err_reg:
286err_gpio:
287 omap_dss_put_device(ddata->in);
288 return r;
289}
290
291static int __exit panel_dpi_remove(struct platform_device *pdev)
292{
293 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
294 struct omap_dss_device *dssdev = &ddata->dssdev;
295 struct omap_dss_device *in = ddata->in;
296
297 omapdss_unregister_display(dssdev);
298
299 panel_dpi_disable(dssdev);
300 panel_dpi_disconnect(dssdev);
301
302 omap_dss_put_device(in);
303
304 return 0;
305}
306
307static const struct of_device_id panel_dpi_of_match[] = {
308 { .compatible = "omapdss,panel-dpi", },
309 {},
310};
311
312MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
313
314static struct platform_driver panel_dpi_driver = {
315 .probe = panel_dpi_probe,
316 .remove = __exit_p(panel_dpi_remove),
317 .driver = {
318 .name = "panel-dpi",
319 .of_match_table = panel_dpi_of_match,
320 .suppress_bind_attrs = true,
321 },
322};
323
324module_platform_driver(panel_dpi_driver);
325
326MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
327MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
328MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
new file mode 100644
index 000000000000..3414c2609320
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
@@ -0,0 +1,1388 @@
1/*
2 * Generic DSI Command Mode panel driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12/* #define DEBUG */
13
14#include <linux/backlight.h>
15#include <linux/delay.h>
16#include <linux/fb.h>
17#include <linux/gpio.h>
18#include <linux/interrupt.h>
19#include <linux/jiffies.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/sched.h>
23#include <linux/slab.h>
24#include <linux/workqueue.h>
25#include <linux/of_device.h>
26#include <linux/of_gpio.h>
27
28#include <video/omapdss.h>
29#include <video/omap-panel-data.h>
30#include <video/mipi_display.h>
31
32/* DSI Virtual channel. Hardcoded for now. */
33#define TCH 0
34
35#define DCS_READ_NUM_ERRORS 0x05
36#define DCS_BRIGHTNESS 0x51
37#define DCS_CTRL_DISPLAY 0x53
38#define DCS_GET_ID1 0xda
39#define DCS_GET_ID2 0xdb
40#define DCS_GET_ID3 0xdc
41
42struct panel_drv_data {
43 struct omap_dss_device dssdev;
44 struct omap_dss_device *in;
45
46 struct omap_video_timings timings;
47
48 struct platform_device *pdev;
49
50 struct mutex lock;
51
52 struct backlight_device *bldev;
53
54 unsigned long hw_guard_end; /* next value of jiffies when we can
55 * issue the next sleep in/out command
56 */
57 unsigned long hw_guard_wait; /* max guard time in jiffies */
58
59 /* panel HW configuration from DT or platform data */
60 int reset_gpio;
61 int ext_te_gpio;
62
63 bool use_dsi_backlight;
64
65 struct omap_dsi_pin_config pin_config;
66
67 /* runtime variables */
68 bool enabled;
69
70 bool te_enabled;
71
72 atomic_t do_update;
73 int channel;
74
75 struct delayed_work te_timeout_work;
76
77 bool intro_printed;
78
79 struct workqueue_struct *workqueue;
80
81 bool ulps_enabled;
82 unsigned ulps_timeout;
83 struct delayed_work ulps_work;
84};
85
86#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
87
88static irqreturn_t dsicm_te_isr(int irq, void *data);
89static void dsicm_te_timeout_work_callback(struct work_struct *work);
90static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);
91
92static int dsicm_panel_reset(struct panel_drv_data *ddata);
93
94static void dsicm_ulps_work(struct work_struct *work);
95
96static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
97{
98 ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
99 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
100}
101
102static void hw_guard_wait(struct panel_drv_data *ddata)
103{
104 unsigned long wait = ddata->hw_guard_end - jiffies;
105
106 if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
107 set_current_state(TASK_UNINTERRUPTIBLE);
108 schedule_timeout(wait);
109 }
110}
111
112static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
113{
114 struct omap_dss_device *in = ddata->in;
115 int r;
116 u8 buf[1];
117
118 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);
119
120 if (r < 0)
121 return r;
122
123 *data = buf[0];
124
125 return 0;
126}
127
128static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
129{
130 struct omap_dss_device *in = ddata->in;
131 return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);
132}
133
134static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
135{
136 struct omap_dss_device *in = ddata->in;
137 u8 buf[2] = { dcs_cmd, param };
138
139 return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);
140}
141
142static int dsicm_sleep_in(struct panel_drv_data *ddata)
143
144{
145 struct omap_dss_device *in = ddata->in;
146 u8 cmd;
147 int r;
148
149 hw_guard_wait(ddata);
150
151 cmd = MIPI_DCS_ENTER_SLEEP_MODE;
152 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);
153 if (r)
154 return r;
155
156 hw_guard_start(ddata, 120);
157
158 usleep_range(5000, 10000);
159
160 return 0;
161}
162
163static int dsicm_sleep_out(struct panel_drv_data *ddata)
164{
165 int r;
166
167 hw_guard_wait(ddata);
168
169 r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE);
170 if (r)
171 return r;
172
173 hw_guard_start(ddata, 120);
174
175 usleep_range(5000, 10000);
176
177 return 0;
178}
179
180static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
181{
182 int r;
183
184 r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
185 if (r)
186 return r;
187 r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
188 if (r)
189 return r;
190 r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
191 if (r)
192 return r;
193
194 return 0;
195}
196
197static int dsicm_set_update_window(struct panel_drv_data *ddata,
198 u16 x, u16 y, u16 w, u16 h)
199{
200 struct omap_dss_device *in = ddata->in;
201 int r;
202 u16 x1 = x;
203 u16 x2 = x + w - 1;
204 u16 y1 = y;
205 u16 y2 = y + h - 1;
206
207 u8 buf[5];
208 buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
209 buf[1] = (x1 >> 8) & 0xff;
210 buf[2] = (x1 >> 0) & 0xff;
211 buf[3] = (x2 >> 8) & 0xff;
212 buf[4] = (x2 >> 0) & 0xff;
213
214 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
215 if (r)
216 return r;
217
218 buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
219 buf[1] = (y1 >> 8) & 0xff;
220 buf[2] = (y1 >> 0) & 0xff;
221 buf[3] = (y2 >> 8) & 0xff;
222 buf[4] = (y2 >> 0) & 0xff;
223
224 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
225 if (r)
226 return r;
227
228 in->ops.dsi->bta_sync(in, ddata->channel);
229
230 return r;
231}
232
233static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)
234{
235 if (ddata->ulps_timeout > 0)
236 queue_delayed_work(ddata->workqueue, &ddata->ulps_work,
237 msecs_to_jiffies(ddata->ulps_timeout));
238}
239
240static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
241{
242 cancel_delayed_work(&ddata->ulps_work);
243}
244
245static int dsicm_enter_ulps(struct panel_drv_data *ddata)
246{
247 struct omap_dss_device *in = ddata->in;
248 int r;
249
250 if (ddata->ulps_enabled)
251 return 0;
252
253 dsicm_cancel_ulps_work(ddata);
254
255 r = _dsicm_enable_te(ddata, false);
256 if (r)
257 goto err;
258
259 if (gpio_is_valid(ddata->ext_te_gpio))
260 disable_irq(gpio_to_irq(ddata->ext_te_gpio));
261
262 in->ops.dsi->disable(in, false, true);
263
264 ddata->ulps_enabled = true;
265
266 return 0;
267
268err:
269 dev_err(&ddata->pdev->dev, "enter ULPS failed");
270 dsicm_panel_reset(ddata);
271
272 ddata->ulps_enabled = false;
273
274 dsicm_queue_ulps_work(ddata);
275
276 return r;
277}
278
279static int dsicm_exit_ulps(struct panel_drv_data *ddata)
280{
281 struct omap_dss_device *in = ddata->in;
282 int r;
283
284 if (!ddata->ulps_enabled)
285 return 0;
286
287 r = in->ops.dsi->enable(in);
288 if (r) {
289 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
290 goto err1;
291 }
292
293 in->ops.dsi->enable_hs(in, ddata->channel, true);
294
295 r = _dsicm_enable_te(ddata, true);
296 if (r) {
297 dev_err(&ddata->pdev->dev, "failed to re-enable TE");
298 goto err2;
299 }
300
301 if (gpio_is_valid(ddata->ext_te_gpio))
302 enable_irq(gpio_to_irq(ddata->ext_te_gpio));
303
304 dsicm_queue_ulps_work(ddata);
305
306 ddata->ulps_enabled = false;
307
308 return 0;
309
310err2:
311 dev_err(&ddata->pdev->dev, "failed to exit ULPS");
312
313 r = dsicm_panel_reset(ddata);
314 if (!r) {
315 if (gpio_is_valid(ddata->ext_te_gpio))
316 enable_irq(gpio_to_irq(ddata->ext_te_gpio));
317 ddata->ulps_enabled = false;
318 }
319err1:
320 dsicm_queue_ulps_work(ddata);
321
322 return r;
323}
324
325static int dsicm_wake_up(struct panel_drv_data *ddata)
326{
327 if (ddata->ulps_enabled)
328 return dsicm_exit_ulps(ddata);
329
330 dsicm_cancel_ulps_work(ddata);
331 dsicm_queue_ulps_work(ddata);
332 return 0;
333}
334
335static int dsicm_bl_update_status(struct backlight_device *dev)
336{
337 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
338 struct omap_dss_device *in = ddata->in;
339 int r;
340 int level;
341
342 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
343 dev->props.power == FB_BLANK_UNBLANK)
344 level = dev->props.brightness;
345 else
346 level = 0;
347
348 dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);
349
350 mutex_lock(&ddata->lock);
351
352 if (ddata->enabled) {
353 in->ops.dsi->bus_lock(in);
354
355 r = dsicm_wake_up(ddata);
356 if (!r)
357 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
358
359 in->ops.dsi->bus_unlock(in);
360 } else {
361 r = 0;
362 }
363
364 mutex_unlock(&ddata->lock);
365
366 return r;
367}
368
369static int dsicm_bl_get_intensity(struct backlight_device *dev)
370{
371 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
372 dev->props.power == FB_BLANK_UNBLANK)
373 return dev->props.brightness;
374
375 return 0;
376}
377
378static const struct backlight_ops dsicm_bl_ops = {
379 .get_brightness = dsicm_bl_get_intensity,
380 .update_status = dsicm_bl_update_status,
381};
382
383static void dsicm_get_resolution(struct omap_dss_device *dssdev,
384 u16 *xres, u16 *yres)
385{
386 *xres = dssdev->panel.timings.x_res;
387 *yres = dssdev->panel.timings.y_res;
388}
389
390static ssize_t dsicm_num_errors_show(struct device *dev,
391 struct device_attribute *attr, char *buf)
392{
393 struct platform_device *pdev = to_platform_device(dev);
394 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
395 struct omap_dss_device *in = ddata->in;
396 u8 errors = 0;
397 int r;
398
399 mutex_lock(&ddata->lock);
400
401 if (ddata->enabled) {
402 in->ops.dsi->bus_lock(in);
403
404 r = dsicm_wake_up(ddata);
405 if (!r)
406 r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,
407 &errors);
408
409 in->ops.dsi->bus_unlock(in);
410 } else {
411 r = -ENODEV;
412 }
413
414 mutex_unlock(&ddata->lock);
415
416 if (r)
417 return r;
418
419 return snprintf(buf, PAGE_SIZE, "%d\n", errors);
420}
421
422static ssize_t dsicm_hw_revision_show(struct device *dev,
423 struct device_attribute *attr, char *buf)
424{
425 struct platform_device *pdev = to_platform_device(dev);
426 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
427 struct omap_dss_device *in = ddata->in;
428 u8 id1, id2, id3;
429 int r;
430
431 mutex_lock(&ddata->lock);
432
433 if (ddata->enabled) {
434 in->ops.dsi->bus_lock(in);
435
436 r = dsicm_wake_up(ddata);
437 if (!r)
438 r = dsicm_get_id(ddata, &id1, &id2, &id3);
439
440 in->ops.dsi->bus_unlock(in);
441 } else {
442 r = -ENODEV;
443 }
444
445 mutex_unlock(&ddata->lock);
446
447 if (r)
448 return r;
449
450 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
451}
452
453static ssize_t dsicm_store_ulps(struct device *dev,
454 struct device_attribute *attr,
455 const char *buf, size_t count)
456{
457 struct platform_device *pdev = to_platform_device(dev);
458 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
459 struct omap_dss_device *in = ddata->in;
460 unsigned long t;
461 int r;
462
463 r = kstrtoul(buf, 0, &t);
464 if (r)
465 return r;
466
467 mutex_lock(&ddata->lock);
468
469 if (ddata->enabled) {
470 in->ops.dsi->bus_lock(in);
471
472 if (t)
473 r = dsicm_enter_ulps(ddata);
474 else
475 r = dsicm_wake_up(ddata);
476
477 in->ops.dsi->bus_unlock(in);
478 }
479
480 mutex_unlock(&ddata->lock);
481
482 if (r)
483 return r;
484
485 return count;
486}
487
488static ssize_t dsicm_show_ulps(struct device *dev,
489 struct device_attribute *attr,
490 char *buf)
491{
492 struct platform_device *pdev = to_platform_device(dev);
493 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
494 unsigned t;
495
496 mutex_lock(&ddata->lock);
497 t = ddata->ulps_enabled;
498 mutex_unlock(&ddata->lock);
499
500 return snprintf(buf, PAGE_SIZE, "%u\n", t);
501}
502
503static ssize_t dsicm_store_ulps_timeout(struct device *dev,
504 struct device_attribute *attr,
505 const char *buf, size_t count)
506{
507 struct platform_device *pdev = to_platform_device(dev);
508 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
509 struct omap_dss_device *in = ddata->in;
510 unsigned long t;
511 int r;
512
513 r = kstrtoul(buf, 0, &t);
514 if (r)
515 return r;
516
517 mutex_lock(&ddata->lock);
518 ddata->ulps_timeout = t;
519
520 if (ddata->enabled) {
521 /* dsicm_wake_up will restart the timer */
522 in->ops.dsi->bus_lock(in);
523 r = dsicm_wake_up(ddata);
524 in->ops.dsi->bus_unlock(in);
525 }
526
527 mutex_unlock(&ddata->lock);
528
529 if (r)
530 return r;
531
532 return count;
533}
534
535static ssize_t dsicm_show_ulps_timeout(struct device *dev,
536 struct device_attribute *attr,
537 char *buf)
538{
539 struct platform_device *pdev = to_platform_device(dev);
540 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
541 unsigned t;
542
543 mutex_lock(&ddata->lock);
544 t = ddata->ulps_timeout;
545 mutex_unlock(&ddata->lock);
546
547 return snprintf(buf, PAGE_SIZE, "%u\n", t);
548}
549
550static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);
551static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL);
552static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
553 dsicm_show_ulps, dsicm_store_ulps);
554static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
555 dsicm_show_ulps_timeout, dsicm_store_ulps_timeout);
556
557static struct attribute *dsicm_attrs[] = {
558 &dev_attr_num_dsi_errors.attr,
559 &dev_attr_hw_revision.attr,
560 &dev_attr_ulps.attr,
561 &dev_attr_ulps_timeout.attr,
562 NULL,
563};
564
565static struct attribute_group dsicm_attr_group = {
566 .attrs = dsicm_attrs,
567};
568
569static void dsicm_hw_reset(struct panel_drv_data *ddata)
570{
571 if (!gpio_is_valid(ddata->reset_gpio))
572 return;
573
574 gpio_set_value(ddata->reset_gpio, 1);
575 udelay(10);
576 /* reset the panel */
577 gpio_set_value(ddata->reset_gpio, 0);
578 /* assert reset */
579 udelay(10);
580 gpio_set_value(ddata->reset_gpio, 1);
581 /* wait after releasing reset */
582 usleep_range(5000, 10000);
583}
584
585static int dsicm_power_on(struct panel_drv_data *ddata)
586{
587 struct omap_dss_device *in = ddata->in;
588 u8 id1, id2, id3;
589 int r;
590 struct omap_dss_dsi_config dsi_config = {
591 .mode = OMAP_DSS_DSI_CMD_MODE,
592 .pixel_format = OMAP_DSS_DSI_FMT_RGB888,
593 .timings = &ddata->timings,
594 .hs_clk_min = 150000000,
595 .hs_clk_max = 300000000,
596 .lp_clk_min = 7000000,
597 .lp_clk_max = 10000000,
598 };
599
600 if (ddata->pin_config.num_pins > 0) {
601 r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
602 if (r) {
603 dev_err(&ddata->pdev->dev,
604 "failed to configure DSI pins\n");
605 goto err0;
606 }
607 }
608
609 r = in->ops.dsi->set_config(in, &dsi_config);
610 if (r) {
611 dev_err(&ddata->pdev->dev, "failed to configure DSI\n");
612 goto err0;
613 }
614
615 r = in->ops.dsi->enable(in);
616 if (r) {
617 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
618 goto err0;
619 }
620
621 dsicm_hw_reset(ddata);
622
623 in->ops.dsi->enable_hs(in, ddata->channel, false);
624
625 r = dsicm_sleep_out(ddata);
626 if (r)
627 goto err;
628
629 r = dsicm_get_id(ddata, &id1, &id2, &id3);
630 if (r)
631 goto err;
632
633 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff);
634 if (r)
635 goto err;
636
637 r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY,
638 (1<<2) | (1<<5)); /* BL | BCTRL */
639 if (r)
640 goto err;
641
642 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT,
643 MIPI_DCS_PIXEL_FMT_24BIT);
644 if (r)
645 goto err;
646
647 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON);
648 if (r)
649 goto err;
650
651 r = _dsicm_enable_te(ddata, ddata->te_enabled);
652 if (r)
653 goto err;
654
655 r = in->ops.dsi->enable_video_output(in, ddata->channel);
656 if (r)
657 goto err;
658
659 ddata->enabled = 1;
660
661 if (!ddata->intro_printed) {
662 dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",
663 id1, id2, id3);
664 ddata->intro_printed = true;
665 }
666
667 in->ops.dsi->enable_hs(in, ddata->channel, true);
668
669 return 0;
670err:
671 dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n");
672
673 dsicm_hw_reset(ddata);
674
675 in->ops.dsi->disable(in, true, false);
676err0:
677 return r;
678}
679
680static void dsicm_power_off(struct panel_drv_data *ddata)
681{
682 struct omap_dss_device *in = ddata->in;
683 int r;
684
685 in->ops.dsi->disable_video_output(in, ddata->channel);
686
687 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);
688 if (!r)
689 r = dsicm_sleep_in(ddata);
690
691 if (r) {
692 dev_err(&ddata->pdev->dev,
693 "error disabling panel, issuing HW reset\n");
694 dsicm_hw_reset(ddata);
695 }
696
697 in->ops.dsi->disable(in, true, false);
698
699 ddata->enabled = 0;
700}
701
702static int dsicm_panel_reset(struct panel_drv_data *ddata)
703{
704 dev_err(&ddata->pdev->dev, "performing LCD reset\n");
705
706 dsicm_power_off(ddata);
707 dsicm_hw_reset(ddata);
708 return dsicm_power_on(ddata);
709}
710
711static int dsicm_connect(struct omap_dss_device *dssdev)
712{
713 struct panel_drv_data *ddata = to_panel_data(dssdev);
714 struct omap_dss_device *in = ddata->in;
715 struct device *dev = &ddata->pdev->dev;
716 int r;
717
718 if (omapdss_device_is_connected(dssdev))
719 return 0;
720
721 r = in->ops.dsi->connect(in, dssdev);
722 if (r) {
723 dev_err(dev, "Failed to connect to video source\n");
724 return r;
725 }
726
727 r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);
728 if (r) {
729 dev_err(dev, "failed to get virtual channel\n");
730 goto err_req_vc;
731 }
732
733 r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH);
734 if (r) {
735 dev_err(dev, "failed to set VC_ID\n");
736 goto err_vc_id;
737 }
738
739 return 0;
740
741err_vc_id:
742 in->ops.dsi->release_vc(ddata->in, ddata->channel);
743err_req_vc:
744 in->ops.dsi->disconnect(in, dssdev);
745 return r;
746}
747
748static void dsicm_disconnect(struct omap_dss_device *dssdev)
749{
750 struct panel_drv_data *ddata = to_panel_data(dssdev);
751 struct omap_dss_device *in = ddata->in;
752
753 if (!omapdss_device_is_connected(dssdev))
754 return;
755
756 in->ops.dsi->release_vc(in, ddata->channel);
757 in->ops.dsi->disconnect(in, dssdev);
758}
759
760static int dsicm_enable(struct omap_dss_device *dssdev)
761{
762 struct panel_drv_data *ddata = to_panel_data(dssdev);
763 struct omap_dss_device *in = ddata->in;
764 int r;
765
766 dev_dbg(&ddata->pdev->dev, "enable\n");
767
768 mutex_lock(&ddata->lock);
769
770 if (!omapdss_device_is_connected(dssdev)) {
771 r = -ENODEV;
772 goto err;
773 }
774
775 if (omapdss_device_is_enabled(dssdev)) {
776 r = 0;
777 goto err;
778 }
779
780 in->ops.dsi->bus_lock(in);
781
782 r = dsicm_power_on(ddata);
783
784 in->ops.dsi->bus_unlock(in);
785
786 if (r)
787 goto err;
788
789 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
790
791 mutex_unlock(&ddata->lock);
792
793 return 0;
794err:
795 dev_dbg(&ddata->pdev->dev, "enable failed\n");
796 mutex_unlock(&ddata->lock);
797 return r;
798}
799
800static void dsicm_disable(struct omap_dss_device *dssdev)
801{
802 struct panel_drv_data *ddata = to_panel_data(dssdev);
803 struct omap_dss_device *in = ddata->in;
804 int r;
805
806 dev_dbg(&ddata->pdev->dev, "disable\n");
807
808 mutex_lock(&ddata->lock);
809
810 dsicm_cancel_ulps_work(ddata);
811
812 in->ops.dsi->bus_lock(in);
813
814 if (omapdss_device_is_enabled(dssdev)) {
815 r = dsicm_wake_up(ddata);
816 if (!r)
817 dsicm_power_off(ddata);
818 }
819
820 in->ops.dsi->bus_unlock(in);
821
822 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
823
824 mutex_unlock(&ddata->lock);
825}
826
827static void dsicm_framedone_cb(int err, void *data)
828{
829 struct panel_drv_data *ddata = data;
830 struct omap_dss_device *in = ddata->in;
831
832 dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
833 in->ops.dsi->bus_unlock(ddata->in);
834}
835
836static irqreturn_t dsicm_te_isr(int irq, void *data)
837{
838 struct panel_drv_data *ddata = data;
839 struct omap_dss_device *in = ddata->in;
840 int old;
841 int r;
842
843 old = atomic_cmpxchg(&ddata->do_update, 1, 0);
844
845 if (old) {
846 cancel_delayed_work(&ddata->te_timeout_work);
847
848 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
849 ddata);
850 if (r)
851 goto err;
852 }
853
854 return IRQ_HANDLED;
855err:
856 dev_err(&ddata->pdev->dev, "start update failed\n");
857 in->ops.dsi->bus_unlock(in);
858 return IRQ_HANDLED;
859}
860
861static void dsicm_te_timeout_work_callback(struct work_struct *work)
862{
863 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
864 te_timeout_work.work);
865 struct omap_dss_device *in = ddata->in;
866
867 dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
868
869 atomic_set(&ddata->do_update, 0);
870 in->ops.dsi->bus_unlock(in);
871}
872
873static int dsicm_update(struct omap_dss_device *dssdev,
874 u16 x, u16 y, u16 w, u16 h)
875{
876 struct panel_drv_data *ddata = to_panel_data(dssdev);
877 struct omap_dss_device *in = ddata->in;
878 int r;
879
880 dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
881
882 mutex_lock(&ddata->lock);
883 in->ops.dsi->bus_lock(in);
884
885 r = dsicm_wake_up(ddata);
886 if (r)
887 goto err;
888
889 if (!ddata->enabled) {
890 r = 0;
891 goto err;
892 }
893
894 /* XXX no need to send this every frame, but dsi break if not done */
895 r = dsicm_set_update_window(ddata, 0, 0,
896 dssdev->panel.timings.x_res,
897 dssdev->panel.timings.y_res);
898 if (r)
899 goto err;
900
901 if (ddata->te_enabled && gpio_is_valid(ddata->ext_te_gpio)) {
902 schedule_delayed_work(&ddata->te_timeout_work,
903 msecs_to_jiffies(250));
904 atomic_set(&ddata->do_update, 1);
905 } else {
906 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
907 ddata);
908 if (r)
909 goto err;
910 }
911
912 /* note: no bus_unlock here. unlock is in framedone_cb */
913 mutex_unlock(&ddata->lock);
914 return 0;
915err:
916 in->ops.dsi->bus_unlock(in);
917 mutex_unlock(&ddata->lock);
918 return r;
919}
920
921static int dsicm_sync(struct omap_dss_device *dssdev)
922{
923 struct panel_drv_data *ddata = to_panel_data(dssdev);
924 struct omap_dss_device *in = ddata->in;
925
926 dev_dbg(&ddata->pdev->dev, "sync\n");
927
928 mutex_lock(&ddata->lock);
929 in->ops.dsi->bus_lock(in);
930 in->ops.dsi->bus_unlock(in);
931 mutex_unlock(&ddata->lock);
932
933 dev_dbg(&ddata->pdev->dev, "sync done\n");
934
935 return 0;
936}
937
938static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
939{
940 struct omap_dss_device *in = ddata->in;
941 int r;
942
943 if (enable)
944 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0);
945 else
946 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);
947
948 if (!gpio_is_valid(ddata->ext_te_gpio))
949 in->ops.dsi->enable_te(in, enable);
950
951 /* possible panel bug */
952 msleep(100);
953
954 return r;
955}
956
957static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
958{
959 struct panel_drv_data *ddata = to_panel_data(dssdev);
960 struct omap_dss_device *in = ddata->in;
961 int r;
962
963 mutex_lock(&ddata->lock);
964
965 if (ddata->te_enabled == enable)
966 goto end;
967
968 in->ops.dsi->bus_lock(in);
969
970 if (ddata->enabled) {
971 r = dsicm_wake_up(ddata);
972 if (r)
973 goto err;
974
975 r = _dsicm_enable_te(ddata, enable);
976 if (r)
977 goto err;
978 }
979
980 ddata->te_enabled = enable;
981
982 in->ops.dsi->bus_unlock(in);
983end:
984 mutex_unlock(&ddata->lock);
985
986 return 0;
987err:
988 in->ops.dsi->bus_unlock(in);
989 mutex_unlock(&ddata->lock);
990
991 return r;
992}
993
994static int dsicm_get_te(struct omap_dss_device *dssdev)
995{
996 struct panel_drv_data *ddata = to_panel_data(dssdev);
997 int r;
998
999 mutex_lock(&ddata->lock);
1000 r = ddata->te_enabled;
1001 mutex_unlock(&ddata->lock);
1002
1003 return r;
1004}
1005
1006static int dsicm_memory_read(struct omap_dss_device *dssdev,
1007 void *buf, size_t size,
1008 u16 x, u16 y, u16 w, u16 h)
1009{
1010 struct panel_drv_data *ddata = to_panel_data(dssdev);
1011 struct omap_dss_device *in = ddata->in;
1012 int r;
1013 int first = 1;
1014 int plen;
1015 unsigned buf_used = 0;
1016
1017 if (size < w * h * 3)
1018 return -ENOMEM;
1019
1020 mutex_lock(&ddata->lock);
1021
1022 if (!ddata->enabled) {
1023 r = -ENODEV;
1024 goto err1;
1025 }
1026
1027 size = min(w * h * 3,
1028 dssdev->panel.timings.x_res *
1029 dssdev->panel.timings.y_res * 3);
1030
1031 in->ops.dsi->bus_lock(in);
1032
1033 r = dsicm_wake_up(ddata);
1034 if (r)
1035 goto err2;
1036
1037 /* plen 1 or 2 goes into short packet. until checksum error is fixed,
1038 * use short packets. plen 32 works, but bigger packets seem to cause
1039 * an error. */
1040 if (size % 2)
1041 plen = 1;
1042 else
1043 plen = 2;
1044
1045 dsicm_set_update_window(ddata, x, y, w, h);
1046
1047 r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);
1048 if (r)
1049 goto err2;
1050
1051 while (buf_used < size) {
1052 u8 dcs_cmd = first ? 0x2e : 0x3e;
1053 first = 0;
1054
1055 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,
1056 buf + buf_used, size - buf_used);
1057
1058 if (r < 0) {
1059 dev_err(dssdev->dev, "read error\n");
1060 goto err3;
1061 }
1062
1063 buf_used += r;
1064
1065 if (r < plen) {
1066 dev_err(&ddata->pdev->dev, "short read\n");
1067 break;
1068 }
1069
1070 if (signal_pending(current)) {
1071 dev_err(&ddata->pdev->dev, "signal pending, "
1072 "aborting memory read\n");
1073 r = -ERESTARTSYS;
1074 goto err3;
1075 }
1076 }
1077
1078 r = buf_used;
1079
1080err3:
1081 in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);
1082err2:
1083 in->ops.dsi->bus_unlock(in);
1084err1:
1085 mutex_unlock(&ddata->lock);
1086 return r;
1087}
1088
1089static void dsicm_ulps_work(struct work_struct *work)
1090{
1091 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
1092 ulps_work.work);
1093 struct omap_dss_device *dssdev = &ddata->dssdev;
1094 struct omap_dss_device *in = ddata->in;
1095
1096 mutex_lock(&ddata->lock);
1097
1098 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) {
1099 mutex_unlock(&ddata->lock);
1100 return;
1101 }
1102
1103 in->ops.dsi->bus_lock(in);
1104
1105 dsicm_enter_ulps(ddata);
1106
1107 in->ops.dsi->bus_unlock(in);
1108 mutex_unlock(&ddata->lock);
1109}
1110
1111static struct omap_dss_driver dsicm_ops = {
1112 .connect = dsicm_connect,
1113 .disconnect = dsicm_disconnect,
1114
1115 .enable = dsicm_enable,
1116 .disable = dsicm_disable,
1117
1118 .update = dsicm_update,
1119 .sync = dsicm_sync,
1120
1121 .get_resolution = dsicm_get_resolution,
1122 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
1123
1124 .enable_te = dsicm_enable_te,
1125 .get_te = dsicm_get_te,
1126
1127 .memory_read = dsicm_memory_read,
1128};
1129
1130static int dsicm_probe_pdata(struct platform_device *pdev)
1131{
1132 const struct panel_dsicm_platform_data *pdata;
1133 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
1134 struct omap_dss_device *dssdev, *in;
1135
1136 pdata = dev_get_platdata(&pdev->dev);
1137
1138 in = omap_dss_find_output(pdata->source);
1139 if (in == NULL) {
1140 dev_err(&pdev->dev, "failed to find video source\n");
1141 return -EPROBE_DEFER;
1142 }
1143 ddata->in = in;
1144
1145 ddata->reset_gpio = pdata->reset_gpio;
1146
1147 if (pdata->use_ext_te)
1148 ddata->ext_te_gpio = pdata->ext_te_gpio;
1149 else
1150 ddata->ext_te_gpio = -1;
1151
1152 ddata->ulps_timeout = pdata->ulps_timeout;
1153
1154 ddata->use_dsi_backlight = pdata->use_dsi_backlight;
1155
1156 ddata->pin_config = pdata->pin_config;
1157
1158 dssdev = &ddata->dssdev;
1159 dssdev->name = pdata->name;
1160
1161 return 0;
1162}
1163
1164static int dsicm_probe_of(struct platform_device *pdev)
1165{
1166 struct device_node *node = pdev->dev.of_node;
1167 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
1168 struct omap_dss_device *in;
1169 int gpio;
1170
1171 gpio = of_get_named_gpio(node, "reset-gpios", 0);
1172 if (!gpio_is_valid(gpio)) {
1173 dev_err(&pdev->dev, "failed to parse reset gpio\n");
1174 return gpio;
1175 }
1176 ddata->reset_gpio = gpio;
1177
1178 gpio = of_get_named_gpio(node, "te-gpios", 0);
1179 if (gpio_is_valid(gpio) || gpio == -ENOENT) {
1180 ddata->ext_te_gpio = gpio;
1181 } else {
1182 dev_err(&pdev->dev, "failed to parse TE gpio\n");
1183 return gpio;
1184 }
1185
1186 in = omapdss_of_find_source_for_first_ep(node);
1187 if (IS_ERR(in)) {
1188 dev_err(&pdev->dev, "failed to find video source\n");
1189 return PTR_ERR(in);
1190 }
1191
1192 ddata->in = in;
1193
1194 /* TODO: ulps, backlight */
1195
1196 return 0;
1197}
1198
1199static int dsicm_probe(struct platform_device *pdev)
1200{
1201 struct backlight_properties props;
1202 struct panel_drv_data *ddata;
1203 struct backlight_device *bldev = NULL;
1204 struct device *dev = &pdev->dev;
1205 struct omap_dss_device *dssdev;
1206 int r;
1207
1208 dev_dbg(dev, "probe\n");
1209
1210 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
1211 if (!ddata)
1212 return -ENOMEM;
1213
1214 platform_set_drvdata(pdev, ddata);
1215 ddata->pdev = pdev;
1216
1217 if (dev_get_platdata(dev)) {
1218 r = dsicm_probe_pdata(pdev);
1219 if (r)
1220 return r;
1221 } else if (pdev->dev.of_node) {
1222 r = dsicm_probe_of(pdev);
1223 if (r)
1224 return r;
1225 } else {
1226 return -ENODEV;
1227 }
1228
1229 ddata->timings.x_res = 864;
1230 ddata->timings.y_res = 480;
1231 ddata->timings.pixelclock = 864 * 480 * 60;
1232
1233 dssdev = &ddata->dssdev;
1234 dssdev->dev = dev;
1235 dssdev->driver = &dsicm_ops;
1236 dssdev->panel.timings = ddata->timings;
1237 dssdev->type = OMAP_DISPLAY_TYPE_DSI;
1238 dssdev->owner = THIS_MODULE;
1239
1240 dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
1241 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
1242 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
1243
1244 r = omapdss_register_display(dssdev);
1245 if (r) {
1246 dev_err(dev, "Failed to register panel\n");
1247 goto err_reg;
1248 }
1249
1250 mutex_init(&ddata->lock);
1251
1252 atomic_set(&ddata->do_update, 0);
1253
1254 if (gpio_is_valid(ddata->reset_gpio)) {
1255 r = devm_gpio_request_one(dev, ddata->reset_gpio,
1256 GPIOF_OUT_INIT_LOW, "taal rst");
1257 if (r) {
1258 dev_err(dev, "failed to request reset gpio\n");
1259 return r;
1260 }
1261 }
1262
1263 if (gpio_is_valid(ddata->ext_te_gpio)) {
1264 r = devm_gpio_request_one(dev, ddata->ext_te_gpio,
1265 GPIOF_IN, "taal irq");
1266 if (r) {
1267 dev_err(dev, "GPIO request failed\n");
1268 return r;
1269 }
1270
1271 r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio),
1272 dsicm_te_isr,
1273 IRQF_TRIGGER_RISING,
1274 "taal vsync", ddata);
1275
1276 if (r) {
1277 dev_err(dev, "IRQ request failed\n");
1278 return r;
1279 }
1280
1281 INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,
1282 dsicm_te_timeout_work_callback);
1283
1284 dev_dbg(dev, "Using GPIO TE\n");
1285 }
1286
1287 ddata->workqueue = create_singlethread_workqueue("dsicm_wq");
1288 if (ddata->workqueue == NULL) {
1289 dev_err(dev, "can't create workqueue\n");
1290 return -ENOMEM;
1291 }
1292 INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);
1293
1294 dsicm_hw_reset(ddata);
1295
1296 if (ddata->use_dsi_backlight) {
1297 memset(&props, 0, sizeof(struct backlight_properties));
1298 props.max_brightness = 255;
1299
1300 props.type = BACKLIGHT_RAW;
1301 bldev = backlight_device_register(dev_name(dev),
1302 dev, ddata, &dsicm_bl_ops, &props);
1303 if (IS_ERR(bldev)) {
1304 r = PTR_ERR(bldev);
1305 goto err_bl;
1306 }
1307
1308 ddata->bldev = bldev;
1309
1310 bldev->props.fb_blank = FB_BLANK_UNBLANK;
1311 bldev->props.power = FB_BLANK_UNBLANK;
1312 bldev->props.brightness = 255;
1313
1314 dsicm_bl_update_status(bldev);
1315 }
1316
1317 r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
1318 if (r) {
1319 dev_err(dev, "failed to create sysfs files\n");
1320 goto err_sysfs_create;
1321 }
1322
1323 return 0;
1324
1325err_sysfs_create:
1326 if (bldev != NULL)
1327 backlight_device_unregister(bldev);
1328err_bl:
1329 destroy_workqueue(ddata->workqueue);
1330err_reg:
1331 return r;
1332}
1333
1334static int __exit dsicm_remove(struct platform_device *pdev)
1335{
1336 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
1337 struct omap_dss_device *dssdev = &ddata->dssdev;
1338 struct backlight_device *bldev;
1339
1340 dev_dbg(&pdev->dev, "remove\n");
1341
1342 omapdss_unregister_display(dssdev);
1343
1344 dsicm_disable(dssdev);
1345 dsicm_disconnect(dssdev);
1346
1347 sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
1348
1349 bldev = ddata->bldev;
1350 if (bldev != NULL) {
1351 bldev->props.power = FB_BLANK_POWERDOWN;
1352 dsicm_bl_update_status(bldev);
1353 backlight_device_unregister(bldev);
1354 }
1355
1356 omap_dss_put_device(ddata->in);
1357
1358 dsicm_cancel_ulps_work(ddata);
1359 destroy_workqueue(ddata->workqueue);
1360
1361 /* reset, to be sure that the panel is in a valid state */
1362 dsicm_hw_reset(ddata);
1363
1364 return 0;
1365}
1366
1367static const struct of_device_id dsicm_of_match[] = {
1368 { .compatible = "omapdss,panel-dsi-cm", },
1369 {},
1370};
1371
1372MODULE_DEVICE_TABLE(of, dsicm_of_match);
1373
1374static struct platform_driver dsicm_driver = {
1375 .probe = dsicm_probe,
1376 .remove = __exit_p(dsicm_remove),
1377 .driver = {
1378 .name = "panel-dsi-cm",
1379 .of_match_table = dsicm_of_match,
1380 .suppress_bind_attrs = true,
1381 },
1382};
1383
1384module_platform_driver(dsicm_driver);
1385
1386MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
1387MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
1388MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
new file mode 100644
index 000000000000..18eb60e9c9ec
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
@@ -0,0 +1,404 @@
1/*
2 * LG.Philips LB035Q02 LCD Panel driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6 * Based on a driver by: Steve Sakoman <steve@sakoman.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/delay.h>
15#include <linux/spi/spi.h>
16#include <linux/mutex.h>
17#include <linux/gpio.h>
18
19#include <video/omapdss.h>
20#include <video/omap-panel-data.h>
21
22static struct omap_video_timings lb035q02_timings = {
23 .x_res = 320,
24 .y_res = 240,
25
26 .pixelclock = 6500000,
27
28 .hsw = 2,
29 .hfp = 20,
30 .hbp = 68,
31
32 .vsw = 2,
33 .vfp = 4,
34 .vbp = 18,
35
36 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
37 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
38 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
39 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
40 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
41};
42
43struct panel_drv_data {
44 struct omap_dss_device dssdev;
45 struct omap_dss_device *in;
46
47 struct spi_device *spi;
48
49 int data_lines;
50
51 struct omap_video_timings videomode;
52
53 /* used for non-DT boot, to be removed */
54 int backlight_gpio;
55
56 struct gpio_desc *enable_gpio;
57};
58
59#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
60
61static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val)
62{
63 struct spi_message msg;
64 struct spi_transfer index_xfer = {
65 .len = 3,
66 .cs_change = 1,
67 };
68 struct spi_transfer value_xfer = {
69 .len = 3,
70 };
71 u8 buffer[16];
72
73 spi_message_init(&msg);
74
75 /* register index */
76 buffer[0] = 0x70;
77 buffer[1] = 0x00;
78 buffer[2] = reg & 0x7f;
79 index_xfer.tx_buf = buffer;
80 spi_message_add_tail(&index_xfer, &msg);
81
82 /* register value */
83 buffer[4] = 0x72;
84 buffer[5] = val >> 8;
85 buffer[6] = val;
86 value_xfer.tx_buf = buffer + 4;
87 spi_message_add_tail(&value_xfer, &msg);
88
89 return spi_sync(spi, &msg);
90}
91
92static void init_lb035q02_panel(struct spi_device *spi)
93{
94 /* Init sequence from page 28 of the lb035q02 spec */
95 lb035q02_write_reg(spi, 0x01, 0x6300);
96 lb035q02_write_reg(spi, 0x02, 0x0200);
97 lb035q02_write_reg(spi, 0x03, 0x0177);
98 lb035q02_write_reg(spi, 0x04, 0x04c7);
99 lb035q02_write_reg(spi, 0x05, 0xffc0);
100 lb035q02_write_reg(spi, 0x06, 0xe806);
101 lb035q02_write_reg(spi, 0x0a, 0x4008);
102 lb035q02_write_reg(spi, 0x0b, 0x0000);
103 lb035q02_write_reg(spi, 0x0d, 0x0030);
104 lb035q02_write_reg(spi, 0x0e, 0x2800);
105 lb035q02_write_reg(spi, 0x0f, 0x0000);
106 lb035q02_write_reg(spi, 0x16, 0x9f80);
107 lb035q02_write_reg(spi, 0x17, 0x0a0f);
108 lb035q02_write_reg(spi, 0x1e, 0x00c1);
109 lb035q02_write_reg(spi, 0x30, 0x0300);
110 lb035q02_write_reg(spi, 0x31, 0x0007);
111 lb035q02_write_reg(spi, 0x32, 0x0000);
112 lb035q02_write_reg(spi, 0x33, 0x0000);
113 lb035q02_write_reg(spi, 0x34, 0x0707);
114 lb035q02_write_reg(spi, 0x35, 0x0004);
115 lb035q02_write_reg(spi, 0x36, 0x0302);
116 lb035q02_write_reg(spi, 0x37, 0x0202);
117 lb035q02_write_reg(spi, 0x3a, 0x0a0d);
118 lb035q02_write_reg(spi, 0x3b, 0x0806);
119}
120
121static int lb035q02_connect(struct omap_dss_device *dssdev)
122{
123 struct panel_drv_data *ddata = to_panel_data(dssdev);
124 struct omap_dss_device *in = ddata->in;
125 int r;
126
127 if (omapdss_device_is_connected(dssdev))
128 return 0;
129
130 r = in->ops.dpi->connect(in, dssdev);
131 if (r)
132 return r;
133
134 init_lb035q02_panel(ddata->spi);
135
136 return 0;
137}
138
139static void lb035q02_disconnect(struct omap_dss_device *dssdev)
140{
141 struct panel_drv_data *ddata = to_panel_data(dssdev);
142 struct omap_dss_device *in = ddata->in;
143
144 if (!omapdss_device_is_connected(dssdev))
145 return;
146
147 in->ops.dpi->disconnect(in, dssdev);
148}
149
150static int lb035q02_enable(struct omap_dss_device *dssdev)
151{
152 struct panel_drv_data *ddata = to_panel_data(dssdev);
153 struct omap_dss_device *in = ddata->in;
154 int r;
155
156 if (!omapdss_device_is_connected(dssdev))
157 return -ENODEV;
158
159 if (omapdss_device_is_enabled(dssdev))
160 return 0;
161
162 if (ddata->data_lines)
163 in->ops.dpi->set_data_lines(in, ddata->data_lines);
164 in->ops.dpi->set_timings(in, &ddata->videomode);
165
166 r = in->ops.dpi->enable(in);
167 if (r)
168 return r;
169
170 if (ddata->enable_gpio)
171 gpiod_set_value_cansleep(ddata->enable_gpio, 1);
172
173 if (gpio_is_valid(ddata->backlight_gpio))
174 gpio_set_value_cansleep(ddata->backlight_gpio, 1);
175
176 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
177
178 return 0;
179}
180
181static void lb035q02_disable(struct omap_dss_device *dssdev)
182{
183 struct panel_drv_data *ddata = to_panel_data(dssdev);
184 struct omap_dss_device *in = ddata->in;
185
186 if (!omapdss_device_is_enabled(dssdev))
187 return;
188
189 if (ddata->enable_gpio)
190 gpiod_set_value_cansleep(ddata->enable_gpio, 0);
191
192 if (gpio_is_valid(ddata->backlight_gpio))
193 gpio_set_value_cansleep(ddata->backlight_gpio, 0);
194
195 in->ops.dpi->disable(in);
196
197 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
198}
199
200static void lb035q02_set_timings(struct omap_dss_device *dssdev,
201 struct omap_video_timings *timings)
202{
203 struct panel_drv_data *ddata = to_panel_data(dssdev);
204 struct omap_dss_device *in = ddata->in;
205
206 ddata->videomode = *timings;
207 dssdev->panel.timings = *timings;
208
209 in->ops.dpi->set_timings(in, timings);
210}
211
212static void lb035q02_get_timings(struct omap_dss_device *dssdev,
213 struct omap_video_timings *timings)
214{
215 struct panel_drv_data *ddata = to_panel_data(dssdev);
216
217 *timings = ddata->videomode;
218}
219
220static int lb035q02_check_timings(struct omap_dss_device *dssdev,
221 struct omap_video_timings *timings)
222{
223 struct panel_drv_data *ddata = to_panel_data(dssdev);
224 struct omap_dss_device *in = ddata->in;
225
226 return in->ops.dpi->check_timings(in, timings);
227}
228
229static struct omap_dss_driver lb035q02_ops = {
230 .connect = lb035q02_connect,
231 .disconnect = lb035q02_disconnect,
232
233 .enable = lb035q02_enable,
234 .disable = lb035q02_disable,
235
236 .set_timings = lb035q02_set_timings,
237 .get_timings = lb035q02_get_timings,
238 .check_timings = lb035q02_check_timings,
239
240 .get_resolution = omapdss_default_get_resolution,
241};
242
243static int lb035q02_probe_pdata(struct spi_device *spi)
244{
245 const struct panel_lb035q02_platform_data *pdata;
246 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
247 struct omap_dss_device *dssdev, *in;
248 int r;
249
250 pdata = dev_get_platdata(&spi->dev);
251
252 in = omap_dss_find_output(pdata->source);
253 if (in == NULL) {
254 dev_err(&spi->dev, "failed to find video source '%s'\n",
255 pdata->source);
256 return -EPROBE_DEFER;
257 }
258
259 ddata->in = in;
260
261 ddata->data_lines = pdata->data_lines;
262
263 dssdev = &ddata->dssdev;
264 dssdev->name = pdata->name;
265
266 r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio,
267 GPIOF_OUT_INIT_LOW, "panel enable");
268 if (r)
269 goto err_gpio;
270
271 ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
272
273 ddata->backlight_gpio = pdata->backlight_gpio;
274
275 return 0;
276err_gpio:
277 omap_dss_put_device(ddata->in);
278 return r;
279}
280
281static int lb035q02_probe_of(struct spi_device *spi)
282{
283 struct device_node *node = spi->dev.of_node;
284 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
285 struct omap_dss_device *in;
286 struct gpio_desc *gpio;
287
288 gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW);
289 if (IS_ERR(gpio)) {
290 dev_err(&spi->dev, "failed to parse enable gpio\n");
291 return PTR_ERR(gpio);
292 }
293
294 ddata->enable_gpio = gpio;
295
296 ddata->backlight_gpio = -ENOENT;
297
298 in = omapdss_of_find_source_for_first_ep(node);
299 if (IS_ERR(in)) {
300 dev_err(&spi->dev, "failed to find video source\n");
301 return PTR_ERR(in);
302 }
303
304 ddata->in = in;
305
306 return 0;
307}
308
309static int lb035q02_panel_spi_probe(struct spi_device *spi)
310{
311 struct panel_drv_data *ddata;
312 struct omap_dss_device *dssdev;
313 int r;
314
315 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
316 if (ddata == NULL)
317 return -ENOMEM;
318
319 dev_set_drvdata(&spi->dev, ddata);
320
321 ddata->spi = spi;
322
323 if (dev_get_platdata(&spi->dev)) {
324 r = lb035q02_probe_pdata(spi);
325 if (r)
326 return r;
327 } else if (spi->dev.of_node) {
328 r = lb035q02_probe_of(spi);
329 if (r)
330 return r;
331 } else {
332 return -ENODEV;
333 }
334
335 if (gpio_is_valid(ddata->backlight_gpio)) {
336 r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio,
337 GPIOF_OUT_INIT_LOW, "panel backlight");
338 if (r)
339 goto err_gpio;
340 }
341
342 ddata->videomode = lb035q02_timings;
343
344 dssdev = &ddata->dssdev;
345 dssdev->dev = &spi->dev;
346 dssdev->driver = &lb035q02_ops;
347 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
348 dssdev->owner = THIS_MODULE;
349 dssdev->panel.timings = ddata->videomode;
350 dssdev->phy.dpi.data_lines = ddata->data_lines;
351
352 r = omapdss_register_display(dssdev);
353 if (r) {
354 dev_err(&spi->dev, "Failed to register panel\n");
355 goto err_reg;
356 }
357
358 return 0;
359
360err_reg:
361err_gpio:
362 omap_dss_put_device(ddata->in);
363 return r;
364}
365
366static int lb035q02_panel_spi_remove(struct spi_device *spi)
367{
368 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
369 struct omap_dss_device *dssdev = &ddata->dssdev;
370 struct omap_dss_device *in = ddata->in;
371
372 omapdss_unregister_display(dssdev);
373
374 lb035q02_disable(dssdev);
375 lb035q02_disconnect(dssdev);
376
377 omap_dss_put_device(in);
378
379 return 0;
380}
381
382static const struct of_device_id lb035q02_of_match[] = {
383 { .compatible = "omapdss,lgphilips,lb035q02", },
384 {},
385};
386
387MODULE_DEVICE_TABLE(of, lb035q02_of_match);
388
389static struct spi_driver lb035q02_spi_driver = {
390 .probe = lb035q02_panel_spi_probe,
391 .remove = lb035q02_panel_spi_remove,
392 .driver = {
393 .name = "panel_lgphilips_lb035q02",
394 .of_match_table = lb035q02_of_match,
395 .suppress_bind_attrs = true,
396 },
397};
398
399module_spi_driver(lb035q02_spi_driver);
400
401MODULE_ALIAS("spi:lgphilips,lb035q02");
402MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
403MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver");
404MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
new file mode 100644
index 000000000000..8a928c9a2fc9
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
@@ -0,0 +1,437 @@
1/*
2 * NEC NL8048HL11 Panel driver
3 *
4 * Copyright (C) 2010 Texas Instruments Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/delay.h>
16#include <linux/spi/spi.h>
17#include <linux/fb.h>
18#include <linux/gpio.h>
19#include <linux/of_gpio.h>
20
21#include <video/omapdss.h>
22#include <video/omap-panel-data.h>
23
24struct panel_drv_data {
25 struct omap_dss_device dssdev;
26 struct omap_dss_device *in;
27
28 struct omap_video_timings videomode;
29
30 int data_lines;
31
32 int res_gpio;
33 int qvga_gpio;
34
35 struct spi_device *spi;
36};
37
38#define LCD_XRES 800
39#define LCD_YRES 480
40/*
41 * NEC PIX Clock Ratings
42 * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
43 */
44#define LCD_PIXEL_CLOCK 23800000
45
46static const struct {
47 unsigned char addr;
48 unsigned char dat;
49} nec_8048_init_seq[] = {
50 { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
51 { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
52 { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
53 { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
54 { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
55 { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
56 { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
57 { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
58 { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
59 { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
60 { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
61 { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
62 { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
63 { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
64 { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
65 { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
66 { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
67 { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
68};
69
70static const struct omap_video_timings nec_8048_panel_timings = {
71 .x_res = LCD_XRES,
72 .y_res = LCD_YRES,
73 .pixelclock = LCD_PIXEL_CLOCK,
74 .hfp = 6,
75 .hsw = 1,
76 .hbp = 4,
77 .vfp = 3,
78 .vsw = 1,
79 .vbp = 4,
80
81 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
82 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
83 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
84 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
85 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
86};
87
88#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
89
90static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
91 unsigned char reg_data)
92{
93 int ret = 0;
94 unsigned int cmd = 0, data = 0;
95
96 cmd = 0x0000 | reg_addr; /* register address write */
97 data = 0x0100 | reg_data; /* register data write */
98 data = (cmd << 16) | data;
99
100 ret = spi_write(spi, (unsigned char *)&data, 4);
101 if (ret)
102 pr_err("error in spi_write %x\n", data);
103
104 return ret;
105}
106
107static int init_nec_8048_wvga_lcd(struct spi_device *spi)
108{
109 unsigned int i;
110 /* Initialization Sequence */
111 /* nec_8048_spi_send(spi, REG, VAL) */
112 for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
113 nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
114 nec_8048_init_seq[i].dat);
115 udelay(20);
116 nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
117 nec_8048_init_seq[i].dat);
118 return 0;
119}
120
121static int nec_8048_connect(struct omap_dss_device *dssdev)
122{
123 struct panel_drv_data *ddata = to_panel_data(dssdev);
124 struct omap_dss_device *in = ddata->in;
125 int r;
126
127 if (omapdss_device_is_connected(dssdev))
128 return 0;
129
130 r = in->ops.dpi->connect(in, dssdev);
131 if (r)
132 return r;
133
134 return 0;
135}
136
137static void nec_8048_disconnect(struct omap_dss_device *dssdev)
138{
139 struct panel_drv_data *ddata = to_panel_data(dssdev);
140 struct omap_dss_device *in = ddata->in;
141
142 if (!omapdss_device_is_connected(dssdev))
143 return;
144
145 in->ops.dpi->disconnect(in, dssdev);
146}
147
148static int nec_8048_enable(struct omap_dss_device *dssdev)
149{
150 struct panel_drv_data *ddata = to_panel_data(dssdev);
151 struct omap_dss_device *in = ddata->in;
152 int r;
153
154 if (!omapdss_device_is_connected(dssdev))
155 return -ENODEV;
156
157 if (omapdss_device_is_enabled(dssdev))
158 return 0;
159
160 if (ddata->data_lines)
161 in->ops.dpi->set_data_lines(in, ddata->data_lines);
162 in->ops.dpi->set_timings(in, &ddata->videomode);
163
164 r = in->ops.dpi->enable(in);
165 if (r)
166 return r;
167
168 if (gpio_is_valid(ddata->res_gpio))
169 gpio_set_value_cansleep(ddata->res_gpio, 1);
170
171 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
172
173 return 0;
174}
175
176static void nec_8048_disable(struct omap_dss_device *dssdev)
177{
178 struct panel_drv_data *ddata = to_panel_data(dssdev);
179 struct omap_dss_device *in = ddata->in;
180
181 if (!omapdss_device_is_enabled(dssdev))
182 return;
183
184 if (gpio_is_valid(ddata->res_gpio))
185 gpio_set_value_cansleep(ddata->res_gpio, 0);
186
187 in->ops.dpi->disable(in);
188
189 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
190}
191
192static void nec_8048_set_timings(struct omap_dss_device *dssdev,
193 struct omap_video_timings *timings)
194{
195 struct panel_drv_data *ddata = to_panel_data(dssdev);
196 struct omap_dss_device *in = ddata->in;
197
198 ddata->videomode = *timings;
199 dssdev->panel.timings = *timings;
200
201 in->ops.dpi->set_timings(in, timings);
202}
203
204static void nec_8048_get_timings(struct omap_dss_device *dssdev,
205 struct omap_video_timings *timings)
206{
207 struct panel_drv_data *ddata = to_panel_data(dssdev);
208
209 *timings = ddata->videomode;
210}
211
212static int nec_8048_check_timings(struct omap_dss_device *dssdev,
213 struct omap_video_timings *timings)
214{
215 struct panel_drv_data *ddata = to_panel_data(dssdev);
216 struct omap_dss_device *in = ddata->in;
217
218 return in->ops.dpi->check_timings(in, timings);
219}
220
221static struct omap_dss_driver nec_8048_ops = {
222 .connect = nec_8048_connect,
223 .disconnect = nec_8048_disconnect,
224
225 .enable = nec_8048_enable,
226 .disable = nec_8048_disable,
227
228 .set_timings = nec_8048_set_timings,
229 .get_timings = nec_8048_get_timings,
230 .check_timings = nec_8048_check_timings,
231
232 .get_resolution = omapdss_default_get_resolution,
233};
234
235
236static int nec_8048_probe_pdata(struct spi_device *spi)
237{
238 const struct panel_nec_nl8048hl11_platform_data *pdata;
239 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
240 struct omap_dss_device *dssdev, *in;
241
242 pdata = dev_get_platdata(&spi->dev);
243
244 ddata->qvga_gpio = pdata->qvga_gpio;
245 ddata->res_gpio = pdata->res_gpio;
246
247 in = omap_dss_find_output(pdata->source);
248 if (in == NULL) {
249 dev_err(&spi->dev, "failed to find video source '%s'\n",
250 pdata->source);
251 return -EPROBE_DEFER;
252 }
253 ddata->in = in;
254
255 ddata->data_lines = pdata->data_lines;
256
257 dssdev = &ddata->dssdev;
258 dssdev->name = pdata->name;
259
260 return 0;
261}
262
263static int nec_8048_probe_of(struct spi_device *spi)
264{
265 struct device_node *node = spi->dev.of_node;
266 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
267 struct omap_dss_device *in;
268 int gpio;
269
270 gpio = of_get_named_gpio(node, "reset-gpios", 0);
271 if (!gpio_is_valid(gpio)) {
272 dev_err(&spi->dev, "failed to parse enable gpio\n");
273 return gpio;
274 }
275 ddata->res_gpio = gpio;
276
277 /* XXX the panel spec doesn't mention any QVGA pin?? */
278 ddata->qvga_gpio = -ENOENT;
279
280 in = omapdss_of_find_source_for_first_ep(node);
281 if (IS_ERR(in)) {
282 dev_err(&spi->dev, "failed to find video source\n");
283 return PTR_ERR(in);
284 }
285
286 ddata->in = in;
287
288 return 0;
289}
290
291static int nec_8048_probe(struct spi_device *spi)
292{
293 struct panel_drv_data *ddata;
294 struct omap_dss_device *dssdev;
295 int r;
296
297 dev_dbg(&spi->dev, "%s\n", __func__);
298
299 spi->mode = SPI_MODE_0;
300 spi->bits_per_word = 32;
301
302 r = spi_setup(spi);
303 if (r < 0) {
304 dev_err(&spi->dev, "spi_setup failed: %d\n", r);
305 return r;
306 }
307
308 init_nec_8048_wvga_lcd(spi);
309
310 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
311 if (ddata == NULL)
312 return -ENOMEM;
313
314 dev_set_drvdata(&spi->dev, ddata);
315
316 ddata->spi = spi;
317
318 if (dev_get_platdata(&spi->dev)) {
319 r = nec_8048_probe_pdata(spi);
320 if (r)
321 return r;
322 } else if (spi->dev.of_node) {
323 r = nec_8048_probe_of(spi);
324 if (r)
325 return r;
326 } else {
327 return -ENODEV;
328 }
329
330 if (gpio_is_valid(ddata->qvga_gpio)) {
331 r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
332 GPIOF_OUT_INIT_HIGH, "lcd QVGA");
333 if (r)
334 goto err_gpio;
335 }
336
337 if (gpio_is_valid(ddata->res_gpio)) {
338 r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
339 GPIOF_OUT_INIT_LOW, "lcd RES");
340 if (r)
341 goto err_gpio;
342 }
343
344 ddata->videomode = nec_8048_panel_timings;
345
346 dssdev = &ddata->dssdev;
347 dssdev->dev = &spi->dev;
348 dssdev->driver = &nec_8048_ops;
349 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
350 dssdev->owner = THIS_MODULE;
351 dssdev->panel.timings = ddata->videomode;
352
353 r = omapdss_register_display(dssdev);
354 if (r) {
355 dev_err(&spi->dev, "Failed to register panel\n");
356 goto err_reg;
357 }
358
359 return 0;
360
361err_reg:
362err_gpio:
363 omap_dss_put_device(ddata->in);
364 return r;
365}
366
367static int nec_8048_remove(struct spi_device *spi)
368{
369 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
370 struct omap_dss_device *dssdev = &ddata->dssdev;
371 struct omap_dss_device *in = ddata->in;
372
373 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
374
375 omapdss_unregister_display(dssdev);
376
377 nec_8048_disable(dssdev);
378 nec_8048_disconnect(dssdev);
379
380 omap_dss_put_device(in);
381
382 return 0;
383}
384
385#ifdef CONFIG_PM_SLEEP
386static int nec_8048_suspend(struct device *dev)
387{
388 struct spi_device *spi = to_spi_device(dev);
389
390 nec_8048_spi_send(spi, 2, 0x01);
391 mdelay(40);
392
393 return 0;
394}
395
396static int nec_8048_resume(struct device *dev)
397{
398 struct spi_device *spi = to_spi_device(dev);
399
400 /* reinitialize the panel */
401 spi_setup(spi);
402 nec_8048_spi_send(spi, 2, 0x00);
403 init_nec_8048_wvga_lcd(spi);
404
405 return 0;
406}
407static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend,
408 nec_8048_resume);
409#define NEC_8048_PM_OPS (&nec_8048_pm_ops)
410#else
411#define NEC_8048_PM_OPS NULL
412#endif
413
414static const struct of_device_id nec_8048_of_match[] = {
415 { .compatible = "omapdss,nec,nl8048hl11", },
416 {},
417};
418
419MODULE_DEVICE_TABLE(of, nec_8048_of_match);
420
421static struct spi_driver nec_8048_driver = {
422 .driver = {
423 .name = "panel-nec-nl8048hl11",
424 .pm = NEC_8048_PM_OPS,
425 .of_match_table = nec_8048_of_match,
426 .suppress_bind_attrs = true,
427 },
428 .probe = nec_8048_probe,
429 .remove = nec_8048_remove,
430};
431
432module_spi_driver(nec_8048_driver);
433
434MODULE_ALIAS("spi:nec,nl8048hl11");
435MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
436MODULE_DESCRIPTION("NEC-NL8048HL11 Driver");
437MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
new file mode 100644
index 000000000000..abfd1f6e3327
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
@@ -0,0 +1,415 @@
1/*
2 * LCD panel driver for Sharp LS037V7DW01
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@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
12#include <linux/delay.h>
13#include <linux/gpio.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/of_gpio.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/regulator/consumer.h>
20#include <video/omapdss.h>
21#include <video/omap-panel-data.h>
22
23struct panel_drv_data {
24 struct omap_dss_device dssdev;
25 struct omap_dss_device *in;
26 struct regulator *vcc;
27
28 int data_lines;
29
30 struct omap_video_timings videomode;
31
32 struct gpio_desc *resb_gpio; /* low = reset active min 20 us */
33 struct gpio_desc *ini_gpio; /* high = power on */
34 struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */
35 struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */
36 struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */
37};
38
39static const struct omap_video_timings sharp_ls_timings = {
40 .x_res = 480,
41 .y_res = 640,
42
43 .pixelclock = 19200000,
44
45 .hsw = 2,
46 .hfp = 1,
47 .hbp = 28,
48
49 .vsw = 1,
50 .vfp = 1,
51 .vbp = 1,
52
53 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
54 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
55 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
56 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
57 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
58};
59
60#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
61
62static int sharp_ls_connect(struct omap_dss_device *dssdev)
63{
64 struct panel_drv_data *ddata = to_panel_data(dssdev);
65 struct omap_dss_device *in = ddata->in;
66 int r;
67
68 if (omapdss_device_is_connected(dssdev))
69 return 0;
70
71 r = in->ops.dpi->connect(in, dssdev);
72 if (r)
73 return r;
74
75 return 0;
76}
77
78static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
79{
80 struct panel_drv_data *ddata = to_panel_data(dssdev);
81 struct omap_dss_device *in = ddata->in;
82
83 if (!omapdss_device_is_connected(dssdev))
84 return;
85
86 in->ops.dpi->disconnect(in, dssdev);
87}
88
89static int sharp_ls_enable(struct omap_dss_device *dssdev)
90{
91 struct panel_drv_data *ddata = to_panel_data(dssdev);
92 struct omap_dss_device *in = ddata->in;
93 int r;
94
95 if (!omapdss_device_is_connected(dssdev))
96 return -ENODEV;
97
98 if (omapdss_device_is_enabled(dssdev))
99 return 0;
100
101 if (ddata->data_lines)
102 in->ops.dpi->set_data_lines(in, ddata->data_lines);
103 in->ops.dpi->set_timings(in, &ddata->videomode);
104
105 if (ddata->vcc) {
106 r = regulator_enable(ddata->vcc);
107 if (r != 0)
108 return r;
109 }
110
111 r = in->ops.dpi->enable(in);
112 if (r) {
113 regulator_disable(ddata->vcc);
114 return r;
115 }
116
117 /* wait couple of vsyncs until enabling the LCD */
118 msleep(50);
119
120 if (ddata->resb_gpio)
121 gpiod_set_value_cansleep(ddata->resb_gpio, 1);
122
123 if (ddata->ini_gpio)
124 gpiod_set_value_cansleep(ddata->ini_gpio, 1);
125
126 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
127
128 return 0;
129}
130
131static void sharp_ls_disable(struct omap_dss_device *dssdev)
132{
133 struct panel_drv_data *ddata = to_panel_data(dssdev);
134 struct omap_dss_device *in = ddata->in;
135
136 if (!omapdss_device_is_enabled(dssdev))
137 return;
138
139 if (ddata->ini_gpio)
140 gpiod_set_value_cansleep(ddata->ini_gpio, 0);
141
142 if (ddata->resb_gpio)
143 gpiod_set_value_cansleep(ddata->resb_gpio, 0);
144
145 /* wait at least 5 vsyncs after disabling the LCD */
146
147 msleep(100);
148
149 in->ops.dpi->disable(in);
150
151 if (ddata->vcc)
152 regulator_disable(ddata->vcc);
153
154 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
155}
156
157static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
158 struct omap_video_timings *timings)
159{
160 struct panel_drv_data *ddata = to_panel_data(dssdev);
161 struct omap_dss_device *in = ddata->in;
162
163 ddata->videomode = *timings;
164 dssdev->panel.timings = *timings;
165
166 in->ops.dpi->set_timings(in, timings);
167}
168
169static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
170 struct omap_video_timings *timings)
171{
172 struct panel_drv_data *ddata = to_panel_data(dssdev);
173
174 *timings = ddata->videomode;
175}
176
177static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
178 struct omap_video_timings *timings)
179{
180 struct panel_drv_data *ddata = to_panel_data(dssdev);
181 struct omap_dss_device *in = ddata->in;
182
183 return in->ops.dpi->check_timings(in, timings);
184}
185
186static struct omap_dss_driver sharp_ls_ops = {
187 .connect = sharp_ls_connect,
188 .disconnect = sharp_ls_disconnect,
189
190 .enable = sharp_ls_enable,
191 .disable = sharp_ls_disable,
192
193 .set_timings = sharp_ls_set_timings,
194 .get_timings = sharp_ls_get_timings,
195 .check_timings = sharp_ls_check_timings,
196
197 .get_resolution = omapdss_default_get_resolution,
198};
199
200static int sharp_ls_get_gpio(struct device *dev, int gpio, unsigned long flags,
201 char *desc, struct gpio_desc **gpiod)
202{
203 struct gpio_desc *gd;
204 int r;
205
206 *gpiod = NULL;
207
208 r = devm_gpio_request_one(dev, gpio, flags, desc);
209 if (r)
210 return r == -ENOENT ? 0 : r;
211
212 gd = gpio_to_desc(gpio);
213 if (IS_ERR(gd))
214 return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd);
215
216 *gpiod = gd;
217 return 0;
218}
219
220static int sharp_ls_probe_pdata(struct platform_device *pdev)
221{
222 const struct panel_sharp_ls037v7dw01_platform_data *pdata;
223 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
224 struct omap_dss_device *dssdev, *in;
225 int r;
226
227 pdata = dev_get_platdata(&pdev->dev);
228
229 in = omap_dss_find_output(pdata->source);
230 if (in == NULL) {
231 dev_err(&pdev->dev, "failed to find video source '%s'\n",
232 pdata->source);
233 return -EPROBE_DEFER;
234 }
235
236 ddata->in = in;
237
238 ddata->data_lines = pdata->data_lines;
239
240 dssdev = &ddata->dssdev;
241 dssdev->name = pdata->name;
242
243 r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW,
244 "lcd MO", &ddata->mo_gpio);
245 if (r)
246 return r;
247 r = sharp_ls_get_gpio(&pdev->dev, pdata->lr_gpio, GPIOF_OUT_INIT_HIGH,
248 "lcd LR", &ddata->lr_gpio);
249 if (r)
250 return r;
251 r = sharp_ls_get_gpio(&pdev->dev, pdata->ud_gpio, GPIOF_OUT_INIT_HIGH,
252 "lcd UD", &ddata->ud_gpio);
253 if (r)
254 return r;
255 r = sharp_ls_get_gpio(&pdev->dev, pdata->resb_gpio, GPIOF_OUT_INIT_LOW,
256 "lcd RESB", &ddata->resb_gpio);
257 if (r)
258 return r;
259 r = sharp_ls_get_gpio(&pdev->dev, pdata->ini_gpio, GPIOF_OUT_INIT_LOW,
260 "lcd INI", &ddata->ini_gpio);
261 if (r)
262 return r;
263
264 return 0;
265}
266
267static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
268 const char *desc, struct gpio_desc **gpiod)
269{
270 struct gpio_desc *gd;
271
272 *gpiod = NULL;
273
274 gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW);
275 if (IS_ERR(gd))
276 return PTR_ERR(gd);
277
278 *gpiod = gd;
279 return 0;
280}
281
282static int sharp_ls_probe_of(struct platform_device *pdev)
283{
284 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
285 struct device_node *node = pdev->dev.of_node;
286 struct omap_dss_device *in;
287 int r;
288
289 ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");
290 if (IS_ERR(ddata->vcc)) {
291 dev_err(&pdev->dev, "failed to get regulator\n");
292 return PTR_ERR(ddata->vcc);
293 }
294
295 /* lcd INI */
296 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio);
297 if (r)
298 return r;
299
300 /* lcd RESB */
301 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio);
302 if (r)
303 return r;
304
305 /* lcd MO */
306 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio);
307 if (r)
308 return r;
309
310 /* lcd LR */
311 r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio);
312 if (r)
313 return r;
314
315 /* lcd UD */
316 r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio);
317 if (r)
318 return r;
319
320 in = omapdss_of_find_source_for_first_ep(node);
321 if (IS_ERR(in)) {
322 dev_err(&pdev->dev, "failed to find video source\n");
323 return PTR_ERR(in);
324 }
325
326 ddata->in = in;
327
328 return 0;
329}
330
331static int sharp_ls_probe(struct platform_device *pdev)
332{
333 struct panel_drv_data *ddata;
334 struct omap_dss_device *dssdev;
335 int r;
336
337 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
338 if (ddata == NULL)
339 return -ENOMEM;
340
341 platform_set_drvdata(pdev, ddata);
342
343 if (dev_get_platdata(&pdev->dev)) {
344 r = sharp_ls_probe_pdata(pdev);
345 if (r)
346 return r;
347 } else if (pdev->dev.of_node) {
348 r = sharp_ls_probe_of(pdev);
349 if (r)
350 return r;
351 } else {
352 return -ENODEV;
353 }
354
355 ddata->videomode = sharp_ls_timings;
356
357 dssdev = &ddata->dssdev;
358 dssdev->dev = &pdev->dev;
359 dssdev->driver = &sharp_ls_ops;
360 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
361 dssdev->owner = THIS_MODULE;
362 dssdev->panel.timings = ddata->videomode;
363 dssdev->phy.dpi.data_lines = ddata->data_lines;
364
365 r = omapdss_register_display(dssdev);
366 if (r) {
367 dev_err(&pdev->dev, "Failed to register panel\n");
368 goto err_reg;
369 }
370
371 return 0;
372
373err_reg:
374 omap_dss_put_device(ddata->in);
375 return r;
376}
377
378static int __exit sharp_ls_remove(struct platform_device *pdev)
379{
380 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
381 struct omap_dss_device *dssdev = &ddata->dssdev;
382 struct omap_dss_device *in = ddata->in;
383
384 omapdss_unregister_display(dssdev);
385
386 sharp_ls_disable(dssdev);
387 sharp_ls_disconnect(dssdev);
388
389 omap_dss_put_device(in);
390
391 return 0;
392}
393
394static const struct of_device_id sharp_ls_of_match[] = {
395 { .compatible = "omapdss,sharp,ls037v7dw01", },
396 {},
397};
398
399MODULE_DEVICE_TABLE(of, sharp_ls_of_match);
400
401static struct platform_driver sharp_ls_driver = {
402 .probe = sharp_ls_probe,
403 .remove = __exit_p(sharp_ls_remove),
404 .driver = {
405 .name = "panel-sharp-ls037v7dw01",
406 .of_match_table = sharp_ls_of_match,
407 .suppress_bind_attrs = true,
408 },
409};
410
411module_platform_driver(sharp_ls_driver);
412
413MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
414MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
415MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
new file mode 100644
index 000000000000..31efcca801bd
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
@@ -0,0 +1,917 @@
1/*
2 * Sony ACX565AKM LCD Panel driver
3 *
4 * Copyright (C) 2010 Nokia Corporation
5 *
6 * Original Driver Author: Imre Deak <imre.deak@nokia.com>
7 * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
8 * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/delay.h>
27#include <linux/spi/spi.h>
28#include <linux/jiffies.h>
29#include <linux/sched.h>
30#include <linux/backlight.h>
31#include <linux/fb.h>
32#include <linux/gpio.h>
33#include <linux/of.h>
34#include <linux/of_gpio.h>
35
36#include <video/omapdss.h>
37#include <video/omap-panel-data.h>
38
39#define MIPID_CMD_READ_DISP_ID 0x04
40#define MIPID_CMD_READ_RED 0x06
41#define MIPID_CMD_READ_GREEN 0x07
42#define MIPID_CMD_READ_BLUE 0x08
43#define MIPID_CMD_READ_DISP_STATUS 0x09
44#define MIPID_CMD_RDDSDR 0x0F
45#define MIPID_CMD_SLEEP_IN 0x10
46#define MIPID_CMD_SLEEP_OUT 0x11
47#define MIPID_CMD_DISP_OFF 0x28
48#define MIPID_CMD_DISP_ON 0x29
49#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
50#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
51#define MIPID_CMD_WRITE_CTRL_DISP 0x53
52
53#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
54#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
55#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
56#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
57
58#define MIPID_CMD_READ_CTRL_DISP 0x54
59#define MIPID_CMD_WRITE_CABC 0x55
60#define MIPID_CMD_READ_CABC 0x56
61
62#define MIPID_VER_LPH8923 3
63#define MIPID_VER_LS041Y3 4
64#define MIPID_VER_L4F00311 8
65#define MIPID_VER_ACX565AKM 9
66
67struct panel_drv_data {
68 struct omap_dss_device dssdev;
69 struct omap_dss_device *in;
70
71 int reset_gpio;
72 int datapairs;
73
74 struct omap_video_timings videomode;
75
76 char *name;
77 int enabled;
78 int model;
79 int revision;
80 u8 display_id[3];
81 unsigned has_bc:1;
82 unsigned has_cabc:1;
83 unsigned cabc_mode;
84 unsigned long hw_guard_end; /* next value of jiffies
85 when we can issue the
86 next sleep in/out command */
87 unsigned long hw_guard_wait; /* max guard time in jiffies */
88
89 struct spi_device *spi;
90 struct mutex mutex;
91
92 struct backlight_device *bl_dev;
93};
94
95static const struct omap_video_timings acx565akm_panel_timings = {
96 .x_res = 800,
97 .y_res = 480,
98 .pixelclock = 24000000,
99 .hfp = 28,
100 .hsw = 4,
101 .hbp = 24,
102 .vfp = 3,
103 .vsw = 3,
104 .vbp = 4,
105
106 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
107 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
108
109 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
110 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
111 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
112};
113
114#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
115
116static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd,
117 const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
118{
119 struct spi_message m;
120 struct spi_transfer *x, xfer[5];
121 int r;
122
123 BUG_ON(ddata->spi == NULL);
124
125 spi_message_init(&m);
126
127 memset(xfer, 0, sizeof(xfer));
128 x = &xfer[0];
129
130 cmd &= 0xff;
131 x->tx_buf = &cmd;
132 x->bits_per_word = 9;
133 x->len = 2;
134
135 if (rlen > 1 && wlen == 0) {
136 /*
137 * Between the command and the response data there is a
138 * dummy clock cycle. Add an extra bit after the command
139 * word to account for this.
140 */
141 x->bits_per_word = 10;
142 cmd <<= 1;
143 }
144 spi_message_add_tail(x, &m);
145
146 if (wlen) {
147 x++;
148 x->tx_buf = wbuf;
149 x->len = wlen;
150 x->bits_per_word = 9;
151 spi_message_add_tail(x, &m);
152 }
153
154 if (rlen) {
155 x++;
156 x->rx_buf = rbuf;
157 x->len = rlen;
158 spi_message_add_tail(x, &m);
159 }
160
161 r = spi_sync(ddata->spi, &m);
162 if (r < 0)
163 dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r);
164}
165
166static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd)
167{
168 acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0);
169}
170
171static inline void acx565akm_write(struct panel_drv_data *ddata,
172 int reg, const u8 *buf, int len)
173{
174 acx565akm_transfer(ddata, reg, buf, len, NULL, 0);
175}
176
177static inline void acx565akm_read(struct panel_drv_data *ddata,
178 int reg, u8 *buf, int len)
179{
180 acx565akm_transfer(ddata, reg, NULL, 0, buf, len);
181}
182
183static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
184{
185 ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
186 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
187}
188
189static void hw_guard_wait(struct panel_drv_data *ddata)
190{
191 unsigned long wait = ddata->hw_guard_end - jiffies;
192
193 if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
194 set_current_state(TASK_UNINTERRUPTIBLE);
195 schedule_timeout(wait);
196 }
197}
198
199static void set_sleep_mode(struct panel_drv_data *ddata, int on)
200{
201 int cmd;
202
203 if (on)
204 cmd = MIPID_CMD_SLEEP_IN;
205 else
206 cmd = MIPID_CMD_SLEEP_OUT;
207 /*
208 * We have to keep 120msec between sleep in/out commands.
209 * (8.2.15, 8.2.16).
210 */
211 hw_guard_wait(ddata);
212 acx565akm_cmd(ddata, cmd);
213 hw_guard_start(ddata, 120);
214}
215
216static void set_display_state(struct panel_drv_data *ddata, int enabled)
217{
218 int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
219
220 acx565akm_cmd(ddata, cmd);
221}
222
223static int panel_enabled(struct panel_drv_data *ddata)
224{
225 u32 disp_status;
226 int enabled;
227
228 acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS,
229 (u8 *)&disp_status, 4);
230 disp_status = __be32_to_cpu(disp_status);
231 enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
232 dev_dbg(&ddata->spi->dev,
233 "LCD panel %senabled by bootloader (status 0x%04x)\n",
234 enabled ? "" : "not ", disp_status);
235 return enabled;
236}
237
238static int panel_detect(struct panel_drv_data *ddata)
239{
240 acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3);
241 dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n",
242 ddata->display_id[0],
243 ddata->display_id[1],
244 ddata->display_id[2]);
245
246 switch (ddata->display_id[0]) {
247 case 0x10:
248 ddata->model = MIPID_VER_ACX565AKM;
249 ddata->name = "acx565akm";
250 ddata->has_bc = 1;
251 ddata->has_cabc = 1;
252 break;
253 case 0x29:
254 ddata->model = MIPID_VER_L4F00311;
255 ddata->name = "l4f00311";
256 break;
257 case 0x45:
258 ddata->model = MIPID_VER_LPH8923;
259 ddata->name = "lph8923";
260 break;
261 case 0x83:
262 ddata->model = MIPID_VER_LS041Y3;
263 ddata->name = "ls041y3";
264 break;
265 default:
266 ddata->name = "unknown";
267 dev_err(&ddata->spi->dev, "invalid display ID\n");
268 return -ENODEV;
269 }
270
271 ddata->revision = ddata->display_id[1];
272
273 dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n",
274 ddata->name, ddata->revision);
275
276 return 0;
277}
278
279/*----------------------Backlight Control-------------------------*/
280
281static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable)
282{
283 u16 ctrl;
284
285 acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
286 if (enable) {
287 ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
288 CTRL_DISP_BACKLIGHT_ON;
289 } else {
290 ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
291 CTRL_DISP_BACKLIGHT_ON);
292 }
293
294 ctrl |= 1 << 8;
295 acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
296}
297
298static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode)
299{
300 u16 cabc_ctrl;
301
302 ddata->cabc_mode = mode;
303 if (!ddata->enabled)
304 return;
305 cabc_ctrl = 0;
306 acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
307 cabc_ctrl &= ~3;
308 cabc_ctrl |= (1 << 8) | (mode & 3);
309 acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
310}
311
312static unsigned get_cabc_mode(struct panel_drv_data *ddata)
313{
314 return ddata->cabc_mode;
315}
316
317static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata)
318{
319 u8 cabc_ctrl;
320
321 acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
322 return cabc_ctrl & 3;
323}
324
325static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level)
326{
327 int bv;
328
329 bv = level | (1 << 8);
330 acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
331
332 if (level)
333 enable_backlight_ctrl(ddata, 1);
334 else
335 enable_backlight_ctrl(ddata, 0);
336}
337
338static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata)
339{
340 u8 bv;
341
342 acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
343
344 return bv;
345}
346
347
348static int acx565akm_bl_update_status(struct backlight_device *dev)
349{
350 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
351 int level;
352
353 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
354
355 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
356 dev->props.power == FB_BLANK_UNBLANK)
357 level = dev->props.brightness;
358 else
359 level = 0;
360
361 if (ddata->has_bc)
362 acx565akm_set_brightness(ddata, level);
363 else
364 return -ENODEV;
365
366 return 0;
367}
368
369static int acx565akm_bl_get_intensity(struct backlight_device *dev)
370{
371 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
372
373 dev_dbg(&dev->dev, "%s\n", __func__);
374
375 if (!ddata->has_bc)
376 return -ENODEV;
377
378 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
379 dev->props.power == FB_BLANK_UNBLANK) {
380 if (ddata->has_bc)
381 return acx565akm_get_actual_brightness(ddata);
382 else
383 return dev->props.brightness;
384 }
385
386 return 0;
387}
388
389static int acx565akm_bl_update_status_locked(struct backlight_device *dev)
390{
391 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
392 int r;
393
394 mutex_lock(&ddata->mutex);
395 r = acx565akm_bl_update_status(dev);
396 mutex_unlock(&ddata->mutex);
397
398 return r;
399}
400
401static int acx565akm_bl_get_intensity_locked(struct backlight_device *dev)
402{
403 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
404 int r;
405
406 mutex_lock(&ddata->mutex);
407 r = acx565akm_bl_get_intensity(dev);
408 mutex_unlock(&ddata->mutex);
409
410 return r;
411}
412
413static const struct backlight_ops acx565akm_bl_ops = {
414 .get_brightness = acx565akm_bl_get_intensity_locked,
415 .update_status = acx565akm_bl_update_status_locked,
416};
417
418/*--------------------Auto Brightness control via Sysfs---------------------*/
419
420static const char * const cabc_modes[] = {
421 "off", /* always used when CABC is not supported */
422 "ui",
423 "still-image",
424 "moving-image",
425};
426
427static ssize_t show_cabc_mode(struct device *dev,
428 struct device_attribute *attr,
429 char *buf)
430{
431 struct panel_drv_data *ddata = dev_get_drvdata(dev);
432 const char *mode_str;
433 int mode;
434 int len;
435
436 if (!ddata->has_cabc)
437 mode = 0;
438 else
439 mode = get_cabc_mode(ddata);
440 mode_str = "unknown";
441 if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
442 mode_str = cabc_modes[mode];
443 len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
444
445 return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
446}
447
448static ssize_t store_cabc_mode(struct device *dev,
449 struct device_attribute *attr,
450 const char *buf, size_t count)
451{
452 struct panel_drv_data *ddata = dev_get_drvdata(dev);
453 int i;
454
455 for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
456 const char *mode_str = cabc_modes[i];
457 int cmp_len = strlen(mode_str);
458
459 if (count > 0 && buf[count - 1] == '\n')
460 count--;
461 if (count != cmp_len)
462 continue;
463
464 if (strncmp(buf, mode_str, cmp_len) == 0)
465 break;
466 }
467
468 if (i == ARRAY_SIZE(cabc_modes))
469 return -EINVAL;
470
471 if (!ddata->has_cabc && i != 0)
472 return -EINVAL;
473
474 mutex_lock(&ddata->mutex);
475 set_cabc_mode(ddata, i);
476 mutex_unlock(&ddata->mutex);
477
478 return count;
479}
480
481static ssize_t show_cabc_available_modes(struct device *dev,
482 struct device_attribute *attr,
483 char *buf)
484{
485 struct panel_drv_data *ddata = dev_get_drvdata(dev);
486 int len;
487 int i;
488
489 if (!ddata->has_cabc)
490 return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
491
492 for (i = 0, len = 0;
493 len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
494 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
495 i ? " " : "", cabc_modes[i],
496 i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
497
498 return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
499}
500
501static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
502 show_cabc_mode, store_cabc_mode);
503static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
504 show_cabc_available_modes, NULL);
505
506static struct attribute *bldev_attrs[] = {
507 &dev_attr_cabc_mode.attr,
508 &dev_attr_cabc_available_modes.attr,
509 NULL,
510};
511
512static struct attribute_group bldev_attr_group = {
513 .attrs = bldev_attrs,
514};
515
516static int acx565akm_connect(struct omap_dss_device *dssdev)
517{
518 struct panel_drv_data *ddata = to_panel_data(dssdev);
519 struct omap_dss_device *in = ddata->in;
520 int r;
521
522 if (omapdss_device_is_connected(dssdev))
523 return 0;
524
525 r = in->ops.sdi->connect(in, dssdev);
526 if (r)
527 return r;
528
529 return 0;
530}
531
532static void acx565akm_disconnect(struct omap_dss_device *dssdev)
533{
534 struct panel_drv_data *ddata = to_panel_data(dssdev);
535 struct omap_dss_device *in = ddata->in;
536
537 if (!omapdss_device_is_connected(dssdev))
538 return;
539
540 in->ops.sdi->disconnect(in, dssdev);
541}
542
543static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
544{
545 struct panel_drv_data *ddata = to_panel_data(dssdev);
546 struct omap_dss_device *in = ddata->in;
547 int r;
548
549 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
550
551 in->ops.sdi->set_timings(in, &ddata->videomode);
552
553 if (ddata->datapairs > 0)
554 in->ops.sdi->set_datapairs(in, ddata->datapairs);
555
556 r = in->ops.sdi->enable(in);
557 if (r) {
558 pr_err("%s sdi enable failed\n", __func__);
559 return r;
560 }
561
562 /*FIXME tweak me */
563 msleep(50);
564
565 if (gpio_is_valid(ddata->reset_gpio))
566 gpio_set_value(ddata->reset_gpio, 1);
567
568 if (ddata->enabled) {
569 dev_dbg(&ddata->spi->dev, "panel already enabled\n");
570 return 0;
571 }
572
573 /*
574 * We have to meet all the following delay requirements:
575 * 1. tRW: reset pulse width 10usec (7.12.1)
576 * 2. tRT: reset cancel time 5msec (7.12.1)
577 * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
578 * case (7.6.2)
579 * 4. 120msec before the sleep out command (7.12.1)
580 */
581 msleep(120);
582
583 set_sleep_mode(ddata, 0);
584 ddata->enabled = 1;
585
586 /* 5msec between sleep out and the next command. (8.2.16) */
587 usleep_range(5000, 10000);
588 set_display_state(ddata, 1);
589 set_cabc_mode(ddata, ddata->cabc_mode);
590
591 return acx565akm_bl_update_status(ddata->bl_dev);
592}
593
594static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
595{
596 struct panel_drv_data *ddata = to_panel_data(dssdev);
597 struct omap_dss_device *in = ddata->in;
598
599 dev_dbg(dssdev->dev, "%s\n", __func__);
600
601 if (!ddata->enabled)
602 return;
603
604 set_display_state(ddata, 0);
605 set_sleep_mode(ddata, 1);
606 ddata->enabled = 0;
607 /*
608 * We have to provide PCLK,HS,VS signals for 2 frames (worst case
609 * ~50msec) after sending the sleep in command and asserting the
610 * reset signal. We probably could assert the reset w/o the delay
611 * but we still delay to avoid possible artifacts. (7.6.1)
612 */
613 msleep(50);
614
615 if (gpio_is_valid(ddata->reset_gpio))
616 gpio_set_value(ddata->reset_gpio, 0);
617
618 /* FIXME need to tweak this delay */
619 msleep(100);
620
621 in->ops.sdi->disable(in);
622}
623
624static int acx565akm_enable(struct omap_dss_device *dssdev)
625{
626 struct panel_drv_data *ddata = to_panel_data(dssdev);
627 int r;
628
629 dev_dbg(dssdev->dev, "%s\n", __func__);
630
631 if (!omapdss_device_is_connected(dssdev))
632 return -ENODEV;
633
634 if (omapdss_device_is_enabled(dssdev))
635 return 0;
636
637 mutex_lock(&ddata->mutex);
638 r = acx565akm_panel_power_on(dssdev);
639 mutex_unlock(&ddata->mutex);
640 if (r)
641 return r;
642
643 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
644
645 return 0;
646}
647
648static void acx565akm_disable(struct omap_dss_device *dssdev)
649{
650 struct panel_drv_data *ddata = to_panel_data(dssdev);
651
652 dev_dbg(dssdev->dev, "%s\n", __func__);
653
654 if (!omapdss_device_is_enabled(dssdev))
655 return;
656
657 mutex_lock(&ddata->mutex);
658 acx565akm_panel_power_off(dssdev);
659 mutex_unlock(&ddata->mutex);
660
661 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
662}
663
664static void acx565akm_set_timings(struct omap_dss_device *dssdev,
665 struct omap_video_timings *timings)
666{
667 struct panel_drv_data *ddata = to_panel_data(dssdev);
668 struct omap_dss_device *in = ddata->in;
669
670 ddata->videomode = *timings;
671 dssdev->panel.timings = *timings;
672
673 in->ops.sdi->set_timings(in, timings);
674}
675
676static void acx565akm_get_timings(struct omap_dss_device *dssdev,
677 struct omap_video_timings *timings)
678{
679 struct panel_drv_data *ddata = to_panel_data(dssdev);
680
681 *timings = ddata->videomode;
682}
683
684static int acx565akm_check_timings(struct omap_dss_device *dssdev,
685 struct omap_video_timings *timings)
686{
687 struct panel_drv_data *ddata = to_panel_data(dssdev);
688 struct omap_dss_device *in = ddata->in;
689
690 return in->ops.sdi->check_timings(in, timings);
691}
692
693static struct omap_dss_driver acx565akm_ops = {
694 .connect = acx565akm_connect,
695 .disconnect = acx565akm_disconnect,
696
697 .enable = acx565akm_enable,
698 .disable = acx565akm_disable,
699
700 .set_timings = acx565akm_set_timings,
701 .get_timings = acx565akm_get_timings,
702 .check_timings = acx565akm_check_timings,
703
704 .get_resolution = omapdss_default_get_resolution,
705};
706
707static int acx565akm_probe_pdata(struct spi_device *spi)
708{
709 const struct panel_acx565akm_platform_data *pdata;
710 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
711 struct omap_dss_device *dssdev, *in;
712
713 pdata = dev_get_platdata(&spi->dev);
714
715 ddata->reset_gpio = pdata->reset_gpio;
716
717 in = omap_dss_find_output(pdata->source);
718 if (in == NULL) {
719 dev_err(&spi->dev, "failed to find video source '%s'\n",
720 pdata->source);
721 return -EPROBE_DEFER;
722 }
723 ddata->in = in;
724
725 ddata->datapairs = pdata->datapairs;
726
727 dssdev = &ddata->dssdev;
728 dssdev->name = pdata->name;
729
730 return 0;
731}
732
733static int acx565akm_probe_of(struct spi_device *spi)
734{
735 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
736 struct device_node *np = spi->dev.of_node;
737
738 ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
739
740 ddata->in = omapdss_of_find_source_for_first_ep(np);
741 if (IS_ERR(ddata->in)) {
742 dev_err(&spi->dev, "failed to find video source\n");
743 return PTR_ERR(ddata->in);
744 }
745
746 return 0;
747}
748
749static int acx565akm_probe(struct spi_device *spi)
750{
751 struct panel_drv_data *ddata;
752 struct omap_dss_device *dssdev;
753 struct backlight_device *bldev;
754 int max_brightness, brightness;
755 struct backlight_properties props;
756 int r;
757
758 dev_dbg(&spi->dev, "%s\n", __func__);
759
760 spi->mode = SPI_MODE_3;
761
762 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
763 if (ddata == NULL)
764 return -ENOMEM;
765
766 dev_set_drvdata(&spi->dev, ddata);
767
768 ddata->spi = spi;
769
770 mutex_init(&ddata->mutex);
771
772 if (dev_get_platdata(&spi->dev)) {
773 r = acx565akm_probe_pdata(spi);
774 if (r)
775 return r;
776 } else if (spi->dev.of_node) {
777 r = acx565akm_probe_of(spi);
778 if (r)
779 return r;
780 } else {
781 dev_err(&spi->dev, "platform data missing!\n");
782 return -ENODEV;
783 }
784
785 if (gpio_is_valid(ddata->reset_gpio)) {
786 r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
787 GPIOF_OUT_INIT_LOW, "lcd reset");
788 if (r)
789 goto err_gpio;
790 }
791
792 if (gpio_is_valid(ddata->reset_gpio))
793 gpio_set_value(ddata->reset_gpio, 1);
794
795 /*
796 * After reset we have to wait 5 msec before the first
797 * command can be sent.
798 */
799 usleep_range(5000, 10000);
800
801 ddata->enabled = panel_enabled(ddata);
802
803 r = panel_detect(ddata);
804
805 if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
806 gpio_set_value(ddata->reset_gpio, 0);
807
808 if (r) {
809 dev_err(&spi->dev, "%s panel detect error\n", __func__);
810 goto err_detect;
811 }
812
813 memset(&props, 0, sizeof(props));
814 props.fb_blank = FB_BLANK_UNBLANK;
815 props.power = FB_BLANK_UNBLANK;
816 props.type = BACKLIGHT_RAW;
817
818 bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
819 ddata, &acx565akm_bl_ops, &props);
820 if (IS_ERR(bldev)) {
821 r = PTR_ERR(bldev);
822 goto err_reg_bl;
823 }
824 ddata->bl_dev = bldev;
825 if (ddata->has_cabc) {
826 r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
827 if (r) {
828 dev_err(&bldev->dev,
829 "%s failed to create sysfs files\n", __func__);
830 goto err_sysfs;
831 }
832 ddata->cabc_mode = get_hw_cabc_mode(ddata);
833 }
834
835 max_brightness = 255;
836
837 if (ddata->has_bc)
838 brightness = acx565akm_get_actual_brightness(ddata);
839 else
840 brightness = 0;
841
842 bldev->props.max_brightness = max_brightness;
843 bldev->props.brightness = brightness;
844
845 acx565akm_bl_update_status(bldev);
846
847
848 ddata->videomode = acx565akm_panel_timings;
849
850 dssdev = &ddata->dssdev;
851 dssdev->dev = &spi->dev;
852 dssdev->driver = &acx565akm_ops;
853 dssdev->type = OMAP_DISPLAY_TYPE_SDI;
854 dssdev->owner = THIS_MODULE;
855 dssdev->panel.timings = ddata->videomode;
856
857 r = omapdss_register_display(dssdev);
858 if (r) {
859 dev_err(&spi->dev, "Failed to register panel\n");
860 goto err_reg;
861 }
862
863 return 0;
864
865err_reg:
866 sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
867err_sysfs:
868 backlight_device_unregister(bldev);
869err_reg_bl:
870err_detect:
871err_gpio:
872 omap_dss_put_device(ddata->in);
873 return r;
874}
875
876static int acx565akm_remove(struct spi_device *spi)
877{
878 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
879 struct omap_dss_device *dssdev = &ddata->dssdev;
880 struct omap_dss_device *in = ddata->in;
881
882 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
883
884 sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
885 backlight_device_unregister(ddata->bl_dev);
886
887 omapdss_unregister_display(dssdev);
888
889 acx565akm_disable(dssdev);
890 acx565akm_disconnect(dssdev);
891
892 omap_dss_put_device(in);
893
894 return 0;
895}
896
897static const struct of_device_id acx565akm_of_match[] = {
898 { .compatible = "omapdss,sony,acx565akm", },
899 {},
900};
901MODULE_DEVICE_TABLE(of, acx565akm_of_match);
902
903static struct spi_driver acx565akm_driver = {
904 .driver = {
905 .name = "acx565akm",
906 .of_match_table = acx565akm_of_match,
907 .suppress_bind_attrs = true,
908 },
909 .probe = acx565akm_probe,
910 .remove = acx565akm_remove,
911};
912
913module_spi_driver(acx565akm_driver);
914
915MODULE_AUTHOR("Nokia Corporation");
916MODULE_DESCRIPTION("acx565akm LCD Driver");
917MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
new file mode 100644
index 000000000000..4d657f3ab679
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
@@ -0,0 +1,511 @@
1/*
2 * Toppoly TD028TTEC1 panel support
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Neo 1973 code (jbt6k74.c):
8 * Copyright (C) 2006-2007 by OpenMoko, Inc.
9 * Author: Harald Welte <laforge@openmoko.org>
10 *
11 * Ported and adapted from Neo 1973 U-Boot by:
12 * H. Nikolaus Schaller <hns@goldelico.com>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License version 2 as published by
16 * the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 * more details.
22 *
23 * You should have received a copy of the GNU General Public License along with
24 * this program. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#include <linux/module.h>
28#include <linux/delay.h>
29#include <linux/spi/spi.h>
30#include <linux/gpio.h>
31#include <video/omapdss.h>
32#include <video/omap-panel-data.h>
33
34struct panel_drv_data {
35 struct omap_dss_device dssdev;
36 struct omap_dss_device *in;
37
38 int data_lines;
39
40 struct omap_video_timings videomode;
41
42 struct spi_device *spi_dev;
43};
44
45static struct omap_video_timings td028ttec1_panel_timings = {
46 .x_res = 480,
47 .y_res = 640,
48 .pixelclock = 22153000,
49 .hfp = 24,
50 .hsw = 8,
51 .hbp = 8,
52 .vfp = 4,
53 .vsw = 2,
54 .vbp = 2,
55
56 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
57 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
58
59 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
60 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
61 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
62};
63
64#define JBT_COMMAND 0x000
65#define JBT_DATA 0x100
66
67static int jbt_ret_write_0(struct panel_drv_data *ddata, u8 reg)
68{
69 int rc;
70 u16 tx_buf = JBT_COMMAND | reg;
71
72 rc = spi_write(ddata->spi_dev, (u8 *)&tx_buf,
73 1*sizeof(u16));
74 if (rc != 0)
75 dev_err(&ddata->spi_dev->dev,
76 "jbt_ret_write_0 spi_write ret %d\n", rc);
77
78 return rc;
79}
80
81static int jbt_reg_write_1(struct panel_drv_data *ddata, u8 reg, u8 data)
82{
83 int rc;
84 u16 tx_buf[2];
85
86 tx_buf[0] = JBT_COMMAND | reg;
87 tx_buf[1] = JBT_DATA | data;
88 rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
89 2*sizeof(u16));
90 if (rc != 0)
91 dev_err(&ddata->spi_dev->dev,
92 "jbt_reg_write_1 spi_write ret %d\n", rc);
93
94 return rc;
95}
96
97static int jbt_reg_write_2(struct panel_drv_data *ddata, u8 reg, u16 data)
98{
99 int rc;
100 u16 tx_buf[3];
101
102 tx_buf[0] = JBT_COMMAND | reg;
103 tx_buf[1] = JBT_DATA | (data >> 8);
104 tx_buf[2] = JBT_DATA | (data & 0xff);
105
106 rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
107 3*sizeof(u16));
108
109 if (rc != 0)
110 dev_err(&ddata->spi_dev->dev,
111 "jbt_reg_write_2 spi_write ret %d\n", rc);
112
113 return rc;
114}
115
116enum jbt_register {
117 JBT_REG_SLEEP_IN = 0x10,
118 JBT_REG_SLEEP_OUT = 0x11,
119
120 JBT_REG_DISPLAY_OFF = 0x28,
121 JBT_REG_DISPLAY_ON = 0x29,
122
123 JBT_REG_RGB_FORMAT = 0x3a,
124 JBT_REG_QUAD_RATE = 0x3b,
125
126 JBT_REG_POWER_ON_OFF = 0xb0,
127 JBT_REG_BOOSTER_OP = 0xb1,
128 JBT_REG_BOOSTER_MODE = 0xb2,
129 JBT_REG_BOOSTER_FREQ = 0xb3,
130 JBT_REG_OPAMP_SYSCLK = 0xb4,
131 JBT_REG_VSC_VOLTAGE = 0xb5,
132 JBT_REG_VCOM_VOLTAGE = 0xb6,
133 JBT_REG_EXT_DISPL = 0xb7,
134 JBT_REG_OUTPUT_CONTROL = 0xb8,
135 JBT_REG_DCCLK_DCEV = 0xb9,
136 JBT_REG_DISPLAY_MODE1 = 0xba,
137 JBT_REG_DISPLAY_MODE2 = 0xbb,
138 JBT_REG_DISPLAY_MODE = 0xbc,
139 JBT_REG_ASW_SLEW = 0xbd,
140 JBT_REG_DUMMY_DISPLAY = 0xbe,
141 JBT_REG_DRIVE_SYSTEM = 0xbf,
142
143 JBT_REG_SLEEP_OUT_FR_A = 0xc0,
144 JBT_REG_SLEEP_OUT_FR_B = 0xc1,
145 JBT_REG_SLEEP_OUT_FR_C = 0xc2,
146 JBT_REG_SLEEP_IN_LCCNT_D = 0xc3,
147 JBT_REG_SLEEP_IN_LCCNT_E = 0xc4,
148 JBT_REG_SLEEP_IN_LCCNT_F = 0xc5,
149 JBT_REG_SLEEP_IN_LCCNT_G = 0xc6,
150
151 JBT_REG_GAMMA1_FINE_1 = 0xc7,
152 JBT_REG_GAMMA1_FINE_2 = 0xc8,
153 JBT_REG_GAMMA1_INCLINATION = 0xc9,
154 JBT_REG_GAMMA1_BLUE_OFFSET = 0xca,
155
156 JBT_REG_BLANK_CONTROL = 0xcf,
157 JBT_REG_BLANK_TH_TV = 0xd0,
158 JBT_REG_CKV_ON_OFF = 0xd1,
159 JBT_REG_CKV_1_2 = 0xd2,
160 JBT_REG_OEV_TIMING = 0xd3,
161 JBT_REG_ASW_TIMING_1 = 0xd4,
162 JBT_REG_ASW_TIMING_2 = 0xd5,
163
164 JBT_REG_HCLOCK_VGA = 0xec,
165 JBT_REG_HCLOCK_QVGA = 0xed,
166};
167
168#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
169
170static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
171{
172 struct panel_drv_data *ddata = to_panel_data(dssdev);
173 struct omap_dss_device *in = ddata->in;
174 int r;
175
176 if (omapdss_device_is_connected(dssdev))
177 return 0;
178
179 r = in->ops.dpi->connect(in, dssdev);
180 if (r)
181 return r;
182
183 return 0;
184}
185
186static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
187{
188 struct panel_drv_data *ddata = to_panel_data(dssdev);
189 struct omap_dss_device *in = ddata->in;
190
191 if (!omapdss_device_is_connected(dssdev))
192 return;
193
194 in->ops.dpi->disconnect(in, dssdev);
195}
196
197static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
198{
199 struct panel_drv_data *ddata = to_panel_data(dssdev);
200 struct omap_dss_device *in = ddata->in;
201 int r;
202
203 if (!omapdss_device_is_connected(dssdev))
204 return -ENODEV;
205
206 if (omapdss_device_is_enabled(dssdev))
207 return 0;
208
209 if (ddata->data_lines)
210 in->ops.dpi->set_data_lines(in, ddata->data_lines);
211 in->ops.dpi->set_timings(in, &ddata->videomode);
212
213 r = in->ops.dpi->enable(in);
214 if (r)
215 return r;
216
217 dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
218 dssdev->state);
219
220 /* three times command zero */
221 r |= jbt_ret_write_0(ddata, 0x00);
222 usleep_range(1000, 2000);
223 r |= jbt_ret_write_0(ddata, 0x00);
224 usleep_range(1000, 2000);
225 r |= jbt_ret_write_0(ddata, 0x00);
226 usleep_range(1000, 2000);
227
228 if (r) {
229 dev_warn(dssdev->dev, "transfer error\n");
230 goto transfer_err;
231 }
232
233 /* deep standby out */
234 r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x17);
235
236 /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
237 r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE, 0x80);
238
239 /* Quad mode off */
240 r |= jbt_reg_write_1(ddata, JBT_REG_QUAD_RATE, 0x00);
241
242 /* AVDD on, XVDD on */
243 r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x16);
244
245 /* Output control */
246 r |= jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
247
248 /* Sleep mode off */
249 r |= jbt_ret_write_0(ddata, JBT_REG_SLEEP_OUT);
250
251 /* at this point we have like 50% grey */
252
253 /* initialize register set */
254 r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
255 r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
256 r |= jbt_reg_write_1(ddata, JBT_REG_RGB_FORMAT, 0x60);
257 r |= jbt_reg_write_1(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
258 r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_OP, 0x56);
259 r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_MODE, 0x33);
260 r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
261 r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
262 r |= jbt_reg_write_1(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
263 r |= jbt_reg_write_1(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
264 r |= jbt_reg_write_1(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
265 r |= jbt_reg_write_1(ddata, JBT_REG_EXT_DISPL, 0x03);
266 r |= jbt_reg_write_1(ddata, JBT_REG_DCCLK_DCEV, 0x04);
267 /*
268 * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
269 * to avoid red / blue flicker
270 */
271 r |= jbt_reg_write_1(ddata, JBT_REG_ASW_SLEW, 0x04);
272 r |= jbt_reg_write_1(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
273
274 r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
275 r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
276 r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
277 r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
278 r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
279 r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
280 r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
281
282 r |= jbt_reg_write_2(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
283 r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
284 r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
285 r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
286
287 r |= jbt_reg_write_2(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
288 r |= jbt_reg_write_1(ddata, JBT_REG_BLANK_CONTROL, 0x02);
289 r |= jbt_reg_write_2(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
290
291 r |= jbt_reg_write_1(ddata, JBT_REG_CKV_ON_OFF, 0x01);
292 r |= jbt_reg_write_2(ddata, JBT_REG_CKV_1_2, 0x0000);
293
294 r |= jbt_reg_write_2(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
295 r |= jbt_reg_write_2(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
296 r |= jbt_reg_write_1(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
297
298 r |= jbt_ret_write_0(ddata, JBT_REG_DISPLAY_ON);
299
300 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
301
302transfer_err:
303
304 return r ? -EIO : 0;
305}
306
307static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
308{
309 struct panel_drv_data *ddata = to_panel_data(dssdev);
310 struct omap_dss_device *in = ddata->in;
311
312 if (!omapdss_device_is_enabled(dssdev))
313 return;
314
315 dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
316
317 jbt_ret_write_0(ddata, JBT_REG_DISPLAY_OFF);
318 jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
319 jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
320 jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
321
322 in->ops.dpi->disable(in);
323
324 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
325}
326
327static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
328 struct omap_video_timings *timings)
329{
330 struct panel_drv_data *ddata = to_panel_data(dssdev);
331 struct omap_dss_device *in = ddata->in;
332
333 ddata->videomode = *timings;
334 dssdev->panel.timings = *timings;
335
336 in->ops.dpi->set_timings(in, timings);
337}
338
339static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
340 struct omap_video_timings *timings)
341{
342 struct panel_drv_data *ddata = to_panel_data(dssdev);
343
344 *timings = ddata->videomode;
345}
346
347static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
348 struct omap_video_timings *timings)
349{
350 struct panel_drv_data *ddata = to_panel_data(dssdev);
351 struct omap_dss_device *in = ddata->in;
352
353 return in->ops.dpi->check_timings(in, timings);
354}
355
356static struct omap_dss_driver td028ttec1_ops = {
357 .connect = td028ttec1_panel_connect,
358 .disconnect = td028ttec1_panel_disconnect,
359
360 .enable = td028ttec1_panel_enable,
361 .disable = td028ttec1_panel_disable,
362
363 .set_timings = td028ttec1_panel_set_timings,
364 .get_timings = td028ttec1_panel_get_timings,
365 .check_timings = td028ttec1_panel_check_timings,
366};
367
368static int td028ttec1_panel_probe_pdata(struct spi_device *spi)
369{
370 const struct panel_tpo_td028ttec1_platform_data *pdata;
371 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
372 struct omap_dss_device *dssdev, *in;
373
374 pdata = dev_get_platdata(&spi->dev);
375
376 in = omap_dss_find_output(pdata->source);
377 if (in == NULL) {
378 dev_err(&spi->dev, "failed to find video source '%s'\n",
379 pdata->source);
380 return -EPROBE_DEFER;
381 }
382
383 ddata->in = in;
384
385 ddata->data_lines = pdata->data_lines;
386
387 dssdev = &ddata->dssdev;
388 dssdev->name = pdata->name;
389
390 return 0;
391}
392
393static int td028ttec1_probe_of(struct spi_device *spi)
394{
395 struct device_node *node = spi->dev.of_node;
396 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
397 struct omap_dss_device *in;
398
399 in = omapdss_of_find_source_for_first_ep(node);
400 if (IS_ERR(in)) {
401 dev_err(&spi->dev, "failed to find video source\n");
402 return PTR_ERR(in);
403 }
404
405 ddata->in = in;
406
407 return 0;
408}
409
410static int td028ttec1_panel_probe(struct spi_device *spi)
411{
412 struct panel_drv_data *ddata;
413 struct omap_dss_device *dssdev;
414 int r;
415
416 dev_dbg(&spi->dev, "%s\n", __func__);
417
418 spi->bits_per_word = 9;
419 spi->mode = SPI_MODE_3;
420
421 r = spi_setup(spi);
422 if (r < 0) {
423 dev_err(&spi->dev, "spi_setup failed: %d\n", r);
424 return r;
425 }
426
427 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
428 if (ddata == NULL)
429 return -ENOMEM;
430
431 dev_set_drvdata(&spi->dev, ddata);
432
433 ddata->spi_dev = spi;
434
435 if (dev_get_platdata(&spi->dev)) {
436 r = td028ttec1_panel_probe_pdata(spi);
437 if (r)
438 return r;
439 } else if (spi->dev.of_node) {
440 r = td028ttec1_probe_of(spi);
441 if (r)
442 return r;
443 } else {
444 return -ENODEV;
445 }
446
447 ddata->videomode = td028ttec1_panel_timings;
448
449 dssdev = &ddata->dssdev;
450 dssdev->dev = &spi->dev;
451 dssdev->driver = &td028ttec1_ops;
452 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
453 dssdev->owner = THIS_MODULE;
454 dssdev->panel.timings = ddata->videomode;
455 dssdev->phy.dpi.data_lines = ddata->data_lines;
456
457 r = omapdss_register_display(dssdev);
458 if (r) {
459 dev_err(&spi->dev, "Failed to register panel\n");
460 goto err_reg;
461 }
462
463 return 0;
464
465err_reg:
466 omap_dss_put_device(ddata->in);
467 return r;
468}
469
470static int td028ttec1_panel_remove(struct spi_device *spi)
471{
472 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
473 struct omap_dss_device *dssdev = &ddata->dssdev;
474 struct omap_dss_device *in = ddata->in;
475
476 dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
477
478 omapdss_unregister_display(dssdev);
479
480 td028ttec1_panel_disable(dssdev);
481 td028ttec1_panel_disconnect(dssdev);
482
483 omap_dss_put_device(in);
484
485 return 0;
486}
487
488static const struct of_device_id td028ttec1_of_match[] = {
489 { .compatible = "omapdss,toppoly,td028ttec1", },
490 {},
491};
492
493MODULE_DEVICE_TABLE(of, td028ttec1_of_match);
494
495static struct spi_driver td028ttec1_spi_driver = {
496 .probe = td028ttec1_panel_probe,
497 .remove = td028ttec1_panel_remove,
498
499 .driver = {
500 .name = "panel-tpo-td028ttec1",
501 .of_match_table = td028ttec1_of_match,
502 .suppress_bind_attrs = true,
503 },
504};
505
506module_spi_driver(td028ttec1_spi_driver);
507
508MODULE_ALIAS("spi:toppoly,td028ttec1");
509MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
510MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver");
511MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 000000000000..68e3b68a2920
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,686 @@
1/*
2 * TPO TD043MTEA1 Panel driver
3 *
4 * Author: Gražvydas Ignotas <notasas@gmail.com>
5 * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/delay.h>
15#include <linux/spi/spi.h>
16#include <linux/regulator/consumer.h>
17#include <linux/gpio.h>
18#include <linux/err.h>
19#include <linux/slab.h>
20#include <linux/of_gpio.h>
21
22#include <video/omapdss.h>
23#include <video/omap-panel-data.h>
24
25#define TPO_R02_MODE(x) ((x) & 7)
26#define TPO_R02_MODE_800x480 7
27#define TPO_R02_NCLK_RISING BIT(3)
28#define TPO_R02_HSYNC_HIGH BIT(4)
29#define TPO_R02_VSYNC_HIGH BIT(5)
30
31#define TPO_R03_NSTANDBY BIT(0)
32#define TPO_R03_EN_CP_CLK BIT(1)
33#define TPO_R03_EN_VGL_PUMP BIT(2)
34#define TPO_R03_EN_PWM BIT(3)
35#define TPO_R03_DRIVING_CAP_100 BIT(4)
36#define TPO_R03_EN_PRE_CHARGE BIT(6)
37#define TPO_R03_SOFTWARE_CTL BIT(7)
38
39#define TPO_R04_NFLIP_H BIT(0)
40#define TPO_R04_NFLIP_V BIT(1)
41#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
42#define TPO_R04_VGL_FREQ_1H BIT(4)
43
44#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
45 TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
46 TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
47 TPO_R03_SOFTWARE_CTL)
48
49#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
50 TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
51
52static const u16 tpo_td043_def_gamma[12] = {
53 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
54};
55
56struct panel_drv_data {
57 struct omap_dss_device dssdev;
58 struct omap_dss_device *in;
59
60 struct omap_video_timings videomode;
61
62 int data_lines;
63
64 struct spi_device *spi;
65 struct regulator *vcc_reg;
66 int nreset_gpio;
67 u16 gamma[12];
68 u32 mode;
69 u32 hmirror:1;
70 u32 vmirror:1;
71 u32 powered_on:1;
72 u32 spi_suspended:1;
73 u32 power_on_resume:1;
74};
75
76static const struct omap_video_timings tpo_td043_timings = {
77 .x_res = 800,
78 .y_res = 480,
79
80 .pixelclock = 36000000,
81
82 .hsw = 1,
83 .hfp = 68,
84 .hbp = 214,
85
86 .vsw = 1,
87 .vfp = 39,
88 .vbp = 34,
89
90 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
91 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
92 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
93 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
94 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
95};
96
97#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
98
99static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
100{
101 struct spi_message m;
102 struct spi_transfer xfer;
103 u16 w;
104 int r;
105
106 spi_message_init(&m);
107
108 memset(&xfer, 0, sizeof(xfer));
109
110 w = ((u16)addr << 10) | (1 << 8) | data;
111 xfer.tx_buf = &w;
112 xfer.bits_per_word = 16;
113 xfer.len = 2;
114 spi_message_add_tail(&xfer, &m);
115
116 r = spi_sync(spi, &m);
117 if (r < 0)
118 dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
119 return r;
120}
121
122static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
123{
124 u8 i, val;
125
126 /* gamma bits [9:8] */
127 for (val = i = 0; i < 4; i++)
128 val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
129 tpo_td043_write(spi, 0x11, val);
130
131 for (val = i = 0; i < 4; i++)
132 val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
133 tpo_td043_write(spi, 0x12, val);
134
135 for (val = i = 0; i < 4; i++)
136 val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
137 tpo_td043_write(spi, 0x13, val);
138
139 /* gamma bits [7:0] */
140 for (val = i = 0; i < 12; i++)
141 tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
142}
143
144static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
145{
146 u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |
147 TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
148 if (h)
149 reg4 &= ~TPO_R04_NFLIP_H;
150 if (v)
151 reg4 &= ~TPO_R04_NFLIP_V;
152
153 return tpo_td043_write(spi, 4, reg4);
154}
155
156static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
157{
158 struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
159
160 ddata->hmirror = enable;
161 return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
162 ddata->vmirror);
163}
164
165static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
166{
167 struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
168
169 return ddata->hmirror;
170}
171
172static ssize_t tpo_td043_vmirror_show(struct device *dev,
173 struct device_attribute *attr, char *buf)
174{
175 struct panel_drv_data *ddata = dev_get_drvdata(dev);
176
177 return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror);
178}
179
180static ssize_t tpo_td043_vmirror_store(struct device *dev,
181 struct device_attribute *attr, const char *buf, size_t count)
182{
183 struct panel_drv_data *ddata = dev_get_drvdata(dev);
184 int val;
185 int ret;
186
187 ret = kstrtoint(buf, 0, &val);
188 if (ret < 0)
189 return ret;
190
191 val = !!val;
192
193 ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
194 if (ret < 0)
195 return ret;
196
197 ddata->vmirror = val;
198
199 return count;
200}
201
202static ssize_t tpo_td043_mode_show(struct device *dev,
203 struct device_attribute *attr, char *buf)
204{
205 struct panel_drv_data *ddata = dev_get_drvdata(dev);
206
207 return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode);
208}
209
210static ssize_t tpo_td043_mode_store(struct device *dev,
211 struct device_attribute *attr, const char *buf, size_t count)
212{
213 struct panel_drv_data *ddata = dev_get_drvdata(dev);
214 long val;
215 int ret;
216
217 ret = kstrtol(buf, 0, &val);
218 if (ret != 0 || val & ~7)
219 return -EINVAL;
220
221 ddata->mode = val;
222
223 val |= TPO_R02_NCLK_RISING;
224 tpo_td043_write(ddata->spi, 2, val);
225
226 return count;
227}
228
229static ssize_t tpo_td043_gamma_show(struct device *dev,
230 struct device_attribute *attr, char *buf)
231{
232 struct panel_drv_data *ddata = dev_get_drvdata(dev);
233 ssize_t len = 0;
234 int ret;
235 int i;
236
237 for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) {
238 ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
239 ddata->gamma[i]);
240 if (ret < 0)
241 return ret;
242 len += ret;
243 }
244 buf[len - 1] = '\n';
245
246 return len;
247}
248
249static ssize_t tpo_td043_gamma_store(struct device *dev,
250 struct device_attribute *attr, const char *buf, size_t count)
251{
252 struct panel_drv_data *ddata = dev_get_drvdata(dev);
253 unsigned int g[12];
254 int ret;
255 int i;
256
257 ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
258 &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
259 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
260
261 if (ret != 12)
262 return -EINVAL;
263
264 for (i = 0; i < 12; i++)
265 ddata->gamma[i] = g[i];
266
267 tpo_td043_write_gamma(ddata->spi, ddata->gamma);
268
269 return count;
270}
271
272static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
273 tpo_td043_vmirror_show, tpo_td043_vmirror_store);
274static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
275 tpo_td043_mode_show, tpo_td043_mode_store);
276static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
277 tpo_td043_gamma_show, tpo_td043_gamma_store);
278
279static struct attribute *tpo_td043_attrs[] = {
280 &dev_attr_vmirror.attr,
281 &dev_attr_mode.attr,
282 &dev_attr_gamma.attr,
283 NULL,
284};
285
286static struct attribute_group tpo_td043_attr_group = {
287 .attrs = tpo_td043_attrs,
288};
289
290static int tpo_td043_power_on(struct panel_drv_data *ddata)
291{
292 int r;
293
294 if (ddata->powered_on)
295 return 0;
296
297 r = regulator_enable(ddata->vcc_reg);
298 if (r != 0)
299 return r;
300
301 /* wait for panel to stabilize */
302 msleep(160);
303
304 if (gpio_is_valid(ddata->nreset_gpio))
305 gpio_set_value(ddata->nreset_gpio, 1);
306
307 tpo_td043_write(ddata->spi, 2,
308 TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
309 tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
310 tpo_td043_write(ddata->spi, 0x20, 0xf0);
311 tpo_td043_write(ddata->spi, 0x21, 0xf0);
312 tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
313 ddata->vmirror);
314 tpo_td043_write_gamma(ddata->spi, ddata->gamma);
315
316 ddata->powered_on = 1;
317 return 0;
318}
319
320static void tpo_td043_power_off(struct panel_drv_data *ddata)
321{
322 if (!ddata->powered_on)
323 return;
324
325 tpo_td043_write(ddata->spi, 3,
326 TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
327
328 if (gpio_is_valid(ddata->nreset_gpio))
329 gpio_set_value(ddata->nreset_gpio, 0);
330
331 /* wait for at least 2 vsyncs before cutting off power */
332 msleep(50);
333
334 tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY);
335
336 regulator_disable(ddata->vcc_reg);
337
338 ddata->powered_on = 0;
339}
340
341static int tpo_td043_connect(struct omap_dss_device *dssdev)
342{
343 struct panel_drv_data *ddata = to_panel_data(dssdev);
344 struct omap_dss_device *in = ddata->in;
345 int r;
346
347 if (omapdss_device_is_connected(dssdev))
348 return 0;
349
350 r = in->ops.dpi->connect(in, dssdev);
351 if (r)
352 return r;
353
354 return 0;
355}
356
357static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
358{
359 struct panel_drv_data *ddata = to_panel_data(dssdev);
360 struct omap_dss_device *in = ddata->in;
361
362 if (!omapdss_device_is_connected(dssdev))
363 return;
364
365 in->ops.dpi->disconnect(in, dssdev);
366}
367
368static int tpo_td043_enable(struct omap_dss_device *dssdev)
369{
370 struct panel_drv_data *ddata = to_panel_data(dssdev);
371 struct omap_dss_device *in = ddata->in;
372 int r;
373
374 if (!omapdss_device_is_connected(dssdev))
375 return -ENODEV;
376
377 if (omapdss_device_is_enabled(dssdev))
378 return 0;
379
380 if (ddata->data_lines)
381 in->ops.dpi->set_data_lines(in, ddata->data_lines);
382 in->ops.dpi->set_timings(in, &ddata->videomode);
383
384 r = in->ops.dpi->enable(in);
385 if (r)
386 return r;
387
388 /*
389 * If we are resuming from system suspend, SPI clocks might not be
390 * enabled yet, so we'll program the LCD from SPI PM resume callback.
391 */
392 if (!ddata->spi_suspended) {
393 r = tpo_td043_power_on(ddata);
394 if (r) {
395 in->ops.dpi->disable(in);
396 return r;
397 }
398 }
399
400 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
401
402 return 0;
403}
404
405static void tpo_td043_disable(struct omap_dss_device *dssdev)
406{
407 struct panel_drv_data *ddata = to_panel_data(dssdev);
408 struct omap_dss_device *in = ddata->in;
409
410 if (!omapdss_device_is_enabled(dssdev))
411 return;
412
413 in->ops.dpi->disable(in);
414
415 if (!ddata->spi_suspended)
416 tpo_td043_power_off(ddata);
417
418 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
419}
420
421static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
422 struct omap_video_timings *timings)
423{
424 struct panel_drv_data *ddata = to_panel_data(dssdev);
425 struct omap_dss_device *in = ddata->in;
426
427 ddata->videomode = *timings;
428 dssdev->panel.timings = *timings;
429
430 in->ops.dpi->set_timings(in, timings);
431}
432
433static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
434 struct omap_video_timings *timings)
435{
436 struct panel_drv_data *ddata = to_panel_data(dssdev);
437
438 *timings = ddata->videomode;
439}
440
441static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
442 struct omap_video_timings *timings)
443{
444 struct panel_drv_data *ddata = to_panel_data(dssdev);
445 struct omap_dss_device *in = ddata->in;
446
447 return in->ops.dpi->check_timings(in, timings);
448}
449
450static struct omap_dss_driver tpo_td043_ops = {
451 .connect = tpo_td043_connect,
452 .disconnect = tpo_td043_disconnect,
453
454 .enable = tpo_td043_enable,
455 .disable = tpo_td043_disable,
456
457 .set_timings = tpo_td043_set_timings,
458 .get_timings = tpo_td043_get_timings,
459 .check_timings = tpo_td043_check_timings,
460
461 .set_mirror = tpo_td043_set_hmirror,
462 .get_mirror = tpo_td043_get_hmirror,
463
464 .get_resolution = omapdss_default_get_resolution,
465};
466
467
468static int tpo_td043_probe_pdata(struct spi_device *spi)
469{
470 const struct panel_tpo_td043mtea1_platform_data *pdata;
471 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
472 struct omap_dss_device *dssdev, *in;
473
474 pdata = dev_get_platdata(&spi->dev);
475
476 ddata->nreset_gpio = pdata->nreset_gpio;
477
478 in = omap_dss_find_output(pdata->source);
479 if (in == NULL) {
480 dev_err(&spi->dev, "failed to find video source '%s'\n",
481 pdata->source);
482 return -EPROBE_DEFER;
483 }
484 ddata->in = in;
485
486 ddata->data_lines = pdata->data_lines;
487
488 dssdev = &ddata->dssdev;
489 dssdev->name = pdata->name;
490
491 return 0;
492}
493
494static int tpo_td043_probe_of(struct spi_device *spi)
495{
496 struct device_node *node = spi->dev.of_node;
497 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
498 struct omap_dss_device *in;
499 int gpio;
500
501 gpio = of_get_named_gpio(node, "reset-gpios", 0);
502 if (!gpio_is_valid(gpio)) {
503 dev_err(&spi->dev, "failed to parse enable gpio\n");
504 return gpio;
505 }
506 ddata->nreset_gpio = gpio;
507
508 in = omapdss_of_find_source_for_first_ep(node);
509 if (IS_ERR(in)) {
510 dev_err(&spi->dev, "failed to find video source\n");
511 return PTR_ERR(in);
512 }
513
514 ddata->in = in;
515
516 return 0;
517}
518
519static int tpo_td043_probe(struct spi_device *spi)
520{
521 struct panel_drv_data *ddata;
522 struct omap_dss_device *dssdev;
523 int r;
524
525 dev_dbg(&spi->dev, "%s\n", __func__);
526
527 spi->bits_per_word = 16;
528 spi->mode = SPI_MODE_0;
529
530 r = spi_setup(spi);
531 if (r < 0) {
532 dev_err(&spi->dev, "spi_setup failed: %d\n", r);
533 return r;
534 }
535
536 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
537 if (ddata == NULL)
538 return -ENOMEM;
539
540 dev_set_drvdata(&spi->dev, ddata);
541
542 ddata->spi = spi;
543
544 if (dev_get_platdata(&spi->dev)) {
545 r = tpo_td043_probe_pdata(spi);
546 if (r)
547 return r;
548 } else if (spi->dev.of_node) {
549 r = tpo_td043_probe_of(spi);
550 if (r)
551 return r;
552 } else {
553 return -ENODEV;
554 }
555
556 ddata->mode = TPO_R02_MODE_800x480;
557 memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
558
559 ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
560 if (IS_ERR(ddata->vcc_reg)) {
561 dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
562 r = PTR_ERR(ddata->vcc_reg);
563 goto err_regulator;
564 }
565
566 if (gpio_is_valid(ddata->nreset_gpio)) {
567 r = devm_gpio_request_one(&spi->dev,
568 ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
569 "lcd reset");
570 if (r < 0) {
571 dev_err(&spi->dev, "couldn't request reset GPIO\n");
572 goto err_gpio_req;
573 }
574 }
575
576 r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
577 if (r) {
578 dev_err(&spi->dev, "failed to create sysfs files\n");
579 goto err_sysfs;
580 }
581
582 ddata->videomode = tpo_td043_timings;
583
584 dssdev = &ddata->dssdev;
585 dssdev->dev = &spi->dev;
586 dssdev->driver = &tpo_td043_ops;
587 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
588 dssdev->owner = THIS_MODULE;
589 dssdev->panel.timings = ddata->videomode;
590
591 r = omapdss_register_display(dssdev);
592 if (r) {
593 dev_err(&spi->dev, "Failed to register panel\n");
594 goto err_reg;
595 }
596
597 return 0;
598
599err_reg:
600 sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
601err_sysfs:
602err_gpio_req:
603err_regulator:
604 omap_dss_put_device(ddata->in);
605 return r;
606}
607
608static int tpo_td043_remove(struct spi_device *spi)
609{
610 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
611 struct omap_dss_device *dssdev = &ddata->dssdev;
612 struct omap_dss_device *in = ddata->in;
613
614 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
615
616 omapdss_unregister_display(dssdev);
617
618 tpo_td043_disable(dssdev);
619 tpo_td043_disconnect(dssdev);
620
621 omap_dss_put_device(in);
622
623 sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
624
625 return 0;
626}
627
628#ifdef CONFIG_PM_SLEEP
629static int tpo_td043_spi_suspend(struct device *dev)
630{
631 struct panel_drv_data *ddata = dev_get_drvdata(dev);
632
633 dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata);
634
635 ddata->power_on_resume = ddata->powered_on;
636 tpo_td043_power_off(ddata);
637 ddata->spi_suspended = 1;
638
639 return 0;
640}
641
642static int tpo_td043_spi_resume(struct device *dev)
643{
644 struct panel_drv_data *ddata = dev_get_drvdata(dev);
645 int ret;
646
647 dev_dbg(dev, "tpo_td043_spi_resume\n");
648
649 if (ddata->power_on_resume) {
650 ret = tpo_td043_power_on(ddata);
651 if (ret)
652 return ret;
653 }
654 ddata->spi_suspended = 0;
655
656 return 0;
657}
658#endif
659
660static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
661 tpo_td043_spi_suspend, tpo_td043_spi_resume);
662
663static const struct of_device_id tpo_td043_of_match[] = {
664 { .compatible = "omapdss,tpo,td043mtea1", },
665 {},
666};
667
668MODULE_DEVICE_TABLE(of, tpo_td043_of_match);
669
670static struct spi_driver tpo_td043_spi_driver = {
671 .driver = {
672 .name = "panel-tpo-td043mtea1",
673 .pm = &tpo_td043_spi_pm,
674 .of_match_table = tpo_td043_of_match,
675 .suppress_bind_attrs = true,
676 },
677 .probe = tpo_td043_probe,
678 .remove = tpo_td043_remove,
679};
680
681module_spi_driver(tpo_td043_spi_driver);
682
683MODULE_ALIAS("spi:tpo,td043mtea1");
684MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
685MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
686MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/dss/Kconfig b/drivers/gpu/drm/omapdrm/dss/Kconfig
new file mode 100644
index 000000000000..d1fa730c7d54
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/Kconfig
@@ -0,0 +1,135 @@
1config OMAP2_DSS_INIT
2 bool
3
4menuconfig OMAP2_DSS
5 tristate "OMAP2+ Display Subsystem support"
6 select VIDEOMODE_HELPERS
7 select OMAP2_DSS_INIT
8 select HDMI
9 help
10 OMAP2+ Display Subsystem support.
11
12if OMAP2_DSS
13
14config OMAP2_DSS_DEBUG
15 bool "Debug support"
16 default n
17 help
18 This enables printing of debug messages. Alternatively, debug messages
19 can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
20 appropriate flags in <debugfs>/dynamic_debug/control.
21
22config OMAP2_DSS_DEBUGFS
23 bool "Debugfs filesystem support"
24 depends on DEBUG_FS
25 default n
26 help
27 This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
28 querying about clock configuration and register configuration of dss,
29 dispc, dsi, hdmi and rfbi.
30
31config OMAP2_DSS_COLLECT_IRQ_STATS
32 bool "Collect DSS IRQ statistics"
33 depends on OMAP2_DSS_DEBUGFS
34 default n
35 help
36 Collect DSS IRQ statistics, printable via debugfs.
37
38 The statistics can be found from
39 <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
40 <debugfs>/omapdss/dsi_irq for DSI interrupts.
41
42config OMAP2_DSS_DPI
43 bool "DPI support"
44 default y
45 help
46 DPI Interface. This is the Parallel Display Interface.
47
48config OMAP2_DSS_RFBI
49 bool "RFBI support"
50 depends on BROKEN
51 default n
52 help
53 MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
54 Instrument's terminology).
55
56 DBI is a bus between the host processor and a peripheral,
57 such as a display or a framebuffer chip.
58
59 See http://www.mipi.org/ for DBI specifications.
60
61config OMAP2_DSS_VENC
62 bool "VENC support"
63 default y
64 help
65 OMAP Video Encoder support for S-Video and composite TV-out.
66
67config OMAP2_DSS_HDMI_COMMON
68 bool
69
70config OMAP4_DSS_HDMI
71 bool "HDMI support for OMAP4"
72 default y
73 select OMAP2_DSS_HDMI_COMMON
74 help
75 HDMI support for OMAP4 based SoCs.
76
77config OMAP5_DSS_HDMI
78 bool "HDMI support for OMAP5"
79 default n
80 select OMAP2_DSS_HDMI_COMMON
81 help
82 HDMI Interface for OMAP5 and similar cores. This adds the High
83 Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
84 specification.
85
86config OMAP2_DSS_SDI
87 bool "SDI support"
88 default n
89 help
90 SDI (Serial Display Interface) support.
91
92 SDI is a high speed one-way display serial bus between the host
93 processor and a display.
94
95config OMAP2_DSS_DSI
96 bool "DSI support"
97 default n
98 help
99 MIPI DSI (Display Serial Interface) support.
100
101 DSI is a high speed half-duplex serial interface between the host
102 processor and a peripheral, such as a display or a framebuffer chip.
103
104 See http://www.mipi.org/ for DSI specifications.
105
106config OMAP2_DSS_MIN_FCK_PER_PCK
107 int "Minimum FCK/PCK ratio (for scaling)"
108 range 0 32
109 default 0
110 help
111 This can be used to adjust the minimum FCK/PCK ratio.
112
113 With this you can make sure that DISPC FCK is at least
114 n x PCK. Video plane scaling requires higher FCK than
115 normally.
116
117 If this is set to 0, there's no extra constraint on the
118 DISPC FCK. However, the FCK will at minimum be
119 2xPCK (if active matrix) or 3xPCK (if passive matrix).
120
121 Max FCK is 173MHz, so this doesn't work if your PCK
122 is very high.
123
124config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
125 bool "Sleep 20ms after VENC reset"
126 default y
127 help
128 There is a 20ms sleep after VENC reset which seemed to fix the
129 reset. The reason for the bug is unclear, and it's also unclear
130 on what platforms this happens.
131
132 This option enables the sleep, and is enabled by default. You can
133 disable the sleep if it doesn't cause problems on your platform.
134
135endif
diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile
new file mode 100644
index 000000000000..b5136d3d4b77
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/Makefile
@@ -0,0 +1,18 @@
1obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
2obj-$(CONFIG_OMAP2_DSS) += omapdss.o
3# Core DSS files
4omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
5 output.o dss-of.o pll.o video-pll.o
6# DSS compat layer files
7omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
8 dispc-compat.o display-sysfs.o
9omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
10omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
11omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
12omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
13omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
14omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \
15 hdmi_phy.o
16omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
17omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
18ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
diff --git a/drivers/gpu/drm/omapdrm/dss/apply.c b/drivers/gpu/drm/omapdrm/dss/apply.c
new file mode 100644
index 000000000000..663ccc3bf4e5
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/apply.c
@@ -0,0 +1,1702 @@
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/module.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/jiffies.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30#include "dispc-compat.h"
31
32/*
33 * We have 4 levels of cache for the dispc settings. First two are in SW and
34 * the latter two in HW.
35 *
36 * set_info()
37 * v
38 * +--------------------+
39 * | user_info |
40 * +--------------------+
41 * v
42 * apply()
43 * v
44 * +--------------------+
45 * | info |
46 * +--------------------+
47 * v
48 * write_regs()
49 * v
50 * +--------------------+
51 * | shadow registers |
52 * +--------------------+
53 * v
54 * VFP or lcd/digit_enable
55 * v
56 * +--------------------+
57 * | registers |
58 * +--------------------+
59 */
60
61struct ovl_priv_data {
62
63 bool user_info_dirty;
64 struct omap_overlay_info user_info;
65
66 bool info_dirty;
67 struct omap_overlay_info info;
68
69 bool shadow_info_dirty;
70
71 bool extra_info_dirty;
72 bool shadow_extra_info_dirty;
73
74 bool enabled;
75 u32 fifo_low, fifo_high;
76
77 /*
78 * True if overlay is to be enabled. Used to check and calculate configs
79 * for the overlay before it is enabled in the HW.
80 */
81 bool enabling;
82};
83
84struct mgr_priv_data {
85
86 bool user_info_dirty;
87 struct omap_overlay_manager_info user_info;
88
89 bool info_dirty;
90 struct omap_overlay_manager_info info;
91
92 bool shadow_info_dirty;
93
94 /* If true, GO bit is up and shadow registers cannot be written.
95 * Never true for manual update displays */
96 bool busy;
97
98 /* If true, dispc output is enabled */
99 bool updating;
100
101 /* If true, a display is enabled using this manager */
102 bool enabled;
103
104 bool extra_info_dirty;
105 bool shadow_extra_info_dirty;
106
107 struct omap_video_timings timings;
108 struct dss_lcd_mgr_config lcd_config;
109
110 void (*framedone_handler)(void *);
111 void *framedone_handler_data;
112};
113
114static struct {
115 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
116 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
117
118 bool irq_enabled;
119} dss_data;
120
121/* protects dss_data */
122static spinlock_t data_lock;
123/* lock for blocking functions */
124static DEFINE_MUTEX(apply_lock);
125static DECLARE_COMPLETION(extra_updated_completion);
126
127static void dss_register_vsync_isr(void);
128
129static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
130{
131 return &dss_data.ovl_priv_data_array[ovl->id];
132}
133
134static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
135{
136 return &dss_data.mgr_priv_data_array[mgr->id];
137}
138
139static void apply_init_priv(void)
140{
141 const int num_ovls = dss_feat_get_num_ovls();
142 struct mgr_priv_data *mp;
143 int i;
144
145 spin_lock_init(&data_lock);
146
147 for (i = 0; i < num_ovls; ++i) {
148 struct ovl_priv_data *op;
149
150 op = &dss_data.ovl_priv_data_array[i];
151
152 op->info.color_mode = OMAP_DSS_COLOR_RGB16;
153 op->info.rotation_type = OMAP_DSS_ROT_DMA;
154
155 op->info.global_alpha = 255;
156
157 switch (i) {
158 case 0:
159 op->info.zorder = 0;
160 break;
161 case 1:
162 op->info.zorder =
163 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
164 break;
165 case 2:
166 op->info.zorder =
167 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
168 break;
169 case 3:
170 op->info.zorder =
171 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
172 break;
173 }
174
175 op->user_info = op->info;
176 }
177
178 /*
179 * Initialize some of the lcd_config fields for TV manager, this lets
180 * us prevent checking if the manager is LCD or TV at some places
181 */
182 mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
183
184 mp->lcd_config.video_port_width = 24;
185 mp->lcd_config.clock_info.lck_div = 1;
186 mp->lcd_config.clock_info.pck_div = 1;
187}
188
189/*
190 * A LCD manager's stallmode decides whether it is in manual or auto update. TV
191 * manager is always auto update, stallmode field for TV manager is false by
192 * default
193 */
194static bool ovl_manual_update(struct omap_overlay *ovl)
195{
196 struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
197
198 return mp->lcd_config.stallmode;
199}
200
201static bool mgr_manual_update(struct omap_overlay_manager *mgr)
202{
203 struct mgr_priv_data *mp = get_mgr_priv(mgr);
204
205 return mp->lcd_config.stallmode;
206}
207
208static int dss_check_settings_low(struct omap_overlay_manager *mgr,
209 bool applying)
210{
211 struct omap_overlay_info *oi;
212 struct omap_overlay_manager_info *mi;
213 struct omap_overlay *ovl;
214 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
215 struct ovl_priv_data *op;
216 struct mgr_priv_data *mp;
217
218 mp = get_mgr_priv(mgr);
219
220 if (!mp->enabled)
221 return 0;
222
223 if (applying && mp->user_info_dirty)
224 mi = &mp->user_info;
225 else
226 mi = &mp->info;
227
228 /* collect the infos to be tested into the array */
229 list_for_each_entry(ovl, &mgr->overlays, list) {
230 op = get_ovl_priv(ovl);
231
232 if (!op->enabled && !op->enabling)
233 oi = NULL;
234 else if (applying && op->user_info_dirty)
235 oi = &op->user_info;
236 else
237 oi = &op->info;
238
239 ois[ovl->id] = oi;
240 }
241
242 return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
243}
244
245/*
246 * check manager and overlay settings using overlay_info from data->info
247 */
248static int dss_check_settings(struct omap_overlay_manager *mgr)
249{
250 return dss_check_settings_low(mgr, false);
251}
252
253/*
254 * check manager and overlay settings using overlay_info from ovl->info if
255 * dirty and from data->info otherwise
256 */
257static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
258{
259 return dss_check_settings_low(mgr, true);
260}
261
262static bool need_isr(void)
263{
264 const int num_mgrs = dss_feat_get_num_mgrs();
265 int i;
266
267 for (i = 0; i < num_mgrs; ++i) {
268 struct omap_overlay_manager *mgr;
269 struct mgr_priv_data *mp;
270 struct omap_overlay *ovl;
271
272 mgr = omap_dss_get_overlay_manager(i);
273 mp = get_mgr_priv(mgr);
274
275 if (!mp->enabled)
276 continue;
277
278 if (mgr_manual_update(mgr)) {
279 /* to catch FRAMEDONE */
280 if (mp->updating)
281 return true;
282 } else {
283 /* to catch GO bit going down */
284 if (mp->busy)
285 return true;
286
287 /* to write new values to registers */
288 if (mp->info_dirty)
289 return true;
290
291 /* to set GO bit */
292 if (mp->shadow_info_dirty)
293 return true;
294
295 /*
296 * NOTE: we don't check extra_info flags for disabled
297 * managers, once the manager is enabled, the extra_info
298 * related manager changes will be taken in by HW.
299 */
300
301 /* to write new values to registers */
302 if (mp->extra_info_dirty)
303 return true;
304
305 /* to set GO bit */
306 if (mp->shadow_extra_info_dirty)
307 return true;
308
309 list_for_each_entry(ovl, &mgr->overlays, list) {
310 struct ovl_priv_data *op;
311
312 op = get_ovl_priv(ovl);
313
314 /*
315 * NOTE: we check extra_info flags even for
316 * disabled overlays, as extra_infos need to be
317 * always written.
318 */
319
320 /* to write new values to registers */
321 if (op->extra_info_dirty)
322 return true;
323
324 /* to set GO bit */
325 if (op->shadow_extra_info_dirty)
326 return true;
327
328 if (!op->enabled)
329 continue;
330
331 /* to write new values to registers */
332 if (op->info_dirty)
333 return true;
334
335 /* to set GO bit */
336 if (op->shadow_info_dirty)
337 return true;
338 }
339 }
340 }
341
342 return false;
343}
344
345static bool need_go(struct omap_overlay_manager *mgr)
346{
347 struct omap_overlay *ovl;
348 struct mgr_priv_data *mp;
349 struct ovl_priv_data *op;
350
351 mp = get_mgr_priv(mgr);
352
353 if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
354 return true;
355
356 list_for_each_entry(ovl, &mgr->overlays, list) {
357 op = get_ovl_priv(ovl);
358 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
359 return true;
360 }
361
362 return false;
363}
364
365/* returns true if an extra_info field is currently being updated */
366static bool extra_info_update_ongoing(void)
367{
368 const int num_mgrs = dss_feat_get_num_mgrs();
369 int i;
370
371 for (i = 0; i < num_mgrs; ++i) {
372 struct omap_overlay_manager *mgr;
373 struct omap_overlay *ovl;
374 struct mgr_priv_data *mp;
375
376 mgr = omap_dss_get_overlay_manager(i);
377 mp = get_mgr_priv(mgr);
378
379 if (!mp->enabled)
380 continue;
381
382 if (!mp->updating)
383 continue;
384
385 if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
386 return true;
387
388 list_for_each_entry(ovl, &mgr->overlays, list) {
389 struct ovl_priv_data *op = get_ovl_priv(ovl);
390
391 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
392 return true;
393 }
394 }
395
396 return false;
397}
398
399/* wait until no extra_info updates are pending */
400static void wait_pending_extra_info_updates(void)
401{
402 bool updating;
403 unsigned long flags;
404 unsigned long t;
405 int r;
406
407 spin_lock_irqsave(&data_lock, flags);
408
409 updating = extra_info_update_ongoing();
410
411 if (!updating) {
412 spin_unlock_irqrestore(&data_lock, flags);
413 return;
414 }
415
416 init_completion(&extra_updated_completion);
417
418 spin_unlock_irqrestore(&data_lock, flags);
419
420 t = msecs_to_jiffies(500);
421 r = wait_for_completion_timeout(&extra_updated_completion, t);
422 if (r == 0)
423 DSSWARN("timeout in wait_pending_extra_info_updates\n");
424}
425
426static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
427{
428 struct omap_dss_device *dssdev;
429
430 dssdev = mgr->output;
431 if (dssdev == NULL)
432 return NULL;
433
434 while (dssdev->dst)
435 dssdev = dssdev->dst;
436
437 if (dssdev->driver)
438 return dssdev;
439 else
440 return NULL;
441}
442
443static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
444{
445 return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
446}
447
448static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
449{
450 unsigned long timeout = msecs_to_jiffies(500);
451 u32 irq;
452 int r;
453
454 if (mgr->output == NULL)
455 return -ENODEV;
456
457 r = dispc_runtime_get();
458 if (r)
459 return r;
460
461 switch (mgr->output->id) {
462 case OMAP_DSS_OUTPUT_VENC:
463 irq = DISPC_IRQ_EVSYNC_ODD;
464 break;
465 case OMAP_DSS_OUTPUT_HDMI:
466 irq = DISPC_IRQ_EVSYNC_EVEN;
467 break;
468 default:
469 irq = dispc_mgr_get_vsync_irq(mgr->id);
470 break;
471 }
472
473 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
474
475 dispc_runtime_put();
476
477 return r;
478}
479
480static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
481{
482 unsigned long timeout = msecs_to_jiffies(500);
483 struct mgr_priv_data *mp = get_mgr_priv(mgr);
484 u32 irq;
485 unsigned long flags;
486 int r;
487 int i;
488
489 spin_lock_irqsave(&data_lock, flags);
490
491 if (mgr_manual_update(mgr)) {
492 spin_unlock_irqrestore(&data_lock, flags);
493 return 0;
494 }
495
496 if (!mp->enabled) {
497 spin_unlock_irqrestore(&data_lock, flags);
498 return 0;
499 }
500
501 spin_unlock_irqrestore(&data_lock, flags);
502
503 r = dispc_runtime_get();
504 if (r)
505 return r;
506
507 irq = dispc_mgr_get_vsync_irq(mgr->id);
508
509 i = 0;
510 while (1) {
511 bool shadow_dirty, dirty;
512
513 spin_lock_irqsave(&data_lock, flags);
514 dirty = mp->info_dirty;
515 shadow_dirty = mp->shadow_info_dirty;
516 spin_unlock_irqrestore(&data_lock, flags);
517
518 if (!dirty && !shadow_dirty) {
519 r = 0;
520 break;
521 }
522
523 /* 4 iterations is the worst case:
524 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
525 * 2 - first VSYNC, dirty = true
526 * 3 - dirty = false, shadow_dirty = true
527 * 4 - shadow_dirty = false */
528 if (i++ == 3) {
529 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
530 mgr->id);
531 r = 0;
532 break;
533 }
534
535 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
536 if (r == -ERESTARTSYS)
537 break;
538
539 if (r) {
540 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
541 break;
542 }
543 }
544
545 dispc_runtime_put();
546
547 return r;
548}
549
550static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
551{
552 unsigned long timeout = msecs_to_jiffies(500);
553 struct ovl_priv_data *op;
554 struct mgr_priv_data *mp;
555 u32 irq;
556 unsigned long flags;
557 int r;
558 int i;
559
560 if (!ovl->manager)
561 return 0;
562
563 mp = get_mgr_priv(ovl->manager);
564
565 spin_lock_irqsave(&data_lock, flags);
566
567 if (ovl_manual_update(ovl)) {
568 spin_unlock_irqrestore(&data_lock, flags);
569 return 0;
570 }
571
572 if (!mp->enabled) {
573 spin_unlock_irqrestore(&data_lock, flags);
574 return 0;
575 }
576
577 spin_unlock_irqrestore(&data_lock, flags);
578
579 r = dispc_runtime_get();
580 if (r)
581 return r;
582
583 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
584
585 op = get_ovl_priv(ovl);
586 i = 0;
587 while (1) {
588 bool shadow_dirty, dirty;
589
590 spin_lock_irqsave(&data_lock, flags);
591 dirty = op->info_dirty;
592 shadow_dirty = op->shadow_info_dirty;
593 spin_unlock_irqrestore(&data_lock, flags);
594
595 if (!dirty && !shadow_dirty) {
596 r = 0;
597 break;
598 }
599
600 /* 4 iterations is the worst case:
601 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
602 * 2 - first VSYNC, dirty = true
603 * 3 - dirty = false, shadow_dirty = true
604 * 4 - shadow_dirty = false */
605 if (i++ == 3) {
606 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
607 ovl->id);
608 r = 0;
609 break;
610 }
611
612 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
613 if (r == -ERESTARTSYS)
614 break;
615
616 if (r) {
617 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
618 break;
619 }
620 }
621
622 dispc_runtime_put();
623
624 return r;
625}
626
627static void dss_ovl_write_regs(struct omap_overlay *ovl)
628{
629 struct ovl_priv_data *op = get_ovl_priv(ovl);
630 struct omap_overlay_info *oi;
631 bool replication;
632 struct mgr_priv_data *mp;
633 int r;
634
635 DSSDBG("writing ovl %d regs\n", ovl->id);
636
637 if (!op->enabled || !op->info_dirty)
638 return;
639
640 oi = &op->info;
641
642 mp = get_mgr_priv(ovl->manager);
643
644 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
645
646 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
647 if (r) {
648 /*
649 * We can't do much here, as this function can be called from
650 * vsync interrupt.
651 */
652 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
653
654 /* This will leave fifo configurations in a nonoptimal state */
655 op->enabled = false;
656 dispc_ovl_enable(ovl->id, false);
657 return;
658 }
659
660 op->info_dirty = false;
661 if (mp->updating)
662 op->shadow_info_dirty = true;
663}
664
665static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
666{
667 struct ovl_priv_data *op = get_ovl_priv(ovl);
668 struct mgr_priv_data *mp;
669
670 DSSDBG("writing ovl %d regs extra\n", ovl->id);
671
672 if (!op->extra_info_dirty)
673 return;
674
675 /* note: write also when op->enabled == false, so that the ovl gets
676 * disabled */
677
678 dispc_ovl_enable(ovl->id, op->enabled);
679 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
680
681 mp = get_mgr_priv(ovl->manager);
682
683 op->extra_info_dirty = false;
684 if (mp->updating)
685 op->shadow_extra_info_dirty = true;
686}
687
688static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
689{
690 struct mgr_priv_data *mp = get_mgr_priv(mgr);
691 struct omap_overlay *ovl;
692
693 DSSDBG("writing mgr %d regs\n", mgr->id);
694
695 if (!mp->enabled)
696 return;
697
698 WARN_ON(mp->busy);
699
700 /* Commit overlay settings */
701 list_for_each_entry(ovl, &mgr->overlays, list) {
702 dss_ovl_write_regs(ovl);
703 dss_ovl_write_regs_extra(ovl);
704 }
705
706 if (mp->info_dirty) {
707 dispc_mgr_setup(mgr->id, &mp->info);
708
709 mp->info_dirty = false;
710 if (mp->updating)
711 mp->shadow_info_dirty = true;
712 }
713}
714
715static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
716{
717 struct mgr_priv_data *mp = get_mgr_priv(mgr);
718
719 DSSDBG("writing mgr %d regs extra\n", mgr->id);
720
721 if (!mp->extra_info_dirty)
722 return;
723
724 dispc_mgr_set_timings(mgr->id, &mp->timings);
725
726 /* lcd_config parameters */
727 if (dss_mgr_is_lcd(mgr->id))
728 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
729
730 mp->extra_info_dirty = false;
731 if (mp->updating)
732 mp->shadow_extra_info_dirty = true;
733}
734
735static void dss_write_regs(void)
736{
737 const int num_mgrs = omap_dss_get_num_overlay_managers();
738 int i;
739
740 for (i = 0; i < num_mgrs; ++i) {
741 struct omap_overlay_manager *mgr;
742 struct mgr_priv_data *mp;
743 int r;
744
745 mgr = omap_dss_get_overlay_manager(i);
746 mp = get_mgr_priv(mgr);
747
748 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
749 continue;
750
751 r = dss_check_settings(mgr);
752 if (r) {
753 DSSERR("cannot write registers for manager %s: "
754 "illegal configuration\n", mgr->name);
755 continue;
756 }
757
758 dss_mgr_write_regs(mgr);
759 dss_mgr_write_regs_extra(mgr);
760 }
761}
762
763static void dss_set_go_bits(void)
764{
765 const int num_mgrs = omap_dss_get_num_overlay_managers();
766 int i;
767
768 for (i = 0; i < num_mgrs; ++i) {
769 struct omap_overlay_manager *mgr;
770 struct mgr_priv_data *mp;
771
772 mgr = omap_dss_get_overlay_manager(i);
773 mp = get_mgr_priv(mgr);
774
775 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
776 continue;
777
778 if (!need_go(mgr))
779 continue;
780
781 mp->busy = true;
782
783 if (!dss_data.irq_enabled && need_isr())
784 dss_register_vsync_isr();
785
786 dispc_mgr_go(mgr->id);
787 }
788
789}
790
791static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
792{
793 struct omap_overlay *ovl;
794 struct mgr_priv_data *mp;
795 struct ovl_priv_data *op;
796
797 mp = get_mgr_priv(mgr);
798 mp->shadow_info_dirty = false;
799 mp->shadow_extra_info_dirty = false;
800
801 list_for_each_entry(ovl, &mgr->overlays, list) {
802 op = get_ovl_priv(ovl);
803 op->shadow_info_dirty = false;
804 op->shadow_extra_info_dirty = false;
805 }
806}
807
808static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
809 struct omap_dss_device *dst)
810{
811 return mgr->set_output(mgr, dst);
812}
813
814static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
815 struct omap_dss_device *dst)
816{
817 mgr->unset_output(mgr);
818}
819
820static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
821{
822 struct mgr_priv_data *mp = get_mgr_priv(mgr);
823 unsigned long flags;
824 int r;
825
826 spin_lock_irqsave(&data_lock, flags);
827
828 WARN_ON(mp->updating);
829
830 r = dss_check_settings(mgr);
831 if (r) {
832 DSSERR("cannot start manual update: illegal configuration\n");
833 spin_unlock_irqrestore(&data_lock, flags);
834 return;
835 }
836
837 dss_mgr_write_regs(mgr);
838 dss_mgr_write_regs_extra(mgr);
839
840 mp->updating = true;
841
842 if (!dss_data.irq_enabled && need_isr())
843 dss_register_vsync_isr();
844
845 dispc_mgr_enable_sync(mgr->id);
846
847 spin_unlock_irqrestore(&data_lock, flags);
848}
849
850static void dss_apply_irq_handler(void *data, u32 mask);
851
852static void dss_register_vsync_isr(void)
853{
854 const int num_mgrs = dss_feat_get_num_mgrs();
855 u32 mask;
856 int r, i;
857
858 mask = 0;
859 for (i = 0; i < num_mgrs; ++i)
860 mask |= dispc_mgr_get_vsync_irq(i);
861
862 for (i = 0; i < num_mgrs; ++i)
863 mask |= dispc_mgr_get_framedone_irq(i);
864
865 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
866 WARN_ON(r);
867
868 dss_data.irq_enabled = true;
869}
870
871static void dss_unregister_vsync_isr(void)
872{
873 const int num_mgrs = dss_feat_get_num_mgrs();
874 u32 mask;
875 int r, i;
876
877 mask = 0;
878 for (i = 0; i < num_mgrs; ++i)
879 mask |= dispc_mgr_get_vsync_irq(i);
880
881 for (i = 0; i < num_mgrs; ++i)
882 mask |= dispc_mgr_get_framedone_irq(i);
883
884 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
885 WARN_ON(r);
886
887 dss_data.irq_enabled = false;
888}
889
890static void dss_apply_irq_handler(void *data, u32 mask)
891{
892 const int num_mgrs = dss_feat_get_num_mgrs();
893 int i;
894 bool extra_updating;
895
896 spin_lock(&data_lock);
897
898 /* clear busy, updating flags, shadow_dirty flags */
899 for (i = 0; i < num_mgrs; i++) {
900 struct omap_overlay_manager *mgr;
901 struct mgr_priv_data *mp;
902
903 mgr = omap_dss_get_overlay_manager(i);
904 mp = get_mgr_priv(mgr);
905
906 if (!mp->enabled)
907 continue;
908
909 mp->updating = dispc_mgr_is_enabled(i);
910
911 if (!mgr_manual_update(mgr)) {
912 bool was_busy = mp->busy;
913 mp->busy = dispc_mgr_go_busy(i);
914
915 if (was_busy && !mp->busy)
916 mgr_clear_shadow_dirty(mgr);
917 }
918 }
919
920 dss_write_regs();
921 dss_set_go_bits();
922
923 extra_updating = extra_info_update_ongoing();
924 if (!extra_updating)
925 complete_all(&extra_updated_completion);
926
927 /* call framedone handlers for manual update displays */
928 for (i = 0; i < num_mgrs; i++) {
929 struct omap_overlay_manager *mgr;
930 struct mgr_priv_data *mp;
931
932 mgr = omap_dss_get_overlay_manager(i);
933 mp = get_mgr_priv(mgr);
934
935 if (!mgr_manual_update(mgr) || !mp->framedone_handler)
936 continue;
937
938 if (mask & dispc_mgr_get_framedone_irq(i))
939 mp->framedone_handler(mp->framedone_handler_data);
940 }
941
942 if (!need_isr())
943 dss_unregister_vsync_isr();
944
945 spin_unlock(&data_lock);
946}
947
948static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
949{
950 struct ovl_priv_data *op;
951
952 op = get_ovl_priv(ovl);
953
954 if (!op->user_info_dirty)
955 return;
956
957 op->user_info_dirty = false;
958 op->info_dirty = true;
959 op->info = op->user_info;
960}
961
962static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
963{
964 struct mgr_priv_data *mp;
965
966 mp = get_mgr_priv(mgr);
967
968 if (!mp->user_info_dirty)
969 return;
970
971 mp->user_info_dirty = false;
972 mp->info_dirty = true;
973 mp->info = mp->user_info;
974}
975
976static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
977{
978 unsigned long flags;
979 struct omap_overlay *ovl;
980 int r;
981
982 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
983
984 spin_lock_irqsave(&data_lock, flags);
985
986 r = dss_check_settings_apply(mgr);
987 if (r) {
988 spin_unlock_irqrestore(&data_lock, flags);
989 DSSERR("failed to apply settings: illegal configuration.\n");
990 return r;
991 }
992
993 /* Configure overlays */
994 list_for_each_entry(ovl, &mgr->overlays, list)
995 omap_dss_mgr_apply_ovl(ovl);
996
997 /* Configure manager */
998 omap_dss_mgr_apply_mgr(mgr);
999
1000 dss_write_regs();
1001 dss_set_go_bits();
1002
1003 spin_unlock_irqrestore(&data_lock, flags);
1004
1005 return 0;
1006}
1007
1008static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
1009{
1010 struct ovl_priv_data *op;
1011
1012 op = get_ovl_priv(ovl);
1013
1014 if (op->enabled == enable)
1015 return;
1016
1017 op->enabled = enable;
1018 op->extra_info_dirty = true;
1019}
1020
1021static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
1022 u32 fifo_low, u32 fifo_high)
1023{
1024 struct ovl_priv_data *op = get_ovl_priv(ovl);
1025
1026 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
1027 return;
1028
1029 op->fifo_low = fifo_low;
1030 op->fifo_high = fifo_high;
1031 op->extra_info_dirty = true;
1032}
1033
1034static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
1035{
1036 struct ovl_priv_data *op = get_ovl_priv(ovl);
1037 u32 fifo_low, fifo_high;
1038 bool use_fifo_merge = false;
1039
1040 if (!op->enabled && !op->enabling)
1041 return;
1042
1043 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
1044 use_fifo_merge, ovl_manual_update(ovl));
1045
1046 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
1047}
1048
1049static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
1050{
1051 struct omap_overlay *ovl;
1052 struct mgr_priv_data *mp;
1053
1054 mp = get_mgr_priv(mgr);
1055
1056 if (!mp->enabled)
1057 return;
1058
1059 list_for_each_entry(ovl, &mgr->overlays, list)
1060 dss_ovl_setup_fifo(ovl);
1061}
1062
1063static void dss_setup_fifos(void)
1064{
1065 const int num_mgrs = omap_dss_get_num_overlay_managers();
1066 struct omap_overlay_manager *mgr;
1067 int i;
1068
1069 for (i = 0; i < num_mgrs; ++i) {
1070 mgr = omap_dss_get_overlay_manager(i);
1071 dss_mgr_setup_fifos(mgr);
1072 }
1073}
1074
1075static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
1076{
1077 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1078 unsigned long flags;
1079 int r;
1080
1081 mutex_lock(&apply_lock);
1082
1083 if (mp->enabled)
1084 goto out;
1085
1086 spin_lock_irqsave(&data_lock, flags);
1087
1088 mp->enabled = true;
1089
1090 r = dss_check_settings(mgr);
1091 if (r) {
1092 DSSERR("failed to enable manager %d: check_settings failed\n",
1093 mgr->id);
1094 goto err;
1095 }
1096
1097 dss_setup_fifos();
1098
1099 dss_write_regs();
1100 dss_set_go_bits();
1101
1102 if (!mgr_manual_update(mgr))
1103 mp->updating = true;
1104
1105 if (!dss_data.irq_enabled && need_isr())
1106 dss_register_vsync_isr();
1107
1108 spin_unlock_irqrestore(&data_lock, flags);
1109
1110 if (!mgr_manual_update(mgr))
1111 dispc_mgr_enable_sync(mgr->id);
1112
1113out:
1114 mutex_unlock(&apply_lock);
1115
1116 return 0;
1117
1118err:
1119 mp->enabled = false;
1120 spin_unlock_irqrestore(&data_lock, flags);
1121 mutex_unlock(&apply_lock);
1122 return r;
1123}
1124
1125static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
1126{
1127 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1128 unsigned long flags;
1129
1130 mutex_lock(&apply_lock);
1131
1132 if (!mp->enabled)
1133 goto out;
1134
1135 wait_pending_extra_info_updates();
1136
1137 if (!mgr_manual_update(mgr))
1138 dispc_mgr_disable_sync(mgr->id);
1139
1140 spin_lock_irqsave(&data_lock, flags);
1141
1142 mp->updating = false;
1143 mp->enabled = false;
1144
1145 spin_unlock_irqrestore(&data_lock, flags);
1146
1147out:
1148 mutex_unlock(&apply_lock);
1149}
1150
1151static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1152 struct omap_overlay_manager_info *info)
1153{
1154 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1155 unsigned long flags;
1156 int r;
1157
1158 r = dss_mgr_simple_check(mgr, info);
1159 if (r)
1160 return r;
1161
1162 spin_lock_irqsave(&data_lock, flags);
1163
1164 mp->user_info = *info;
1165 mp->user_info_dirty = true;
1166
1167 spin_unlock_irqrestore(&data_lock, flags);
1168
1169 return 0;
1170}
1171
1172static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1173 struct omap_overlay_manager_info *info)
1174{
1175 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1176 unsigned long flags;
1177
1178 spin_lock_irqsave(&data_lock, flags);
1179
1180 *info = mp->user_info;
1181
1182 spin_unlock_irqrestore(&data_lock, flags);
1183}
1184
1185static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
1186 struct omap_dss_device *output)
1187{
1188 int r;
1189
1190 mutex_lock(&apply_lock);
1191
1192 if (mgr->output) {
1193 DSSERR("manager %s is already connected to an output\n",
1194 mgr->name);
1195 r = -EINVAL;
1196 goto err;
1197 }
1198
1199 if ((mgr->supported_outputs & output->id) == 0) {
1200 DSSERR("output does not support manager %s\n",
1201 mgr->name);
1202 r = -EINVAL;
1203 goto err;
1204 }
1205
1206 output->manager = mgr;
1207 mgr->output = output;
1208
1209 mutex_unlock(&apply_lock);
1210
1211 return 0;
1212err:
1213 mutex_unlock(&apply_lock);
1214 return r;
1215}
1216
1217static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
1218{
1219 int r;
1220 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1221 unsigned long flags;
1222
1223 mutex_lock(&apply_lock);
1224
1225 if (!mgr->output) {
1226 DSSERR("failed to unset output, output not set\n");
1227 r = -EINVAL;
1228 goto err;
1229 }
1230
1231 spin_lock_irqsave(&data_lock, flags);
1232
1233 if (mp->enabled) {
1234 DSSERR("output can't be unset when manager is enabled\n");
1235 r = -EINVAL;
1236 goto err1;
1237 }
1238
1239 spin_unlock_irqrestore(&data_lock, flags);
1240
1241 mgr->output->manager = NULL;
1242 mgr->output = NULL;
1243
1244 mutex_unlock(&apply_lock);
1245
1246 return 0;
1247err1:
1248 spin_unlock_irqrestore(&data_lock, flags);
1249err:
1250 mutex_unlock(&apply_lock);
1251
1252 return r;
1253}
1254
1255static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
1256 const struct omap_video_timings *timings)
1257{
1258 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1259
1260 mp->timings = *timings;
1261 mp->extra_info_dirty = true;
1262}
1263
1264static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
1265 const struct omap_video_timings *timings)
1266{
1267 unsigned long flags;
1268 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1269
1270 spin_lock_irqsave(&data_lock, flags);
1271
1272 if (mp->updating) {
1273 DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1274 mgr->name);
1275 goto out;
1276 }
1277
1278 dss_apply_mgr_timings(mgr, timings);
1279out:
1280 spin_unlock_irqrestore(&data_lock, flags);
1281}
1282
1283static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1284 const struct dss_lcd_mgr_config *config)
1285{
1286 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1287
1288 mp->lcd_config = *config;
1289 mp->extra_info_dirty = true;
1290}
1291
1292static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
1293 const struct dss_lcd_mgr_config *config)
1294{
1295 unsigned long flags;
1296 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1297
1298 spin_lock_irqsave(&data_lock, flags);
1299
1300 if (mp->enabled) {
1301 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1302 mgr->name);
1303 goto out;
1304 }
1305
1306 dss_apply_mgr_lcd_config(mgr, config);
1307out:
1308 spin_unlock_irqrestore(&data_lock, flags);
1309}
1310
1311static int dss_ovl_set_info(struct omap_overlay *ovl,
1312 struct omap_overlay_info *info)
1313{
1314 struct ovl_priv_data *op = get_ovl_priv(ovl);
1315 unsigned long flags;
1316 int r;
1317
1318 r = dss_ovl_simple_check(ovl, info);
1319 if (r)
1320 return r;
1321
1322 spin_lock_irqsave(&data_lock, flags);
1323
1324 op->user_info = *info;
1325 op->user_info_dirty = true;
1326
1327 spin_unlock_irqrestore(&data_lock, flags);
1328
1329 return 0;
1330}
1331
1332static void dss_ovl_get_info(struct omap_overlay *ovl,
1333 struct omap_overlay_info *info)
1334{
1335 struct ovl_priv_data *op = get_ovl_priv(ovl);
1336 unsigned long flags;
1337
1338 spin_lock_irqsave(&data_lock, flags);
1339
1340 *info = op->user_info;
1341
1342 spin_unlock_irqrestore(&data_lock, flags);
1343}
1344
1345static int dss_ovl_set_manager(struct omap_overlay *ovl,
1346 struct omap_overlay_manager *mgr)
1347{
1348 struct ovl_priv_data *op = get_ovl_priv(ovl);
1349 unsigned long flags;
1350 int r;
1351
1352 if (!mgr)
1353 return -EINVAL;
1354
1355 mutex_lock(&apply_lock);
1356
1357 if (ovl->manager) {
1358 DSSERR("overlay '%s' already has a manager '%s'\n",
1359 ovl->name, ovl->manager->name);
1360 r = -EINVAL;
1361 goto err;
1362 }
1363
1364 r = dispc_runtime_get();
1365 if (r)
1366 goto err;
1367
1368 spin_lock_irqsave(&data_lock, flags);
1369
1370 if (op->enabled) {
1371 spin_unlock_irqrestore(&data_lock, flags);
1372 DSSERR("overlay has to be disabled to change the manager\n");
1373 r = -EINVAL;
1374 goto err1;
1375 }
1376
1377 dispc_ovl_set_channel_out(ovl->id, mgr->id);
1378
1379 ovl->manager = mgr;
1380 list_add_tail(&ovl->list, &mgr->overlays);
1381
1382 spin_unlock_irqrestore(&data_lock, flags);
1383
1384 dispc_runtime_put();
1385
1386 mutex_unlock(&apply_lock);
1387
1388 return 0;
1389
1390err1:
1391 dispc_runtime_put();
1392err:
1393 mutex_unlock(&apply_lock);
1394 return r;
1395}
1396
1397static int dss_ovl_unset_manager(struct omap_overlay *ovl)
1398{
1399 struct ovl_priv_data *op = get_ovl_priv(ovl);
1400 unsigned long flags;
1401 int r;
1402
1403 mutex_lock(&apply_lock);
1404
1405 if (!ovl->manager) {
1406 DSSERR("failed to detach overlay: manager not set\n");
1407 r = -EINVAL;
1408 goto err;
1409 }
1410
1411 spin_lock_irqsave(&data_lock, flags);
1412
1413 if (op->enabled) {
1414 spin_unlock_irqrestore(&data_lock, flags);
1415 DSSERR("overlay has to be disabled to unset the manager\n");
1416 r = -EINVAL;
1417 goto err;
1418 }
1419
1420 spin_unlock_irqrestore(&data_lock, flags);
1421
1422 /* wait for pending extra_info updates to ensure the ovl is disabled */
1423 wait_pending_extra_info_updates();
1424
1425 /*
1426 * For a manual update display, there is no guarantee that the overlay
1427 * is really disabled in HW, we may need an extra update from this
1428 * manager before the configurations can go in. Return an error if the
1429 * overlay needed an update from the manager.
1430 *
1431 * TODO: Instead of returning an error, try to do a dummy manager update
1432 * here to disable the overlay in hardware. Use the *GATED fields in
1433 * the DISPC_CONFIG registers to do a dummy update.
1434 */
1435 spin_lock_irqsave(&data_lock, flags);
1436
1437 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1438 spin_unlock_irqrestore(&data_lock, flags);
1439 DSSERR("need an update to change the manager\n");
1440 r = -EINVAL;
1441 goto err;
1442 }
1443
1444 ovl->manager = NULL;
1445 list_del(&ovl->list);
1446
1447 spin_unlock_irqrestore(&data_lock, flags);
1448
1449 mutex_unlock(&apply_lock);
1450
1451 return 0;
1452err:
1453 mutex_unlock(&apply_lock);
1454 return r;
1455}
1456
1457static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1458{
1459 struct ovl_priv_data *op = get_ovl_priv(ovl);
1460 unsigned long flags;
1461 bool e;
1462
1463 spin_lock_irqsave(&data_lock, flags);
1464
1465 e = op->enabled;
1466
1467 spin_unlock_irqrestore(&data_lock, flags);
1468
1469 return e;
1470}
1471
1472static int dss_ovl_enable(struct omap_overlay *ovl)
1473{
1474 struct ovl_priv_data *op = get_ovl_priv(ovl);
1475 unsigned long flags;
1476 int r;
1477
1478 mutex_lock(&apply_lock);
1479
1480 if (op->enabled) {
1481 r = 0;
1482 goto err1;
1483 }
1484
1485 if (ovl->manager == NULL || ovl->manager->output == NULL) {
1486 r = -EINVAL;
1487 goto err1;
1488 }
1489
1490 spin_lock_irqsave(&data_lock, flags);
1491
1492 op->enabling = true;
1493
1494 r = dss_check_settings(ovl->manager);
1495 if (r) {
1496 DSSERR("failed to enable overlay %d: check_settings failed\n",
1497 ovl->id);
1498 goto err2;
1499 }
1500
1501 dss_setup_fifos();
1502
1503 op->enabling = false;
1504 dss_apply_ovl_enable(ovl, true);
1505
1506 dss_write_regs();
1507 dss_set_go_bits();
1508
1509 spin_unlock_irqrestore(&data_lock, flags);
1510
1511 mutex_unlock(&apply_lock);
1512
1513 return 0;
1514err2:
1515 op->enabling = false;
1516 spin_unlock_irqrestore(&data_lock, flags);
1517err1:
1518 mutex_unlock(&apply_lock);
1519 return r;
1520}
1521
1522static int dss_ovl_disable(struct omap_overlay *ovl)
1523{
1524 struct ovl_priv_data *op = get_ovl_priv(ovl);
1525 unsigned long flags;
1526 int r;
1527
1528 mutex_lock(&apply_lock);
1529
1530 if (!op->enabled) {
1531 r = 0;
1532 goto err;
1533 }
1534
1535 if (ovl->manager == NULL || ovl->manager->output == NULL) {
1536 r = -EINVAL;
1537 goto err;
1538 }
1539
1540 spin_lock_irqsave(&data_lock, flags);
1541
1542 dss_apply_ovl_enable(ovl, false);
1543 dss_write_regs();
1544 dss_set_go_bits();
1545
1546 spin_unlock_irqrestore(&data_lock, flags);
1547
1548 mutex_unlock(&apply_lock);
1549
1550 return 0;
1551
1552err:
1553 mutex_unlock(&apply_lock);
1554 return r;
1555}
1556
1557static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
1558 void (*handler)(void *), void *data)
1559{
1560 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1561
1562 if (mp->framedone_handler)
1563 return -EBUSY;
1564
1565 mp->framedone_handler = handler;
1566 mp->framedone_handler_data = data;
1567
1568 return 0;
1569}
1570
1571static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
1572 void (*handler)(void *), void *data)
1573{
1574 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1575
1576 WARN_ON(mp->framedone_handler != handler ||
1577 mp->framedone_handler_data != data);
1578
1579 mp->framedone_handler = NULL;
1580 mp->framedone_handler_data = NULL;
1581}
1582
1583static const struct dss_mgr_ops apply_mgr_ops = {
1584 .connect = dss_mgr_connect_compat,
1585 .disconnect = dss_mgr_disconnect_compat,
1586 .start_update = dss_mgr_start_update_compat,
1587 .enable = dss_mgr_enable_compat,
1588 .disable = dss_mgr_disable_compat,
1589 .set_timings = dss_mgr_set_timings_compat,
1590 .set_lcd_config = dss_mgr_set_lcd_config_compat,
1591 .register_framedone_handler = dss_mgr_register_framedone_handler_compat,
1592 .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
1593};
1594
1595static int compat_refcnt;
1596static DEFINE_MUTEX(compat_init_lock);
1597
1598int omapdss_compat_init(void)
1599{
1600 struct platform_device *pdev = dss_get_core_pdev();
1601 int i, r;
1602
1603 mutex_lock(&compat_init_lock);
1604
1605 if (compat_refcnt++ > 0)
1606 goto out;
1607
1608 apply_init_priv();
1609
1610 dss_init_overlay_managers_sysfs(pdev);
1611 dss_init_overlays(pdev);
1612
1613 for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
1614 struct omap_overlay_manager *mgr;
1615
1616 mgr = omap_dss_get_overlay_manager(i);
1617
1618 mgr->set_output = &dss_mgr_set_output;
1619 mgr->unset_output = &dss_mgr_unset_output;
1620 mgr->apply = &omap_dss_mgr_apply;
1621 mgr->set_manager_info = &dss_mgr_set_info;
1622 mgr->get_manager_info = &dss_mgr_get_info;
1623 mgr->wait_for_go = &dss_mgr_wait_for_go;
1624 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1625 mgr->get_device = &dss_mgr_get_device;
1626 }
1627
1628 for (i = 0; i < omap_dss_get_num_overlays(); i++) {
1629 struct omap_overlay *ovl = omap_dss_get_overlay(i);
1630
1631 ovl->is_enabled = &dss_ovl_is_enabled;
1632 ovl->enable = &dss_ovl_enable;
1633 ovl->disable = &dss_ovl_disable;
1634 ovl->set_manager = &dss_ovl_set_manager;
1635 ovl->unset_manager = &dss_ovl_unset_manager;
1636 ovl->set_overlay_info = &dss_ovl_set_info;
1637 ovl->get_overlay_info = &dss_ovl_get_info;
1638 ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
1639 ovl->get_device = &dss_ovl_get_device;
1640 }
1641
1642 r = dss_install_mgr_ops(&apply_mgr_ops);
1643 if (r)
1644 goto err_mgr_ops;
1645
1646 r = display_init_sysfs(pdev);
1647 if (r)
1648 goto err_disp_sysfs;
1649
1650 dispc_runtime_get();
1651
1652 r = dss_dispc_initialize_irq();
1653 if (r)
1654 goto err_init_irq;
1655
1656 dispc_runtime_put();
1657
1658out:
1659 mutex_unlock(&compat_init_lock);
1660
1661 return 0;
1662
1663err_init_irq:
1664 dispc_runtime_put();
1665 display_uninit_sysfs(pdev);
1666
1667err_disp_sysfs:
1668 dss_uninstall_mgr_ops();
1669
1670err_mgr_ops:
1671 dss_uninit_overlay_managers_sysfs(pdev);
1672 dss_uninit_overlays(pdev);
1673
1674 compat_refcnt--;
1675
1676 mutex_unlock(&compat_init_lock);
1677
1678 return r;
1679}
1680EXPORT_SYMBOL(omapdss_compat_init);
1681
1682void omapdss_compat_uninit(void)
1683{
1684 struct platform_device *pdev = dss_get_core_pdev();
1685
1686 mutex_lock(&compat_init_lock);
1687
1688 if (--compat_refcnt > 0)
1689 goto out;
1690
1691 dss_dispc_uninitialize_irq();
1692
1693 display_uninit_sysfs(pdev);
1694
1695 dss_uninstall_mgr_ops();
1696
1697 dss_uninit_overlay_managers_sysfs(pdev);
1698 dss_uninit_overlays(pdev);
1699out:
1700 mutex_unlock(&compat_init_lock);
1701}
1702EXPORT_SYMBOL(omapdss_compat_uninit);
diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c
new file mode 100644
index 000000000000..54eeb507f9b3
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/core.c
@@ -0,0 +1,343 @@
1/*
2 * linux/drivers/video/omap2/dss/core.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "CORE"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/clk.h>
28#include <linux/err.h>
29#include <linux/platform_device.h>
30#include <linux/seq_file.h>
31#include <linux/debugfs.h>
32#include <linux/io.h>
33#include <linux/device.h>
34#include <linux/regulator/consumer.h>
35#include <linux/suspend.h>
36#include <linux/slab.h>
37
38#include <video/omapdss.h>
39
40#include "dss.h"
41#include "dss_features.h"
42
43static struct {
44 struct platform_device *pdev;
45
46 const char *default_display_name;
47} core;
48
49static char *def_disp_name;
50module_param_named(def_disp, def_disp_name, charp, 0);
51MODULE_PARM_DESC(def_disp, "default display name");
52
53const char *omapdss_get_default_display_name(void)
54{
55 return core.default_display_name;
56}
57EXPORT_SYMBOL(omapdss_get_default_display_name);
58
59enum omapdss_version omapdss_get_version(void)
60{
61 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
62 return pdata->version;
63}
64EXPORT_SYMBOL(omapdss_get_version);
65
66struct platform_device *dss_get_core_pdev(void)
67{
68 return core.pdev;
69}
70
71int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
72{
73 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
74
75 if (!board_data->dsi_enable_pads)
76 return -ENOENT;
77
78 return board_data->dsi_enable_pads(dsi_id, lane_mask);
79}
80
81void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
82{
83 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
84
85 if (!board_data->dsi_disable_pads)
86 return;
87
88 return board_data->dsi_disable_pads(dsi_id, lane_mask);
89}
90
91int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
92{
93 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
94
95 if (pdata->set_min_bus_tput)
96 return pdata->set_min_bus_tput(dev, tput);
97 else
98 return 0;
99}
100
101#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
102static int dss_debug_show(struct seq_file *s, void *unused)
103{
104 void (*func)(struct seq_file *) = s->private;
105 func(s);
106 return 0;
107}
108
109static int dss_debug_open(struct inode *inode, struct file *file)
110{
111 return single_open(file, dss_debug_show, inode->i_private);
112}
113
114static const struct file_operations dss_debug_fops = {
115 .open = dss_debug_open,
116 .read = seq_read,
117 .llseek = seq_lseek,
118 .release = single_release,
119};
120
121static struct dentry *dss_debugfs_dir;
122
123static int dss_initialize_debugfs(void)
124{
125 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
126 if (IS_ERR(dss_debugfs_dir)) {
127 int err = PTR_ERR(dss_debugfs_dir);
128 dss_debugfs_dir = NULL;
129 return err;
130 }
131
132 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
133 &dss_debug_dump_clocks, &dss_debug_fops);
134
135 return 0;
136}
137
138static void dss_uninitialize_debugfs(void)
139{
140 if (dss_debugfs_dir)
141 debugfs_remove_recursive(dss_debugfs_dir);
142}
143
144int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
145{
146 struct dentry *d;
147
148 d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
149 write, &dss_debug_fops);
150
151 return PTR_ERR_OR_ZERO(d);
152}
153#else /* CONFIG_OMAP2_DSS_DEBUGFS */
154static inline int dss_initialize_debugfs(void)
155{
156 return 0;
157}
158static inline void dss_uninitialize_debugfs(void)
159{
160}
161int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
162{
163 return 0;
164}
165#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
166
167/* PLATFORM DEVICE */
168static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
169{
170 DSSDBG("pm notif %lu\n", v);
171
172 switch (v) {
173 case PM_SUSPEND_PREPARE:
174 case PM_HIBERNATION_PREPARE:
175 case PM_RESTORE_PREPARE:
176 DSSDBG("suspending displays\n");
177 return dss_suspend_all_devices();
178
179 case PM_POST_SUSPEND:
180 case PM_POST_HIBERNATION:
181 case PM_POST_RESTORE:
182 DSSDBG("resuming displays\n");
183 return dss_resume_all_devices();
184
185 default:
186 return 0;
187 }
188}
189
190static struct notifier_block omap_dss_pm_notif_block = {
191 .notifier_call = omap_dss_pm_notif,
192};
193
194static int __init omap_dss_probe(struct platform_device *pdev)
195{
196 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
197 int r;
198
199 core.pdev = pdev;
200
201 dss_features_init(omapdss_get_version());
202
203 r = dss_initialize_debugfs();
204 if (r)
205 goto err_debugfs;
206
207 if (def_disp_name)
208 core.default_display_name = def_disp_name;
209 else if (pdata->default_display_name)
210 core.default_display_name = pdata->default_display_name;
211 else if (pdata->default_device)
212 core.default_display_name = pdata->default_device->name;
213
214 register_pm_notifier(&omap_dss_pm_notif_block);
215
216 return 0;
217
218err_debugfs:
219
220 return r;
221}
222
223static int omap_dss_remove(struct platform_device *pdev)
224{
225 unregister_pm_notifier(&omap_dss_pm_notif_block);
226
227 dss_uninitialize_debugfs();
228
229 return 0;
230}
231
232static void omap_dss_shutdown(struct platform_device *pdev)
233{
234 DSSDBG("shutdown\n");
235 dss_disable_all_devices();
236}
237
238static struct platform_driver omap_dss_driver = {
239 .remove = omap_dss_remove,
240 .shutdown = omap_dss_shutdown,
241 .driver = {
242 .name = "omapdss",
243 },
244};
245
246/* INIT */
247static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
248 dss_init_platform_driver,
249 dispc_init_platform_driver,
250#ifdef CONFIG_OMAP2_DSS_DSI
251 dsi_init_platform_driver,
252#endif
253#ifdef CONFIG_OMAP2_DSS_DPI
254 dpi_init_platform_driver,
255#endif
256#ifdef CONFIG_OMAP2_DSS_SDI
257 sdi_init_platform_driver,
258#endif
259#ifdef CONFIG_OMAP2_DSS_RFBI
260 rfbi_init_platform_driver,
261#endif
262#ifdef CONFIG_OMAP2_DSS_VENC
263 venc_init_platform_driver,
264#endif
265#ifdef CONFIG_OMAP4_DSS_HDMI
266 hdmi4_init_platform_driver,
267#endif
268#ifdef CONFIG_OMAP5_DSS_HDMI
269 hdmi5_init_platform_driver,
270#endif
271};
272
273static void (*dss_output_drv_unreg_funcs[])(void) = {
274#ifdef CONFIG_OMAP5_DSS_HDMI
275 hdmi5_uninit_platform_driver,
276#endif
277#ifdef CONFIG_OMAP4_DSS_HDMI
278 hdmi4_uninit_platform_driver,
279#endif
280#ifdef CONFIG_OMAP2_DSS_VENC
281 venc_uninit_platform_driver,
282#endif
283#ifdef CONFIG_OMAP2_DSS_RFBI
284 rfbi_uninit_platform_driver,
285#endif
286#ifdef CONFIG_OMAP2_DSS_SDI
287 sdi_uninit_platform_driver,
288#endif
289#ifdef CONFIG_OMAP2_DSS_DPI
290 dpi_uninit_platform_driver,
291#endif
292#ifdef CONFIG_OMAP2_DSS_DSI
293 dsi_uninit_platform_driver,
294#endif
295 dispc_uninit_platform_driver,
296 dss_uninit_platform_driver,
297};
298
299static int __init omap_dss_init(void)
300{
301 int r;
302 int i;
303
304 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
305 if (r)
306 return r;
307
308 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
309 r = dss_output_drv_reg_funcs[i]();
310 if (r)
311 goto err_reg;
312 }
313
314 return 0;
315
316err_reg:
317 for (i = ARRAY_SIZE(dss_output_drv_reg_funcs) - i;
318 i < ARRAY_SIZE(dss_output_drv_reg_funcs);
319 ++i)
320 dss_output_drv_unreg_funcs[i]();
321
322 platform_driver_unregister(&omap_dss_driver);
323
324 return r;
325}
326
327static void __exit omap_dss_exit(void)
328{
329 int i;
330
331 for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i)
332 dss_output_drv_unreg_funcs[i]();
333
334 platform_driver_unregister(&omap_dss_driver);
335}
336
337module_init(omap_dss_init);
338module_exit(omap_dss_exit);
339
340MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
341MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
342MODULE_LICENSE("GPL v2");
343
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc-compat.c b/drivers/gpu/drm/omapdrm/dss/dispc-compat.c
new file mode 100644
index 000000000000..0918b3bfe82a
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc-compat.c
@@ -0,0 +1,667 @@
1/*
2 * Copyright (C) 2012 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/module.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/jiffies.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/seq_file.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33#include "dispc-compat.h"
34
35#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
36 DISPC_IRQ_OCP_ERR | \
37 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
38 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
39 DISPC_IRQ_SYNC_LOST | \
40 DISPC_IRQ_SYNC_LOST_DIGIT)
41
42#define DISPC_MAX_NR_ISRS 8
43
44struct omap_dispc_isr_data {
45 omap_dispc_isr_t isr;
46 void *arg;
47 u32 mask;
48};
49
50struct dispc_irq_stats {
51 unsigned long last_reset;
52 unsigned irq_count;
53 unsigned irqs[32];
54};
55
56static struct {
57 spinlock_t irq_lock;
58 u32 irq_error_mask;
59 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
60 u32 error_irqs;
61 struct work_struct error_work;
62
63#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
64 spinlock_t irq_stats_lock;
65 struct dispc_irq_stats irq_stats;
66#endif
67} dispc_compat;
68
69
70#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
71static void dispc_dump_irqs(struct seq_file *s)
72{
73 unsigned long flags;
74 struct dispc_irq_stats stats;
75
76 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
77
78 stats = dispc_compat.irq_stats;
79 memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
80 dispc_compat.irq_stats.last_reset = jiffies;
81
82 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
83
84 seq_printf(s, "period %u ms\n",
85 jiffies_to_msecs(jiffies - stats.last_reset));
86
87 seq_printf(s, "irqs %d\n", stats.irq_count);
88#define PIS(x) \
89 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
90
91 PIS(FRAMEDONE);
92 PIS(VSYNC);
93 PIS(EVSYNC_EVEN);
94 PIS(EVSYNC_ODD);
95 PIS(ACBIAS_COUNT_STAT);
96 PIS(PROG_LINE_NUM);
97 PIS(GFX_FIFO_UNDERFLOW);
98 PIS(GFX_END_WIN);
99 PIS(PAL_GAMMA_MASK);
100 PIS(OCP_ERR);
101 PIS(VID1_FIFO_UNDERFLOW);
102 PIS(VID1_END_WIN);
103 PIS(VID2_FIFO_UNDERFLOW);
104 PIS(VID2_END_WIN);
105 if (dss_feat_get_num_ovls() > 3) {
106 PIS(VID3_FIFO_UNDERFLOW);
107 PIS(VID3_END_WIN);
108 }
109 PIS(SYNC_LOST);
110 PIS(SYNC_LOST_DIGIT);
111 PIS(WAKEUP);
112 if (dss_has_feature(FEAT_MGR_LCD2)) {
113 PIS(FRAMEDONE2);
114 PIS(VSYNC2);
115 PIS(ACBIAS_COUNT_STAT2);
116 PIS(SYNC_LOST2);
117 }
118 if (dss_has_feature(FEAT_MGR_LCD3)) {
119 PIS(FRAMEDONE3);
120 PIS(VSYNC3);
121 PIS(ACBIAS_COUNT_STAT3);
122 PIS(SYNC_LOST3);
123 }
124#undef PIS
125}
126#endif
127
128/* dispc.irq_lock has to be locked by the caller */
129static void _omap_dispc_set_irqs(void)
130{
131 u32 mask;
132 int i;
133 struct omap_dispc_isr_data *isr_data;
134
135 mask = dispc_compat.irq_error_mask;
136
137 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
138 isr_data = &dispc_compat.registered_isr[i];
139
140 if (isr_data->isr == NULL)
141 continue;
142
143 mask |= isr_data->mask;
144 }
145
146 dispc_write_irqenable(mask);
147}
148
149int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
150{
151 int i;
152 int ret;
153 unsigned long flags;
154 struct omap_dispc_isr_data *isr_data;
155
156 if (isr == NULL)
157 return -EINVAL;
158
159 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
160
161 /* check for duplicate entry */
162 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
163 isr_data = &dispc_compat.registered_isr[i];
164 if (isr_data->isr == isr && isr_data->arg == arg &&
165 isr_data->mask == mask) {
166 ret = -EINVAL;
167 goto err;
168 }
169 }
170
171 isr_data = NULL;
172 ret = -EBUSY;
173
174 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
175 isr_data = &dispc_compat.registered_isr[i];
176
177 if (isr_data->isr != NULL)
178 continue;
179
180 isr_data->isr = isr;
181 isr_data->arg = arg;
182 isr_data->mask = mask;
183 ret = 0;
184
185 break;
186 }
187
188 if (ret)
189 goto err;
190
191 _omap_dispc_set_irqs();
192
193 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
194
195 return 0;
196err:
197 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
198
199 return ret;
200}
201EXPORT_SYMBOL(omap_dispc_register_isr);
202
203int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
204{
205 int i;
206 unsigned long flags;
207 int ret = -EINVAL;
208 struct omap_dispc_isr_data *isr_data;
209
210 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
211
212 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
213 isr_data = &dispc_compat.registered_isr[i];
214 if (isr_data->isr != isr || isr_data->arg != arg ||
215 isr_data->mask != mask)
216 continue;
217
218 /* found the correct isr */
219
220 isr_data->isr = NULL;
221 isr_data->arg = NULL;
222 isr_data->mask = 0;
223
224 ret = 0;
225 break;
226 }
227
228 if (ret == 0)
229 _omap_dispc_set_irqs();
230
231 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
232
233 return ret;
234}
235EXPORT_SYMBOL(omap_dispc_unregister_isr);
236
237static void print_irq_status(u32 status)
238{
239 if ((status & dispc_compat.irq_error_mask) == 0)
240 return;
241
242#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
243
244 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
245 status,
246 PIS(OCP_ERR),
247 PIS(GFX_FIFO_UNDERFLOW),
248 PIS(VID1_FIFO_UNDERFLOW),
249 PIS(VID2_FIFO_UNDERFLOW),
250 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
251 PIS(SYNC_LOST),
252 PIS(SYNC_LOST_DIGIT),
253 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
254 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
255#undef PIS
256}
257
258/* Called from dss.c. Note that we don't touch clocks here,
259 * but we presume they are on because we got an IRQ. However,
260 * an irq handler may turn the clocks off, so we may not have
261 * clock later in the function. */
262static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
263{
264 int i;
265 u32 irqstatus, irqenable;
266 u32 handledirqs = 0;
267 u32 unhandled_errors;
268 struct omap_dispc_isr_data *isr_data;
269 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
270
271 spin_lock(&dispc_compat.irq_lock);
272
273 irqstatus = dispc_read_irqstatus();
274 irqenable = dispc_read_irqenable();
275
276 /* IRQ is not for us */
277 if (!(irqstatus & irqenable)) {
278 spin_unlock(&dispc_compat.irq_lock);
279 return IRQ_NONE;
280 }
281
282#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
283 spin_lock(&dispc_compat.irq_stats_lock);
284 dispc_compat.irq_stats.irq_count++;
285 dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
286 spin_unlock(&dispc_compat.irq_stats_lock);
287#endif
288
289 print_irq_status(irqstatus);
290
291 /* Ack the interrupt. Do it here before clocks are possibly turned
292 * off */
293 dispc_clear_irqstatus(irqstatus);
294 /* flush posted write */
295 dispc_read_irqstatus();
296
297 /* make a copy and unlock, so that isrs can unregister
298 * themselves */
299 memcpy(registered_isr, dispc_compat.registered_isr,
300 sizeof(registered_isr));
301
302 spin_unlock(&dispc_compat.irq_lock);
303
304 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
305 isr_data = &registered_isr[i];
306
307 if (!isr_data->isr)
308 continue;
309
310 if (isr_data->mask & irqstatus) {
311 isr_data->isr(isr_data->arg, irqstatus);
312 handledirqs |= isr_data->mask;
313 }
314 }
315
316 spin_lock(&dispc_compat.irq_lock);
317
318 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
319
320 if (unhandled_errors) {
321 dispc_compat.error_irqs |= unhandled_errors;
322
323 dispc_compat.irq_error_mask &= ~unhandled_errors;
324 _omap_dispc_set_irqs();
325
326 schedule_work(&dispc_compat.error_work);
327 }
328
329 spin_unlock(&dispc_compat.irq_lock);
330
331 return IRQ_HANDLED;
332}
333
334static void dispc_error_worker(struct work_struct *work)
335{
336 int i;
337 u32 errors;
338 unsigned long flags;
339 static const unsigned fifo_underflow_bits[] = {
340 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
341 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
342 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
343 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
344 };
345
346 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
347 errors = dispc_compat.error_irqs;
348 dispc_compat.error_irqs = 0;
349 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
350
351 dispc_runtime_get();
352
353 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
354 struct omap_overlay *ovl;
355 unsigned bit;
356
357 ovl = omap_dss_get_overlay(i);
358 bit = fifo_underflow_bits[i];
359
360 if (bit & errors) {
361 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
362 ovl->name);
363 ovl->disable(ovl);
364 msleep(50);
365 }
366 }
367
368 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
369 struct omap_overlay_manager *mgr;
370 unsigned bit;
371
372 mgr = omap_dss_get_overlay_manager(i);
373 bit = dispc_mgr_get_sync_lost_irq(i);
374
375 if (bit & errors) {
376 int j;
377
378 DSSERR("SYNC_LOST on channel %s, restarting the output "
379 "with video overlays disabled\n",
380 mgr->name);
381
382 dss_mgr_disable(mgr);
383
384 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
385 struct omap_overlay *ovl;
386 ovl = omap_dss_get_overlay(j);
387
388 if (ovl->id != OMAP_DSS_GFX &&
389 ovl->manager == mgr)
390 ovl->disable(ovl);
391 }
392
393 dss_mgr_enable(mgr);
394 }
395 }
396
397 if (errors & DISPC_IRQ_OCP_ERR) {
398 DSSERR("OCP_ERR\n");
399 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
400 struct omap_overlay_manager *mgr;
401
402 mgr = omap_dss_get_overlay_manager(i);
403 dss_mgr_disable(mgr);
404 }
405 }
406
407 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
408 dispc_compat.irq_error_mask |= errors;
409 _omap_dispc_set_irqs();
410 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
411
412 dispc_runtime_put();
413}
414
415int dss_dispc_initialize_irq(void)
416{
417 int r;
418
419#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
420 spin_lock_init(&dispc_compat.irq_stats_lock);
421 dispc_compat.irq_stats.last_reset = jiffies;
422 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
423#endif
424
425 spin_lock_init(&dispc_compat.irq_lock);
426
427 memset(dispc_compat.registered_isr, 0,
428 sizeof(dispc_compat.registered_isr));
429
430 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
431 if (dss_has_feature(FEAT_MGR_LCD2))
432 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
433 if (dss_has_feature(FEAT_MGR_LCD3))
434 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
435 if (dss_feat_get_num_ovls() > 3)
436 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
437
438 /*
439 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
440 * so clear it
441 */
442 dispc_clear_irqstatus(dispc_read_irqstatus());
443
444 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
445
446 _omap_dispc_set_irqs();
447
448 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
449 if (r) {
450 DSSERR("dispc_request_irq failed\n");
451 return r;
452 }
453
454 return 0;
455}
456
457void dss_dispc_uninitialize_irq(void)
458{
459 dispc_free_irq(&dispc_compat);
460}
461
462static void dispc_mgr_disable_isr(void *data, u32 mask)
463{
464 struct completion *compl = data;
465 complete(compl);
466}
467
468static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
469{
470 dispc_mgr_enable(channel, true);
471}
472
473static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
474{
475 DECLARE_COMPLETION_ONSTACK(framedone_compl);
476 int r;
477 u32 irq;
478
479 if (!dispc_mgr_is_enabled(channel))
480 return;
481
482 /*
483 * When we disable LCD output, we need to wait for FRAMEDONE to know
484 * that DISPC has finished with the LCD output.
485 */
486
487 irq = dispc_mgr_get_framedone_irq(channel);
488
489 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
490 irq);
491 if (r)
492 DSSERR("failed to register FRAMEDONE isr\n");
493
494 dispc_mgr_enable(channel, false);
495
496 /* if we couldn't register for framedone, just sleep and exit */
497 if (r) {
498 msleep(100);
499 return;
500 }
501
502 if (!wait_for_completion_timeout(&framedone_compl,
503 msecs_to_jiffies(100)))
504 DSSERR("timeout waiting for FRAME DONE\n");
505
506 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
507 irq);
508 if (r)
509 DSSERR("failed to unregister FRAMEDONE isr\n");
510}
511
512static void dispc_digit_out_enable_isr(void *data, u32 mask)
513{
514 struct completion *compl = data;
515
516 /* ignore any sync lost interrupts */
517 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
518 complete(compl);
519}
520
521static void dispc_mgr_enable_digit_out(void)
522{
523 DECLARE_COMPLETION_ONSTACK(vsync_compl);
524 int r;
525 u32 irq_mask;
526
527 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
528 return;
529
530 /*
531 * Digit output produces some sync lost interrupts during the first
532 * frame when enabling. Those need to be ignored, so we register for the
533 * sync lost irq to prevent the error handler from triggering.
534 */
535
536 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
537 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
538
539 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
540 irq_mask);
541 if (r) {
542 DSSERR("failed to register %x isr\n", irq_mask);
543 return;
544 }
545
546 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
547
548 /* wait for the first evsync */
549 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
550 DSSERR("timeout waiting for digit out to start\n");
551
552 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
553 irq_mask);
554 if (r)
555 DSSERR("failed to unregister %x isr\n", irq_mask);
556}
557
558static void dispc_mgr_disable_digit_out(void)
559{
560 DECLARE_COMPLETION_ONSTACK(framedone_compl);
561 int r, i;
562 u32 irq_mask;
563 int num_irqs;
564
565 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
566 return;
567
568 /*
569 * When we disable the digit output, we need to wait for FRAMEDONE to
570 * know that DISPC has finished with the output.
571 */
572
573 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
574 num_irqs = 1;
575
576 if (!irq_mask) {
577 /*
578 * omap 2/3 don't have framedone irq for TV, so we need to use
579 * vsyncs for this.
580 */
581
582 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
583 /*
584 * We need to wait for both even and odd vsyncs. Note that this
585 * is not totally reliable, as we could get a vsync interrupt
586 * before we disable the output, which leads to timeout in the
587 * wait_for_completion.
588 */
589 num_irqs = 2;
590 }
591
592 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
593 irq_mask);
594 if (r)
595 DSSERR("failed to register %x isr\n", irq_mask);
596
597 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
598
599 /* if we couldn't register the irq, just sleep and exit */
600 if (r) {
601 msleep(100);
602 return;
603 }
604
605 for (i = 0; i < num_irqs; ++i) {
606 if (!wait_for_completion_timeout(&framedone_compl,
607 msecs_to_jiffies(100)))
608 DSSERR("timeout waiting for digit out to stop\n");
609 }
610
611 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
612 irq_mask);
613 if (r)
614 DSSERR("failed to unregister %x isr\n", irq_mask);
615}
616
617void dispc_mgr_enable_sync(enum omap_channel channel)
618{
619 if (dss_mgr_is_lcd(channel))
620 dispc_mgr_enable_lcd_out(channel);
621 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
622 dispc_mgr_enable_digit_out();
623 else
624 WARN_ON(1);
625}
626
627void dispc_mgr_disable_sync(enum omap_channel channel)
628{
629 if (dss_mgr_is_lcd(channel))
630 dispc_mgr_disable_lcd_out(channel);
631 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
632 dispc_mgr_disable_digit_out();
633 else
634 WARN_ON(1);
635}
636
637static inline void dispc_irq_wait_handler(void *data, u32 mask)
638{
639 complete((struct completion *)data);
640}
641
642int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
643 unsigned long timeout)
644{
645
646 int r;
647 DECLARE_COMPLETION_ONSTACK(completion);
648
649 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
650 irqmask);
651
652 if (r)
653 return r;
654
655 timeout = wait_for_completion_interruptible_timeout(&completion,
656 timeout);
657
658 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
659
660 if (timeout == 0)
661 return -ETIMEDOUT;
662
663 if (timeout == -ERESTARTSYS)
664 return -ERESTARTSYS;
665
666 return 0;
667}
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc-compat.h b/drivers/gpu/drm/omapdrm/dss/dispc-compat.h
new file mode 100644
index 000000000000..14a69b3d4fb0
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc-compat.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2012 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#ifndef __OMAP2_DSS_DISPC_COMPAT_H
19#define __OMAP2_DSS_DISPC_COMPAT_H
20
21void dispc_mgr_enable_sync(enum omap_channel channel);
22void dispc_mgr_disable_sync(enum omap_channel channel);
23
24int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
25 unsigned long timeout);
26
27int dss_dispc_initialize_irq(void);
28void dss_dispc_uninitialize_irq(void);
29
30#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
new file mode 100644
index 000000000000..6b50476ec669
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -0,0 +1,4234 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPC"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/export.h>
29#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/jiffies.h>
32#include <linux/seq_file.h>
33#include <linux/delay.h>
34#include <linux/workqueue.h>
35#include <linux/hardirq.h>
36#include <linux/platform_device.h>
37#include <linux/pm_runtime.h>
38#include <linux/sizes.h>
39#include <linux/mfd/syscon.h>
40#include <linux/regmap.h>
41#include <linux/of.h>
42#include <linux/component.h>
43
44#include <video/omapdss.h>
45
46#include "dss.h"
47#include "dss_features.h"
48#include "dispc.h"
49
50/* DISPC */
51#define DISPC_SZ_REGS SZ_4K
52
53enum omap_burst_size {
54 BURST_SIZE_X2 = 0,
55 BURST_SIZE_X4 = 1,
56 BURST_SIZE_X8 = 2,
57};
58
59#define REG_GET(idx, start, end) \
60 FLD_GET(dispc_read_reg(idx), start, end)
61
62#define REG_FLD_MOD(idx, val, start, end) \
63 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
64
65struct dispc_features {
66 u8 sw_start;
67 u8 fp_start;
68 u8 bp_start;
69 u16 sw_max;
70 u16 vp_max;
71 u16 hp_max;
72 u8 mgr_width_start;
73 u8 mgr_height_start;
74 u16 mgr_width_max;
75 u16 mgr_height_max;
76 unsigned long max_lcd_pclk;
77 unsigned long max_tv_pclk;
78 int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
79 const struct omap_video_timings *mgr_timings,
80 u16 width, u16 height, u16 out_width, u16 out_height,
81 enum omap_color_mode color_mode, bool *five_taps,
82 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
83 u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
84 unsigned long (*calc_core_clk) (unsigned long pclk,
85 u16 width, u16 height, u16 out_width, u16 out_height,
86 bool mem_to_mem);
87 u8 num_fifos;
88
89 /* swap GFX & WB fifos */
90 bool gfx_fifo_workaround:1;
91
92 /* no DISPC_IRQ_FRAMEDONETV on this SoC */
93 bool no_framedone_tv:1;
94
95 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
96 bool mstandby_workaround:1;
97
98 bool set_max_preload:1;
99
100 /* PIXEL_INC is not added to the last pixel of a line */
101 bool last_pixel_inc_missing:1;
102
103 /* POL_FREQ has ALIGN bit */
104 bool supports_sync_align:1;
105
106 bool has_writeback:1;
107};
108
109#define DISPC_MAX_NR_FIFOS 5
110
111static struct {
112 struct platform_device *pdev;
113 void __iomem *base;
114
115 int irq;
116 irq_handler_t user_handler;
117 void *user_data;
118
119 unsigned long core_clk_rate;
120 unsigned long tv_pclk_rate;
121
122 u32 fifo_size[DISPC_MAX_NR_FIFOS];
123 /* maps which plane is using a fifo. fifo-id -> plane-id */
124 int fifo_assignment[DISPC_MAX_NR_FIFOS];
125
126 bool ctx_valid;
127 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
128
129 const struct dispc_features *feat;
130
131 bool is_enabled;
132
133 struct regmap *syscon_pol;
134 u32 syscon_pol_offset;
135
136 /* DISPC_CONTROL & DISPC_CONFIG lock*/
137 spinlock_t control_lock;
138} dispc;
139
140enum omap_color_component {
141 /* used for all color formats for OMAP3 and earlier
142 * and for RGB and Y color component on OMAP4
143 */
144 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
145 /* used for UV component for
146 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
147 * color formats on OMAP4
148 */
149 DISPC_COLOR_COMPONENT_UV = 1 << 1,
150};
151
152enum mgr_reg_fields {
153 DISPC_MGR_FLD_ENABLE,
154 DISPC_MGR_FLD_STNTFT,
155 DISPC_MGR_FLD_GO,
156 DISPC_MGR_FLD_TFTDATALINES,
157 DISPC_MGR_FLD_STALLMODE,
158 DISPC_MGR_FLD_TCKENABLE,
159 DISPC_MGR_FLD_TCKSELECTION,
160 DISPC_MGR_FLD_CPR,
161 DISPC_MGR_FLD_FIFOHANDCHECK,
162 /* used to maintain a count of the above fields */
163 DISPC_MGR_FLD_NUM,
164};
165
166struct dispc_reg_field {
167 u16 reg;
168 u8 high;
169 u8 low;
170};
171
172static const struct {
173 const char *name;
174 u32 vsync_irq;
175 u32 framedone_irq;
176 u32 sync_lost_irq;
177 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
178} mgr_desc[] = {
179 [OMAP_DSS_CHANNEL_LCD] = {
180 .name = "LCD",
181 .vsync_irq = DISPC_IRQ_VSYNC,
182 .framedone_irq = DISPC_IRQ_FRAMEDONE,
183 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
184 .reg_desc = {
185 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
186 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
187 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
188 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
189 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
190 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
191 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
192 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
193 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
194 },
195 },
196 [OMAP_DSS_CHANNEL_DIGIT] = {
197 .name = "DIGIT",
198 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
199 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
200 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
201 .reg_desc = {
202 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
203 [DISPC_MGR_FLD_STNTFT] = { },
204 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
205 [DISPC_MGR_FLD_TFTDATALINES] = { },
206 [DISPC_MGR_FLD_STALLMODE] = { },
207 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
208 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
209 [DISPC_MGR_FLD_CPR] = { },
210 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
211 },
212 },
213 [OMAP_DSS_CHANNEL_LCD2] = {
214 .name = "LCD2",
215 .vsync_irq = DISPC_IRQ_VSYNC2,
216 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
217 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
218 .reg_desc = {
219 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
220 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
221 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
222 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
223 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
224 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
225 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
226 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
227 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
228 },
229 },
230 [OMAP_DSS_CHANNEL_LCD3] = {
231 .name = "LCD3",
232 .vsync_irq = DISPC_IRQ_VSYNC3,
233 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
234 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
235 .reg_desc = {
236 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
237 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
238 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
239 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
240 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
241 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
242 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
243 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
244 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
245 },
246 },
247};
248
249struct color_conv_coef {
250 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
251 int full_range;
252};
253
254static unsigned long dispc_fclk_rate(void);
255static unsigned long dispc_core_clk_rate(void);
256static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
257static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
258
259static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
260static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
261
262static inline void dispc_write_reg(const u16 idx, u32 val)
263{
264 __raw_writel(val, dispc.base + idx);
265}
266
267static inline u32 dispc_read_reg(const u16 idx)
268{
269 return __raw_readl(dispc.base + idx);
270}
271
272static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
273{
274 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
275 return REG_GET(rfld.reg, rfld.high, rfld.low);
276}
277
278static void mgr_fld_write(enum omap_channel channel,
279 enum mgr_reg_fields regfld, int val) {
280 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
281 const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
282 unsigned long flags;
283
284 if (need_lock)
285 spin_lock_irqsave(&dispc.control_lock, flags);
286
287 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
288
289 if (need_lock)
290 spin_unlock_irqrestore(&dispc.control_lock, flags);
291}
292
293#define SR(reg) \
294 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
295#define RR(reg) \
296 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
297
298static void dispc_save_context(void)
299{
300 int i, j;
301
302 DSSDBG("dispc_save_context\n");
303
304 SR(IRQENABLE);
305 SR(CONTROL);
306 SR(CONFIG);
307 SR(LINE_NUMBER);
308 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
309 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
310 SR(GLOBAL_ALPHA);
311 if (dss_has_feature(FEAT_MGR_LCD2)) {
312 SR(CONTROL2);
313 SR(CONFIG2);
314 }
315 if (dss_has_feature(FEAT_MGR_LCD3)) {
316 SR(CONTROL3);
317 SR(CONFIG3);
318 }
319
320 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
321 SR(DEFAULT_COLOR(i));
322 SR(TRANS_COLOR(i));
323 SR(SIZE_MGR(i));
324 if (i == OMAP_DSS_CHANNEL_DIGIT)
325 continue;
326 SR(TIMING_H(i));
327 SR(TIMING_V(i));
328 SR(POL_FREQ(i));
329 SR(DIVISORo(i));
330
331 SR(DATA_CYCLE1(i));
332 SR(DATA_CYCLE2(i));
333 SR(DATA_CYCLE3(i));
334
335 if (dss_has_feature(FEAT_CPR)) {
336 SR(CPR_COEF_R(i));
337 SR(CPR_COEF_G(i));
338 SR(CPR_COEF_B(i));
339 }
340 }
341
342 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
343 SR(OVL_BA0(i));
344 SR(OVL_BA1(i));
345 SR(OVL_POSITION(i));
346 SR(OVL_SIZE(i));
347 SR(OVL_ATTRIBUTES(i));
348 SR(OVL_FIFO_THRESHOLD(i));
349 SR(OVL_ROW_INC(i));
350 SR(OVL_PIXEL_INC(i));
351 if (dss_has_feature(FEAT_PRELOAD))
352 SR(OVL_PRELOAD(i));
353 if (i == OMAP_DSS_GFX) {
354 SR(OVL_WINDOW_SKIP(i));
355 SR(OVL_TABLE_BA(i));
356 continue;
357 }
358 SR(OVL_FIR(i));
359 SR(OVL_PICTURE_SIZE(i));
360 SR(OVL_ACCU0(i));
361 SR(OVL_ACCU1(i));
362
363 for (j = 0; j < 8; j++)
364 SR(OVL_FIR_COEF_H(i, j));
365
366 for (j = 0; j < 8; j++)
367 SR(OVL_FIR_COEF_HV(i, j));
368
369 for (j = 0; j < 5; j++)
370 SR(OVL_CONV_COEF(i, j));
371
372 if (dss_has_feature(FEAT_FIR_COEF_V)) {
373 for (j = 0; j < 8; j++)
374 SR(OVL_FIR_COEF_V(i, j));
375 }
376
377 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
378 SR(OVL_BA0_UV(i));
379 SR(OVL_BA1_UV(i));
380 SR(OVL_FIR2(i));
381 SR(OVL_ACCU2_0(i));
382 SR(OVL_ACCU2_1(i));
383
384 for (j = 0; j < 8; j++)
385 SR(OVL_FIR_COEF_H2(i, j));
386
387 for (j = 0; j < 8; j++)
388 SR(OVL_FIR_COEF_HV2(i, j));
389
390 for (j = 0; j < 8; j++)
391 SR(OVL_FIR_COEF_V2(i, j));
392 }
393 if (dss_has_feature(FEAT_ATTR2))
394 SR(OVL_ATTRIBUTES2(i));
395 }
396
397 if (dss_has_feature(FEAT_CORE_CLK_DIV))
398 SR(DIVISOR);
399
400 dispc.ctx_valid = true;
401
402 DSSDBG("context saved\n");
403}
404
405static void dispc_restore_context(void)
406{
407 int i, j;
408
409 DSSDBG("dispc_restore_context\n");
410
411 if (!dispc.ctx_valid)
412 return;
413
414 /*RR(IRQENABLE);*/
415 /*RR(CONTROL);*/
416 RR(CONFIG);
417 RR(LINE_NUMBER);
418 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
419 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
420 RR(GLOBAL_ALPHA);
421 if (dss_has_feature(FEAT_MGR_LCD2))
422 RR(CONFIG2);
423 if (dss_has_feature(FEAT_MGR_LCD3))
424 RR(CONFIG3);
425
426 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
427 RR(DEFAULT_COLOR(i));
428 RR(TRANS_COLOR(i));
429 RR(SIZE_MGR(i));
430 if (i == OMAP_DSS_CHANNEL_DIGIT)
431 continue;
432 RR(TIMING_H(i));
433 RR(TIMING_V(i));
434 RR(POL_FREQ(i));
435 RR(DIVISORo(i));
436
437 RR(DATA_CYCLE1(i));
438 RR(DATA_CYCLE2(i));
439 RR(DATA_CYCLE3(i));
440
441 if (dss_has_feature(FEAT_CPR)) {
442 RR(CPR_COEF_R(i));
443 RR(CPR_COEF_G(i));
444 RR(CPR_COEF_B(i));
445 }
446 }
447
448 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
449 RR(OVL_BA0(i));
450 RR(OVL_BA1(i));
451 RR(OVL_POSITION(i));
452 RR(OVL_SIZE(i));
453 RR(OVL_ATTRIBUTES(i));
454 RR(OVL_FIFO_THRESHOLD(i));
455 RR(OVL_ROW_INC(i));
456 RR(OVL_PIXEL_INC(i));
457 if (dss_has_feature(FEAT_PRELOAD))
458 RR(OVL_PRELOAD(i));
459 if (i == OMAP_DSS_GFX) {
460 RR(OVL_WINDOW_SKIP(i));
461 RR(OVL_TABLE_BA(i));
462 continue;
463 }
464 RR(OVL_FIR(i));
465 RR(OVL_PICTURE_SIZE(i));
466 RR(OVL_ACCU0(i));
467 RR(OVL_ACCU1(i));
468
469 for (j = 0; j < 8; j++)
470 RR(OVL_FIR_COEF_H(i, j));
471
472 for (j = 0; j < 8; j++)
473 RR(OVL_FIR_COEF_HV(i, j));
474
475 for (j = 0; j < 5; j++)
476 RR(OVL_CONV_COEF(i, j));
477
478 if (dss_has_feature(FEAT_FIR_COEF_V)) {
479 for (j = 0; j < 8; j++)
480 RR(OVL_FIR_COEF_V(i, j));
481 }
482
483 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
484 RR(OVL_BA0_UV(i));
485 RR(OVL_BA1_UV(i));
486 RR(OVL_FIR2(i));
487 RR(OVL_ACCU2_0(i));
488 RR(OVL_ACCU2_1(i));
489
490 for (j = 0; j < 8; j++)
491 RR(OVL_FIR_COEF_H2(i, j));
492
493 for (j = 0; j < 8; j++)
494 RR(OVL_FIR_COEF_HV2(i, j));
495
496 for (j = 0; j < 8; j++)
497 RR(OVL_FIR_COEF_V2(i, j));
498 }
499 if (dss_has_feature(FEAT_ATTR2))
500 RR(OVL_ATTRIBUTES2(i));
501 }
502
503 if (dss_has_feature(FEAT_CORE_CLK_DIV))
504 RR(DIVISOR);
505
506 /* enable last, because LCD & DIGIT enable are here */
507 RR(CONTROL);
508 if (dss_has_feature(FEAT_MGR_LCD2))
509 RR(CONTROL2);
510 if (dss_has_feature(FEAT_MGR_LCD3))
511 RR(CONTROL3);
512 /* clear spurious SYNC_LOST_DIGIT interrupts */
513 dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT);
514
515 /*
516 * enable last so IRQs won't trigger before
517 * the context is fully restored
518 */
519 RR(IRQENABLE);
520
521 DSSDBG("context restored\n");
522}
523
524#undef SR
525#undef RR
526
527int dispc_runtime_get(void)
528{
529 int r;
530
531 DSSDBG("dispc_runtime_get\n");
532
533 r = pm_runtime_get_sync(&dispc.pdev->dev);
534 WARN_ON(r < 0);
535 return r < 0 ? r : 0;
536}
537EXPORT_SYMBOL(dispc_runtime_get);
538
539void dispc_runtime_put(void)
540{
541 int r;
542
543 DSSDBG("dispc_runtime_put\n");
544
545 r = pm_runtime_put_sync(&dispc.pdev->dev);
546 WARN_ON(r < 0 && r != -ENOSYS);
547}
548EXPORT_SYMBOL(dispc_runtime_put);
549
550u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
551{
552 return mgr_desc[channel].vsync_irq;
553}
554EXPORT_SYMBOL(dispc_mgr_get_vsync_irq);
555
556u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
557{
558 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
559 return 0;
560
561 return mgr_desc[channel].framedone_irq;
562}
563EXPORT_SYMBOL(dispc_mgr_get_framedone_irq);
564
565u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
566{
567 return mgr_desc[channel].sync_lost_irq;
568}
569EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq);
570
571u32 dispc_wb_get_framedone_irq(void)
572{
573 return DISPC_IRQ_FRAMEDONEWB;
574}
575
576bool dispc_mgr_go_busy(enum omap_channel channel)
577{
578 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
579}
580EXPORT_SYMBOL(dispc_mgr_go_busy);
581
582void dispc_mgr_go(enum omap_channel channel)
583{
584 WARN_ON(!dispc_mgr_is_enabled(channel));
585 WARN_ON(dispc_mgr_go_busy(channel));
586
587 DSSDBG("GO %s\n", mgr_desc[channel].name);
588
589 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
590}
591EXPORT_SYMBOL(dispc_mgr_go);
592
593bool dispc_wb_go_busy(void)
594{
595 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
596}
597
598void dispc_wb_go(void)
599{
600 enum omap_plane plane = OMAP_DSS_WB;
601 bool enable, go;
602
603 enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
604
605 if (!enable)
606 return;
607
608 go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
609 if (go) {
610 DSSERR("GO bit not down for WB\n");
611 return;
612 }
613
614 REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
615}
616
617static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
618{
619 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
620}
621
622static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
623{
624 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
625}
626
627static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
628{
629 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
630}
631
632static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
633{
634 BUG_ON(plane == OMAP_DSS_GFX);
635
636 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
637}
638
639static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
640 u32 value)
641{
642 BUG_ON(plane == OMAP_DSS_GFX);
643
644 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
645}
646
647static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
648{
649 BUG_ON(plane == OMAP_DSS_GFX);
650
651 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
652}
653
654static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
655 int fir_vinc, int five_taps,
656 enum omap_color_component color_comp)
657{
658 const struct dispc_coef *h_coef, *v_coef;
659 int i;
660
661 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
662 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
663
664 for (i = 0; i < 8; i++) {
665 u32 h, hv;
666
667 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
668 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
669 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
670 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
671 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
672 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
673 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
674 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
675
676 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
677 dispc_ovl_write_firh_reg(plane, i, h);
678 dispc_ovl_write_firhv_reg(plane, i, hv);
679 } else {
680 dispc_ovl_write_firh2_reg(plane, i, h);
681 dispc_ovl_write_firhv2_reg(plane, i, hv);
682 }
683
684 }
685
686 if (five_taps) {
687 for (i = 0; i < 8; i++) {
688 u32 v;
689 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
690 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
691 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
692 dispc_ovl_write_firv_reg(plane, i, v);
693 else
694 dispc_ovl_write_firv2_reg(plane, i, v);
695 }
696 }
697}
698
699
700static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
701 const struct color_conv_coef *ct)
702{
703#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
704
705 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
706 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
707 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
708 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
709 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
710
711 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
712
713#undef CVAL
714}
715
716static void dispc_setup_color_conv_coef(void)
717{
718 int i;
719 int num_ovl = dss_feat_get_num_ovls();
720 const struct color_conv_coef ctbl_bt601_5_ovl = {
721 /* YUV -> RGB */
722 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
723 };
724 const struct color_conv_coef ctbl_bt601_5_wb = {
725 /* RGB -> YUV */
726 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
727 };
728
729 for (i = 1; i < num_ovl; i++)
730 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
731
732 if (dispc.feat->has_writeback)
733 dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
734}
735
736static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
737{
738 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
739}
740
741static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
742{
743 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
744}
745
746static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
747{
748 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
749}
750
751static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
752{
753 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
754}
755
756static void dispc_ovl_set_pos(enum omap_plane plane,
757 enum omap_overlay_caps caps, int x, int y)
758{
759 u32 val;
760
761 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
762 return;
763
764 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
765
766 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
767}
768
769static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
770 int height)
771{
772 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
773
774 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
775 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
776 else
777 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
778}
779
780static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
781 int height)
782{
783 u32 val;
784
785 BUG_ON(plane == OMAP_DSS_GFX);
786
787 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
788
789 if (plane == OMAP_DSS_WB)
790 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
791 else
792 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
793}
794
795static void dispc_ovl_set_zorder(enum omap_plane plane,
796 enum omap_overlay_caps caps, u8 zorder)
797{
798 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
799 return;
800
801 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
802}
803
804static void dispc_ovl_enable_zorder_planes(void)
805{
806 int i;
807
808 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
809 return;
810
811 for (i = 0; i < dss_feat_get_num_ovls(); i++)
812 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
813}
814
815static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
816 enum omap_overlay_caps caps, bool enable)
817{
818 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
819 return;
820
821 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
822}
823
824static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
825 enum omap_overlay_caps caps, u8 global_alpha)
826{
827 static const unsigned shifts[] = { 0, 8, 16, 24, };
828 int shift;
829
830 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
831 return;
832
833 shift = shifts[plane];
834 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
835}
836
837static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
838{
839 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
840}
841
842static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
843{
844 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
845}
846
847static void dispc_ovl_set_color_mode(enum omap_plane plane,
848 enum omap_color_mode color_mode)
849{
850 u32 m = 0;
851 if (plane != OMAP_DSS_GFX) {
852 switch (color_mode) {
853 case OMAP_DSS_COLOR_NV12:
854 m = 0x0; break;
855 case OMAP_DSS_COLOR_RGBX16:
856 m = 0x1; break;
857 case OMAP_DSS_COLOR_RGBA16:
858 m = 0x2; break;
859 case OMAP_DSS_COLOR_RGB12U:
860 m = 0x4; break;
861 case OMAP_DSS_COLOR_ARGB16:
862 m = 0x5; break;
863 case OMAP_DSS_COLOR_RGB16:
864 m = 0x6; break;
865 case OMAP_DSS_COLOR_ARGB16_1555:
866 m = 0x7; break;
867 case OMAP_DSS_COLOR_RGB24U:
868 m = 0x8; break;
869 case OMAP_DSS_COLOR_RGB24P:
870 m = 0x9; break;
871 case OMAP_DSS_COLOR_YUV2:
872 m = 0xa; break;
873 case OMAP_DSS_COLOR_UYVY:
874 m = 0xb; break;
875 case OMAP_DSS_COLOR_ARGB32:
876 m = 0xc; break;
877 case OMAP_DSS_COLOR_RGBA32:
878 m = 0xd; break;
879 case OMAP_DSS_COLOR_RGBX32:
880 m = 0xe; break;
881 case OMAP_DSS_COLOR_XRGB16_1555:
882 m = 0xf; break;
883 default:
884 BUG(); return;
885 }
886 } else {
887 switch (color_mode) {
888 case OMAP_DSS_COLOR_CLUT1:
889 m = 0x0; break;
890 case OMAP_DSS_COLOR_CLUT2:
891 m = 0x1; break;
892 case OMAP_DSS_COLOR_CLUT4:
893 m = 0x2; break;
894 case OMAP_DSS_COLOR_CLUT8:
895 m = 0x3; break;
896 case OMAP_DSS_COLOR_RGB12U:
897 m = 0x4; break;
898 case OMAP_DSS_COLOR_ARGB16:
899 m = 0x5; break;
900 case OMAP_DSS_COLOR_RGB16:
901 m = 0x6; break;
902 case OMAP_DSS_COLOR_ARGB16_1555:
903 m = 0x7; break;
904 case OMAP_DSS_COLOR_RGB24U:
905 m = 0x8; break;
906 case OMAP_DSS_COLOR_RGB24P:
907 m = 0x9; break;
908 case OMAP_DSS_COLOR_RGBX16:
909 m = 0xa; break;
910 case OMAP_DSS_COLOR_RGBA16:
911 m = 0xb; break;
912 case OMAP_DSS_COLOR_ARGB32:
913 m = 0xc; break;
914 case OMAP_DSS_COLOR_RGBA32:
915 m = 0xd; break;
916 case OMAP_DSS_COLOR_RGBX32:
917 m = 0xe; break;
918 case OMAP_DSS_COLOR_XRGB16_1555:
919 m = 0xf; break;
920 default:
921 BUG(); return;
922 }
923 }
924
925 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
926}
927
928static void dispc_ovl_configure_burst_type(enum omap_plane plane,
929 enum omap_dss_rotation_type rotation_type)
930{
931 if (dss_has_feature(FEAT_BURST_2D) == 0)
932 return;
933
934 if (rotation_type == OMAP_DSS_ROT_TILER)
935 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
936 else
937 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
938}
939
940void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
941{
942 int shift;
943 u32 val;
944 int chan = 0, chan2 = 0;
945
946 switch (plane) {
947 case OMAP_DSS_GFX:
948 shift = 8;
949 break;
950 case OMAP_DSS_VIDEO1:
951 case OMAP_DSS_VIDEO2:
952 case OMAP_DSS_VIDEO3:
953 shift = 16;
954 break;
955 default:
956 BUG();
957 return;
958 }
959
960 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
961 if (dss_has_feature(FEAT_MGR_LCD2)) {
962 switch (channel) {
963 case OMAP_DSS_CHANNEL_LCD:
964 chan = 0;
965 chan2 = 0;
966 break;
967 case OMAP_DSS_CHANNEL_DIGIT:
968 chan = 1;
969 chan2 = 0;
970 break;
971 case OMAP_DSS_CHANNEL_LCD2:
972 chan = 0;
973 chan2 = 1;
974 break;
975 case OMAP_DSS_CHANNEL_LCD3:
976 if (dss_has_feature(FEAT_MGR_LCD3)) {
977 chan = 0;
978 chan2 = 2;
979 } else {
980 BUG();
981 return;
982 }
983 break;
984 case OMAP_DSS_CHANNEL_WB:
985 chan = 0;
986 chan2 = 3;
987 break;
988 default:
989 BUG();
990 return;
991 }
992
993 val = FLD_MOD(val, chan, shift, shift);
994 val = FLD_MOD(val, chan2, 31, 30);
995 } else {
996 val = FLD_MOD(val, channel, shift, shift);
997 }
998 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
999}
1000EXPORT_SYMBOL(dispc_ovl_set_channel_out);
1001
1002static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
1003{
1004 int shift;
1005 u32 val;
1006
1007 switch (plane) {
1008 case OMAP_DSS_GFX:
1009 shift = 8;
1010 break;
1011 case OMAP_DSS_VIDEO1:
1012 case OMAP_DSS_VIDEO2:
1013 case OMAP_DSS_VIDEO3:
1014 shift = 16;
1015 break;
1016 default:
1017 BUG();
1018 return 0;
1019 }
1020
1021 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1022
1023 if (FLD_GET(val, shift, shift) == 1)
1024 return OMAP_DSS_CHANNEL_DIGIT;
1025
1026 if (!dss_has_feature(FEAT_MGR_LCD2))
1027 return OMAP_DSS_CHANNEL_LCD;
1028
1029 switch (FLD_GET(val, 31, 30)) {
1030 case 0:
1031 default:
1032 return OMAP_DSS_CHANNEL_LCD;
1033 case 1:
1034 return OMAP_DSS_CHANNEL_LCD2;
1035 case 2:
1036 return OMAP_DSS_CHANNEL_LCD3;
1037 case 3:
1038 return OMAP_DSS_CHANNEL_WB;
1039 }
1040}
1041
1042void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
1043{
1044 enum omap_plane plane = OMAP_DSS_WB;
1045
1046 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1047}
1048
1049static void dispc_ovl_set_burst_size(enum omap_plane plane,
1050 enum omap_burst_size burst_size)
1051{
1052 static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
1053 int shift;
1054
1055 shift = shifts[plane];
1056 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
1057}
1058
1059static void dispc_configure_burst_sizes(void)
1060{
1061 int i;
1062 const int burst_size = BURST_SIZE_X8;
1063
1064 /* Configure burst size always to maximum size */
1065 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
1066 dispc_ovl_set_burst_size(i, burst_size);
1067 if (dispc.feat->has_writeback)
1068 dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
1069}
1070
1071static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
1072{
1073 unsigned unit = dss_feat_get_burst_size_unit();
1074 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
1075 return unit * 8;
1076}
1077
1078void dispc_enable_gamma_table(bool enable)
1079{
1080 /*
1081 * This is partially implemented to support only disabling of
1082 * the gamma table.
1083 */
1084 if (enable) {
1085 DSSWARN("Gamma table enabling for TV not yet supported");
1086 return;
1087 }
1088
1089 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1090}
1091
1092static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
1093{
1094 if (channel == OMAP_DSS_CHANNEL_DIGIT)
1095 return;
1096
1097 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
1098}
1099
1100static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
1101 const struct omap_dss_cpr_coefs *coefs)
1102{
1103 u32 coef_r, coef_g, coef_b;
1104
1105 if (!dss_mgr_is_lcd(channel))
1106 return;
1107
1108 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1109 FLD_VAL(coefs->rb, 9, 0);
1110 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1111 FLD_VAL(coefs->gb, 9, 0);
1112 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1113 FLD_VAL(coefs->bb, 9, 0);
1114
1115 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1116 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1117 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1118}
1119
1120static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
1121{
1122 u32 val;
1123
1124 BUG_ON(plane == OMAP_DSS_GFX);
1125
1126 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1127 val = FLD_MOD(val, enable, 9, 9);
1128 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
1129}
1130
1131static void dispc_ovl_enable_replication(enum omap_plane plane,
1132 enum omap_overlay_caps caps, bool enable)
1133{
1134 static const unsigned shifts[] = { 5, 10, 10, 10 };
1135 int shift;
1136
1137 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1138 return;
1139
1140 shift = shifts[plane];
1141 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
1142}
1143
1144static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
1145 u16 height)
1146{
1147 u32 val;
1148
1149 val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
1150 FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
1151
1152 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
1153}
1154
1155static void dispc_init_fifos(void)
1156{
1157 u32 size;
1158 int fifo;
1159 u8 start, end;
1160 u32 unit;
1161 int i;
1162
1163 unit = dss_feat_get_buffer_size_unit();
1164
1165 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
1166
1167 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1168 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
1169 size *= unit;
1170 dispc.fifo_size[fifo] = size;
1171
1172 /*
1173 * By default fifos are mapped directly to overlays, fifo 0 to
1174 * ovl 0, fifo 1 to ovl 1, etc.
1175 */
1176 dispc.fifo_assignment[fifo] = fifo;
1177 }
1178
1179 /*
1180 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1181 * causes problems with certain use cases, like using the tiler in 2D
1182 * mode. The below hack swaps the fifos of GFX and WB planes, thus
1183 * giving GFX plane a larger fifo. WB but should work fine with a
1184 * smaller fifo.
1185 */
1186 if (dispc.feat->gfx_fifo_workaround) {
1187 u32 v;
1188
1189 v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1190
1191 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1192 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1193 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1194 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1195
1196 dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1197
1198 dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1199 dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1200 }
1201
1202 /*
1203 * Setup default fifo thresholds.
1204 */
1205 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1206 u32 low, high;
1207 const bool use_fifomerge = false;
1208 const bool manual_update = false;
1209
1210 dispc_ovl_compute_fifo_thresholds(i, &low, &high,
1211 use_fifomerge, manual_update);
1212
1213 dispc_ovl_set_fifo_threshold(i, low, high);
1214 }
1215
1216 if (dispc.feat->has_writeback) {
1217 u32 low, high;
1218 const bool use_fifomerge = false;
1219 const bool manual_update = false;
1220
1221 dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high,
1222 use_fifomerge, manual_update);
1223
1224 dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high);
1225 }
1226}
1227
1228static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
1229{
1230 int fifo;
1231 u32 size = 0;
1232
1233 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1234 if (dispc.fifo_assignment[fifo] == plane)
1235 size += dispc.fifo_size[fifo];
1236 }
1237
1238 return size;
1239}
1240
1241void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
1242{
1243 u8 hi_start, hi_end, lo_start, lo_end;
1244 u32 unit;
1245
1246 unit = dss_feat_get_buffer_size_unit();
1247
1248 WARN_ON(low % unit != 0);
1249 WARN_ON(high % unit != 0);
1250
1251 low /= unit;
1252 high /= unit;
1253
1254 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1255 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1256
1257 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
1258 plane,
1259 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1260 lo_start, lo_end) * unit,
1261 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1262 hi_start, hi_end) * unit,
1263 low * unit, high * unit);
1264
1265 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
1266 FLD_VAL(high, hi_start, hi_end) |
1267 FLD_VAL(low, lo_start, lo_end));
1268
1269 /*
1270 * configure the preload to the pipeline's high threhold, if HT it's too
1271 * large for the preload field, set the threshold to the maximum value
1272 * that can be held by the preload register
1273 */
1274 if (dss_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload &&
1275 plane != OMAP_DSS_WB)
1276 dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
1277}
1278
1279void dispc_enable_fifomerge(bool enable)
1280{
1281 if (!dss_has_feature(FEAT_FIFO_MERGE)) {
1282 WARN_ON(enable);
1283 return;
1284 }
1285
1286 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1287 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1288}
1289
1290void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
1291 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1292 bool manual_update)
1293{
1294 /*
1295 * All sizes are in bytes. Both the buffer and burst are made of
1296 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1297 */
1298
1299 unsigned buf_unit = dss_feat_get_buffer_size_unit();
1300 unsigned ovl_fifo_size, total_fifo_size, burst_size;
1301 int i;
1302
1303 burst_size = dispc_ovl_get_burst_size(plane);
1304 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
1305
1306 if (use_fifomerge) {
1307 total_fifo_size = 0;
1308 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
1309 total_fifo_size += dispc_ovl_get_fifo_size(i);
1310 } else {
1311 total_fifo_size = ovl_fifo_size;
1312 }
1313
1314 /*
1315 * We use the same low threshold for both fifomerge and non-fifomerge
1316 * cases, but for fifomerge we calculate the high threshold using the
1317 * combined fifo size
1318 */
1319
1320 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
1321 *fifo_low = ovl_fifo_size - burst_size * 2;
1322 *fifo_high = total_fifo_size - burst_size;
1323 } else if (plane == OMAP_DSS_WB) {
1324 /*
1325 * Most optimal configuration for writeback is to push out data
1326 * to the interconnect the moment writeback pushes enough pixels
1327 * in the FIFO to form a burst
1328 */
1329 *fifo_low = 0;
1330 *fifo_high = burst_size;
1331 } else {
1332 *fifo_low = ovl_fifo_size - burst_size;
1333 *fifo_high = total_fifo_size - buf_unit;
1334 }
1335}
1336
1337static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable)
1338{
1339 int bit;
1340
1341 if (plane == OMAP_DSS_GFX)
1342 bit = 14;
1343 else
1344 bit = 23;
1345
1346 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
1347}
1348
1349static void dispc_ovl_set_mflag_threshold(enum omap_plane plane,
1350 int low, int high)
1351{
1352 dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
1353 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
1354}
1355
1356static void dispc_init_mflag(void)
1357{
1358 int i;
1359
1360 /*
1361 * HACK: NV12 color format and MFLAG seem to have problems working
1362 * together: using two displays, and having an NV12 overlay on one of
1363 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
1364 * Changing MFLAG thresholds and PRELOAD to certain values seem to
1365 * remove the errors, but there doesn't seem to be a clear logic on
1366 * which values work and which not.
1367 *
1368 * As a work-around, set force MFLAG to always on.
1369 */
1370 dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
1371 (1 << 0) | /* MFLAG_CTRL = force always on */
1372 (0 << 2)); /* MFLAG_START = disable */
1373
1374 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1375 u32 size = dispc_ovl_get_fifo_size(i);
1376 u32 unit = dss_feat_get_buffer_size_unit();
1377 u32 low, high;
1378
1379 dispc_ovl_set_mflag(i, true);
1380
1381 /*
1382 * Simulation team suggests below thesholds:
1383 * HT = fifosize * 5 / 8;
1384 * LT = fifosize * 4 / 8;
1385 */
1386
1387 low = size * 4 / 8 / unit;
1388 high = size * 5 / 8 / unit;
1389
1390 dispc_ovl_set_mflag_threshold(i, low, high);
1391 }
1392
1393 if (dispc.feat->has_writeback) {
1394 u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
1395 u32 unit = dss_feat_get_buffer_size_unit();
1396 u32 low, high;
1397
1398 dispc_ovl_set_mflag(OMAP_DSS_WB, true);
1399
1400 /*
1401 * Simulation team suggests below thesholds:
1402 * HT = fifosize * 5 / 8;
1403 * LT = fifosize * 4 / 8;
1404 */
1405
1406 low = size * 4 / 8 / unit;
1407 high = size * 5 / 8 / unit;
1408
1409 dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
1410 }
1411}
1412
1413static void dispc_ovl_set_fir(enum omap_plane plane,
1414 int hinc, int vinc,
1415 enum omap_color_component color_comp)
1416{
1417 u32 val;
1418
1419 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1420 u8 hinc_start, hinc_end, vinc_start, vinc_end;
1421
1422 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1423 &hinc_start, &hinc_end);
1424 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1425 &vinc_start, &vinc_end);
1426 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1427 FLD_VAL(hinc, hinc_start, hinc_end);
1428
1429 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1430 } else {
1431 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1432 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1433 }
1434}
1435
1436static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1437{
1438 u32 val;
1439 u8 hor_start, hor_end, vert_start, vert_end;
1440
1441 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1442 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1443
1444 val = FLD_VAL(vaccu, vert_start, vert_end) |
1445 FLD_VAL(haccu, hor_start, hor_end);
1446
1447 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
1448}
1449
1450static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1451{
1452 u32 val;
1453 u8 hor_start, hor_end, vert_start, vert_end;
1454
1455 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1456 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1457
1458 val = FLD_VAL(vaccu, vert_start, vert_end) |
1459 FLD_VAL(haccu, hor_start, hor_end);
1460
1461 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
1462}
1463
1464static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
1465 int vaccu)
1466{
1467 u32 val;
1468
1469 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1470 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1471}
1472
1473static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
1474 int vaccu)
1475{
1476 u32 val;
1477
1478 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1479 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1480}
1481
1482static void dispc_ovl_set_scale_param(enum omap_plane plane,
1483 u16 orig_width, u16 orig_height,
1484 u16 out_width, u16 out_height,
1485 bool five_taps, u8 rotation,
1486 enum omap_color_component color_comp)
1487{
1488 int fir_hinc, fir_vinc;
1489
1490 fir_hinc = 1024 * orig_width / out_width;
1491 fir_vinc = 1024 * orig_height / out_height;
1492
1493 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1494 color_comp);
1495 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
1496}
1497
1498static void dispc_ovl_set_accu_uv(enum omap_plane plane,
1499 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
1500 bool ilace, enum omap_color_mode color_mode, u8 rotation)
1501{
1502 int h_accu2_0, h_accu2_1;
1503 int v_accu2_0, v_accu2_1;
1504 int chroma_hinc, chroma_vinc;
1505 int idx;
1506
1507 struct accu {
1508 s8 h0_m, h0_n;
1509 s8 h1_m, h1_n;
1510 s8 v0_m, v0_n;
1511 s8 v1_m, v1_n;
1512 };
1513
1514 const struct accu *accu_table;
1515 const struct accu *accu_val;
1516
1517 static const struct accu accu_nv12[4] = {
1518 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1519 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1520 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1521 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1522 };
1523
1524 static const struct accu accu_nv12_ilace[4] = {
1525 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1526 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1527 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1528 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1529 };
1530
1531 static const struct accu accu_yuv[4] = {
1532 { 0, 1, 0, 1, 0, 1, 0, 1 },
1533 { 0, 1, 0, 1, 0, 1, 0, 1 },
1534 { -1, 1, 0, 1, 0, 1, 0, 1 },
1535 { 0, 1, 0, 1, -1, 1, 0, 1 },
1536 };
1537
1538 switch (rotation) {
1539 case OMAP_DSS_ROT_0:
1540 idx = 0;
1541 break;
1542 case OMAP_DSS_ROT_90:
1543 idx = 1;
1544 break;
1545 case OMAP_DSS_ROT_180:
1546 idx = 2;
1547 break;
1548 case OMAP_DSS_ROT_270:
1549 idx = 3;
1550 break;
1551 default:
1552 BUG();
1553 return;
1554 }
1555
1556 switch (color_mode) {
1557 case OMAP_DSS_COLOR_NV12:
1558 if (ilace)
1559 accu_table = accu_nv12_ilace;
1560 else
1561 accu_table = accu_nv12;
1562 break;
1563 case OMAP_DSS_COLOR_YUV2:
1564 case OMAP_DSS_COLOR_UYVY:
1565 accu_table = accu_yuv;
1566 break;
1567 default:
1568 BUG();
1569 return;
1570 }
1571
1572 accu_val = &accu_table[idx];
1573
1574 chroma_hinc = 1024 * orig_width / out_width;
1575 chroma_vinc = 1024 * orig_height / out_height;
1576
1577 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1578 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1579 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1580 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1581
1582 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1583 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1584}
1585
1586static void dispc_ovl_set_scaling_common(enum omap_plane plane,
1587 u16 orig_width, u16 orig_height,
1588 u16 out_width, u16 out_height,
1589 bool ilace, bool five_taps,
1590 bool fieldmode, enum omap_color_mode color_mode,
1591 u8 rotation)
1592{
1593 int accu0 = 0;
1594 int accu1 = 0;
1595 u32 l;
1596
1597 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1598 out_width, out_height, five_taps,
1599 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
1600 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1601
1602 /* RESIZEENABLE and VERTICALTAPS */
1603 l &= ~((0x3 << 5) | (0x1 << 21));
1604 l |= (orig_width != out_width) ? (1 << 5) : 0;
1605 l |= (orig_height != out_height) ? (1 << 6) : 0;
1606 l |= five_taps ? (1 << 21) : 0;
1607
1608 /* VRESIZECONF and HRESIZECONF */
1609 if (dss_has_feature(FEAT_RESIZECONF)) {
1610 l &= ~(0x3 << 7);
1611 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1612 l |= (orig_height <= out_height) ? 0 : (1 << 8);
1613 }
1614
1615 /* LINEBUFFERSPLIT */
1616 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1617 l &= ~(0x1 << 22);
1618 l |= five_taps ? (1 << 22) : 0;
1619 }
1620
1621 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
1622
1623 /*
1624 * field 0 = even field = bottom field
1625 * field 1 = odd field = top field
1626 */
1627 if (ilace && !fieldmode) {
1628 accu1 = 0;
1629 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
1630 if (accu0 >= 1024/2) {
1631 accu1 = 1024/2;
1632 accu0 -= accu1;
1633 }
1634 }
1635
1636 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1637 dispc_ovl_set_vid_accu1(plane, 0, accu1);
1638}
1639
1640static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
1641 u16 orig_width, u16 orig_height,
1642 u16 out_width, u16 out_height,
1643 bool ilace, bool five_taps,
1644 bool fieldmode, enum omap_color_mode color_mode,
1645 u8 rotation)
1646{
1647 int scale_x = out_width != orig_width;
1648 int scale_y = out_height != orig_height;
1649 bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
1650
1651 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1652 return;
1653 if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1654 color_mode != OMAP_DSS_COLOR_UYVY &&
1655 color_mode != OMAP_DSS_COLOR_NV12)) {
1656 /* reset chroma resampling for RGB formats */
1657 if (plane != OMAP_DSS_WB)
1658 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
1659 return;
1660 }
1661
1662 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
1663 out_height, ilace, color_mode, rotation);
1664
1665 switch (color_mode) {
1666 case OMAP_DSS_COLOR_NV12:
1667 if (chroma_upscale) {
1668 /* UV is subsampled by 2 horizontally and vertically */
1669 orig_height >>= 1;
1670 orig_width >>= 1;
1671 } else {
1672 /* UV is downsampled by 2 horizontally and vertically */
1673 orig_height <<= 1;
1674 orig_width <<= 1;
1675 }
1676
1677 break;
1678 case OMAP_DSS_COLOR_YUV2:
1679 case OMAP_DSS_COLOR_UYVY:
1680 /* For YUV422 with 90/270 rotation, we don't upsample chroma */
1681 if (rotation == OMAP_DSS_ROT_0 ||
1682 rotation == OMAP_DSS_ROT_180) {
1683 if (chroma_upscale)
1684 /* UV is subsampled by 2 horizontally */
1685 orig_width >>= 1;
1686 else
1687 /* UV is downsampled by 2 horizontally */
1688 orig_width <<= 1;
1689 }
1690
1691 /* must use FIR for YUV422 if rotated */
1692 if (rotation != OMAP_DSS_ROT_0)
1693 scale_x = scale_y = true;
1694
1695 break;
1696 default:
1697 BUG();
1698 return;
1699 }
1700
1701 if (out_width != orig_width)
1702 scale_x = true;
1703 if (out_height != orig_height)
1704 scale_y = true;
1705
1706 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1707 out_width, out_height, five_taps,
1708 rotation, DISPC_COLOR_COMPONENT_UV);
1709
1710 if (plane != OMAP_DSS_WB)
1711 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1712 (scale_x || scale_y) ? 1 : 0, 8, 8);
1713
1714 /* set H scaling */
1715 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1716 /* set V scaling */
1717 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
1718}
1719
1720static void dispc_ovl_set_scaling(enum omap_plane plane,
1721 u16 orig_width, u16 orig_height,
1722 u16 out_width, u16 out_height,
1723 bool ilace, bool five_taps,
1724 bool fieldmode, enum omap_color_mode color_mode,
1725 u8 rotation)
1726{
1727 BUG_ON(plane == OMAP_DSS_GFX);
1728
1729 dispc_ovl_set_scaling_common(plane,
1730 orig_width, orig_height,
1731 out_width, out_height,
1732 ilace, five_taps,
1733 fieldmode, color_mode,
1734 rotation);
1735
1736 dispc_ovl_set_scaling_uv(plane,
1737 orig_width, orig_height,
1738 out_width, out_height,
1739 ilace, five_taps,
1740 fieldmode, color_mode,
1741 rotation);
1742}
1743
1744static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1745 enum omap_dss_rotation_type rotation_type,
1746 bool mirroring, enum omap_color_mode color_mode)
1747{
1748 bool row_repeat = false;
1749 int vidrot = 0;
1750
1751 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1752 color_mode == OMAP_DSS_COLOR_UYVY) {
1753
1754 if (mirroring) {
1755 switch (rotation) {
1756 case OMAP_DSS_ROT_0:
1757 vidrot = 2;
1758 break;
1759 case OMAP_DSS_ROT_90:
1760 vidrot = 1;
1761 break;
1762 case OMAP_DSS_ROT_180:
1763 vidrot = 0;
1764 break;
1765 case OMAP_DSS_ROT_270:
1766 vidrot = 3;
1767 break;
1768 }
1769 } else {
1770 switch (rotation) {
1771 case OMAP_DSS_ROT_0:
1772 vidrot = 0;
1773 break;
1774 case OMAP_DSS_ROT_90:
1775 vidrot = 1;
1776 break;
1777 case OMAP_DSS_ROT_180:
1778 vidrot = 2;
1779 break;
1780 case OMAP_DSS_ROT_270:
1781 vidrot = 3;
1782 break;
1783 }
1784 }
1785
1786 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1787 row_repeat = true;
1788 else
1789 row_repeat = false;
1790 }
1791
1792 /*
1793 * OMAP4/5 Errata i631:
1794 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
1795 * rows beyond the framebuffer, which may cause OCP error.
1796 */
1797 if (color_mode == OMAP_DSS_COLOR_NV12 &&
1798 rotation_type != OMAP_DSS_ROT_TILER)
1799 vidrot = 1;
1800
1801 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
1802 if (dss_has_feature(FEAT_ROWREPEATENABLE))
1803 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1804 row_repeat ? 1 : 0, 18, 18);
1805
1806 if (color_mode == OMAP_DSS_COLOR_NV12) {
1807 bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
1808 (rotation == OMAP_DSS_ROT_0 ||
1809 rotation == OMAP_DSS_ROT_180);
1810 /* DOUBLESTRIDE */
1811 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
1812 }
1813
1814}
1815
1816static int color_mode_to_bpp(enum omap_color_mode color_mode)
1817{
1818 switch (color_mode) {
1819 case OMAP_DSS_COLOR_CLUT1:
1820 return 1;
1821 case OMAP_DSS_COLOR_CLUT2:
1822 return 2;
1823 case OMAP_DSS_COLOR_CLUT4:
1824 return 4;
1825 case OMAP_DSS_COLOR_CLUT8:
1826 case OMAP_DSS_COLOR_NV12:
1827 return 8;
1828 case OMAP_DSS_COLOR_RGB12U:
1829 case OMAP_DSS_COLOR_RGB16:
1830 case OMAP_DSS_COLOR_ARGB16:
1831 case OMAP_DSS_COLOR_YUV2:
1832 case OMAP_DSS_COLOR_UYVY:
1833 case OMAP_DSS_COLOR_RGBA16:
1834 case OMAP_DSS_COLOR_RGBX16:
1835 case OMAP_DSS_COLOR_ARGB16_1555:
1836 case OMAP_DSS_COLOR_XRGB16_1555:
1837 return 16;
1838 case OMAP_DSS_COLOR_RGB24P:
1839 return 24;
1840 case OMAP_DSS_COLOR_RGB24U:
1841 case OMAP_DSS_COLOR_ARGB32:
1842 case OMAP_DSS_COLOR_RGBA32:
1843 case OMAP_DSS_COLOR_RGBX32:
1844 return 32;
1845 default:
1846 BUG();
1847 return 0;
1848 }
1849}
1850
1851static s32 pixinc(int pixels, u8 ps)
1852{
1853 if (pixels == 1)
1854 return 1;
1855 else if (pixels > 1)
1856 return 1 + (pixels - 1) * ps;
1857 else if (pixels < 0)
1858 return 1 - (-pixels + 1) * ps;
1859 else
1860 BUG();
1861 return 0;
1862}
1863
1864static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1865 u16 screen_width,
1866 u16 width, u16 height,
1867 enum omap_color_mode color_mode, bool fieldmode,
1868 unsigned int field_offset,
1869 unsigned *offset0, unsigned *offset1,
1870 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1871{
1872 u8 ps;
1873
1874 /* FIXME CLUT formats */
1875 switch (color_mode) {
1876 case OMAP_DSS_COLOR_CLUT1:
1877 case OMAP_DSS_COLOR_CLUT2:
1878 case OMAP_DSS_COLOR_CLUT4:
1879 case OMAP_DSS_COLOR_CLUT8:
1880 BUG();
1881 return;
1882 case OMAP_DSS_COLOR_YUV2:
1883 case OMAP_DSS_COLOR_UYVY:
1884 ps = 4;
1885 break;
1886 default:
1887 ps = color_mode_to_bpp(color_mode) / 8;
1888 break;
1889 }
1890
1891 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1892 width, height);
1893
1894 /*
1895 * field 0 = even field = bottom field
1896 * field 1 = odd field = top field
1897 */
1898 switch (rotation + mirror * 4) {
1899 case OMAP_DSS_ROT_0:
1900 case OMAP_DSS_ROT_180:
1901 /*
1902 * If the pixel format is YUV or UYVY divide the width
1903 * of the image by 2 for 0 and 180 degree rotation.
1904 */
1905 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1906 color_mode == OMAP_DSS_COLOR_UYVY)
1907 width = width >> 1;
1908 case OMAP_DSS_ROT_90:
1909 case OMAP_DSS_ROT_270:
1910 *offset1 = 0;
1911 if (field_offset)
1912 *offset0 = field_offset * screen_width * ps;
1913 else
1914 *offset0 = 0;
1915
1916 *row_inc = pixinc(1 +
1917 (y_predecim * screen_width - x_predecim * width) +
1918 (fieldmode ? screen_width : 0), ps);
1919 *pix_inc = pixinc(x_predecim, ps);
1920 break;
1921
1922 case OMAP_DSS_ROT_0 + 4:
1923 case OMAP_DSS_ROT_180 + 4:
1924 /* If the pixel format is YUV or UYVY divide the width
1925 * of the image by 2 for 0 degree and 180 degree
1926 */
1927 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1928 color_mode == OMAP_DSS_COLOR_UYVY)
1929 width = width >> 1;
1930 case OMAP_DSS_ROT_90 + 4:
1931 case OMAP_DSS_ROT_270 + 4:
1932 *offset1 = 0;
1933 if (field_offset)
1934 *offset0 = field_offset * screen_width * ps;
1935 else
1936 *offset0 = 0;
1937 *row_inc = pixinc(1 -
1938 (y_predecim * screen_width + x_predecim * width) -
1939 (fieldmode ? screen_width : 0), ps);
1940 *pix_inc = pixinc(x_predecim, ps);
1941 break;
1942
1943 default:
1944 BUG();
1945 return;
1946 }
1947}
1948
1949static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1950 u16 screen_width,
1951 u16 width, u16 height,
1952 enum omap_color_mode color_mode, bool fieldmode,
1953 unsigned int field_offset,
1954 unsigned *offset0, unsigned *offset1,
1955 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1956{
1957 u8 ps;
1958 u16 fbw, fbh;
1959
1960 /* FIXME CLUT formats */
1961 switch (color_mode) {
1962 case OMAP_DSS_COLOR_CLUT1:
1963 case OMAP_DSS_COLOR_CLUT2:
1964 case OMAP_DSS_COLOR_CLUT4:
1965 case OMAP_DSS_COLOR_CLUT8:
1966 BUG();
1967 return;
1968 default:
1969 ps = color_mode_to_bpp(color_mode) / 8;
1970 break;
1971 }
1972
1973 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1974 width, height);
1975
1976 /* width & height are overlay sizes, convert to fb sizes */
1977
1978 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1979 fbw = width;
1980 fbh = height;
1981 } else {
1982 fbw = height;
1983 fbh = width;
1984 }
1985
1986 /*
1987 * field 0 = even field = bottom field
1988 * field 1 = odd field = top field
1989 */
1990 switch (rotation + mirror * 4) {
1991 case OMAP_DSS_ROT_0:
1992 *offset1 = 0;
1993 if (field_offset)
1994 *offset0 = *offset1 + field_offset * screen_width * ps;
1995 else
1996 *offset0 = *offset1;
1997 *row_inc = pixinc(1 +
1998 (y_predecim * screen_width - fbw * x_predecim) +
1999 (fieldmode ? screen_width : 0), ps);
2000 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2001 color_mode == OMAP_DSS_COLOR_UYVY)
2002 *pix_inc = pixinc(x_predecim, 2 * ps);
2003 else
2004 *pix_inc = pixinc(x_predecim, ps);
2005 break;
2006 case OMAP_DSS_ROT_90:
2007 *offset1 = screen_width * (fbh - 1) * ps;
2008 if (field_offset)
2009 *offset0 = *offset1 + field_offset * ps;
2010 else
2011 *offset0 = *offset1;
2012 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
2013 y_predecim + (fieldmode ? 1 : 0), ps);
2014 *pix_inc = pixinc(-x_predecim * screen_width, ps);
2015 break;
2016 case OMAP_DSS_ROT_180:
2017 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
2018 if (field_offset)
2019 *offset0 = *offset1 - field_offset * screen_width * ps;
2020 else
2021 *offset0 = *offset1;
2022 *row_inc = pixinc(-1 -
2023 (y_predecim * screen_width - fbw * x_predecim) -
2024 (fieldmode ? screen_width : 0), ps);
2025 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2026 color_mode == OMAP_DSS_COLOR_UYVY)
2027 *pix_inc = pixinc(-x_predecim, 2 * ps);
2028 else
2029 *pix_inc = pixinc(-x_predecim, ps);
2030 break;
2031 case OMAP_DSS_ROT_270:
2032 *offset1 = (fbw - 1) * ps;
2033 if (field_offset)
2034 *offset0 = *offset1 - field_offset * ps;
2035 else
2036 *offset0 = *offset1;
2037 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
2038 y_predecim - (fieldmode ? 1 : 0), ps);
2039 *pix_inc = pixinc(x_predecim * screen_width, ps);
2040 break;
2041
2042 /* mirroring */
2043 case OMAP_DSS_ROT_0 + 4:
2044 *offset1 = (fbw - 1) * ps;
2045 if (field_offset)
2046 *offset0 = *offset1 + field_offset * screen_width * ps;
2047 else
2048 *offset0 = *offset1;
2049 *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
2050 (fieldmode ? screen_width : 0),
2051 ps);
2052 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2053 color_mode == OMAP_DSS_COLOR_UYVY)
2054 *pix_inc = pixinc(-x_predecim, 2 * ps);
2055 else
2056 *pix_inc = pixinc(-x_predecim, ps);
2057 break;
2058
2059 case OMAP_DSS_ROT_90 + 4:
2060 *offset1 = 0;
2061 if (field_offset)
2062 *offset0 = *offset1 + field_offset * ps;
2063 else
2064 *offset0 = *offset1;
2065 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
2066 y_predecim + (fieldmode ? 1 : 0),
2067 ps);
2068 *pix_inc = pixinc(x_predecim * screen_width, ps);
2069 break;
2070
2071 case OMAP_DSS_ROT_180 + 4:
2072 *offset1 = screen_width * (fbh - 1) * ps;
2073 if (field_offset)
2074 *offset0 = *offset1 - field_offset * screen_width * ps;
2075 else
2076 *offset0 = *offset1;
2077 *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
2078 (fieldmode ? screen_width : 0),
2079 ps);
2080 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2081 color_mode == OMAP_DSS_COLOR_UYVY)
2082 *pix_inc = pixinc(x_predecim, 2 * ps);
2083 else
2084 *pix_inc = pixinc(x_predecim, ps);
2085 break;
2086
2087 case OMAP_DSS_ROT_270 + 4:
2088 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
2089 if (field_offset)
2090 *offset0 = *offset1 - field_offset * ps;
2091 else
2092 *offset0 = *offset1;
2093 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
2094 y_predecim - (fieldmode ? 1 : 0),
2095 ps);
2096 *pix_inc = pixinc(-x_predecim * screen_width, ps);
2097 break;
2098
2099 default:
2100 BUG();
2101 return;
2102 }
2103}
2104
2105static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
2106 enum omap_color_mode color_mode, bool fieldmode,
2107 unsigned int field_offset, unsigned *offset0, unsigned *offset1,
2108 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
2109{
2110 u8 ps;
2111
2112 switch (color_mode) {
2113 case OMAP_DSS_COLOR_CLUT1:
2114 case OMAP_DSS_COLOR_CLUT2:
2115 case OMAP_DSS_COLOR_CLUT4:
2116 case OMAP_DSS_COLOR_CLUT8:
2117 BUG();
2118 return;
2119 default:
2120 ps = color_mode_to_bpp(color_mode) / 8;
2121 break;
2122 }
2123
2124 DSSDBG("scrw %d, width %d\n", screen_width, width);
2125
2126 /*
2127 * field 0 = even field = bottom field
2128 * field 1 = odd field = top field
2129 */
2130 *offset1 = 0;
2131 if (field_offset)
2132 *offset0 = *offset1 + field_offset * screen_width * ps;
2133 else
2134 *offset0 = *offset1;
2135 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
2136 (fieldmode ? screen_width : 0), ps);
2137 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2138 color_mode == OMAP_DSS_COLOR_UYVY)
2139 *pix_inc = pixinc(x_predecim, 2 * ps);
2140 else
2141 *pix_inc = pixinc(x_predecim, ps);
2142}
2143
2144/*
2145 * This function is used to avoid synclosts in OMAP3, because of some
2146 * undocumented horizontal position and timing related limitations.
2147 */
2148static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
2149 const struct omap_video_timings *t, u16 pos_x,
2150 u16 width, u16 height, u16 out_width, u16 out_height,
2151 bool five_taps)
2152{
2153 const int ds = DIV_ROUND_UP(height, out_height);
2154 unsigned long nonactive;
2155 static const u8 limits[3] = { 8, 10, 20 };
2156 u64 val, blank;
2157 int i;
2158
2159 nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
2160
2161 i = 0;
2162 if (out_height < height)
2163 i++;
2164 if (out_width < width)
2165 i++;
2166 blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
2167 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
2168 if (blank <= limits[i])
2169 return -EINVAL;
2170
2171 /* FIXME add checks for 3-tap filter once the limitations are known */
2172 if (!five_taps)
2173 return 0;
2174
2175 /*
2176 * Pixel data should be prepared before visible display point starts.
2177 * So, atleast DS-2 lines must have already been fetched by DISPC
2178 * during nonactive - pos_x period.
2179 */
2180 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
2181 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
2182 val, max(0, ds - 2) * width);
2183 if (val < max(0, ds - 2) * width)
2184 return -EINVAL;
2185
2186 /*
2187 * All lines need to be refilled during the nonactive period of which
2188 * only one line can be loaded during the active period. So, atleast
2189 * DS - 1 lines should be loaded during nonactive period.
2190 */
2191 val = div_u64((u64)nonactive * lclk, pclk);
2192 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
2193 val, max(0, ds - 1) * width);
2194 if (val < max(0, ds - 1) * width)
2195 return -EINVAL;
2196
2197 return 0;
2198}
2199
2200static unsigned long calc_core_clk_five_taps(unsigned long pclk,
2201 const struct omap_video_timings *mgr_timings, u16 width,
2202 u16 height, u16 out_width, u16 out_height,
2203 enum omap_color_mode color_mode)
2204{
2205 u32 core_clk = 0;
2206 u64 tmp;
2207
2208 if (height <= out_height && width <= out_width)
2209 return (unsigned long) pclk;
2210
2211 if (height > out_height) {
2212 unsigned int ppl = mgr_timings->x_res;
2213
2214 tmp = (u64)pclk * height * out_width;
2215 do_div(tmp, 2 * out_height * ppl);
2216 core_clk = tmp;
2217
2218 if (height > 2 * out_height) {
2219 if (ppl == out_width)
2220 return 0;
2221
2222 tmp = (u64)pclk * (height - 2 * out_height) * out_width;
2223 do_div(tmp, 2 * out_height * (ppl - out_width));
2224 core_clk = max_t(u32, core_clk, tmp);
2225 }
2226 }
2227
2228 if (width > out_width) {
2229 tmp = (u64)pclk * width;
2230 do_div(tmp, out_width);
2231 core_clk = max_t(u32, core_clk, tmp);
2232
2233 if (color_mode == OMAP_DSS_COLOR_RGB24U)
2234 core_clk <<= 1;
2235 }
2236
2237 return core_clk;
2238}
2239
2240static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
2241 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2242{
2243 if (height > out_height && width > out_width)
2244 return pclk * 4;
2245 else
2246 return pclk * 2;
2247}
2248
2249static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
2250 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2251{
2252 unsigned int hf, vf;
2253
2254 /*
2255 * FIXME how to determine the 'A' factor
2256 * for the no downscaling case ?
2257 */
2258
2259 if (width > 3 * out_width)
2260 hf = 4;
2261 else if (width > 2 * out_width)
2262 hf = 3;
2263 else if (width > out_width)
2264 hf = 2;
2265 else
2266 hf = 1;
2267 if (height > out_height)
2268 vf = 2;
2269 else
2270 vf = 1;
2271
2272 return pclk * vf * hf;
2273}
2274
2275static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
2276 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2277{
2278 /*
2279 * If the overlay/writeback is in mem to mem mode, there are no
2280 * downscaling limitations with respect to pixel clock, return 1 as
2281 * required core clock to represent that we have sufficient enough
2282 * core clock to do maximum downscaling
2283 */
2284 if (mem_to_mem)
2285 return 1;
2286
2287 if (width > out_width)
2288 return DIV_ROUND_UP(pclk, out_width) * width;
2289 else
2290 return pclk;
2291}
2292
2293static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
2294 const struct omap_video_timings *mgr_timings,
2295 u16 width, u16 height, u16 out_width, u16 out_height,
2296 enum omap_color_mode color_mode, bool *five_taps,
2297 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2298 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2299{
2300 int error;
2301 u16 in_width, in_height;
2302 int min_factor = min(*decim_x, *decim_y);
2303 const int maxsinglelinewidth =
2304 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2305
2306 *five_taps = false;
2307
2308 do {
2309 in_height = height / *decim_y;
2310 in_width = width / *decim_x;
2311 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
2312 in_height, out_width, out_height, mem_to_mem);
2313 error = (in_width > maxsinglelinewidth || !*core_clk ||
2314 *core_clk > dispc_core_clk_rate());
2315 if (error) {
2316 if (*decim_x == *decim_y) {
2317 *decim_x = min_factor;
2318 ++*decim_y;
2319 } else {
2320 swap(*decim_x, *decim_y);
2321 if (*decim_x < *decim_y)
2322 ++*decim_x;
2323 }
2324 }
2325 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2326
2327 if (error) {
2328 DSSERR("failed to find scaling settings\n");
2329 return -EINVAL;
2330 }
2331
2332 if (in_width > maxsinglelinewidth) {
2333 DSSERR("Cannot scale max input width exceeded");
2334 return -EINVAL;
2335 }
2336 return 0;
2337}
2338
2339static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
2340 const struct omap_video_timings *mgr_timings,
2341 u16 width, u16 height, u16 out_width, u16 out_height,
2342 enum omap_color_mode color_mode, bool *five_taps,
2343 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2344 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2345{
2346 int error;
2347 u16 in_width, in_height;
2348 const int maxsinglelinewidth =
2349 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2350
2351 do {
2352 in_height = height / *decim_y;
2353 in_width = width / *decim_x;
2354 *five_taps = in_height > out_height;
2355
2356 if (in_width > maxsinglelinewidth)
2357 if (in_height > out_height &&
2358 in_height < out_height * 2)
2359 *five_taps = false;
2360again:
2361 if (*five_taps)
2362 *core_clk = calc_core_clk_five_taps(pclk, mgr_timings,
2363 in_width, in_height, out_width,
2364 out_height, color_mode);
2365 else
2366 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
2367 in_height, out_width, out_height,
2368 mem_to_mem);
2369
2370 error = check_horiz_timing_omap3(pclk, lclk, mgr_timings,
2371 pos_x, in_width, in_height, out_width,
2372 out_height, *five_taps);
2373 if (error && *five_taps) {
2374 *five_taps = false;
2375 goto again;
2376 }
2377
2378 error = (error || in_width > maxsinglelinewidth * 2 ||
2379 (in_width > maxsinglelinewidth && *five_taps) ||
2380 !*core_clk || *core_clk > dispc_core_clk_rate());
2381
2382 if (!error) {
2383 /* verify that we're inside the limits of scaler */
2384 if (in_width / 4 > out_width)
2385 error = 1;
2386
2387 if (*five_taps) {
2388 if (in_height / 4 > out_height)
2389 error = 1;
2390 } else {
2391 if (in_height / 2 > out_height)
2392 error = 1;
2393 }
2394 }
2395
2396 if (error)
2397 ++*decim_y;
2398 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2399
2400 if (error) {
2401 DSSERR("failed to find scaling settings\n");
2402 return -EINVAL;
2403 }
2404
2405 if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width,
2406 in_height, out_width, out_height, *five_taps)) {
2407 DSSERR("horizontal timing too tight\n");
2408 return -EINVAL;
2409 }
2410
2411 if (in_width > (maxsinglelinewidth * 2)) {
2412 DSSERR("Cannot setup scaling");
2413 DSSERR("width exceeds maximum width possible");
2414 return -EINVAL;
2415 }
2416
2417 if (in_width > maxsinglelinewidth && *five_taps) {
2418 DSSERR("cannot setup scaling with five taps");
2419 return -EINVAL;
2420 }
2421 return 0;
2422}
2423
2424static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
2425 const struct omap_video_timings *mgr_timings,
2426 u16 width, u16 height, u16 out_width, u16 out_height,
2427 enum omap_color_mode color_mode, bool *five_taps,
2428 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2429 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2430{
2431 u16 in_width, in_width_max;
2432 int decim_x_min = *decim_x;
2433 u16 in_height = height / *decim_y;
2434 const int maxsinglelinewidth =
2435 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2436 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2437
2438 if (mem_to_mem) {
2439 in_width_max = out_width * maxdownscale;
2440 } else {
2441 in_width_max = dispc_core_clk_rate() /
2442 DIV_ROUND_UP(pclk, out_width);
2443 }
2444
2445 *decim_x = DIV_ROUND_UP(width, in_width_max);
2446
2447 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2448 if (*decim_x > *x_predecim)
2449 return -EINVAL;
2450
2451 do {
2452 in_width = width / *decim_x;
2453 } while (*decim_x <= *x_predecim &&
2454 in_width > maxsinglelinewidth && ++*decim_x);
2455
2456 if (in_width > maxsinglelinewidth) {
2457 DSSERR("Cannot scale width exceeds max line width");
2458 return -EINVAL;
2459 }
2460
2461 *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
2462 out_width, out_height, mem_to_mem);
2463 return 0;
2464}
2465
2466#define DIV_FRAC(dividend, divisor) \
2467 ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
2468
2469static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
2470 enum omap_overlay_caps caps,
2471 const struct omap_video_timings *mgr_timings,
2472 u16 width, u16 height, u16 out_width, u16 out_height,
2473 enum omap_color_mode color_mode, bool *five_taps,
2474 int *x_predecim, int *y_predecim, u16 pos_x,
2475 enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
2476{
2477 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2478 const int max_decim_limit = 16;
2479 unsigned long core_clk = 0;
2480 int decim_x, decim_y, ret;
2481
2482 if (width == out_width && height == out_height)
2483 return 0;
2484
2485 if (!mem_to_mem && (pclk == 0 || mgr_timings->pixelclock == 0)) {
2486 DSSERR("cannot calculate scaling settings: pclk is zero\n");
2487 return -EINVAL;
2488 }
2489
2490 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
2491 return -EINVAL;
2492
2493 if (mem_to_mem) {
2494 *x_predecim = *y_predecim = 1;
2495 } else {
2496 *x_predecim = max_decim_limit;
2497 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
2498 dss_has_feature(FEAT_BURST_2D)) ?
2499 2 : max_decim_limit;
2500 }
2501
2502 if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
2503 color_mode == OMAP_DSS_COLOR_CLUT2 ||
2504 color_mode == OMAP_DSS_COLOR_CLUT4 ||
2505 color_mode == OMAP_DSS_COLOR_CLUT8) {
2506 *x_predecim = 1;
2507 *y_predecim = 1;
2508 *five_taps = false;
2509 return 0;
2510 }
2511
2512 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2513 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2514
2515 if (decim_x > *x_predecim || out_width > width * 8)
2516 return -EINVAL;
2517
2518 if (decim_y > *y_predecim || out_height > height * 8)
2519 return -EINVAL;
2520
2521 ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height,
2522 out_width, out_height, color_mode, five_taps,
2523 x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2524 mem_to_mem);
2525 if (ret)
2526 return ret;
2527
2528 DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n",
2529 width, height,
2530 out_width, out_height,
2531 out_width / width, DIV_FRAC(out_width, width),
2532 out_height / height, DIV_FRAC(out_height, height),
2533
2534 decim_x, decim_y,
2535 width / decim_x, height / decim_y,
2536 out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
2537 out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
2538
2539 *five_taps ? 5 : 3,
2540 core_clk, dispc_core_clk_rate());
2541
2542 if (!core_clk || core_clk > dispc_core_clk_rate()) {
2543 DSSERR("failed to set up scaling, "
2544 "required core clk rate = %lu Hz, "
2545 "current core clk rate = %lu Hz\n",
2546 core_clk, dispc_core_clk_rate());
2547 return -EINVAL;
2548 }
2549
2550 *x_predecim = decim_x;
2551 *y_predecim = decim_y;
2552 return 0;
2553}
2554
2555int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
2556 const struct omap_overlay_info *oi,
2557 const struct omap_video_timings *timings,
2558 int *x_predecim, int *y_predecim)
2559{
2560 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
2561 bool five_taps = true;
2562 bool fieldmode = false;
2563 u16 in_height = oi->height;
2564 u16 in_width = oi->width;
2565 bool ilace = timings->interlace;
2566 u16 out_width, out_height;
2567 int pos_x = oi->pos_x;
2568 unsigned long pclk = dispc_mgr_pclk_rate(channel);
2569 unsigned long lclk = dispc_mgr_lclk_rate(channel);
2570
2571 out_width = oi->out_width == 0 ? oi->width : oi->out_width;
2572 out_height = oi->out_height == 0 ? oi->height : oi->out_height;
2573
2574 if (ilace && oi->height == out_height)
2575 fieldmode = true;
2576
2577 if (ilace) {
2578 if (fieldmode)
2579 in_height /= 2;
2580 out_height /= 2;
2581
2582 DSSDBG("adjusting for ilace: height %d, out_height %d\n",
2583 in_height, out_height);
2584 }
2585
2586 if (!dss_feat_color_mode_supported(plane, oi->color_mode))
2587 return -EINVAL;
2588
2589 return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width,
2590 in_height, out_width, out_height, oi->color_mode,
2591 &five_taps, x_predecim, y_predecim, pos_x,
2592 oi->rotation_type, false);
2593}
2594EXPORT_SYMBOL(dispc_ovl_check);
2595
2596static int dispc_ovl_setup_common(enum omap_plane plane,
2597 enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2598 u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
2599 u16 out_width, u16 out_height, enum omap_color_mode color_mode,
2600 u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
2601 u8 global_alpha, enum omap_dss_rotation_type rotation_type,
2602 bool replication, const struct omap_video_timings *mgr_timings,
2603 bool mem_to_mem)
2604{
2605 bool five_taps = true;
2606 bool fieldmode = false;
2607 int r, cconv = 0;
2608 unsigned offset0, offset1;
2609 s32 row_inc;
2610 s32 pix_inc;
2611 u16 frame_width, frame_height;
2612 unsigned int field_offset = 0;
2613 u16 in_height = height;
2614 u16 in_width = width;
2615 int x_predecim = 1, y_predecim = 1;
2616 bool ilace = mgr_timings->interlace;
2617 unsigned long pclk = dispc_plane_pclk_rate(plane);
2618 unsigned long lclk = dispc_plane_lclk_rate(plane);
2619
2620 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
2621 return -EINVAL;
2622
2623 switch (color_mode) {
2624 case OMAP_DSS_COLOR_YUV2:
2625 case OMAP_DSS_COLOR_UYVY:
2626 case OMAP_DSS_COLOR_NV12:
2627 if (in_width & 1) {
2628 DSSERR("input width %d is not even for YUV format\n",
2629 in_width);
2630 return -EINVAL;
2631 }
2632 break;
2633
2634 default:
2635 break;
2636 }
2637
2638 out_width = out_width == 0 ? width : out_width;
2639 out_height = out_height == 0 ? height : out_height;
2640
2641 if (ilace && height == out_height)
2642 fieldmode = true;
2643
2644 if (ilace) {
2645 if (fieldmode)
2646 in_height /= 2;
2647 pos_y /= 2;
2648 out_height /= 2;
2649
2650 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
2651 "out_height %d\n", in_height, pos_y,
2652 out_height);
2653 }
2654
2655 if (!dss_feat_color_mode_supported(plane, color_mode))
2656 return -EINVAL;
2657
2658 r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width,
2659 in_height, out_width, out_height, color_mode,
2660 &five_taps, &x_predecim, &y_predecim, pos_x,
2661 rotation_type, mem_to_mem);
2662 if (r)
2663 return r;
2664
2665 in_width = in_width / x_predecim;
2666 in_height = in_height / y_predecim;
2667
2668 if (x_predecim > 1 || y_predecim > 1)
2669 DSSDBG("predecimation %d x %x, new input size %d x %d\n",
2670 x_predecim, y_predecim, in_width, in_height);
2671
2672 switch (color_mode) {
2673 case OMAP_DSS_COLOR_YUV2:
2674 case OMAP_DSS_COLOR_UYVY:
2675 case OMAP_DSS_COLOR_NV12:
2676 if (in_width & 1) {
2677 DSSDBG("predecimated input width is not even for YUV format\n");
2678 DSSDBG("adjusting input width %d -> %d\n",
2679 in_width, in_width & ~1);
2680
2681 in_width &= ~1;
2682 }
2683 break;
2684
2685 default:
2686 break;
2687 }
2688
2689 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2690 color_mode == OMAP_DSS_COLOR_UYVY ||
2691 color_mode == OMAP_DSS_COLOR_NV12)
2692 cconv = 1;
2693
2694 if (ilace && !fieldmode) {
2695 /*
2696 * when downscaling the bottom field may have to start several
2697 * source lines below the top field. Unfortunately ACCUI
2698 * registers will only hold the fractional part of the offset
2699 * so the integer part must be added to the base address of the
2700 * bottom field.
2701 */
2702 if (!in_height || in_height == out_height)
2703 field_offset = 0;
2704 else
2705 field_offset = in_height / out_height / 2;
2706 }
2707
2708 /* Fields are independent but interleaved in memory. */
2709 if (fieldmode)
2710 field_offset = 1;
2711
2712 offset0 = 0;
2713 offset1 = 0;
2714 row_inc = 0;
2715 pix_inc = 0;
2716
2717 if (plane == OMAP_DSS_WB) {
2718 frame_width = out_width;
2719 frame_height = out_height;
2720 } else {
2721 frame_width = in_width;
2722 frame_height = height;
2723 }
2724
2725 if (rotation_type == OMAP_DSS_ROT_TILER)
2726 calc_tiler_rotation_offset(screen_width, frame_width,
2727 color_mode, fieldmode, field_offset,
2728 &offset0, &offset1, &row_inc, &pix_inc,
2729 x_predecim, y_predecim);
2730 else if (rotation_type == OMAP_DSS_ROT_DMA)
2731 calc_dma_rotation_offset(rotation, mirror, screen_width,
2732 frame_width, frame_height,
2733 color_mode, fieldmode, field_offset,
2734 &offset0, &offset1, &row_inc, &pix_inc,
2735 x_predecim, y_predecim);
2736 else
2737 calc_vrfb_rotation_offset(rotation, mirror,
2738 screen_width, frame_width, frame_height,
2739 color_mode, fieldmode, field_offset,
2740 &offset0, &offset1, &row_inc, &pix_inc,
2741 x_predecim, y_predecim);
2742
2743 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2744 offset0, offset1, row_inc, pix_inc);
2745
2746 dispc_ovl_set_color_mode(plane, color_mode);
2747
2748 dispc_ovl_configure_burst_type(plane, rotation_type);
2749
2750 dispc_ovl_set_ba0(plane, paddr + offset0);
2751 dispc_ovl_set_ba1(plane, paddr + offset1);
2752
2753 if (OMAP_DSS_COLOR_NV12 == color_mode) {
2754 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2755 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
2756 }
2757
2758 if (dispc.feat->last_pixel_inc_missing)
2759 row_inc += pix_inc - 1;
2760
2761 dispc_ovl_set_row_inc(plane, row_inc);
2762 dispc_ovl_set_pix_inc(plane, pix_inc);
2763
2764 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
2765 in_height, out_width, out_height);
2766
2767 dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
2768
2769 dispc_ovl_set_input_size(plane, in_width, in_height);
2770
2771 if (caps & OMAP_DSS_OVL_CAP_SCALE) {
2772 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2773 out_height, ilace, five_taps, fieldmode,
2774 color_mode, rotation);
2775 dispc_ovl_set_output_size(plane, out_width, out_height);
2776 dispc_ovl_set_vid_color_conv(plane, cconv);
2777 }
2778
2779 dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
2780 color_mode);
2781
2782 dispc_ovl_set_zorder(plane, caps, zorder);
2783 dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2784 dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
2785
2786 dispc_ovl_enable_replication(plane, caps, replication);
2787
2788 return 0;
2789}
2790
2791int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
2792 bool replication, const struct omap_video_timings *mgr_timings,
2793 bool mem_to_mem)
2794{
2795 int r;
2796 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
2797 enum omap_channel channel;
2798
2799 channel = dispc_ovl_get_channel_out(plane);
2800
2801 DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
2802 " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
2803 plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
2804 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
2805 oi->color_mode, oi->rotation, oi->mirror, channel, replication);
2806
2807 r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
2808 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
2809 oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
2810 oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
2811 oi->rotation_type, replication, mgr_timings, mem_to_mem);
2812
2813 return r;
2814}
2815EXPORT_SYMBOL(dispc_ovl_setup);
2816
2817int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
2818 bool mem_to_mem, const struct omap_video_timings *mgr_timings)
2819{
2820 int r;
2821 u32 l;
2822 enum omap_plane plane = OMAP_DSS_WB;
2823 const int pos_x = 0, pos_y = 0;
2824 const u8 zorder = 0, global_alpha = 0;
2825 const bool replication = false;
2826 bool truncation;
2827 int in_width = mgr_timings->x_res;
2828 int in_height = mgr_timings->y_res;
2829 enum omap_overlay_caps caps =
2830 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2831
2832 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
2833 "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
2834 in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
2835 wi->mirror);
2836
2837 r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2838 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
2839 wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
2840 wi->pre_mult_alpha, global_alpha, wi->rotation_type,
2841 replication, mgr_timings, mem_to_mem);
2842
2843 switch (wi->color_mode) {
2844 case OMAP_DSS_COLOR_RGB16:
2845 case OMAP_DSS_COLOR_RGB24P:
2846 case OMAP_DSS_COLOR_ARGB16:
2847 case OMAP_DSS_COLOR_RGBA16:
2848 case OMAP_DSS_COLOR_RGB12U:
2849 case OMAP_DSS_COLOR_ARGB16_1555:
2850 case OMAP_DSS_COLOR_XRGB16_1555:
2851 case OMAP_DSS_COLOR_RGBX16:
2852 truncation = true;
2853 break;
2854 default:
2855 truncation = false;
2856 break;
2857 }
2858
2859 /* setup extra DISPC_WB_ATTRIBUTES */
2860 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2861 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2862 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
2863 if (mem_to_mem)
2864 l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
2865 else
2866 l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
2867 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
2868
2869 if (mem_to_mem) {
2870 /* WBDELAYCOUNT */
2871 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
2872 } else {
2873 int wbdelay;
2874
2875 wbdelay = min(mgr_timings->vfp + mgr_timings->vsw +
2876 mgr_timings->vbp, 255);
2877
2878 /* WBDELAYCOUNT */
2879 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
2880 }
2881
2882 return r;
2883}
2884
2885int dispc_ovl_enable(enum omap_plane plane, bool enable)
2886{
2887 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2888
2889 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
2890
2891 return 0;
2892}
2893EXPORT_SYMBOL(dispc_ovl_enable);
2894
2895bool dispc_ovl_enabled(enum omap_plane plane)
2896{
2897 return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
2898}
2899EXPORT_SYMBOL(dispc_ovl_enabled);
2900
2901void dispc_mgr_enable(enum omap_channel channel, bool enable)
2902{
2903 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
2904 /* flush posted write */
2905 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2906}
2907EXPORT_SYMBOL(dispc_mgr_enable);
2908
2909bool dispc_mgr_is_enabled(enum omap_channel channel)
2910{
2911 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2912}
2913EXPORT_SYMBOL(dispc_mgr_is_enabled);
2914
2915void dispc_wb_enable(bool enable)
2916{
2917 dispc_ovl_enable(OMAP_DSS_WB, enable);
2918}
2919
2920bool dispc_wb_is_enabled(void)
2921{
2922 return dispc_ovl_enabled(OMAP_DSS_WB);
2923}
2924
2925static void dispc_lcd_enable_signal_polarity(bool act_high)
2926{
2927 if (!dss_has_feature(FEAT_LCDENABLEPOL))
2928 return;
2929
2930 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
2931}
2932
2933void dispc_lcd_enable_signal(bool enable)
2934{
2935 if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2936 return;
2937
2938 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
2939}
2940
2941void dispc_pck_free_enable(bool enable)
2942{
2943 if (!dss_has_feature(FEAT_PCKFREEENABLE))
2944 return;
2945
2946 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
2947}
2948
2949static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
2950{
2951 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
2952}
2953
2954
2955static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
2956{
2957 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
2958}
2959
2960static void dispc_set_loadmode(enum omap_dss_load_mode mode)
2961{
2962 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
2963}
2964
2965
2966static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
2967{
2968 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
2969}
2970
2971static void dispc_mgr_set_trans_key(enum omap_channel ch,
2972 enum omap_dss_trans_key_type type,
2973 u32 trans_key)
2974{
2975 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
2976
2977 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
2978}
2979
2980static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2981{
2982 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
2983}
2984
2985static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2986 bool enable)
2987{
2988 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
2989 return;
2990
2991 if (ch == OMAP_DSS_CHANNEL_LCD)
2992 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2993 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2994 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2995}
2996
2997void dispc_mgr_setup(enum omap_channel channel,
2998 const struct omap_overlay_manager_info *info)
2999{
3000 dispc_mgr_set_default_color(channel, info->default_color);
3001 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
3002 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
3003 dispc_mgr_enable_alpha_fixed_zorder(channel,
3004 info->partial_alpha_enabled);
3005 if (dss_has_feature(FEAT_CPR)) {
3006 dispc_mgr_enable_cpr(channel, info->cpr_enable);
3007 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
3008 }
3009}
3010EXPORT_SYMBOL(dispc_mgr_setup);
3011
3012static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
3013{
3014 int code;
3015
3016 switch (data_lines) {
3017 case 12:
3018 code = 0;
3019 break;
3020 case 16:
3021 code = 1;
3022 break;
3023 case 18:
3024 code = 2;
3025 break;
3026 case 24:
3027 code = 3;
3028 break;
3029 default:
3030 BUG();
3031 return;
3032 }
3033
3034 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
3035}
3036
3037static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
3038{
3039 u32 l;
3040 int gpout0, gpout1;
3041
3042 switch (mode) {
3043 case DSS_IO_PAD_MODE_RESET:
3044 gpout0 = 0;
3045 gpout1 = 0;
3046 break;
3047 case DSS_IO_PAD_MODE_RFBI:
3048 gpout0 = 1;
3049 gpout1 = 0;
3050 break;
3051 case DSS_IO_PAD_MODE_BYPASS:
3052 gpout0 = 1;
3053 gpout1 = 1;
3054 break;
3055 default:
3056 BUG();
3057 return;
3058 }
3059
3060 l = dispc_read_reg(DISPC_CONTROL);
3061 l = FLD_MOD(l, gpout0, 15, 15);
3062 l = FLD_MOD(l, gpout1, 16, 16);
3063 dispc_write_reg(DISPC_CONTROL, l);
3064}
3065
3066static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
3067{
3068 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
3069}
3070
3071void dispc_mgr_set_lcd_config(enum omap_channel channel,
3072 const struct dss_lcd_mgr_config *config)
3073{
3074 dispc_mgr_set_io_pad_mode(config->io_pad_mode);
3075
3076 dispc_mgr_enable_stallmode(channel, config->stallmode);
3077 dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
3078
3079 dispc_mgr_set_clock_div(channel, &config->clock_info);
3080
3081 dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
3082
3083 dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
3084
3085 dispc_mgr_set_lcd_type_tft(channel);
3086}
3087EXPORT_SYMBOL(dispc_mgr_set_lcd_config);
3088
3089static bool _dispc_mgr_size_ok(u16 width, u16 height)
3090{
3091 return width <= dispc.feat->mgr_width_max &&
3092 height <= dispc.feat->mgr_height_max;
3093}
3094
3095static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
3096 int vsw, int vfp, int vbp)
3097{
3098 if (hsw < 1 || hsw > dispc.feat->sw_max ||
3099 hfp < 1 || hfp > dispc.feat->hp_max ||
3100 hbp < 1 || hbp > dispc.feat->hp_max ||
3101 vsw < 1 || vsw > dispc.feat->sw_max ||
3102 vfp < 0 || vfp > dispc.feat->vp_max ||
3103 vbp < 0 || vbp > dispc.feat->vp_max)
3104 return false;
3105 return true;
3106}
3107
3108static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
3109 unsigned long pclk)
3110{
3111 if (dss_mgr_is_lcd(channel))
3112 return pclk <= dispc.feat->max_lcd_pclk ? true : false;
3113 else
3114 return pclk <= dispc.feat->max_tv_pclk ? true : false;
3115}
3116
3117bool dispc_mgr_timings_ok(enum omap_channel channel,
3118 const struct omap_video_timings *timings)
3119{
3120 if (!_dispc_mgr_size_ok(timings->x_res, timings->y_res))
3121 return false;
3122
3123 if (!_dispc_mgr_pclk_ok(channel, timings->pixelclock))
3124 return false;
3125
3126 if (dss_mgr_is_lcd(channel)) {
3127 /* TODO: OMAP4+ supports interlace for LCD outputs */
3128 if (timings->interlace)
3129 return false;
3130
3131 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
3132 timings->hbp, timings->vsw, timings->vfp,
3133 timings->vbp))
3134 return false;
3135 }
3136
3137 return true;
3138}
3139
3140static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
3141 int hfp, int hbp, int vsw, int vfp, int vbp,
3142 enum omap_dss_signal_level vsync_level,
3143 enum omap_dss_signal_level hsync_level,
3144 enum omap_dss_signal_edge data_pclk_edge,
3145 enum omap_dss_signal_level de_level,
3146 enum omap_dss_signal_edge sync_pclk_edge)
3147
3148{
3149 u32 timing_h, timing_v, l;
3150 bool onoff, rf, ipc, vs, hs, de;
3151
3152 timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
3153 FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
3154 FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
3155 timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
3156 FLD_VAL(vfp, dispc.feat->fp_start, 8) |
3157 FLD_VAL(vbp, dispc.feat->bp_start, 20);
3158
3159 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
3160 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
3161
3162 switch (vsync_level) {
3163 case OMAPDSS_SIG_ACTIVE_LOW:
3164 vs = true;
3165 break;
3166 case OMAPDSS_SIG_ACTIVE_HIGH:
3167 vs = false;
3168 break;
3169 default:
3170 BUG();
3171 }
3172
3173 switch (hsync_level) {
3174 case OMAPDSS_SIG_ACTIVE_LOW:
3175 hs = true;
3176 break;
3177 case OMAPDSS_SIG_ACTIVE_HIGH:
3178 hs = false;
3179 break;
3180 default:
3181 BUG();
3182 }
3183
3184 switch (de_level) {
3185 case OMAPDSS_SIG_ACTIVE_LOW:
3186 de = true;
3187 break;
3188 case OMAPDSS_SIG_ACTIVE_HIGH:
3189 de = false;
3190 break;
3191 default:
3192 BUG();
3193 }
3194
3195 switch (data_pclk_edge) {
3196 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
3197 ipc = false;
3198 break;
3199 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
3200 ipc = true;
3201 break;
3202 default:
3203 BUG();
3204 }
3205
3206 /* always use the 'rf' setting */
3207 onoff = true;
3208
3209 switch (sync_pclk_edge) {
3210 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
3211 rf = false;
3212 break;
3213 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
3214 rf = true;
3215 break;
3216 default:
3217 BUG();
3218 }
3219
3220 l = FLD_VAL(onoff, 17, 17) |
3221 FLD_VAL(rf, 16, 16) |
3222 FLD_VAL(de, 15, 15) |
3223 FLD_VAL(ipc, 14, 14) |
3224 FLD_VAL(hs, 13, 13) |
3225 FLD_VAL(vs, 12, 12);
3226
3227 /* always set ALIGN bit when available */
3228 if (dispc.feat->supports_sync_align)
3229 l |= (1 << 18);
3230
3231 dispc_write_reg(DISPC_POL_FREQ(channel), l);
3232
3233 if (dispc.syscon_pol) {
3234 const int shifts[] = {
3235 [OMAP_DSS_CHANNEL_LCD] = 0,
3236 [OMAP_DSS_CHANNEL_LCD2] = 1,
3237 [OMAP_DSS_CHANNEL_LCD3] = 2,
3238 };
3239
3240 u32 mask, val;
3241
3242 mask = (1 << 0) | (1 << 3) | (1 << 6);
3243 val = (rf << 0) | (ipc << 3) | (onoff << 6);
3244
3245 mask <<= 16 + shifts[channel];
3246 val <<= 16 + shifts[channel];
3247
3248 regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
3249 mask, val);
3250 }
3251}
3252
3253/* change name to mode? */
3254void dispc_mgr_set_timings(enum omap_channel channel,
3255 const struct omap_video_timings *timings)
3256{
3257 unsigned xtot, ytot;
3258 unsigned long ht, vt;
3259 struct omap_video_timings t = *timings;
3260
3261 DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
3262
3263 if (!dispc_mgr_timings_ok(channel, &t)) {
3264 BUG();
3265 return;
3266 }
3267
3268 if (dss_mgr_is_lcd(channel)) {
3269 _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
3270 t.vfp, t.vbp, t.vsync_level, t.hsync_level,
3271 t.data_pclk_edge, t.de_level, t.sync_pclk_edge);
3272
3273 xtot = t.x_res + t.hfp + t.hsw + t.hbp;
3274 ytot = t.y_res + t.vfp + t.vsw + t.vbp;
3275
3276 ht = timings->pixelclock / xtot;
3277 vt = timings->pixelclock / xtot / ytot;
3278
3279 DSSDBG("pck %u\n", timings->pixelclock);
3280 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
3281 t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
3282 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
3283 t.vsync_level, t.hsync_level, t.data_pclk_edge,
3284 t.de_level, t.sync_pclk_edge);
3285
3286 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
3287 } else {
3288 if (t.interlace)
3289 t.y_res /= 2;
3290 }
3291
3292 dispc_mgr_set_size(channel, t.x_res, t.y_res);
3293}
3294EXPORT_SYMBOL(dispc_mgr_set_timings);
3295
3296static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
3297 u16 pck_div)
3298{
3299 BUG_ON(lck_div < 1);
3300 BUG_ON(pck_div < 1);
3301
3302 dispc_write_reg(DISPC_DIVISORo(channel),
3303 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
3304
3305 if (!dss_has_feature(FEAT_CORE_CLK_DIV) &&
3306 channel == OMAP_DSS_CHANNEL_LCD)
3307 dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
3308}
3309
3310static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
3311 int *pck_div)
3312{
3313 u32 l;
3314 l = dispc_read_reg(DISPC_DIVISORo(channel));
3315 *lck_div = FLD_GET(l, 23, 16);
3316 *pck_div = FLD_GET(l, 7, 0);
3317}
3318
3319static unsigned long dispc_fclk_rate(void)
3320{
3321 struct dss_pll *pll;
3322 unsigned long r = 0;
3323
3324 switch (dss_get_dispc_clk_source()) {
3325 case OMAP_DSS_CLK_SRC_FCK:
3326 r = dss_get_dispc_clk_rate();
3327 break;
3328 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
3329 pll = dss_pll_find("dsi0");
3330 if (!pll)
3331 pll = dss_pll_find("video0");
3332
3333 r = pll->cinfo.clkout[0];
3334 break;
3335 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
3336 pll = dss_pll_find("dsi1");
3337 if (!pll)
3338 pll = dss_pll_find("video1");
3339
3340 r = pll->cinfo.clkout[0];
3341 break;
3342 default:
3343 BUG();
3344 return 0;
3345 }
3346
3347 return r;
3348}
3349
3350static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
3351{
3352 struct dss_pll *pll;
3353 int lcd;
3354 unsigned long r;
3355 u32 l;
3356
3357 if (dss_mgr_is_lcd(channel)) {
3358 l = dispc_read_reg(DISPC_DIVISORo(channel));
3359
3360 lcd = FLD_GET(l, 23, 16);
3361
3362 switch (dss_get_lcd_clk_source(channel)) {
3363 case OMAP_DSS_CLK_SRC_FCK:
3364 r = dss_get_dispc_clk_rate();
3365 break;
3366 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
3367 pll = dss_pll_find("dsi0");
3368 if (!pll)
3369 pll = dss_pll_find("video0");
3370
3371 r = pll->cinfo.clkout[0];
3372 break;
3373 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
3374 pll = dss_pll_find("dsi1");
3375 if (!pll)
3376 pll = dss_pll_find("video1");
3377
3378 r = pll->cinfo.clkout[0];
3379 break;
3380 default:
3381 BUG();
3382 return 0;
3383 }
3384
3385 return r / lcd;
3386 } else {
3387 return dispc_fclk_rate();
3388 }
3389}
3390
3391static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
3392{
3393 unsigned long r;
3394
3395 if (dss_mgr_is_lcd(channel)) {
3396 int pcd;
3397 u32 l;
3398
3399 l = dispc_read_reg(DISPC_DIVISORo(channel));
3400
3401 pcd = FLD_GET(l, 7, 0);
3402
3403 r = dispc_mgr_lclk_rate(channel);
3404
3405 return r / pcd;
3406 } else {
3407 return dispc.tv_pclk_rate;
3408 }
3409}
3410
3411void dispc_set_tv_pclk(unsigned long pclk)
3412{
3413 dispc.tv_pclk_rate = pclk;
3414}
3415
3416static unsigned long dispc_core_clk_rate(void)
3417{
3418 return dispc.core_clk_rate;
3419}
3420
3421static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
3422{
3423 enum omap_channel channel;
3424
3425 if (plane == OMAP_DSS_WB)
3426 return 0;
3427
3428 channel = dispc_ovl_get_channel_out(plane);
3429
3430 return dispc_mgr_pclk_rate(channel);
3431}
3432
3433static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
3434{
3435 enum omap_channel channel;
3436
3437 if (plane == OMAP_DSS_WB)
3438 return 0;
3439
3440 channel = dispc_ovl_get_channel_out(plane);
3441
3442 return dispc_mgr_lclk_rate(channel);
3443}
3444
3445static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
3446{
3447 int lcd, pcd;
3448 enum omap_dss_clk_source lcd_clk_src;
3449
3450 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3451
3452 lcd_clk_src = dss_get_lcd_clk_source(channel);
3453
3454 seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name,
3455 dss_get_generic_clk_source_name(lcd_clk_src),
3456 dss_feat_get_clk_source_name(lcd_clk_src));
3457
3458 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3459
3460 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3461 dispc_mgr_lclk_rate(channel), lcd);
3462 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3463 dispc_mgr_pclk_rate(channel), pcd);
3464}
3465
3466void dispc_dump_clocks(struct seq_file *s)
3467{
3468 int lcd;
3469 u32 l;
3470 enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
3471
3472 if (dispc_runtime_get())
3473 return;
3474
3475 seq_printf(s, "- DISPC -\n");
3476
3477 seq_printf(s, "dispc fclk source = %s (%s)\n",
3478 dss_get_generic_clk_source_name(dispc_clk_src),
3479 dss_feat_get_clk_source_name(dispc_clk_src));
3480
3481 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
3482
3483 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3484 seq_printf(s, "- DISPC-CORE-CLK -\n");
3485 l = dispc_read_reg(DISPC_DIVISOR);
3486 lcd = FLD_GET(l, 23, 16);
3487
3488 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3489 (dispc_fclk_rate()/lcd), lcd);
3490 }
3491
3492 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
3493
3494 if (dss_has_feature(FEAT_MGR_LCD2))
3495 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
3496 if (dss_has_feature(FEAT_MGR_LCD3))
3497 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
3498
3499 dispc_runtime_put();
3500}
3501
3502static void dispc_dump_regs(struct seq_file *s)
3503{
3504 int i, j;
3505 const char *mgr_names[] = {
3506 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3507 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3508 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
3509 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
3510 };
3511 const char *ovl_names[] = {
3512 [OMAP_DSS_GFX] = "GFX",
3513 [OMAP_DSS_VIDEO1] = "VID1",
3514 [OMAP_DSS_VIDEO2] = "VID2",
3515 [OMAP_DSS_VIDEO3] = "VID3",
3516 [OMAP_DSS_WB] = "WB",
3517 };
3518 const char **p_names;
3519
3520#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
3521
3522 if (dispc_runtime_get())
3523 return;
3524
3525 /* DISPC common registers */
3526 DUMPREG(DISPC_REVISION);
3527 DUMPREG(DISPC_SYSCONFIG);
3528 DUMPREG(DISPC_SYSSTATUS);
3529 DUMPREG(DISPC_IRQSTATUS);
3530 DUMPREG(DISPC_IRQENABLE);
3531 DUMPREG(DISPC_CONTROL);
3532 DUMPREG(DISPC_CONFIG);
3533 DUMPREG(DISPC_CAPABLE);
3534 DUMPREG(DISPC_LINE_STATUS);
3535 DUMPREG(DISPC_LINE_NUMBER);
3536 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3537 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
3538 DUMPREG(DISPC_GLOBAL_ALPHA);
3539 if (dss_has_feature(FEAT_MGR_LCD2)) {
3540 DUMPREG(DISPC_CONTROL2);
3541 DUMPREG(DISPC_CONFIG2);
3542 }
3543 if (dss_has_feature(FEAT_MGR_LCD3)) {
3544 DUMPREG(DISPC_CONTROL3);
3545 DUMPREG(DISPC_CONFIG3);
3546 }
3547 if (dss_has_feature(FEAT_MFLAG))
3548 DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
3549
3550#undef DUMPREG
3551
3552#define DISPC_REG(i, name) name(i)
3553#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
3554 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
3555 dispc_read_reg(DISPC_REG(i, r)))
3556
3557 p_names = mgr_names;
3558
3559 /* DISPC channel specific registers */
3560 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3561 DUMPREG(i, DISPC_DEFAULT_COLOR);
3562 DUMPREG(i, DISPC_TRANS_COLOR);
3563 DUMPREG(i, DISPC_SIZE_MGR);
3564
3565 if (i == OMAP_DSS_CHANNEL_DIGIT)
3566 continue;
3567
3568 DUMPREG(i, DISPC_TIMING_H);
3569 DUMPREG(i, DISPC_TIMING_V);
3570 DUMPREG(i, DISPC_POL_FREQ);
3571 DUMPREG(i, DISPC_DIVISORo);
3572
3573 DUMPREG(i, DISPC_DATA_CYCLE1);
3574 DUMPREG(i, DISPC_DATA_CYCLE2);
3575 DUMPREG(i, DISPC_DATA_CYCLE3);
3576
3577 if (dss_has_feature(FEAT_CPR)) {
3578 DUMPREG(i, DISPC_CPR_COEF_R);
3579 DUMPREG(i, DISPC_CPR_COEF_G);
3580 DUMPREG(i, DISPC_CPR_COEF_B);
3581 }
3582 }
3583
3584 p_names = ovl_names;
3585
3586 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3587 DUMPREG(i, DISPC_OVL_BA0);
3588 DUMPREG(i, DISPC_OVL_BA1);
3589 DUMPREG(i, DISPC_OVL_POSITION);
3590 DUMPREG(i, DISPC_OVL_SIZE);
3591 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3592 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3593 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3594 DUMPREG(i, DISPC_OVL_ROW_INC);
3595 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3596
3597 if (dss_has_feature(FEAT_PRELOAD))
3598 DUMPREG(i, DISPC_OVL_PRELOAD);
3599 if (dss_has_feature(FEAT_MFLAG))
3600 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3601
3602 if (i == OMAP_DSS_GFX) {
3603 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3604 DUMPREG(i, DISPC_OVL_TABLE_BA);
3605 continue;
3606 }
3607
3608 DUMPREG(i, DISPC_OVL_FIR);
3609 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3610 DUMPREG(i, DISPC_OVL_ACCU0);
3611 DUMPREG(i, DISPC_OVL_ACCU1);
3612 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3613 DUMPREG(i, DISPC_OVL_BA0_UV);
3614 DUMPREG(i, DISPC_OVL_BA1_UV);
3615 DUMPREG(i, DISPC_OVL_FIR2);
3616 DUMPREG(i, DISPC_OVL_ACCU2_0);
3617 DUMPREG(i, DISPC_OVL_ACCU2_1);
3618 }
3619 if (dss_has_feature(FEAT_ATTR2))
3620 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3621 }
3622
3623 if (dispc.feat->has_writeback) {
3624 i = OMAP_DSS_WB;
3625 DUMPREG(i, DISPC_OVL_BA0);
3626 DUMPREG(i, DISPC_OVL_BA1);
3627 DUMPREG(i, DISPC_OVL_SIZE);
3628 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3629 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3630 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3631 DUMPREG(i, DISPC_OVL_ROW_INC);
3632 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3633
3634 if (dss_has_feature(FEAT_MFLAG))
3635 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3636
3637 DUMPREG(i, DISPC_OVL_FIR);
3638 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3639 DUMPREG(i, DISPC_OVL_ACCU0);
3640 DUMPREG(i, DISPC_OVL_ACCU1);
3641 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3642 DUMPREG(i, DISPC_OVL_BA0_UV);
3643 DUMPREG(i, DISPC_OVL_BA1_UV);
3644 DUMPREG(i, DISPC_OVL_FIR2);
3645 DUMPREG(i, DISPC_OVL_ACCU2_0);
3646 DUMPREG(i, DISPC_OVL_ACCU2_1);
3647 }
3648 if (dss_has_feature(FEAT_ATTR2))
3649 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3650 }
3651
3652#undef DISPC_REG
3653#undef DUMPREG
3654
3655#define DISPC_REG(plane, name, i) name(plane, i)
3656#define DUMPREG(plane, name, i) \
3657 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
3658 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
3659 dispc_read_reg(DISPC_REG(plane, name, i)))
3660
3661 /* Video pipeline coefficient registers */
3662
3663 /* start from OMAP_DSS_VIDEO1 */
3664 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3665 for (j = 0; j < 8; j++)
3666 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
3667
3668 for (j = 0; j < 8; j++)
3669 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
3670
3671 for (j = 0; j < 5; j++)
3672 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
3673
3674 if (dss_has_feature(FEAT_FIR_COEF_V)) {
3675 for (j = 0; j < 8; j++)
3676 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3677 }
3678
3679 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3680 for (j = 0; j < 8; j++)
3681 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
3682
3683 for (j = 0; j < 8; j++)
3684 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
3685
3686 for (j = 0; j < 8; j++)
3687 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3688 }
3689 }
3690
3691 dispc_runtime_put();
3692
3693#undef DISPC_REG
3694#undef DUMPREG
3695}
3696
3697/* calculate clock rates using dividers in cinfo */
3698int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
3699 struct dispc_clock_info *cinfo)
3700{
3701 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3702 return -EINVAL;
3703 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
3704 return -EINVAL;
3705
3706 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3707 cinfo->pck = cinfo->lck / cinfo->pck_div;
3708
3709 return 0;
3710}
3711
3712bool dispc_div_calc(unsigned long dispc,
3713 unsigned long pck_min, unsigned long pck_max,
3714 dispc_div_calc_func func, void *data)
3715{
3716 int lckd, lckd_start, lckd_stop;
3717 int pckd, pckd_start, pckd_stop;
3718 unsigned long pck, lck;
3719 unsigned long lck_max;
3720 unsigned long pckd_hw_min, pckd_hw_max;
3721 unsigned min_fck_per_pck;
3722 unsigned long fck;
3723
3724#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
3725 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
3726#else
3727 min_fck_per_pck = 0;
3728#endif
3729
3730 pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
3731 pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
3732
3733 lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
3734
3735 pck_min = pck_min ? pck_min : 1;
3736 pck_max = pck_max ? pck_max : ULONG_MAX;
3737
3738 lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
3739 lckd_stop = min(dispc / pck_min, 255ul);
3740
3741 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
3742 lck = dispc / lckd;
3743
3744 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
3745 pckd_stop = min(lck / pck_min, pckd_hw_max);
3746
3747 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
3748 pck = lck / pckd;
3749
3750 /*
3751 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
3752 * clock, which means we're configuring DISPC fclk here
3753 * also. Thus we need to use the calculated lck. For
3754 * OMAP4+ the DISPC fclk is a separate clock.
3755 */
3756 if (dss_has_feature(FEAT_CORE_CLK_DIV))
3757 fck = dispc_core_clk_rate();
3758 else
3759 fck = lck;
3760
3761 if (fck < pck * min_fck_per_pck)
3762 continue;
3763
3764 if (func(lckd, pckd, lck, pck, data))
3765 return true;
3766 }
3767 }
3768
3769 return false;
3770}
3771
3772void dispc_mgr_set_clock_div(enum omap_channel channel,
3773 const struct dispc_clock_info *cinfo)
3774{
3775 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3776 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3777
3778 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
3779}
3780
3781int dispc_mgr_get_clock_div(enum omap_channel channel,
3782 struct dispc_clock_info *cinfo)
3783{
3784 unsigned long fck;
3785
3786 fck = dispc_fclk_rate();
3787
3788 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3789 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
3790
3791 cinfo->lck = fck / cinfo->lck_div;
3792 cinfo->pck = cinfo->lck / cinfo->pck_div;
3793
3794 return 0;
3795}
3796
3797u32 dispc_read_irqstatus(void)
3798{
3799 return dispc_read_reg(DISPC_IRQSTATUS);
3800}
3801EXPORT_SYMBOL(dispc_read_irqstatus);
3802
3803void dispc_clear_irqstatus(u32 mask)
3804{
3805 dispc_write_reg(DISPC_IRQSTATUS, mask);
3806}
3807EXPORT_SYMBOL(dispc_clear_irqstatus);
3808
3809u32 dispc_read_irqenable(void)
3810{
3811 return dispc_read_reg(DISPC_IRQENABLE);
3812}
3813EXPORT_SYMBOL(dispc_read_irqenable);
3814
3815void dispc_write_irqenable(u32 mask)
3816{
3817 u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3818
3819 /* clear the irqstatus for newly enabled irqs */
3820 dispc_clear_irqstatus((mask ^ old_mask) & mask);
3821
3822 dispc_write_reg(DISPC_IRQENABLE, mask);
3823}
3824EXPORT_SYMBOL(dispc_write_irqenable);
3825
3826void dispc_enable_sidle(void)
3827{
3828 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3829}
3830
3831void dispc_disable_sidle(void)
3832{
3833 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3834}
3835
3836static void _omap_dispc_initial_config(void)
3837{
3838 u32 l;
3839
3840 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3841 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3842 l = dispc_read_reg(DISPC_DIVISOR);
3843 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3844 l = FLD_MOD(l, 1, 0, 0);
3845 l = FLD_MOD(l, 1, 23, 16);
3846 dispc_write_reg(DISPC_DIVISOR, l);
3847
3848 dispc.core_clk_rate = dispc_fclk_rate();
3849 }
3850
3851 /* FUNCGATED */
3852 if (dss_has_feature(FEAT_FUNCGATED))
3853 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3854
3855 dispc_setup_color_conv_coef();
3856
3857 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3858
3859 dispc_init_fifos();
3860
3861 dispc_configure_burst_sizes();
3862
3863 dispc_ovl_enable_zorder_planes();
3864
3865 if (dispc.feat->mstandby_workaround)
3866 REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
3867
3868 if (dss_has_feature(FEAT_MFLAG))
3869 dispc_init_mflag();
3870}
3871
3872static const struct dispc_features omap24xx_dispc_feats = {
3873 .sw_start = 5,
3874 .fp_start = 15,
3875 .bp_start = 27,
3876 .sw_max = 64,
3877 .vp_max = 255,
3878 .hp_max = 256,
3879 .mgr_width_start = 10,
3880 .mgr_height_start = 26,
3881 .mgr_width_max = 2048,
3882 .mgr_height_max = 2048,
3883 .max_lcd_pclk = 66500000,
3884 .calc_scaling = dispc_ovl_calc_scaling_24xx,
3885 .calc_core_clk = calc_core_clk_24xx,
3886 .num_fifos = 3,
3887 .no_framedone_tv = true,
3888 .set_max_preload = false,
3889 .last_pixel_inc_missing = true,
3890};
3891
3892static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
3893 .sw_start = 5,
3894 .fp_start = 15,
3895 .bp_start = 27,
3896 .sw_max = 64,
3897 .vp_max = 255,
3898 .hp_max = 256,
3899 .mgr_width_start = 10,
3900 .mgr_height_start = 26,
3901 .mgr_width_max = 2048,
3902 .mgr_height_max = 2048,
3903 .max_lcd_pclk = 173000000,
3904 .max_tv_pclk = 59000000,
3905 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3906 .calc_core_clk = calc_core_clk_34xx,
3907 .num_fifos = 3,
3908 .no_framedone_tv = true,
3909 .set_max_preload = false,
3910 .last_pixel_inc_missing = true,
3911};
3912
3913static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
3914 .sw_start = 7,
3915 .fp_start = 19,
3916 .bp_start = 31,
3917 .sw_max = 256,
3918 .vp_max = 4095,
3919 .hp_max = 4096,
3920 .mgr_width_start = 10,
3921 .mgr_height_start = 26,
3922 .mgr_width_max = 2048,
3923 .mgr_height_max = 2048,
3924 .max_lcd_pclk = 173000000,
3925 .max_tv_pclk = 59000000,
3926 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3927 .calc_core_clk = calc_core_clk_34xx,
3928 .num_fifos = 3,
3929 .no_framedone_tv = true,
3930 .set_max_preload = false,
3931 .last_pixel_inc_missing = true,
3932};
3933
3934static const struct dispc_features omap44xx_dispc_feats = {
3935 .sw_start = 7,
3936 .fp_start = 19,
3937 .bp_start = 31,
3938 .sw_max = 256,
3939 .vp_max = 4095,
3940 .hp_max = 4096,
3941 .mgr_width_start = 10,
3942 .mgr_height_start = 26,
3943 .mgr_width_max = 2048,
3944 .mgr_height_max = 2048,
3945 .max_lcd_pclk = 170000000,
3946 .max_tv_pclk = 185625000,
3947 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3948 .calc_core_clk = calc_core_clk_44xx,
3949 .num_fifos = 5,
3950 .gfx_fifo_workaround = true,
3951 .set_max_preload = true,
3952 .supports_sync_align = true,
3953 .has_writeback = true,
3954};
3955
3956static const struct dispc_features omap54xx_dispc_feats = {
3957 .sw_start = 7,
3958 .fp_start = 19,
3959 .bp_start = 31,
3960 .sw_max = 256,
3961 .vp_max = 4095,
3962 .hp_max = 4096,
3963 .mgr_width_start = 11,
3964 .mgr_height_start = 27,
3965 .mgr_width_max = 4096,
3966 .mgr_height_max = 4096,
3967 .max_lcd_pclk = 170000000,
3968 .max_tv_pclk = 186000000,
3969 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3970 .calc_core_clk = calc_core_clk_44xx,
3971 .num_fifos = 5,
3972 .gfx_fifo_workaround = true,
3973 .mstandby_workaround = true,
3974 .set_max_preload = true,
3975 .supports_sync_align = true,
3976 .has_writeback = true,
3977};
3978
3979static int dispc_init_features(struct platform_device *pdev)
3980{
3981 const struct dispc_features *src;
3982 struct dispc_features *dst;
3983
3984 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
3985 if (!dst) {
3986 dev_err(&pdev->dev, "Failed to allocate DISPC Features\n");
3987 return -ENOMEM;
3988 }
3989
3990 switch (omapdss_get_version()) {
3991 case OMAPDSS_VER_OMAP24xx:
3992 src = &omap24xx_dispc_feats;
3993 break;
3994
3995 case OMAPDSS_VER_OMAP34xx_ES1:
3996 src = &omap34xx_rev1_0_dispc_feats;
3997 break;
3998
3999 case OMAPDSS_VER_OMAP34xx_ES3:
4000 case OMAPDSS_VER_OMAP3630:
4001 case OMAPDSS_VER_AM35xx:
4002 case OMAPDSS_VER_AM43xx:
4003 src = &omap34xx_rev3_0_dispc_feats;
4004 break;
4005
4006 case OMAPDSS_VER_OMAP4430_ES1:
4007 case OMAPDSS_VER_OMAP4430_ES2:
4008 case OMAPDSS_VER_OMAP4:
4009 src = &omap44xx_dispc_feats;
4010 break;
4011
4012 case OMAPDSS_VER_OMAP5:
4013 case OMAPDSS_VER_DRA7xx:
4014 src = &omap54xx_dispc_feats;
4015 break;
4016
4017 default:
4018 return -ENODEV;
4019 }
4020
4021 memcpy(dst, src, sizeof(*dst));
4022 dispc.feat = dst;
4023
4024 return 0;
4025}
4026
4027static irqreturn_t dispc_irq_handler(int irq, void *arg)
4028{
4029 if (!dispc.is_enabled)
4030 return IRQ_NONE;
4031
4032 return dispc.user_handler(irq, dispc.user_data);
4033}
4034
4035int dispc_request_irq(irq_handler_t handler, void *dev_id)
4036{
4037 int r;
4038
4039 if (dispc.user_handler != NULL)
4040 return -EBUSY;
4041
4042 dispc.user_handler = handler;
4043 dispc.user_data = dev_id;
4044
4045 /* ensure the dispc_irq_handler sees the values above */
4046 smp_wmb();
4047
4048 r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
4049 IRQF_SHARED, "OMAP DISPC", &dispc);
4050 if (r) {
4051 dispc.user_handler = NULL;
4052 dispc.user_data = NULL;
4053 }
4054
4055 return r;
4056}
4057EXPORT_SYMBOL(dispc_request_irq);
4058
4059void dispc_free_irq(void *dev_id)
4060{
4061 devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
4062
4063 dispc.user_handler = NULL;
4064 dispc.user_data = NULL;
4065}
4066EXPORT_SYMBOL(dispc_free_irq);
4067
4068/* DISPC HW IP initialisation */
4069static int dispc_bind(struct device *dev, struct device *master, void *data)
4070{
4071 struct platform_device *pdev = to_platform_device(dev);
4072 u32 rev;
4073 int r = 0;
4074 struct resource *dispc_mem;
4075 struct device_node *np = pdev->dev.of_node;
4076
4077 dispc.pdev = pdev;
4078
4079 spin_lock_init(&dispc.control_lock);
4080
4081 r = dispc_init_features(dispc.pdev);
4082 if (r)
4083 return r;
4084
4085 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
4086 if (!dispc_mem) {
4087 DSSERR("can't get IORESOURCE_MEM DISPC\n");
4088 return -EINVAL;
4089 }
4090
4091 dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
4092 resource_size(dispc_mem));
4093 if (!dispc.base) {
4094 DSSERR("can't ioremap DISPC\n");
4095 return -ENOMEM;
4096 }
4097
4098 dispc.irq = platform_get_irq(dispc.pdev, 0);
4099 if (dispc.irq < 0) {
4100 DSSERR("platform_get_irq failed\n");
4101 return -ENODEV;
4102 }
4103
4104 if (np && of_property_read_bool(np, "syscon-pol")) {
4105 dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
4106 if (IS_ERR(dispc.syscon_pol)) {
4107 dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
4108 return PTR_ERR(dispc.syscon_pol);
4109 }
4110
4111 if (of_property_read_u32_index(np, "syscon-pol", 1,
4112 &dispc.syscon_pol_offset)) {
4113 dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
4114 return -EINVAL;
4115 }
4116 }
4117
4118 pm_runtime_enable(&pdev->dev);
4119
4120 r = dispc_runtime_get();
4121 if (r)
4122 goto err_runtime_get;
4123
4124 _omap_dispc_initial_config();
4125
4126 rev = dispc_read_reg(DISPC_REVISION);
4127 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
4128 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4129
4130 dispc_runtime_put();
4131
4132 dss_init_overlay_managers();
4133
4134 dss_debugfs_create_file("dispc", dispc_dump_regs);
4135
4136 return 0;
4137
4138err_runtime_get:
4139 pm_runtime_disable(&pdev->dev);
4140 return r;
4141}
4142
4143static void dispc_unbind(struct device *dev, struct device *master,
4144 void *data)
4145{
4146 pm_runtime_disable(dev);
4147
4148 dss_uninit_overlay_managers();
4149}
4150
4151static const struct component_ops dispc_component_ops = {
4152 .bind = dispc_bind,
4153 .unbind = dispc_unbind,
4154};
4155
4156static int dispc_probe(struct platform_device *pdev)
4157{
4158 return component_add(&pdev->dev, &dispc_component_ops);
4159}
4160
4161static int dispc_remove(struct platform_device *pdev)
4162{
4163 component_del(&pdev->dev, &dispc_component_ops);
4164 return 0;
4165}
4166
4167static int dispc_runtime_suspend(struct device *dev)
4168{
4169 dispc.is_enabled = false;
4170 /* ensure the dispc_irq_handler sees the is_enabled value */
4171 smp_wmb();
4172 /* wait for current handler to finish before turning the DISPC off */
4173 synchronize_irq(dispc.irq);
4174
4175 dispc_save_context();
4176
4177 return 0;
4178}
4179
4180static int dispc_runtime_resume(struct device *dev)
4181{
4182 /*
4183 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
4184 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
4185 * _omap_dispc_initial_config(). We can thus use it to detect if
4186 * we have lost register context.
4187 */
4188 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
4189 _omap_dispc_initial_config();
4190
4191 dispc_restore_context();
4192 }
4193
4194 dispc.is_enabled = true;
4195 /* ensure the dispc_irq_handler sees the is_enabled value */
4196 smp_wmb();
4197
4198 return 0;
4199}
4200
4201static const struct dev_pm_ops dispc_pm_ops = {
4202 .runtime_suspend = dispc_runtime_suspend,
4203 .runtime_resume = dispc_runtime_resume,
4204};
4205
4206static const struct of_device_id dispc_of_match[] = {
4207 { .compatible = "ti,omap2-dispc", },
4208 { .compatible = "ti,omap3-dispc", },
4209 { .compatible = "ti,omap4-dispc", },
4210 { .compatible = "ti,omap5-dispc", },
4211 { .compatible = "ti,dra7-dispc", },
4212 {},
4213};
4214
4215static struct platform_driver omap_dispchw_driver = {
4216 .probe = dispc_probe,
4217 .remove = dispc_remove,
4218 .driver = {
4219 .name = "omapdss_dispc",
4220 .pm = &dispc_pm_ops,
4221 .of_match_table = dispc_of_match,
4222 .suppress_bind_attrs = true,
4223 },
4224};
4225
4226int __init dispc_init_platform_driver(void)
4227{
4228 return platform_driver_register(&omap_dispchw_driver);
4229}
4230
4231void dispc_uninit_platform_driver(void)
4232{
4233 platform_driver_unregister(&omap_dispchw_driver);
4234}
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h
new file mode 100644
index 000000000000..483744223dd1
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.h
@@ -0,0 +1,918 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc.h
3 *
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Archit Taneja <archit@ti.com>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __OMAP2_DISPC_REG_H
22#define __OMAP2_DISPC_REG_H
23
24/* DISPC common registers */
25#define DISPC_REVISION 0x0000
26#define DISPC_SYSCONFIG 0x0010
27#define DISPC_SYSSTATUS 0x0014
28#define DISPC_IRQSTATUS 0x0018
29#define DISPC_IRQENABLE 0x001C
30#define DISPC_CONTROL 0x0040
31#define DISPC_CONFIG 0x0044
32#define DISPC_CAPABLE 0x0048
33#define DISPC_LINE_STATUS 0x005C
34#define DISPC_LINE_NUMBER 0x0060
35#define DISPC_GLOBAL_ALPHA 0x0074
36#define DISPC_CONTROL2 0x0238
37#define DISPC_CONFIG2 0x0620
38#define DISPC_DIVISOR 0x0804
39#define DISPC_GLOBAL_BUFFER 0x0800
40#define DISPC_CONTROL3 0x0848
41#define DISPC_CONFIG3 0x084C
42#define DISPC_MSTANDBY_CTRL 0x0858
43#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C
44
45/* DISPC overlay registers */
46#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
47 DISPC_BA0_OFFSET(n))
48#define DISPC_OVL_BA1(n) (DISPC_OVL_BASE(n) + \
49 DISPC_BA1_OFFSET(n))
50#define DISPC_OVL_BA0_UV(n) (DISPC_OVL_BASE(n) + \
51 DISPC_BA0_UV_OFFSET(n))
52#define DISPC_OVL_BA1_UV(n) (DISPC_OVL_BASE(n) + \
53 DISPC_BA1_UV_OFFSET(n))
54#define DISPC_OVL_POSITION(n) (DISPC_OVL_BASE(n) + \
55 DISPC_POS_OFFSET(n))
56#define DISPC_OVL_SIZE(n) (DISPC_OVL_BASE(n) + \
57 DISPC_SIZE_OFFSET(n))
58#define DISPC_OVL_ATTRIBUTES(n) (DISPC_OVL_BASE(n) + \
59 DISPC_ATTR_OFFSET(n))
60#define DISPC_OVL_ATTRIBUTES2(n) (DISPC_OVL_BASE(n) + \
61 DISPC_ATTR2_OFFSET(n))
62#define DISPC_OVL_FIFO_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
63 DISPC_FIFO_THRESH_OFFSET(n))
64#define DISPC_OVL_FIFO_SIZE_STATUS(n) (DISPC_OVL_BASE(n) + \
65 DISPC_FIFO_SIZE_STATUS_OFFSET(n))
66#define DISPC_OVL_ROW_INC(n) (DISPC_OVL_BASE(n) + \
67 DISPC_ROW_INC_OFFSET(n))
68#define DISPC_OVL_PIXEL_INC(n) (DISPC_OVL_BASE(n) + \
69 DISPC_PIX_INC_OFFSET(n))
70#define DISPC_OVL_WINDOW_SKIP(n) (DISPC_OVL_BASE(n) + \
71 DISPC_WINDOW_SKIP_OFFSET(n))
72#define DISPC_OVL_TABLE_BA(n) (DISPC_OVL_BASE(n) + \
73 DISPC_TABLE_BA_OFFSET(n))
74#define DISPC_OVL_FIR(n) (DISPC_OVL_BASE(n) + \
75 DISPC_FIR_OFFSET(n))
76#define DISPC_OVL_FIR2(n) (DISPC_OVL_BASE(n) + \
77 DISPC_FIR2_OFFSET(n))
78#define DISPC_OVL_PICTURE_SIZE(n) (DISPC_OVL_BASE(n) + \
79 DISPC_PIC_SIZE_OFFSET(n))
80#define DISPC_OVL_ACCU0(n) (DISPC_OVL_BASE(n) + \
81 DISPC_ACCU0_OFFSET(n))
82#define DISPC_OVL_ACCU1(n) (DISPC_OVL_BASE(n) + \
83 DISPC_ACCU1_OFFSET(n))
84#define DISPC_OVL_ACCU2_0(n) (DISPC_OVL_BASE(n) + \
85 DISPC_ACCU2_0_OFFSET(n))
86#define DISPC_OVL_ACCU2_1(n) (DISPC_OVL_BASE(n) + \
87 DISPC_ACCU2_1_OFFSET(n))
88#define DISPC_OVL_FIR_COEF_H(n, i) (DISPC_OVL_BASE(n) + \
89 DISPC_FIR_COEF_H_OFFSET(n, i))
90#define DISPC_OVL_FIR_COEF_HV(n, i) (DISPC_OVL_BASE(n) + \
91 DISPC_FIR_COEF_HV_OFFSET(n, i))
92#define DISPC_OVL_FIR_COEF_H2(n, i) (DISPC_OVL_BASE(n) + \
93 DISPC_FIR_COEF_H2_OFFSET(n, i))
94#define DISPC_OVL_FIR_COEF_HV2(n, i) (DISPC_OVL_BASE(n) + \
95 DISPC_FIR_COEF_HV2_OFFSET(n, i))
96#define DISPC_OVL_CONV_COEF(n, i) (DISPC_OVL_BASE(n) + \
97 DISPC_CONV_COEF_OFFSET(n, i))
98#define DISPC_OVL_FIR_COEF_V(n, i) (DISPC_OVL_BASE(n) + \
99 DISPC_FIR_COEF_V_OFFSET(n, i))
100#define DISPC_OVL_FIR_COEF_V2(n, i) (DISPC_OVL_BASE(n) + \
101 DISPC_FIR_COEF_V2_OFFSET(n, i))
102#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
103 DISPC_PRELOAD_OFFSET(n))
104#define DISPC_OVL_MFLAG_THRESHOLD(n) DISPC_MFLAG_THRESHOLD_OFFSET(n)
105
106/* DISPC up/downsampling FIR filter coefficient structure */
107struct dispc_coef {
108 s8 hc4_vc22;
109 s8 hc3_vc2;
110 u8 hc2_vc1;
111 s8 hc1_vc0;
112 s8 hc0_vc00;
113};
114
115const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
116
117/* DISPC manager/channel specific registers */
118static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
119{
120 switch (channel) {
121 case OMAP_DSS_CHANNEL_LCD:
122 return 0x004C;
123 case OMAP_DSS_CHANNEL_DIGIT:
124 return 0x0050;
125 case OMAP_DSS_CHANNEL_LCD2:
126 return 0x03AC;
127 case OMAP_DSS_CHANNEL_LCD3:
128 return 0x0814;
129 default:
130 BUG();
131 return 0;
132 }
133}
134
135static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
136{
137 switch (channel) {
138 case OMAP_DSS_CHANNEL_LCD:
139 return 0x0054;
140 case OMAP_DSS_CHANNEL_DIGIT:
141 return 0x0058;
142 case OMAP_DSS_CHANNEL_LCD2:
143 return 0x03B0;
144 case OMAP_DSS_CHANNEL_LCD3:
145 return 0x0818;
146 default:
147 BUG();
148 return 0;
149 }
150}
151
152static inline u16 DISPC_TIMING_H(enum omap_channel channel)
153{
154 switch (channel) {
155 case OMAP_DSS_CHANNEL_LCD:
156 return 0x0064;
157 case OMAP_DSS_CHANNEL_DIGIT:
158 BUG();
159 return 0;
160 case OMAP_DSS_CHANNEL_LCD2:
161 return 0x0400;
162 case OMAP_DSS_CHANNEL_LCD3:
163 return 0x0840;
164 default:
165 BUG();
166 return 0;
167 }
168}
169
170static inline u16 DISPC_TIMING_V(enum omap_channel channel)
171{
172 switch (channel) {
173 case OMAP_DSS_CHANNEL_LCD:
174 return 0x0068;
175 case OMAP_DSS_CHANNEL_DIGIT:
176 BUG();
177 return 0;
178 case OMAP_DSS_CHANNEL_LCD2:
179 return 0x0404;
180 case OMAP_DSS_CHANNEL_LCD3:
181 return 0x0844;
182 default:
183 BUG();
184 return 0;
185 }
186}
187
188static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
189{
190 switch (channel) {
191 case OMAP_DSS_CHANNEL_LCD:
192 return 0x006C;
193 case OMAP_DSS_CHANNEL_DIGIT:
194 BUG();
195 return 0;
196 case OMAP_DSS_CHANNEL_LCD2:
197 return 0x0408;
198 case OMAP_DSS_CHANNEL_LCD3:
199 return 0x083C;
200 default:
201 BUG();
202 return 0;
203 }
204}
205
206static inline u16 DISPC_DIVISORo(enum omap_channel channel)
207{
208 switch (channel) {
209 case OMAP_DSS_CHANNEL_LCD:
210 return 0x0070;
211 case OMAP_DSS_CHANNEL_DIGIT:
212 BUG();
213 return 0;
214 case OMAP_DSS_CHANNEL_LCD2:
215 return 0x040C;
216 case OMAP_DSS_CHANNEL_LCD3:
217 return 0x0838;
218 default:
219 BUG();
220 return 0;
221 }
222}
223
224/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
225static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
226{
227 switch (channel) {
228 case OMAP_DSS_CHANNEL_LCD:
229 return 0x007C;
230 case OMAP_DSS_CHANNEL_DIGIT:
231 return 0x0078;
232 case OMAP_DSS_CHANNEL_LCD2:
233 return 0x03CC;
234 case OMAP_DSS_CHANNEL_LCD3:
235 return 0x0834;
236 default:
237 BUG();
238 return 0;
239 }
240}
241
242static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
243{
244 switch (channel) {
245 case OMAP_DSS_CHANNEL_LCD:
246 return 0x01D4;
247 case OMAP_DSS_CHANNEL_DIGIT:
248 BUG();
249 return 0;
250 case OMAP_DSS_CHANNEL_LCD2:
251 return 0x03C0;
252 case OMAP_DSS_CHANNEL_LCD3:
253 return 0x0828;
254 default:
255 BUG();
256 return 0;
257 }
258}
259
260static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
261{
262 switch (channel) {
263 case OMAP_DSS_CHANNEL_LCD:
264 return 0x01D8;
265 case OMAP_DSS_CHANNEL_DIGIT:
266 BUG();
267 return 0;
268 case OMAP_DSS_CHANNEL_LCD2:
269 return 0x03C4;
270 case OMAP_DSS_CHANNEL_LCD3:
271 return 0x082C;
272 default:
273 BUG();
274 return 0;
275 }
276}
277
278static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
279{
280 switch (channel) {
281 case OMAP_DSS_CHANNEL_LCD:
282 return 0x01DC;
283 case OMAP_DSS_CHANNEL_DIGIT:
284 BUG();
285 return 0;
286 case OMAP_DSS_CHANNEL_LCD2:
287 return 0x03C8;
288 case OMAP_DSS_CHANNEL_LCD3:
289 return 0x0830;
290 default:
291 BUG();
292 return 0;
293 }
294}
295
296static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
297{
298 switch (channel) {
299 case OMAP_DSS_CHANNEL_LCD:
300 return 0x0220;
301 case OMAP_DSS_CHANNEL_DIGIT:
302 BUG();
303 return 0;
304 case OMAP_DSS_CHANNEL_LCD2:
305 return 0x03BC;
306 case OMAP_DSS_CHANNEL_LCD3:
307 return 0x0824;
308 default:
309 BUG();
310 return 0;
311 }
312}
313
314static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
315{
316 switch (channel) {
317 case OMAP_DSS_CHANNEL_LCD:
318 return 0x0224;
319 case OMAP_DSS_CHANNEL_DIGIT:
320 BUG();
321 return 0;
322 case OMAP_DSS_CHANNEL_LCD2:
323 return 0x03B8;
324 case OMAP_DSS_CHANNEL_LCD3:
325 return 0x0820;
326 default:
327 BUG();
328 return 0;
329 }
330}
331
332static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
333{
334 switch (channel) {
335 case OMAP_DSS_CHANNEL_LCD:
336 return 0x0228;
337 case OMAP_DSS_CHANNEL_DIGIT:
338 BUG();
339 return 0;
340 case OMAP_DSS_CHANNEL_LCD2:
341 return 0x03B4;
342 case OMAP_DSS_CHANNEL_LCD3:
343 return 0x081C;
344 default:
345 BUG();
346 return 0;
347 }
348}
349
350/* DISPC overlay register base addresses */
351static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
352{
353 switch (plane) {
354 case OMAP_DSS_GFX:
355 return 0x0080;
356 case OMAP_DSS_VIDEO1:
357 return 0x00BC;
358 case OMAP_DSS_VIDEO2:
359 return 0x014C;
360 case OMAP_DSS_VIDEO3:
361 return 0x0300;
362 case OMAP_DSS_WB:
363 return 0x0500;
364 default:
365 BUG();
366 return 0;
367 }
368}
369
370/* DISPC overlay register offsets */
371static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
372{
373 switch (plane) {
374 case OMAP_DSS_GFX:
375 case OMAP_DSS_VIDEO1:
376 case OMAP_DSS_VIDEO2:
377 return 0x0000;
378 case OMAP_DSS_VIDEO3:
379 case OMAP_DSS_WB:
380 return 0x0008;
381 default:
382 BUG();
383 return 0;
384 }
385}
386
387static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
388{
389 switch (plane) {
390 case OMAP_DSS_GFX:
391 case OMAP_DSS_VIDEO1:
392 case OMAP_DSS_VIDEO2:
393 return 0x0004;
394 case OMAP_DSS_VIDEO3:
395 case OMAP_DSS_WB:
396 return 0x000C;
397 default:
398 BUG();
399 return 0;
400 }
401}
402
403static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
404{
405 switch (plane) {
406 case OMAP_DSS_GFX:
407 BUG();
408 return 0;
409 case OMAP_DSS_VIDEO1:
410 return 0x0544;
411 case OMAP_DSS_VIDEO2:
412 return 0x04BC;
413 case OMAP_DSS_VIDEO3:
414 return 0x0310;
415 case OMAP_DSS_WB:
416 return 0x0118;
417 default:
418 BUG();
419 return 0;
420 }
421}
422
423static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
424{
425 switch (plane) {
426 case OMAP_DSS_GFX:
427 BUG();
428 return 0;
429 case OMAP_DSS_VIDEO1:
430 return 0x0548;
431 case OMAP_DSS_VIDEO2:
432 return 0x04C0;
433 case OMAP_DSS_VIDEO3:
434 return 0x0314;
435 case OMAP_DSS_WB:
436 return 0x011C;
437 default:
438 BUG();
439 return 0;
440 }
441}
442
443static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
444{
445 switch (plane) {
446 case OMAP_DSS_GFX:
447 case OMAP_DSS_VIDEO1:
448 case OMAP_DSS_VIDEO2:
449 return 0x0008;
450 case OMAP_DSS_VIDEO3:
451 return 0x009C;
452 default:
453 BUG();
454 return 0;
455 }
456}
457
458static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
459{
460 switch (plane) {
461 case OMAP_DSS_GFX:
462 case OMAP_DSS_VIDEO1:
463 case OMAP_DSS_VIDEO2:
464 return 0x000C;
465 case OMAP_DSS_VIDEO3:
466 case OMAP_DSS_WB:
467 return 0x00A8;
468 default:
469 BUG();
470 return 0;
471 }
472}
473
474static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
475{
476 switch (plane) {
477 case OMAP_DSS_GFX:
478 return 0x0020;
479 case OMAP_DSS_VIDEO1:
480 case OMAP_DSS_VIDEO2:
481 return 0x0010;
482 case OMAP_DSS_VIDEO3:
483 case OMAP_DSS_WB:
484 return 0x0070;
485 default:
486 BUG();
487 return 0;
488 }
489}
490
491static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
492{
493 switch (plane) {
494 case OMAP_DSS_GFX:
495 BUG();
496 return 0;
497 case OMAP_DSS_VIDEO1:
498 return 0x0568;
499 case OMAP_DSS_VIDEO2:
500 return 0x04DC;
501 case OMAP_DSS_VIDEO3:
502 return 0x032C;
503 case OMAP_DSS_WB:
504 return 0x0310;
505 default:
506 BUG();
507 return 0;
508 }
509}
510
511static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
512{
513 switch (plane) {
514 case OMAP_DSS_GFX:
515 return 0x0024;
516 case OMAP_DSS_VIDEO1:
517 case OMAP_DSS_VIDEO2:
518 return 0x0014;
519 case OMAP_DSS_VIDEO3:
520 case OMAP_DSS_WB:
521 return 0x008C;
522 default:
523 BUG();
524 return 0;
525 }
526}
527
528static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
529{
530 switch (plane) {
531 case OMAP_DSS_GFX:
532 return 0x0028;
533 case OMAP_DSS_VIDEO1:
534 case OMAP_DSS_VIDEO2:
535 return 0x0018;
536 case OMAP_DSS_VIDEO3:
537 case OMAP_DSS_WB:
538 return 0x0088;
539 default:
540 BUG();
541 return 0;
542 }
543}
544
545static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
546{
547 switch (plane) {
548 case OMAP_DSS_GFX:
549 return 0x002C;
550 case OMAP_DSS_VIDEO1:
551 case OMAP_DSS_VIDEO2:
552 return 0x001C;
553 case OMAP_DSS_VIDEO3:
554 case OMAP_DSS_WB:
555 return 0x00A4;
556 default:
557 BUG();
558 return 0;
559 }
560}
561
562static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
563{
564 switch (plane) {
565 case OMAP_DSS_GFX:
566 return 0x0030;
567 case OMAP_DSS_VIDEO1:
568 case OMAP_DSS_VIDEO2:
569 return 0x0020;
570 case OMAP_DSS_VIDEO3:
571 case OMAP_DSS_WB:
572 return 0x0098;
573 default:
574 BUG();
575 return 0;
576 }
577}
578
579static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
580{
581 switch (plane) {
582 case OMAP_DSS_GFX:
583 return 0x0034;
584 case OMAP_DSS_VIDEO1:
585 case OMAP_DSS_VIDEO2:
586 case OMAP_DSS_VIDEO3:
587 BUG();
588 return 0;
589 default:
590 BUG();
591 return 0;
592 }
593}
594
595static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
596{
597 switch (plane) {
598 case OMAP_DSS_GFX:
599 return 0x0038;
600 case OMAP_DSS_VIDEO1:
601 case OMAP_DSS_VIDEO2:
602 case OMAP_DSS_VIDEO3:
603 BUG();
604 return 0;
605 default:
606 BUG();
607 return 0;
608 }
609}
610
611static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
612{
613 switch (plane) {
614 case OMAP_DSS_GFX:
615 BUG();
616 return 0;
617 case OMAP_DSS_VIDEO1:
618 case OMAP_DSS_VIDEO2:
619 return 0x0024;
620 case OMAP_DSS_VIDEO3:
621 case OMAP_DSS_WB:
622 return 0x0090;
623 default:
624 BUG();
625 return 0;
626 }
627}
628
629static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
630{
631 switch (plane) {
632 case OMAP_DSS_GFX:
633 BUG();
634 return 0;
635 case OMAP_DSS_VIDEO1:
636 return 0x0580;
637 case OMAP_DSS_VIDEO2:
638 return 0x055C;
639 case OMAP_DSS_VIDEO3:
640 return 0x0424;
641 case OMAP_DSS_WB:
642 return 0x290;
643 default:
644 BUG();
645 return 0;
646 }
647}
648
649static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
650{
651 switch (plane) {
652 case OMAP_DSS_GFX:
653 BUG();
654 return 0;
655 case OMAP_DSS_VIDEO1:
656 case OMAP_DSS_VIDEO2:
657 return 0x0028;
658 case OMAP_DSS_VIDEO3:
659 case OMAP_DSS_WB:
660 return 0x0094;
661 default:
662 BUG();
663 return 0;
664 }
665}
666
667
668static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
669{
670 switch (plane) {
671 case OMAP_DSS_GFX:
672 BUG();
673 return 0;
674 case OMAP_DSS_VIDEO1:
675 case OMAP_DSS_VIDEO2:
676 return 0x002C;
677 case OMAP_DSS_VIDEO3:
678 case OMAP_DSS_WB:
679 return 0x0000;
680 default:
681 BUG();
682 return 0;
683 }
684}
685
686static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
687{
688 switch (plane) {
689 case OMAP_DSS_GFX:
690 BUG();
691 return 0;
692 case OMAP_DSS_VIDEO1:
693 return 0x0584;
694 case OMAP_DSS_VIDEO2:
695 return 0x0560;
696 case OMAP_DSS_VIDEO3:
697 return 0x0428;
698 case OMAP_DSS_WB:
699 return 0x0294;
700 default:
701 BUG();
702 return 0;
703 }
704}
705
706static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
707{
708 switch (plane) {
709 case OMAP_DSS_GFX:
710 BUG();
711 return 0;
712 case OMAP_DSS_VIDEO1:
713 case OMAP_DSS_VIDEO2:
714 return 0x0030;
715 case OMAP_DSS_VIDEO3:
716 case OMAP_DSS_WB:
717 return 0x0004;
718 default:
719 BUG();
720 return 0;
721 }
722}
723
724static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
725{
726 switch (plane) {
727 case OMAP_DSS_GFX:
728 BUG();
729 return 0;
730 case OMAP_DSS_VIDEO1:
731 return 0x0588;
732 case OMAP_DSS_VIDEO2:
733 return 0x0564;
734 case OMAP_DSS_VIDEO3:
735 return 0x042C;
736 case OMAP_DSS_WB:
737 return 0x0298;
738 default:
739 BUG();
740 return 0;
741 }
742}
743
744/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
745static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
746{
747 switch (plane) {
748 case OMAP_DSS_GFX:
749 BUG();
750 return 0;
751 case OMAP_DSS_VIDEO1:
752 case OMAP_DSS_VIDEO2:
753 return 0x0034 + i * 0x8;
754 case OMAP_DSS_VIDEO3:
755 case OMAP_DSS_WB:
756 return 0x0010 + i * 0x8;
757 default:
758 BUG();
759 return 0;
760 }
761}
762
763/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
764static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
765{
766 switch (plane) {
767 case OMAP_DSS_GFX:
768 BUG();
769 return 0;
770 case OMAP_DSS_VIDEO1:
771 return 0x058C + i * 0x8;
772 case OMAP_DSS_VIDEO2:
773 return 0x0568 + i * 0x8;
774 case OMAP_DSS_VIDEO3:
775 return 0x0430 + i * 0x8;
776 case OMAP_DSS_WB:
777 return 0x02A0 + i * 0x8;
778 default:
779 BUG();
780 return 0;
781 }
782}
783
784/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
785static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
786{
787 switch (plane) {
788 case OMAP_DSS_GFX:
789 BUG();
790 return 0;
791 case OMAP_DSS_VIDEO1:
792 case OMAP_DSS_VIDEO2:
793 return 0x0038 + i * 0x8;
794 case OMAP_DSS_VIDEO3:
795 case OMAP_DSS_WB:
796 return 0x0014 + i * 0x8;
797 default:
798 BUG();
799 return 0;
800 }
801}
802
803/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
804static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
805{
806 switch (plane) {
807 case OMAP_DSS_GFX:
808 BUG();
809 return 0;
810 case OMAP_DSS_VIDEO1:
811 return 0x0590 + i * 8;
812 case OMAP_DSS_VIDEO2:
813 return 0x056C + i * 0x8;
814 case OMAP_DSS_VIDEO3:
815 return 0x0434 + i * 0x8;
816 case OMAP_DSS_WB:
817 return 0x02A4 + i * 0x8;
818 default:
819 BUG();
820 return 0;
821 }
822}
823
824/* coef index i = {0, 1, 2, 3, 4,} */
825static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
826{
827 switch (plane) {
828 case OMAP_DSS_GFX:
829 BUG();
830 return 0;
831 case OMAP_DSS_VIDEO1:
832 case OMAP_DSS_VIDEO2:
833 case OMAP_DSS_VIDEO3:
834 case OMAP_DSS_WB:
835 return 0x0074 + i * 0x4;
836 default:
837 BUG();
838 return 0;
839 }
840}
841
842/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
843static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
844{
845 switch (plane) {
846 case OMAP_DSS_GFX:
847 BUG();
848 return 0;
849 case OMAP_DSS_VIDEO1:
850 return 0x0124 + i * 0x4;
851 case OMAP_DSS_VIDEO2:
852 return 0x00B4 + i * 0x4;
853 case OMAP_DSS_VIDEO3:
854 case OMAP_DSS_WB:
855 return 0x0050 + i * 0x4;
856 default:
857 BUG();
858 return 0;
859 }
860}
861
862/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
863static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
864{
865 switch (plane) {
866 case OMAP_DSS_GFX:
867 BUG();
868 return 0;
869 case OMAP_DSS_VIDEO1:
870 return 0x05CC + i * 0x4;
871 case OMAP_DSS_VIDEO2:
872 return 0x05A8 + i * 0x4;
873 case OMAP_DSS_VIDEO3:
874 return 0x0470 + i * 0x4;
875 case OMAP_DSS_WB:
876 return 0x02E0 + i * 0x4;
877 default:
878 BUG();
879 return 0;
880 }
881}
882
883static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
884{
885 switch (plane) {
886 case OMAP_DSS_GFX:
887 return 0x01AC;
888 case OMAP_DSS_VIDEO1:
889 return 0x0174;
890 case OMAP_DSS_VIDEO2:
891 return 0x00E8;
892 case OMAP_DSS_VIDEO3:
893 return 0x00A0;
894 default:
895 BUG();
896 return 0;
897 }
898}
899
900static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
901{
902 switch (plane) {
903 case OMAP_DSS_GFX:
904 return 0x0860;
905 case OMAP_DSS_VIDEO1:
906 return 0x0864;
907 case OMAP_DSS_VIDEO2:
908 return 0x0868;
909 case OMAP_DSS_VIDEO3:
910 return 0x086c;
911 case OMAP_DSS_WB:
912 return 0x0870;
913 default:
914 BUG();
915 return 0;
916 }
917}
918#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
new file mode 100644
index 000000000000..038c15b04215
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
@@ -0,0 +1,325 @@
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
23#include "dispc.h"
24
25static const struct dispc_coef coef3_M8[8] = {
26 { 0, 0, 128, 0, 0 },
27 { 0, -4, 123, 9, 0 },
28 { 0, -4, 108, 24, 0 },
29 { 0, -2, 87, 43, 0 },
30 { 0, 64, 64, 0, 0 },
31 { 0, 43, 87, -2, 0 },
32 { 0, 24, 108, -4, 0 },
33 { 0, 9, 123, -4, 0 },
34};
35
36static const struct dispc_coef coef3_M9[8] = {
37 { 0, 6, 116, 6, 0 },
38 { 0, 0, 112, 16, 0 },
39 { 0, -2, 100, 30, 0 },
40 { 0, -2, 83, 47, 0 },
41 { 0, 64, 64, 0, 0 },
42 { 0, 47, 83, -2, 0 },
43 { 0, 30, 100, -2, 0 },
44 { 0, 16, 112, 0, 0 },
45};
46
47static const struct dispc_coef coef3_M10[8] = {
48 { 0, 10, 108, 10, 0 },
49 { 0, 3, 104, 21, 0 },
50 { 0, 0, 94, 34, 0 },
51 { 0, -1, 80, 49, 0 },
52 { 0, 64, 64, 0, 0 },
53 { 0, 49, 80, -1, 0 },
54 { 0, 34, 94, 0, 0 },
55 { 0, 21, 104, 3, 0 },
56};
57
58static const struct dispc_coef coef3_M11[8] = {
59 { 0, 14, 100, 14, 0 },
60 { 0, 6, 98, 24, 0 },
61 { 0, 2, 90, 36, 0 },
62 { 0, 0, 78, 50, 0 },
63 { 0, 64, 64, 0, 0 },
64 { 0, 50, 78, 0, 0 },
65 { 0, 36, 90, 2, 0 },
66 { 0, 24, 98, 6, 0 },
67};
68
69static const struct dispc_coef coef3_M12[8] = {
70 { 0, 16, 96, 16, 0 },
71 { 0, 9, 93, 26, 0 },
72 { 0, 4, 86, 38, 0 },
73 { 0, 1, 76, 51, 0 },
74 { 0, 64, 64, 0, 0 },
75 { 0, 51, 76, 1, 0 },
76 { 0, 38, 86, 4, 0 },
77 { 0, 26, 93, 9, 0 },
78};
79
80static const struct dispc_coef coef3_M13[8] = {
81 { 0, 18, 92, 18, 0 },
82 { 0, 10, 90, 28, 0 },
83 { 0, 5, 83, 40, 0 },
84 { 0, 1, 75, 52, 0 },
85 { 0, 64, 64, 0, 0 },
86 { 0, 52, 75, 1, 0 },
87 { 0, 40, 83, 5, 0 },
88 { 0, 28, 90, 10, 0 },
89};
90
91static const struct dispc_coef coef3_M14[8] = {
92 { 0, 20, 88, 20, 0 },
93 { 0, 12, 86, 30, 0 },
94 { 0, 6, 81, 41, 0 },
95 { 0, 2, 74, 52, 0 },
96 { 0, 64, 64, 0, 0 },
97 { 0, 52, 74, 2, 0 },
98 { 0, 41, 81, 6, 0 },
99 { 0, 30, 86, 12, 0 },
100};
101
102static const struct dispc_coef coef3_M16[8] = {
103 { 0, 22, 84, 22, 0 },
104 { 0, 14, 82, 32, 0 },
105 { 0, 8, 78, 42, 0 },
106 { 0, 3, 72, 53, 0 },
107 { 0, 64, 64, 0, 0 },
108 { 0, 53, 72, 3, 0 },
109 { 0, 42, 78, 8, 0 },
110 { 0, 32, 82, 14, 0 },
111};
112
113static const struct dispc_coef coef3_M19[8] = {
114 { 0, 24, 80, 24, 0 },
115 { 0, 16, 79, 33, 0 },
116 { 0, 9, 76, 43, 0 },
117 { 0, 4, 70, 54, 0 },
118 { 0, 64, 64, 0, 0 },
119 { 0, 54, 70, 4, 0 },
120 { 0, 43, 76, 9, 0 },
121 { 0, 33, 79, 16, 0 },
122};
123
124static const struct dispc_coef coef3_M22[8] = {
125 { 0, 25, 78, 25, 0 },
126 { 0, 17, 77, 34, 0 },
127 { 0, 10, 74, 44, 0 },
128 { 0, 5, 69, 54, 0 },
129 { 0, 64, 64, 0, 0 },
130 { 0, 54, 69, 5, 0 },
131 { 0, 44, 74, 10, 0 },
132 { 0, 34, 77, 17, 0 },
133};
134
135static const struct dispc_coef coef3_M26[8] = {
136 { 0, 26, 76, 26, 0 },
137 { 0, 19, 74, 35, 0 },
138 { 0, 11, 72, 45, 0 },
139 { 0, 5, 69, 54, 0 },
140 { 0, 64, 64, 0, 0 },
141 { 0, 54, 69, 5, 0 },
142 { 0, 45, 72, 11, 0 },
143 { 0, 35, 74, 19, 0 },
144};
145
146static const struct dispc_coef coef3_M32[8] = {
147 { 0, 27, 74, 27, 0 },
148 { 0, 19, 73, 36, 0 },
149 { 0, 12, 71, 45, 0 },
150 { 0, 6, 68, 54, 0 },
151 { 0, 64, 64, 0, 0 },
152 { 0, 54, 68, 6, 0 },
153 { 0, 45, 71, 12, 0 },
154 { 0, 36, 73, 19, 0 },
155};
156
157static const struct dispc_coef coef5_M8[8] = {
158 { 0, 0, 128, 0, 0 },
159 { -2, 14, 125, -10, 1 },
160 { -6, 33, 114, -15, 2 },
161 { -10, 55, 98, -16, 1 },
162 { 0, -14, 78, 78, -14 },
163 { 1, -16, 98, 55, -10 },
164 { 2, -15, 114, 33, -6 },
165 { 1, -10, 125, 14, -2 },
166};
167
168static const struct dispc_coef coef5_M9[8] = {
169 { -3, 10, 114, 10, -3 },
170 { -6, 24, 111, 0, -1 },
171 { -8, 40, 103, -7, 0 },
172 { -11, 58, 91, -11, 1 },
173 { 0, -12, 76, 76, -12 },
174 { 1, -11, 91, 58, -11 },
175 { 0, -7, 103, 40, -8 },
176 { -1, 0, 111, 24, -6 },
177};
178
179static const struct dispc_coef coef5_M10[8] = {
180 { -4, 18, 100, 18, -4 },
181 { -6, 30, 99, 8, -3 },
182 { -8, 44, 93, 0, -1 },
183 { -9, 58, 84, -5, 0 },
184 { 0, -8, 72, 72, -8 },
185 { 0, -5, 84, 58, -9 },
186 { -1, 0, 93, 44, -8 },
187 { -3, 8, 99, 30, -6 },
188};
189
190static const struct dispc_coef coef5_M11[8] = {
191 { -5, 23, 92, 23, -5 },
192 { -6, 34, 90, 13, -3 },
193 { -6, 45, 85, 6, -2 },
194 { -6, 57, 78, 0, -1 },
195 { 0, -4, 68, 68, -4 },
196 { -1, 0, 78, 57, -6 },
197 { -2, 6, 85, 45, -6 },
198 { -3, 13, 90, 34, -6 },
199};
200
201static const struct dispc_coef coef5_M12[8] = {
202 { -4, 26, 84, 26, -4 },
203 { -5, 36, 82, 18, -3 },
204 { -4, 46, 78, 10, -2 },
205 { -3, 55, 72, 5, -1 },
206 { 0, 0, 64, 64, 0 },
207 { -1, 5, 72, 55, -3 },
208 { -2, 10, 78, 46, -4 },
209 { -3, 18, 82, 36, -5 },
210};
211
212static const struct dispc_coef coef5_M13[8] = {
213 { -3, 28, 78, 28, -3 },
214 { -3, 37, 76, 21, -3 },
215 { -2, 45, 73, 14, -2 },
216 { 0, 53, 68, 8, -1 },
217 { 0, 3, 61, 61, 3 },
218 { -1, 8, 68, 53, 0 },
219 { -2, 14, 73, 45, -2 },
220 { -3, 21, 76, 37, -3 },
221};
222
223static const struct dispc_coef coef5_M14[8] = {
224 { -2, 30, 72, 30, -2 },
225 { -1, 37, 71, 23, -2 },
226 { 0, 45, 69, 16, -2 },
227 { 3, 52, 64, 10, -1 },
228 { 0, 6, 58, 58, 6 },
229 { -1, 10, 64, 52, 3 },
230 { -2, 16, 69, 45, 0 },
231 { -2, 23, 71, 37, -1 },
232};
233
234static const struct dispc_coef coef5_M16[8] = {
235 { 0, 31, 66, 31, 0 },
236 { 1, 38, 65, 25, -1 },
237 { 3, 44, 62, 20, -1 },
238 { 6, 49, 59, 14, 0 },
239 { 0, 10, 54, 54, 10 },
240 { 0, 14, 59, 49, 6 },
241 { -1, 20, 62, 44, 3 },
242 { -1, 25, 65, 38, 1 },
243};
244
245static const struct dispc_coef coef5_M19[8] = {
246 { 3, 32, 58, 32, 3 },
247 { 4, 38, 58, 27, 1 },
248 { 7, 42, 55, 23, 1 },
249 { 10, 46, 54, 18, 0 },
250 { 0, 14, 50, 50, 14 },
251 { 0, 18, 54, 46, 10 },
252 { 1, 23, 55, 42, 7 },
253 { 1, 27, 58, 38, 4 },
254};
255
256static const struct dispc_coef coef5_M22[8] = {
257 { 4, 33, 54, 33, 4 },
258 { 6, 37, 54, 28, 3 },
259 { 9, 41, 53, 24, 1 },
260 { 12, 45, 51, 20, 0 },
261 { 0, 16, 48, 48, 16 },
262 { 0, 20, 51, 45, 12 },
263 { 1, 24, 53, 41, 9 },
264 { 3, 28, 54, 37, 6 },
265};
266
267static const struct dispc_coef coef5_M26[8] = {
268 { 6, 33, 50, 33, 6 },
269 { 8, 36, 51, 29, 4 },
270 { 11, 40, 50, 25, 2 },
271 { 14, 43, 48, 22, 1 },
272 { 0, 18, 46, 46, 18 },
273 { 1, 22, 48, 43, 14 },
274 { 2, 25, 50, 40, 11 },
275 { 4, 29, 51, 36, 8 },
276};
277
278static const struct dispc_coef coef5_M32[8] = {
279 { 7, 33, 48, 33, 7 },
280 { 10, 36, 48, 29, 5 },
281 { 13, 39, 47, 26, 3 },
282 { 16, 42, 46, 23, 1 },
283 { 0, 19, 45, 45, 19 },
284 { 1, 23, 46, 42, 16 },
285 { 3, 26, 47, 39, 13 },
286 { 5, 29, 48, 36, 10 },
287};
288
289const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
290{
291 int i;
292 static const struct {
293 int Mmin;
294 int Mmax;
295 const struct dispc_coef *coef_3;
296 const struct dispc_coef *coef_5;
297 } coefs[] = {
298 { 27, 32, coef3_M32, coef5_M32 },
299 { 23, 26, coef3_M26, coef5_M26 },
300 { 20, 22, coef3_M22, coef5_M22 },
301 { 17, 19, coef3_M19, coef5_M19 },
302 { 15, 16, coef3_M16, coef5_M16 },
303 { 14, 14, coef3_M14, coef5_M14 },
304 { 13, 13, coef3_M13, coef5_M13 },
305 { 12, 12, coef3_M12, coef5_M12 },
306 { 11, 11, coef3_M11, coef5_M11 },
307 { 10, 10, coef3_M10, coef5_M10 },
308 { 9, 9, coef3_M9, coef5_M9 },
309 { 4, 8, coef3_M8, coef5_M8 },
310 /*
311 * When upscaling more than two times, blockiness and outlines
312 * around the image are observed when M8 tables are used. M11,
313 * M16 and M19 tables are used to prevent this.
314 */
315 { 3, 3, coef3_M11, coef5_M11 },
316 { 2, 2, coef3_M16, coef5_M16 },
317 { 0, 1, coef3_M19, coef5_M19 },
318 };
319
320 inc /= 128;
321 for (i = 0; i < ARRAY_SIZE(coefs); ++i)
322 if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
323 return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
324 return NULL;
325}
diff --git a/drivers/gpu/drm/omapdrm/dss/display-sysfs.c b/drivers/gpu/drm/omapdrm/dss/display-sysfs.c
new file mode 100644
index 000000000000..6ad0991f8259
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/display-sysfs.c
@@ -0,0 +1,356 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "DISPLAY"
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/sysfs.h>
27
28#include <video/omapdss.h>
29#include "dss.h"
30
31static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
32{
33 return snprintf(buf, PAGE_SIZE, "%s\n",
34 dssdev->name ?
35 dssdev->name : "");
36}
37
38static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
39{
40 return snprintf(buf, PAGE_SIZE, "%d\n",
41 omapdss_device_is_enabled(dssdev));
42}
43
44static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
45 const char *buf, size_t size)
46{
47 int r;
48 bool enable;
49
50 r = strtobool(buf, &enable);
51 if (r)
52 return r;
53
54 if (enable == omapdss_device_is_enabled(dssdev))
55 return size;
56
57 if (omapdss_device_is_connected(dssdev) == false)
58 return -ENODEV;
59
60 if (enable) {
61 r = dssdev->driver->enable(dssdev);
62 if (r)
63 return r;
64 } else {
65 dssdev->driver->disable(dssdev);
66 }
67
68 return size;
69}
70
71static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
72{
73 return snprintf(buf, PAGE_SIZE, "%d\n",
74 dssdev->driver->get_te ?
75 dssdev->driver->get_te(dssdev) : 0);
76}
77
78static ssize_t display_tear_store(struct omap_dss_device *dssdev,
79 const char *buf, size_t size)
80{
81 int r;
82 bool te;
83
84 if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
85 return -ENOENT;
86
87 r = strtobool(buf, &te);
88 if (r)
89 return r;
90
91 r = dssdev->driver->enable_te(dssdev, te);
92 if (r)
93 return r;
94
95 return size;
96}
97
98static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
99{
100 struct omap_video_timings t;
101
102 if (!dssdev->driver->get_timings)
103 return -ENOENT;
104
105 dssdev->driver->get_timings(dssdev, &t);
106
107 return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
108 t.pixelclock,
109 t.x_res, t.hfp, t.hbp, t.hsw,
110 t.y_res, t.vfp, t.vbp, t.vsw);
111}
112
113static ssize_t display_timings_store(struct omap_dss_device *dssdev,
114 const char *buf, size_t size)
115{
116 struct omap_video_timings t = dssdev->panel.timings;
117 int r, found;
118
119 if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
120 return -ENOENT;
121
122 found = 0;
123#ifdef CONFIG_OMAP2_DSS_VENC
124 if (strncmp("pal", buf, 3) == 0) {
125 t = omap_dss_pal_timings;
126 found = 1;
127 } else if (strncmp("ntsc", buf, 4) == 0) {
128 t = omap_dss_ntsc_timings;
129 found = 1;
130 }
131#endif
132 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
133 &t.pixelclock,
134 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
135 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
136 return -EINVAL;
137
138 r = dssdev->driver->check_timings(dssdev, &t);
139 if (r)
140 return r;
141
142 dssdev->driver->disable(dssdev);
143 dssdev->driver->set_timings(dssdev, &t);
144 r = dssdev->driver->enable(dssdev);
145 if (r)
146 return r;
147
148 return size;
149}
150
151static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
152{
153 int rotate;
154 if (!dssdev->driver->get_rotate)
155 return -ENOENT;
156 rotate = dssdev->driver->get_rotate(dssdev);
157 return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
158}
159
160static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
161 const char *buf, size_t size)
162{
163 int rot, r;
164
165 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
166 return -ENOENT;
167
168 r = kstrtoint(buf, 0, &rot);
169 if (r)
170 return r;
171
172 r = dssdev->driver->set_rotate(dssdev, rot);
173 if (r)
174 return r;
175
176 return size;
177}
178
179static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
180{
181 int mirror;
182 if (!dssdev->driver->get_mirror)
183 return -ENOENT;
184 mirror = dssdev->driver->get_mirror(dssdev);
185 return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
186}
187
188static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
189 const char *buf, size_t size)
190{
191 int r;
192 bool mirror;
193
194 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
195 return -ENOENT;
196
197 r = strtobool(buf, &mirror);
198 if (r)
199 return r;
200
201 r = dssdev->driver->set_mirror(dssdev, mirror);
202 if (r)
203 return r;
204
205 return size;
206}
207
208static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
209{
210 unsigned int wss;
211
212 if (!dssdev->driver->get_wss)
213 return -ENOENT;
214
215 wss = dssdev->driver->get_wss(dssdev);
216
217 return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
218}
219
220static ssize_t display_wss_store(struct omap_dss_device *dssdev,
221 const char *buf, size_t size)
222{
223 u32 wss;
224 int r;
225
226 if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
227 return -ENOENT;
228
229 r = kstrtou32(buf, 0, &wss);
230 if (r)
231 return r;
232
233 if (wss > 0xfffff)
234 return -EINVAL;
235
236 r = dssdev->driver->set_wss(dssdev, wss);
237 if (r)
238 return r;
239
240 return size;
241}
242
243struct display_attribute {
244 struct attribute attr;
245 ssize_t (*show)(struct omap_dss_device *, char *);
246 ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
247};
248
249#define DISPLAY_ATTR(_name, _mode, _show, _store) \
250 struct display_attribute display_attr_##_name = \
251 __ATTR(_name, _mode, _show, _store)
252
253static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
254static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
255static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
256 display_enabled_show, display_enabled_store);
257static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
258 display_tear_show, display_tear_store);
259static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
260 display_timings_show, display_timings_store);
261static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
262 display_rotate_show, display_rotate_store);
263static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
264 display_mirror_show, display_mirror_store);
265static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
266 display_wss_show, display_wss_store);
267
268static struct attribute *display_sysfs_attrs[] = {
269 &display_attr_name.attr,
270 &display_attr_display_name.attr,
271 &display_attr_enabled.attr,
272 &display_attr_tear_elim.attr,
273 &display_attr_timings.attr,
274 &display_attr_rotate.attr,
275 &display_attr_mirror.attr,
276 &display_attr_wss.attr,
277 NULL
278};
279
280static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
281 char *buf)
282{
283 struct omap_dss_device *dssdev;
284 struct display_attribute *display_attr;
285
286 dssdev = container_of(kobj, struct omap_dss_device, kobj);
287 display_attr = container_of(attr, struct display_attribute, attr);
288
289 if (!display_attr->show)
290 return -ENOENT;
291
292 return display_attr->show(dssdev, buf);
293}
294
295static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
296 const char *buf, size_t size)
297{
298 struct omap_dss_device *dssdev;
299 struct display_attribute *display_attr;
300
301 dssdev = container_of(kobj, struct omap_dss_device, kobj);
302 display_attr = container_of(attr, struct display_attribute, attr);
303
304 if (!display_attr->store)
305 return -ENOENT;
306
307 return display_attr->store(dssdev, buf, size);
308}
309
310static const struct sysfs_ops display_sysfs_ops = {
311 .show = display_attr_show,
312 .store = display_attr_store,
313};
314
315static struct kobj_type display_ktype = {
316 .sysfs_ops = &display_sysfs_ops,
317 .default_attrs = display_sysfs_attrs,
318};
319
320int display_init_sysfs(struct platform_device *pdev)
321{
322 struct omap_dss_device *dssdev = NULL;
323 int r;
324
325 for_each_dss_dev(dssdev) {
326 r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
327 &pdev->dev.kobj, "%s", dssdev->alias);
328 if (r) {
329 DSSERR("failed to create sysfs files\n");
330 omap_dss_put_device(dssdev);
331 goto err;
332 }
333 }
334
335 return 0;
336
337err:
338 display_uninit_sysfs(pdev);
339
340 return r;
341}
342
343void display_uninit_sysfs(struct platform_device *pdev)
344{
345 struct omap_dss_device *dssdev = NULL;
346
347 for_each_dss_dev(dssdev) {
348 if (kobject_name(&dssdev->kobj) == NULL)
349 continue;
350
351 kobject_del(&dssdev->kobj);
352 kobject_put(&dssdev->kobj);
353
354 memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
355 }
356}
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
new file mode 100644
index 000000000000..ef5b9027985d
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/display.c
@@ -0,0 +1,338 @@
1/*
2 * linux/drivers/video/omap2/dss/display.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/jiffies.h>
28#include <linux/platform_device.h>
29#include <linux/of.h>
30
31#include <video/omapdss.h>
32#include "dss.h"
33#include "dss_features.h"
34
35void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
36 u16 *xres, u16 *yres)
37{
38 *xres = dssdev->panel.timings.x_res;
39 *yres = dssdev->panel.timings.y_res;
40}
41EXPORT_SYMBOL(omapdss_default_get_resolution);
42
43int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
44{
45 switch (dssdev->type) {
46 case OMAP_DISPLAY_TYPE_DPI:
47 if (dssdev->phy.dpi.data_lines == 24)
48 return 24;
49 else
50 return 16;
51
52 case OMAP_DISPLAY_TYPE_DBI:
53 if (dssdev->ctrl.pixel_size == 24)
54 return 24;
55 else
56 return 16;
57 case OMAP_DISPLAY_TYPE_DSI:
58 if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
59 return 24;
60 else
61 return 16;
62 case OMAP_DISPLAY_TYPE_VENC:
63 case OMAP_DISPLAY_TYPE_SDI:
64 case OMAP_DISPLAY_TYPE_HDMI:
65 case OMAP_DISPLAY_TYPE_DVI:
66 return 24;
67 default:
68 BUG();
69 return 0;
70 }
71}
72EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
73
74void omapdss_default_get_timings(struct omap_dss_device *dssdev,
75 struct omap_video_timings *timings)
76{
77 *timings = dssdev->panel.timings;
78}
79EXPORT_SYMBOL(omapdss_default_get_timings);
80
81int dss_suspend_all_devices(void)
82{
83 struct omap_dss_device *dssdev = NULL;
84
85 for_each_dss_dev(dssdev) {
86 if (!dssdev->driver)
87 continue;
88
89 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
90 dssdev->driver->disable(dssdev);
91 dssdev->activate_after_resume = true;
92 } else {
93 dssdev->activate_after_resume = false;
94 }
95 }
96
97 return 0;
98}
99
100int dss_resume_all_devices(void)
101{
102 struct omap_dss_device *dssdev = NULL;
103
104 for_each_dss_dev(dssdev) {
105 if (!dssdev->driver)
106 continue;
107
108 if (dssdev->activate_after_resume) {
109 dssdev->driver->enable(dssdev);
110 dssdev->activate_after_resume = false;
111 }
112 }
113
114 return 0;
115}
116
117void dss_disable_all_devices(void)
118{
119 struct omap_dss_device *dssdev = NULL;
120
121 for_each_dss_dev(dssdev) {
122 if (!dssdev->driver)
123 continue;
124
125 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
126 dssdev->driver->disable(dssdev);
127 }
128}
129
130static LIST_HEAD(panel_list);
131static DEFINE_MUTEX(panel_list_mutex);
132static int disp_num_counter;
133
134int omapdss_register_display(struct omap_dss_device *dssdev)
135{
136 struct omap_dss_driver *drv = dssdev->driver;
137 int id;
138
139 /*
140 * Note: this presumes all the displays are either using DT or non-DT,
141 * which normally should be the case. This also presumes that all
142 * displays either have an DT alias, or none has.
143 */
144
145 if (dssdev->dev->of_node) {
146 id = of_alias_get_id(dssdev->dev->of_node, "display");
147
148 if (id < 0)
149 id = disp_num_counter++;
150 } else {
151 id = disp_num_counter++;
152 }
153
154 snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
155
156 /* Use 'label' property for name, if it exists */
157 if (dssdev->dev->of_node)
158 of_property_read_string(dssdev->dev->of_node, "label",
159 &dssdev->name);
160
161 if (dssdev->name == NULL)
162 dssdev->name = dssdev->alias;
163
164 if (drv && drv->get_resolution == NULL)
165 drv->get_resolution = omapdss_default_get_resolution;
166 if (drv && drv->get_recommended_bpp == NULL)
167 drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
168 if (drv && drv->get_timings == NULL)
169 drv->get_timings = omapdss_default_get_timings;
170
171 mutex_lock(&panel_list_mutex);
172 list_add_tail(&dssdev->panel_list, &panel_list);
173 mutex_unlock(&panel_list_mutex);
174 return 0;
175}
176EXPORT_SYMBOL(omapdss_register_display);
177
178void omapdss_unregister_display(struct omap_dss_device *dssdev)
179{
180 mutex_lock(&panel_list_mutex);
181 list_del(&dssdev->panel_list);
182 mutex_unlock(&panel_list_mutex);
183}
184EXPORT_SYMBOL(omapdss_unregister_display);
185
186struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
187{
188 if (!try_module_get(dssdev->owner))
189 return NULL;
190
191 if (get_device(dssdev->dev) == NULL) {
192 module_put(dssdev->owner);
193 return NULL;
194 }
195
196 return dssdev;
197}
198EXPORT_SYMBOL(omap_dss_get_device);
199
200void omap_dss_put_device(struct omap_dss_device *dssdev)
201{
202 put_device(dssdev->dev);
203 module_put(dssdev->owner);
204}
205EXPORT_SYMBOL(omap_dss_put_device);
206
207/*
208 * ref count of the found device is incremented.
209 * ref count of from-device is decremented.
210 */
211struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
212{
213 struct list_head *l;
214 struct omap_dss_device *dssdev;
215
216 mutex_lock(&panel_list_mutex);
217
218 if (list_empty(&panel_list)) {
219 dssdev = NULL;
220 goto out;
221 }
222
223 if (from == NULL) {
224 dssdev = list_first_entry(&panel_list, struct omap_dss_device,
225 panel_list);
226 omap_dss_get_device(dssdev);
227 goto out;
228 }
229
230 omap_dss_put_device(from);
231
232 list_for_each(l, &panel_list) {
233 dssdev = list_entry(l, struct omap_dss_device, panel_list);
234 if (dssdev == from) {
235 if (list_is_last(l, &panel_list)) {
236 dssdev = NULL;
237 goto out;
238 }
239
240 dssdev = list_entry(l->next, struct omap_dss_device,
241 panel_list);
242 omap_dss_get_device(dssdev);
243 goto out;
244 }
245 }
246
247 WARN(1, "'from' dssdev not found\n");
248
249 dssdev = NULL;
250out:
251 mutex_unlock(&panel_list_mutex);
252 return dssdev;
253}
254EXPORT_SYMBOL(omap_dss_get_next_device);
255
256struct omap_dss_device *omap_dss_find_device(void *data,
257 int (*match)(struct omap_dss_device *dssdev, void *data))
258{
259 struct omap_dss_device *dssdev = NULL;
260
261 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
262 if (match(dssdev, data))
263 return dssdev;
264 }
265
266 return NULL;
267}
268EXPORT_SYMBOL(omap_dss_find_device);
269
270void videomode_to_omap_video_timings(const struct videomode *vm,
271 struct omap_video_timings *ovt)
272{
273 memset(ovt, 0, sizeof(*ovt));
274
275 ovt->pixelclock = vm->pixelclock;
276 ovt->x_res = vm->hactive;
277 ovt->hbp = vm->hback_porch;
278 ovt->hfp = vm->hfront_porch;
279 ovt->hsw = vm->hsync_len;
280 ovt->y_res = vm->vactive;
281 ovt->vbp = vm->vback_porch;
282 ovt->vfp = vm->vfront_porch;
283 ovt->vsw = vm->vsync_len;
284
285 ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
286 OMAPDSS_SIG_ACTIVE_HIGH :
287 OMAPDSS_SIG_ACTIVE_LOW;
288 ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
289 OMAPDSS_SIG_ACTIVE_HIGH :
290 OMAPDSS_SIG_ACTIVE_LOW;
291 ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
292 OMAPDSS_SIG_ACTIVE_HIGH :
293 OMAPDSS_SIG_ACTIVE_LOW;
294 ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
295 OMAPDSS_DRIVE_SIG_RISING_EDGE :
296 OMAPDSS_DRIVE_SIG_FALLING_EDGE;
297
298 ovt->sync_pclk_edge = ovt->data_pclk_edge;
299}
300EXPORT_SYMBOL(videomode_to_omap_video_timings);
301
302void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
303 struct videomode *vm)
304{
305 memset(vm, 0, sizeof(*vm));
306
307 vm->pixelclock = ovt->pixelclock;
308
309 vm->hactive = ovt->x_res;
310 vm->hback_porch = ovt->hbp;
311 vm->hfront_porch = ovt->hfp;
312 vm->hsync_len = ovt->hsw;
313 vm->vactive = ovt->y_res;
314 vm->vback_porch = ovt->vbp;
315 vm->vfront_porch = ovt->vfp;
316 vm->vsync_len = ovt->vsw;
317
318 if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
319 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
320 else
321 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
322
323 if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
324 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
325 else
326 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
327
328 if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
329 vm->flags |= DISPLAY_FLAGS_DE_HIGH;
330 else
331 vm->flags |= DISPLAY_FLAGS_DE_LOW;
332
333 if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
334 vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
335 else
336 vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
337}
338EXPORT_SYMBOL(omap_video_timings_to_videomode);
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
new file mode 100644
index 000000000000..7953e6a52346
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -0,0 +1,899 @@
1/*
2 * linux/drivers/video/omap2/dss/dpi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DPI"
24
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/export.h>
28#include <linux/err.h>
29#include <linux/errno.h>
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
32#include <linux/string.h>
33#include <linux/of.h>
34#include <linux/clk.h>
35#include <linux/component.h>
36
37#include <video/omapdss.h>
38
39#include "dss.h"
40#include "dss_features.h"
41
42#define HSDIV_DISPC 0
43
44struct dpi_data {
45 struct platform_device *pdev;
46
47 struct regulator *vdds_dsi_reg;
48 struct dss_pll *pll;
49
50 struct mutex lock;
51
52 struct omap_video_timings timings;
53 struct dss_lcd_mgr_config mgr_config;
54 int data_lines;
55
56 struct omap_dss_device output;
57
58 bool port_initialized;
59};
60
61static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
62{
63 return container_of(dssdev, struct dpi_data, output);
64}
65
66/* only used in non-DT mode */
67static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
68{
69 return dev_get_drvdata(&pdev->dev);
70}
71
72static struct dss_pll *dpi_get_pll(enum omap_channel channel)
73{
74 /*
75 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
76 * would also be used for DISPC fclk. Meaning, when the DPI output is
77 * disabled, DISPC clock will be disabled, and TV out will stop.
78 */
79 switch (omapdss_get_version()) {
80 case OMAPDSS_VER_OMAP24xx:
81 case OMAPDSS_VER_OMAP34xx_ES1:
82 case OMAPDSS_VER_OMAP34xx_ES3:
83 case OMAPDSS_VER_OMAP3630:
84 case OMAPDSS_VER_AM35xx:
85 case OMAPDSS_VER_AM43xx:
86 return NULL;
87
88 case OMAPDSS_VER_OMAP4430_ES1:
89 case OMAPDSS_VER_OMAP4430_ES2:
90 case OMAPDSS_VER_OMAP4:
91 switch (channel) {
92 case OMAP_DSS_CHANNEL_LCD:
93 return dss_pll_find("dsi0");
94 case OMAP_DSS_CHANNEL_LCD2:
95 return dss_pll_find("dsi1");
96 default:
97 return NULL;
98 }
99
100 case OMAPDSS_VER_OMAP5:
101 switch (channel) {
102 case OMAP_DSS_CHANNEL_LCD:
103 return dss_pll_find("dsi0");
104 case OMAP_DSS_CHANNEL_LCD3:
105 return dss_pll_find("dsi1");
106 default:
107 return NULL;
108 }
109
110 case OMAPDSS_VER_DRA7xx:
111 switch (channel) {
112 case OMAP_DSS_CHANNEL_LCD:
113 case OMAP_DSS_CHANNEL_LCD2:
114 return dss_pll_find("video0");
115 case OMAP_DSS_CHANNEL_LCD3:
116 return dss_pll_find("video1");
117 default:
118 return NULL;
119 }
120
121 default:
122 return NULL;
123 }
124}
125
126static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
127{
128 switch (channel) {
129 case OMAP_DSS_CHANNEL_LCD:
130 return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
131 case OMAP_DSS_CHANNEL_LCD2:
132 return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
133 case OMAP_DSS_CHANNEL_LCD3:
134 return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
135 default:
136 /* this shouldn't happen */
137 WARN_ON(1);
138 return OMAP_DSS_CLK_SRC_FCK;
139 }
140}
141
142struct dpi_clk_calc_ctx {
143 struct dss_pll *pll;
144
145 /* inputs */
146
147 unsigned long pck_min, pck_max;
148
149 /* outputs */
150
151 struct dss_pll_clock_info dsi_cinfo;
152 unsigned long fck;
153 struct dispc_clock_info dispc_cinfo;
154};
155
156static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
157 unsigned long pck, void *data)
158{
159 struct dpi_clk_calc_ctx *ctx = data;
160
161 /*
162 * Odd dividers give us uneven duty cycle, causing problem when level
163 * shifted. So skip all odd dividers when the pixel clock is on the
164 * higher side.
165 */
166 if (ctx->pck_min >= 100000000) {
167 if (lckd > 1 && lckd % 2 != 0)
168 return false;
169
170 if (pckd > 1 && pckd % 2 != 0)
171 return false;
172 }
173
174 ctx->dispc_cinfo.lck_div = lckd;
175 ctx->dispc_cinfo.pck_div = pckd;
176 ctx->dispc_cinfo.lck = lck;
177 ctx->dispc_cinfo.pck = pck;
178
179 return true;
180}
181
182
183static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
184 void *data)
185{
186 struct dpi_clk_calc_ctx *ctx = data;
187
188 /*
189 * Odd dividers give us uneven duty cycle, causing problem when level
190 * shifted. So skip all odd dividers when the pixel clock is on the
191 * higher side.
192 */
193 if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
194 return false;
195
196 ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
197 ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
198
199 return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
200 dpi_calc_dispc_cb, ctx);
201}
202
203
204static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
205 unsigned long clkdco,
206 void *data)
207{
208 struct dpi_clk_calc_ctx *ctx = data;
209
210 ctx->dsi_cinfo.n = n;
211 ctx->dsi_cinfo.m = m;
212 ctx->dsi_cinfo.fint = fint;
213 ctx->dsi_cinfo.clkdco = clkdco;
214
215 return dss_pll_hsdiv_calc(ctx->pll, clkdco,
216 ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
217 dpi_calc_hsdiv_cb, ctx);
218}
219
220static bool dpi_calc_dss_cb(unsigned long fck, void *data)
221{
222 struct dpi_clk_calc_ctx *ctx = data;
223
224 ctx->fck = fck;
225
226 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
227 dpi_calc_dispc_cb, ctx);
228}
229
230static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
231 struct dpi_clk_calc_ctx *ctx)
232{
233 unsigned long clkin;
234 unsigned long pll_min, pll_max;
235
236 memset(ctx, 0, sizeof(*ctx));
237 ctx->pll = dpi->pll;
238 ctx->pck_min = pck - 1000;
239 ctx->pck_max = pck + 1000;
240
241 pll_min = 0;
242 pll_max = 0;
243
244 clkin = clk_get_rate(ctx->pll->clkin);
245
246 return dss_pll_calc(ctx->pll, clkin,
247 pll_min, pll_max,
248 dpi_calc_pll_cb, ctx);
249}
250
251static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
252{
253 int i;
254
255 /*
256 * DSS fck gives us very few possibilities, so finding a good pixel
257 * clock may not be possible. We try multiple times to find the clock,
258 * each time widening the pixel clock range we look for, up to
259 * +/- ~15MHz.
260 */
261
262 for (i = 0; i < 25; ++i) {
263 bool ok;
264
265 memset(ctx, 0, sizeof(*ctx));
266 if (pck > 1000 * i * i * i)
267 ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
268 else
269 ctx->pck_min = 0;
270 ctx->pck_max = pck + 1000 * i * i * i;
271
272 ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
273 if (ok)
274 return ok;
275 }
276
277 return false;
278}
279
280
281
282static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
283 unsigned long pck_req, unsigned long *fck, int *lck_div,
284 int *pck_div)
285{
286 struct dpi_clk_calc_ctx ctx;
287 int r;
288 bool ok;
289
290 ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
291 if (!ok)
292 return -EINVAL;
293
294 r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
295 if (r)
296 return r;
297
298 dss_select_lcd_clk_source(channel,
299 dpi_get_alt_clk_src(channel));
300
301 dpi->mgr_config.clock_info = ctx.dispc_cinfo;
302
303 *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
304 *lck_div = ctx.dispc_cinfo.lck_div;
305 *pck_div = ctx.dispc_cinfo.pck_div;
306
307 return 0;
308}
309
310static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
311 unsigned long *fck, int *lck_div, int *pck_div)
312{
313 struct dpi_clk_calc_ctx ctx;
314 int r;
315 bool ok;
316
317 ok = dpi_dss_clk_calc(pck_req, &ctx);
318 if (!ok)
319 return -EINVAL;
320
321 r = dss_set_fck_rate(ctx.fck);
322 if (r)
323 return r;
324
325 dpi->mgr_config.clock_info = ctx.dispc_cinfo;
326
327 *fck = ctx.fck;
328 *lck_div = ctx.dispc_cinfo.lck_div;
329 *pck_div = ctx.dispc_cinfo.pck_div;
330
331 return 0;
332}
333
334static int dpi_set_mode(struct dpi_data *dpi)
335{
336 struct omap_dss_device *out = &dpi->output;
337 struct omap_overlay_manager *mgr = out->manager;
338 struct omap_video_timings *t = &dpi->timings;
339 int lck_div = 0, pck_div = 0;
340 unsigned long fck = 0;
341 unsigned long pck;
342 int r = 0;
343
344 if (dpi->pll)
345 r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
346 &lck_div, &pck_div);
347 else
348 r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
349 &lck_div, &pck_div);
350 if (r)
351 return r;
352
353 pck = fck / lck_div / pck_div;
354
355 if (pck != t->pixelclock) {
356 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
357 t->pixelclock, pck);
358
359 t->pixelclock = pck;
360 }
361
362 dss_mgr_set_timings(mgr, t);
363
364 return 0;
365}
366
367static void dpi_config_lcd_manager(struct dpi_data *dpi)
368{
369 struct omap_dss_device *out = &dpi->output;
370 struct omap_overlay_manager *mgr = out->manager;
371
372 dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
373
374 dpi->mgr_config.stallmode = false;
375 dpi->mgr_config.fifohandcheck = false;
376
377 dpi->mgr_config.video_port_width = dpi->data_lines;
378
379 dpi->mgr_config.lcden_sig_polarity = 0;
380
381 dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
382}
383
384static int dpi_display_enable(struct omap_dss_device *dssdev)
385{
386 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
387 struct omap_dss_device *out = &dpi->output;
388 int r;
389
390 mutex_lock(&dpi->lock);
391
392 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
393 DSSERR("no VDSS_DSI regulator\n");
394 r = -ENODEV;
395 goto err_no_reg;
396 }
397
398 if (out->manager == NULL) {
399 DSSERR("failed to enable display: no output/manager\n");
400 r = -ENODEV;
401 goto err_no_out_mgr;
402 }
403
404 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
405 r = regulator_enable(dpi->vdds_dsi_reg);
406 if (r)
407 goto err_reg_enable;
408 }
409
410 r = dispc_runtime_get();
411 if (r)
412 goto err_get_dispc;
413
414 r = dss_dpi_select_source(out->port_num, out->manager->id);
415 if (r)
416 goto err_src_sel;
417
418 if (dpi->pll) {
419 r = dss_pll_enable(dpi->pll);
420 if (r)
421 goto err_dsi_pll_init;
422 }
423
424 r = dpi_set_mode(dpi);
425 if (r)
426 goto err_set_mode;
427
428 dpi_config_lcd_manager(dpi);
429
430 mdelay(2);
431
432 r = dss_mgr_enable(out->manager);
433 if (r)
434 goto err_mgr_enable;
435
436 mutex_unlock(&dpi->lock);
437
438 return 0;
439
440err_mgr_enable:
441err_set_mode:
442 if (dpi->pll)
443 dss_pll_disable(dpi->pll);
444err_dsi_pll_init:
445err_src_sel:
446 dispc_runtime_put();
447err_get_dispc:
448 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
449 regulator_disable(dpi->vdds_dsi_reg);
450err_reg_enable:
451err_no_out_mgr:
452err_no_reg:
453 mutex_unlock(&dpi->lock);
454 return r;
455}
456
457static void dpi_display_disable(struct omap_dss_device *dssdev)
458{
459 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
460 struct omap_overlay_manager *mgr = dpi->output.manager;
461
462 mutex_lock(&dpi->lock);
463
464 dss_mgr_disable(mgr);
465
466 if (dpi->pll) {
467 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
468 dss_pll_disable(dpi->pll);
469 }
470
471 dispc_runtime_put();
472
473 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
474 regulator_disable(dpi->vdds_dsi_reg);
475
476 mutex_unlock(&dpi->lock);
477}
478
479static void dpi_set_timings(struct omap_dss_device *dssdev,
480 struct omap_video_timings *timings)
481{
482 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
483
484 DSSDBG("dpi_set_timings\n");
485
486 mutex_lock(&dpi->lock);
487
488 dpi->timings = *timings;
489
490 mutex_unlock(&dpi->lock);
491}
492
493static void dpi_get_timings(struct omap_dss_device *dssdev,
494 struct omap_video_timings *timings)
495{
496 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
497
498 mutex_lock(&dpi->lock);
499
500 *timings = dpi->timings;
501
502 mutex_unlock(&dpi->lock);
503}
504
505static int dpi_check_timings(struct omap_dss_device *dssdev,
506 struct omap_video_timings *timings)
507{
508 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
509 struct omap_overlay_manager *mgr = dpi->output.manager;
510 int lck_div, pck_div;
511 unsigned long fck;
512 unsigned long pck;
513 struct dpi_clk_calc_ctx ctx;
514 bool ok;
515
516 if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
517 return -EINVAL;
518
519 if (timings->pixelclock == 0)
520 return -EINVAL;
521
522 if (dpi->pll) {
523 ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
524 if (!ok)
525 return -EINVAL;
526
527 fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
528 } else {
529 ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
530 if (!ok)
531 return -EINVAL;
532
533 fck = ctx.fck;
534 }
535
536 lck_div = ctx.dispc_cinfo.lck_div;
537 pck_div = ctx.dispc_cinfo.pck_div;
538
539 pck = fck / lck_div / pck_div;
540
541 timings->pixelclock = pck;
542
543 return 0;
544}
545
546static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
547{
548 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
549
550 mutex_lock(&dpi->lock);
551
552 dpi->data_lines = data_lines;
553
554 mutex_unlock(&dpi->lock);
555}
556
557static int dpi_verify_dsi_pll(struct dss_pll *pll)
558{
559 int r;
560
561 /* do initial setup with the PLL to see if it is operational */
562
563 r = dss_pll_enable(pll);
564 if (r)
565 return r;
566
567 dss_pll_disable(pll);
568
569 return 0;
570}
571
572static int dpi_init_regulator(struct dpi_data *dpi)
573{
574 struct regulator *vdds_dsi;
575
576 if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
577 return 0;
578
579 if (dpi->vdds_dsi_reg)
580 return 0;
581
582 vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
583 if (IS_ERR(vdds_dsi)) {
584 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
585 DSSERR("can't get VDDS_DSI regulator\n");
586 return PTR_ERR(vdds_dsi);
587 }
588
589 dpi->vdds_dsi_reg = vdds_dsi;
590
591 return 0;
592}
593
594static void dpi_init_pll(struct dpi_data *dpi)
595{
596 struct dss_pll *pll;
597
598 if (dpi->pll)
599 return;
600
601 pll = dpi_get_pll(dpi->output.dispc_channel);
602 if (!pll)
603 return;
604
605 /* On DRA7 we need to set a mux to use the PLL */
606 if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
607 dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
608
609 if (dpi_verify_dsi_pll(pll)) {
610 DSSWARN("DSI PLL not operational\n");
611 return;
612 }
613
614 dpi->pll = pll;
615}
616
617/*
618 * Return a hardcoded channel for the DPI output. This should work for
619 * current use cases, but this can be later expanded to either resolve
620 * the channel in some more dynamic manner, or get the channel as a user
621 * parameter.
622 */
623static enum omap_channel dpi_get_channel(int port_num)
624{
625 switch (omapdss_get_version()) {
626 case OMAPDSS_VER_OMAP24xx:
627 case OMAPDSS_VER_OMAP34xx_ES1:
628 case OMAPDSS_VER_OMAP34xx_ES3:
629 case OMAPDSS_VER_OMAP3630:
630 case OMAPDSS_VER_AM35xx:
631 case OMAPDSS_VER_AM43xx:
632 return OMAP_DSS_CHANNEL_LCD;
633
634 case OMAPDSS_VER_DRA7xx:
635 switch (port_num) {
636 case 2:
637 return OMAP_DSS_CHANNEL_LCD3;
638 case 1:
639 return OMAP_DSS_CHANNEL_LCD2;
640 case 0:
641 default:
642 return OMAP_DSS_CHANNEL_LCD;
643 }
644
645 case OMAPDSS_VER_OMAP4430_ES1:
646 case OMAPDSS_VER_OMAP4430_ES2:
647 case OMAPDSS_VER_OMAP4:
648 return OMAP_DSS_CHANNEL_LCD2;
649
650 case OMAPDSS_VER_OMAP5:
651 return OMAP_DSS_CHANNEL_LCD3;
652
653 default:
654 DSSWARN("unsupported DSS version\n");
655 return OMAP_DSS_CHANNEL_LCD;
656 }
657}
658
659static int dpi_connect(struct omap_dss_device *dssdev,
660 struct omap_dss_device *dst)
661{
662 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
663 struct omap_overlay_manager *mgr;
664 int r;
665
666 r = dpi_init_regulator(dpi);
667 if (r)
668 return r;
669
670 dpi_init_pll(dpi);
671
672 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
673 if (!mgr)
674 return -ENODEV;
675
676 r = dss_mgr_connect(mgr, dssdev);
677 if (r)
678 return r;
679
680 r = omapdss_output_set_device(dssdev, dst);
681 if (r) {
682 DSSERR("failed to connect output to new device: %s\n",
683 dst->name);
684 dss_mgr_disconnect(mgr, dssdev);
685 return r;
686 }
687
688 return 0;
689}
690
691static void dpi_disconnect(struct omap_dss_device *dssdev,
692 struct omap_dss_device *dst)
693{
694 WARN_ON(dst != dssdev->dst);
695
696 if (dst != dssdev->dst)
697 return;
698
699 omapdss_output_unset_device(dssdev);
700
701 if (dssdev->manager)
702 dss_mgr_disconnect(dssdev->manager, dssdev);
703}
704
705static const struct omapdss_dpi_ops dpi_ops = {
706 .connect = dpi_connect,
707 .disconnect = dpi_disconnect,
708
709 .enable = dpi_display_enable,
710 .disable = dpi_display_disable,
711
712 .check_timings = dpi_check_timings,
713 .set_timings = dpi_set_timings,
714 .get_timings = dpi_get_timings,
715
716 .set_data_lines = dpi_set_data_lines,
717};
718
719static void dpi_init_output(struct platform_device *pdev)
720{
721 struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
722 struct omap_dss_device *out = &dpi->output;
723
724 out->dev = &pdev->dev;
725 out->id = OMAP_DSS_OUTPUT_DPI;
726 out->output_type = OMAP_DISPLAY_TYPE_DPI;
727 out->name = "dpi.0";
728 out->dispc_channel = dpi_get_channel(0);
729 out->ops.dpi = &dpi_ops;
730 out->owner = THIS_MODULE;
731
732 omapdss_register_output(out);
733}
734
735static void dpi_uninit_output(struct platform_device *pdev)
736{
737 struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
738 struct omap_dss_device *out = &dpi->output;
739
740 omapdss_unregister_output(out);
741}
742
743static void dpi_init_output_port(struct platform_device *pdev,
744 struct device_node *port)
745{
746 struct dpi_data *dpi = port->data;
747 struct omap_dss_device *out = &dpi->output;
748 int r;
749 u32 port_num;
750
751 r = of_property_read_u32(port, "reg", &port_num);
752 if (r)
753 port_num = 0;
754
755 switch (port_num) {
756 case 2:
757 out->name = "dpi.2";
758 break;
759 case 1:
760 out->name = "dpi.1";
761 break;
762 case 0:
763 default:
764 out->name = "dpi.0";
765 break;
766 }
767
768 out->dev = &pdev->dev;
769 out->id = OMAP_DSS_OUTPUT_DPI;
770 out->output_type = OMAP_DISPLAY_TYPE_DPI;
771 out->dispc_channel = dpi_get_channel(port_num);
772 out->port_num = port_num;
773 out->ops.dpi = &dpi_ops;
774 out->owner = THIS_MODULE;
775
776 omapdss_register_output(out);
777}
778
779static void dpi_uninit_output_port(struct device_node *port)
780{
781 struct dpi_data *dpi = port->data;
782 struct omap_dss_device *out = &dpi->output;
783
784 omapdss_unregister_output(out);
785}
786
787static int dpi_bind(struct device *dev, struct device *master, void *data)
788{
789 struct platform_device *pdev = to_platform_device(dev);
790 struct dpi_data *dpi;
791
792 dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
793 if (!dpi)
794 return -ENOMEM;
795
796 dpi->pdev = pdev;
797
798 dev_set_drvdata(&pdev->dev, dpi);
799
800 mutex_init(&dpi->lock);
801
802 dpi_init_output(pdev);
803
804 return 0;
805}
806
807static void dpi_unbind(struct device *dev, struct device *master, void *data)
808{
809 struct platform_device *pdev = to_platform_device(dev);
810
811 dpi_uninit_output(pdev);
812}
813
814static const struct component_ops dpi_component_ops = {
815 .bind = dpi_bind,
816 .unbind = dpi_unbind,
817};
818
819static int dpi_probe(struct platform_device *pdev)
820{
821 return component_add(&pdev->dev, &dpi_component_ops);
822}
823
824static int dpi_remove(struct platform_device *pdev)
825{
826 component_del(&pdev->dev, &dpi_component_ops);
827 return 0;
828}
829
830static struct platform_driver omap_dpi_driver = {
831 .probe = dpi_probe,
832 .remove = dpi_remove,
833 .driver = {
834 .name = "omapdss_dpi",
835 .suppress_bind_attrs = true,
836 },
837};
838
839int __init dpi_init_platform_driver(void)
840{
841 return platform_driver_register(&omap_dpi_driver);
842}
843
844void dpi_uninit_platform_driver(void)
845{
846 platform_driver_unregister(&omap_dpi_driver);
847}
848
849int dpi_init_port(struct platform_device *pdev, struct device_node *port)
850{
851 struct dpi_data *dpi;
852 struct device_node *ep;
853 u32 datalines;
854 int r;
855
856 dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
857 if (!dpi)
858 return -ENOMEM;
859
860 ep = omapdss_of_get_next_endpoint(port, NULL);
861 if (!ep)
862 return 0;
863
864 r = of_property_read_u32(ep, "data-lines", &datalines);
865 if (r) {
866 DSSERR("failed to parse datalines\n");
867 goto err_datalines;
868 }
869
870 dpi->data_lines = datalines;
871
872 of_node_put(ep);
873
874 dpi->pdev = pdev;
875 port->data = dpi;
876
877 mutex_init(&dpi->lock);
878
879 dpi_init_output_port(pdev, port);
880
881 dpi->port_initialized = true;
882
883 return 0;
884
885err_datalines:
886 of_node_put(ep);
887
888 return r;
889}
890
891void dpi_uninit_port(struct device_node *port)
892{
893 struct dpi_data *dpi = port->data;
894
895 if (!dpi->port_initialized)
896 return;
897
898 dpi_uninit_output_port(port);
899}
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
new file mode 100644
index 000000000000..43be4b2a7b05
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -0,0 +1,5607 @@
1/*
2 * linux/drivers/video/omap2/dss/dsi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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#define DSS_SUBSYS_NAME "DSI"
21
22#include <linux/kernel.h>
23#include <linux/io.h>
24#include <linux/clk.h>
25#include <linux/device.h>
26#include <linux/err.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/mutex.h>
30#include <linux/module.h>
31#include <linux/semaphore.h>
32#include <linux/seq_file.h>
33#include <linux/platform_device.h>
34#include <linux/regulator/consumer.h>
35#include <linux/wait.h>
36#include <linux/workqueue.h>
37#include <linux/sched.h>
38#include <linux/slab.h>
39#include <linux/debugfs.h>
40#include <linux/pm_runtime.h>
41#include <linux/of.h>
42#include <linux/of_platform.h>
43#include <linux/component.h>
44
45#include <video/omapdss.h>
46#include <video/mipi_display.h>
47
48#include "dss.h"
49#include "dss_features.h"
50
51#define DSI_CATCH_MISSING_TE
52
53struct dsi_reg { u16 module; u16 idx; };
54
55#define DSI_REG(mod, idx) ((const struct dsi_reg) { mod, idx })
56
57/* DSI Protocol Engine */
58
59#define DSI_PROTO 0
60#define DSI_PROTO_SZ 0x200
61
62#define DSI_REVISION DSI_REG(DSI_PROTO, 0x0000)
63#define DSI_SYSCONFIG DSI_REG(DSI_PROTO, 0x0010)
64#define DSI_SYSSTATUS DSI_REG(DSI_PROTO, 0x0014)
65#define DSI_IRQSTATUS DSI_REG(DSI_PROTO, 0x0018)
66#define DSI_IRQENABLE DSI_REG(DSI_PROTO, 0x001C)
67#define DSI_CTRL DSI_REG(DSI_PROTO, 0x0040)
68#define DSI_GNQ DSI_REG(DSI_PROTO, 0x0044)
69#define DSI_COMPLEXIO_CFG1 DSI_REG(DSI_PROTO, 0x0048)
70#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(DSI_PROTO, 0x004C)
71#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(DSI_PROTO, 0x0050)
72#define DSI_CLK_CTRL DSI_REG(DSI_PROTO, 0x0054)
73#define DSI_TIMING1 DSI_REG(DSI_PROTO, 0x0058)
74#define DSI_TIMING2 DSI_REG(DSI_PROTO, 0x005C)
75#define DSI_VM_TIMING1 DSI_REG(DSI_PROTO, 0x0060)
76#define DSI_VM_TIMING2 DSI_REG(DSI_PROTO, 0x0064)
77#define DSI_VM_TIMING3 DSI_REG(DSI_PROTO, 0x0068)
78#define DSI_CLK_TIMING DSI_REG(DSI_PROTO, 0x006C)
79#define DSI_TX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0070)
80#define DSI_RX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0074)
81#define DSI_COMPLEXIO_CFG2 DSI_REG(DSI_PROTO, 0x0078)
82#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(DSI_PROTO, 0x007C)
83#define DSI_VM_TIMING4 DSI_REG(DSI_PROTO, 0x0080)
84#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(DSI_PROTO, 0x0084)
85#define DSI_VM_TIMING5 DSI_REG(DSI_PROTO, 0x0088)
86#define DSI_VM_TIMING6 DSI_REG(DSI_PROTO, 0x008C)
87#define DSI_VM_TIMING7 DSI_REG(DSI_PROTO, 0x0090)
88#define DSI_STOPCLK_TIMING DSI_REG(DSI_PROTO, 0x0094)
89#define DSI_VC_CTRL(n) DSI_REG(DSI_PROTO, 0x0100 + (n * 0x20))
90#define DSI_VC_TE(n) DSI_REG(DSI_PROTO, 0x0104 + (n * 0x20))
91#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0108 + (n * 0x20))
92#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(DSI_PROTO, 0x010C + (n * 0x20))
93#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0110 + (n * 0x20))
94#define DSI_VC_IRQSTATUS(n) DSI_REG(DSI_PROTO, 0x0118 + (n * 0x20))
95#define DSI_VC_IRQENABLE(n) DSI_REG(DSI_PROTO, 0x011C + (n * 0x20))
96
97/* DSIPHY_SCP */
98
99#define DSI_PHY 1
100#define DSI_PHY_OFFSET 0x200
101#define DSI_PHY_SZ 0x40
102
103#define DSI_DSIPHY_CFG0 DSI_REG(DSI_PHY, 0x0000)
104#define DSI_DSIPHY_CFG1 DSI_REG(DSI_PHY, 0x0004)
105#define DSI_DSIPHY_CFG2 DSI_REG(DSI_PHY, 0x0008)
106#define DSI_DSIPHY_CFG5 DSI_REG(DSI_PHY, 0x0014)
107#define DSI_DSIPHY_CFG10 DSI_REG(DSI_PHY, 0x0028)
108
109/* DSI_PLL_CTRL_SCP */
110
111#define DSI_PLL 2
112#define DSI_PLL_OFFSET 0x300
113#define DSI_PLL_SZ 0x20
114
115#define DSI_PLL_CONTROL DSI_REG(DSI_PLL, 0x0000)
116#define DSI_PLL_STATUS DSI_REG(DSI_PLL, 0x0004)
117#define DSI_PLL_GO DSI_REG(DSI_PLL, 0x0008)
118#define DSI_PLL_CONFIGURATION1 DSI_REG(DSI_PLL, 0x000C)
119#define DSI_PLL_CONFIGURATION2 DSI_REG(DSI_PLL, 0x0010)
120
121#define REG_GET(dsidev, idx, start, end) \
122 FLD_GET(dsi_read_reg(dsidev, idx), start, end)
123
124#define REG_FLD_MOD(dsidev, idx, val, start, end) \
125 dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
126
127/* Global interrupts */
128#define DSI_IRQ_VC0 (1 << 0)
129#define DSI_IRQ_VC1 (1 << 1)
130#define DSI_IRQ_VC2 (1 << 2)
131#define DSI_IRQ_VC3 (1 << 3)
132#define DSI_IRQ_WAKEUP (1 << 4)
133#define DSI_IRQ_RESYNC (1 << 5)
134#define DSI_IRQ_PLL_LOCK (1 << 7)
135#define DSI_IRQ_PLL_UNLOCK (1 << 8)
136#define DSI_IRQ_PLL_RECALL (1 << 9)
137#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
138#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
139#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
140#define DSI_IRQ_TE_TRIGGER (1 << 16)
141#define DSI_IRQ_ACK_TRIGGER (1 << 17)
142#define DSI_IRQ_SYNC_LOST (1 << 18)
143#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
144#define DSI_IRQ_TA_TIMEOUT (1 << 20)
145#define DSI_IRQ_ERROR_MASK \
146 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
147 DSI_IRQ_TA_TIMEOUT)
148#define DSI_IRQ_CHANNEL_MASK 0xf
149
150/* Virtual channel interrupts */
151#define DSI_VC_IRQ_CS (1 << 0)
152#define DSI_VC_IRQ_ECC_CORR (1 << 1)
153#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
154#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
155#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
156#define DSI_VC_IRQ_BTA (1 << 5)
157#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
158#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
159#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
160#define DSI_VC_IRQ_ERROR_MASK \
161 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
162 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
163 DSI_VC_IRQ_FIFO_TX_UDF)
164
165/* ComplexIO interrupts */
166#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
167#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
168#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
169#define DSI_CIO_IRQ_ERRSYNCESC4 (1 << 3)
170#define DSI_CIO_IRQ_ERRSYNCESC5 (1 << 4)
171#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
172#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
173#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
174#define DSI_CIO_IRQ_ERRESC4 (1 << 8)
175#define DSI_CIO_IRQ_ERRESC5 (1 << 9)
176#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
177#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
178#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
179#define DSI_CIO_IRQ_ERRCONTROL4 (1 << 13)
180#define DSI_CIO_IRQ_ERRCONTROL5 (1 << 14)
181#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
182#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
183#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
184#define DSI_CIO_IRQ_STATEULPS4 (1 << 18)
185#define DSI_CIO_IRQ_STATEULPS5 (1 << 19)
186#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
187#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
188#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
189#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
190#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
191#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
192#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
193#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
194#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
195#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
196#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
197#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
198#define DSI_CIO_IRQ_ERROR_MASK \
199 (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
200 DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
201 DSI_CIO_IRQ_ERRSYNCESC5 | \
202 DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
203 DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
204 DSI_CIO_IRQ_ERRESC5 | \
205 DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
206 DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
207 DSI_CIO_IRQ_ERRCONTROL5 | \
208 DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
209 DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
210 DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
211 DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
212 DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
213
214typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
215
216static int dsi_display_init_dispc(struct platform_device *dsidev,
217 struct omap_overlay_manager *mgr);
218static void dsi_display_uninit_dispc(struct platform_device *dsidev,
219 struct omap_overlay_manager *mgr);
220
221static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
222
223/* DSI PLL HSDIV indices */
224#define HSDIV_DISPC 0
225#define HSDIV_DSI 1
226
227#define DSI_MAX_NR_ISRS 2
228#define DSI_MAX_NR_LANES 5
229
230enum dsi_lane_function {
231 DSI_LANE_UNUSED = 0,
232 DSI_LANE_CLK,
233 DSI_LANE_DATA1,
234 DSI_LANE_DATA2,
235 DSI_LANE_DATA3,
236 DSI_LANE_DATA4,
237};
238
239struct dsi_lane_config {
240 enum dsi_lane_function function;
241 u8 polarity;
242};
243
244struct dsi_isr_data {
245 omap_dsi_isr_t isr;
246 void *arg;
247 u32 mask;
248};
249
250enum fifo_size {
251 DSI_FIFO_SIZE_0 = 0,
252 DSI_FIFO_SIZE_32 = 1,
253 DSI_FIFO_SIZE_64 = 2,
254 DSI_FIFO_SIZE_96 = 3,
255 DSI_FIFO_SIZE_128 = 4,
256};
257
258enum dsi_vc_source {
259 DSI_VC_SOURCE_L4 = 0,
260 DSI_VC_SOURCE_VP,
261};
262
263struct dsi_irq_stats {
264 unsigned long last_reset;
265 unsigned irq_count;
266 unsigned dsi_irqs[32];
267 unsigned vc_irqs[4][32];
268 unsigned cio_irqs[32];
269};
270
271struct dsi_isr_tables {
272 struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
273 struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
274 struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
275};
276
277struct dsi_clk_calc_ctx {
278 struct platform_device *dsidev;
279 struct dss_pll *pll;
280
281 /* inputs */
282
283 const struct omap_dss_dsi_config *config;
284
285 unsigned long req_pck_min, req_pck_nom, req_pck_max;
286
287 /* outputs */
288
289 struct dss_pll_clock_info dsi_cinfo;
290 struct dispc_clock_info dispc_cinfo;
291
292 struct omap_video_timings dispc_vm;
293 struct omap_dss_dsi_videomode_timings dsi_vm;
294};
295
296struct dsi_lp_clock_info {
297 unsigned long lp_clk;
298 u16 lp_clk_div;
299};
300
301struct dsi_data {
302 struct platform_device *pdev;
303 void __iomem *proto_base;
304 void __iomem *phy_base;
305 void __iomem *pll_base;
306
307 int module_id;
308
309 int irq;
310
311 bool is_enabled;
312
313 struct clk *dss_clk;
314
315 struct dispc_clock_info user_dispc_cinfo;
316 struct dss_pll_clock_info user_dsi_cinfo;
317
318 struct dsi_lp_clock_info user_lp_cinfo;
319 struct dsi_lp_clock_info current_lp_cinfo;
320
321 struct dss_pll pll;
322
323 bool vdds_dsi_enabled;
324 struct regulator *vdds_dsi_reg;
325
326 struct {
327 enum dsi_vc_source source;
328 struct omap_dss_device *dssdev;
329 enum fifo_size tx_fifo_size;
330 enum fifo_size rx_fifo_size;
331 int vc_id;
332 } vc[4];
333
334 struct mutex lock;
335 struct semaphore bus_lock;
336
337 spinlock_t irq_lock;
338 struct dsi_isr_tables isr_tables;
339 /* space for a copy used by the interrupt handler */
340 struct dsi_isr_tables isr_tables_copy;
341
342 int update_channel;
343#ifdef DSI_PERF_MEASURE
344 unsigned update_bytes;
345#endif
346
347 bool te_enabled;
348 bool ulps_enabled;
349
350 void (*framedone_callback)(int, void *);
351 void *framedone_data;
352
353 struct delayed_work framedone_timeout_work;
354
355#ifdef DSI_CATCH_MISSING_TE
356 struct timer_list te_timer;
357#endif
358
359 unsigned long cache_req_pck;
360 unsigned long cache_clk_freq;
361 struct dss_pll_clock_info cache_cinfo;
362
363 u32 errors;
364 spinlock_t errors_lock;
365#ifdef DSI_PERF_MEASURE
366 ktime_t perf_setup_time;
367 ktime_t perf_start_time;
368#endif
369 int debug_read;
370 int debug_write;
371
372#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
373 spinlock_t irq_stats_lock;
374 struct dsi_irq_stats irq_stats;
375#endif
376
377 unsigned num_lanes_supported;
378 unsigned line_buffer_size;
379
380 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
381 unsigned num_lanes_used;
382
383 unsigned scp_clk_refcount;
384
385 struct dss_lcd_mgr_config mgr_config;
386 struct omap_video_timings timings;
387 enum omap_dss_dsi_pixel_format pix_fmt;
388 enum omap_dss_dsi_mode mode;
389 struct omap_dss_dsi_videomode_timings vm_timings;
390
391 struct omap_dss_device output;
392};
393
394struct dsi_packet_sent_handler_data {
395 struct platform_device *dsidev;
396 struct completion *completion;
397};
398
399struct dsi_module_id_data {
400 u32 address;
401 int id;
402};
403
404static const struct of_device_id dsi_of_match[];
405
406#ifdef DSI_PERF_MEASURE
407static bool dsi_perf;
408module_param(dsi_perf, bool, 0644);
409#endif
410
411static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
412{
413 return dev_get_drvdata(&dsidev->dev);
414}
415
416static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
417{
418 return to_platform_device(dssdev->dev);
419}
420
421static struct platform_device *dsi_get_dsidev_from_id(int module)
422{
423 struct omap_dss_device *out;
424 enum omap_dss_output_id id;
425
426 switch (module) {
427 case 0:
428 id = OMAP_DSS_OUTPUT_DSI1;
429 break;
430 case 1:
431 id = OMAP_DSS_OUTPUT_DSI2;
432 break;
433 default:
434 return NULL;
435 }
436
437 out = omap_dss_get_output(id);
438
439 return out ? to_platform_device(out->dev) : NULL;
440}
441
442static inline void dsi_write_reg(struct platform_device *dsidev,
443 const struct dsi_reg idx, u32 val)
444{
445 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
446 void __iomem *base;
447
448 switch(idx.module) {
449 case DSI_PROTO: base = dsi->proto_base; break;
450 case DSI_PHY: base = dsi->phy_base; break;
451 case DSI_PLL: base = dsi->pll_base; break;
452 default: return;
453 }
454
455 __raw_writel(val, base + idx.idx);
456}
457
458static inline u32 dsi_read_reg(struct platform_device *dsidev,
459 const struct dsi_reg idx)
460{
461 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
462 void __iomem *base;
463
464 switch(idx.module) {
465 case DSI_PROTO: base = dsi->proto_base; break;
466 case DSI_PHY: base = dsi->phy_base; break;
467 case DSI_PLL: base = dsi->pll_base; break;
468 default: return 0;
469 }
470
471 return __raw_readl(base + idx.idx);
472}
473
474static void dsi_bus_lock(struct omap_dss_device *dssdev)
475{
476 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
477 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
478
479 down(&dsi->bus_lock);
480}
481
482static void dsi_bus_unlock(struct omap_dss_device *dssdev)
483{
484 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
485 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
486
487 up(&dsi->bus_lock);
488}
489
490static bool dsi_bus_is_locked(struct platform_device *dsidev)
491{
492 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
493
494 return dsi->bus_lock.count == 0;
495}
496
497static void dsi_completion_handler(void *data, u32 mask)
498{
499 complete((struct completion *)data);
500}
501
502static inline int wait_for_bit_change(struct platform_device *dsidev,
503 const struct dsi_reg idx, int bitnum, int value)
504{
505 unsigned long timeout;
506 ktime_t wait;
507 int t;
508
509 /* first busyloop to see if the bit changes right away */
510 t = 100;
511 while (t-- > 0) {
512 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
513 return value;
514 }
515
516 /* then loop for 500ms, sleeping for 1ms in between */
517 timeout = jiffies + msecs_to_jiffies(500);
518 while (time_before(jiffies, timeout)) {
519 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
520 return value;
521
522 wait = ns_to_ktime(1000 * 1000);
523 set_current_state(TASK_UNINTERRUPTIBLE);
524 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
525 }
526
527 return !value;
528}
529
530u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
531{
532 switch (fmt) {
533 case OMAP_DSS_DSI_FMT_RGB888:
534 case OMAP_DSS_DSI_FMT_RGB666:
535 return 24;
536 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
537 return 18;
538 case OMAP_DSS_DSI_FMT_RGB565:
539 return 16;
540 default:
541 BUG();
542 return 0;
543 }
544}
545
546#ifdef DSI_PERF_MEASURE
547static void dsi_perf_mark_setup(struct platform_device *dsidev)
548{
549 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
550 dsi->perf_setup_time = ktime_get();
551}
552
553static void dsi_perf_mark_start(struct platform_device *dsidev)
554{
555 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
556 dsi->perf_start_time = ktime_get();
557}
558
559static void dsi_perf_show(struct platform_device *dsidev, const char *name)
560{
561 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
562 ktime_t t, setup_time, trans_time;
563 u32 total_bytes;
564 u32 setup_us, trans_us, total_us;
565
566 if (!dsi_perf)
567 return;
568
569 t = ktime_get();
570
571 setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
572 setup_us = (u32)ktime_to_us(setup_time);
573 if (setup_us == 0)
574 setup_us = 1;
575
576 trans_time = ktime_sub(t, dsi->perf_start_time);
577 trans_us = (u32)ktime_to_us(trans_time);
578 if (trans_us == 0)
579 trans_us = 1;
580
581 total_us = setup_us + trans_us;
582
583 total_bytes = dsi->update_bytes;
584
585 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
586 "%u bytes, %u kbytes/sec\n",
587 name,
588 setup_us,
589 trans_us,
590 total_us,
591 1000*1000 / total_us,
592 total_bytes,
593 total_bytes * 1000 / total_us);
594}
595#else
596static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
597{
598}
599
600static inline void dsi_perf_mark_start(struct platform_device *dsidev)
601{
602}
603
604static inline void dsi_perf_show(struct platform_device *dsidev,
605 const char *name)
606{
607}
608#endif
609
610static int verbose_irq;
611
612static void print_irq_status(u32 status)
613{
614 if (status == 0)
615 return;
616
617 if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0)
618 return;
619
620#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : ""
621
622 pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
623 status,
624 verbose_irq ? PIS(VC0) : "",
625 verbose_irq ? PIS(VC1) : "",
626 verbose_irq ? PIS(VC2) : "",
627 verbose_irq ? PIS(VC3) : "",
628 PIS(WAKEUP),
629 PIS(RESYNC),
630 PIS(PLL_LOCK),
631 PIS(PLL_UNLOCK),
632 PIS(PLL_RECALL),
633 PIS(COMPLEXIO_ERR),
634 PIS(HS_TX_TIMEOUT),
635 PIS(LP_RX_TIMEOUT),
636 PIS(TE_TRIGGER),
637 PIS(ACK_TRIGGER),
638 PIS(SYNC_LOST),
639 PIS(LDO_POWER_GOOD),
640 PIS(TA_TIMEOUT));
641#undef PIS
642}
643
644static void print_irq_status_vc(int channel, u32 status)
645{
646 if (status == 0)
647 return;
648
649 if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
650 return;
651
652#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : ""
653
654 pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n",
655 channel,
656 status,
657 PIS(CS),
658 PIS(ECC_CORR),
659 PIS(ECC_NO_CORR),
660 verbose_irq ? PIS(PACKET_SENT) : "",
661 PIS(BTA),
662 PIS(FIFO_TX_OVF),
663 PIS(FIFO_RX_OVF),
664 PIS(FIFO_TX_UDF),
665 PIS(PP_BUSY_CHANGE));
666#undef PIS
667}
668
669static void print_irq_status_cio(u32 status)
670{
671 if (status == 0)
672 return;
673
674#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : ""
675
676 pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
677 status,
678 PIS(ERRSYNCESC1),
679 PIS(ERRSYNCESC2),
680 PIS(ERRSYNCESC3),
681 PIS(ERRESC1),
682 PIS(ERRESC2),
683 PIS(ERRESC3),
684 PIS(ERRCONTROL1),
685 PIS(ERRCONTROL2),
686 PIS(ERRCONTROL3),
687 PIS(STATEULPS1),
688 PIS(STATEULPS2),
689 PIS(STATEULPS3),
690 PIS(ERRCONTENTIONLP0_1),
691 PIS(ERRCONTENTIONLP1_1),
692 PIS(ERRCONTENTIONLP0_2),
693 PIS(ERRCONTENTIONLP1_2),
694 PIS(ERRCONTENTIONLP0_3),
695 PIS(ERRCONTENTIONLP1_3),
696 PIS(ULPSACTIVENOT_ALL0),
697 PIS(ULPSACTIVENOT_ALL1));
698#undef PIS
699}
700
701#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
702static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
703 u32 *vcstatus, u32 ciostatus)
704{
705 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
706 int i;
707
708 spin_lock(&dsi->irq_stats_lock);
709
710 dsi->irq_stats.irq_count++;
711 dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
712
713 for (i = 0; i < 4; ++i)
714 dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
715
716 dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
717
718 spin_unlock(&dsi->irq_stats_lock);
719}
720#else
721#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
722#endif
723
724static int debug_irq;
725
726static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
727 u32 *vcstatus, u32 ciostatus)
728{
729 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
730 int i;
731
732 if (irqstatus & DSI_IRQ_ERROR_MASK) {
733 DSSERR("DSI error, irqstatus %x\n", irqstatus);
734 print_irq_status(irqstatus);
735 spin_lock(&dsi->errors_lock);
736 dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
737 spin_unlock(&dsi->errors_lock);
738 } else if (debug_irq) {
739 print_irq_status(irqstatus);
740 }
741
742 for (i = 0; i < 4; ++i) {
743 if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
744 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
745 i, vcstatus[i]);
746 print_irq_status_vc(i, vcstatus[i]);
747 } else if (debug_irq) {
748 print_irq_status_vc(i, vcstatus[i]);
749 }
750 }
751
752 if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
753 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
754 print_irq_status_cio(ciostatus);
755 } else if (debug_irq) {
756 print_irq_status_cio(ciostatus);
757 }
758}
759
760static void dsi_call_isrs(struct dsi_isr_data *isr_array,
761 unsigned isr_array_size, u32 irqstatus)
762{
763 struct dsi_isr_data *isr_data;
764 int i;
765
766 for (i = 0; i < isr_array_size; i++) {
767 isr_data = &isr_array[i];
768 if (isr_data->isr && isr_data->mask & irqstatus)
769 isr_data->isr(isr_data->arg, irqstatus);
770 }
771}
772
773static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
774 u32 irqstatus, u32 *vcstatus, u32 ciostatus)
775{
776 int i;
777
778 dsi_call_isrs(isr_tables->isr_table,
779 ARRAY_SIZE(isr_tables->isr_table),
780 irqstatus);
781
782 for (i = 0; i < 4; ++i) {
783 if (vcstatus[i] == 0)
784 continue;
785 dsi_call_isrs(isr_tables->isr_table_vc[i],
786 ARRAY_SIZE(isr_tables->isr_table_vc[i]),
787 vcstatus[i]);
788 }
789
790 if (ciostatus != 0)
791 dsi_call_isrs(isr_tables->isr_table_cio,
792 ARRAY_SIZE(isr_tables->isr_table_cio),
793 ciostatus);
794}
795
796static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
797{
798 struct platform_device *dsidev;
799 struct dsi_data *dsi;
800 u32 irqstatus, vcstatus[4], ciostatus;
801 int i;
802
803 dsidev = (struct platform_device *) arg;
804 dsi = dsi_get_dsidrv_data(dsidev);
805
806 if (!dsi->is_enabled)
807 return IRQ_NONE;
808
809 spin_lock(&dsi->irq_lock);
810
811 irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
812
813 /* IRQ is not for us */
814 if (!irqstatus) {
815 spin_unlock(&dsi->irq_lock);
816 return IRQ_NONE;
817 }
818
819 dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
820 /* flush posted write */
821 dsi_read_reg(dsidev, DSI_IRQSTATUS);
822
823 for (i = 0; i < 4; ++i) {
824 if ((irqstatus & (1 << i)) == 0) {
825 vcstatus[i] = 0;
826 continue;
827 }
828
829 vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
830
831 dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
832 /* flush posted write */
833 dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
834 }
835
836 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
837 ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
838
839 dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
840 /* flush posted write */
841 dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
842 } else {
843 ciostatus = 0;
844 }
845
846#ifdef DSI_CATCH_MISSING_TE
847 if (irqstatus & DSI_IRQ_TE_TRIGGER)
848 del_timer(&dsi->te_timer);
849#endif
850
851 /* make a copy and unlock, so that isrs can unregister
852 * themselves */
853 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
854 sizeof(dsi->isr_tables));
855
856 spin_unlock(&dsi->irq_lock);
857
858 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
859
860 dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
861
862 dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
863
864 return IRQ_HANDLED;
865}
866
867/* dsi->irq_lock has to be locked by the caller */
868static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
869 struct dsi_isr_data *isr_array,
870 unsigned isr_array_size, u32 default_mask,
871 const struct dsi_reg enable_reg,
872 const struct dsi_reg status_reg)
873{
874 struct dsi_isr_data *isr_data;
875 u32 mask;
876 u32 old_mask;
877 int i;
878
879 mask = default_mask;
880
881 for (i = 0; i < isr_array_size; i++) {
882 isr_data = &isr_array[i];
883
884 if (isr_data->isr == NULL)
885 continue;
886
887 mask |= isr_data->mask;
888 }
889
890 old_mask = dsi_read_reg(dsidev, enable_reg);
891 /* clear the irqstatus for newly enabled irqs */
892 dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
893 dsi_write_reg(dsidev, enable_reg, mask);
894
895 /* flush posted writes */
896 dsi_read_reg(dsidev, enable_reg);
897 dsi_read_reg(dsidev, status_reg);
898}
899
900/* dsi->irq_lock has to be locked by the caller */
901static void _omap_dsi_set_irqs(struct platform_device *dsidev)
902{
903 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
904 u32 mask = DSI_IRQ_ERROR_MASK;
905#ifdef DSI_CATCH_MISSING_TE
906 mask |= DSI_IRQ_TE_TRIGGER;
907#endif
908 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
909 ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
910 DSI_IRQENABLE, DSI_IRQSTATUS);
911}
912
913/* dsi->irq_lock has to be locked by the caller */
914static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
915{
916 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
917
918 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
919 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
920 DSI_VC_IRQ_ERROR_MASK,
921 DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
922}
923
924/* dsi->irq_lock has to be locked by the caller */
925static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
926{
927 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
928
929 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
930 ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
931 DSI_CIO_IRQ_ERROR_MASK,
932 DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
933}
934
935static void _dsi_initialize_irq(struct platform_device *dsidev)
936{
937 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
938 unsigned long flags;
939 int vc;
940
941 spin_lock_irqsave(&dsi->irq_lock, flags);
942
943 memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
944
945 _omap_dsi_set_irqs(dsidev);
946 for (vc = 0; vc < 4; ++vc)
947 _omap_dsi_set_irqs_vc(dsidev, vc);
948 _omap_dsi_set_irqs_cio(dsidev);
949
950 spin_unlock_irqrestore(&dsi->irq_lock, flags);
951}
952
953static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
954 struct dsi_isr_data *isr_array, unsigned isr_array_size)
955{
956 struct dsi_isr_data *isr_data;
957 int free_idx;
958 int i;
959
960 BUG_ON(isr == NULL);
961
962 /* check for duplicate entry and find a free slot */
963 free_idx = -1;
964 for (i = 0; i < isr_array_size; i++) {
965 isr_data = &isr_array[i];
966
967 if (isr_data->isr == isr && isr_data->arg == arg &&
968 isr_data->mask == mask) {
969 return -EINVAL;
970 }
971
972 if (isr_data->isr == NULL && free_idx == -1)
973 free_idx = i;
974 }
975
976 if (free_idx == -1)
977 return -EBUSY;
978
979 isr_data = &isr_array[free_idx];
980 isr_data->isr = isr;
981 isr_data->arg = arg;
982 isr_data->mask = mask;
983
984 return 0;
985}
986
987static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
988 struct dsi_isr_data *isr_array, unsigned isr_array_size)
989{
990 struct dsi_isr_data *isr_data;
991 int i;
992
993 for (i = 0; i < isr_array_size; i++) {
994 isr_data = &isr_array[i];
995 if (isr_data->isr != isr || isr_data->arg != arg ||
996 isr_data->mask != mask)
997 continue;
998
999 isr_data->isr = NULL;
1000 isr_data->arg = NULL;
1001 isr_data->mask = 0;
1002
1003 return 0;
1004 }
1005
1006 return -EINVAL;
1007}
1008
1009static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
1010 void *arg, u32 mask)
1011{
1012 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1013 unsigned long flags;
1014 int r;
1015
1016 spin_lock_irqsave(&dsi->irq_lock, flags);
1017
1018 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
1019 ARRAY_SIZE(dsi->isr_tables.isr_table));
1020
1021 if (r == 0)
1022 _omap_dsi_set_irqs(dsidev);
1023
1024 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1025
1026 return r;
1027}
1028
1029static int dsi_unregister_isr(struct platform_device *dsidev,
1030 omap_dsi_isr_t isr, void *arg, u32 mask)
1031{
1032 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1033 unsigned long flags;
1034 int r;
1035
1036 spin_lock_irqsave(&dsi->irq_lock, flags);
1037
1038 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
1039 ARRAY_SIZE(dsi->isr_tables.isr_table));
1040
1041 if (r == 0)
1042 _omap_dsi_set_irqs(dsidev);
1043
1044 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1045
1046 return r;
1047}
1048
1049static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
1050 omap_dsi_isr_t isr, void *arg, u32 mask)
1051{
1052 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1053 unsigned long flags;
1054 int r;
1055
1056 spin_lock_irqsave(&dsi->irq_lock, flags);
1057
1058 r = _dsi_register_isr(isr, arg, mask,
1059 dsi->isr_tables.isr_table_vc[channel],
1060 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
1061
1062 if (r == 0)
1063 _omap_dsi_set_irqs_vc(dsidev, channel);
1064
1065 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1066
1067 return r;
1068}
1069
1070static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
1071 omap_dsi_isr_t isr, void *arg, u32 mask)
1072{
1073 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1074 unsigned long flags;
1075 int r;
1076
1077 spin_lock_irqsave(&dsi->irq_lock, flags);
1078
1079 r = _dsi_unregister_isr(isr, arg, mask,
1080 dsi->isr_tables.isr_table_vc[channel],
1081 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
1082
1083 if (r == 0)
1084 _omap_dsi_set_irqs_vc(dsidev, channel);
1085
1086 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1087
1088 return r;
1089}
1090
1091static int dsi_register_isr_cio(struct platform_device *dsidev,
1092 omap_dsi_isr_t isr, void *arg, u32 mask)
1093{
1094 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1095 unsigned long flags;
1096 int r;
1097
1098 spin_lock_irqsave(&dsi->irq_lock, flags);
1099
1100 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1101 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
1102
1103 if (r == 0)
1104 _omap_dsi_set_irqs_cio(dsidev);
1105
1106 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1107
1108 return r;
1109}
1110
1111static int dsi_unregister_isr_cio(struct platform_device *dsidev,
1112 omap_dsi_isr_t isr, void *arg, u32 mask)
1113{
1114 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1115 unsigned long flags;
1116 int r;
1117
1118 spin_lock_irqsave(&dsi->irq_lock, flags);
1119
1120 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1121 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
1122
1123 if (r == 0)
1124 _omap_dsi_set_irqs_cio(dsidev);
1125
1126 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1127
1128 return r;
1129}
1130
1131static u32 dsi_get_errors(struct platform_device *dsidev)
1132{
1133 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1134 unsigned long flags;
1135 u32 e;
1136 spin_lock_irqsave(&dsi->errors_lock, flags);
1137 e = dsi->errors;
1138 dsi->errors = 0;
1139 spin_unlock_irqrestore(&dsi->errors_lock, flags);
1140 return e;
1141}
1142
1143static int dsi_runtime_get(struct platform_device *dsidev)
1144{
1145 int r;
1146 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1147
1148 DSSDBG("dsi_runtime_get\n");
1149
1150 r = pm_runtime_get_sync(&dsi->pdev->dev);
1151 WARN_ON(r < 0);
1152 return r < 0 ? r : 0;
1153}
1154
1155static void dsi_runtime_put(struct platform_device *dsidev)
1156{
1157 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1158 int r;
1159
1160 DSSDBG("dsi_runtime_put\n");
1161
1162 r = pm_runtime_put_sync(&dsi->pdev->dev);
1163 WARN_ON(r < 0 && r != -ENOSYS);
1164}
1165
1166static int dsi_regulator_init(struct platform_device *dsidev)
1167{
1168 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1169 struct regulator *vdds_dsi;
1170 int r;
1171
1172 if (dsi->vdds_dsi_reg != NULL)
1173 return 0;
1174
1175 vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd");
1176
1177 if (IS_ERR(vdds_dsi)) {
1178 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
1179 DSSERR("can't get DSI VDD regulator\n");
1180 return PTR_ERR(vdds_dsi);
1181 }
1182
1183 if (regulator_can_change_voltage(vdds_dsi)) {
1184 r = regulator_set_voltage(vdds_dsi, 1800000, 1800000);
1185 if (r) {
1186 devm_regulator_put(vdds_dsi);
1187 DSSERR("can't set the DSI regulator voltage\n");
1188 return r;
1189 }
1190 }
1191
1192 dsi->vdds_dsi_reg = vdds_dsi;
1193
1194 return 0;
1195}
1196
1197static void _dsi_print_reset_status(struct platform_device *dsidev)
1198{
1199 u32 l;
1200 int b0, b1, b2;
1201
1202 /* A dummy read using the SCP interface to any DSIPHY register is
1203 * required after DSIPHY reset to complete the reset of the DSI complex
1204 * I/O. */
1205 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
1206
1207 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
1208 b0 = 28;
1209 b1 = 27;
1210 b2 = 26;
1211 } else {
1212 b0 = 24;
1213 b1 = 25;
1214 b2 = 26;
1215 }
1216
1217#define DSI_FLD_GET(fld, start, end)\
1218 FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end)
1219
1220 pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n",
1221 DSI_FLD_GET(PLL_STATUS, 0, 0),
1222 DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29),
1223 DSI_FLD_GET(DSIPHY_CFG5, b0, b0),
1224 DSI_FLD_GET(DSIPHY_CFG5, b1, b1),
1225 DSI_FLD_GET(DSIPHY_CFG5, b2, b2),
1226 DSI_FLD_GET(DSIPHY_CFG5, 29, 29),
1227 DSI_FLD_GET(DSIPHY_CFG5, 30, 30),
1228 DSI_FLD_GET(DSIPHY_CFG5, 31, 31));
1229
1230#undef DSI_FLD_GET
1231}
1232
1233static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
1234{
1235 DSSDBG("dsi_if_enable(%d)\n", enable);
1236
1237 enable = enable ? 1 : 0;
1238 REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
1239
1240 if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
1241 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
1242 return -EIO;
1243 }
1244
1245 return 0;
1246}
1247
1248static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
1249{
1250 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1251
1252 return dsi->pll.cinfo.clkout[HSDIV_DISPC];
1253}
1254
1255static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
1256{
1257 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1258
1259 return dsi->pll.cinfo.clkout[HSDIV_DSI];
1260}
1261
1262static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
1263{
1264 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1265
1266 return dsi->pll.cinfo.clkdco / 16;
1267}
1268
1269static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
1270{
1271 unsigned long r;
1272 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1273
1274 if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
1275 /* DSI FCLK source is DSS_CLK_FCK */
1276 r = clk_get_rate(dsi->dss_clk);
1277 } else {
1278 /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
1279 r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
1280 }
1281
1282 return r;
1283}
1284
1285static int dsi_lp_clock_calc(unsigned long dsi_fclk,
1286 unsigned long lp_clk_min, unsigned long lp_clk_max,
1287 struct dsi_lp_clock_info *lp_cinfo)
1288{
1289 unsigned lp_clk_div;
1290 unsigned long lp_clk;
1291
1292 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
1293 lp_clk = dsi_fclk / 2 / lp_clk_div;
1294
1295 if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
1296 return -EINVAL;
1297
1298 lp_cinfo->lp_clk_div = lp_clk_div;
1299 lp_cinfo->lp_clk = lp_clk;
1300
1301 return 0;
1302}
1303
1304static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
1305{
1306 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1307 unsigned long dsi_fclk;
1308 unsigned lp_clk_div;
1309 unsigned long lp_clk;
1310 unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
1311
1312
1313 lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;
1314
1315 if (lp_clk_div == 0 || lp_clk_div > lpdiv_max)
1316 return -EINVAL;
1317
1318 dsi_fclk = dsi_fclk_rate(dsidev);
1319
1320 lp_clk = dsi_fclk / 2 / lp_clk_div;
1321
1322 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
1323 dsi->current_lp_cinfo.lp_clk = lp_clk;
1324 dsi->current_lp_cinfo.lp_clk_div = lp_clk_div;
1325
1326 /* LP_CLK_DIVISOR */
1327 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
1328
1329 /* LP_RX_SYNCHRO_ENABLE */
1330 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
1331
1332 return 0;
1333}
1334
1335static void dsi_enable_scp_clk(struct platform_device *dsidev)
1336{
1337 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1338
1339 if (dsi->scp_clk_refcount++ == 0)
1340 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
1341}
1342
1343static void dsi_disable_scp_clk(struct platform_device *dsidev)
1344{
1345 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1346
1347 WARN_ON(dsi->scp_clk_refcount == 0);
1348 if (--dsi->scp_clk_refcount == 0)
1349 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
1350}
1351
1352enum dsi_pll_power_state {
1353 DSI_PLL_POWER_OFF = 0x0,
1354 DSI_PLL_POWER_ON_HSCLK = 0x1,
1355 DSI_PLL_POWER_ON_ALL = 0x2,
1356 DSI_PLL_POWER_ON_DIV = 0x3,
1357};
1358
1359static int dsi_pll_power(struct platform_device *dsidev,
1360 enum dsi_pll_power_state state)
1361{
1362 int t = 0;
1363
1364 /* DSI-PLL power command 0x3 is not working */
1365 if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
1366 state == DSI_PLL_POWER_ON_DIV)
1367 state = DSI_PLL_POWER_ON_ALL;
1368
1369 /* PLL_PWR_CMD */
1370 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
1371
1372 /* PLL_PWR_STATUS */
1373 while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
1374 if (++t > 1000) {
1375 DSSERR("Failed to set DSI PLL power mode to %d\n",
1376 state);
1377 return -ENODEV;
1378 }
1379 udelay(1);
1380 }
1381
1382 return 0;
1383}
1384
1385
1386static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo)
1387{
1388 unsigned long max_dsi_fck;
1389
1390 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
1391
1392 cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
1393 cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
1394}
1395
1396static int dsi_pll_enable(struct dss_pll *pll)
1397{
1398 struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
1399 struct platform_device *dsidev = dsi->pdev;
1400 int r = 0;
1401
1402 DSSDBG("PLL init\n");
1403
1404 r = dsi_regulator_init(dsidev);
1405 if (r)
1406 return r;
1407
1408 r = dsi_runtime_get(dsidev);
1409 if (r)
1410 return r;
1411
1412 /*
1413 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
1414 */
1415 dsi_enable_scp_clk(dsidev);
1416
1417 if (!dsi->vdds_dsi_enabled) {
1418 r = regulator_enable(dsi->vdds_dsi_reg);
1419 if (r)
1420 goto err0;
1421 dsi->vdds_dsi_enabled = true;
1422 }
1423
1424 /* XXX PLL does not come out of reset without this... */
1425 dispc_pck_free_enable(1);
1426
1427 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
1428 DSSERR("PLL not coming out of reset.\n");
1429 r = -ENODEV;
1430 dispc_pck_free_enable(0);
1431 goto err1;
1432 }
1433
1434 /* XXX ... but if left on, we get problems when planes do not
1435 * fill the whole display. No idea about this */
1436 dispc_pck_free_enable(0);
1437
1438 r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL);
1439
1440 if (r)
1441 goto err1;
1442
1443 DSSDBG("PLL init done\n");
1444
1445 return 0;
1446err1:
1447 if (dsi->vdds_dsi_enabled) {
1448 regulator_disable(dsi->vdds_dsi_reg);
1449 dsi->vdds_dsi_enabled = false;
1450 }
1451err0:
1452 dsi_disable_scp_clk(dsidev);
1453 dsi_runtime_put(dsidev);
1454 return r;
1455}
1456
1457static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
1458{
1459 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1460
1461 dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
1462 if (disconnect_lanes) {
1463 WARN_ON(!dsi->vdds_dsi_enabled);
1464 regulator_disable(dsi->vdds_dsi_reg);
1465 dsi->vdds_dsi_enabled = false;
1466 }
1467
1468 dsi_disable_scp_clk(dsidev);
1469 dsi_runtime_put(dsidev);
1470
1471 DSSDBG("PLL uninit done\n");
1472}
1473
1474static void dsi_pll_disable(struct dss_pll *pll)
1475{
1476 struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
1477 struct platform_device *dsidev = dsi->pdev;
1478
1479 dsi_pll_uninit(dsidev, true);
1480}
1481
1482static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
1483 struct seq_file *s)
1484{
1485 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1486 struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
1487 enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
1488 int dsi_module = dsi->module_id;
1489 struct dss_pll *pll = &dsi->pll;
1490
1491 dispc_clk_src = dss_get_dispc_clk_source();
1492 dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
1493
1494 if (dsi_runtime_get(dsidev))
1495 return;
1496
1497 seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
1498
1499 seq_printf(s, "dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin));
1500
1501 seq_printf(s, "Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n);
1502
1503 seq_printf(s, "CLKIN4DDR\t%-16lum %u\n",
1504 cinfo->clkdco, cinfo->m);
1505
1506 seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n",
1507 dss_feat_get_clk_source_name(dsi_module == 0 ?
1508 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
1509 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
1510 cinfo->clkout[HSDIV_DISPC],
1511 cinfo->mX[HSDIV_DISPC],
1512 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1513 "off" : "on");
1514
1515 seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n",
1516 dss_feat_get_clk_source_name(dsi_module == 0 ?
1517 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
1518 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
1519 cinfo->clkout[HSDIV_DSI],
1520 cinfo->mX[HSDIV_DSI],
1521 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1522 "off" : "on");
1523
1524 seq_printf(s, "- DSI%d -\n", dsi_module + 1);
1525
1526 seq_printf(s, "dsi fclk source = %s (%s)\n",
1527 dss_get_generic_clk_source_name(dsi_clk_src),
1528 dss_feat_get_clk_source_name(dsi_clk_src));
1529
1530 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
1531
1532 seq_printf(s, "DDR_CLK\t\t%lu\n",
1533 cinfo->clkdco / 4);
1534
1535 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
1536
1537 seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
1538
1539 dsi_runtime_put(dsidev);
1540}
1541
1542void dsi_dump_clocks(struct seq_file *s)
1543{
1544 struct platform_device *dsidev;
1545 int i;
1546
1547 for (i = 0; i < MAX_NUM_DSI; i++) {
1548 dsidev = dsi_get_dsidev_from_id(i);
1549 if (dsidev)
1550 dsi_dump_dsidev_clocks(dsidev, s);
1551 }
1552}
1553
1554#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1555static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
1556 struct seq_file *s)
1557{
1558 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1559 unsigned long flags;
1560 struct dsi_irq_stats stats;
1561
1562 spin_lock_irqsave(&dsi->irq_stats_lock, flags);
1563
1564 stats = dsi->irq_stats;
1565 memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
1566 dsi->irq_stats.last_reset = jiffies;
1567
1568 spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
1569
1570 seq_printf(s, "period %u ms\n",
1571 jiffies_to_msecs(jiffies - stats.last_reset));
1572
1573 seq_printf(s, "irqs %d\n", stats.irq_count);
1574#define PIS(x) \
1575 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1576
1577 seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
1578 PIS(VC0);
1579 PIS(VC1);
1580 PIS(VC2);
1581 PIS(VC3);
1582 PIS(WAKEUP);
1583 PIS(RESYNC);
1584 PIS(PLL_LOCK);
1585 PIS(PLL_UNLOCK);
1586 PIS(PLL_RECALL);
1587 PIS(COMPLEXIO_ERR);
1588 PIS(HS_TX_TIMEOUT);
1589 PIS(LP_RX_TIMEOUT);
1590 PIS(TE_TRIGGER);
1591 PIS(ACK_TRIGGER);
1592 PIS(SYNC_LOST);
1593 PIS(LDO_POWER_GOOD);
1594 PIS(TA_TIMEOUT);
1595#undef PIS
1596
1597#define PIS(x) \
1598 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1599 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1600 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1601 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1602 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1603
1604 seq_printf(s, "-- VC interrupts --\n");
1605 PIS(CS);
1606 PIS(ECC_CORR);
1607 PIS(PACKET_SENT);
1608 PIS(FIFO_TX_OVF);
1609 PIS(FIFO_RX_OVF);
1610 PIS(BTA);
1611 PIS(ECC_NO_CORR);
1612 PIS(FIFO_TX_UDF);
1613 PIS(PP_BUSY_CHANGE);
1614#undef PIS
1615
1616#define PIS(x) \
1617 seq_printf(s, "%-20s %10d\n", #x, \
1618 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1619
1620 seq_printf(s, "-- CIO interrupts --\n");
1621 PIS(ERRSYNCESC1);
1622 PIS(ERRSYNCESC2);
1623 PIS(ERRSYNCESC3);
1624 PIS(ERRESC1);
1625 PIS(ERRESC2);
1626 PIS(ERRESC3);
1627 PIS(ERRCONTROL1);
1628 PIS(ERRCONTROL2);
1629 PIS(ERRCONTROL3);
1630 PIS(STATEULPS1);
1631 PIS(STATEULPS2);
1632 PIS(STATEULPS3);
1633 PIS(ERRCONTENTIONLP0_1);
1634 PIS(ERRCONTENTIONLP1_1);
1635 PIS(ERRCONTENTIONLP0_2);
1636 PIS(ERRCONTENTIONLP1_2);
1637 PIS(ERRCONTENTIONLP0_3);
1638 PIS(ERRCONTENTIONLP1_3);
1639 PIS(ULPSACTIVENOT_ALL0);
1640 PIS(ULPSACTIVENOT_ALL1);
1641#undef PIS
1642}
1643
1644static void dsi1_dump_irqs(struct seq_file *s)
1645{
1646 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1647
1648 dsi_dump_dsidev_irqs(dsidev, s);
1649}
1650
1651static void dsi2_dump_irqs(struct seq_file *s)
1652{
1653 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
1654
1655 dsi_dump_dsidev_irqs(dsidev, s);
1656}
1657#endif
1658
1659static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
1660 struct seq_file *s)
1661{
1662#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
1663
1664 if (dsi_runtime_get(dsidev))
1665 return;
1666 dsi_enable_scp_clk(dsidev);
1667
1668 DUMPREG(DSI_REVISION);
1669 DUMPREG(DSI_SYSCONFIG);
1670 DUMPREG(DSI_SYSSTATUS);
1671 DUMPREG(DSI_IRQSTATUS);
1672 DUMPREG(DSI_IRQENABLE);
1673 DUMPREG(DSI_CTRL);
1674 DUMPREG(DSI_COMPLEXIO_CFG1);
1675 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1676 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1677 DUMPREG(DSI_CLK_CTRL);
1678 DUMPREG(DSI_TIMING1);
1679 DUMPREG(DSI_TIMING2);
1680 DUMPREG(DSI_VM_TIMING1);
1681 DUMPREG(DSI_VM_TIMING2);
1682 DUMPREG(DSI_VM_TIMING3);
1683 DUMPREG(DSI_CLK_TIMING);
1684 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1685 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1686 DUMPREG(DSI_COMPLEXIO_CFG2);
1687 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1688 DUMPREG(DSI_VM_TIMING4);
1689 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1690 DUMPREG(DSI_VM_TIMING5);
1691 DUMPREG(DSI_VM_TIMING6);
1692 DUMPREG(DSI_VM_TIMING7);
1693 DUMPREG(DSI_STOPCLK_TIMING);
1694
1695 DUMPREG(DSI_VC_CTRL(0));
1696 DUMPREG(DSI_VC_TE(0));
1697 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1698 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1699 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1700 DUMPREG(DSI_VC_IRQSTATUS(0));
1701 DUMPREG(DSI_VC_IRQENABLE(0));
1702
1703 DUMPREG(DSI_VC_CTRL(1));
1704 DUMPREG(DSI_VC_TE(1));
1705 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1706 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1707 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1708 DUMPREG(DSI_VC_IRQSTATUS(1));
1709 DUMPREG(DSI_VC_IRQENABLE(1));
1710
1711 DUMPREG(DSI_VC_CTRL(2));
1712 DUMPREG(DSI_VC_TE(2));
1713 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1714 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1715 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1716 DUMPREG(DSI_VC_IRQSTATUS(2));
1717 DUMPREG(DSI_VC_IRQENABLE(2));
1718
1719 DUMPREG(DSI_VC_CTRL(3));
1720 DUMPREG(DSI_VC_TE(3));
1721 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1722 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1723 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1724 DUMPREG(DSI_VC_IRQSTATUS(3));
1725 DUMPREG(DSI_VC_IRQENABLE(3));
1726
1727 DUMPREG(DSI_DSIPHY_CFG0);
1728 DUMPREG(DSI_DSIPHY_CFG1);
1729 DUMPREG(DSI_DSIPHY_CFG2);
1730 DUMPREG(DSI_DSIPHY_CFG5);
1731
1732 DUMPREG(DSI_PLL_CONTROL);
1733 DUMPREG(DSI_PLL_STATUS);
1734 DUMPREG(DSI_PLL_GO);
1735 DUMPREG(DSI_PLL_CONFIGURATION1);
1736 DUMPREG(DSI_PLL_CONFIGURATION2);
1737
1738 dsi_disable_scp_clk(dsidev);
1739 dsi_runtime_put(dsidev);
1740#undef DUMPREG
1741}
1742
1743static void dsi1_dump_regs(struct seq_file *s)
1744{
1745 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1746
1747 dsi_dump_dsidev_regs(dsidev, s);
1748}
1749
1750static void dsi2_dump_regs(struct seq_file *s)
1751{
1752 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
1753
1754 dsi_dump_dsidev_regs(dsidev, s);
1755}
1756
1757enum dsi_cio_power_state {
1758 DSI_COMPLEXIO_POWER_OFF = 0x0,
1759 DSI_COMPLEXIO_POWER_ON = 0x1,
1760 DSI_COMPLEXIO_POWER_ULPS = 0x2,
1761};
1762
1763static int dsi_cio_power(struct platform_device *dsidev,
1764 enum dsi_cio_power_state state)
1765{
1766 int t = 0;
1767
1768 /* PWR_CMD */
1769 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
1770
1771 /* PWR_STATUS */
1772 while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
1773 26, 25) != state) {
1774 if (++t > 1000) {
1775 DSSERR("failed to set complexio power state to "
1776 "%d\n", state);
1777 return -ENODEV;
1778 }
1779 udelay(1);
1780 }
1781
1782 return 0;
1783}
1784
1785static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
1786{
1787 int val;
1788
1789 /* line buffer on OMAP3 is 1024 x 24bits */
1790 /* XXX: for some reason using full buffer size causes
1791 * considerable TX slowdown with update sizes that fill the
1792 * whole buffer */
1793 if (!dss_has_feature(FEAT_DSI_GNQ))
1794 return 1023 * 3;
1795
1796 val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
1797
1798 switch (val) {
1799 case 1:
1800 return 512 * 3; /* 512x24 bits */
1801 case 2:
1802 return 682 * 3; /* 682x24 bits */
1803 case 3:
1804 return 853 * 3; /* 853x24 bits */
1805 case 4:
1806 return 1024 * 3; /* 1024x24 bits */
1807 case 5:
1808 return 1194 * 3; /* 1194x24 bits */
1809 case 6:
1810 return 1365 * 3; /* 1365x24 bits */
1811 case 7:
1812 return 1920 * 3; /* 1920x24 bits */
1813 default:
1814 BUG();
1815 return 0;
1816 }
1817}
1818
1819static int dsi_set_lane_config(struct platform_device *dsidev)
1820{
1821 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1822 static const u8 offsets[] = { 0, 4, 8, 12, 16 };
1823 static const enum dsi_lane_function functions[] = {
1824 DSI_LANE_CLK,
1825 DSI_LANE_DATA1,
1826 DSI_LANE_DATA2,
1827 DSI_LANE_DATA3,
1828 DSI_LANE_DATA4,
1829 };
1830 u32 r;
1831 int i;
1832
1833 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
1834
1835 for (i = 0; i < dsi->num_lanes_used; ++i) {
1836 unsigned offset = offsets[i];
1837 unsigned polarity, lane_number;
1838 unsigned t;
1839
1840 for (t = 0; t < dsi->num_lanes_supported; ++t)
1841 if (dsi->lanes[t].function == functions[i])
1842 break;
1843
1844 if (t == dsi->num_lanes_supported)
1845 return -EINVAL;
1846
1847 lane_number = t;
1848 polarity = dsi->lanes[t].polarity;
1849
1850 r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
1851 r = FLD_MOD(r, polarity, offset + 3, offset + 3);
1852 }
1853
1854 /* clear the unused lanes */
1855 for (; i < dsi->num_lanes_supported; ++i) {
1856 unsigned offset = offsets[i];
1857
1858 r = FLD_MOD(r, 0, offset + 2, offset);
1859 r = FLD_MOD(r, 0, offset + 3, offset + 3);
1860 }
1861
1862 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
1863
1864 return 0;
1865}
1866
1867static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
1868{
1869 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1870
1871 /* convert time in ns to ddr ticks, rounding up */
1872 unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
1873 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
1874}
1875
1876static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
1877{
1878 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1879
1880 unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
1881 return ddr * 1000 * 1000 / (ddr_clk / 1000);
1882}
1883
1884static void dsi_cio_timings(struct platform_device *dsidev)
1885{
1886 u32 r;
1887 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
1888 u32 tlpx_half, tclk_trail, tclk_zero;
1889 u32 tclk_prepare;
1890
1891 /* calculate timings */
1892
1893 /* 1 * DDR_CLK = 2 * UI */
1894
1895 /* min 40ns + 4*UI max 85ns + 6*UI */
1896 ths_prepare = ns2ddr(dsidev, 70) + 2;
1897
1898 /* min 145ns + 10*UI */
1899 ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
1900
1901 /* min max(8*UI, 60ns+4*UI) */
1902 ths_trail = ns2ddr(dsidev, 60) + 5;
1903
1904 /* min 100ns */
1905 ths_exit = ns2ddr(dsidev, 145);
1906
1907 /* tlpx min 50n */
1908 tlpx_half = ns2ddr(dsidev, 25);
1909
1910 /* min 60ns */
1911 tclk_trail = ns2ddr(dsidev, 60) + 2;
1912
1913 /* min 38ns, max 95ns */
1914 tclk_prepare = ns2ddr(dsidev, 65);
1915
1916 /* min tclk-prepare + tclk-zero = 300ns */
1917 tclk_zero = ns2ddr(dsidev, 260);
1918
1919 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
1920 ths_prepare, ddr2ns(dsidev, ths_prepare),
1921 ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
1922 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
1923 ths_trail, ddr2ns(dsidev, ths_trail),
1924 ths_exit, ddr2ns(dsidev, ths_exit));
1925
1926 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
1927 "tclk_zero %u (%uns)\n",
1928 tlpx_half, ddr2ns(dsidev, tlpx_half),
1929 tclk_trail, ddr2ns(dsidev, tclk_trail),
1930 tclk_zero, ddr2ns(dsidev, tclk_zero));
1931 DSSDBG("tclk_prepare %u (%uns)\n",
1932 tclk_prepare, ddr2ns(dsidev, tclk_prepare));
1933
1934 /* program timings */
1935
1936 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
1937 r = FLD_MOD(r, ths_prepare, 31, 24);
1938 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
1939 r = FLD_MOD(r, ths_trail, 15, 8);
1940 r = FLD_MOD(r, ths_exit, 7, 0);
1941 dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
1942
1943 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
1944 r = FLD_MOD(r, tlpx_half, 20, 16);
1945 r = FLD_MOD(r, tclk_trail, 15, 8);
1946 r = FLD_MOD(r, tclk_zero, 7, 0);
1947
1948 if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
1949 r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
1950 r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
1951 r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
1952 }
1953
1954 dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
1955
1956 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
1957 r = FLD_MOD(r, tclk_prepare, 7, 0);
1958 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
1959}
1960
1961/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
1962static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
1963 unsigned mask_p, unsigned mask_n)
1964{
1965 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1966 int i;
1967 u32 l;
1968 u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
1969
1970 l = 0;
1971
1972 for (i = 0; i < dsi->num_lanes_supported; ++i) {
1973 unsigned p = dsi->lanes[i].polarity;
1974
1975 if (mask_p & (1 << i))
1976 l |= 1 << (i * 2 + (p ? 0 : 1));
1977
1978 if (mask_n & (1 << i))
1979 l |= 1 << (i * 2 + (p ? 1 : 0));
1980 }
1981
1982 /*
1983 * Bits in REGLPTXSCPDAT4TO0DXDY:
1984 * 17: DY0 18: DX0
1985 * 19: DY1 20: DX1
1986 * 21: DY2 22: DX2
1987 * 23: DY3 24: DX3
1988 * 25: DY4 26: DX4
1989 */
1990
1991 /* Set the lane override configuration */
1992
1993 /* REGLPTXSCPDAT4TO0DXDY */
1994 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
1995
1996 /* Enable lane override */
1997
1998 /* ENLPTXSCPDAT */
1999 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
2000}
2001
2002static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
2003{
2004 /* Disable lane override */
2005 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
2006 /* Reset the lane override configuration */
2007 /* REGLPTXSCPDAT4TO0DXDY */
2008 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
2009}
2010
2011static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
2012{
2013 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2014 int t, i;
2015 bool in_use[DSI_MAX_NR_LANES];
2016 static const u8 offsets_old[] = { 28, 27, 26 };
2017 static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
2018 const u8 *offsets;
2019
2020 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
2021 offsets = offsets_old;
2022 else
2023 offsets = offsets_new;
2024
2025 for (i = 0; i < dsi->num_lanes_supported; ++i)
2026 in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
2027
2028 t = 100000;
2029 while (true) {
2030 u32 l;
2031 int ok;
2032
2033 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2034
2035 ok = 0;
2036 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2037 if (!in_use[i] || (l & (1 << offsets[i])))
2038 ok++;
2039 }
2040
2041 if (ok == dsi->num_lanes_supported)
2042 break;
2043
2044 if (--t == 0) {
2045 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2046 if (!in_use[i] || (l & (1 << offsets[i])))
2047 continue;
2048
2049 DSSERR("CIO TXCLKESC%d domain not coming " \
2050 "out of reset\n", i);
2051 }
2052 return -EIO;
2053 }
2054 }
2055
2056 return 0;
2057}
2058
2059/* return bitmask of enabled lanes, lane0 being the lsb */
2060static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
2061{
2062 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2063 unsigned mask = 0;
2064 int i;
2065
2066 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2067 if (dsi->lanes[i].function != DSI_LANE_UNUSED)
2068 mask |= 1 << i;
2069 }
2070
2071 return mask;
2072}
2073
2074static int dsi_cio_init(struct platform_device *dsidev)
2075{
2076 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2077 int r;
2078 u32 l;
2079
2080 DSSDBG("DSI CIO init starts");
2081
2082 r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2083 if (r)
2084 return r;
2085
2086 dsi_enable_scp_clk(dsidev);
2087
2088 /* A dummy read using the SCP interface to any DSIPHY register is
2089 * required after DSIPHY reset to complete the reset of the DSI complex
2090 * I/O. */
2091 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2092
2093 if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
2094 DSSERR("CIO SCP Clock domain not coming out of reset.\n");
2095 r = -EIO;
2096 goto err_scp_clk_dom;
2097 }
2098
2099 r = dsi_set_lane_config(dsidev);
2100 if (r)
2101 goto err_scp_clk_dom;
2102
2103 /* set TX STOP MODE timer to maximum for this operation */
2104 l = dsi_read_reg(dsidev, DSI_TIMING1);
2105 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2106 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
2107 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
2108 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
2109 dsi_write_reg(dsidev, DSI_TIMING1, l);
2110
2111 if (dsi->ulps_enabled) {
2112 unsigned mask_p;
2113 int i;
2114
2115 DSSDBG("manual ulps exit\n");
2116
2117 /* ULPS is exited by Mark-1 state for 1ms, followed by
2118 * stop state. DSS HW cannot do this via the normal
2119 * ULPS exit sequence, as after reset the DSS HW thinks
2120 * that we are not in ULPS mode, and refuses to send the
2121 * sequence. So we need to send the ULPS exit sequence
2122 * manually by setting positive lines high and negative lines
2123 * low for 1ms.
2124 */
2125
2126 mask_p = 0;
2127
2128 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2129 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
2130 continue;
2131 mask_p |= 1 << i;
2132 }
2133
2134 dsi_cio_enable_lane_override(dsidev, mask_p, 0);
2135 }
2136
2137 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
2138 if (r)
2139 goto err_cio_pwr;
2140
2141 if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
2142 DSSERR("CIO PWR clock domain not coming out of reset.\n");
2143 r = -ENODEV;
2144 goto err_cio_pwr_dom;
2145 }
2146
2147 dsi_if_enable(dsidev, true);
2148 dsi_if_enable(dsidev, false);
2149 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
2150
2151 r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
2152 if (r)
2153 goto err_tx_clk_esc_rst;
2154
2155 if (dsi->ulps_enabled) {
2156 /* Keep Mark-1 state for 1ms (as per DSI spec) */
2157 ktime_t wait = ns_to_ktime(1000 * 1000);
2158 set_current_state(TASK_UNINTERRUPTIBLE);
2159 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
2160
2161 /* Disable the override. The lanes should be set to Mark-11
2162 * state by the HW */
2163 dsi_cio_disable_lane_override(dsidev);
2164 }
2165
2166 /* FORCE_TX_STOP_MODE_IO */
2167 REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
2168
2169 dsi_cio_timings(dsidev);
2170
2171 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
2172 /* DDR_CLK_ALWAYS_ON */
2173 REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
2174 dsi->vm_timings.ddr_clk_always_on, 13, 13);
2175 }
2176
2177 dsi->ulps_enabled = false;
2178
2179 DSSDBG("CIO init done\n");
2180
2181 return 0;
2182
2183err_tx_clk_esc_rst:
2184 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
2185err_cio_pwr_dom:
2186 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2187err_cio_pwr:
2188 if (dsi->ulps_enabled)
2189 dsi_cio_disable_lane_override(dsidev);
2190err_scp_clk_dom:
2191 dsi_disable_scp_clk(dsidev);
2192 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2193 return r;
2194}
2195
2196static void dsi_cio_uninit(struct platform_device *dsidev)
2197{
2198 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2199
2200 /* DDR_CLK_ALWAYS_ON */
2201 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
2202
2203 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2204 dsi_disable_scp_clk(dsidev);
2205 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2206}
2207
2208static void dsi_config_tx_fifo(struct platform_device *dsidev,
2209 enum fifo_size size1, enum fifo_size size2,
2210 enum fifo_size size3, enum fifo_size size4)
2211{
2212 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2213 u32 r = 0;
2214 int add = 0;
2215 int i;
2216
2217 dsi->vc[0].tx_fifo_size = size1;
2218 dsi->vc[1].tx_fifo_size = size2;
2219 dsi->vc[2].tx_fifo_size = size3;
2220 dsi->vc[3].tx_fifo_size = size4;
2221
2222 for (i = 0; i < 4; i++) {
2223 u8 v;
2224 int size = dsi->vc[i].tx_fifo_size;
2225
2226 if (add + size > 4) {
2227 DSSERR("Illegal FIFO configuration\n");
2228 BUG();
2229 return;
2230 }
2231
2232 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2233 r |= v << (8 * i);
2234 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
2235 add += size;
2236 }
2237
2238 dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
2239}
2240
2241static void dsi_config_rx_fifo(struct platform_device *dsidev,
2242 enum fifo_size size1, enum fifo_size size2,
2243 enum fifo_size size3, enum fifo_size size4)
2244{
2245 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2246 u32 r = 0;
2247 int add = 0;
2248 int i;
2249
2250 dsi->vc[0].rx_fifo_size = size1;
2251 dsi->vc[1].rx_fifo_size = size2;
2252 dsi->vc[2].rx_fifo_size = size3;
2253 dsi->vc[3].rx_fifo_size = size4;
2254
2255 for (i = 0; i < 4; i++) {
2256 u8 v;
2257 int size = dsi->vc[i].rx_fifo_size;
2258
2259 if (add + size > 4) {
2260 DSSERR("Illegal FIFO configuration\n");
2261 BUG();
2262 return;
2263 }
2264
2265 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2266 r |= v << (8 * i);
2267 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
2268 add += size;
2269 }
2270
2271 dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
2272}
2273
2274static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
2275{
2276 u32 r;
2277
2278 r = dsi_read_reg(dsidev, DSI_TIMING1);
2279 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2280 dsi_write_reg(dsidev, DSI_TIMING1, r);
2281
2282 if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
2283 DSSERR("TX_STOP bit not going down\n");
2284 return -EIO;
2285 }
2286
2287 return 0;
2288}
2289
2290static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
2291{
2292 return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
2293}
2294
2295static void dsi_packet_sent_handler_vp(void *data, u32 mask)
2296{
2297 struct dsi_packet_sent_handler_data *vp_data =
2298 (struct dsi_packet_sent_handler_data *) data;
2299 struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
2300 const int channel = dsi->update_channel;
2301 u8 bit = dsi->te_enabled ? 30 : 31;
2302
2303 if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
2304 complete(vp_data->completion);
2305}
2306
2307static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
2308{
2309 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2310 DECLARE_COMPLETION_ONSTACK(completion);
2311 struct dsi_packet_sent_handler_data vp_data = {
2312 .dsidev = dsidev,
2313 .completion = &completion
2314 };
2315 int r = 0;
2316 u8 bit;
2317
2318 bit = dsi->te_enabled ? 30 : 31;
2319
2320 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2321 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2322 if (r)
2323 goto err0;
2324
2325 /* Wait for completion only if TE_EN/TE_START is still set */
2326 if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
2327 if (wait_for_completion_timeout(&completion,
2328 msecs_to_jiffies(10)) == 0) {
2329 DSSERR("Failed to complete previous frame transfer\n");
2330 r = -EIO;
2331 goto err1;
2332 }
2333 }
2334
2335 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2336 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2337
2338 return 0;
2339err1:
2340 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2341 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2342err0:
2343 return r;
2344}
2345
2346static void dsi_packet_sent_handler_l4(void *data, u32 mask)
2347{
2348 struct dsi_packet_sent_handler_data *l4_data =
2349 (struct dsi_packet_sent_handler_data *) data;
2350 struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
2351 const int channel = dsi->update_channel;
2352
2353 if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
2354 complete(l4_data->completion);
2355}
2356
2357static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
2358{
2359 DECLARE_COMPLETION_ONSTACK(completion);
2360 struct dsi_packet_sent_handler_data l4_data = {
2361 .dsidev = dsidev,
2362 .completion = &completion
2363 };
2364 int r = 0;
2365
2366 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2367 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2368 if (r)
2369 goto err0;
2370
2371 /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
2372 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
2373 if (wait_for_completion_timeout(&completion,
2374 msecs_to_jiffies(10)) == 0) {
2375 DSSERR("Failed to complete previous l4 transfer\n");
2376 r = -EIO;
2377 goto err1;
2378 }
2379 }
2380
2381 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2382 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2383
2384 return 0;
2385err1:
2386 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2387 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2388err0:
2389 return r;
2390}
2391
2392static int dsi_sync_vc(struct platform_device *dsidev, int channel)
2393{
2394 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2395
2396 WARN_ON(!dsi_bus_is_locked(dsidev));
2397
2398 WARN_ON(in_interrupt());
2399
2400 if (!dsi_vc_is_enabled(dsidev, channel))
2401 return 0;
2402
2403 switch (dsi->vc[channel].source) {
2404 case DSI_VC_SOURCE_VP:
2405 return dsi_sync_vc_vp(dsidev, channel);
2406 case DSI_VC_SOURCE_L4:
2407 return dsi_sync_vc_l4(dsidev, channel);
2408 default:
2409 BUG();
2410 return -EINVAL;
2411 }
2412}
2413
2414static int dsi_vc_enable(struct platform_device *dsidev, int channel,
2415 bool enable)
2416{
2417 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
2418 channel, enable);
2419
2420 enable = enable ? 1 : 0;
2421
2422 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
2423
2424 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
2425 0, enable) != enable) {
2426 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
2427 return -EIO;
2428 }
2429
2430 return 0;
2431}
2432
2433static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
2434{
2435 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2436 u32 r;
2437
2438 DSSDBG("Initial config of virtual channel %d", channel);
2439
2440 r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2441
2442 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
2443 DSSERR("VC(%d) busy when trying to configure it!\n",
2444 channel);
2445
2446 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
2447 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
2448 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
2449 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
2450 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
2451 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
2452 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
2453 if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
2454 r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
2455
2456 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
2457 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
2458
2459 dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
2460
2461 dsi->vc[channel].source = DSI_VC_SOURCE_L4;
2462}
2463
2464static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
2465 enum dsi_vc_source source)
2466{
2467 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2468
2469 if (dsi->vc[channel].source == source)
2470 return 0;
2471
2472 DSSDBG("Source config of virtual channel %d", channel);
2473
2474 dsi_sync_vc(dsidev, channel);
2475
2476 dsi_vc_enable(dsidev, channel, 0);
2477
2478 /* VC_BUSY */
2479 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
2480 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
2481 return -EIO;
2482 }
2483
2484 /* SOURCE, 0 = L4, 1 = video port */
2485 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
2486
2487 /* DCS_CMD_ENABLE */
2488 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
2489 bool enable = source == DSI_VC_SOURCE_VP;
2490 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
2491 }
2492
2493 dsi_vc_enable(dsidev, channel, 1);
2494
2495 dsi->vc[channel].source = source;
2496
2497 return 0;
2498}
2499
2500static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
2501 bool enable)
2502{
2503 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2504 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2505
2506 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
2507
2508 WARN_ON(!dsi_bus_is_locked(dsidev));
2509
2510 dsi_vc_enable(dsidev, channel, 0);
2511 dsi_if_enable(dsidev, 0);
2512
2513 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
2514
2515 dsi_vc_enable(dsidev, channel, 1);
2516 dsi_if_enable(dsidev, 1);
2517
2518 dsi_force_tx_stop_mode_io(dsidev);
2519
2520 /* start the DDR clock by sending a NULL packet */
2521 if (dsi->vm_timings.ddr_clk_always_on && enable)
2522 dsi_vc_send_null(dssdev, channel);
2523}
2524
2525static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
2526{
2527 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2528 u32 val;
2529 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2530 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
2531 (val >> 0) & 0xff,
2532 (val >> 8) & 0xff,
2533 (val >> 16) & 0xff,
2534 (val >> 24) & 0xff);
2535 }
2536}
2537
2538static void dsi_show_rx_ack_with_err(u16 err)
2539{
2540 DSSERR("\tACK with ERROR (%#x):\n", err);
2541 if (err & (1 << 0))
2542 DSSERR("\t\tSoT Error\n");
2543 if (err & (1 << 1))
2544 DSSERR("\t\tSoT Sync Error\n");
2545 if (err & (1 << 2))
2546 DSSERR("\t\tEoT Sync Error\n");
2547 if (err & (1 << 3))
2548 DSSERR("\t\tEscape Mode Entry Command Error\n");
2549 if (err & (1 << 4))
2550 DSSERR("\t\tLP Transmit Sync Error\n");
2551 if (err & (1 << 5))
2552 DSSERR("\t\tHS Receive Timeout Error\n");
2553 if (err & (1 << 6))
2554 DSSERR("\t\tFalse Control Error\n");
2555 if (err & (1 << 7))
2556 DSSERR("\t\t(reserved7)\n");
2557 if (err & (1 << 8))
2558 DSSERR("\t\tECC Error, single-bit (corrected)\n");
2559 if (err & (1 << 9))
2560 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
2561 if (err & (1 << 10))
2562 DSSERR("\t\tChecksum Error\n");
2563 if (err & (1 << 11))
2564 DSSERR("\t\tData type not recognized\n");
2565 if (err & (1 << 12))
2566 DSSERR("\t\tInvalid VC ID\n");
2567 if (err & (1 << 13))
2568 DSSERR("\t\tInvalid Transmission Length\n");
2569 if (err & (1 << 14))
2570 DSSERR("\t\t(reserved14)\n");
2571 if (err & (1 << 15))
2572 DSSERR("\t\tDSI Protocol Violation\n");
2573}
2574
2575static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
2576 int channel)
2577{
2578 /* RX_FIFO_NOT_EMPTY */
2579 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2580 u32 val;
2581 u8 dt;
2582 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2583 DSSERR("\trawval %#08x\n", val);
2584 dt = FLD_GET(val, 5, 0);
2585 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
2586 u16 err = FLD_GET(val, 23, 8);
2587 dsi_show_rx_ack_with_err(err);
2588 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
2589 DSSERR("\tDCS short response, 1 byte: %#x\n",
2590 FLD_GET(val, 23, 8));
2591 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
2592 DSSERR("\tDCS short response, 2 byte: %#x\n",
2593 FLD_GET(val, 23, 8));
2594 } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
2595 DSSERR("\tDCS long response, len %d\n",
2596 FLD_GET(val, 23, 8));
2597 dsi_vc_flush_long_data(dsidev, channel);
2598 } else {
2599 DSSERR("\tunknown datatype 0x%02x\n", dt);
2600 }
2601 }
2602 return 0;
2603}
2604
2605static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
2606{
2607 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2608
2609 if (dsi->debug_write || dsi->debug_read)
2610 DSSDBG("dsi_vc_send_bta %d\n", channel);
2611
2612 WARN_ON(!dsi_bus_is_locked(dsidev));
2613
2614 /* RX_FIFO_NOT_EMPTY */
2615 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2616 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
2617 dsi_vc_flush_receive_data(dsidev, channel);
2618 }
2619
2620 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
2621
2622 /* flush posted write */
2623 dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2624
2625 return 0;
2626}
2627
2628static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
2629{
2630 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2631 DECLARE_COMPLETION_ONSTACK(completion);
2632 int r = 0;
2633 u32 err;
2634
2635 r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
2636 &completion, DSI_VC_IRQ_BTA);
2637 if (r)
2638 goto err0;
2639
2640 r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
2641 DSI_IRQ_ERROR_MASK);
2642 if (r)
2643 goto err1;
2644
2645 r = dsi_vc_send_bta(dsidev, channel);
2646 if (r)
2647 goto err2;
2648
2649 if (wait_for_completion_timeout(&completion,
2650 msecs_to_jiffies(500)) == 0) {
2651 DSSERR("Failed to receive BTA\n");
2652 r = -EIO;
2653 goto err2;
2654 }
2655
2656 err = dsi_get_errors(dsidev);
2657 if (err) {
2658 DSSERR("Error while sending BTA: %x\n", err);
2659 r = -EIO;
2660 goto err2;
2661 }
2662err2:
2663 dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
2664 DSI_IRQ_ERROR_MASK);
2665err1:
2666 dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
2667 &completion, DSI_VC_IRQ_BTA);
2668err0:
2669 return r;
2670}
2671
2672static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
2673 int channel, u8 data_type, u16 len, u8 ecc)
2674{
2675 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2676 u32 val;
2677 u8 data_id;
2678
2679 WARN_ON(!dsi_bus_is_locked(dsidev));
2680
2681 data_id = data_type | dsi->vc[channel].vc_id << 6;
2682
2683 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
2684 FLD_VAL(ecc, 31, 24);
2685
2686 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
2687}
2688
2689static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
2690 int channel, u8 b1, u8 b2, u8 b3, u8 b4)
2691{
2692 u32 val;
2693
2694 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
2695
2696/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
2697 b1, b2, b3, b4, val); */
2698
2699 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
2700}
2701
2702static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
2703 u8 data_type, u8 *data, u16 len, u8 ecc)
2704{
2705 /*u32 val; */
2706 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2707 int i;
2708 u8 *p;
2709 int r = 0;
2710 u8 b1, b2, b3, b4;
2711
2712 if (dsi->debug_write)
2713 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
2714
2715 /* len + header */
2716 if (dsi->vc[channel].tx_fifo_size * 32 * 4 < len + 4) {
2717 DSSERR("unable to send long packet: packet too long.\n");
2718 return -EINVAL;
2719 }
2720
2721 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
2722
2723 dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
2724
2725 p = data;
2726 for (i = 0; i < len >> 2; i++) {
2727 if (dsi->debug_write)
2728 DSSDBG("\tsending full packet %d\n", i);
2729
2730 b1 = *p++;
2731 b2 = *p++;
2732 b3 = *p++;
2733 b4 = *p++;
2734
2735 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
2736 }
2737
2738 i = len % 4;
2739 if (i) {
2740 b1 = 0; b2 = 0; b3 = 0;
2741
2742 if (dsi->debug_write)
2743 DSSDBG("\tsending remainder bytes %d\n", i);
2744
2745 switch (i) {
2746 case 3:
2747 b1 = *p++;
2748 b2 = *p++;
2749 b3 = *p++;
2750 break;
2751 case 2:
2752 b1 = *p++;
2753 b2 = *p++;
2754 break;
2755 case 1:
2756 b1 = *p++;
2757 break;
2758 }
2759
2760 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
2761 }
2762
2763 return r;
2764}
2765
2766static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
2767 u8 data_type, u16 data, u8 ecc)
2768{
2769 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2770 u32 r;
2771 u8 data_id;
2772
2773 WARN_ON(!dsi_bus_is_locked(dsidev));
2774
2775 if (dsi->debug_write)
2776 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
2777 channel,
2778 data_type, data & 0xff, (data >> 8) & 0xff);
2779
2780 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
2781
2782 if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
2783 DSSERR("ERROR FIFO FULL, aborting transfer\n");
2784 return -EINVAL;
2785 }
2786
2787 data_id = data_type | dsi->vc[channel].vc_id << 6;
2788
2789 r = (data_id << 0) | (data << 8) | (ecc << 24);
2790
2791 dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
2792
2793 return 0;
2794}
2795
2796static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
2797{
2798 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2799
2800 return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
2801 0, 0);
2802}
2803
2804static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
2805 int channel, u8 *data, int len, enum dss_dsi_content_type type)
2806{
2807 int r;
2808
2809 if (len == 0) {
2810 BUG_ON(type == DSS_DSI_CONTENT_DCS);
2811 r = dsi_vc_send_short(dsidev, channel,
2812 MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0);
2813 } else if (len == 1) {
2814 r = dsi_vc_send_short(dsidev, channel,
2815 type == DSS_DSI_CONTENT_GENERIC ?
2816 MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
2817 MIPI_DSI_DCS_SHORT_WRITE, data[0], 0);
2818 } else if (len == 2) {
2819 r = dsi_vc_send_short(dsidev, channel,
2820 type == DSS_DSI_CONTENT_GENERIC ?
2821 MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
2822 MIPI_DSI_DCS_SHORT_WRITE_PARAM,
2823 data[0] | (data[1] << 8), 0);
2824 } else {
2825 r = dsi_vc_send_long(dsidev, channel,
2826 type == DSS_DSI_CONTENT_GENERIC ?
2827 MIPI_DSI_GENERIC_LONG_WRITE :
2828 MIPI_DSI_DCS_LONG_WRITE, data, len, 0);
2829 }
2830
2831 return r;
2832}
2833
2834static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
2835 u8 *data, int len)
2836{
2837 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2838
2839 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
2840 DSS_DSI_CONTENT_DCS);
2841}
2842
2843static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
2844 u8 *data, int len)
2845{
2846 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2847
2848 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
2849 DSS_DSI_CONTENT_GENERIC);
2850}
2851
2852static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
2853 u8 *data, int len, enum dss_dsi_content_type type)
2854{
2855 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2856 int r;
2857
2858 r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
2859 if (r)
2860 goto err;
2861
2862 r = dsi_vc_send_bta_sync(dssdev, channel);
2863 if (r)
2864 goto err;
2865
2866 /* RX_FIFO_NOT_EMPTY */
2867 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2868 DSSERR("rx fifo not empty after write, dumping data:\n");
2869 dsi_vc_flush_receive_data(dsidev, channel);
2870 r = -EIO;
2871 goto err;
2872 }
2873
2874 return 0;
2875err:
2876 DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n",
2877 channel, data[0], len);
2878 return r;
2879}
2880
2881static int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
2882 int len)
2883{
2884 return dsi_vc_write_common(dssdev, channel, data, len,
2885 DSS_DSI_CONTENT_DCS);
2886}
2887
2888static int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
2889 int len)
2890{
2891 return dsi_vc_write_common(dssdev, channel, data, len,
2892 DSS_DSI_CONTENT_GENERIC);
2893}
2894
2895static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
2896 int channel, u8 dcs_cmd)
2897{
2898 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2899 int r;
2900
2901 if (dsi->debug_read)
2902 DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n",
2903 channel, dcs_cmd);
2904
2905 r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0);
2906 if (r) {
2907 DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)"
2908 " failed\n", channel, dcs_cmd);
2909 return r;
2910 }
2911
2912 return 0;
2913}
2914
2915static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
2916 int channel, u8 *reqdata, int reqlen)
2917{
2918 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2919 u16 data;
2920 u8 data_type;
2921 int r;
2922
2923 if (dsi->debug_read)
2924 DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n",
2925 channel, reqlen);
2926
2927 if (reqlen == 0) {
2928 data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
2929 data = 0;
2930 } else if (reqlen == 1) {
2931 data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
2932 data = reqdata[0];
2933 } else if (reqlen == 2) {
2934 data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
2935 data = reqdata[0] | (reqdata[1] << 8);
2936 } else {
2937 BUG();
2938 return -EINVAL;
2939 }
2940
2941 r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
2942 if (r) {
2943 DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)"
2944 " failed\n", channel, reqlen);
2945 return r;
2946 }
2947
2948 return 0;
2949}
2950
2951static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
2952 u8 *buf, int buflen, enum dss_dsi_content_type type)
2953{
2954 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2955 u32 val;
2956 u8 dt;
2957 int r;
2958
2959 /* RX_FIFO_NOT_EMPTY */
2960 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
2961 DSSERR("RX fifo empty when trying to read.\n");
2962 r = -EIO;
2963 goto err;
2964 }
2965
2966 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2967 if (dsi->debug_read)
2968 DSSDBG("\theader: %08x\n", val);
2969 dt = FLD_GET(val, 5, 0);
2970 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
2971 u16 err = FLD_GET(val, 23, 8);
2972 dsi_show_rx_ack_with_err(err);
2973 r = -EIO;
2974 goto err;
2975
2976 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
2977 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE :
2978 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) {
2979 u8 data = FLD_GET(val, 15, 8);
2980 if (dsi->debug_read)
2981 DSSDBG("\t%s short response, 1 byte: %02x\n",
2982 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
2983 "DCS", data);
2984
2985 if (buflen < 1) {
2986 r = -EIO;
2987 goto err;
2988 }
2989
2990 buf[0] = data;
2991
2992 return 1;
2993 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
2994 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE :
2995 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) {
2996 u16 data = FLD_GET(val, 23, 8);
2997 if (dsi->debug_read)
2998 DSSDBG("\t%s short response, 2 byte: %04x\n",
2999 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3000 "DCS", data);
3001
3002 if (buflen < 2) {
3003 r = -EIO;
3004 goto err;
3005 }
3006
3007 buf[0] = data & 0xff;
3008 buf[1] = (data >> 8) & 0xff;
3009
3010 return 2;
3011 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3012 MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE :
3013 MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) {
3014 int w;
3015 int len = FLD_GET(val, 23, 8);
3016 if (dsi->debug_read)
3017 DSSDBG("\t%s long response, len %d\n",
3018 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3019 "DCS", len);
3020
3021 if (len > buflen) {
3022 r = -EIO;
3023 goto err;
3024 }
3025
3026 /* two byte checksum ends the packet, not included in len */
3027 for (w = 0; w < len + 2;) {
3028 int b;
3029 val = dsi_read_reg(dsidev,
3030 DSI_VC_SHORT_PACKET_HEADER(channel));
3031 if (dsi->debug_read)
3032 DSSDBG("\t\t%02x %02x %02x %02x\n",
3033 (val >> 0) & 0xff,
3034 (val >> 8) & 0xff,
3035 (val >> 16) & 0xff,
3036 (val >> 24) & 0xff);
3037
3038 for (b = 0; b < 4; ++b) {
3039 if (w < len)
3040 buf[w] = (val >> (b * 8)) & 0xff;
3041 /* we discard the 2 byte checksum */
3042 ++w;
3043 }
3044 }
3045
3046 return len;
3047 } else {
3048 DSSERR("\tunknown datatype 0x%02x\n", dt);
3049 r = -EIO;
3050 goto err;
3051 }
3052
3053err:
3054 DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
3055 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
3056
3057 return r;
3058}
3059
3060static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3061 u8 *buf, int buflen)
3062{
3063 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3064 int r;
3065
3066 r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
3067 if (r)
3068 goto err;
3069
3070 r = dsi_vc_send_bta_sync(dssdev, channel);
3071 if (r)
3072 goto err;
3073
3074 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3075 DSS_DSI_CONTENT_DCS);
3076 if (r < 0)
3077 goto err;
3078
3079 if (r != buflen) {
3080 r = -EIO;
3081 goto err;
3082 }
3083
3084 return 0;
3085err:
3086 DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd);
3087 return r;
3088}
3089
3090static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
3091 u8 *reqdata, int reqlen, u8 *buf, int buflen)
3092{
3093 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3094 int r;
3095
3096 r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
3097 if (r)
3098 return r;
3099
3100 r = dsi_vc_send_bta_sync(dssdev, channel);
3101 if (r)
3102 return r;
3103
3104 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3105 DSS_DSI_CONTENT_GENERIC);
3106 if (r < 0)
3107 return r;
3108
3109 if (r != buflen) {
3110 r = -EIO;
3111 return r;
3112 }
3113
3114 return 0;
3115}
3116
3117static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
3118 u16 len)
3119{
3120 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3121
3122 return dsi_vc_send_short(dsidev, channel,
3123 MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
3124}
3125
3126static int dsi_enter_ulps(struct platform_device *dsidev)
3127{
3128 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3129 DECLARE_COMPLETION_ONSTACK(completion);
3130 int r, i;
3131 unsigned mask;
3132
3133 DSSDBG("Entering ULPS");
3134
3135 WARN_ON(!dsi_bus_is_locked(dsidev));
3136
3137 WARN_ON(dsi->ulps_enabled);
3138
3139 if (dsi->ulps_enabled)
3140 return 0;
3141
3142 /* DDR_CLK_ALWAYS_ON */
3143 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
3144 dsi_if_enable(dsidev, 0);
3145 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
3146 dsi_if_enable(dsidev, 1);
3147 }
3148
3149 dsi_sync_vc(dsidev, 0);
3150 dsi_sync_vc(dsidev, 1);
3151 dsi_sync_vc(dsidev, 2);
3152 dsi_sync_vc(dsidev, 3);
3153
3154 dsi_force_tx_stop_mode_io(dsidev);
3155
3156 dsi_vc_enable(dsidev, 0, false);
3157 dsi_vc_enable(dsidev, 1, false);
3158 dsi_vc_enable(dsidev, 2, false);
3159 dsi_vc_enable(dsidev, 3, false);
3160
3161 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
3162 DSSERR("HS busy when enabling ULPS\n");
3163 return -EIO;
3164 }
3165
3166 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
3167 DSSERR("LP busy when enabling ULPS\n");
3168 return -EIO;
3169 }
3170
3171 r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
3172 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3173 if (r)
3174 return r;
3175
3176 mask = 0;
3177
3178 for (i = 0; i < dsi->num_lanes_supported; ++i) {
3179 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
3180 continue;
3181 mask |= 1 << i;
3182 }
3183 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
3184 /* LANEx_ULPS_SIG2 */
3185 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
3186
3187 /* flush posted write and wait for SCP interface to finish the write */
3188 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3189
3190 if (wait_for_completion_timeout(&completion,
3191 msecs_to_jiffies(1000)) == 0) {
3192 DSSERR("ULPS enable timeout\n");
3193 r = -EIO;
3194 goto err;
3195 }
3196
3197 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3198 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3199
3200 /* Reset LANEx_ULPS_SIG2 */
3201 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
3202
3203 /* flush posted write and wait for SCP interface to finish the write */
3204 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3205
3206 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
3207
3208 dsi_if_enable(dsidev, false);
3209
3210 dsi->ulps_enabled = true;
3211
3212 return 0;
3213
3214err:
3215 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3216 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3217 return r;
3218}
3219
3220static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
3221 unsigned ticks, bool x4, bool x16)
3222{
3223 unsigned long fck;
3224 unsigned long total_ticks;
3225 u32 r;
3226
3227 BUG_ON(ticks > 0x1fff);
3228
3229 /* ticks in DSI_FCK */
3230 fck = dsi_fclk_rate(dsidev);
3231
3232 r = dsi_read_reg(dsidev, DSI_TIMING2);
3233 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
3234 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
3235 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
3236 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
3237 dsi_write_reg(dsidev, DSI_TIMING2, r);
3238
3239 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3240
3241 DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3242 total_ticks,
3243 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3244 (total_ticks * 1000) / (fck / 1000 / 1000));
3245}
3246
3247static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
3248 bool x8, bool x16)
3249{
3250 unsigned long fck;
3251 unsigned long total_ticks;
3252 u32 r;
3253
3254 BUG_ON(ticks > 0x1fff);
3255
3256 /* ticks in DSI_FCK */
3257 fck = dsi_fclk_rate(dsidev);
3258
3259 r = dsi_read_reg(dsidev, DSI_TIMING1);
3260 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
3261 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
3262 r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
3263 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
3264 dsi_write_reg(dsidev, DSI_TIMING1, r);
3265
3266 total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
3267
3268 DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
3269 total_ticks,
3270 ticks, x8 ? " x8" : "", x16 ? " x16" : "",
3271 (total_ticks * 1000) / (fck / 1000 / 1000));
3272}
3273
3274static void dsi_set_stop_state_counter(struct platform_device *dsidev,
3275 unsigned ticks, bool x4, bool x16)
3276{
3277 unsigned long fck;
3278 unsigned long total_ticks;
3279 u32 r;
3280
3281 BUG_ON(ticks > 0x1fff);
3282
3283 /* ticks in DSI_FCK */
3284 fck = dsi_fclk_rate(dsidev);
3285
3286 r = dsi_read_reg(dsidev, DSI_TIMING1);
3287 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
3288 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
3289 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
3290 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
3291 dsi_write_reg(dsidev, DSI_TIMING1, r);
3292
3293 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3294
3295 DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
3296 total_ticks,
3297 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3298 (total_ticks * 1000) / (fck / 1000 / 1000));
3299}
3300
3301static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
3302 unsigned ticks, bool x4, bool x16)
3303{
3304 unsigned long fck;
3305 unsigned long total_ticks;
3306 u32 r;
3307
3308 BUG_ON(ticks > 0x1fff);
3309
3310 /* ticks in TxByteClkHS */
3311 fck = dsi_get_txbyteclkhs(dsidev);
3312
3313 r = dsi_read_reg(dsidev, DSI_TIMING2);
3314 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
3315 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
3316 r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
3317 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
3318 dsi_write_reg(dsidev, DSI_TIMING2, r);
3319
3320 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3321
3322 DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3323 total_ticks,
3324 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3325 (total_ticks * 1000) / (fck / 1000 / 1000));
3326}
3327
3328static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
3329{
3330 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3331 int num_line_buffers;
3332
3333 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3334 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3335 struct omap_video_timings *timings = &dsi->timings;
3336 /*
3337 * Don't use line buffers if width is greater than the video
3338 * port's line buffer size
3339 */
3340 if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
3341 num_line_buffers = 0;
3342 else
3343 num_line_buffers = 2;
3344 } else {
3345 /* Use maximum number of line buffers in command mode */
3346 num_line_buffers = 2;
3347 }
3348
3349 /* LINE_BUFFER */
3350 REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
3351}
3352
3353static void dsi_config_vp_sync_events(struct platform_device *dsidev)
3354{
3355 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3356 bool sync_end;
3357 u32 r;
3358
3359 if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
3360 sync_end = true;
3361 else
3362 sync_end = false;
3363
3364 r = dsi_read_reg(dsidev, DSI_CTRL);
3365 r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
3366 r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
3367 r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
3368 r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
3369 r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */
3370 r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
3371 r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */
3372 dsi_write_reg(dsidev, DSI_CTRL, r);
3373}
3374
3375static void dsi_config_blanking_modes(struct platform_device *dsidev)
3376{
3377 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3378 int blanking_mode = dsi->vm_timings.blanking_mode;
3379 int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
3380 int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
3381 int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
3382 u32 r;
3383
3384 /*
3385 * 0 = TX FIFO packets sent or LPS in corresponding blanking periods
3386 * 1 = Long blanking packets are sent in corresponding blanking periods
3387 */
3388 r = dsi_read_reg(dsidev, DSI_CTRL);
3389 r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */
3390 r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */
3391 r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */
3392 r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */
3393 dsi_write_reg(dsidev, DSI_CTRL, r);
3394}
3395
3396/*
3397 * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3
3398 * results in maximum transition time for data and clock lanes to enter and
3399 * exit HS mode. Hence, this is the scenario where the least amount of command
3400 * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS
3401 * clock cycles that can be used to interleave command mode data in HS so that
3402 * all scenarios are satisfied.
3403 */
3404static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs,
3405 int exit_hs, int exiths_clk, int ddr_pre, int ddr_post)
3406{
3407 int transition;
3408
3409 /*
3410 * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition
3411 * time of data lanes only, if it isn't set, we need to consider HS
3412 * transition time of both data and clock lanes. HS transition time
3413 * of Scenario 3 is considered.
3414 */
3415 if (ddr_alwon) {
3416 transition = enter_hs + exit_hs + max(enter_hs, 2) + 1;
3417 } else {
3418 int trans1, trans2;
3419 trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1;
3420 trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre +
3421 enter_hs + 1;
3422 transition = max(trans1, trans2);
3423 }
3424
3425 return blank > transition ? blank - transition : 0;
3426}
3427
3428/*
3429 * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1
3430 * results in maximum transition time for data lanes to enter and exit LP mode.
3431 * Hence, this is the scenario where the least amount of command mode data can
3432 * be interleaved. We program the minimum amount of bytes that can be
3433 * interleaved in LP so that all scenarios are satisfied.
3434 */
3435static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
3436 int lp_clk_div, int tdsi_fclk)
3437{
3438 int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */
3439 int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */
3440 int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */
3441 int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */
3442 int lp_inter; /* cmd mode data that can be interleaved, in bytes */
3443
3444 /* maximum LP transition time according to Scenario 1 */
3445 trans_lp = exit_hs + max(enter_hs, 2) + 1;
3446
3447 /* CLKIN4DDR = 16 * TXBYTECLKHS */
3448 tlp_avail = thsbyte_clk * (blank - trans_lp);
3449
3450 ttxclkesc = tdsi_fclk * lp_clk_div;
3451
3452 lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc -
3453 26) / 16;
3454
3455 return max(lp_inter, 0);
3456}
3457
3458static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
3459{
3460 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3461 int blanking_mode;
3462 int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
3463 int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
3464 int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
3465 int tclk_trail, ths_exit, exiths_clk;
3466 bool ddr_alwon;
3467 struct omap_video_timings *timings = &dsi->timings;
3468 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3469 int ndl = dsi->num_lanes_used - 1;
3470 int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
3471 int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
3472 int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
3473 int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
3474 int bl_interleave_hs = 0, bl_interleave_lp = 0;
3475 u32 r;
3476
3477 r = dsi_read_reg(dsidev, DSI_CTRL);
3478 blanking_mode = FLD_GET(r, 20, 20);
3479 hfp_blanking_mode = FLD_GET(r, 21, 21);
3480 hbp_blanking_mode = FLD_GET(r, 22, 22);
3481 hsa_blanking_mode = FLD_GET(r, 23, 23);
3482
3483 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
3484 hbp = FLD_GET(r, 11, 0);
3485 hfp = FLD_GET(r, 23, 12);
3486 hsa = FLD_GET(r, 31, 24);
3487
3488 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
3489 ddr_clk_post = FLD_GET(r, 7, 0);
3490 ddr_clk_pre = FLD_GET(r, 15, 8);
3491
3492 r = dsi_read_reg(dsidev, DSI_VM_TIMING7);
3493 exit_hs_mode_lat = FLD_GET(r, 15, 0);
3494 enter_hs_mode_lat = FLD_GET(r, 31, 16);
3495
3496 r = dsi_read_reg(dsidev, DSI_CLK_CTRL);
3497 lp_clk_div = FLD_GET(r, 12, 0);
3498 ddr_alwon = FLD_GET(r, 13, 13);
3499
3500 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
3501 ths_exit = FLD_GET(r, 7, 0);
3502
3503 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
3504 tclk_trail = FLD_GET(r, 15, 8);
3505
3506 exiths_clk = ths_exit + tclk_trail;
3507
3508 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
3509 bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl);
3510
3511 if (!hsa_blanking_mode) {
3512 hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon,
3513 enter_hs_mode_lat, exit_hs_mode_lat,
3514 exiths_clk, ddr_clk_pre, ddr_clk_post);
3515 hsa_interleave_lp = dsi_compute_interleave_lp(hsa,
3516 enter_hs_mode_lat, exit_hs_mode_lat,
3517 lp_clk_div, dsi_fclk_hsdiv);
3518 }
3519
3520 if (!hfp_blanking_mode) {
3521 hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon,
3522 enter_hs_mode_lat, exit_hs_mode_lat,
3523 exiths_clk, ddr_clk_pre, ddr_clk_post);
3524 hfp_interleave_lp = dsi_compute_interleave_lp(hfp,
3525 enter_hs_mode_lat, exit_hs_mode_lat,
3526 lp_clk_div, dsi_fclk_hsdiv);
3527 }
3528
3529 if (!hbp_blanking_mode) {
3530 hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon,
3531 enter_hs_mode_lat, exit_hs_mode_lat,
3532 exiths_clk, ddr_clk_pre, ddr_clk_post);
3533
3534 hbp_interleave_lp = dsi_compute_interleave_lp(hbp,
3535 enter_hs_mode_lat, exit_hs_mode_lat,
3536 lp_clk_div, dsi_fclk_hsdiv);
3537 }
3538
3539 if (!blanking_mode) {
3540 bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon,
3541 enter_hs_mode_lat, exit_hs_mode_lat,
3542 exiths_clk, ddr_clk_pre, ddr_clk_post);
3543
3544 bl_interleave_lp = dsi_compute_interleave_lp(bllp,
3545 enter_hs_mode_lat, exit_hs_mode_lat,
3546 lp_clk_div, dsi_fclk_hsdiv);
3547 }
3548
3549 DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3550 hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs,
3551 bl_interleave_hs);
3552
3553 DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3554 hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp,
3555 bl_interleave_lp);
3556
3557 r = dsi_read_reg(dsidev, DSI_VM_TIMING4);
3558 r = FLD_MOD(r, hsa_interleave_hs, 23, 16);
3559 r = FLD_MOD(r, hfp_interleave_hs, 15, 8);
3560 r = FLD_MOD(r, hbp_interleave_hs, 7, 0);
3561 dsi_write_reg(dsidev, DSI_VM_TIMING4, r);
3562
3563 r = dsi_read_reg(dsidev, DSI_VM_TIMING5);
3564 r = FLD_MOD(r, hsa_interleave_lp, 23, 16);
3565 r = FLD_MOD(r, hfp_interleave_lp, 15, 8);
3566 r = FLD_MOD(r, hbp_interleave_lp, 7, 0);
3567 dsi_write_reg(dsidev, DSI_VM_TIMING5, r);
3568
3569 r = dsi_read_reg(dsidev, DSI_VM_TIMING6);
3570 r = FLD_MOD(r, bl_interleave_hs, 31, 15);
3571 r = FLD_MOD(r, bl_interleave_lp, 16, 0);
3572 dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
3573}
3574
3575static int dsi_proto_config(struct platform_device *dsidev)
3576{
3577 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3578 u32 r;
3579 int buswidth = 0;
3580
3581 dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
3582 DSI_FIFO_SIZE_32,
3583 DSI_FIFO_SIZE_32,
3584 DSI_FIFO_SIZE_32);
3585
3586 dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
3587 DSI_FIFO_SIZE_32,
3588 DSI_FIFO_SIZE_32,
3589 DSI_FIFO_SIZE_32);
3590
3591 /* XXX what values for the timeouts? */
3592 dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
3593 dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
3594 dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
3595 dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
3596
3597 switch (dsi_get_pixel_size(dsi->pix_fmt)) {
3598 case 16:
3599 buswidth = 0;
3600 break;
3601 case 18:
3602 buswidth = 1;
3603 break;
3604 case 24:
3605 buswidth = 2;
3606 break;
3607 default:
3608 BUG();
3609 return -EINVAL;
3610 }
3611
3612 r = dsi_read_reg(dsidev, DSI_CTRL);
3613 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
3614 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
3615 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
3616 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
3617 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
3618 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
3619 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
3620 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
3621 if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
3622 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
3623 /* DCS_CMD_CODE, 1=start, 0=continue */
3624 r = FLD_MOD(r, 0, 25, 25);
3625 }
3626
3627 dsi_write_reg(dsidev, DSI_CTRL, r);
3628
3629 dsi_config_vp_num_line_buffers(dsidev);
3630
3631 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3632 dsi_config_vp_sync_events(dsidev);
3633 dsi_config_blanking_modes(dsidev);
3634 dsi_config_cmd_mode_interleaving(dsidev);
3635 }
3636
3637 dsi_vc_initial_config(dsidev, 0);
3638 dsi_vc_initial_config(dsidev, 1);
3639 dsi_vc_initial_config(dsidev, 2);
3640 dsi_vc_initial_config(dsidev, 3);
3641
3642 return 0;
3643}
3644
3645static void dsi_proto_timings(struct platform_device *dsidev)
3646{
3647 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3648 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
3649 unsigned tclk_pre, tclk_post;
3650 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
3651 unsigned ths_trail, ths_exit;
3652 unsigned ddr_clk_pre, ddr_clk_post;
3653 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
3654 unsigned ths_eot;
3655 int ndl = dsi->num_lanes_used - 1;
3656 u32 r;
3657
3658 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
3659 ths_prepare = FLD_GET(r, 31, 24);
3660 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
3661 ths_zero = ths_prepare_ths_zero - ths_prepare;
3662 ths_trail = FLD_GET(r, 15, 8);
3663 ths_exit = FLD_GET(r, 7, 0);
3664
3665 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
3666 tlpx = FLD_GET(r, 20, 16) * 2;
3667 tclk_trail = FLD_GET(r, 15, 8);
3668 tclk_zero = FLD_GET(r, 7, 0);
3669
3670 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
3671 tclk_prepare = FLD_GET(r, 7, 0);
3672
3673 /* min 8*UI */
3674 tclk_pre = 20;
3675 /* min 60ns + 52*UI */
3676 tclk_post = ns2ddr(dsidev, 60) + 26;
3677
3678 ths_eot = DIV_ROUND_UP(4, ndl);
3679
3680 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
3681 4);
3682 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
3683
3684 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
3685 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
3686
3687 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
3688 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
3689 r = FLD_MOD(r, ddr_clk_post, 7, 0);
3690 dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
3691
3692 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
3693 ddr_clk_pre,
3694 ddr_clk_post);
3695
3696 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
3697 DIV_ROUND_UP(ths_prepare, 4) +
3698 DIV_ROUND_UP(ths_zero + 3, 4);
3699
3700 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
3701
3702 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
3703 FLD_VAL(exit_hs_mode_lat, 15, 0);
3704 dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
3705
3706 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
3707 enter_hs_mode_lat, exit_hs_mode_lat);
3708
3709 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3710 /* TODO: Implement a video mode check_timings function */
3711 int hsa = dsi->vm_timings.hsa;
3712 int hfp = dsi->vm_timings.hfp;
3713 int hbp = dsi->vm_timings.hbp;
3714 int vsa = dsi->vm_timings.vsa;
3715 int vfp = dsi->vm_timings.vfp;
3716 int vbp = dsi->vm_timings.vbp;
3717 int window_sync = dsi->vm_timings.window_sync;
3718 bool hsync_end;
3719 struct omap_video_timings *timings = &dsi->timings;
3720 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3721 int tl, t_he, width_bytes;
3722
3723 hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
3724 t_he = hsync_end ?
3725 ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
3726
3727 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
3728
3729 /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */
3730 tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp +
3731 DIV_ROUND_UP(width_bytes + 6, ndl) + hbp;
3732
3733 DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp,
3734 hfp, hsync_end ? hsa : 0, tl);
3735 DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp,
3736 vsa, timings->y_res);
3737
3738 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
3739 r = FLD_MOD(r, hbp, 11, 0); /* HBP */
3740 r = FLD_MOD(r, hfp, 23, 12); /* HFP */
3741 r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */
3742 dsi_write_reg(dsidev, DSI_VM_TIMING1, r);
3743
3744 r = dsi_read_reg(dsidev, DSI_VM_TIMING2);
3745 r = FLD_MOD(r, vbp, 7, 0); /* VBP */
3746 r = FLD_MOD(r, vfp, 15, 8); /* VFP */
3747 r = FLD_MOD(r, vsa, 23, 16); /* VSA */
3748 r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */
3749 dsi_write_reg(dsidev, DSI_VM_TIMING2, r);
3750
3751 r = dsi_read_reg(dsidev, DSI_VM_TIMING3);
3752 r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */
3753 r = FLD_MOD(r, tl, 31, 16); /* TL */
3754 dsi_write_reg(dsidev, DSI_VM_TIMING3, r);
3755 }
3756}
3757
3758static int dsi_configure_pins(struct omap_dss_device *dssdev,
3759 const struct omap_dsi_pin_config *pin_cfg)
3760{
3761 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3762 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3763 int num_pins;
3764 const int *pins;
3765 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
3766 int num_lanes;
3767 int i;
3768
3769 static const enum dsi_lane_function functions[] = {
3770 DSI_LANE_CLK,
3771 DSI_LANE_DATA1,
3772 DSI_LANE_DATA2,
3773 DSI_LANE_DATA3,
3774 DSI_LANE_DATA4,
3775 };
3776
3777 num_pins = pin_cfg->num_pins;
3778 pins = pin_cfg->pins;
3779
3780 if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
3781 || num_pins % 2 != 0)
3782 return -EINVAL;
3783
3784 for (i = 0; i < DSI_MAX_NR_LANES; ++i)
3785 lanes[i].function = DSI_LANE_UNUSED;
3786
3787 num_lanes = 0;
3788
3789 for (i = 0; i < num_pins; i += 2) {
3790 u8 lane, pol;
3791 int dx, dy;
3792
3793 dx = pins[i];
3794 dy = pins[i + 1];
3795
3796 if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
3797 return -EINVAL;
3798
3799 if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
3800 return -EINVAL;
3801
3802 if (dx & 1) {
3803 if (dy != dx - 1)
3804 return -EINVAL;
3805 pol = 1;
3806 } else {
3807 if (dy != dx + 1)
3808 return -EINVAL;
3809 pol = 0;
3810 }
3811
3812 lane = dx / 2;
3813
3814 lanes[lane].function = functions[i / 2];
3815 lanes[lane].polarity = pol;
3816 num_lanes++;
3817 }
3818
3819 memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
3820 dsi->num_lanes_used = num_lanes;
3821
3822 return 0;
3823}
3824
3825static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
3826{
3827 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3828 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3829 struct omap_overlay_manager *mgr = dsi->output.manager;
3830 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3831 struct omap_dss_device *out = &dsi->output;
3832 u8 data_type;
3833 u16 word_count;
3834 int r;
3835
3836 if (out->manager == NULL) {
3837 DSSERR("failed to enable display: no output/manager\n");
3838 return -ENODEV;
3839 }
3840
3841 r = dsi_display_init_dispc(dsidev, mgr);
3842 if (r)
3843 goto err_init_dispc;
3844
3845 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3846 switch (dsi->pix_fmt) {
3847 case OMAP_DSS_DSI_FMT_RGB888:
3848 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
3849 break;
3850 case OMAP_DSS_DSI_FMT_RGB666:
3851 data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
3852 break;
3853 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
3854 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
3855 break;
3856 case OMAP_DSS_DSI_FMT_RGB565:
3857 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
3858 break;
3859 default:
3860 r = -EINVAL;
3861 goto err_pix_fmt;
3862 }
3863
3864 dsi_if_enable(dsidev, false);
3865 dsi_vc_enable(dsidev, channel, false);
3866
3867 /* MODE, 1 = video mode */
3868 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
3869
3870 word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
3871
3872 dsi_vc_write_long_header(dsidev, channel, data_type,
3873 word_count, 0);
3874
3875 dsi_vc_enable(dsidev, channel, true);
3876 dsi_if_enable(dsidev, true);
3877 }
3878
3879 r = dss_mgr_enable(mgr);
3880 if (r)
3881 goto err_mgr_enable;
3882
3883 return 0;
3884
3885err_mgr_enable:
3886 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3887 dsi_if_enable(dsidev, false);
3888 dsi_vc_enable(dsidev, channel, false);
3889 }
3890err_pix_fmt:
3891 dsi_display_uninit_dispc(dsidev, mgr);
3892err_init_dispc:
3893 return r;
3894}
3895
3896static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
3897{
3898 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3899 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3900 struct omap_overlay_manager *mgr = dsi->output.manager;
3901
3902 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3903 dsi_if_enable(dsidev, false);
3904 dsi_vc_enable(dsidev, channel, false);
3905
3906 /* MODE, 0 = command mode */
3907 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
3908
3909 dsi_vc_enable(dsidev, channel, true);
3910 dsi_if_enable(dsidev, true);
3911 }
3912
3913 dss_mgr_disable(mgr);
3914
3915 dsi_display_uninit_dispc(dsidev, mgr);
3916}
3917
3918static void dsi_update_screen_dispc(struct platform_device *dsidev)
3919{
3920 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3921 struct omap_overlay_manager *mgr = dsi->output.manager;
3922 unsigned bytespp;
3923 unsigned bytespl;
3924 unsigned bytespf;
3925 unsigned total_len;
3926 unsigned packet_payload;
3927 unsigned packet_len;
3928 u32 l;
3929 int r;
3930 const unsigned channel = dsi->update_channel;
3931 const unsigned line_buf_size = dsi->line_buffer_size;
3932 u16 w = dsi->timings.x_res;
3933 u16 h = dsi->timings.y_res;
3934
3935 DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
3936
3937 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
3938
3939 bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
3940 bytespl = w * bytespp;
3941 bytespf = bytespl * h;
3942
3943 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
3944 * number of lines in a packet. See errata about VP_CLK_RATIO */
3945
3946 if (bytespf < line_buf_size)
3947 packet_payload = bytespf;
3948 else
3949 packet_payload = (line_buf_size) / bytespl * bytespl;
3950
3951 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
3952 total_len = (bytespf / packet_payload) * packet_len;
3953
3954 if (bytespf % packet_payload)
3955 total_len += (bytespf % packet_payload) + 1;
3956
3957 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
3958 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
3959
3960 dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE,
3961 packet_len, 0);
3962
3963 if (dsi->te_enabled)
3964 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
3965 else
3966 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
3967 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
3968
3969 /* We put SIDLEMODE to no-idle for the duration of the transfer,
3970 * because DSS interrupts are not capable of waking up the CPU and the
3971 * framedone interrupt could be delayed for quite a long time. I think
3972 * the same goes for any DSS interrupts, but for some reason I have not
3973 * seen the problem anywhere else than here.
3974 */
3975 dispc_disable_sidle();
3976
3977 dsi_perf_mark_start(dsidev);
3978
3979 r = schedule_delayed_work(&dsi->framedone_timeout_work,
3980 msecs_to_jiffies(250));
3981 BUG_ON(r == 0);
3982
3983 dss_mgr_set_timings(mgr, &dsi->timings);
3984
3985 dss_mgr_start_update(mgr);
3986
3987 if (dsi->te_enabled) {
3988 /* disable LP_RX_TO, so that we can receive TE. Time to wait
3989 * for TE is longer than the timer allows */
3990 REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
3991
3992 dsi_vc_send_bta(dsidev, channel);
3993
3994#ifdef DSI_CATCH_MISSING_TE
3995 mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
3996#endif
3997 }
3998}
3999
4000#ifdef DSI_CATCH_MISSING_TE
4001static void dsi_te_timeout(unsigned long arg)
4002{
4003 DSSERR("TE not received for 250ms!\n");
4004}
4005#endif
4006
4007static void dsi_handle_framedone(struct platform_device *dsidev, int error)
4008{
4009 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4010
4011 /* SIDLEMODE back to smart-idle */
4012 dispc_enable_sidle();
4013
4014 if (dsi->te_enabled) {
4015 /* enable LP_RX_TO again after the TE */
4016 REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
4017 }
4018
4019 dsi->framedone_callback(error, dsi->framedone_data);
4020
4021 if (!error)
4022 dsi_perf_show(dsidev, "DISPC");
4023}
4024
4025static void dsi_framedone_timeout_work_callback(struct work_struct *work)
4026{
4027 struct dsi_data *dsi = container_of(work, struct dsi_data,
4028 framedone_timeout_work.work);
4029 /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
4030 * 250ms which would conflict with this timeout work. What should be
4031 * done is first cancel the transfer on the HW, and then cancel the
4032 * possibly scheduled framedone work. However, cancelling the transfer
4033 * on the HW is buggy, and would probably require resetting the whole
4034 * DSI */
4035
4036 DSSERR("Framedone not received for 250ms!\n");
4037
4038 dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
4039}
4040
4041static void dsi_framedone_irq_callback(void *data)
4042{
4043 struct platform_device *dsidev = (struct platform_device *) data;
4044 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4045
4046 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
4047 * turns itself off. However, DSI still has the pixels in its buffers,
4048 * and is sending the data.
4049 */
4050
4051 cancel_delayed_work(&dsi->framedone_timeout_work);
4052
4053 dsi_handle_framedone(dsidev, 0);
4054}
4055
4056static int dsi_update(struct omap_dss_device *dssdev, int channel,
4057 void (*callback)(int, void *), void *data)
4058{
4059 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4060 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4061 u16 dw, dh;
4062
4063 dsi_perf_mark_setup(dsidev);
4064
4065 dsi->update_channel = channel;
4066
4067 dsi->framedone_callback = callback;
4068 dsi->framedone_data = data;
4069
4070 dw = dsi->timings.x_res;
4071 dh = dsi->timings.y_res;
4072
4073#ifdef DSI_PERF_MEASURE
4074 dsi->update_bytes = dw * dh *
4075 dsi_get_pixel_size(dsi->pix_fmt) / 8;
4076#endif
4077 dsi_update_screen_dispc(dsidev);
4078
4079 return 0;
4080}
4081
4082/* Display funcs */
4083
4084static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
4085{
4086 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4087 struct dispc_clock_info dispc_cinfo;
4088 int r;
4089 unsigned long fck;
4090
4091 fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
4092
4093 dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
4094 dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
4095
4096 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
4097 if (r) {
4098 DSSERR("Failed to calc dispc clocks\n");
4099 return r;
4100 }
4101
4102 dsi->mgr_config.clock_info = dispc_cinfo;
4103
4104 return 0;
4105}
4106
4107static int dsi_display_init_dispc(struct platform_device *dsidev,
4108 struct omap_overlay_manager *mgr)
4109{
4110 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4111 int r;
4112
4113 dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
4114 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
4115 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
4116
4117 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
4118 r = dss_mgr_register_framedone_handler(mgr,
4119 dsi_framedone_irq_callback, dsidev);
4120 if (r) {
4121 DSSERR("can't register FRAMEDONE handler\n");
4122 goto err;
4123 }
4124
4125 dsi->mgr_config.stallmode = true;
4126 dsi->mgr_config.fifohandcheck = true;
4127 } else {
4128 dsi->mgr_config.stallmode = false;
4129 dsi->mgr_config.fifohandcheck = false;
4130 }
4131
4132 /*
4133 * override interlace, logic level and edge related parameters in
4134 * omap_video_timings with default values
4135 */
4136 dsi->timings.interlace = false;
4137 dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4138 dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4139 dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
4140 dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
4141 dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
4142
4143 dss_mgr_set_timings(mgr, &dsi->timings);
4144
4145 r = dsi_configure_dispc_clocks(dsidev);
4146 if (r)
4147 goto err1;
4148
4149 dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
4150 dsi->mgr_config.video_port_width =
4151 dsi_get_pixel_size(dsi->pix_fmt);
4152 dsi->mgr_config.lcden_sig_polarity = 0;
4153
4154 dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
4155
4156 return 0;
4157err1:
4158 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
4159 dss_mgr_unregister_framedone_handler(mgr,
4160 dsi_framedone_irq_callback, dsidev);
4161err:
4162 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
4163 return r;
4164}
4165
4166static void dsi_display_uninit_dispc(struct platform_device *dsidev,
4167 struct omap_overlay_manager *mgr)
4168{
4169 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4170
4171 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
4172 dss_mgr_unregister_framedone_handler(mgr,
4173 dsi_framedone_irq_callback, dsidev);
4174
4175 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
4176}
4177
4178static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
4179{
4180 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4181 struct dss_pll_clock_info cinfo;
4182 int r;
4183
4184 cinfo = dsi->user_dsi_cinfo;
4185
4186 r = dss_pll_set_config(&dsi->pll, &cinfo);
4187 if (r) {
4188 DSSERR("Failed to set dsi clocks\n");
4189 return r;
4190 }
4191
4192 return 0;
4193}
4194
4195static int dsi_display_init_dsi(struct platform_device *dsidev)
4196{
4197 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4198 int r;
4199
4200 r = dss_pll_enable(&dsi->pll);
4201 if (r)
4202 goto err0;
4203
4204 r = dsi_configure_dsi_clocks(dsidev);
4205 if (r)
4206 goto err1;
4207
4208 dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
4209 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
4210 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
4211
4212 DSSDBG("PLL OK\n");
4213
4214 r = dsi_cio_init(dsidev);
4215 if (r)
4216 goto err2;
4217
4218 _dsi_print_reset_status(dsidev);
4219
4220 dsi_proto_timings(dsidev);
4221 dsi_set_lp_clk_divisor(dsidev);
4222
4223 if (1)
4224 _dsi_print_reset_status(dsidev);
4225
4226 r = dsi_proto_config(dsidev);
4227 if (r)
4228 goto err3;
4229
4230 /* enable interface */
4231 dsi_vc_enable(dsidev, 0, 1);
4232 dsi_vc_enable(dsidev, 1, 1);
4233 dsi_vc_enable(dsidev, 2, 1);
4234 dsi_vc_enable(dsidev, 3, 1);
4235 dsi_if_enable(dsidev, 1);
4236 dsi_force_tx_stop_mode_io(dsidev);
4237
4238 return 0;
4239err3:
4240 dsi_cio_uninit(dsidev);
4241err2:
4242 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
4243err1:
4244 dss_pll_disable(&dsi->pll);
4245err0:
4246 return r;
4247}
4248
4249static void dsi_display_uninit_dsi(struct platform_device *dsidev,
4250 bool disconnect_lanes, bool enter_ulps)
4251{
4252 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4253
4254 if (enter_ulps && !dsi->ulps_enabled)
4255 dsi_enter_ulps(dsidev);
4256
4257 /* disable interface */
4258 dsi_if_enable(dsidev, 0);
4259 dsi_vc_enable(dsidev, 0, 0);
4260 dsi_vc_enable(dsidev, 1, 0);
4261 dsi_vc_enable(dsidev, 2, 0);
4262 dsi_vc_enable(dsidev, 3, 0);
4263
4264 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
4265 dsi_cio_uninit(dsidev);
4266 dsi_pll_uninit(dsidev, disconnect_lanes);
4267}
4268
4269static int dsi_display_enable(struct omap_dss_device *dssdev)
4270{
4271 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4272 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4273 int r = 0;
4274
4275 DSSDBG("dsi_display_enable\n");
4276
4277 WARN_ON(!dsi_bus_is_locked(dsidev));
4278
4279 mutex_lock(&dsi->lock);
4280
4281 r = dsi_runtime_get(dsidev);
4282 if (r)
4283 goto err_get_dsi;
4284
4285 _dsi_initialize_irq(dsidev);
4286
4287 r = dsi_display_init_dsi(dsidev);
4288 if (r)
4289 goto err_init_dsi;
4290
4291 mutex_unlock(&dsi->lock);
4292
4293 return 0;
4294
4295err_init_dsi:
4296 dsi_runtime_put(dsidev);
4297err_get_dsi:
4298 mutex_unlock(&dsi->lock);
4299 DSSDBG("dsi_display_enable FAILED\n");
4300 return r;
4301}
4302
4303static void dsi_display_disable(struct omap_dss_device *dssdev,
4304 bool disconnect_lanes, bool enter_ulps)
4305{
4306 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4307 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4308
4309 DSSDBG("dsi_display_disable\n");
4310
4311 WARN_ON(!dsi_bus_is_locked(dsidev));
4312
4313 mutex_lock(&dsi->lock);
4314
4315 dsi_sync_vc(dsidev, 0);
4316 dsi_sync_vc(dsidev, 1);
4317 dsi_sync_vc(dsidev, 2);
4318 dsi_sync_vc(dsidev, 3);
4319
4320 dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
4321
4322 dsi_runtime_put(dsidev);
4323
4324 mutex_unlock(&dsi->lock);
4325}
4326
4327static int dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
4328{
4329 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4330 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4331
4332 dsi->te_enabled = enable;
4333 return 0;
4334}
4335
4336#ifdef PRINT_VERBOSE_VM_TIMINGS
4337static void print_dsi_vm(const char *str,
4338 const struct omap_dss_dsi_videomode_timings *t)
4339{
4340 unsigned long byteclk = t->hsclk / 4;
4341 int bl, wc, pps, tot;
4342
4343 wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
4344 pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
4345 bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
4346 tot = bl + pps;
4347
4348#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
4349
4350 pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
4351 "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
4352 str,
4353 byteclk,
4354 t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
4355 bl, pps, tot,
4356 TO_DSI_T(t->hss),
4357 TO_DSI_T(t->hsa),
4358 TO_DSI_T(t->hse),
4359 TO_DSI_T(t->hbp),
4360 TO_DSI_T(pps),
4361 TO_DSI_T(t->hfp),
4362
4363 TO_DSI_T(bl),
4364 TO_DSI_T(pps),
4365
4366 TO_DSI_T(tot));
4367#undef TO_DSI_T
4368}
4369
4370static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
4371{
4372 unsigned long pck = t->pixelclock;
4373 int hact, bl, tot;
4374
4375 hact = t->x_res;
4376 bl = t->hsw + t->hbp + t->hfp;
4377 tot = hact + bl;
4378
4379#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
4380
4381 pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
4382 "%u/%u/%u/%u = %u + %u = %u\n",
4383 str,
4384 pck,
4385 t->hsw, t->hbp, hact, t->hfp,
4386 bl, hact, tot,
4387 TO_DISPC_T(t->hsw),
4388 TO_DISPC_T(t->hbp),
4389 TO_DISPC_T(hact),
4390 TO_DISPC_T(t->hfp),
4391 TO_DISPC_T(bl),
4392 TO_DISPC_T(hact),
4393 TO_DISPC_T(tot));
4394#undef TO_DISPC_T
4395}
4396
4397/* note: this is not quite accurate */
4398static void print_dsi_dispc_vm(const char *str,
4399 const struct omap_dss_dsi_videomode_timings *t)
4400{
4401 struct omap_video_timings vm = { 0 };
4402 unsigned long byteclk = t->hsclk / 4;
4403 unsigned long pck;
4404 u64 dsi_tput;
4405 int dsi_hact, dsi_htot;
4406
4407 dsi_tput = (u64)byteclk * t->ndl * 8;
4408 pck = (u32)div64_u64(dsi_tput, t->bitspp);
4409 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
4410 dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
4411
4412 vm.pixelclock = pck;
4413 vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
4414 vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
4415 vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
4416 vm.x_res = t->hact;
4417
4418 print_dispc_vm(str, &vm);
4419}
4420#endif /* PRINT_VERBOSE_VM_TIMINGS */
4421
4422static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
4423 unsigned long pck, void *data)
4424{
4425 struct dsi_clk_calc_ctx *ctx = data;
4426 struct omap_video_timings *t = &ctx->dispc_vm;
4427
4428 ctx->dispc_cinfo.lck_div = lckd;
4429 ctx->dispc_cinfo.pck_div = pckd;
4430 ctx->dispc_cinfo.lck = lck;
4431 ctx->dispc_cinfo.pck = pck;
4432
4433 *t = *ctx->config->timings;
4434 t->pixelclock = pck;
4435 t->x_res = ctx->config->timings->x_res;
4436 t->y_res = ctx->config->timings->y_res;
4437 t->hsw = t->hfp = t->hbp = t->vsw = 1;
4438 t->vfp = t->vbp = 0;
4439
4440 return true;
4441}
4442
4443static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
4444 void *data)
4445{
4446 struct dsi_clk_calc_ctx *ctx = data;
4447
4448 ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
4449 ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
4450
4451 return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
4452 dsi_cm_calc_dispc_cb, ctx);
4453}
4454
4455static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
4456 unsigned long clkdco, void *data)
4457{
4458 struct dsi_clk_calc_ctx *ctx = data;
4459
4460 ctx->dsi_cinfo.n = n;
4461 ctx->dsi_cinfo.m = m;
4462 ctx->dsi_cinfo.fint = fint;
4463 ctx->dsi_cinfo.clkdco = clkdco;
4464
4465 return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
4466 dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
4467 dsi_cm_calc_hsdiv_cb, ctx);
4468}
4469
4470static bool dsi_cm_calc(struct dsi_data *dsi,
4471 const struct omap_dss_dsi_config *cfg,
4472 struct dsi_clk_calc_ctx *ctx)
4473{
4474 unsigned long clkin;
4475 int bitspp, ndl;
4476 unsigned long pll_min, pll_max;
4477 unsigned long pck, txbyteclk;
4478
4479 clkin = clk_get_rate(dsi->pll.clkin);
4480 bitspp = dsi_get_pixel_size(cfg->pixel_format);
4481 ndl = dsi->num_lanes_used - 1;
4482
4483 /*
4484 * Here we should calculate minimum txbyteclk to be able to send the
4485 * frame in time, and also to handle TE. That's not very simple, though,
4486 * especially as we go to LP between each pixel packet due to HW
4487 * "feature". So let's just estimate very roughly and multiply by 1.5.
4488 */
4489 pck = cfg->timings->pixelclock;
4490 pck = pck * 3 / 2;
4491 txbyteclk = pck * bitspp / 8 / ndl;
4492
4493 memset(ctx, 0, sizeof(*ctx));
4494 ctx->dsidev = dsi->pdev;
4495 ctx->pll = &dsi->pll;
4496 ctx->config = cfg;
4497 ctx->req_pck_min = pck;
4498 ctx->req_pck_nom = pck;
4499 ctx->req_pck_max = pck * 3 / 2;
4500
4501 pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
4502 pll_max = cfg->hs_clk_max * 4;
4503
4504 return dss_pll_calc(ctx->pll, clkin,
4505 pll_min, pll_max,
4506 dsi_cm_calc_pll_cb, ctx);
4507}
4508
4509static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
4510{
4511 struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
4512 const struct omap_dss_dsi_config *cfg = ctx->config;
4513 int bitspp = dsi_get_pixel_size(cfg->pixel_format);
4514 int ndl = dsi->num_lanes_used - 1;
4515 unsigned long hsclk = ctx->dsi_cinfo.clkdco / 4;
4516 unsigned long byteclk = hsclk / 4;
4517
4518 unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
4519 int xres;
4520 int panel_htot, panel_hbl; /* pixels */
4521 int dispc_htot, dispc_hbl; /* pixels */
4522 int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
4523 int hfp, hsa, hbp;
4524 const struct omap_video_timings *req_vm;
4525 struct omap_video_timings *dispc_vm;
4526 struct omap_dss_dsi_videomode_timings *dsi_vm;
4527 u64 dsi_tput, dispc_tput;
4528
4529 dsi_tput = (u64)byteclk * ndl * 8;
4530
4531 req_vm = cfg->timings;
4532 req_pck_min = ctx->req_pck_min;
4533 req_pck_max = ctx->req_pck_max;
4534 req_pck_nom = ctx->req_pck_nom;
4535
4536 dispc_pck = ctx->dispc_cinfo.pck;
4537 dispc_tput = (u64)dispc_pck * bitspp;
4538
4539 xres = req_vm->x_res;
4540
4541 panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
4542 panel_htot = xres + panel_hbl;
4543
4544 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
4545
4546 /*
4547 * When there are no line buffers, DISPC and DSI must have the
4548 * same tput. Otherwise DISPC tput needs to be higher than DSI's.
4549 */
4550 if (dsi->line_buffer_size < xres * bitspp / 8) {
4551 if (dispc_tput != dsi_tput)
4552 return false;
4553 } else {
4554 if (dispc_tput < dsi_tput)
4555 return false;
4556 }
4557
4558 /* DSI tput must be over the min requirement */
4559 if (dsi_tput < (u64)bitspp * req_pck_min)
4560 return false;
4561
4562 /* When non-burst mode, DSI tput must be below max requirement. */
4563 if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
4564 if (dsi_tput > (u64)bitspp * req_pck_max)
4565 return false;
4566 }
4567
4568 hss = DIV_ROUND_UP(4, ndl);
4569
4570 if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
4571 if (ndl == 3 && req_vm->hsw == 0)
4572 hse = 1;
4573 else
4574 hse = DIV_ROUND_UP(4, ndl);
4575 } else {
4576 hse = 0;
4577 }
4578
4579 /* DSI htot to match the panel's nominal pck */
4580 dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
4581
4582 /* fail if there would be no time for blanking */
4583 if (dsi_htot < hss + hse + dsi_hact)
4584 return false;
4585
4586 /* total DSI blanking needed to achieve panel's TL */
4587 dsi_hbl = dsi_htot - dsi_hact;
4588
4589 /* DISPC htot to match the DSI TL */
4590 dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
4591
4592 /* verify that the DSI and DISPC TLs are the same */
4593 if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
4594 return false;
4595
4596 dispc_hbl = dispc_htot - xres;
4597
4598 /* setup DSI videomode */
4599
4600 dsi_vm = &ctx->dsi_vm;
4601 memset(dsi_vm, 0, sizeof(*dsi_vm));
4602
4603 dsi_vm->hsclk = hsclk;
4604
4605 dsi_vm->ndl = ndl;
4606 dsi_vm->bitspp = bitspp;
4607
4608 if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
4609 hsa = 0;
4610 } else if (ndl == 3 && req_vm->hsw == 0) {
4611 hsa = 0;
4612 } else {
4613 hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
4614 hsa = max(hsa - hse, 1);
4615 }
4616
4617 hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
4618 hbp = max(hbp, 1);
4619
4620 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4621 if (hfp < 1) {
4622 int t;
4623 /* we need to take cycles from hbp */
4624
4625 t = 1 - hfp;
4626 hbp = max(hbp - t, 1);
4627 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4628
4629 if (hfp < 1 && hsa > 0) {
4630 /* we need to take cycles from hsa */
4631 t = 1 - hfp;
4632 hsa = max(hsa - t, 1);
4633 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4634 }
4635 }
4636
4637 if (hfp < 1)
4638 return false;
4639
4640 dsi_vm->hss = hss;
4641 dsi_vm->hsa = hsa;
4642 dsi_vm->hse = hse;
4643 dsi_vm->hbp = hbp;
4644 dsi_vm->hact = xres;
4645 dsi_vm->hfp = hfp;
4646
4647 dsi_vm->vsa = req_vm->vsw;
4648 dsi_vm->vbp = req_vm->vbp;
4649 dsi_vm->vact = req_vm->y_res;
4650 dsi_vm->vfp = req_vm->vfp;
4651
4652 dsi_vm->trans_mode = cfg->trans_mode;
4653
4654 dsi_vm->blanking_mode = 0;
4655 dsi_vm->hsa_blanking_mode = 1;
4656 dsi_vm->hfp_blanking_mode = 1;
4657 dsi_vm->hbp_blanking_mode = 1;
4658
4659 dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
4660 dsi_vm->window_sync = 4;
4661
4662 /* setup DISPC videomode */
4663
4664 dispc_vm = &ctx->dispc_vm;
4665 *dispc_vm = *req_vm;
4666 dispc_vm->pixelclock = dispc_pck;
4667
4668 if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
4669 hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
4670 req_pck_nom);
4671 hsa = max(hsa, 1);
4672 } else {
4673 hsa = 1;
4674 }
4675
4676 hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
4677 hbp = max(hbp, 1);
4678
4679 hfp = dispc_hbl - hsa - hbp;
4680 if (hfp < 1) {
4681 int t;
4682 /* we need to take cycles from hbp */
4683
4684 t = 1 - hfp;
4685 hbp = max(hbp - t, 1);
4686 hfp = dispc_hbl - hsa - hbp;
4687
4688 if (hfp < 1) {
4689 /* we need to take cycles from hsa */
4690 t = 1 - hfp;
4691 hsa = max(hsa - t, 1);
4692 hfp = dispc_hbl - hsa - hbp;
4693 }
4694 }
4695
4696 if (hfp < 1)
4697 return false;
4698
4699 dispc_vm->hfp = hfp;
4700 dispc_vm->hsw = hsa;
4701 dispc_vm->hbp = hbp;
4702
4703 return true;
4704}
4705
4706
4707static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
4708 unsigned long pck, void *data)
4709{
4710 struct dsi_clk_calc_ctx *ctx = data;
4711
4712 ctx->dispc_cinfo.lck_div = lckd;
4713 ctx->dispc_cinfo.pck_div = pckd;
4714 ctx->dispc_cinfo.lck = lck;
4715 ctx->dispc_cinfo.pck = pck;
4716
4717 if (dsi_vm_calc_blanking(ctx) == false)
4718 return false;
4719
4720#ifdef PRINT_VERBOSE_VM_TIMINGS
4721 print_dispc_vm("dispc", &ctx->dispc_vm);
4722 print_dsi_vm("dsi ", &ctx->dsi_vm);
4723 print_dispc_vm("req ", ctx->config->timings);
4724 print_dsi_dispc_vm("act ", &ctx->dsi_vm);
4725#endif
4726
4727 return true;
4728}
4729
4730static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
4731 void *data)
4732{
4733 struct dsi_clk_calc_ctx *ctx = data;
4734 unsigned long pck_max;
4735
4736 ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
4737 ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
4738
4739 /*
4740 * In burst mode we can let the dispc pck be arbitrarily high, but it
4741 * limits our scaling abilities. So for now, don't aim too high.
4742 */
4743
4744 if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
4745 pck_max = ctx->req_pck_max + 10000000;
4746 else
4747 pck_max = ctx->req_pck_max;
4748
4749 return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
4750 dsi_vm_calc_dispc_cb, ctx);
4751}
4752
4753static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
4754 unsigned long clkdco, void *data)
4755{
4756 struct dsi_clk_calc_ctx *ctx = data;
4757
4758 ctx->dsi_cinfo.n = n;
4759 ctx->dsi_cinfo.m = m;
4760 ctx->dsi_cinfo.fint = fint;
4761 ctx->dsi_cinfo.clkdco = clkdco;
4762
4763 return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
4764 dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
4765 dsi_vm_calc_hsdiv_cb, ctx);
4766}
4767
4768static bool dsi_vm_calc(struct dsi_data *dsi,
4769 const struct omap_dss_dsi_config *cfg,
4770 struct dsi_clk_calc_ctx *ctx)
4771{
4772 const struct omap_video_timings *t = cfg->timings;
4773 unsigned long clkin;
4774 unsigned long pll_min;
4775 unsigned long pll_max;
4776 int ndl = dsi->num_lanes_used - 1;
4777 int bitspp = dsi_get_pixel_size(cfg->pixel_format);
4778 unsigned long byteclk_min;
4779
4780 clkin = clk_get_rate(dsi->pll.clkin);
4781
4782 memset(ctx, 0, sizeof(*ctx));
4783 ctx->dsidev = dsi->pdev;
4784 ctx->pll = &dsi->pll;
4785 ctx->config = cfg;
4786
4787 /* these limits should come from the panel driver */
4788 ctx->req_pck_min = t->pixelclock - 1000;
4789 ctx->req_pck_nom = t->pixelclock;
4790 ctx->req_pck_max = t->pixelclock + 1000;
4791
4792 byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
4793 pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
4794
4795 if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
4796 pll_max = cfg->hs_clk_max * 4;
4797 } else {
4798 unsigned long byteclk_max;
4799 byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
4800 ndl * 8);
4801
4802 pll_max = byteclk_max * 4 * 4;
4803 }
4804
4805 return dss_pll_calc(ctx->pll, clkin,
4806 pll_min, pll_max,
4807 dsi_vm_calc_pll_cb, ctx);
4808}
4809
4810static int dsi_set_config(struct omap_dss_device *dssdev,
4811 const struct omap_dss_dsi_config *config)
4812{
4813 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4814 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4815 struct dsi_clk_calc_ctx ctx;
4816 bool ok;
4817 int r;
4818
4819 mutex_lock(&dsi->lock);
4820
4821 dsi->pix_fmt = config->pixel_format;
4822 dsi->mode = config->mode;
4823
4824 if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
4825 ok = dsi_vm_calc(dsi, config, &ctx);
4826 else
4827 ok = dsi_cm_calc(dsi, config, &ctx);
4828
4829 if (!ok) {
4830 DSSERR("failed to find suitable DSI clock settings\n");
4831 r = -EINVAL;
4832 goto err;
4833 }
4834
4835 dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
4836
4837 r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI],
4838 config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo);
4839 if (r) {
4840 DSSERR("failed to find suitable DSI LP clock settings\n");
4841 goto err;
4842 }
4843
4844 dsi->user_dsi_cinfo = ctx.dsi_cinfo;
4845 dsi->user_dispc_cinfo = ctx.dispc_cinfo;
4846
4847 dsi->timings = ctx.dispc_vm;
4848 dsi->vm_timings = ctx.dsi_vm;
4849
4850 mutex_unlock(&dsi->lock);
4851
4852 return 0;
4853err:
4854 mutex_unlock(&dsi->lock);
4855
4856 return r;
4857}
4858
4859/*
4860 * Return a hardcoded channel for the DSI output. This should work for
4861 * current use cases, but this can be later expanded to either resolve
4862 * the channel in some more dynamic manner, or get the channel as a user
4863 * parameter.
4864 */
4865static enum omap_channel dsi_get_channel(int module_id)
4866{
4867 switch (omapdss_get_version()) {
4868 case OMAPDSS_VER_OMAP24xx:
4869 case OMAPDSS_VER_AM43xx:
4870 DSSWARN("DSI not supported\n");
4871 return OMAP_DSS_CHANNEL_LCD;
4872
4873 case OMAPDSS_VER_OMAP34xx_ES1:
4874 case OMAPDSS_VER_OMAP34xx_ES3:
4875 case OMAPDSS_VER_OMAP3630:
4876 case OMAPDSS_VER_AM35xx:
4877 return OMAP_DSS_CHANNEL_LCD;
4878
4879 case OMAPDSS_VER_OMAP4430_ES1:
4880 case OMAPDSS_VER_OMAP4430_ES2:
4881 case OMAPDSS_VER_OMAP4:
4882 switch (module_id) {
4883 case 0:
4884 return OMAP_DSS_CHANNEL_LCD;
4885 case 1:
4886 return OMAP_DSS_CHANNEL_LCD2;
4887 default:
4888 DSSWARN("unsupported module id\n");
4889 return OMAP_DSS_CHANNEL_LCD;
4890 }
4891
4892 case OMAPDSS_VER_OMAP5:
4893 switch (module_id) {
4894 case 0:
4895 return OMAP_DSS_CHANNEL_LCD;
4896 case 1:
4897 return OMAP_DSS_CHANNEL_LCD3;
4898 default:
4899 DSSWARN("unsupported module id\n");
4900 return OMAP_DSS_CHANNEL_LCD;
4901 }
4902
4903 default:
4904 DSSWARN("unsupported DSS version\n");
4905 return OMAP_DSS_CHANNEL_LCD;
4906 }
4907}
4908
4909static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
4910{
4911 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4912 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4913 int i;
4914
4915 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
4916 if (!dsi->vc[i].dssdev) {
4917 dsi->vc[i].dssdev = dssdev;
4918 *channel = i;
4919 return 0;
4920 }
4921 }
4922
4923 DSSERR("cannot get VC for display %s", dssdev->name);
4924 return -ENOSPC;
4925}
4926
4927static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
4928{
4929 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4930 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4931
4932 if (vc_id < 0 || vc_id > 3) {
4933 DSSERR("VC ID out of range\n");
4934 return -EINVAL;
4935 }
4936
4937 if (channel < 0 || channel > 3) {
4938 DSSERR("Virtual Channel out of range\n");
4939 return -EINVAL;
4940 }
4941
4942 if (dsi->vc[channel].dssdev != dssdev) {
4943 DSSERR("Virtual Channel not allocated to display %s\n",
4944 dssdev->name);
4945 return -EINVAL;
4946 }
4947
4948 dsi->vc[channel].vc_id = vc_id;
4949
4950 return 0;
4951}
4952
4953static void dsi_release_vc(struct omap_dss_device *dssdev, int channel)
4954{
4955 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4956 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4957
4958 if ((channel >= 0 && channel <= 3) &&
4959 dsi->vc[channel].dssdev == dssdev) {
4960 dsi->vc[channel].dssdev = NULL;
4961 dsi->vc[channel].vc_id = 0;
4962 }
4963}
4964
4965
4966static int dsi_get_clocks(struct platform_device *dsidev)
4967{
4968 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4969 struct clk *clk;
4970
4971 clk = devm_clk_get(&dsidev->dev, "fck");
4972 if (IS_ERR(clk)) {
4973 DSSERR("can't get fck\n");
4974 return PTR_ERR(clk);
4975 }
4976
4977 dsi->dss_clk = clk;
4978
4979 return 0;
4980}
4981
4982static int dsi_connect(struct omap_dss_device *dssdev,
4983 struct omap_dss_device *dst)
4984{
4985 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4986 struct omap_overlay_manager *mgr;
4987 int r;
4988
4989 r = dsi_regulator_init(dsidev);
4990 if (r)
4991 return r;
4992
4993 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
4994 if (!mgr)
4995 return -ENODEV;
4996
4997 r = dss_mgr_connect(mgr, dssdev);
4998 if (r)
4999 return r;
5000
5001 r = omapdss_output_set_device(dssdev, dst);
5002 if (r) {
5003 DSSERR("failed to connect output to new device: %s\n",
5004 dssdev->name);
5005 dss_mgr_disconnect(mgr, dssdev);
5006 return r;
5007 }
5008
5009 return 0;
5010}
5011
5012static void dsi_disconnect(struct omap_dss_device *dssdev,
5013 struct omap_dss_device *dst)
5014{
5015 WARN_ON(dst != dssdev->dst);
5016
5017 if (dst != dssdev->dst)
5018 return;
5019
5020 omapdss_output_unset_device(dssdev);
5021
5022 if (dssdev->manager)
5023 dss_mgr_disconnect(dssdev->manager, dssdev);
5024}
5025
5026static const struct omapdss_dsi_ops dsi_ops = {
5027 .connect = dsi_connect,
5028 .disconnect = dsi_disconnect,
5029
5030 .bus_lock = dsi_bus_lock,
5031 .bus_unlock = dsi_bus_unlock,
5032
5033 .enable = dsi_display_enable,
5034 .disable = dsi_display_disable,
5035
5036 .enable_hs = dsi_vc_enable_hs,
5037
5038 .configure_pins = dsi_configure_pins,
5039 .set_config = dsi_set_config,
5040
5041 .enable_video_output = dsi_enable_video_output,
5042 .disable_video_output = dsi_disable_video_output,
5043
5044 .update = dsi_update,
5045
5046 .enable_te = dsi_enable_te,
5047
5048 .request_vc = dsi_request_vc,
5049 .set_vc_id = dsi_set_vc_id,
5050 .release_vc = dsi_release_vc,
5051
5052 .dcs_write = dsi_vc_dcs_write,
5053 .dcs_write_nosync = dsi_vc_dcs_write_nosync,
5054 .dcs_read = dsi_vc_dcs_read,
5055
5056 .gen_write = dsi_vc_generic_write,
5057 .gen_write_nosync = dsi_vc_generic_write_nosync,
5058 .gen_read = dsi_vc_generic_read,
5059
5060 .bta_sync = dsi_vc_send_bta_sync,
5061
5062 .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
5063};
5064
5065static void dsi_init_output(struct platform_device *dsidev)
5066{
5067 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5068 struct omap_dss_device *out = &dsi->output;
5069
5070 out->dev = &dsidev->dev;
5071 out->id = dsi->module_id == 0 ?
5072 OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
5073
5074 out->output_type = OMAP_DISPLAY_TYPE_DSI;
5075 out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
5076 out->dispc_channel = dsi_get_channel(dsi->module_id);
5077 out->ops.dsi = &dsi_ops;
5078 out->owner = THIS_MODULE;
5079
5080 omapdss_register_output(out);
5081}
5082
5083static void dsi_uninit_output(struct platform_device *dsidev)
5084{
5085 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5086 struct omap_dss_device *out = &dsi->output;
5087
5088 omapdss_unregister_output(out);
5089}
5090
5091static int dsi_probe_of(struct platform_device *pdev)
5092{
5093 struct device_node *node = pdev->dev.of_node;
5094 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5095 struct property *prop;
5096 u32 lane_arr[10];
5097 int len, num_pins;
5098 int r, i;
5099 struct device_node *ep;
5100 struct omap_dsi_pin_config pin_cfg;
5101
5102 ep = omapdss_of_get_first_endpoint(node);
5103 if (!ep)
5104 return 0;
5105
5106 prop = of_find_property(ep, "lanes", &len);
5107 if (prop == NULL) {
5108 dev_err(&pdev->dev, "failed to find lane data\n");
5109 r = -EINVAL;
5110 goto err;
5111 }
5112
5113 num_pins = len / sizeof(u32);
5114
5115 if (num_pins < 4 || num_pins % 2 != 0 ||
5116 num_pins > dsi->num_lanes_supported * 2) {
5117 dev_err(&pdev->dev, "bad number of lanes\n");
5118 r = -EINVAL;
5119 goto err;
5120 }
5121
5122 r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
5123 if (r) {
5124 dev_err(&pdev->dev, "failed to read lane data\n");
5125 goto err;
5126 }
5127
5128 pin_cfg.num_pins = num_pins;
5129 for (i = 0; i < num_pins; ++i)
5130 pin_cfg.pins[i] = (int)lane_arr[i];
5131
5132 r = dsi_configure_pins(&dsi->output, &pin_cfg);
5133 if (r) {
5134 dev_err(&pdev->dev, "failed to configure pins");
5135 goto err;
5136 }
5137
5138 of_node_put(ep);
5139
5140 return 0;
5141
5142err:
5143 of_node_put(ep);
5144 return r;
5145}
5146
5147static const struct dss_pll_ops dsi_pll_ops = {
5148 .enable = dsi_pll_enable,
5149 .disable = dsi_pll_disable,
5150 .set_config = dss_pll_write_config_type_a,
5151};
5152
5153static const struct dss_pll_hw dss_omap3_dsi_pll_hw = {
5154 .n_max = (1 << 7) - 1,
5155 .m_max = (1 << 11) - 1,
5156 .mX_max = (1 << 4) - 1,
5157 .fint_min = 750000,
5158 .fint_max = 2100000,
5159 .clkdco_low = 1000000000,
5160 .clkdco_max = 1800000000,
5161
5162 .n_msb = 7,
5163 .n_lsb = 1,
5164 .m_msb = 18,
5165 .m_lsb = 8,
5166
5167 .mX_msb[0] = 22,
5168 .mX_lsb[0] = 19,
5169 .mX_msb[1] = 26,
5170 .mX_lsb[1] = 23,
5171
5172 .has_stopmode = true,
5173 .has_freqsel = true,
5174 .has_selfreqdco = false,
5175 .has_refsel = false,
5176};
5177
5178static const struct dss_pll_hw dss_omap4_dsi_pll_hw = {
5179 .n_max = (1 << 8) - 1,
5180 .m_max = (1 << 12) - 1,
5181 .mX_max = (1 << 5) - 1,
5182 .fint_min = 500000,
5183 .fint_max = 2500000,
5184 .clkdco_low = 1000000000,
5185 .clkdco_max = 1800000000,
5186
5187 .n_msb = 8,
5188 .n_lsb = 1,
5189 .m_msb = 20,
5190 .m_lsb = 9,
5191
5192 .mX_msb[0] = 25,
5193 .mX_lsb[0] = 21,
5194 .mX_msb[1] = 30,
5195 .mX_lsb[1] = 26,
5196
5197 .has_stopmode = true,
5198 .has_freqsel = false,
5199 .has_selfreqdco = false,
5200 .has_refsel = false,
5201};
5202
5203static const struct dss_pll_hw dss_omap5_dsi_pll_hw = {
5204 .n_max = (1 << 8) - 1,
5205 .m_max = (1 << 12) - 1,
5206 .mX_max = (1 << 5) - 1,
5207 .fint_min = 150000,
5208 .fint_max = 52000000,
5209 .clkdco_low = 1000000000,
5210 .clkdco_max = 1800000000,
5211
5212 .n_msb = 8,
5213 .n_lsb = 1,
5214 .m_msb = 20,
5215 .m_lsb = 9,
5216
5217 .mX_msb[0] = 25,
5218 .mX_lsb[0] = 21,
5219 .mX_msb[1] = 30,
5220 .mX_lsb[1] = 26,
5221
5222 .has_stopmode = true,
5223 .has_freqsel = false,
5224 .has_selfreqdco = true,
5225 .has_refsel = true,
5226};
5227
5228static int dsi_init_pll_data(struct platform_device *dsidev)
5229{
5230 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5231 struct dss_pll *pll = &dsi->pll;
5232 struct clk *clk;
5233 int r;
5234
5235 clk = devm_clk_get(&dsidev->dev, "sys_clk");
5236 if (IS_ERR(clk)) {
5237 DSSERR("can't get sys_clk\n");
5238 return PTR_ERR(clk);
5239 }
5240
5241 pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
5242 pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
5243 pll->clkin = clk;
5244 pll->base = dsi->pll_base;
5245
5246 switch (omapdss_get_version()) {
5247 case OMAPDSS_VER_OMAP34xx_ES1:
5248 case OMAPDSS_VER_OMAP34xx_ES3:
5249 case OMAPDSS_VER_OMAP3630:
5250 case OMAPDSS_VER_AM35xx:
5251 pll->hw = &dss_omap3_dsi_pll_hw;
5252 break;
5253
5254 case OMAPDSS_VER_OMAP4430_ES1:
5255 case OMAPDSS_VER_OMAP4430_ES2:
5256 case OMAPDSS_VER_OMAP4:
5257 pll->hw = &dss_omap4_dsi_pll_hw;
5258 break;
5259
5260 case OMAPDSS_VER_OMAP5:
5261 pll->hw = &dss_omap5_dsi_pll_hw;
5262 break;
5263
5264 default:
5265 return -ENODEV;
5266 }
5267
5268 pll->ops = &dsi_pll_ops;
5269
5270 r = dss_pll_register(pll);
5271 if (r)
5272 return r;
5273
5274 return 0;
5275}
5276
5277/* DSI1 HW IP initialisation */
5278static int dsi_bind(struct device *dev, struct device *master, void *data)
5279{
5280 struct platform_device *dsidev = to_platform_device(dev);
5281 u32 rev;
5282 int r, i;
5283 struct dsi_data *dsi;
5284 struct resource *dsi_mem;
5285 struct resource *res;
5286 struct resource temp_res;
5287
5288 dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL);
5289 if (!dsi)
5290 return -ENOMEM;
5291
5292 dsi->pdev = dsidev;
5293 dev_set_drvdata(&dsidev->dev, dsi);
5294
5295 spin_lock_init(&dsi->irq_lock);
5296 spin_lock_init(&dsi->errors_lock);
5297 dsi->errors = 0;
5298
5299#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
5300 spin_lock_init(&dsi->irq_stats_lock);
5301 dsi->irq_stats.last_reset = jiffies;
5302#endif
5303
5304 mutex_init(&dsi->lock);
5305 sema_init(&dsi->bus_lock, 1);
5306
5307 INIT_DEFERRABLE_WORK(&dsi->framedone_timeout_work,
5308 dsi_framedone_timeout_work_callback);
5309
5310#ifdef DSI_CATCH_MISSING_TE
5311 init_timer(&dsi->te_timer);
5312 dsi->te_timer.function = dsi_te_timeout;
5313 dsi->te_timer.data = 0;
5314#endif
5315
5316 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto");
5317 if (!res) {
5318 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5319 if (!res) {
5320 DSSERR("can't get IORESOURCE_MEM DSI\n");
5321 return -EINVAL;
5322 }
5323
5324 temp_res.start = res->start;
5325 temp_res.end = temp_res.start + DSI_PROTO_SZ - 1;
5326 res = &temp_res;
5327 }
5328
5329 dsi_mem = res;
5330
5331 dsi->proto_base = devm_ioremap(&dsidev->dev, res->start,
5332 resource_size(res));
5333 if (!dsi->proto_base) {
5334 DSSERR("can't ioremap DSI protocol engine\n");
5335 return -ENOMEM;
5336 }
5337
5338 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "phy");
5339 if (!res) {
5340 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5341 if (!res) {
5342 DSSERR("can't get IORESOURCE_MEM DSI\n");
5343 return -EINVAL;
5344 }
5345
5346 temp_res.start = res->start + DSI_PHY_OFFSET;
5347 temp_res.end = temp_res.start + DSI_PHY_SZ - 1;
5348 res = &temp_res;
5349 }
5350
5351 dsi->phy_base = devm_ioremap(&dsidev->dev, res->start,
5352 resource_size(res));
5353 if (!dsi->proto_base) {
5354 DSSERR("can't ioremap DSI PHY\n");
5355 return -ENOMEM;
5356 }
5357
5358 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "pll");
5359 if (!res) {
5360 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5361 if (!res) {
5362 DSSERR("can't get IORESOURCE_MEM DSI\n");
5363 return -EINVAL;
5364 }
5365
5366 temp_res.start = res->start + DSI_PLL_OFFSET;
5367 temp_res.end = temp_res.start + DSI_PLL_SZ - 1;
5368 res = &temp_res;
5369 }
5370
5371 dsi->pll_base = devm_ioremap(&dsidev->dev, res->start,
5372 resource_size(res));
5373 if (!dsi->proto_base) {
5374 DSSERR("can't ioremap DSI PLL\n");
5375 return -ENOMEM;
5376 }
5377
5378 dsi->irq = platform_get_irq(dsi->pdev, 0);
5379 if (dsi->irq < 0) {
5380 DSSERR("platform_get_irq failed\n");
5381 return -ENODEV;
5382 }
5383
5384 r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler,
5385 IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev);
5386 if (r < 0) {
5387 DSSERR("request_irq failed\n");
5388 return r;
5389 }
5390
5391 if (dsidev->dev.of_node) {
5392 const struct of_device_id *match;
5393 const struct dsi_module_id_data *d;
5394
5395 match = of_match_node(dsi_of_match, dsidev->dev.of_node);
5396 if (!match) {
5397 DSSERR("unsupported DSI module\n");
5398 return -ENODEV;
5399 }
5400
5401 d = match->data;
5402
5403 while (d->address != 0 && d->address != dsi_mem->start)
5404 d++;
5405
5406 if (d->address == 0) {
5407 DSSERR("unsupported DSI module\n");
5408 return -ENODEV;
5409 }
5410
5411 dsi->module_id = d->id;
5412 } else {
5413 dsi->module_id = dsidev->id;
5414 }
5415
5416 /* DSI VCs initialization */
5417 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
5418 dsi->vc[i].source = DSI_VC_SOURCE_L4;
5419 dsi->vc[i].dssdev = NULL;
5420 dsi->vc[i].vc_id = 0;
5421 }
5422
5423 r = dsi_get_clocks(dsidev);
5424 if (r)
5425 return r;
5426
5427 dsi_init_pll_data(dsidev);
5428
5429 pm_runtime_enable(&dsidev->dev);
5430
5431 r = dsi_runtime_get(dsidev);
5432 if (r)
5433 goto err_runtime_get;
5434
5435 rev = dsi_read_reg(dsidev, DSI_REVISION);
5436 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
5437 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
5438
5439 /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
5440 * of data to 3 by default */
5441 if (dss_has_feature(FEAT_DSI_GNQ))
5442 /* NB_DATA_LANES */
5443 dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
5444 else
5445 dsi->num_lanes_supported = 3;
5446
5447 dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
5448
5449 dsi_init_output(dsidev);
5450
5451 if (dsidev->dev.of_node) {
5452 r = dsi_probe_of(dsidev);
5453 if (r) {
5454 DSSERR("Invalid DSI DT data\n");
5455 goto err_probe_of;
5456 }
5457
5458 r = of_platform_populate(dsidev->dev.of_node, NULL, NULL,
5459 &dsidev->dev);
5460 if (r)
5461 DSSERR("Failed to populate DSI child devices: %d\n", r);
5462 }
5463
5464 dsi_runtime_put(dsidev);
5465
5466 if (dsi->module_id == 0)
5467 dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs);
5468 else if (dsi->module_id == 1)
5469 dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs);
5470
5471#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
5472 if (dsi->module_id == 0)
5473 dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs);
5474 else if (dsi->module_id == 1)
5475 dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
5476#endif
5477
5478 return 0;
5479
5480err_probe_of:
5481 dsi_uninit_output(dsidev);
5482 dsi_runtime_put(dsidev);
5483
5484err_runtime_get:
5485 pm_runtime_disable(&dsidev->dev);
5486 return r;
5487}
5488
5489static void dsi_unbind(struct device *dev, struct device *master, void *data)
5490{
5491 struct platform_device *dsidev = to_platform_device(dev);
5492 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5493
5494 of_platform_depopulate(&dsidev->dev);
5495
5496 WARN_ON(dsi->scp_clk_refcount > 0);
5497
5498 dss_pll_unregister(&dsi->pll);
5499
5500 dsi_uninit_output(dsidev);
5501
5502 pm_runtime_disable(&dsidev->dev);
5503
5504 if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
5505 regulator_disable(dsi->vdds_dsi_reg);
5506 dsi->vdds_dsi_enabled = false;
5507 }
5508}
5509
5510static const struct component_ops dsi_component_ops = {
5511 .bind = dsi_bind,
5512 .unbind = dsi_unbind,
5513};
5514
5515static int dsi_probe(struct platform_device *pdev)
5516{
5517 return component_add(&pdev->dev, &dsi_component_ops);
5518}
5519
5520static int dsi_remove(struct platform_device *pdev)
5521{
5522 component_del(&pdev->dev, &dsi_component_ops);
5523 return 0;
5524}
5525
5526static int dsi_runtime_suspend(struct device *dev)
5527{
5528 struct platform_device *pdev = to_platform_device(dev);
5529 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5530
5531 dsi->is_enabled = false;
5532 /* ensure the irq handler sees the is_enabled value */
5533 smp_wmb();
5534 /* wait for current handler to finish before turning the DSI off */
5535 synchronize_irq(dsi->irq);
5536
5537 dispc_runtime_put();
5538
5539 return 0;
5540}
5541
5542static int dsi_runtime_resume(struct device *dev)
5543{
5544 struct platform_device *pdev = to_platform_device(dev);
5545 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5546 int r;
5547
5548 r = dispc_runtime_get();
5549 if (r)
5550 return r;
5551
5552 dsi->is_enabled = true;
5553 /* ensure the irq handler sees the is_enabled value */
5554 smp_wmb();
5555
5556 return 0;
5557}
5558
5559static const struct dev_pm_ops dsi_pm_ops = {
5560 .runtime_suspend = dsi_runtime_suspend,
5561 .runtime_resume = dsi_runtime_resume,
5562};
5563
5564static const struct dsi_module_id_data dsi_of_data_omap3[] = {
5565 { .address = 0x4804fc00, .id = 0, },
5566 { },
5567};
5568
5569static const struct dsi_module_id_data dsi_of_data_omap4[] = {
5570 { .address = 0x58004000, .id = 0, },
5571 { .address = 0x58005000, .id = 1, },
5572 { },
5573};
5574
5575static const struct dsi_module_id_data dsi_of_data_omap5[] = {
5576 { .address = 0x58004000, .id = 0, },
5577 { .address = 0x58009000, .id = 1, },
5578 { },
5579};
5580
5581static const struct of_device_id dsi_of_match[] = {
5582 { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
5583 { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
5584 { .compatible = "ti,omap5-dsi", .data = dsi_of_data_omap5, },
5585 {},
5586};
5587
5588static struct platform_driver omap_dsihw_driver = {
5589 .probe = dsi_probe,
5590 .remove = dsi_remove,
5591 .driver = {
5592 .name = "omapdss_dsi",
5593 .pm = &dsi_pm_ops,
5594 .of_match_table = dsi_of_match,
5595 .suppress_bind_attrs = true,
5596 },
5597};
5598
5599int __init dsi_init_platform_driver(void)
5600{
5601 return platform_driver_register(&omap_dsihw_driver);
5602}
5603
5604void dsi_uninit_platform_driver(void)
5605{
5606 platform_driver_unregister(&omap_dsihw_driver);
5607}
diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c
new file mode 100644
index 000000000000..bf407b6ba15c
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c
@@ -0,0 +1,183 @@
1/*
2 * Copyright (C) 2013 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
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/seq_file.h>
20
21#include <video/omapdss.h>
22
23#include "dss.h"
24
25struct device_node *
26omapdss_of_get_next_port(const struct device_node *parent,
27 struct device_node *prev)
28{
29 struct device_node *port = NULL;
30
31 if (!parent)
32 return NULL;
33
34 if (!prev) {
35 struct device_node *ports;
36 /*
37 * It's the first call, we have to find a port subnode
38 * within this node or within an optional 'ports' node.
39 */
40 ports = of_get_child_by_name(parent, "ports");
41 if (ports)
42 parent = ports;
43
44 port = of_get_child_by_name(parent, "port");
45
46 /* release the 'ports' node */
47 of_node_put(ports);
48 } else {
49 struct device_node *ports;
50
51 ports = of_get_parent(prev);
52 if (!ports)
53 return NULL;
54
55 do {
56 port = of_get_next_child(ports, prev);
57 if (!port) {
58 of_node_put(ports);
59 return NULL;
60 }
61 prev = port;
62 } while (of_node_cmp(port->name, "port") != 0);
63
64 of_node_put(ports);
65 }
66
67 return port;
68}
69EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
70
71struct device_node *
72omapdss_of_get_next_endpoint(const struct device_node *parent,
73 struct device_node *prev)
74{
75 struct device_node *ep = NULL;
76
77 if (!parent)
78 return NULL;
79
80 do {
81 ep = of_get_next_child(parent, prev);
82 if (!ep)
83 return NULL;
84 prev = ep;
85 } while (of_node_cmp(ep->name, "endpoint") != 0);
86
87 return ep;
88}
89EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
90
91struct device_node *dss_of_port_get_parent_device(struct device_node *port)
92{
93 struct device_node *np;
94 int i;
95
96 if (!port)
97 return NULL;
98
99 np = of_get_parent(port);
100
101 for (i = 0; i < 2 && np; ++i) {
102 struct property *prop;
103
104 prop = of_find_property(np, "compatible", NULL);
105
106 if (prop)
107 return np;
108
109 np = of_get_next_parent(np);
110 }
111
112 return NULL;
113}
114
115u32 dss_of_port_get_port_number(struct device_node *port)
116{
117 int r;
118 u32 reg;
119
120 r = of_property_read_u32(port, "reg", &reg);
121 if (r)
122 reg = 0;
123
124 return reg;
125}
126
127static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
128{
129 struct device_node *np;
130
131 np = of_parse_phandle(node, "remote-endpoint", 0);
132 if (!np)
133 return NULL;
134
135 np = of_get_next_parent(np);
136
137 return np;
138}
139
140struct device_node *
141omapdss_of_get_first_endpoint(const struct device_node *parent)
142{
143 struct device_node *port, *ep;
144
145 port = omapdss_of_get_next_port(parent, NULL);
146
147 if (!port)
148 return NULL;
149
150 ep = omapdss_of_get_next_endpoint(port, NULL);
151
152 of_node_put(port);
153
154 return ep;
155}
156EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
157
158struct omap_dss_device *
159omapdss_of_find_source_for_first_ep(struct device_node *node)
160{
161 struct device_node *ep;
162 struct device_node *src_port;
163 struct omap_dss_device *src;
164
165 ep = omapdss_of_get_first_endpoint(node);
166 if (!ep)
167 return ERR_PTR(-EINVAL);
168
169 src_port = omapdss_of_get_remote_port(ep);
170 if (!src_port) {
171 of_node_put(ep);
172 return ERR_PTR(-EINVAL);
173 }
174
175 of_node_put(ep);
176
177 src = omap_dss_find_output_by_port_node(src_port);
178
179 of_node_put(src_port);
180
181 return src ? src : ERR_PTR(-EPROBE_DEFER);
182}
183EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c
new file mode 100644
index 000000000000..f95ff319e68e
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -0,0 +1,1329 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DSS"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/io.h>
28#include <linux/export.h>
29#include <linux/err.h>
30#include <linux/delay.h>
31#include <linux/seq_file.h>
32#include <linux/clk.h>
33#include <linux/platform_device.h>
34#include <linux/pm_runtime.h>
35#include <linux/gfp.h>
36#include <linux/sizes.h>
37#include <linux/mfd/syscon.h>
38#include <linux/regmap.h>
39#include <linux/of.h>
40#include <linux/regulator/consumer.h>
41#include <linux/suspend.h>
42#include <linux/component.h>
43
44#include <video/omapdss.h>
45
46#include "dss.h"
47#include "dss_features.h"
48
49#define DSS_SZ_REGS SZ_512
50
51struct dss_reg {
52 u16 idx;
53};
54
55#define DSS_REG(idx) ((const struct dss_reg) { idx })
56
57#define DSS_REVISION DSS_REG(0x0000)
58#define DSS_SYSCONFIG DSS_REG(0x0010)
59#define DSS_SYSSTATUS DSS_REG(0x0014)
60#define DSS_CONTROL DSS_REG(0x0040)
61#define DSS_SDI_CONTROL DSS_REG(0x0044)
62#define DSS_PLL_CONTROL DSS_REG(0x0048)
63#define DSS_SDI_STATUS DSS_REG(0x005C)
64
65#define REG_GET(idx, start, end) \
66 FLD_GET(dss_read_reg(idx), start, end)
67
68#define REG_FLD_MOD(idx, val, start, end) \
69 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
70
71struct dss_features {
72 u8 fck_div_max;
73 u8 dss_fck_multiplier;
74 const char *parent_clk_name;
75 const enum omap_display_type *ports;
76 int num_ports;
77 int (*dpi_select_source)(int port, enum omap_channel channel);
78};
79
80static struct {
81 struct platform_device *pdev;
82 void __iomem *base;
83 struct regmap *syscon_pll_ctrl;
84 u32 syscon_pll_ctrl_offset;
85
86 struct clk *parent_clk;
87 struct clk *dss_clk;
88 unsigned long dss_clk_rate;
89
90 unsigned long cache_req_pck;
91 unsigned long cache_prate;
92 struct dispc_clock_info cache_dispc_cinfo;
93
94 enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
95 enum omap_dss_clk_source dispc_clk_source;
96 enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
97
98 bool ctx_valid;
99 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
100
101 const struct dss_features *feat;
102
103 struct dss_pll *video1_pll;
104 struct dss_pll *video2_pll;
105} dss;
106
107static const char * const dss_generic_clk_source_names[] = {
108 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
109 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
110 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
111 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
112 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
113};
114
115static bool dss_initialized;
116
117bool omapdss_is_initialized(void)
118{
119 return dss_initialized;
120}
121EXPORT_SYMBOL(omapdss_is_initialized);
122
123static inline void dss_write_reg(const struct dss_reg idx, u32 val)
124{
125 __raw_writel(val, dss.base + idx.idx);
126}
127
128static inline u32 dss_read_reg(const struct dss_reg idx)
129{
130 return __raw_readl(dss.base + idx.idx);
131}
132
133#define SR(reg) \
134 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
135#define RR(reg) \
136 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
137
138static void dss_save_context(void)
139{
140 DSSDBG("dss_save_context\n");
141
142 SR(CONTROL);
143
144 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
145 OMAP_DISPLAY_TYPE_SDI) {
146 SR(SDI_CONTROL);
147 SR(PLL_CONTROL);
148 }
149
150 dss.ctx_valid = true;
151
152 DSSDBG("context saved\n");
153}
154
155static void dss_restore_context(void)
156{
157 DSSDBG("dss_restore_context\n");
158
159 if (!dss.ctx_valid)
160 return;
161
162 RR(CONTROL);
163
164 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
165 OMAP_DISPLAY_TYPE_SDI) {
166 RR(SDI_CONTROL);
167 RR(PLL_CONTROL);
168 }
169
170 DSSDBG("context restored\n");
171}
172
173#undef SR
174#undef RR
175
176void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
177{
178 unsigned shift;
179 unsigned val;
180
181 if (!dss.syscon_pll_ctrl)
182 return;
183
184 val = !enable;
185
186 switch (pll_id) {
187 case DSS_PLL_VIDEO1:
188 shift = 0;
189 break;
190 case DSS_PLL_VIDEO2:
191 shift = 1;
192 break;
193 case DSS_PLL_HDMI:
194 shift = 2;
195 break;
196 default:
197 DSSERR("illegal DSS PLL ID %d\n", pll_id);
198 return;
199 }
200
201 regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
202 1 << shift, val << shift);
203}
204
205void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
206 enum omap_channel channel)
207{
208 unsigned shift, val;
209
210 if (!dss.syscon_pll_ctrl)
211 return;
212
213 switch (channel) {
214 case OMAP_DSS_CHANNEL_LCD:
215 shift = 3;
216
217 switch (pll_id) {
218 case DSS_PLL_VIDEO1:
219 val = 0; break;
220 case DSS_PLL_HDMI:
221 val = 1; break;
222 default:
223 DSSERR("error in PLL mux config for LCD\n");
224 return;
225 }
226
227 break;
228 case OMAP_DSS_CHANNEL_LCD2:
229 shift = 5;
230
231 switch (pll_id) {
232 case DSS_PLL_VIDEO1:
233 val = 0; break;
234 case DSS_PLL_VIDEO2:
235 val = 1; break;
236 case DSS_PLL_HDMI:
237 val = 2; break;
238 default:
239 DSSERR("error in PLL mux config for LCD2\n");
240 return;
241 }
242
243 break;
244 case OMAP_DSS_CHANNEL_LCD3:
245 shift = 7;
246
247 switch (pll_id) {
248 case DSS_PLL_VIDEO1:
249 val = 1; break;
250 case DSS_PLL_VIDEO2:
251 val = 0; break;
252 case DSS_PLL_HDMI:
253 val = 2; break;
254 default:
255 DSSERR("error in PLL mux config for LCD3\n");
256 return;
257 }
258
259 break;
260 default:
261 DSSERR("error in PLL mux config\n");
262 return;
263 }
264
265 regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
266 0x3 << shift, val << shift);
267}
268
269void dss_sdi_init(int datapairs)
270{
271 u32 l;
272
273 BUG_ON(datapairs > 3 || datapairs < 1);
274
275 l = dss_read_reg(DSS_SDI_CONTROL);
276 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
277 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
278 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
279 dss_write_reg(DSS_SDI_CONTROL, l);
280
281 l = dss_read_reg(DSS_PLL_CONTROL);
282 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
283 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
284 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
285 dss_write_reg(DSS_PLL_CONTROL, l);
286}
287
288int dss_sdi_enable(void)
289{
290 unsigned long timeout;
291
292 dispc_pck_free_enable(1);
293
294 /* Reset SDI PLL */
295 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
296 udelay(1); /* wait 2x PCLK */
297
298 /* Lock SDI PLL */
299 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
300
301 /* Waiting for PLL lock request to complete */
302 timeout = jiffies + msecs_to_jiffies(500);
303 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
304 if (time_after_eq(jiffies, timeout)) {
305 DSSERR("PLL lock request timed out\n");
306 goto err1;
307 }
308 }
309
310 /* Clearing PLL_GO bit */
311 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
312
313 /* Waiting for PLL to lock */
314 timeout = jiffies + msecs_to_jiffies(500);
315 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
316 if (time_after_eq(jiffies, timeout)) {
317 DSSERR("PLL lock timed out\n");
318 goto err1;
319 }
320 }
321
322 dispc_lcd_enable_signal(1);
323
324 /* Waiting for SDI reset to complete */
325 timeout = jiffies + msecs_to_jiffies(500);
326 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
327 if (time_after_eq(jiffies, timeout)) {
328 DSSERR("SDI reset timed out\n");
329 goto err2;
330 }
331 }
332
333 return 0;
334
335 err2:
336 dispc_lcd_enable_signal(0);
337 err1:
338 /* Reset SDI PLL */
339 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
340
341 dispc_pck_free_enable(0);
342
343 return -ETIMEDOUT;
344}
345
346void dss_sdi_disable(void)
347{
348 dispc_lcd_enable_signal(0);
349
350 dispc_pck_free_enable(0);
351
352 /* Reset SDI PLL */
353 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
354}
355
356const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
357{
358 return dss_generic_clk_source_names[clk_src];
359}
360
361void dss_dump_clocks(struct seq_file *s)
362{
363 const char *fclk_name, *fclk_real_name;
364 unsigned long fclk_rate;
365
366 if (dss_runtime_get())
367 return;
368
369 seq_printf(s, "- DSS -\n");
370
371 fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
372 fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
373 fclk_rate = clk_get_rate(dss.dss_clk);
374
375 seq_printf(s, "%s (%s) = %lu\n",
376 fclk_name, fclk_real_name,
377 fclk_rate);
378
379 dss_runtime_put();
380}
381
382static void dss_dump_regs(struct seq_file *s)
383{
384#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
385
386 if (dss_runtime_get())
387 return;
388
389 DUMPREG(DSS_REVISION);
390 DUMPREG(DSS_SYSCONFIG);
391 DUMPREG(DSS_SYSSTATUS);
392 DUMPREG(DSS_CONTROL);
393
394 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
395 OMAP_DISPLAY_TYPE_SDI) {
396 DUMPREG(DSS_SDI_CONTROL);
397 DUMPREG(DSS_PLL_CONTROL);
398 DUMPREG(DSS_SDI_STATUS);
399 }
400
401 dss_runtime_put();
402#undef DUMPREG
403}
404
405static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
406{
407 int b;
408 u8 start, end;
409
410 switch (clk_src) {
411 case OMAP_DSS_CLK_SRC_FCK:
412 b = 0;
413 break;
414 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
415 b = 1;
416 break;
417 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
418 b = 2;
419 break;
420 default:
421 BUG();
422 return;
423 }
424
425 dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
426
427 REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
428
429 dss.dispc_clk_source = clk_src;
430}
431
432void dss_select_dsi_clk_source(int dsi_module,
433 enum omap_dss_clk_source clk_src)
434{
435 int b, pos;
436
437 switch (clk_src) {
438 case OMAP_DSS_CLK_SRC_FCK:
439 b = 0;
440 break;
441 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
442 BUG_ON(dsi_module != 0);
443 b = 1;
444 break;
445 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
446 BUG_ON(dsi_module != 1);
447 b = 1;
448 break;
449 default:
450 BUG();
451 return;
452 }
453
454 pos = dsi_module == 0 ? 1 : 10;
455 REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */
456
457 dss.dsi_clk_source[dsi_module] = clk_src;
458}
459
460void dss_select_lcd_clk_source(enum omap_channel channel,
461 enum omap_dss_clk_source clk_src)
462{
463 int b, ix, pos;
464
465 if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
466 dss_select_dispc_clk_source(clk_src);
467 return;
468 }
469
470 switch (clk_src) {
471 case OMAP_DSS_CLK_SRC_FCK:
472 b = 0;
473 break;
474 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
475 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
476 b = 1;
477 break;
478 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
479 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
480 channel != OMAP_DSS_CHANNEL_LCD3);
481 b = 1;
482 break;
483 default:
484 BUG();
485 return;
486 }
487
488 pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
489 (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
490 REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
491
492 ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
493 (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
494 dss.lcd_clk_source[ix] = clk_src;
495}
496
497enum omap_dss_clk_source dss_get_dispc_clk_source(void)
498{
499 return dss.dispc_clk_source;
500}
501
502enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
503{
504 return dss.dsi_clk_source[dsi_module];
505}
506
507enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
508{
509 if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
510 int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
511 (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
512 return dss.lcd_clk_source[ix];
513 } else {
514 /* LCD_CLK source is the same as DISPC_FCLK source for
515 * OMAP2 and OMAP3 */
516 return dss.dispc_clk_source;
517 }
518}
519
520bool dss_div_calc(unsigned long pck, unsigned long fck_min,
521 dss_div_calc_func func, void *data)
522{
523 int fckd, fckd_start, fckd_stop;
524 unsigned long fck;
525 unsigned long fck_hw_max;
526 unsigned long fckd_hw_max;
527 unsigned long prate;
528 unsigned m;
529
530 fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
531
532 if (dss.parent_clk == NULL) {
533 unsigned pckd;
534
535 pckd = fck_hw_max / pck;
536
537 fck = pck * pckd;
538
539 fck = clk_round_rate(dss.dss_clk, fck);
540
541 return func(fck, data);
542 }
543
544 fckd_hw_max = dss.feat->fck_div_max;
545
546 m = dss.feat->dss_fck_multiplier;
547 prate = clk_get_rate(dss.parent_clk);
548
549 fck_min = fck_min ? fck_min : 1;
550
551 fckd_start = min(prate * m / fck_min, fckd_hw_max);
552 fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
553
554 for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
555 fck = DIV_ROUND_UP(prate, fckd) * m;
556
557 if (func(fck, data))
558 return true;
559 }
560
561 return false;
562}
563
564int dss_set_fck_rate(unsigned long rate)
565{
566 int r;
567
568 DSSDBG("set fck to %lu\n", rate);
569
570 r = clk_set_rate(dss.dss_clk, rate);
571 if (r)
572 return r;
573
574 dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
575
576 WARN_ONCE(dss.dss_clk_rate != rate,
577 "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
578 rate);
579
580 return 0;
581}
582
583unsigned long dss_get_dispc_clk_rate(void)
584{
585 return dss.dss_clk_rate;
586}
587
588static int dss_setup_default_clock(void)
589{
590 unsigned long max_dss_fck, prate;
591 unsigned long fck;
592 unsigned fck_div;
593 int r;
594
595 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
596
597 if (dss.parent_clk == NULL) {
598 fck = clk_round_rate(dss.dss_clk, max_dss_fck);
599 } else {
600 prate = clk_get_rate(dss.parent_clk);
601
602 fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
603 max_dss_fck);
604 fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
605 }
606
607 r = dss_set_fck_rate(fck);
608 if (r)
609 return r;
610
611 return 0;
612}
613
614void dss_set_venc_output(enum omap_dss_venc_type type)
615{
616 int l = 0;
617
618 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
619 l = 0;
620 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
621 l = 1;
622 else
623 BUG();
624
625 /* venc out selection. 0 = comp, 1 = svideo */
626 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
627}
628
629void dss_set_dac_pwrdn_bgz(bool enable)
630{
631 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
632}
633
634void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
635{
636 enum omap_display_type dp;
637 dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
638
639 /* Complain about invalid selections */
640 WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
641 WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
642
643 /* Select only if we have options */
644 if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
645 REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
646}
647
648enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
649{
650 enum omap_display_type displays;
651
652 displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
653 if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
654 return DSS_VENC_TV_CLK;
655
656 if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
657 return DSS_HDMI_M_PCLK;
658
659 return REG_GET(DSS_CONTROL, 15, 15);
660}
661
662static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
663{
664 if (channel != OMAP_DSS_CHANNEL_LCD)
665 return -EINVAL;
666
667 return 0;
668}
669
670static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
671{
672 int val;
673
674 switch (channel) {
675 case OMAP_DSS_CHANNEL_LCD2:
676 val = 0;
677 break;
678 case OMAP_DSS_CHANNEL_DIGIT:
679 val = 1;
680 break;
681 default:
682 return -EINVAL;
683 }
684
685 REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
686
687 return 0;
688}
689
690static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
691{
692 int val;
693
694 switch (channel) {
695 case OMAP_DSS_CHANNEL_LCD:
696 val = 1;
697 break;
698 case OMAP_DSS_CHANNEL_LCD2:
699 val = 2;
700 break;
701 case OMAP_DSS_CHANNEL_LCD3:
702 val = 3;
703 break;
704 case OMAP_DSS_CHANNEL_DIGIT:
705 val = 0;
706 break;
707 default:
708 return -EINVAL;
709 }
710
711 REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
712
713 return 0;
714}
715
716static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
717{
718 switch (port) {
719 case 0:
720 return dss_dpi_select_source_omap5(port, channel);
721 case 1:
722 if (channel != OMAP_DSS_CHANNEL_LCD2)
723 return -EINVAL;
724 break;
725 case 2:
726 if (channel != OMAP_DSS_CHANNEL_LCD3)
727 return -EINVAL;
728 break;
729 default:
730 return -EINVAL;
731 }
732
733 return 0;
734}
735
736int dss_dpi_select_source(int port, enum omap_channel channel)
737{
738 return dss.feat->dpi_select_source(port, channel);
739}
740
741static int dss_get_clocks(void)
742{
743 struct clk *clk;
744
745 clk = devm_clk_get(&dss.pdev->dev, "fck");
746 if (IS_ERR(clk)) {
747 DSSERR("can't get clock fck\n");
748 return PTR_ERR(clk);
749 }
750
751 dss.dss_clk = clk;
752
753 if (dss.feat->parent_clk_name) {
754 clk = clk_get(NULL, dss.feat->parent_clk_name);
755 if (IS_ERR(clk)) {
756 DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
757 return PTR_ERR(clk);
758 }
759 } else {
760 clk = NULL;
761 }
762
763 dss.parent_clk = clk;
764
765 return 0;
766}
767
768static void dss_put_clocks(void)
769{
770 if (dss.parent_clk)
771 clk_put(dss.parent_clk);
772}
773
774int dss_runtime_get(void)
775{
776 int r;
777
778 DSSDBG("dss_runtime_get\n");
779
780 r = pm_runtime_get_sync(&dss.pdev->dev);
781 WARN_ON(r < 0);
782 return r < 0 ? r : 0;
783}
784
785void dss_runtime_put(void)
786{
787 int r;
788
789 DSSDBG("dss_runtime_put\n");
790
791 r = pm_runtime_put_sync(&dss.pdev->dev);
792 WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
793}
794
795/* DEBUGFS */
796#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
797void dss_debug_dump_clocks(struct seq_file *s)
798{
799 dss_dump_clocks(s);
800 dispc_dump_clocks(s);
801#ifdef CONFIG_OMAP2_DSS_DSI
802 dsi_dump_clocks(s);
803#endif
804}
805#endif
806
807
808static const enum omap_display_type omap2plus_ports[] = {
809 OMAP_DISPLAY_TYPE_DPI,
810};
811
812static const enum omap_display_type omap34xx_ports[] = {
813 OMAP_DISPLAY_TYPE_DPI,
814 OMAP_DISPLAY_TYPE_SDI,
815};
816
817static const enum omap_display_type dra7xx_ports[] = {
818 OMAP_DISPLAY_TYPE_DPI,
819 OMAP_DISPLAY_TYPE_DPI,
820 OMAP_DISPLAY_TYPE_DPI,
821};
822
823static const struct dss_features omap24xx_dss_feats = {
824 /*
825 * fck div max is really 16, but the divider range has gaps. The range
826 * from 1 to 6 has no gaps, so let's use that as a max.
827 */
828 .fck_div_max = 6,
829 .dss_fck_multiplier = 2,
830 .parent_clk_name = "core_ck",
831 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
832 .ports = omap2plus_ports,
833 .num_ports = ARRAY_SIZE(omap2plus_ports),
834};
835
836static const struct dss_features omap34xx_dss_feats = {
837 .fck_div_max = 16,
838 .dss_fck_multiplier = 2,
839 .parent_clk_name = "dpll4_ck",
840 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
841 .ports = omap34xx_ports,
842 .num_ports = ARRAY_SIZE(omap34xx_ports),
843};
844
845static const struct dss_features omap3630_dss_feats = {
846 .fck_div_max = 32,
847 .dss_fck_multiplier = 1,
848 .parent_clk_name = "dpll4_ck",
849 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
850 .ports = omap2plus_ports,
851 .num_ports = ARRAY_SIZE(omap2plus_ports),
852};
853
854static const struct dss_features omap44xx_dss_feats = {
855 .fck_div_max = 32,
856 .dss_fck_multiplier = 1,
857 .parent_clk_name = "dpll_per_x2_ck",
858 .dpi_select_source = &dss_dpi_select_source_omap4,
859 .ports = omap2plus_ports,
860 .num_ports = ARRAY_SIZE(omap2plus_ports),
861};
862
863static const struct dss_features omap54xx_dss_feats = {
864 .fck_div_max = 64,
865 .dss_fck_multiplier = 1,
866 .parent_clk_name = "dpll_per_x2_ck",
867 .dpi_select_source = &dss_dpi_select_source_omap5,
868 .ports = omap2plus_ports,
869 .num_ports = ARRAY_SIZE(omap2plus_ports),
870};
871
872static const struct dss_features am43xx_dss_feats = {
873 .fck_div_max = 0,
874 .dss_fck_multiplier = 0,
875 .parent_clk_name = NULL,
876 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
877 .ports = omap2plus_ports,
878 .num_ports = ARRAY_SIZE(omap2plus_ports),
879};
880
881static const struct dss_features dra7xx_dss_feats = {
882 .fck_div_max = 64,
883 .dss_fck_multiplier = 1,
884 .parent_clk_name = "dpll_per_x2_ck",
885 .dpi_select_source = &dss_dpi_select_source_dra7xx,
886 .ports = dra7xx_ports,
887 .num_ports = ARRAY_SIZE(dra7xx_ports),
888};
889
890static int dss_init_features(struct platform_device *pdev)
891{
892 const struct dss_features *src;
893 struct dss_features *dst;
894
895 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
896 if (!dst) {
897 dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
898 return -ENOMEM;
899 }
900
901 switch (omapdss_get_version()) {
902 case OMAPDSS_VER_OMAP24xx:
903 src = &omap24xx_dss_feats;
904 break;
905
906 case OMAPDSS_VER_OMAP34xx_ES1:
907 case OMAPDSS_VER_OMAP34xx_ES3:
908 case OMAPDSS_VER_AM35xx:
909 src = &omap34xx_dss_feats;
910 break;
911
912 case OMAPDSS_VER_OMAP3630:
913 src = &omap3630_dss_feats;
914 break;
915
916 case OMAPDSS_VER_OMAP4430_ES1:
917 case OMAPDSS_VER_OMAP4430_ES2:
918 case OMAPDSS_VER_OMAP4:
919 src = &omap44xx_dss_feats;
920 break;
921
922 case OMAPDSS_VER_OMAP5:
923 src = &omap54xx_dss_feats;
924 break;
925
926 case OMAPDSS_VER_AM43xx:
927 src = &am43xx_dss_feats;
928 break;
929
930 case OMAPDSS_VER_DRA7xx:
931 src = &dra7xx_dss_feats;
932 break;
933
934 default:
935 return -ENODEV;
936 }
937
938 memcpy(dst, src, sizeof(*dst));
939 dss.feat = dst;
940
941 return 0;
942}
943
944static int dss_init_ports(struct platform_device *pdev)
945{
946 struct device_node *parent = pdev->dev.of_node;
947 struct device_node *port;
948 int r;
949
950 if (parent == NULL)
951 return 0;
952
953 port = omapdss_of_get_next_port(parent, NULL);
954 if (!port)
955 return 0;
956
957 if (dss.feat->num_ports == 0)
958 return 0;
959
960 do {
961 enum omap_display_type port_type;
962 u32 reg;
963
964 r = of_property_read_u32(port, "reg", &reg);
965 if (r)
966 reg = 0;
967
968 if (reg >= dss.feat->num_ports)
969 continue;
970
971 port_type = dss.feat->ports[reg];
972
973 switch (port_type) {
974 case OMAP_DISPLAY_TYPE_DPI:
975 dpi_init_port(pdev, port);
976 break;
977 case OMAP_DISPLAY_TYPE_SDI:
978 sdi_init_port(pdev, port);
979 break;
980 default:
981 break;
982 }
983 } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
984
985 return 0;
986}
987
988static void dss_uninit_ports(struct platform_device *pdev)
989{
990 struct device_node *parent = pdev->dev.of_node;
991 struct device_node *port;
992
993 if (parent == NULL)
994 return;
995
996 port = omapdss_of_get_next_port(parent, NULL);
997 if (!port)
998 return;
999
1000 if (dss.feat->num_ports == 0)
1001 return;
1002
1003 do {
1004 enum omap_display_type port_type;
1005 u32 reg;
1006 int r;
1007
1008 r = of_property_read_u32(port, "reg", &reg);
1009 if (r)
1010 reg = 0;
1011
1012 if (reg >= dss.feat->num_ports)
1013 continue;
1014
1015 port_type = dss.feat->ports[reg];
1016
1017 switch (port_type) {
1018 case OMAP_DISPLAY_TYPE_DPI:
1019 dpi_uninit_port(port);
1020 break;
1021 case OMAP_DISPLAY_TYPE_SDI:
1022 sdi_uninit_port(port);
1023 break;
1024 default:
1025 break;
1026 }
1027 } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
1028}
1029
1030static int dss_video_pll_probe(struct platform_device *pdev)
1031{
1032 struct device_node *np = pdev->dev.of_node;
1033 struct regulator *pll_regulator;
1034 int r;
1035
1036 if (!np)
1037 return 0;
1038
1039 if (of_property_read_bool(np, "syscon-pll-ctrl")) {
1040 dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
1041 "syscon-pll-ctrl");
1042 if (IS_ERR(dss.syscon_pll_ctrl)) {
1043 dev_err(&pdev->dev,
1044 "failed to get syscon-pll-ctrl regmap\n");
1045 return PTR_ERR(dss.syscon_pll_ctrl);
1046 }
1047
1048 if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
1049 &dss.syscon_pll_ctrl_offset)) {
1050 dev_err(&pdev->dev,
1051 "failed to get syscon-pll-ctrl offset\n");
1052 return -EINVAL;
1053 }
1054 }
1055
1056 pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
1057 if (IS_ERR(pll_regulator)) {
1058 r = PTR_ERR(pll_regulator);
1059
1060 switch (r) {
1061 case -ENOENT:
1062 pll_regulator = NULL;
1063 break;
1064
1065 case -EPROBE_DEFER:
1066 return -EPROBE_DEFER;
1067
1068 default:
1069 DSSERR("can't get DPLL VDDA regulator\n");
1070 return r;
1071 }
1072 }
1073
1074 if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
1075 dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
1076 if (IS_ERR(dss.video1_pll))
1077 return PTR_ERR(dss.video1_pll);
1078 }
1079
1080 if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
1081 dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
1082 if (IS_ERR(dss.video2_pll)) {
1083 dss_video_pll_uninit(dss.video1_pll);
1084 return PTR_ERR(dss.video2_pll);
1085 }
1086 }
1087
1088 return 0;
1089}
1090
1091/* DSS HW IP initialisation */
1092static int dss_bind(struct device *dev)
1093{
1094 struct platform_device *pdev = to_platform_device(dev);
1095 struct resource *dss_mem;
1096 u32 rev;
1097 int r;
1098
1099 dss.pdev = pdev;
1100
1101 r = dss_init_features(dss.pdev);
1102 if (r)
1103 return r;
1104
1105 dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
1106 if (!dss_mem) {
1107 DSSERR("can't get IORESOURCE_MEM DSS\n");
1108 return -EINVAL;
1109 }
1110
1111 dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
1112 resource_size(dss_mem));
1113 if (!dss.base) {
1114 DSSERR("can't ioremap DSS\n");
1115 return -ENOMEM;
1116 }
1117
1118 r = dss_get_clocks();
1119 if (r)
1120 return r;
1121
1122 r = dss_setup_default_clock();
1123 if (r)
1124 goto err_setup_clocks;
1125
1126 r = dss_video_pll_probe(pdev);
1127 if (r)
1128 goto err_pll_init;
1129
1130 r = dss_init_ports(pdev);
1131 if (r)
1132 goto err_init_ports;
1133
1134 pm_runtime_enable(&pdev->dev);
1135
1136 r = dss_runtime_get();
1137 if (r)
1138 goto err_runtime_get;
1139
1140 dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
1141
1142 /* Select DPLL */
1143 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
1144
1145 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
1146
1147#ifdef CONFIG_OMAP2_DSS_VENC
1148 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
1149 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
1150 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
1151#endif
1152 dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
1153 dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
1154 dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
1155 dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
1156 dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
1157
1158 rev = dss_read_reg(DSS_REVISION);
1159 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
1160 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
1161
1162 dss_runtime_put();
1163
1164 r = component_bind_all(&pdev->dev, NULL);
1165 if (r)
1166 goto err_component;
1167
1168 dss_debugfs_create_file("dss", dss_dump_regs);
1169
1170 pm_set_vt_switch(0);
1171
1172 dss_initialized = true;
1173
1174 return 0;
1175
1176err_component:
1177err_runtime_get:
1178 pm_runtime_disable(&pdev->dev);
1179 dss_uninit_ports(pdev);
1180err_init_ports:
1181 if (dss.video1_pll)
1182 dss_video_pll_uninit(dss.video1_pll);
1183
1184 if (dss.video2_pll)
1185 dss_video_pll_uninit(dss.video2_pll);
1186err_pll_init:
1187err_setup_clocks:
1188 dss_put_clocks();
1189 return r;
1190}
1191
1192static void dss_unbind(struct device *dev)
1193{
1194 struct platform_device *pdev = to_platform_device(dev);
1195
1196 dss_initialized = false;
1197
1198 component_unbind_all(&pdev->dev, NULL);
1199
1200 if (dss.video1_pll)
1201 dss_video_pll_uninit(dss.video1_pll);
1202
1203 if (dss.video2_pll)
1204 dss_video_pll_uninit(dss.video2_pll);
1205
1206 dss_uninit_ports(pdev);
1207
1208 pm_runtime_disable(&pdev->dev);
1209
1210 dss_put_clocks();
1211}
1212
1213static const struct component_master_ops dss_component_ops = {
1214 .bind = dss_bind,
1215 .unbind = dss_unbind,
1216};
1217
1218static int dss_component_compare(struct device *dev, void *data)
1219{
1220 struct device *child = data;
1221 return dev == child;
1222}
1223
1224static int dss_add_child_component(struct device *dev, void *data)
1225{
1226 struct component_match **match = data;
1227
1228 /*
1229 * HACK
1230 * We don't have a working driver for rfbi, so skip it here always.
1231 * Otherwise dss will never get probed successfully, as it will wait
1232 * for rfbi to get probed.
1233 */
1234 if (strstr(dev_name(dev), "rfbi"))
1235 return 0;
1236
1237 component_match_add(dev->parent, match, dss_component_compare, dev);
1238
1239 return 0;
1240}
1241
1242static int dss_probe(struct platform_device *pdev)
1243{
1244 struct component_match *match = NULL;
1245 int r;
1246
1247 /* add all the child devices as components */
1248 device_for_each_child(&pdev->dev, &match, dss_add_child_component);
1249
1250 r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
1251 if (r)
1252 return r;
1253
1254 return 0;
1255}
1256
1257static int dss_remove(struct platform_device *pdev)
1258{
1259 component_master_del(&pdev->dev, &dss_component_ops);
1260 return 0;
1261}
1262
1263static int dss_runtime_suspend(struct device *dev)
1264{
1265 dss_save_context();
1266 dss_set_min_bus_tput(dev, 0);
1267
1268 pinctrl_pm_select_sleep_state(dev);
1269
1270 return 0;
1271}
1272
1273static int dss_runtime_resume(struct device *dev)
1274{
1275 int r;
1276
1277 pinctrl_pm_select_default_state(dev);
1278
1279 /*
1280 * Set an arbitrarily high tput request to ensure OPP100.
1281 * What we should really do is to make a request to stay in OPP100,
1282 * without any tput requirements, but that is not currently possible
1283 * via the PM layer.
1284 */
1285
1286 r = dss_set_min_bus_tput(dev, 1000000000);
1287 if (r)
1288 return r;
1289
1290 dss_restore_context();
1291 return 0;
1292}
1293
1294static const struct dev_pm_ops dss_pm_ops = {
1295 .runtime_suspend = dss_runtime_suspend,
1296 .runtime_resume = dss_runtime_resume,
1297};
1298
1299static const struct of_device_id dss_of_match[] = {
1300 { .compatible = "ti,omap2-dss", },
1301 { .compatible = "ti,omap3-dss", },
1302 { .compatible = "ti,omap4-dss", },
1303 { .compatible = "ti,omap5-dss", },
1304 { .compatible = "ti,dra7-dss", },
1305 {},
1306};
1307
1308MODULE_DEVICE_TABLE(of, dss_of_match);
1309
1310static struct platform_driver omap_dsshw_driver = {
1311 .probe = dss_probe,
1312 .remove = dss_remove,
1313 .driver = {
1314 .name = "omapdss_dss",
1315 .pm = &dss_pm_ops,
1316 .of_match_table = dss_of_match,
1317 .suppress_bind_attrs = true,
1318 },
1319};
1320
1321int __init dss_init_platform_driver(void)
1322{
1323 return platform_driver_register(&omap_dsshw_driver);
1324}
1325
1326void dss_uninit_platform_driver(void)
1327{
1328 platform_driver_unregister(&omap_dsshw_driver);
1329}
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h
new file mode 100644
index 000000000000..9a6453235585
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss.h
@@ -0,0 +1,468 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.h
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef __OMAP2_DSS_H
24#define __OMAP2_DSS_H
25
26#include <linux/interrupt.h>
27
28#ifdef pr_fmt
29#undef pr_fmt
30#endif
31
32#ifdef DSS_SUBSYS_NAME
33#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt
34#else
35#define pr_fmt(fmt) fmt
36#endif
37
38#define DSSDBG(format, ...) \
39 pr_debug(format, ## __VA_ARGS__)
40
41#ifdef DSS_SUBSYS_NAME
42#define DSSERR(format, ...) \
43 printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
44 ## __VA_ARGS__)
45#else
46#define DSSERR(format, ...) \
47 printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
48#endif
49
50#ifdef DSS_SUBSYS_NAME
51#define DSSINFO(format, ...) \
52 printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
53 ## __VA_ARGS__)
54#else
55#define DSSINFO(format, ...) \
56 printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
57#endif
58
59#ifdef DSS_SUBSYS_NAME
60#define DSSWARN(format, ...) \
61 printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
62 ## __VA_ARGS__)
63#else
64#define DSSWARN(format, ...) \
65 printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
66#endif
67
68/* OMAP TRM gives bitfields as start:end, where start is the higher bit
69 number. For example 7:0 */
70#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
71#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
72#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
73#define FLD_MOD(orig, val, start, end) \
74 (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
75
76enum dss_io_pad_mode {
77 DSS_IO_PAD_MODE_RESET,
78 DSS_IO_PAD_MODE_RFBI,
79 DSS_IO_PAD_MODE_BYPASS,
80};
81
82enum dss_hdmi_venc_clk_source_select {
83 DSS_VENC_TV_CLK = 0,
84 DSS_HDMI_M_PCLK = 1,
85};
86
87enum dss_dsi_content_type {
88 DSS_DSI_CONTENT_DCS,
89 DSS_DSI_CONTENT_GENERIC,
90};
91
92enum dss_writeback_channel {
93 DSS_WB_LCD1_MGR = 0,
94 DSS_WB_LCD2_MGR = 1,
95 DSS_WB_TV_MGR = 2,
96 DSS_WB_OVL0 = 3,
97 DSS_WB_OVL1 = 4,
98 DSS_WB_OVL2 = 5,
99 DSS_WB_OVL3 = 6,
100 DSS_WB_LCD3_MGR = 7,
101};
102
103enum dss_pll_id {
104 DSS_PLL_DSI1,
105 DSS_PLL_DSI2,
106 DSS_PLL_HDMI,
107 DSS_PLL_VIDEO1,
108 DSS_PLL_VIDEO2,
109};
110
111struct dss_pll;
112
113#define DSS_PLL_MAX_HSDIVS 4
114
115/*
116 * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
117 * Type-B PLLs: clkout[0] refers to m2.
118 */
119struct dss_pll_clock_info {
120 /* rates that we get with dividers below */
121 unsigned long fint;
122 unsigned long clkdco;
123 unsigned long clkout[DSS_PLL_MAX_HSDIVS];
124
125 /* dividers */
126 u16 n;
127 u16 m;
128 u32 mf;
129 u16 mX[DSS_PLL_MAX_HSDIVS];
130 u16 sd;
131};
132
133struct dss_pll_ops {
134 int (*enable)(struct dss_pll *pll);
135 void (*disable)(struct dss_pll *pll);
136 int (*set_config)(struct dss_pll *pll,
137 const struct dss_pll_clock_info *cinfo);
138};
139
140struct dss_pll_hw {
141 unsigned n_max;
142 unsigned m_min;
143 unsigned m_max;
144 unsigned mX_max;
145
146 unsigned long fint_min, fint_max;
147 unsigned long clkdco_min, clkdco_low, clkdco_max;
148
149 u8 n_msb, n_lsb;
150 u8 m_msb, m_lsb;
151 u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
152
153 bool has_stopmode;
154 bool has_freqsel;
155 bool has_selfreqdco;
156 bool has_refsel;
157};
158
159struct dss_pll {
160 const char *name;
161 enum dss_pll_id id;
162
163 struct clk *clkin;
164 struct regulator *regulator;
165
166 void __iomem *base;
167
168 const struct dss_pll_hw *hw;
169
170 const struct dss_pll_ops *ops;
171
172 struct dss_pll_clock_info cinfo;
173};
174
175struct dispc_clock_info {
176 /* rates that we get with dividers below */
177 unsigned long lck;
178 unsigned long pck;
179
180 /* dividers */
181 u16 lck_div;
182 u16 pck_div;
183};
184
185struct dss_lcd_mgr_config {
186 enum dss_io_pad_mode io_pad_mode;
187
188 bool stallmode;
189 bool fifohandcheck;
190
191 struct dispc_clock_info clock_info;
192
193 int video_port_width;
194
195 int lcden_sig_polarity;
196};
197
198struct seq_file;
199struct platform_device;
200
201/* core */
202struct platform_device *dss_get_core_pdev(void);
203int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
204void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
205int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
206int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
207
208/* display */
209int dss_suspend_all_devices(void);
210int dss_resume_all_devices(void);
211void dss_disable_all_devices(void);
212
213int display_init_sysfs(struct platform_device *pdev);
214void display_uninit_sysfs(struct platform_device *pdev);
215
216/* manager */
217int dss_init_overlay_managers(void);
218void dss_uninit_overlay_managers(void);
219int dss_init_overlay_managers_sysfs(struct platform_device *pdev);
220void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev);
221int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
222 const struct omap_overlay_manager_info *info);
223int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
224 const struct omap_video_timings *timings);
225int dss_mgr_check(struct omap_overlay_manager *mgr,
226 struct omap_overlay_manager_info *info,
227 const struct omap_video_timings *mgr_timings,
228 const struct dss_lcd_mgr_config *config,
229 struct omap_overlay_info **overlay_infos);
230
231static inline bool dss_mgr_is_lcd(enum omap_channel id)
232{
233 if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 ||
234 id == OMAP_DSS_CHANNEL_LCD3)
235 return true;
236 else
237 return false;
238}
239
240int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
241 struct platform_device *pdev);
242void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
243
244/* overlay */
245void dss_init_overlays(struct platform_device *pdev);
246void dss_uninit_overlays(struct platform_device *pdev);
247void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
248int dss_ovl_simple_check(struct omap_overlay *ovl,
249 const struct omap_overlay_info *info);
250int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
251 const struct omap_video_timings *mgr_timings);
252bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
253 enum omap_color_mode mode);
254int dss_overlay_kobj_init(struct omap_overlay *ovl,
255 struct platform_device *pdev);
256void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
257
258/* DSS */
259int dss_init_platform_driver(void) __init;
260void dss_uninit_platform_driver(void);
261
262int dss_runtime_get(void);
263void dss_runtime_put(void);
264
265unsigned long dss_get_dispc_clk_rate(void);
266int dss_dpi_select_source(int port, enum omap_channel channel);
267void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
268enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
269const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
270void dss_dump_clocks(struct seq_file *s);
271
272/* DSS VIDEO PLL */
273struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
274 struct regulator *regulator);
275void dss_video_pll_uninit(struct dss_pll *pll);
276
277/* dss-of */
278struct device_node *dss_of_port_get_parent_device(struct device_node *port);
279u32 dss_of_port_get_port_number(struct device_node *port);
280
281#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
282void dss_debug_dump_clocks(struct seq_file *s);
283#endif
284
285void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
286void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
287 enum omap_channel channel);
288
289void dss_sdi_init(int datapairs);
290int dss_sdi_enable(void);
291void dss_sdi_disable(void);
292
293void dss_select_dsi_clk_source(int dsi_module,
294 enum omap_dss_clk_source clk_src);
295void dss_select_lcd_clk_source(enum omap_channel channel,
296 enum omap_dss_clk_source clk_src);
297enum omap_dss_clk_source dss_get_dispc_clk_source(void);
298enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
299enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
300
301void dss_set_venc_output(enum omap_dss_venc_type type);
302void dss_set_dac_pwrdn_bgz(bool enable);
303
304int dss_set_fck_rate(unsigned long rate);
305
306typedef bool (*dss_div_calc_func)(unsigned long fck, void *data);
307bool dss_div_calc(unsigned long pck, unsigned long fck_min,
308 dss_div_calc_func func, void *data);
309
310/* SDI */
311int sdi_init_platform_driver(void) __init;
312void sdi_uninit_platform_driver(void);
313
314#ifdef CONFIG_OMAP2_DSS_SDI
315int sdi_init_port(struct platform_device *pdev, struct device_node *port);
316void sdi_uninit_port(struct device_node *port);
317#else
318static inline int sdi_init_port(struct platform_device *pdev,
319 struct device_node *port)
320{
321 return 0;
322}
323static inline void sdi_uninit_port(struct device_node *port)
324{
325}
326#endif
327
328/* DSI */
329
330#ifdef CONFIG_OMAP2_DSS_DSI
331
332struct dentry;
333struct file_operations;
334
335int dsi_init_platform_driver(void) __init;
336void dsi_uninit_platform_driver(void);
337
338void dsi_dump_clocks(struct seq_file *s);
339
340void dsi_irq_handler(void);
341u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
342
343#else
344static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
345{
346 WARN(1, "%s: DSI not compiled in, returning pixel_size as 0\n",
347 __func__);
348 return 0;
349}
350#endif
351
352/* DPI */
353int dpi_init_platform_driver(void) __init;
354void dpi_uninit_platform_driver(void);
355
356#ifdef CONFIG_OMAP2_DSS_DPI
357int dpi_init_port(struct platform_device *pdev, struct device_node *port);
358void dpi_uninit_port(struct device_node *port);
359#else
360static inline int dpi_init_port(struct platform_device *pdev,
361 struct device_node *port)
362{
363 return 0;
364}
365static inline void dpi_uninit_port(struct device_node *port)
366{
367}
368#endif
369
370/* DISPC */
371int dispc_init_platform_driver(void) __init;
372void dispc_uninit_platform_driver(void);
373void dispc_dump_clocks(struct seq_file *s);
374
375void dispc_enable_sidle(void);
376void dispc_disable_sidle(void);
377
378void dispc_lcd_enable_signal(bool enable);
379void dispc_pck_free_enable(bool enable);
380void dispc_enable_fifomerge(bool enable);
381void dispc_enable_gamma_table(bool enable);
382
383typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
384 unsigned long pck, void *data);
385bool dispc_div_calc(unsigned long dispc,
386 unsigned long pck_min, unsigned long pck_max,
387 dispc_div_calc_func func, void *data);
388
389bool dispc_mgr_timings_ok(enum omap_channel channel,
390 const struct omap_video_timings *timings);
391int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
392 struct dispc_clock_info *cinfo);
393
394
395void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
396void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
397 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
398 bool manual_update);
399
400void dispc_mgr_set_clock_div(enum omap_channel channel,
401 const struct dispc_clock_info *cinfo);
402int dispc_mgr_get_clock_div(enum omap_channel channel,
403 struct dispc_clock_info *cinfo);
404void dispc_set_tv_pclk(unsigned long pclk);
405
406u32 dispc_wb_get_framedone_irq(void);
407bool dispc_wb_go_busy(void);
408void dispc_wb_go(void);
409void dispc_wb_enable(bool enable);
410bool dispc_wb_is_enabled(void);
411void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
412int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
413 bool mem_to_mem, const struct omap_video_timings *timings);
414
415/* VENC */
416int venc_init_platform_driver(void) __init;
417void venc_uninit_platform_driver(void);
418
419/* HDMI */
420int hdmi4_init_platform_driver(void) __init;
421void hdmi4_uninit_platform_driver(void);
422
423int hdmi5_init_platform_driver(void) __init;
424void hdmi5_uninit_platform_driver(void);
425
426/* RFBI */
427int rfbi_init_platform_driver(void) __init;
428void rfbi_uninit_platform_driver(void);
429
430
431#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
432static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
433{
434 int b;
435 for (b = 0; b < 32; ++b) {
436 if (irqstatus & (1 << b))
437 irq_arr[b]++;
438 }
439}
440#endif
441
442/* PLL */
443typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
444 unsigned long clkdco, void *data);
445typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
446 void *data);
447
448int dss_pll_register(struct dss_pll *pll);
449void dss_pll_unregister(struct dss_pll *pll);
450struct dss_pll *dss_pll_find(const char *name);
451int dss_pll_enable(struct dss_pll *pll);
452void dss_pll_disable(struct dss_pll *pll);
453int dss_pll_set_config(struct dss_pll *pll,
454 const struct dss_pll_clock_info *cinfo);
455
456bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
457 unsigned long out_min, unsigned long out_max,
458 dss_hsdiv_calc_func func, void *data);
459bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
460 unsigned long pll_min, unsigned long pll_max,
461 dss_pll_calc_func func, void *data);
462int dss_pll_write_config_type_a(struct dss_pll *pll,
463 const struct dss_pll_clock_info *cinfo);
464int dss_pll_write_config_type_b(struct dss_pll *pll,
465 const struct dss_pll_clock_info *cinfo);
466int dss_pll_wait_reset_done(struct dss_pll *pll);
467
468#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/dss_features.c b/drivers/gpu/drm/omapdrm/dss/dss_features.c
new file mode 100644
index 000000000000..c886a2927f73
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss_features.c
@@ -0,0 +1,951 @@
1/*
2 * linux/drivers/video/omap2/dss/dss_features.c
3 *
4 * Copyright (C) 2010 Texas Instruments
5 * Author: Archit Taneja <archit@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 <linux/module.h>
22#include <linux/types.h>
23#include <linux/err.h>
24#include <linux/slab.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30
31/* Defines a generic omap register field */
32struct dss_reg_field {
33 u8 start, end;
34};
35
36struct dss_param_range {
37 int min, max;
38};
39
40struct omap_dss_features {
41 const struct dss_reg_field *reg_fields;
42 const int num_reg_fields;
43
44 const enum dss_feat_id *features;
45 const int num_features;
46
47 const int num_mgrs;
48 const int num_ovls;
49 const enum omap_display_type *supported_displays;
50 const enum omap_dss_output_id *supported_outputs;
51 const enum omap_color_mode *supported_color_modes;
52 const enum omap_overlay_caps *overlay_caps;
53 const char * const *clksrc_names;
54 const struct dss_param_range *dss_params;
55
56 const enum omap_dss_rotation_type supported_rotation_types;
57
58 const u32 buffer_size_unit;
59 const u32 burst_size_unit;
60};
61
62/* This struct is assigned to one of the below during initialization */
63static const struct omap_dss_features *omap_current_dss_features;
64
65static const struct dss_reg_field omap2_dss_reg_fields[] = {
66 [FEAT_REG_FIRHINC] = { 11, 0 },
67 [FEAT_REG_FIRVINC] = { 27, 16 },
68 [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
69 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
70 [FEAT_REG_FIFOSIZE] = { 8, 0 },
71 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
72 [FEAT_REG_VERTICALACCU] = { 25, 16 },
73 [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
74};
75
76static const struct dss_reg_field omap3_dss_reg_fields[] = {
77 [FEAT_REG_FIRHINC] = { 12, 0 },
78 [FEAT_REG_FIRVINC] = { 28, 16 },
79 [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
80 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
81 [FEAT_REG_FIFOSIZE] = { 10, 0 },
82 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
83 [FEAT_REG_VERTICALACCU] = { 25, 16 },
84 [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
85};
86
87static const struct dss_reg_field am43xx_dss_reg_fields[] = {
88 [FEAT_REG_FIRHINC] = { 12, 0 },
89 [FEAT_REG_FIRVINC] = { 28, 16 },
90 [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
91 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
92 [FEAT_REG_FIFOSIZE] = { 10, 0 },
93 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
94 [FEAT_REG_VERTICALACCU] = { 25, 16 },
95 [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
96};
97
98static const struct dss_reg_field omap4_dss_reg_fields[] = {
99 [FEAT_REG_FIRHINC] = { 12, 0 },
100 [FEAT_REG_FIRVINC] = { 28, 16 },
101 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
102 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
103 [FEAT_REG_FIFOSIZE] = { 15, 0 },
104 [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
105 [FEAT_REG_VERTICALACCU] = { 26, 16 },
106 [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
107};
108
109static const struct dss_reg_field omap5_dss_reg_fields[] = {
110 [FEAT_REG_FIRHINC] = { 12, 0 },
111 [FEAT_REG_FIRVINC] = { 28, 16 },
112 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
113 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
114 [FEAT_REG_FIFOSIZE] = { 15, 0 },
115 [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
116 [FEAT_REG_VERTICALACCU] = { 26, 16 },
117 [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
118};
119
120static const enum omap_display_type omap2_dss_supported_displays[] = {
121 /* OMAP_DSS_CHANNEL_LCD */
122 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
123
124 /* OMAP_DSS_CHANNEL_DIGIT */
125 OMAP_DISPLAY_TYPE_VENC,
126};
127
128static const enum omap_display_type omap3430_dss_supported_displays[] = {
129 /* OMAP_DSS_CHANNEL_LCD */
130 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
131 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
132
133 /* OMAP_DSS_CHANNEL_DIGIT */
134 OMAP_DISPLAY_TYPE_VENC,
135};
136
137static const enum omap_display_type omap3630_dss_supported_displays[] = {
138 /* OMAP_DSS_CHANNEL_LCD */
139 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
140 OMAP_DISPLAY_TYPE_DSI,
141
142 /* OMAP_DSS_CHANNEL_DIGIT */
143 OMAP_DISPLAY_TYPE_VENC,
144};
145
146static const enum omap_display_type am43xx_dss_supported_displays[] = {
147 /* OMAP_DSS_CHANNEL_LCD */
148 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
149};
150
151static const enum omap_display_type omap4_dss_supported_displays[] = {
152 /* OMAP_DSS_CHANNEL_LCD */
153 OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
154
155 /* OMAP_DSS_CHANNEL_DIGIT */
156 OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
157
158 /* OMAP_DSS_CHANNEL_LCD2 */
159 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
160 OMAP_DISPLAY_TYPE_DSI,
161};
162
163static const enum omap_display_type omap5_dss_supported_displays[] = {
164 /* OMAP_DSS_CHANNEL_LCD */
165 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
166 OMAP_DISPLAY_TYPE_DSI,
167
168 /* OMAP_DSS_CHANNEL_DIGIT */
169 OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
170
171 /* OMAP_DSS_CHANNEL_LCD2 */
172 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
173 OMAP_DISPLAY_TYPE_DSI,
174};
175
176static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
177 /* OMAP_DSS_CHANNEL_LCD */
178 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
179
180 /* OMAP_DSS_CHANNEL_DIGIT */
181 OMAP_DSS_OUTPUT_VENC,
182};
183
184static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
185 /* OMAP_DSS_CHANNEL_LCD */
186 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
187 OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
188
189 /* OMAP_DSS_CHANNEL_DIGIT */
190 OMAP_DSS_OUTPUT_VENC,
191};
192
193static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
194 /* OMAP_DSS_CHANNEL_LCD */
195 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
196 OMAP_DSS_OUTPUT_DSI1,
197
198 /* OMAP_DSS_CHANNEL_DIGIT */
199 OMAP_DSS_OUTPUT_VENC,
200};
201
202static const enum omap_dss_output_id am43xx_dss_supported_outputs[] = {
203 /* OMAP_DSS_CHANNEL_LCD */
204 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
205};
206
207static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
208 /* OMAP_DSS_CHANNEL_LCD */
209 OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
210
211 /* OMAP_DSS_CHANNEL_DIGIT */
212 OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
213
214 /* OMAP_DSS_CHANNEL_LCD2 */
215 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
216 OMAP_DSS_OUTPUT_DSI2,
217};
218
219static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
220 /* OMAP_DSS_CHANNEL_LCD */
221 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
222 OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
223
224 /* OMAP_DSS_CHANNEL_DIGIT */
225 OMAP_DSS_OUTPUT_HDMI,
226
227 /* OMAP_DSS_CHANNEL_LCD2 */
228 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
229 OMAP_DSS_OUTPUT_DSI1,
230
231 /* OMAP_DSS_CHANNEL_LCD3 */
232 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
233 OMAP_DSS_OUTPUT_DSI2,
234};
235
236static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
237 /* OMAP_DSS_GFX */
238 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
239 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
240 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
241 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
242
243 /* OMAP_DSS_VIDEO1 */
244 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
245 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
246 OMAP_DSS_COLOR_UYVY,
247
248 /* OMAP_DSS_VIDEO2 */
249 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
250 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
251 OMAP_DSS_COLOR_UYVY,
252};
253
254static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
255 /* OMAP_DSS_GFX */
256 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
257 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
258 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
259 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
260 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
261 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
262
263 /* OMAP_DSS_VIDEO1 */
264 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
265 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
266 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
267
268 /* OMAP_DSS_VIDEO2 */
269 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
270 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
271 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
272 OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
273 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
274};
275
276static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
277 /* OMAP_DSS_GFX */
278 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
279 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
280 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
281 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
282 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
283 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
284 OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 |
285 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555,
286
287 /* OMAP_DSS_VIDEO1 */
288 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
289 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
290 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
291 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
292 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
293 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
294 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
295 OMAP_DSS_COLOR_RGBX32,
296
297 /* OMAP_DSS_VIDEO2 */
298 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
299 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
300 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
301 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
302 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
303 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
304 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
305 OMAP_DSS_COLOR_RGBX32,
306
307 /* OMAP_DSS_VIDEO3 */
308 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
309 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
310 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
311 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
312 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
313 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
314 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
315 OMAP_DSS_COLOR_RGBX32,
316
317 /* OMAP_DSS_WB */
318 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
319 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
320 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
321 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
322 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
323 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
324 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
325 OMAP_DSS_COLOR_RGBX32,
326};
327
328static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
329 /* OMAP_DSS_GFX */
330 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
331
332 /* OMAP_DSS_VIDEO1 */
333 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
334 OMAP_DSS_OVL_CAP_REPLICATION,
335
336 /* OMAP_DSS_VIDEO2 */
337 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
338 OMAP_DSS_OVL_CAP_REPLICATION,
339};
340
341static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
342 /* OMAP_DSS_GFX */
343 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
344 OMAP_DSS_OVL_CAP_REPLICATION,
345
346 /* OMAP_DSS_VIDEO1 */
347 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
348 OMAP_DSS_OVL_CAP_REPLICATION,
349
350 /* OMAP_DSS_VIDEO2 */
351 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
352 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
353};
354
355static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
356 /* OMAP_DSS_GFX */
357 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
358 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
359
360 /* OMAP_DSS_VIDEO1 */
361 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
362 OMAP_DSS_OVL_CAP_REPLICATION,
363
364 /* OMAP_DSS_VIDEO2 */
365 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
366 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
367 OMAP_DSS_OVL_CAP_REPLICATION,
368};
369
370static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
371 /* OMAP_DSS_GFX */
372 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
373 OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
374 OMAP_DSS_OVL_CAP_REPLICATION,
375
376 /* OMAP_DSS_VIDEO1 */
377 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
378 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
379 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
380
381 /* OMAP_DSS_VIDEO2 */
382 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
383 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
384 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
385
386 /* OMAP_DSS_VIDEO3 */
387 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
388 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
389 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
390};
391
392static const char * const omap2_dss_clk_source_names[] = {
393 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
394 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
395 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK1",
396};
397
398static const char * const omap3_dss_clk_source_names[] = {
399 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
400 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
401 [OMAP_DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
402};
403
404static const char * const omap4_dss_clk_source_names[] = {
405 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
406 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
407 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK",
408 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
409 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
410};
411
412static const char * const omap5_dss_clk_source_names[] = {
413 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
414 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
415 [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
416 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
417 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
418};
419
420static const struct dss_param_range omap2_dss_param_range[] = {
421 [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
422 [FEAT_PARAM_DSS_PCD] = { 2, 255 },
423 [FEAT_PARAM_DOWNSCALE] = { 1, 2 },
424 /*
425 * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
426 * scaler cannot scale a image with width more than 768.
427 */
428 [FEAT_PARAM_LINEWIDTH] = { 1, 768 },
429};
430
431static const struct dss_param_range omap3_dss_param_range[] = {
432 [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
433 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
434 [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
435 [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
436 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
437 [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
438};
439
440static const struct dss_param_range am43xx_dss_param_range[] = {
441 [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
442 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
443 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
444 [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
445};
446
447static const struct dss_param_range omap4_dss_param_range[] = {
448 [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
449 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
450 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
451 [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
452 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
453 [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
454};
455
456static const struct dss_param_range omap5_dss_param_range[] = {
457 [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
458 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
459 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
460 [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
461 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
462 [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
463};
464
465static const enum dss_feat_id omap2_dss_feat_list[] = {
466 FEAT_LCDENABLEPOL,
467 FEAT_LCDENABLESIGNAL,
468 FEAT_PCKFREEENABLE,
469 FEAT_FUNCGATED,
470 FEAT_ROWREPEATENABLE,
471 FEAT_RESIZECONF,
472};
473
474static const enum dss_feat_id omap3430_dss_feat_list[] = {
475 FEAT_LCDENABLEPOL,
476 FEAT_LCDENABLESIGNAL,
477 FEAT_PCKFREEENABLE,
478 FEAT_FUNCGATED,
479 FEAT_LINEBUFFERSPLIT,
480 FEAT_ROWREPEATENABLE,
481 FEAT_RESIZECONF,
482 FEAT_DSI_REVERSE_TXCLKESC,
483 FEAT_VENC_REQUIRES_TV_DAC_CLK,
484 FEAT_CPR,
485 FEAT_PRELOAD,
486 FEAT_FIR_COEF_V,
487 FEAT_ALPHA_FIXED_ZORDER,
488 FEAT_FIFO_MERGE,
489 FEAT_OMAP3_DSI_FIFO_BUG,
490 FEAT_DPI_USES_VDDS_DSI,
491};
492
493static const enum dss_feat_id am35xx_dss_feat_list[] = {
494 FEAT_LCDENABLEPOL,
495 FEAT_LCDENABLESIGNAL,
496 FEAT_PCKFREEENABLE,
497 FEAT_FUNCGATED,
498 FEAT_LINEBUFFERSPLIT,
499 FEAT_ROWREPEATENABLE,
500 FEAT_RESIZECONF,
501 FEAT_DSI_REVERSE_TXCLKESC,
502 FEAT_VENC_REQUIRES_TV_DAC_CLK,
503 FEAT_CPR,
504 FEAT_PRELOAD,
505 FEAT_FIR_COEF_V,
506 FEAT_ALPHA_FIXED_ZORDER,
507 FEAT_FIFO_MERGE,
508 FEAT_OMAP3_DSI_FIFO_BUG,
509};
510
511static const enum dss_feat_id am43xx_dss_feat_list[] = {
512 FEAT_LCDENABLEPOL,
513 FEAT_LCDENABLESIGNAL,
514 FEAT_PCKFREEENABLE,
515 FEAT_FUNCGATED,
516 FEAT_LINEBUFFERSPLIT,
517 FEAT_ROWREPEATENABLE,
518 FEAT_RESIZECONF,
519 FEAT_CPR,
520 FEAT_PRELOAD,
521 FEAT_FIR_COEF_V,
522 FEAT_ALPHA_FIXED_ZORDER,
523 FEAT_FIFO_MERGE,
524};
525
526static const enum dss_feat_id omap3630_dss_feat_list[] = {
527 FEAT_LCDENABLEPOL,
528 FEAT_LCDENABLESIGNAL,
529 FEAT_PCKFREEENABLE,
530 FEAT_FUNCGATED,
531 FEAT_LINEBUFFERSPLIT,
532 FEAT_ROWREPEATENABLE,
533 FEAT_RESIZECONF,
534 FEAT_DSI_PLL_PWR_BUG,
535 FEAT_CPR,
536 FEAT_PRELOAD,
537 FEAT_FIR_COEF_V,
538 FEAT_ALPHA_FIXED_ZORDER,
539 FEAT_FIFO_MERGE,
540 FEAT_OMAP3_DSI_FIFO_BUG,
541 FEAT_DPI_USES_VDDS_DSI,
542};
543
544static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
545 FEAT_MGR_LCD2,
546 FEAT_CORE_CLK_DIV,
547 FEAT_LCD_CLK_SRC,
548 FEAT_DSI_DCS_CMD_CONFIG_VC,
549 FEAT_DSI_VC_OCP_WIDTH,
550 FEAT_DSI_GNQ,
551 FEAT_HANDLE_UV_SEPARATE,
552 FEAT_ATTR2,
553 FEAT_CPR,
554 FEAT_PRELOAD,
555 FEAT_FIR_COEF_V,
556 FEAT_ALPHA_FREE_ZORDER,
557 FEAT_FIFO_MERGE,
558 FEAT_BURST_2D,
559};
560
561static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
562 FEAT_MGR_LCD2,
563 FEAT_CORE_CLK_DIV,
564 FEAT_LCD_CLK_SRC,
565 FEAT_DSI_DCS_CMD_CONFIG_VC,
566 FEAT_DSI_VC_OCP_WIDTH,
567 FEAT_DSI_GNQ,
568 FEAT_HDMI_CTS_SWMODE,
569 FEAT_HANDLE_UV_SEPARATE,
570 FEAT_ATTR2,
571 FEAT_CPR,
572 FEAT_PRELOAD,
573 FEAT_FIR_COEF_V,
574 FEAT_ALPHA_FREE_ZORDER,
575 FEAT_FIFO_MERGE,
576 FEAT_BURST_2D,
577};
578
579static const enum dss_feat_id omap4_dss_feat_list[] = {
580 FEAT_MGR_LCD2,
581 FEAT_CORE_CLK_DIV,
582 FEAT_LCD_CLK_SRC,
583 FEAT_DSI_DCS_CMD_CONFIG_VC,
584 FEAT_DSI_VC_OCP_WIDTH,
585 FEAT_DSI_GNQ,
586 FEAT_HDMI_CTS_SWMODE,
587 FEAT_HDMI_AUDIO_USE_MCLK,
588 FEAT_HANDLE_UV_SEPARATE,
589 FEAT_ATTR2,
590 FEAT_CPR,
591 FEAT_PRELOAD,
592 FEAT_FIR_COEF_V,
593 FEAT_ALPHA_FREE_ZORDER,
594 FEAT_FIFO_MERGE,
595 FEAT_BURST_2D,
596};
597
598static const enum dss_feat_id omap5_dss_feat_list[] = {
599 FEAT_MGR_LCD2,
600 FEAT_MGR_LCD3,
601 FEAT_CORE_CLK_DIV,
602 FEAT_LCD_CLK_SRC,
603 FEAT_DSI_DCS_CMD_CONFIG_VC,
604 FEAT_DSI_VC_OCP_WIDTH,
605 FEAT_DSI_GNQ,
606 FEAT_HDMI_CTS_SWMODE,
607 FEAT_HDMI_AUDIO_USE_MCLK,
608 FEAT_HANDLE_UV_SEPARATE,
609 FEAT_ATTR2,
610 FEAT_CPR,
611 FEAT_PRELOAD,
612 FEAT_FIR_COEF_V,
613 FEAT_ALPHA_FREE_ZORDER,
614 FEAT_FIFO_MERGE,
615 FEAT_BURST_2D,
616 FEAT_DSI_PHY_DCC,
617 FEAT_MFLAG,
618};
619
620/* OMAP2 DSS Features */
621static const struct omap_dss_features omap2_dss_features = {
622 .reg_fields = omap2_dss_reg_fields,
623 .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
624
625 .features = omap2_dss_feat_list,
626 .num_features = ARRAY_SIZE(omap2_dss_feat_list),
627
628 .num_mgrs = 2,
629 .num_ovls = 3,
630 .supported_displays = omap2_dss_supported_displays,
631 .supported_outputs = omap2_dss_supported_outputs,
632 .supported_color_modes = omap2_dss_supported_color_modes,
633 .overlay_caps = omap2_dss_overlay_caps,
634 .clksrc_names = omap2_dss_clk_source_names,
635 .dss_params = omap2_dss_param_range,
636 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
637 .buffer_size_unit = 1,
638 .burst_size_unit = 8,
639};
640
641/* OMAP3 DSS Features */
642static const struct omap_dss_features omap3430_dss_features = {
643 .reg_fields = omap3_dss_reg_fields,
644 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
645
646 .features = omap3430_dss_feat_list,
647 .num_features = ARRAY_SIZE(omap3430_dss_feat_list),
648
649 .num_mgrs = 2,
650 .num_ovls = 3,
651 .supported_displays = omap3430_dss_supported_displays,
652 .supported_outputs = omap3430_dss_supported_outputs,
653 .supported_color_modes = omap3_dss_supported_color_modes,
654 .overlay_caps = omap3430_dss_overlay_caps,
655 .clksrc_names = omap3_dss_clk_source_names,
656 .dss_params = omap3_dss_param_range,
657 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
658 .buffer_size_unit = 1,
659 .burst_size_unit = 8,
660};
661
662/*
663 * AM35xx DSS Features. This is basically OMAP3 DSS Features without the
664 * vdds_dsi regulator.
665 */
666static const struct omap_dss_features am35xx_dss_features = {
667 .reg_fields = omap3_dss_reg_fields,
668 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
669
670 .features = am35xx_dss_feat_list,
671 .num_features = ARRAY_SIZE(am35xx_dss_feat_list),
672
673 .num_mgrs = 2,
674 .num_ovls = 3,
675 .supported_displays = omap3430_dss_supported_displays,
676 .supported_outputs = omap3430_dss_supported_outputs,
677 .supported_color_modes = omap3_dss_supported_color_modes,
678 .overlay_caps = omap3430_dss_overlay_caps,
679 .clksrc_names = omap3_dss_clk_source_names,
680 .dss_params = omap3_dss_param_range,
681 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
682 .buffer_size_unit = 1,
683 .burst_size_unit = 8,
684};
685
686static const struct omap_dss_features am43xx_dss_features = {
687 .reg_fields = am43xx_dss_reg_fields,
688 .num_reg_fields = ARRAY_SIZE(am43xx_dss_reg_fields),
689
690 .features = am43xx_dss_feat_list,
691 .num_features = ARRAY_SIZE(am43xx_dss_feat_list),
692
693 .num_mgrs = 1,
694 .num_ovls = 3,
695 .supported_displays = am43xx_dss_supported_displays,
696 .supported_outputs = am43xx_dss_supported_outputs,
697 .supported_color_modes = omap3_dss_supported_color_modes,
698 .overlay_caps = omap3430_dss_overlay_caps,
699 .clksrc_names = omap2_dss_clk_source_names,
700 .dss_params = am43xx_dss_param_range,
701 .supported_rotation_types = OMAP_DSS_ROT_DMA,
702 .buffer_size_unit = 1,
703 .burst_size_unit = 8,
704};
705
706static const struct omap_dss_features omap3630_dss_features = {
707 .reg_fields = omap3_dss_reg_fields,
708 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
709
710 .features = omap3630_dss_feat_list,
711 .num_features = ARRAY_SIZE(omap3630_dss_feat_list),
712
713 .num_mgrs = 2,
714 .num_ovls = 3,
715 .supported_displays = omap3630_dss_supported_displays,
716 .supported_outputs = omap3630_dss_supported_outputs,
717 .supported_color_modes = omap3_dss_supported_color_modes,
718 .overlay_caps = omap3630_dss_overlay_caps,
719 .clksrc_names = omap3_dss_clk_source_names,
720 .dss_params = omap3_dss_param_range,
721 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
722 .buffer_size_unit = 1,
723 .burst_size_unit = 8,
724};
725
726/* OMAP4 DSS Features */
727/* For OMAP4430 ES 1.0 revision */
728static const struct omap_dss_features omap4430_es1_0_dss_features = {
729 .reg_fields = omap4_dss_reg_fields,
730 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
731
732 .features = omap4430_es1_0_dss_feat_list,
733 .num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list),
734
735 .num_mgrs = 3,
736 .num_ovls = 4,
737 .supported_displays = omap4_dss_supported_displays,
738 .supported_outputs = omap4_dss_supported_outputs,
739 .supported_color_modes = omap4_dss_supported_color_modes,
740 .overlay_caps = omap4_dss_overlay_caps,
741 .clksrc_names = omap4_dss_clk_source_names,
742 .dss_params = omap4_dss_param_range,
743 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
744 .buffer_size_unit = 16,
745 .burst_size_unit = 16,
746};
747
748/* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */
749static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
750 .reg_fields = omap4_dss_reg_fields,
751 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
752
753 .features = omap4430_es2_0_1_2_dss_feat_list,
754 .num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list),
755
756 .num_mgrs = 3,
757 .num_ovls = 4,
758 .supported_displays = omap4_dss_supported_displays,
759 .supported_outputs = omap4_dss_supported_outputs,
760 .supported_color_modes = omap4_dss_supported_color_modes,
761 .overlay_caps = omap4_dss_overlay_caps,
762 .clksrc_names = omap4_dss_clk_source_names,
763 .dss_params = omap4_dss_param_range,
764 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
765 .buffer_size_unit = 16,
766 .burst_size_unit = 16,
767};
768
769/* For all the other OMAP4 versions */
770static const struct omap_dss_features omap4_dss_features = {
771 .reg_fields = omap4_dss_reg_fields,
772 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
773
774 .features = omap4_dss_feat_list,
775 .num_features = ARRAY_SIZE(omap4_dss_feat_list),
776
777 .num_mgrs = 3,
778 .num_ovls = 4,
779 .supported_displays = omap4_dss_supported_displays,
780 .supported_outputs = omap4_dss_supported_outputs,
781 .supported_color_modes = omap4_dss_supported_color_modes,
782 .overlay_caps = omap4_dss_overlay_caps,
783 .clksrc_names = omap4_dss_clk_source_names,
784 .dss_params = omap4_dss_param_range,
785 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
786 .buffer_size_unit = 16,
787 .burst_size_unit = 16,
788};
789
790/* OMAP5 DSS Features */
791static const struct omap_dss_features omap5_dss_features = {
792 .reg_fields = omap5_dss_reg_fields,
793 .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
794
795 .features = omap5_dss_feat_list,
796 .num_features = ARRAY_SIZE(omap5_dss_feat_list),
797
798 .num_mgrs = 4,
799 .num_ovls = 4,
800 .supported_displays = omap5_dss_supported_displays,
801 .supported_outputs = omap5_dss_supported_outputs,
802 .supported_color_modes = omap4_dss_supported_color_modes,
803 .overlay_caps = omap4_dss_overlay_caps,
804 .clksrc_names = omap5_dss_clk_source_names,
805 .dss_params = omap5_dss_param_range,
806 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
807 .buffer_size_unit = 16,
808 .burst_size_unit = 16,
809};
810
811/* Functions returning values related to a DSS feature */
812int dss_feat_get_num_mgrs(void)
813{
814 return omap_current_dss_features->num_mgrs;
815}
816EXPORT_SYMBOL(dss_feat_get_num_mgrs);
817
818int dss_feat_get_num_ovls(void)
819{
820 return omap_current_dss_features->num_ovls;
821}
822EXPORT_SYMBOL(dss_feat_get_num_ovls);
823
824unsigned long dss_feat_get_param_min(enum dss_range_param param)
825{
826 return omap_current_dss_features->dss_params[param].min;
827}
828
829unsigned long dss_feat_get_param_max(enum dss_range_param param)
830{
831 return omap_current_dss_features->dss_params[param].max;
832}
833
834enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
835{
836 return omap_current_dss_features->supported_displays[channel];
837}
838
839enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
840{
841 return omap_current_dss_features->supported_outputs[channel];
842}
843
844enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
845{
846 return omap_current_dss_features->supported_color_modes[plane];
847}
848EXPORT_SYMBOL(dss_feat_get_supported_color_modes);
849
850enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
851{
852 return omap_current_dss_features->overlay_caps[plane];
853}
854
855bool dss_feat_color_mode_supported(enum omap_plane plane,
856 enum omap_color_mode color_mode)
857{
858 return omap_current_dss_features->supported_color_modes[plane] &
859 color_mode;
860}
861
862const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
863{
864 return omap_current_dss_features->clksrc_names[id];
865}
866
867u32 dss_feat_get_buffer_size_unit(void)
868{
869 return omap_current_dss_features->buffer_size_unit;
870}
871
872u32 dss_feat_get_burst_size_unit(void)
873{
874 return omap_current_dss_features->burst_size_unit;
875}
876
877/* DSS has_feature check */
878bool dss_has_feature(enum dss_feat_id id)
879{
880 int i;
881 const enum dss_feat_id *features = omap_current_dss_features->features;
882 const int num_features = omap_current_dss_features->num_features;
883
884 for (i = 0; i < num_features; i++) {
885 if (features[i] == id)
886 return true;
887 }
888
889 return false;
890}
891
892void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
893{
894 if (id >= omap_current_dss_features->num_reg_fields)
895 BUG();
896
897 *start = omap_current_dss_features->reg_fields[id].start;
898 *end = omap_current_dss_features->reg_fields[id].end;
899}
900
901bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
902{
903 return omap_current_dss_features->supported_rotation_types & rot_type;
904}
905
906void dss_features_init(enum omapdss_version version)
907{
908 switch (version) {
909 case OMAPDSS_VER_OMAP24xx:
910 omap_current_dss_features = &omap2_dss_features;
911 break;
912
913 case OMAPDSS_VER_OMAP34xx_ES1:
914 case OMAPDSS_VER_OMAP34xx_ES3:
915 omap_current_dss_features = &omap3430_dss_features;
916 break;
917
918 case OMAPDSS_VER_OMAP3630:
919 omap_current_dss_features = &omap3630_dss_features;
920 break;
921
922 case OMAPDSS_VER_OMAP4430_ES1:
923 omap_current_dss_features = &omap4430_es1_0_dss_features;
924 break;
925
926 case OMAPDSS_VER_OMAP4430_ES2:
927 omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
928 break;
929
930 case OMAPDSS_VER_OMAP4:
931 omap_current_dss_features = &omap4_dss_features;
932 break;
933
934 case OMAPDSS_VER_OMAP5:
935 case OMAPDSS_VER_DRA7xx:
936 omap_current_dss_features = &omap5_dss_features;
937 break;
938
939 case OMAPDSS_VER_AM35xx:
940 omap_current_dss_features = &am35xx_dss_features;
941 break;
942
943 case OMAPDSS_VER_AM43xx:
944 omap_current_dss_features = &am43xx_dss_features;
945 break;
946
947 default:
948 DSSWARN("Unsupported OMAP version");
949 break;
950 }
951}
diff --git a/drivers/gpu/drm/omapdrm/dss/dss_features.h b/drivers/gpu/drm/omapdrm/dss/dss_features.h
new file mode 100644
index 000000000000..3d67d39f192f
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss_features.h
@@ -0,0 +1,108 @@
1/*
2 * linux/drivers/video/omap2/dss/dss_features.h
3 *
4 * Copyright (C) 2010 Texas Instruments
5 * Author: Archit Taneja <archit@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#ifndef __OMAP2_DSS_FEATURES_H
21#define __OMAP2_DSS_FEATURES_H
22
23#define MAX_DSS_MANAGERS 4
24#define MAX_DSS_OVERLAYS 4
25#define MAX_DSS_LCD_MANAGERS 3
26#define MAX_NUM_DSI 2
27
28/* DSS has feature id */
29enum dss_feat_id {
30 FEAT_LCDENABLEPOL,
31 FEAT_LCDENABLESIGNAL,
32 FEAT_PCKFREEENABLE,
33 FEAT_FUNCGATED,
34 FEAT_MGR_LCD2,
35 FEAT_MGR_LCD3,
36 FEAT_LINEBUFFERSPLIT,
37 FEAT_ROWREPEATENABLE,
38 FEAT_RESIZECONF,
39 /* Independent core clk divider */
40 FEAT_CORE_CLK_DIV,
41 FEAT_LCD_CLK_SRC,
42 /* DSI-PLL power command 0x3 is not working */
43 FEAT_DSI_PLL_PWR_BUG,
44 FEAT_DSI_DCS_CMD_CONFIG_VC,
45 FEAT_DSI_VC_OCP_WIDTH,
46 FEAT_DSI_REVERSE_TXCLKESC,
47 FEAT_DSI_GNQ,
48 FEAT_DPI_USES_VDDS_DSI,
49 FEAT_HDMI_CTS_SWMODE,
50 FEAT_HDMI_AUDIO_USE_MCLK,
51 FEAT_HANDLE_UV_SEPARATE,
52 FEAT_ATTR2,
53 FEAT_VENC_REQUIRES_TV_DAC_CLK,
54 FEAT_CPR,
55 FEAT_PRELOAD,
56 FEAT_FIR_COEF_V,
57 FEAT_ALPHA_FIXED_ZORDER,
58 FEAT_ALPHA_FREE_ZORDER,
59 FEAT_FIFO_MERGE,
60 /* An unknown HW bug causing the normal FIFO thresholds not to work */
61 FEAT_OMAP3_DSI_FIFO_BUG,
62 FEAT_BURST_2D,
63 FEAT_DSI_PHY_DCC,
64 FEAT_MFLAG,
65};
66
67/* DSS register field id */
68enum dss_feat_reg_field {
69 FEAT_REG_FIRHINC,
70 FEAT_REG_FIRVINC,
71 FEAT_REG_FIFOHIGHTHRESHOLD,
72 FEAT_REG_FIFOLOWTHRESHOLD,
73 FEAT_REG_FIFOSIZE,
74 FEAT_REG_HORIZONTALACCU,
75 FEAT_REG_VERTICALACCU,
76 FEAT_REG_DISPC_CLK_SWITCH,
77};
78
79enum dss_range_param {
80 FEAT_PARAM_DSS_FCK,
81 FEAT_PARAM_DSS_PCD,
82 FEAT_PARAM_DSIPLL_LPDIV,
83 FEAT_PARAM_DSI_FCK,
84 FEAT_PARAM_DOWNSCALE,
85 FEAT_PARAM_LINEWIDTH,
86};
87
88/* DSS Feature Functions */
89unsigned long dss_feat_get_param_min(enum dss_range_param param);
90unsigned long dss_feat_get_param_max(enum dss_range_param param);
91enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
92bool dss_feat_color_mode_supported(enum omap_plane plane,
93 enum omap_color_mode color_mode);
94const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
95
96u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
97u32 dss_feat_get_burst_size_unit(void); /* in bytes */
98
99bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
100
101bool dss_has_feature(enum dss_feat_id id);
102void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
103void dss_features_init(enum omapdss_version version);
104
105enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
106enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
107
108#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h
new file mode 100644
index 000000000000..53616b02b613
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
@@ -0,0 +1,370 @@
1/*
2 * HDMI driver definition for TI OMAP4 Processor.
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _HDMI_H
20#define _HDMI_H
21
22#include <linux/delay.h>
23#include <linux/io.h>
24#include <linux/platform_device.h>
25#include <linux/hdmi.h>
26#include <video/omapdss.h>
27
28#include "dss.h"
29
30/* HDMI Wrapper */
31
32#define HDMI_WP_REVISION 0x0
33#define HDMI_WP_SYSCONFIG 0x10
34#define HDMI_WP_IRQSTATUS_RAW 0x24
35#define HDMI_WP_IRQSTATUS 0x28
36#define HDMI_WP_IRQENABLE_SET 0x2C
37#define HDMI_WP_IRQENABLE_CLR 0x30
38#define HDMI_WP_IRQWAKEEN 0x34
39#define HDMI_WP_PWR_CTRL 0x40
40#define HDMI_WP_DEBOUNCE 0x44
41#define HDMI_WP_VIDEO_CFG 0x50
42#define HDMI_WP_VIDEO_SIZE 0x60
43#define HDMI_WP_VIDEO_TIMING_H 0x68
44#define HDMI_WP_VIDEO_TIMING_V 0x6C
45#define HDMI_WP_CLK 0x70
46#define HDMI_WP_AUDIO_CFG 0x80
47#define HDMI_WP_AUDIO_CFG2 0x84
48#define HDMI_WP_AUDIO_CTRL 0x88
49#define HDMI_WP_AUDIO_DATA 0x8C
50
51/* HDMI WP IRQ flags */
52#define HDMI_IRQ_CORE (1 << 0)
53#define HDMI_IRQ_OCP_TIMEOUT (1 << 4)
54#define HDMI_IRQ_AUDIO_FIFO_UNDERFLOW (1 << 8)
55#define HDMI_IRQ_AUDIO_FIFO_OVERFLOW (1 << 9)
56#define HDMI_IRQ_AUDIO_FIFO_SAMPLE_REQ (1 << 10)
57#define HDMI_IRQ_VIDEO_VSYNC (1 << 16)
58#define HDMI_IRQ_VIDEO_FRAME_DONE (1 << 17)
59#define HDMI_IRQ_PHY_LINE5V_ASSERT (1 << 24)
60#define HDMI_IRQ_LINK_CONNECT (1 << 25)
61#define HDMI_IRQ_LINK_DISCONNECT (1 << 26)
62#define HDMI_IRQ_PLL_LOCK (1 << 29)
63#define HDMI_IRQ_PLL_UNLOCK (1 << 30)
64#define HDMI_IRQ_PLL_RECAL (1 << 31)
65
66/* HDMI PLL */
67
68#define PLLCTRL_PLL_CONTROL 0x0
69#define PLLCTRL_PLL_STATUS 0x4
70#define PLLCTRL_PLL_GO 0x8
71#define PLLCTRL_CFG1 0xC
72#define PLLCTRL_CFG2 0x10
73#define PLLCTRL_CFG3 0x14
74#define PLLCTRL_SSC_CFG1 0x18
75#define PLLCTRL_SSC_CFG2 0x1C
76#define PLLCTRL_CFG4 0x20
77
78/* HDMI PHY */
79
80#define HDMI_TXPHY_TX_CTRL 0x0
81#define HDMI_TXPHY_DIGITAL_CTRL 0x4
82#define HDMI_TXPHY_POWER_CTRL 0x8
83#define HDMI_TXPHY_PAD_CFG_CTRL 0xC
84#define HDMI_TXPHY_BIST_CONTROL 0x1C
85
86enum hdmi_pll_pwr {
87 HDMI_PLLPWRCMD_ALLOFF = 0,
88 HDMI_PLLPWRCMD_PLLONLY = 1,
89 HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
90 HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
91};
92
93enum hdmi_phy_pwr {
94 HDMI_PHYPWRCMD_OFF = 0,
95 HDMI_PHYPWRCMD_LDOON = 1,
96 HDMI_PHYPWRCMD_TXON = 2
97};
98
99enum hdmi_core_hdmi_dvi {
100 HDMI_DVI = 0,
101 HDMI_HDMI = 1
102};
103
104enum hdmi_packing_mode {
105 HDMI_PACK_10b_RGB_YUV444 = 0,
106 HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
107 HDMI_PACK_20b_YUV422 = 2,
108 HDMI_PACK_ALREADYPACKED = 7
109};
110
111enum hdmi_stereo_channels {
112 HDMI_AUDIO_STEREO_NOCHANNELS = 0,
113 HDMI_AUDIO_STEREO_ONECHANNEL = 1,
114 HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
115 HDMI_AUDIO_STEREO_THREECHANNELS = 3,
116 HDMI_AUDIO_STEREO_FOURCHANNELS = 4
117};
118
119enum hdmi_audio_type {
120 HDMI_AUDIO_TYPE_LPCM = 0,
121 HDMI_AUDIO_TYPE_IEC = 1
122};
123
124enum hdmi_audio_justify {
125 HDMI_AUDIO_JUSTIFY_LEFT = 0,
126 HDMI_AUDIO_JUSTIFY_RIGHT = 1
127};
128
129enum hdmi_audio_sample_order {
130 HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
131 HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
132};
133
134enum hdmi_audio_samples_perword {
135 HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
136 HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
137};
138
139enum hdmi_audio_sample_size_omap {
140 HDMI_AUDIO_SAMPLE_16BITS = 0,
141 HDMI_AUDIO_SAMPLE_24BITS = 1
142};
143
144enum hdmi_audio_transf_mode {
145 HDMI_AUDIO_TRANSF_DMA = 0,
146 HDMI_AUDIO_TRANSF_IRQ = 1
147};
148
149enum hdmi_audio_blk_strt_end_sig {
150 HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
151 HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
152};
153
154enum hdmi_core_audio_layout {
155 HDMI_AUDIO_LAYOUT_2CH = 0,
156 HDMI_AUDIO_LAYOUT_8CH = 1,
157 HDMI_AUDIO_LAYOUT_6CH = 2
158};
159
160enum hdmi_core_cts_mode {
161 HDMI_AUDIO_CTS_MODE_HW = 0,
162 HDMI_AUDIO_CTS_MODE_SW = 1
163};
164
165enum hdmi_audio_mclk_mode {
166 HDMI_AUDIO_MCLK_128FS = 0,
167 HDMI_AUDIO_MCLK_256FS = 1,
168 HDMI_AUDIO_MCLK_384FS = 2,
169 HDMI_AUDIO_MCLK_512FS = 3,
170 HDMI_AUDIO_MCLK_768FS = 4,
171 HDMI_AUDIO_MCLK_1024FS = 5,
172 HDMI_AUDIO_MCLK_1152FS = 6,
173 HDMI_AUDIO_MCLK_192FS = 7
174};
175
176struct hdmi_video_format {
177 enum hdmi_packing_mode packing_mode;
178 u32 y_res; /* Line per panel */
179 u32 x_res; /* pixel per line */
180};
181
182struct hdmi_config {
183 struct omap_video_timings timings;
184 struct hdmi_avi_infoframe infoframe;
185 enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
186};
187
188struct hdmi_audio_format {
189 enum hdmi_stereo_channels stereo_channels;
190 u8 active_chnnls_msk;
191 enum hdmi_audio_type type;
192 enum hdmi_audio_justify justification;
193 enum hdmi_audio_sample_order sample_order;
194 enum hdmi_audio_samples_perword samples_per_word;
195 enum hdmi_audio_sample_size_omap sample_size;
196 enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end;
197};
198
199struct hdmi_audio_dma {
200 u8 transfer_size;
201 u8 block_size;
202 enum hdmi_audio_transf_mode mode;
203 u16 fifo_threshold;
204};
205
206struct hdmi_core_audio_i2s_config {
207 u8 in_length_bits;
208 u8 justification;
209 u8 sck_edge_mode;
210 u8 vbit;
211 u8 direction;
212 u8 shift;
213 u8 active_sds;
214};
215
216struct hdmi_core_audio_config {
217 struct hdmi_core_audio_i2s_config i2s_cfg;
218 struct snd_aes_iec958 *iec60958_cfg;
219 bool fs_override;
220 u32 n;
221 u32 cts;
222 u32 aud_par_busclk;
223 enum hdmi_core_audio_layout layout;
224 enum hdmi_core_cts_mode cts_mode;
225 bool use_mclk;
226 enum hdmi_audio_mclk_mode mclk_mode;
227 bool en_acr_pkt;
228 bool en_dsd_audio;
229 bool en_parallel_aud_input;
230 bool en_spdif;
231};
232
233struct hdmi_wp_data {
234 void __iomem *base;
235 phys_addr_t phys_base;
236};
237
238struct hdmi_pll_data {
239 struct dss_pll pll;
240
241 void __iomem *base;
242
243 struct hdmi_wp_data *wp;
244};
245
246struct hdmi_phy_data {
247 void __iomem *base;
248
249 u8 lane_function[4];
250 u8 lane_polarity[4];
251};
252
253struct hdmi_core_data {
254 void __iomem *base;
255};
256
257static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx,
258 u32 val)
259{
260 __raw_writel(val, base_addr + idx);
261}
262
263static inline u32 hdmi_read_reg(void __iomem *base_addr, const u32 idx)
264{
265 return __raw_readl(base_addr + idx);
266}
267
268#define REG_FLD_MOD(base, idx, val, start, end) \
269 hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
270 val, start, end))
271#define REG_GET(base, idx, start, end) \
272 FLD_GET(hdmi_read_reg(base, idx), start, end)
273
274static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
275 const u32 idx, int b2, int b1, u32 val)
276{
277 u32 t = 0, v;
278 while (val != (v = REG_GET(base_addr, idx, b2, b1))) {
279 if (t++ > 10000)
280 return v;
281 udelay(1);
282 }
283 return v;
284}
285
286/* HDMI wrapper funcs */
287int hdmi_wp_video_start(struct hdmi_wp_data *wp);
288void hdmi_wp_video_stop(struct hdmi_wp_data *wp);
289void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s);
290u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp);
291void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus);
292void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask);
293void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
294int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
295int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
296void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
297 struct hdmi_video_format *video_fmt);
298void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
299 struct omap_video_timings *timings);
300void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
301 struct omap_video_timings *timings);
302void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
303 struct omap_video_timings *timings, struct hdmi_config *param);
304int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
305phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
306
307/* HDMI PLL funcs */
308void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
309void hdmi_pll_compute(struct hdmi_pll_data *pll,
310 unsigned long target_tmds, struct dss_pll_clock_info *pi);
311int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
312 struct hdmi_wp_data *wp);
313void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
314
315/* HDMI PHY funcs */
316int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
317 unsigned long lfbitclk);
318void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
319int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
320int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
321
322/* HDMI common funcs */
323int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
324 struct hdmi_phy_data *phy);
325
326/* Audio funcs */
327int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
328int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
329int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
330void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
331 struct hdmi_audio_format *aud_fmt);
332void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
333 struct hdmi_audio_dma *aud_dma);
334static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
335{
336 return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
337}
338
339/* HDMI DRV data */
340struct omap_hdmi {
341 struct mutex lock;
342 struct platform_device *pdev;
343
344 struct hdmi_wp_data wp;
345 struct hdmi_pll_data pll;
346 struct hdmi_phy_data phy;
347 struct hdmi_core_data core;
348
349 struct hdmi_config cfg;
350
351 struct regulator *vdda_reg;
352
353 bool core_enabled;
354
355 struct omap_dss_device output;
356
357 struct platform_device *audio_pdev;
358 void (*audio_abort_cb)(struct device *dev);
359 int wp_idlemode;
360
361 bool audio_configured;
362 struct omap_dss_audio audio_config;
363
364 /* This lock should be taken when booleans bellow are touched. */
365 spinlock_t audio_playing_lock;
366 bool audio_playing;
367 bool display_enabled;
368};
369
370#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
new file mode 100644
index 000000000000..7103c659a534
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -0,0 +1,839 @@
1/*
2 * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
3 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
4 * Authors: Yong Zhi
5 * Mythri pk <mythripk@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#define DSS_SUBSYS_NAME "HDMI"
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/interrupt.h>
27#include <linux/mutex.h>
28#include <linux/delay.h>
29#include <linux/string.h>
30#include <linux/platform_device.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/gpio.h>
34#include <linux/regulator/consumer.h>
35#include <linux/component.h>
36#include <video/omapdss.h>
37#include <sound/omap-hdmi-audio.h>
38
39#include "hdmi4_core.h"
40#include "dss.h"
41#include "dss_features.h"
42#include "hdmi.h"
43
44static struct omap_hdmi hdmi;
45
46static int hdmi_runtime_get(void)
47{
48 int r;
49
50 DSSDBG("hdmi_runtime_get\n");
51
52 r = pm_runtime_get_sync(&hdmi.pdev->dev);
53 WARN_ON(r < 0);
54 if (r < 0)
55 return r;
56
57 return 0;
58}
59
60static void hdmi_runtime_put(void)
61{
62 int r;
63
64 DSSDBG("hdmi_runtime_put\n");
65
66 r = pm_runtime_put_sync(&hdmi.pdev->dev);
67 WARN_ON(r < 0 && r != -ENOSYS);
68}
69
70static irqreturn_t hdmi_irq_handler(int irq, void *data)
71{
72 struct hdmi_wp_data *wp = data;
73 u32 irqstatus;
74
75 irqstatus = hdmi_wp_get_irqstatus(wp);
76 hdmi_wp_set_irqstatus(wp, irqstatus);
77
78 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
79 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
80 /*
81 * If we get both connect and disconnect interrupts at the same
82 * time, turn off the PHY, clear interrupts, and restart, which
83 * raises connect interrupt if a cable is connected, or nothing
84 * if cable is not connected.
85 */
86 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
87
88 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
89 HDMI_IRQ_LINK_DISCONNECT);
90
91 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
92 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
93 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
94 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
95 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
96 }
97
98 return IRQ_HANDLED;
99}
100
101static int hdmi_init_regulator(void)
102{
103 int r;
104 struct regulator *reg;
105
106 if (hdmi.vdda_reg != NULL)
107 return 0;
108
109 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
110
111 if (IS_ERR(reg)) {
112 if (PTR_ERR(reg) != -EPROBE_DEFER)
113 DSSERR("can't get VDDA regulator\n");
114 return PTR_ERR(reg);
115 }
116
117 if (regulator_can_change_voltage(reg)) {
118 r = regulator_set_voltage(reg, 1800000, 1800000);
119 if (r) {
120 devm_regulator_put(reg);
121 DSSWARN("can't set the regulator voltage\n");
122 return r;
123 }
124 }
125
126 hdmi.vdda_reg = reg;
127
128 return 0;
129}
130
131static int hdmi_power_on_core(struct omap_dss_device *dssdev)
132{
133 int r;
134
135 r = regulator_enable(hdmi.vdda_reg);
136 if (r)
137 return r;
138
139 r = hdmi_runtime_get();
140 if (r)
141 goto err_runtime_get;
142
143 /* Make selection of HDMI in DSS */
144 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
145
146 hdmi.core_enabled = true;
147
148 return 0;
149
150err_runtime_get:
151 regulator_disable(hdmi.vdda_reg);
152
153 return r;
154}
155
156static void hdmi_power_off_core(struct omap_dss_device *dssdev)
157{
158 hdmi.core_enabled = false;
159
160 hdmi_runtime_put();
161 regulator_disable(hdmi.vdda_reg);
162}
163
164static int hdmi_power_on_full(struct omap_dss_device *dssdev)
165{
166 int r;
167 struct omap_video_timings *p;
168 struct omap_overlay_manager *mgr = hdmi.output.manager;
169 struct hdmi_wp_data *wp = &hdmi.wp;
170 struct dss_pll_clock_info hdmi_cinfo = { 0 };
171
172 r = hdmi_power_on_core(dssdev);
173 if (r)
174 return r;
175
176 /* disable and clear irqs */
177 hdmi_wp_clear_irqenable(wp, 0xffffffff);
178 hdmi_wp_set_irqstatus(wp, 0xffffffff);
179
180 p = &hdmi.cfg.timings;
181
182 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
183
184 hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
185
186 r = dss_pll_enable(&hdmi.pll.pll);
187 if (r) {
188 DSSERR("Failed to enable PLL\n");
189 goto err_pll_enable;
190 }
191
192 r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
193 if (r) {
194 DSSERR("Failed to configure PLL\n");
195 goto err_pll_cfg;
196 }
197
198 r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
199 hdmi_cinfo.clkout[0]);
200 if (r) {
201 DSSDBG("Failed to configure PHY\n");
202 goto err_phy_cfg;
203 }
204
205 r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
206 if (r)
207 goto err_phy_pwr;
208
209 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
210
211 /* bypass TV gamma table */
212 dispc_enable_gamma_table(0);
213
214 /* tv size */
215 dss_mgr_set_timings(mgr, p);
216
217 r = hdmi_wp_video_start(&hdmi.wp);
218 if (r)
219 goto err_vid_enable;
220
221 r = dss_mgr_enable(mgr);
222 if (r)
223 goto err_mgr_enable;
224
225 hdmi_wp_set_irqenable(wp,
226 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
227
228 return 0;
229
230err_mgr_enable:
231 hdmi_wp_video_stop(&hdmi.wp);
232err_vid_enable:
233 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
234err_phy_pwr:
235err_phy_cfg:
236err_pll_cfg:
237 dss_pll_disable(&hdmi.pll.pll);
238err_pll_enable:
239 hdmi_power_off_core(dssdev);
240 return -EIO;
241}
242
243static void hdmi_power_off_full(struct omap_dss_device *dssdev)
244{
245 struct omap_overlay_manager *mgr = hdmi.output.manager;
246
247 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
248
249 dss_mgr_disable(mgr);
250
251 hdmi_wp_video_stop(&hdmi.wp);
252
253 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
254
255 dss_pll_disable(&hdmi.pll.pll);
256
257 hdmi_power_off_core(dssdev);
258}
259
260static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
261 struct omap_video_timings *timings)
262{
263 struct omap_dss_device *out = &hdmi.output;
264
265 if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
266 return -EINVAL;
267
268 return 0;
269}
270
271static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
272 struct omap_video_timings *timings)
273{
274 mutex_lock(&hdmi.lock);
275
276 hdmi.cfg.timings = *timings;
277
278 dispc_set_tv_pclk(timings->pixelclock);
279
280 mutex_unlock(&hdmi.lock);
281}
282
283static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
284 struct omap_video_timings *timings)
285{
286 *timings = hdmi.cfg.timings;
287}
288
289static void hdmi_dump_regs(struct seq_file *s)
290{
291 mutex_lock(&hdmi.lock);
292
293 if (hdmi_runtime_get()) {
294 mutex_unlock(&hdmi.lock);
295 return;
296 }
297
298 hdmi_wp_dump(&hdmi.wp, s);
299 hdmi_pll_dump(&hdmi.pll, s);
300 hdmi_phy_dump(&hdmi.phy, s);
301 hdmi4_core_dump(&hdmi.core, s);
302
303 hdmi_runtime_put();
304 mutex_unlock(&hdmi.lock);
305}
306
307static int read_edid(u8 *buf, int len)
308{
309 int r;
310
311 mutex_lock(&hdmi.lock);
312
313 r = hdmi_runtime_get();
314 BUG_ON(r);
315
316 r = hdmi4_read_edid(&hdmi.core, buf, len);
317
318 hdmi_runtime_put();
319 mutex_unlock(&hdmi.lock);
320
321 return r;
322}
323
324static void hdmi_start_audio_stream(struct omap_hdmi *hd)
325{
326 hdmi_wp_audio_enable(&hd->wp, true);
327 hdmi4_audio_start(&hd->core, &hd->wp);
328}
329
330static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
331{
332 hdmi4_audio_stop(&hd->core, &hd->wp);
333 hdmi_wp_audio_enable(&hd->wp, false);
334}
335
336static int hdmi_display_enable(struct omap_dss_device *dssdev)
337{
338 struct omap_dss_device *out = &hdmi.output;
339 unsigned long flags;
340 int r = 0;
341
342 DSSDBG("ENTER hdmi_display_enable\n");
343
344 mutex_lock(&hdmi.lock);
345
346 if (out->manager == NULL) {
347 DSSERR("failed to enable display: no output/manager\n");
348 r = -ENODEV;
349 goto err0;
350 }
351
352 r = hdmi_power_on_full(dssdev);
353 if (r) {
354 DSSERR("failed to power on device\n");
355 goto err0;
356 }
357
358 if (hdmi.audio_configured) {
359 r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
360 hdmi.cfg.timings.pixelclock);
361 if (r) {
362 DSSERR("Error restoring audio configuration: %d", r);
363 hdmi.audio_abort_cb(&hdmi.pdev->dev);
364 hdmi.audio_configured = false;
365 }
366 }
367
368 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
369 if (hdmi.audio_configured && hdmi.audio_playing)
370 hdmi_start_audio_stream(&hdmi);
371 hdmi.display_enabled = true;
372 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
373
374 mutex_unlock(&hdmi.lock);
375 return 0;
376
377err0:
378 mutex_unlock(&hdmi.lock);
379 return r;
380}
381
382static void hdmi_display_disable(struct omap_dss_device *dssdev)
383{
384 unsigned long flags;
385
386 DSSDBG("Enter hdmi_display_disable\n");
387
388 mutex_lock(&hdmi.lock);
389
390 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
391 hdmi_stop_audio_stream(&hdmi);
392 hdmi.display_enabled = false;
393 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
394
395 hdmi_power_off_full(dssdev);
396
397 mutex_unlock(&hdmi.lock);
398}
399
400static int hdmi_core_enable(struct omap_dss_device *dssdev)
401{
402 int r = 0;
403
404 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
405
406 mutex_lock(&hdmi.lock);
407
408 r = hdmi_power_on_core(dssdev);
409 if (r) {
410 DSSERR("failed to power on device\n");
411 goto err0;
412 }
413
414 mutex_unlock(&hdmi.lock);
415 return 0;
416
417err0:
418 mutex_unlock(&hdmi.lock);
419 return r;
420}
421
422static void hdmi_core_disable(struct omap_dss_device *dssdev)
423{
424 DSSDBG("Enter omapdss_hdmi_core_disable\n");
425
426 mutex_lock(&hdmi.lock);
427
428 hdmi_power_off_core(dssdev);
429
430 mutex_unlock(&hdmi.lock);
431}
432
433static int hdmi_connect(struct omap_dss_device *dssdev,
434 struct omap_dss_device *dst)
435{
436 struct omap_overlay_manager *mgr;
437 int r;
438
439 r = hdmi_init_regulator();
440 if (r)
441 return r;
442
443 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
444 if (!mgr)
445 return -ENODEV;
446
447 r = dss_mgr_connect(mgr, dssdev);
448 if (r)
449 return r;
450
451 r = omapdss_output_set_device(dssdev, dst);
452 if (r) {
453 DSSERR("failed to connect output to new device: %s\n",
454 dst->name);
455 dss_mgr_disconnect(mgr, dssdev);
456 return r;
457 }
458
459 return 0;
460}
461
462static void hdmi_disconnect(struct omap_dss_device *dssdev,
463 struct omap_dss_device *dst)
464{
465 WARN_ON(dst != dssdev->dst);
466
467 if (dst != dssdev->dst)
468 return;
469
470 omapdss_output_unset_device(dssdev);
471
472 if (dssdev->manager)
473 dss_mgr_disconnect(dssdev->manager, dssdev);
474}
475
476static int hdmi_read_edid(struct omap_dss_device *dssdev,
477 u8 *edid, int len)
478{
479 bool need_enable;
480 int r;
481
482 need_enable = hdmi.core_enabled == false;
483
484 if (need_enable) {
485 r = hdmi_core_enable(dssdev);
486 if (r)
487 return r;
488 }
489
490 r = read_edid(edid, len);
491
492 if (need_enable)
493 hdmi_core_disable(dssdev);
494
495 return r;
496}
497
498static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
499 const struct hdmi_avi_infoframe *avi)
500{
501 hdmi.cfg.infoframe = *avi;
502 return 0;
503}
504
505static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
506 bool hdmi_mode)
507{
508 hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
509 return 0;
510}
511
512static const struct omapdss_hdmi_ops hdmi_ops = {
513 .connect = hdmi_connect,
514 .disconnect = hdmi_disconnect,
515
516 .enable = hdmi_display_enable,
517 .disable = hdmi_display_disable,
518
519 .check_timings = hdmi_display_check_timing,
520 .set_timings = hdmi_display_set_timing,
521 .get_timings = hdmi_display_get_timings,
522
523 .read_edid = hdmi_read_edid,
524 .set_infoframe = hdmi_set_infoframe,
525 .set_hdmi_mode = hdmi_set_hdmi_mode,
526};
527
528static void hdmi_init_output(struct platform_device *pdev)
529{
530 struct omap_dss_device *out = &hdmi.output;
531
532 out->dev = &pdev->dev;
533 out->id = OMAP_DSS_OUTPUT_HDMI;
534 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
535 out->name = "hdmi.0";
536 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
537 out->ops.hdmi = &hdmi_ops;
538 out->owner = THIS_MODULE;
539
540 omapdss_register_output(out);
541}
542
543static void hdmi_uninit_output(struct platform_device *pdev)
544{
545 struct omap_dss_device *out = &hdmi.output;
546
547 omapdss_unregister_output(out);
548}
549
550static int hdmi_probe_of(struct platform_device *pdev)
551{
552 struct device_node *node = pdev->dev.of_node;
553 struct device_node *ep;
554 int r;
555
556 ep = omapdss_of_get_first_endpoint(node);
557 if (!ep)
558 return 0;
559
560 r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
561 if (r)
562 goto err;
563
564 of_node_put(ep);
565 return 0;
566
567err:
568 of_node_put(ep);
569 return r;
570}
571
572/* Audio callbacks */
573static int hdmi_audio_startup(struct device *dev,
574 void (*abort_cb)(struct device *dev))
575{
576 struct omap_hdmi *hd = dev_get_drvdata(dev);
577 int ret = 0;
578
579 mutex_lock(&hd->lock);
580
581 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
582 ret = -EPERM;
583 goto out;
584 }
585
586 hd->audio_abort_cb = abort_cb;
587
588out:
589 mutex_unlock(&hd->lock);
590
591 return ret;
592}
593
594static int hdmi_audio_shutdown(struct device *dev)
595{
596 struct omap_hdmi *hd = dev_get_drvdata(dev);
597
598 mutex_lock(&hd->lock);
599 hd->audio_abort_cb = NULL;
600 hd->audio_configured = false;
601 hd->audio_playing = false;
602 mutex_unlock(&hd->lock);
603
604 return 0;
605}
606
607static int hdmi_audio_start(struct device *dev)
608{
609 struct omap_hdmi *hd = dev_get_drvdata(dev);
610 unsigned long flags;
611
612 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
613
614 spin_lock_irqsave(&hd->audio_playing_lock, flags);
615
616 if (hd->display_enabled)
617 hdmi_start_audio_stream(hd);
618 hd->audio_playing = true;
619
620 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
621 return 0;
622}
623
624static void hdmi_audio_stop(struct device *dev)
625{
626 struct omap_hdmi *hd = dev_get_drvdata(dev);
627 unsigned long flags;
628
629 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
630
631 spin_lock_irqsave(&hd->audio_playing_lock, flags);
632
633 if (hd->display_enabled)
634 hdmi_stop_audio_stream(hd);
635 hd->audio_playing = false;
636
637 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
638}
639
640static int hdmi_audio_config(struct device *dev,
641 struct omap_dss_audio *dss_audio)
642{
643 struct omap_hdmi *hd = dev_get_drvdata(dev);
644 int ret;
645
646 mutex_lock(&hd->lock);
647
648 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
649 ret = -EPERM;
650 goto out;
651 }
652
653 ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
654 hd->cfg.timings.pixelclock);
655 if (!ret) {
656 hd->audio_configured = true;
657 hd->audio_config = *dss_audio;
658 }
659out:
660 mutex_unlock(&hd->lock);
661
662 return ret;
663}
664
665static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
666 .audio_startup = hdmi_audio_startup,
667 .audio_shutdown = hdmi_audio_shutdown,
668 .audio_start = hdmi_audio_start,
669 .audio_stop = hdmi_audio_stop,
670 .audio_config = hdmi_audio_config,
671};
672
673static int hdmi_audio_register(struct device *dev)
674{
675 struct omap_hdmi_audio_pdata pdata = {
676 .dev = dev,
677 .dss_version = omapdss_get_version(),
678 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
679 .ops = &hdmi_audio_ops,
680 };
681
682 hdmi.audio_pdev = platform_device_register_data(
683 dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
684 &pdata, sizeof(pdata));
685
686 if (IS_ERR(hdmi.audio_pdev))
687 return PTR_ERR(hdmi.audio_pdev);
688
689 return 0;
690}
691
692/* HDMI HW IP initialisation */
693static int hdmi4_bind(struct device *dev, struct device *master, void *data)
694{
695 struct platform_device *pdev = to_platform_device(dev);
696 int r;
697 int irq;
698
699 hdmi.pdev = pdev;
700 dev_set_drvdata(&pdev->dev, &hdmi);
701
702 mutex_init(&hdmi.lock);
703 spin_lock_init(&hdmi.audio_playing_lock);
704
705 if (pdev->dev.of_node) {
706 r = hdmi_probe_of(pdev);
707 if (r)
708 return r;
709 }
710
711 r = hdmi_wp_init(pdev, &hdmi.wp);
712 if (r)
713 return r;
714
715 r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
716 if (r)
717 return r;
718
719 r = hdmi_phy_init(pdev, &hdmi.phy);
720 if (r)
721 goto err;
722
723 r = hdmi4_core_init(pdev, &hdmi.core);
724 if (r)
725 goto err;
726
727 irq = platform_get_irq(pdev, 0);
728 if (irq < 0) {
729 DSSERR("platform_get_irq failed\n");
730 r = -ENODEV;
731 goto err;
732 }
733
734 r = devm_request_threaded_irq(&pdev->dev, irq,
735 NULL, hdmi_irq_handler,
736 IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
737 if (r) {
738 DSSERR("HDMI IRQ request failed\n");
739 goto err;
740 }
741
742 pm_runtime_enable(&pdev->dev);
743
744 hdmi_init_output(pdev);
745
746 r = hdmi_audio_register(&pdev->dev);
747 if (r) {
748 DSSERR("Registering HDMI audio failed\n");
749 hdmi_uninit_output(pdev);
750 pm_runtime_disable(&pdev->dev);
751 return r;
752 }
753
754 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
755
756 return 0;
757err:
758 hdmi_pll_uninit(&hdmi.pll);
759 return r;
760}
761
762static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
763{
764 struct platform_device *pdev = to_platform_device(dev);
765
766 if (hdmi.audio_pdev)
767 platform_device_unregister(hdmi.audio_pdev);
768
769 hdmi_uninit_output(pdev);
770
771 hdmi_pll_uninit(&hdmi.pll);
772
773 pm_runtime_disable(&pdev->dev);
774}
775
776static const struct component_ops hdmi4_component_ops = {
777 .bind = hdmi4_bind,
778 .unbind = hdmi4_unbind,
779};
780
781static int hdmi4_probe(struct platform_device *pdev)
782{
783 return component_add(&pdev->dev, &hdmi4_component_ops);
784}
785
786static int hdmi4_remove(struct platform_device *pdev)
787{
788 component_del(&pdev->dev, &hdmi4_component_ops);
789 return 0;
790}
791
792static int hdmi_runtime_suspend(struct device *dev)
793{
794 dispc_runtime_put();
795
796 return 0;
797}
798
799static int hdmi_runtime_resume(struct device *dev)
800{
801 int r;
802
803 r = dispc_runtime_get();
804 if (r < 0)
805 return r;
806
807 return 0;
808}
809
810static const struct dev_pm_ops hdmi_pm_ops = {
811 .runtime_suspend = hdmi_runtime_suspend,
812 .runtime_resume = hdmi_runtime_resume,
813};
814
815static const struct of_device_id hdmi_of_match[] = {
816 { .compatible = "ti,omap4-hdmi", },
817 {},
818};
819
820static struct platform_driver omapdss_hdmihw_driver = {
821 .probe = hdmi4_probe,
822 .remove = hdmi4_remove,
823 .driver = {
824 .name = "omapdss_hdmi",
825 .pm = &hdmi_pm_ops,
826 .of_match_table = hdmi_of_match,
827 .suppress_bind_attrs = true,
828 },
829};
830
831int __init hdmi4_init_platform_driver(void)
832{
833 return platform_driver_register(&omapdss_hdmihw_driver);
834}
835
836void hdmi4_uninit_platform_driver(void)
837{
838 platform_driver_unregister(&omapdss_hdmihw_driver);
839}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
new file mode 100644
index 000000000000..fa72e735dad2
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
@@ -0,0 +1,904 @@
1/*
2 * ti_hdmi_4xxx_ip.c
3 *
4 * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
6 * Authors: Yong Zhi
7 * Mythri pk <mythripk@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "HDMICORE"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/interrupt.h>
29#include <linux/mutex.h>
30#include <linux/delay.h>
31#include <linux/platform_device.h>
32#include <linux/string.h>
33#include <linux/seq_file.h>
34#include <sound/asound.h>
35#include <sound/asoundef.h>
36
37#include "hdmi4_core.h"
38#include "dss_features.h"
39
40#define HDMI_CORE_AV 0x500
41
42static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core)
43{
44 return core->base + HDMI_CORE_AV;
45}
46
47static int hdmi_core_ddc_init(struct hdmi_core_data *core)
48{
49 void __iomem *base = core->base;
50
51 /* Turn on CLK for DDC */
52 REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0);
53
54 /* IN_PROG */
55 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) {
56 /* Abort transaction */
57 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0);
58 /* IN_PROG */
59 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
60 4, 4, 0) != 0) {
61 DSSERR("Timeout aborting DDC transaction\n");
62 return -ETIMEDOUT;
63 }
64 }
65
66 /* Clk SCL Devices */
67 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0);
68
69 /* HDMI_CORE_DDC_STATUS_IN_PROG */
70 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
71 4, 4, 0) != 0) {
72 DSSERR("Timeout starting SCL clock\n");
73 return -ETIMEDOUT;
74 }
75
76 /* Clear FIFO */
77 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0);
78
79 /* HDMI_CORE_DDC_STATUS_IN_PROG */
80 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
81 4, 4, 0) != 0) {
82 DSSERR("Timeout clearing DDC fifo\n");
83 return -ETIMEDOUT;
84 }
85
86 return 0;
87}
88
89static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
90 u8 *pedid, int ext)
91{
92 void __iomem *base = core->base;
93 u32 i;
94 char checksum;
95 u32 offset = 0;
96
97 /* HDMI_CORE_DDC_STATUS_IN_PROG */
98 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
99 4, 4, 0) != 0) {
100 DSSERR("Timeout waiting DDC to be ready\n");
101 return -ETIMEDOUT;
102 }
103
104 if (ext % 2 != 0)
105 offset = 0x80;
106
107 /* Load Segment Address Register */
108 REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
109
110 /* Load Slave Address Register */
111 REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
112
113 /* Load Offset Address Register */
114 REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
115
116 /* Load Byte Count */
117 REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
118 REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
119
120 /* Set DDC_CMD */
121 if (ext)
122 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
123 else
124 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
125
126 /* HDMI_CORE_DDC_STATUS_BUS_LOW */
127 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
128 DSSERR("I2C Bus Low?\n");
129 return -EIO;
130 }
131 /* HDMI_CORE_DDC_STATUS_NO_ACK */
132 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
133 DSSERR("I2C No Ack\n");
134 return -EIO;
135 }
136
137 for (i = 0; i < 0x80; ++i) {
138 int t;
139
140 /* IN_PROG */
141 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) {
142 DSSERR("operation stopped when reading edid\n");
143 return -EIO;
144 }
145
146 t = 0;
147 /* FIFO_EMPTY */
148 while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) {
149 if (t++ > 10000) {
150 DSSERR("timeout reading edid\n");
151 return -ETIMEDOUT;
152 }
153 udelay(1);
154 }
155
156 pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
157 }
158
159 checksum = 0;
160 for (i = 0; i < 0x80; ++i)
161 checksum += pedid[i];
162
163 if (checksum != 0) {
164 DSSERR("E-EDID checksum failed!!\n");
165 return -EIO;
166 }
167
168 return 0;
169}
170
171int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
172{
173 int r, l;
174
175 if (len < 128)
176 return -EINVAL;
177
178 r = hdmi_core_ddc_init(core);
179 if (r)
180 return r;
181
182 r = hdmi_core_ddc_edid(core, edid, 0);
183 if (r)
184 return r;
185
186 l = 128;
187
188 if (len >= 128 * 2 && edid[0x7e] > 0) {
189 r = hdmi_core_ddc_edid(core, edid + 0x80, 1);
190 if (r)
191 return r;
192 l += 128;
193 }
194
195 return l;
196}
197
198static void hdmi_core_init(struct hdmi_core_video_config *video_cfg)
199{
200 DSSDBG("Enter hdmi_core_init\n");
201
202 /* video core */
203 video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
204 video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
205 video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
206 video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
207 video_cfg->hdmi_dvi = HDMI_DVI;
208 video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
209}
210
211static void hdmi_core_powerdown_disable(struct hdmi_core_data *core)
212{
213 DSSDBG("Enter hdmi_core_powerdown_disable\n");
214 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SYS_CTRL1, 0x0, 0, 0);
215}
216
217static void hdmi_core_swreset_release(struct hdmi_core_data *core)
218{
219 DSSDBG("Enter hdmi_core_swreset_release\n");
220 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x0, 0, 0);
221}
222
223static void hdmi_core_swreset_assert(struct hdmi_core_data *core)
224{
225 DSSDBG("Enter hdmi_core_swreset_assert\n");
226 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x1, 0, 0);
227}
228
229/* HDMI_CORE_VIDEO_CONFIG */
230static void hdmi_core_video_config(struct hdmi_core_data *core,
231 struct hdmi_core_video_config *cfg)
232{
233 u32 r = 0;
234 void __iomem *core_sys_base = core->base;
235 void __iomem *core_av_base = hdmi_av_base(core);
236
237 /* sys_ctrl1 default configuration not tunable */
238 r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1);
239 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
240 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
241 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS, 2, 2);
242 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE, 1, 1);
243 hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1, r);
244
245 REG_FLD_MOD(core_sys_base,
246 HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
247
248 /* Vid_Mode */
249 r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE);
250
251 /* dither truncation configuration */
252 if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
253 r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
254 r = FLD_MOD(r, 1, 5, 5);
255 } else {
256 r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
257 r = FLD_MOD(r, 0, 5, 5);
258 }
259 hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r);
260
261 /* HDMI_Ctrl */
262 r = hdmi_read_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL);
263 r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
264 r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
265 r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
266 hdmi_write_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL, r);
267
268 /* TMDS_CTRL */
269 REG_FLD_MOD(core_sys_base,
270 HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
271}
272
273static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core,
274 struct hdmi_avi_infoframe *frame)
275{
276 void __iomem *av_base = hdmi_av_base(core);
277 u8 data[HDMI_INFOFRAME_SIZE(AVI)];
278 int i;
279
280 hdmi_avi_infoframe_pack(frame, data, sizeof(data));
281
282 print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data,
283 HDMI_INFOFRAME_SIZE(AVI), false);
284
285 for (i = 0; i < sizeof(data); ++i) {
286 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_BASE + i * 4,
287 data[i]);
288 }
289}
290
291static void hdmi_core_av_packet_config(struct hdmi_core_data *core,
292 struct hdmi_core_packet_enable_repeat repeat_cfg)
293{
294 /* enable/repeat the infoframe */
295 hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL1,
296 (repeat_cfg.audio_pkt << 5) |
297 (repeat_cfg.audio_pkt_repeat << 4) |
298 (repeat_cfg.avi_infoframe << 1) |
299 (repeat_cfg.avi_infoframe_repeat));
300
301 /* enable/repeat the packet */
302 hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL2,
303 (repeat_cfg.gen_cntrl_pkt << 3) |
304 (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
305 (repeat_cfg.generic_pkt << 1) |
306 (repeat_cfg.generic_pkt_repeat));
307}
308
309void hdmi4_configure(struct hdmi_core_data *core,
310 struct hdmi_wp_data *wp, struct hdmi_config *cfg)
311{
312 /* HDMI */
313 struct omap_video_timings video_timing;
314 struct hdmi_video_format video_format;
315 /* HDMI core */
316 struct hdmi_core_video_config v_core_cfg;
317 struct hdmi_core_packet_enable_repeat repeat_cfg = { 0 };
318
319 hdmi_core_init(&v_core_cfg);
320
321 hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
322
323 hdmi_wp_video_config_timing(wp, &video_timing);
324
325 /* video config */
326 video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
327
328 hdmi_wp_video_config_format(wp, &video_format);
329
330 hdmi_wp_video_config_interface(wp, &video_timing);
331
332 /*
333 * configure core video part
334 * set software reset in the core
335 */
336 hdmi_core_swreset_assert(core);
337
338 /* power down off */
339 hdmi_core_powerdown_disable(core);
340
341 v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
342 v_core_cfg.hdmi_dvi = cfg->hdmi_dvi_mode;
343
344 hdmi_core_video_config(core, &v_core_cfg);
345
346 /* release software reset in the core */
347 hdmi_core_swreset_release(core);
348
349 if (cfg->hdmi_dvi_mode == HDMI_HDMI) {
350 hdmi_core_write_avi_infoframe(core, &cfg->infoframe);
351
352 /* enable/repeat the infoframe */
353 repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
354 repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
355 /* wakeup */
356 repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
357 repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
358 }
359
360 hdmi_core_av_packet_config(core, repeat_cfg);
361}
362
363void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
364{
365 int i;
366
367#define CORE_REG(i, name) name(i)
368#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
369 hdmi_read_reg(core->base, r))
370#define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\
371 hdmi_read_reg(hdmi_av_base(core), r))
372#define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
373 (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \
374 hdmi_read_reg(hdmi_av_base(core), CORE_REG(i, r)))
375
376 DUMPCORE(HDMI_CORE_SYS_VND_IDL);
377 DUMPCORE(HDMI_CORE_SYS_DEV_IDL);
378 DUMPCORE(HDMI_CORE_SYS_DEV_IDH);
379 DUMPCORE(HDMI_CORE_SYS_DEV_REV);
380 DUMPCORE(HDMI_CORE_SYS_SRST);
381 DUMPCORE(HDMI_CORE_SYS_SYS_CTRL1);
382 DUMPCORE(HDMI_CORE_SYS_SYS_STAT);
383 DUMPCORE(HDMI_CORE_SYS_SYS_CTRL3);
384 DUMPCORE(HDMI_CORE_SYS_DE_DLY);
385 DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
386 DUMPCORE(HDMI_CORE_SYS_DE_TOP);
387 DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
388 DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
389 DUMPCORE(HDMI_CORE_SYS_DE_LINL);
390 DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
391 DUMPCORE(HDMI_CORE_SYS_HRES_L);
392 DUMPCORE(HDMI_CORE_SYS_HRES_H);
393 DUMPCORE(HDMI_CORE_SYS_VRES_L);
394 DUMPCORE(HDMI_CORE_SYS_VRES_H);
395 DUMPCORE(HDMI_CORE_SYS_IADJUST);
396 DUMPCORE(HDMI_CORE_SYS_POLDETECT);
397 DUMPCORE(HDMI_CORE_SYS_HWIDTH1);
398 DUMPCORE(HDMI_CORE_SYS_HWIDTH2);
399 DUMPCORE(HDMI_CORE_SYS_VWIDTH);
400 DUMPCORE(HDMI_CORE_SYS_VID_CTRL);
401 DUMPCORE(HDMI_CORE_SYS_VID_ACEN);
402 DUMPCORE(HDMI_CORE_SYS_VID_MODE);
403 DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
404 DUMPCORE(HDMI_CORE_SYS_VID_BLANK3);
405 DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
406 DUMPCORE(HDMI_CORE_SYS_DC_HEADER);
407 DUMPCORE(HDMI_CORE_SYS_VID_DITHER);
408 DUMPCORE(HDMI_CORE_SYS_RGB2XVYCC_CT);
409 DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_LOW);
410 DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_UP);
411 DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_LOW);
412 DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_UP);
413 DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_LOW);
414 DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_UP);
415 DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_LOW);
416 DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_UP);
417 DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_LOW);
418 DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_UP);
419 DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_LOW);
420 DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_UP);
421 DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_LOW);
422 DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_UP);
423 DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_LOW);
424 DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_UP);
425 DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_LOW);
426 DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_UP);
427 DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_LOW);
428 DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_UP);
429 DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_LOW);
430 DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_UP);
431 DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_LOW);
432 DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_UP);
433 DUMPCORE(HDMI_CORE_SYS_INTR_STATE);
434 DUMPCORE(HDMI_CORE_SYS_INTR1);
435 DUMPCORE(HDMI_CORE_SYS_INTR2);
436 DUMPCORE(HDMI_CORE_SYS_INTR3);
437 DUMPCORE(HDMI_CORE_SYS_INTR4);
438 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK1);
439 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK2);
440 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK3);
441 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK4);
442 DUMPCORE(HDMI_CORE_SYS_INTR_CTRL);
443 DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL);
444
445 DUMPCORE(HDMI_CORE_DDC_ADDR);
446 DUMPCORE(HDMI_CORE_DDC_SEGM);
447 DUMPCORE(HDMI_CORE_DDC_OFFSET);
448 DUMPCORE(HDMI_CORE_DDC_COUNT1);
449 DUMPCORE(HDMI_CORE_DDC_COUNT2);
450 DUMPCORE(HDMI_CORE_DDC_STATUS);
451 DUMPCORE(HDMI_CORE_DDC_CMD);
452 DUMPCORE(HDMI_CORE_DDC_DATA);
453
454 DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL);
455 DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL);
456 DUMPCOREAV(HDMI_CORE_AV_N_SVAL1);
457 DUMPCOREAV(HDMI_CORE_AV_N_SVAL2);
458 DUMPCOREAV(HDMI_CORE_AV_N_SVAL3);
459 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1);
460 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2);
461 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3);
462 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1);
463 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2);
464 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3);
465 DUMPCOREAV(HDMI_CORE_AV_AUD_MODE);
466 DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL);
467 DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS);
468 DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S);
469 DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH);
470 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP);
471 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL);
472 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0);
473 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1);
474 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2);
475 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4);
476 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5);
477 DUMPCOREAV(HDMI_CORE_AV_ASRC);
478 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN);
479 DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL);
480 DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT);
481 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
482 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
483 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
484 DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL);
485 DUMPCOREAV(HDMI_CORE_AV_DPD);
486 DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1);
487 DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2);
488 DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE);
489 DUMPCOREAV(HDMI_CORE_AV_AVI_VERS);
490 DUMPCOREAV(HDMI_CORE_AV_AVI_LEN);
491 DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM);
492
493 for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++)
494 DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE);
495
496 DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE);
497 DUMPCOREAV(HDMI_CORE_AV_SPD_VERS);
498 DUMPCOREAV(HDMI_CORE_AV_SPD_LEN);
499 DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM);
500
501 for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++)
502 DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE);
503
504 DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE);
505 DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS);
506 DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN);
507 DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM);
508
509 for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++)
510 DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE);
511
512 DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE);
513 DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS);
514 DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN);
515 DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM);
516
517 for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++)
518 DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE);
519
520 for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++)
521 DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE);
522
523 DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1);
524
525 for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++)
526 DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE);
527
528 DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
529}
530
531static void hdmi_core_audio_config(struct hdmi_core_data *core,
532 struct hdmi_core_audio_config *cfg)
533{
534 u32 r;
535 void __iomem *av_base = hdmi_av_base(core);
536
537 /*
538 * Parameters for generation of Audio Clock Recovery packets
539 */
540 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
541 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
542 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
543
544 if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
545 REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
546 REG_FLD_MOD(av_base,
547 HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
548 REG_FLD_MOD(av_base,
549 HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
550 } else {
551 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
552 cfg->aud_par_busclk, 7, 0);
553 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
554 (cfg->aud_par_busclk >> 8), 7, 0);
555 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
556 (cfg->aud_par_busclk >> 16), 7, 0);
557 }
558
559 /* Set ACR clock divisor */
560 REG_FLD_MOD(av_base,
561 HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
562
563 r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
564 /*
565 * Use TMDS clock for ACR packets. For devices that use
566 * the MCLK, this is the first part of the MCLK initialization.
567 */
568 r = FLD_MOD(r, 0, 2, 2);
569
570 r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
571 r = FLD_MOD(r, cfg->cts_mode, 0, 0);
572 hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
573
574 /* For devices using MCLK, this completes its initialization. */
575 if (cfg->use_mclk)
576 REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2);
577
578 /* Override of SPDIF sample frequency with value in I2S_CHST4 */
579 REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
580 cfg->fs_override, 1, 1);
581
582 /*
583 * Set IEC-60958-3 channel status word. It is passed to the IP
584 * just as it is received. The user of the driver is responsible
585 * for its contents.
586 */
587 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0,
588 cfg->iec60958_cfg->status[0]);
589 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1,
590 cfg->iec60958_cfg->status[1]);
591 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2,
592 cfg->iec60958_cfg->status[2]);
593 /* yes, this is correct: status[3] goes to CHST4 register */
594 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4,
595 cfg->iec60958_cfg->status[3]);
596 /* yes, this is correct: status[4] goes to CHST5 register */
597 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5,
598 cfg->iec60958_cfg->status[4]);
599
600 /* set I2S parameters */
601 r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
602 r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
603 r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
604 r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
605 r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
606 r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
607 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
608
609 REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
610 cfg->i2s_cfg.in_length_bits, 3, 0);
611
612 /* Audio channels and mode parameters */
613 REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
614 r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE);
615 r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
616 r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
617 r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
618 r = FLD_MOD(r, cfg->en_spdif, 1, 1);
619 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
620
621 /* Audio channel mappings */
622 /* TODO: Make channel mapping dynamic. For now, map channels
623 * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as
624 * HDMI speaker order is different. See CEA-861 Section 6.6.2.
625 */
626 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78);
627 REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5);
628}
629
630static void hdmi_core_audio_infoframe_cfg(struct hdmi_core_data *core,
631 struct snd_cea_861_aud_if *info_aud)
632{
633 u8 sum = 0, checksum = 0;
634 void __iomem *av_base = hdmi_av_base(core);
635
636 /*
637 * Set audio info frame type, version and length as
638 * described in HDMI 1.4a Section 8.2.2 specification.
639 * Checksum calculation is defined in Section 5.3.5.
640 */
641 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84);
642 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01);
643 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
644 sum += 0x84 + 0x001 + 0x00a;
645
646 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0),
647 info_aud->db1_ct_cc);
648 sum += info_aud->db1_ct_cc;
649
650 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1),
651 info_aud->db2_sf_ss);
652 sum += info_aud->db2_sf_ss;
653
654 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3);
655 sum += info_aud->db3;
656
657 /*
658 * The OMAP HDMI IP requires to use the 8-channel channel code when
659 * transmitting more than two channels.
660 */
661 if (info_aud->db4_ca != 0x00)
662 info_aud->db4_ca = 0x13;
663
664 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca);
665 sum += info_aud->db4_ca;
666
667 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4),
668 info_aud->db5_dminh_lsv);
669 sum += info_aud->db5_dminh_lsv;
670
671 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
672 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
673 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
674 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
675 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
676
677 checksum = 0x100 - sum;
678 hdmi_write_reg(av_base,
679 HDMI_CORE_AV_AUDIO_CHSUM, checksum);
680
681 /*
682 * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
683 * is available.
684 */
685}
686
687int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
688 struct omap_dss_audio *audio, u32 pclk)
689{
690 struct hdmi_audio_format audio_format;
691 struct hdmi_audio_dma audio_dma;
692 struct hdmi_core_audio_config acore;
693 int err, n, cts, channel_count;
694 unsigned int fs_nr;
695 bool word_length_16b = false;
696
697 if (!audio || !audio->iec || !audio->cea || !core)
698 return -EINVAL;
699
700 acore.iec60958_cfg = audio->iec;
701 /*
702 * In the IEC-60958 status word, check if the audio sample word length
703 * is 16-bit as several optimizations can be performed in such case.
704 */
705 if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
706 if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
707 word_length_16b = true;
708
709 /* I2S configuration. See Phillips' specification */
710 if (word_length_16b)
711 acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
712 else
713 acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
714 /*
715 * The I2S input word length is twice the lenght given in the IEC-60958
716 * status word. If the word size is greater than
717 * 20 bits, increment by one.
718 */
719 acore.i2s_cfg.in_length_bits = audio->iec->status[4]
720 & IEC958_AES4_CON_WORDLEN;
721 if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
722 acore.i2s_cfg.in_length_bits++;
723 acore.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
724 acore.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
725 acore.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
726 acore.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
727
728 /* convert sample frequency to a number */
729 switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
730 case IEC958_AES3_CON_FS_32000:
731 fs_nr = 32000;
732 break;
733 case IEC958_AES3_CON_FS_44100:
734 fs_nr = 44100;
735 break;
736 case IEC958_AES3_CON_FS_48000:
737 fs_nr = 48000;
738 break;
739 case IEC958_AES3_CON_FS_88200:
740 fs_nr = 88200;
741 break;
742 case IEC958_AES3_CON_FS_96000:
743 fs_nr = 96000;
744 break;
745 case IEC958_AES3_CON_FS_176400:
746 fs_nr = 176400;
747 break;
748 case IEC958_AES3_CON_FS_192000:
749 fs_nr = 192000;
750 break;
751 default:
752 return -EINVAL;
753 }
754
755 err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
756
757 /* Audio clock regeneration settings */
758 acore.n = n;
759 acore.cts = cts;
760 if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
761 acore.aud_par_busclk = 0;
762 acore.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
763 acore.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
764 } else {
765 acore.aud_par_busclk = (((128 * 31) - 1) << 8);
766 acore.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
767 acore.use_mclk = true;
768 }
769
770 if (acore.use_mclk)
771 acore.mclk_mode = HDMI_AUDIO_MCLK_128FS;
772
773 /* Audio channels settings */
774 channel_count = (audio->cea->db1_ct_cc &
775 CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
776
777 switch (channel_count) {
778 case 2:
779 audio_format.active_chnnls_msk = 0x03;
780 break;
781 case 3:
782 audio_format.active_chnnls_msk = 0x07;
783 break;
784 case 4:
785 audio_format.active_chnnls_msk = 0x0f;
786 break;
787 case 5:
788 audio_format.active_chnnls_msk = 0x1f;
789 break;
790 case 6:
791 audio_format.active_chnnls_msk = 0x3f;
792 break;
793 case 7:
794 audio_format.active_chnnls_msk = 0x7f;
795 break;
796 case 8:
797 audio_format.active_chnnls_msk = 0xff;
798 break;
799 default:
800 return -EINVAL;
801 }
802
803 /*
804 * the HDMI IP needs to enable four stereo channels when transmitting
805 * more than 2 audio channels. Similarly, the channel count in the
806 * Audio InfoFrame has to match the sample_present bits (some channels
807 * are padded with zeroes)
808 */
809 if (channel_count == 2) {
810 audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
811 acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
812 acore.layout = HDMI_AUDIO_LAYOUT_2CH;
813 } else {
814 audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
815 acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
816 HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
817 HDMI_AUDIO_I2S_SD3_EN;
818 acore.layout = HDMI_AUDIO_LAYOUT_8CH;
819 audio->cea->db1_ct_cc = 7;
820 }
821
822 acore.en_spdif = false;
823 /* use sample frequency from channel status word */
824 acore.fs_override = true;
825 /* enable ACR packets */
826 acore.en_acr_pkt = true;
827 /* disable direct streaming digital audio */
828 acore.en_dsd_audio = false;
829 /* use parallel audio interface */
830 acore.en_parallel_aud_input = true;
831
832 /* DMA settings */
833 if (word_length_16b)
834 audio_dma.transfer_size = 0x10;
835 else
836 audio_dma.transfer_size = 0x20;
837 audio_dma.block_size = 0xC0;
838 audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
839 audio_dma.fifo_threshold = 0x20; /* in number of samples */
840
841 /* audio FIFO format settings */
842 if (word_length_16b) {
843 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
844 audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
845 audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
846 } else {
847 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
848 audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
849 audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
850 }
851 audio_format.type = HDMI_AUDIO_TYPE_LPCM;
852 audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
853 /* disable start/stop signals of IEC 60958 blocks */
854 audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
855
856 /* configure DMA and audio FIFO format*/
857 hdmi_wp_audio_config_dma(wp, &audio_dma);
858 hdmi_wp_audio_config_format(wp, &audio_format);
859
860 /* configure the core*/
861 hdmi_core_audio_config(core, &acore);
862
863 /* configure CEA 861 audio infoframe*/
864 hdmi_core_audio_infoframe_cfg(core, audio->cea);
865
866 return 0;
867}
868
869int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
870{
871 REG_FLD_MOD(hdmi_av_base(core),
872 HDMI_CORE_AV_AUD_MODE, true, 0, 0);
873
874 hdmi_wp_audio_core_req_enable(wp, true);
875
876 return 0;
877}
878
879void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
880{
881 REG_FLD_MOD(hdmi_av_base(core),
882 HDMI_CORE_AV_AUD_MODE, false, 0, 0);
883
884 hdmi_wp_audio_core_req_enable(wp, false);
885}
886
887int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
888{
889 struct resource *res;
890
891 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
892 if (!res) {
893 DSSERR("can't get CORE mem resource\n");
894 return -EINVAL;
895 }
896
897 core->base = devm_ioremap_resource(&pdev->dev, res);
898 if (IS_ERR(core->base)) {
899 DSSERR("can't ioremap CORE\n");
900 return PTR_ERR(core->base);
901 }
902
903 return 0;
904}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
new file mode 100644
index 000000000000..a069f96ec6f6
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
@@ -0,0 +1,273 @@
1/*
2 * HDMI header definition for OMAP4 HDMI core IP
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _HDMI4_CORE_H_
20#define _HDMI4_CORE_H_
21
22#include "hdmi.h"
23
24/* OMAP4 HDMI IP Core System */
25
26#define HDMI_CORE_SYS_VND_IDL 0x0
27#define HDMI_CORE_SYS_DEV_IDL 0x8
28#define HDMI_CORE_SYS_DEV_IDH 0xC
29#define HDMI_CORE_SYS_DEV_REV 0x10
30#define HDMI_CORE_SYS_SRST 0x14
31#define HDMI_CORE_SYS_SYS_CTRL1 0x20
32#define HDMI_CORE_SYS_SYS_STAT 0x24
33#define HDMI_CORE_SYS_SYS_CTRL3 0x28
34#define HDMI_CORE_SYS_DCTL 0x34
35#define HDMI_CORE_SYS_DE_DLY 0xC8
36#define HDMI_CORE_SYS_DE_CTRL 0xCC
37#define HDMI_CORE_SYS_DE_TOP 0xD0
38#define HDMI_CORE_SYS_DE_CNTL 0xD8
39#define HDMI_CORE_SYS_DE_CNTH 0xDC
40#define HDMI_CORE_SYS_DE_LINL 0xE0
41#define HDMI_CORE_SYS_DE_LINH_1 0xE4
42#define HDMI_CORE_SYS_HRES_L 0xE8
43#define HDMI_CORE_SYS_HRES_H 0xEC
44#define HDMI_CORE_SYS_VRES_L 0xF0
45#define HDMI_CORE_SYS_VRES_H 0xF4
46#define HDMI_CORE_SYS_IADJUST 0xF8
47#define HDMI_CORE_SYS_POLDETECT 0xFC
48#define HDMI_CORE_SYS_HWIDTH1 0x110
49#define HDMI_CORE_SYS_HWIDTH2 0x114
50#define HDMI_CORE_SYS_VWIDTH 0x11C
51#define HDMI_CORE_SYS_VID_CTRL 0x120
52#define HDMI_CORE_SYS_VID_ACEN 0x124
53#define HDMI_CORE_SYS_VID_MODE 0x128
54#define HDMI_CORE_SYS_VID_BLANK1 0x12C
55#define HDMI_CORE_SYS_VID_BLANK2 0x130
56#define HDMI_CORE_SYS_VID_BLANK3 0x134
57#define HDMI_CORE_SYS_DC_HEADER 0x138
58#define HDMI_CORE_SYS_VID_DITHER 0x13C
59#define HDMI_CORE_SYS_RGB2XVYCC_CT 0x140
60#define HDMI_CORE_SYS_R2Y_COEFF_LOW 0x144
61#define HDMI_CORE_SYS_R2Y_COEFF_UP 0x148
62#define HDMI_CORE_SYS_G2Y_COEFF_LOW 0x14C
63#define HDMI_CORE_SYS_G2Y_COEFF_UP 0x150
64#define HDMI_CORE_SYS_B2Y_COEFF_LOW 0x154
65#define HDMI_CORE_SYS_B2Y_COEFF_UP 0x158
66#define HDMI_CORE_SYS_R2CB_COEFF_LOW 0x15C
67#define HDMI_CORE_SYS_R2CB_COEFF_UP 0x160
68#define HDMI_CORE_SYS_G2CB_COEFF_LOW 0x164
69#define HDMI_CORE_SYS_G2CB_COEFF_UP 0x168
70#define HDMI_CORE_SYS_B2CB_COEFF_LOW 0x16C
71#define HDMI_CORE_SYS_B2CB_COEFF_UP 0x170
72#define HDMI_CORE_SYS_R2CR_COEFF_LOW 0x174
73#define HDMI_CORE_SYS_R2CR_COEFF_UP 0x178
74#define HDMI_CORE_SYS_G2CR_COEFF_LOW 0x17C
75#define HDMI_CORE_SYS_G2CR_COEFF_UP 0x180
76#define HDMI_CORE_SYS_B2CR_COEFF_LOW 0x184
77#define HDMI_CORE_SYS_B2CR_COEFF_UP 0x188
78#define HDMI_CORE_SYS_RGB_OFFSET_LOW 0x18C
79#define HDMI_CORE_SYS_RGB_OFFSET_UP 0x190
80#define HDMI_CORE_SYS_Y_OFFSET_LOW 0x194
81#define HDMI_CORE_SYS_Y_OFFSET_UP 0x198
82#define HDMI_CORE_SYS_CBCR_OFFSET_LOW 0x19C
83#define HDMI_CORE_SYS_CBCR_OFFSET_UP 0x1A0
84#define HDMI_CORE_SYS_INTR_STATE 0x1C0
85#define HDMI_CORE_SYS_INTR1 0x1C4
86#define HDMI_CORE_SYS_INTR2 0x1C8
87#define HDMI_CORE_SYS_INTR3 0x1CC
88#define HDMI_CORE_SYS_INTR4 0x1D0
89#define HDMI_CORE_SYS_INTR_UNMASK1 0x1D4
90#define HDMI_CORE_SYS_INTR_UNMASK2 0x1D8
91#define HDMI_CORE_SYS_INTR_UNMASK3 0x1DC
92#define HDMI_CORE_SYS_INTR_UNMASK4 0x1E0
93#define HDMI_CORE_SYS_INTR_CTRL 0x1E4
94#define HDMI_CORE_SYS_TMDS_CTRL 0x208
95
96/* value definitions for HDMI_CORE_SYS_SYS_CTRL1 fields */
97#define HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC 0x1
98#define HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC 0x1
99#define HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS 0x1
100#define HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE 0x1
101
102/* HDMI DDC E-DID */
103#define HDMI_CORE_DDC_ADDR 0x3B4
104#define HDMI_CORE_DDC_SEGM 0x3B8
105#define HDMI_CORE_DDC_OFFSET 0x3BC
106#define HDMI_CORE_DDC_COUNT1 0x3C0
107#define HDMI_CORE_DDC_COUNT2 0x3C4
108#define HDMI_CORE_DDC_STATUS 0x3C8
109#define HDMI_CORE_DDC_CMD 0x3CC
110#define HDMI_CORE_DDC_DATA 0x3D0
111
112/* HDMI IP Core Audio Video */
113
114#define HDMI_CORE_AV_ACR_CTRL 0x4
115#define HDMI_CORE_AV_FREQ_SVAL 0x8
116#define HDMI_CORE_AV_N_SVAL1 0xC
117#define HDMI_CORE_AV_N_SVAL2 0x10
118#define HDMI_CORE_AV_N_SVAL3 0x14
119#define HDMI_CORE_AV_CTS_SVAL1 0x18
120#define HDMI_CORE_AV_CTS_SVAL2 0x1C
121#define HDMI_CORE_AV_CTS_SVAL3 0x20
122#define HDMI_CORE_AV_CTS_HVAL1 0x24
123#define HDMI_CORE_AV_CTS_HVAL2 0x28
124#define HDMI_CORE_AV_CTS_HVAL3 0x2C
125#define HDMI_CORE_AV_AUD_MODE 0x50
126#define HDMI_CORE_AV_SPDIF_CTRL 0x54
127#define HDMI_CORE_AV_HW_SPDIF_FS 0x60
128#define HDMI_CORE_AV_SWAP_I2S 0x64
129#define HDMI_CORE_AV_SPDIF_ERTH 0x6C
130#define HDMI_CORE_AV_I2S_IN_MAP 0x70
131#define HDMI_CORE_AV_I2S_IN_CTRL 0x74
132#define HDMI_CORE_AV_I2S_CHST0 0x78
133#define HDMI_CORE_AV_I2S_CHST1 0x7C
134#define HDMI_CORE_AV_I2S_CHST2 0x80
135#define HDMI_CORE_AV_I2S_CHST4 0x84
136#define HDMI_CORE_AV_I2S_CHST5 0x88
137#define HDMI_CORE_AV_ASRC 0x8C
138#define HDMI_CORE_AV_I2S_IN_LEN 0x90
139#define HDMI_CORE_AV_HDMI_CTRL 0xBC
140#define HDMI_CORE_AV_AUDO_TXSTAT 0xC0
141#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC
142#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0
143#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4
144#define HDMI_CORE_AV_TEST_TXCTRL 0xF0
145#define HDMI_CORE_AV_DPD 0xF4
146#define HDMI_CORE_AV_PB_CTRL1 0xF8
147#define HDMI_CORE_AV_PB_CTRL2 0xFC
148#define HDMI_CORE_AV_AVI_BASE 0x100
149#define HDMI_CORE_AV_AVI_TYPE 0x100
150#define HDMI_CORE_AV_AVI_VERS 0x104
151#define HDMI_CORE_AV_AVI_LEN 0x108
152#define HDMI_CORE_AV_AVI_CHSUM 0x10C
153#define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110)
154#define HDMI_CORE_AV_SPD_TYPE 0x180
155#define HDMI_CORE_AV_SPD_VERS 0x184
156#define HDMI_CORE_AV_SPD_LEN 0x188
157#define HDMI_CORE_AV_SPD_CHSUM 0x18C
158#define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190)
159#define HDMI_CORE_AV_AUDIO_TYPE 0x200
160#define HDMI_CORE_AV_AUDIO_VERS 0x204
161#define HDMI_CORE_AV_AUDIO_LEN 0x208
162#define HDMI_CORE_AV_AUDIO_CHSUM 0x20C
163#define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210)
164#define HDMI_CORE_AV_MPEG_TYPE 0x280
165#define HDMI_CORE_AV_MPEG_VERS 0x284
166#define HDMI_CORE_AV_MPEG_LEN 0x288
167#define HDMI_CORE_AV_MPEG_CHSUM 0x28C
168#define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290)
169#define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300)
170#define HDMI_CORE_AV_CP_BYTE1 0x37C
171#define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380)
172#define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC
173
174#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4
175#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4
176#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4
177#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4
178
179#define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15
180#define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27
181#define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10
182#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27
183#define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31
184#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31
185
186enum hdmi_core_inputbus_width {
187 HDMI_INPUT_8BIT = 0,
188 HDMI_INPUT_10BIT = 1,
189 HDMI_INPUT_12BIT = 2
190};
191
192enum hdmi_core_dither_trunc {
193 HDMI_OUTPUTTRUNCATION_8BIT = 0,
194 HDMI_OUTPUTTRUNCATION_10BIT = 1,
195 HDMI_OUTPUTTRUNCATION_12BIT = 2,
196 HDMI_OUTPUTDITHER_8BIT = 3,
197 HDMI_OUTPUTDITHER_10BIT = 4,
198 HDMI_OUTPUTDITHER_12BIT = 5
199};
200
201enum hdmi_core_deepcolor_ed {
202 HDMI_DEEPCOLORPACKECTDISABLE = 0,
203 HDMI_DEEPCOLORPACKECTENABLE = 1
204};
205
206enum hdmi_core_packet_mode {
207 HDMI_PACKETMODERESERVEDVALUE = 0,
208 HDMI_PACKETMODE24BITPERPIXEL = 4,
209 HDMI_PACKETMODE30BITPERPIXEL = 5,
210 HDMI_PACKETMODE36BITPERPIXEL = 6,
211 HDMI_PACKETMODE48BITPERPIXEL = 7
212};
213
214enum hdmi_core_tclkselclkmult {
215 HDMI_FPLL05IDCK = 0,
216 HDMI_FPLL10IDCK = 1,
217 HDMI_FPLL20IDCK = 2,
218 HDMI_FPLL40IDCK = 3
219};
220
221enum hdmi_core_packet_ctrl {
222 HDMI_PACKETENABLE = 1,
223 HDMI_PACKETDISABLE = 0,
224 HDMI_PACKETREPEATON = 1,
225 HDMI_PACKETREPEATOFF = 0
226};
227
228enum hdmi_audio_i2s_config {
229 HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
230 HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
231 HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
232 HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
233 HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
234 HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
235 HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
236 HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
237 HDMI_AUDIO_I2S_SD0_EN = 1,
238 HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
239 HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
240 HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
241};
242
243struct hdmi_core_video_config {
244 enum hdmi_core_inputbus_width ip_bus_width;
245 enum hdmi_core_dither_trunc op_dither_truc;
246 enum hdmi_core_deepcolor_ed deep_color_pkt;
247 enum hdmi_core_packet_mode pkt_mode;
248 enum hdmi_core_hdmi_dvi hdmi_dvi;
249 enum hdmi_core_tclkselclkmult tclk_sel_clkmult;
250};
251
252struct hdmi_core_packet_enable_repeat {
253 u32 audio_pkt;
254 u32 audio_pkt_repeat;
255 u32 avi_infoframe;
256 u32 avi_infoframe_repeat;
257 u32 gen_cntrl_pkt;
258 u32 gen_cntrl_pkt_repeat;
259 u32 generic_pkt;
260 u32 generic_pkt_repeat;
261};
262
263int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
264void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
265 struct hdmi_config *cfg);
266void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
267int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
268
269int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
270void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
271int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
272 struct omap_dss_audio *audio, u32 pclk);
273#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
new file mode 100644
index 000000000000..a955a2c4c061
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -0,0 +1,876 @@
1/*
2 * HDMI driver for OMAP5
3 *
4 * Copyright (C) 2014 Texas Instruments Incorporated
5 *
6 * Authors:
7 * Yong Zhi
8 * Mythri pk
9 * Archit Taneja <archit@ti.com>
10 * Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25#define DSS_SUBSYS_NAME "HDMI"
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/err.h>
30#include <linux/io.h>
31#include <linux/interrupt.h>
32#include <linux/mutex.h>
33#include <linux/delay.h>
34#include <linux/string.h>
35#include <linux/platform_device.h>
36#include <linux/pm_runtime.h>
37#include <linux/clk.h>
38#include <linux/gpio.h>
39#include <linux/regulator/consumer.h>
40#include <linux/component.h>
41#include <video/omapdss.h>
42#include <sound/omap-hdmi-audio.h>
43
44#include "hdmi5_core.h"
45#include "dss.h"
46#include "dss_features.h"
47
48static struct omap_hdmi hdmi;
49
50static int hdmi_runtime_get(void)
51{
52 int r;
53
54 DSSDBG("hdmi_runtime_get\n");
55
56 r = pm_runtime_get_sync(&hdmi.pdev->dev);
57 WARN_ON(r < 0);
58 if (r < 0)
59 return r;
60
61 return 0;
62}
63
64static void hdmi_runtime_put(void)
65{
66 int r;
67
68 DSSDBG("hdmi_runtime_put\n");
69
70 r = pm_runtime_put_sync(&hdmi.pdev->dev);
71 WARN_ON(r < 0 && r != -ENOSYS);
72}
73
74static irqreturn_t hdmi_irq_handler(int irq, void *data)
75{
76 struct hdmi_wp_data *wp = data;
77 u32 irqstatus;
78
79 irqstatus = hdmi_wp_get_irqstatus(wp);
80 hdmi_wp_set_irqstatus(wp, irqstatus);
81
82 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
83 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
84 u32 v;
85 /*
86 * If we get both connect and disconnect interrupts at the same
87 * time, turn off the PHY, clear interrupts, and restart, which
88 * raises connect interrupt if a cable is connected, or nothing
89 * if cable is not connected.
90 */
91
92 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
93
94 /*
95 * We always get bogus CONNECT & DISCONNECT interrupts when
96 * setting the PHY to LDOON. To ignore those, we force the RXDET
97 * line to 0 until the PHY power state has been changed.
98 */
99 v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
100 v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
101 v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
102 hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
103
104 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
105 HDMI_IRQ_LINK_DISCONNECT);
106
107 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
108
109 REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
110
111 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
112 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
113 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
114 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
115 }
116
117 return IRQ_HANDLED;
118}
119
120static int hdmi_init_regulator(void)
121{
122 int r;
123 struct regulator *reg;
124
125 if (hdmi.vdda_reg != NULL)
126 return 0;
127
128 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
129 if (IS_ERR(reg)) {
130 DSSERR("can't get VDDA regulator\n");
131 return PTR_ERR(reg);
132 }
133
134 if (regulator_can_change_voltage(reg)) {
135 r = regulator_set_voltage(reg, 1800000, 1800000);
136 if (r) {
137 devm_regulator_put(reg);
138 DSSWARN("can't set the regulator voltage\n");
139 return r;
140 }
141 }
142
143 hdmi.vdda_reg = reg;
144
145 return 0;
146}
147
148static int hdmi_power_on_core(struct omap_dss_device *dssdev)
149{
150 int r;
151
152 r = regulator_enable(hdmi.vdda_reg);
153 if (r)
154 return r;
155
156 r = hdmi_runtime_get();
157 if (r)
158 goto err_runtime_get;
159
160 /* Make selection of HDMI in DSS */
161 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
162
163 hdmi.core_enabled = true;
164
165 return 0;
166
167err_runtime_get:
168 regulator_disable(hdmi.vdda_reg);
169
170 return r;
171}
172
173static void hdmi_power_off_core(struct omap_dss_device *dssdev)
174{
175 hdmi.core_enabled = false;
176
177 hdmi_runtime_put();
178 regulator_disable(hdmi.vdda_reg);
179}
180
181static int hdmi_power_on_full(struct omap_dss_device *dssdev)
182{
183 int r;
184 struct omap_video_timings *p;
185 struct omap_overlay_manager *mgr = hdmi.output.manager;
186 struct dss_pll_clock_info hdmi_cinfo = { 0 };
187
188 r = hdmi_power_on_core(dssdev);
189 if (r)
190 return r;
191
192 p = &hdmi.cfg.timings;
193
194 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
195
196 hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
197
198 /* disable and clear irqs */
199 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
200 hdmi_wp_set_irqstatus(&hdmi.wp,
201 hdmi_wp_get_irqstatus(&hdmi.wp));
202
203 r = dss_pll_enable(&hdmi.pll.pll);
204 if (r) {
205 DSSERR("Failed to enable PLL\n");
206 goto err_pll_enable;
207 }
208
209 r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
210 if (r) {
211 DSSERR("Failed to configure PLL\n");
212 goto err_pll_cfg;
213 }
214
215 r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
216 hdmi_cinfo.clkout[0]);
217 if (r) {
218 DSSDBG("Failed to start PHY\n");
219 goto err_phy_cfg;
220 }
221
222 r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
223 if (r)
224 goto err_phy_pwr;
225
226 hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
227
228 /* bypass TV gamma table */
229 dispc_enable_gamma_table(0);
230
231 /* tv size */
232 dss_mgr_set_timings(mgr, p);
233
234 r = hdmi_wp_video_start(&hdmi.wp);
235 if (r)
236 goto err_vid_enable;
237
238 r = dss_mgr_enable(mgr);
239 if (r)
240 goto err_mgr_enable;
241
242 hdmi_wp_set_irqenable(&hdmi.wp,
243 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
244
245 return 0;
246
247err_mgr_enable:
248 hdmi_wp_video_stop(&hdmi.wp);
249err_vid_enable:
250 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
251err_phy_pwr:
252err_phy_cfg:
253err_pll_cfg:
254 dss_pll_disable(&hdmi.pll.pll);
255err_pll_enable:
256 hdmi_power_off_core(dssdev);
257 return -EIO;
258}
259
260static void hdmi_power_off_full(struct omap_dss_device *dssdev)
261{
262 struct omap_overlay_manager *mgr = hdmi.output.manager;
263
264 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
265
266 dss_mgr_disable(mgr);
267
268 hdmi_wp_video_stop(&hdmi.wp);
269
270 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
271
272 dss_pll_disable(&hdmi.pll.pll);
273
274 hdmi_power_off_core(dssdev);
275}
276
277static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
278 struct omap_video_timings *timings)
279{
280 struct omap_dss_device *out = &hdmi.output;
281
282 /* TODO: proper interlace support */
283 if (timings->interlace)
284 return -EINVAL;
285
286 if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
287 return -EINVAL;
288
289 return 0;
290}
291
292static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
293 struct omap_video_timings *timings)
294{
295 mutex_lock(&hdmi.lock);
296
297 hdmi.cfg.timings = *timings;
298
299 dispc_set_tv_pclk(timings->pixelclock);
300
301 mutex_unlock(&hdmi.lock);
302}
303
304static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
305 struct omap_video_timings *timings)
306{
307 *timings = hdmi.cfg.timings;
308}
309
310static void hdmi_dump_regs(struct seq_file *s)
311{
312 mutex_lock(&hdmi.lock);
313
314 if (hdmi_runtime_get()) {
315 mutex_unlock(&hdmi.lock);
316 return;
317 }
318
319 hdmi_wp_dump(&hdmi.wp, s);
320 hdmi_pll_dump(&hdmi.pll, s);
321 hdmi_phy_dump(&hdmi.phy, s);
322 hdmi5_core_dump(&hdmi.core, s);
323
324 hdmi_runtime_put();
325 mutex_unlock(&hdmi.lock);
326}
327
328static int read_edid(u8 *buf, int len)
329{
330 int r;
331 int idlemode;
332
333 mutex_lock(&hdmi.lock);
334
335 r = hdmi_runtime_get();
336 BUG_ON(r);
337
338 idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
339 /* No-idle mode */
340 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
341
342 r = hdmi5_read_edid(&hdmi.core, buf, len);
343
344 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
345
346 hdmi_runtime_put();
347 mutex_unlock(&hdmi.lock);
348
349 return r;
350}
351
352static void hdmi_start_audio_stream(struct omap_hdmi *hd)
353{
354 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
355 hdmi_wp_audio_enable(&hd->wp, true);
356 hdmi_wp_audio_core_req_enable(&hd->wp, true);
357}
358
359static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
360{
361 hdmi_wp_audio_core_req_enable(&hd->wp, false);
362 hdmi_wp_audio_enable(&hd->wp, false);
363 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
364}
365
366static int hdmi_display_enable(struct omap_dss_device *dssdev)
367{
368 struct omap_dss_device *out = &hdmi.output;
369 unsigned long flags;
370 int r = 0;
371
372 DSSDBG("ENTER hdmi_display_enable\n");
373
374 mutex_lock(&hdmi.lock);
375
376 if (out->manager == NULL) {
377 DSSERR("failed to enable display: no output/manager\n");
378 r = -ENODEV;
379 goto err0;
380 }
381
382 r = hdmi_power_on_full(dssdev);
383 if (r) {
384 DSSERR("failed to power on device\n");
385 goto err0;
386 }
387
388 if (hdmi.audio_configured) {
389 r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
390 hdmi.cfg.timings.pixelclock);
391 if (r) {
392 DSSERR("Error restoring audio configuration: %d", r);
393 hdmi.audio_abort_cb(&hdmi.pdev->dev);
394 hdmi.audio_configured = false;
395 }
396 }
397
398 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
399 if (hdmi.audio_configured && hdmi.audio_playing)
400 hdmi_start_audio_stream(&hdmi);
401 hdmi.display_enabled = true;
402 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
403
404 mutex_unlock(&hdmi.lock);
405 return 0;
406
407err0:
408 mutex_unlock(&hdmi.lock);
409 return r;
410}
411
412static void hdmi_display_disable(struct omap_dss_device *dssdev)
413{
414 unsigned long flags;
415
416 DSSDBG("Enter hdmi_display_disable\n");
417
418 mutex_lock(&hdmi.lock);
419
420 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
421 hdmi_stop_audio_stream(&hdmi);
422 hdmi.display_enabled = false;
423 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
424
425 hdmi_power_off_full(dssdev);
426
427 mutex_unlock(&hdmi.lock);
428}
429
430static int hdmi_core_enable(struct omap_dss_device *dssdev)
431{
432 int r = 0;
433
434 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
435
436 mutex_lock(&hdmi.lock);
437
438 r = hdmi_power_on_core(dssdev);
439 if (r) {
440 DSSERR("failed to power on device\n");
441 goto err0;
442 }
443
444 mutex_unlock(&hdmi.lock);
445 return 0;
446
447err0:
448 mutex_unlock(&hdmi.lock);
449 return r;
450}
451
452static void hdmi_core_disable(struct omap_dss_device *dssdev)
453{
454 DSSDBG("Enter omapdss_hdmi_core_disable\n");
455
456 mutex_lock(&hdmi.lock);
457
458 hdmi_power_off_core(dssdev);
459
460 mutex_unlock(&hdmi.lock);
461}
462
463static int hdmi_connect(struct omap_dss_device *dssdev,
464 struct omap_dss_device *dst)
465{
466 struct omap_overlay_manager *mgr;
467 int r;
468
469 r = hdmi_init_regulator();
470 if (r)
471 return r;
472
473 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
474 if (!mgr)
475 return -ENODEV;
476
477 r = dss_mgr_connect(mgr, dssdev);
478 if (r)
479 return r;
480
481 r = omapdss_output_set_device(dssdev, dst);
482 if (r) {
483 DSSERR("failed to connect output to new device: %s\n",
484 dst->name);
485 dss_mgr_disconnect(mgr, dssdev);
486 return r;
487 }
488
489 return 0;
490}
491
492static void hdmi_disconnect(struct omap_dss_device *dssdev,
493 struct omap_dss_device *dst)
494{
495 WARN_ON(dst != dssdev->dst);
496
497 if (dst != dssdev->dst)
498 return;
499
500 omapdss_output_unset_device(dssdev);
501
502 if (dssdev->manager)
503 dss_mgr_disconnect(dssdev->manager, dssdev);
504}
505
506static int hdmi_read_edid(struct omap_dss_device *dssdev,
507 u8 *edid, int len)
508{
509 bool need_enable;
510 int r;
511
512 need_enable = hdmi.core_enabled == false;
513
514 if (need_enable) {
515 r = hdmi_core_enable(dssdev);
516 if (r)
517 return r;
518 }
519
520 r = read_edid(edid, len);
521
522 if (need_enable)
523 hdmi_core_disable(dssdev);
524
525 return r;
526}
527
528static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
529 const struct hdmi_avi_infoframe *avi)
530{
531 hdmi.cfg.infoframe = *avi;
532 return 0;
533}
534
535static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
536 bool hdmi_mode)
537{
538 hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
539 return 0;
540}
541
542static const struct omapdss_hdmi_ops hdmi_ops = {
543 .connect = hdmi_connect,
544 .disconnect = hdmi_disconnect,
545
546 .enable = hdmi_display_enable,
547 .disable = hdmi_display_disable,
548
549 .check_timings = hdmi_display_check_timing,
550 .set_timings = hdmi_display_set_timing,
551 .get_timings = hdmi_display_get_timings,
552
553 .read_edid = hdmi_read_edid,
554 .set_infoframe = hdmi_set_infoframe,
555 .set_hdmi_mode = hdmi_set_hdmi_mode,
556};
557
558static void hdmi_init_output(struct platform_device *pdev)
559{
560 struct omap_dss_device *out = &hdmi.output;
561
562 out->dev = &pdev->dev;
563 out->id = OMAP_DSS_OUTPUT_HDMI;
564 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
565 out->name = "hdmi.0";
566 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
567 out->ops.hdmi = &hdmi_ops;
568 out->owner = THIS_MODULE;
569
570 omapdss_register_output(out);
571}
572
573static void hdmi_uninit_output(struct platform_device *pdev)
574{
575 struct omap_dss_device *out = &hdmi.output;
576
577 omapdss_unregister_output(out);
578}
579
580static int hdmi_probe_of(struct platform_device *pdev)
581{
582 struct device_node *node = pdev->dev.of_node;
583 struct device_node *ep;
584 int r;
585
586 ep = omapdss_of_get_first_endpoint(node);
587 if (!ep)
588 return 0;
589
590 r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
591 if (r)
592 goto err;
593
594 of_node_put(ep);
595 return 0;
596
597err:
598 of_node_put(ep);
599 return r;
600}
601
602/* Audio callbacks */
603static int hdmi_audio_startup(struct device *dev,
604 void (*abort_cb)(struct device *dev))
605{
606 struct omap_hdmi *hd = dev_get_drvdata(dev);
607 int ret = 0;
608
609 mutex_lock(&hd->lock);
610
611 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
612 ret = -EPERM;
613 goto out;
614 }
615
616 hd->audio_abort_cb = abort_cb;
617
618out:
619 mutex_unlock(&hd->lock);
620
621 return ret;
622}
623
624static int hdmi_audio_shutdown(struct device *dev)
625{
626 struct omap_hdmi *hd = dev_get_drvdata(dev);
627
628 mutex_lock(&hd->lock);
629 hd->audio_abort_cb = NULL;
630 hd->audio_configured = false;
631 hd->audio_playing = false;
632 mutex_unlock(&hd->lock);
633
634 return 0;
635}
636
637static int hdmi_audio_start(struct device *dev)
638{
639 struct omap_hdmi *hd = dev_get_drvdata(dev);
640 unsigned long flags;
641
642 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
643
644 spin_lock_irqsave(&hd->audio_playing_lock, flags);
645
646 if (hd->display_enabled)
647 hdmi_start_audio_stream(hd);
648 hd->audio_playing = true;
649
650 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
651 return 0;
652}
653
654static void hdmi_audio_stop(struct device *dev)
655{
656 struct omap_hdmi *hd = dev_get_drvdata(dev);
657 unsigned long flags;
658
659 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
660
661 spin_lock_irqsave(&hd->audio_playing_lock, flags);
662
663 if (hd->display_enabled)
664 hdmi_stop_audio_stream(hd);
665 hd->audio_playing = false;
666
667 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
668}
669
670static int hdmi_audio_config(struct device *dev,
671 struct omap_dss_audio *dss_audio)
672{
673 struct omap_hdmi *hd = dev_get_drvdata(dev);
674 int ret;
675
676 mutex_lock(&hd->lock);
677
678 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
679 ret = -EPERM;
680 goto out;
681 }
682
683 ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
684 hd->cfg.timings.pixelclock);
685
686 if (!ret) {
687 hd->audio_configured = true;
688 hd->audio_config = *dss_audio;
689 }
690out:
691 mutex_unlock(&hd->lock);
692
693 return ret;
694}
695
696static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
697 .audio_startup = hdmi_audio_startup,
698 .audio_shutdown = hdmi_audio_shutdown,
699 .audio_start = hdmi_audio_start,
700 .audio_stop = hdmi_audio_stop,
701 .audio_config = hdmi_audio_config,
702};
703
704static int hdmi_audio_register(struct device *dev)
705{
706 struct omap_hdmi_audio_pdata pdata = {
707 .dev = dev,
708 .dss_version = omapdss_get_version(),
709 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
710 .ops = &hdmi_audio_ops,
711 };
712
713 hdmi.audio_pdev = platform_device_register_data(
714 dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
715 &pdata, sizeof(pdata));
716
717 if (IS_ERR(hdmi.audio_pdev))
718 return PTR_ERR(hdmi.audio_pdev);
719
720 hdmi_runtime_get();
721 hdmi.wp_idlemode =
722 REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
723 hdmi_runtime_put();
724
725 return 0;
726}
727
728/* HDMI HW IP initialisation */
729static int hdmi5_bind(struct device *dev, struct device *master, void *data)
730{
731 struct platform_device *pdev = to_platform_device(dev);
732 int r;
733 int irq;
734
735 hdmi.pdev = pdev;
736 dev_set_drvdata(&pdev->dev, &hdmi);
737
738 mutex_init(&hdmi.lock);
739 spin_lock_init(&hdmi.audio_playing_lock);
740
741 if (pdev->dev.of_node) {
742 r = hdmi_probe_of(pdev);
743 if (r)
744 return r;
745 }
746
747 r = hdmi_wp_init(pdev, &hdmi.wp);
748 if (r)
749 return r;
750
751 r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
752 if (r)
753 return r;
754
755 r = hdmi_phy_init(pdev, &hdmi.phy);
756 if (r)
757 goto err;
758
759 r = hdmi5_core_init(pdev, &hdmi.core);
760 if (r)
761 goto err;
762
763 irq = platform_get_irq(pdev, 0);
764 if (irq < 0) {
765 DSSERR("platform_get_irq failed\n");
766 r = -ENODEV;
767 goto err;
768 }
769
770 r = devm_request_threaded_irq(&pdev->dev, irq,
771 NULL, hdmi_irq_handler,
772 IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
773 if (r) {
774 DSSERR("HDMI IRQ request failed\n");
775 goto err;
776 }
777
778 pm_runtime_enable(&pdev->dev);
779
780 hdmi_init_output(pdev);
781
782 r = hdmi_audio_register(&pdev->dev);
783 if (r) {
784 DSSERR("Registering HDMI audio failed %d\n", r);
785 hdmi_uninit_output(pdev);
786 pm_runtime_disable(&pdev->dev);
787 return r;
788 }
789
790 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
791
792 return 0;
793err:
794 hdmi_pll_uninit(&hdmi.pll);
795 return r;
796}
797
798static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
799{
800 struct platform_device *pdev = to_platform_device(dev);
801
802 if (hdmi.audio_pdev)
803 platform_device_unregister(hdmi.audio_pdev);
804
805 hdmi_uninit_output(pdev);
806
807 hdmi_pll_uninit(&hdmi.pll);
808
809 pm_runtime_disable(&pdev->dev);
810}
811
812static const struct component_ops hdmi5_component_ops = {
813 .bind = hdmi5_bind,
814 .unbind = hdmi5_unbind,
815};
816
817static int hdmi5_probe(struct platform_device *pdev)
818{
819 return component_add(&pdev->dev, &hdmi5_component_ops);
820}
821
822static int hdmi5_remove(struct platform_device *pdev)
823{
824 component_del(&pdev->dev, &hdmi5_component_ops);
825 return 0;
826}
827
828static int hdmi_runtime_suspend(struct device *dev)
829{
830 dispc_runtime_put();
831
832 return 0;
833}
834
835static int hdmi_runtime_resume(struct device *dev)
836{
837 int r;
838
839 r = dispc_runtime_get();
840 if (r < 0)
841 return r;
842
843 return 0;
844}
845
846static const struct dev_pm_ops hdmi_pm_ops = {
847 .runtime_suspend = hdmi_runtime_suspend,
848 .runtime_resume = hdmi_runtime_resume,
849};
850
851static const struct of_device_id hdmi_of_match[] = {
852 { .compatible = "ti,omap5-hdmi", },
853 { .compatible = "ti,dra7-hdmi", },
854 {},
855};
856
857static struct platform_driver omapdss_hdmihw_driver = {
858 .probe = hdmi5_probe,
859 .remove = hdmi5_remove,
860 .driver = {
861 .name = "omapdss_hdmi5",
862 .pm = &hdmi_pm_ops,
863 .of_match_table = hdmi_of_match,
864 .suppress_bind_attrs = true,
865 },
866};
867
868int __init hdmi5_init_platform_driver(void)
869{
870 return platform_driver_register(&omapdss_hdmihw_driver);
871}
872
873void hdmi5_uninit_platform_driver(void)
874{
875 platform_driver_unregister(&omapdss_hdmihw_driver);
876}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
new file mode 100644
index 000000000000..8ea531d2652c
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
@@ -0,0 +1,916 @@
1/*
2 * OMAP5 HDMI CORE IP driver library
3 *
4 * Copyright (C) 2014 Texas Instruments Incorporated
5 *
6 * Authors:
7 * Yong Zhi
8 * Mythri pk
9 * Archit Taneja <archit@ti.com>
10 * Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/err.h>
28#include <linux/io.h>
29#include <linux/delay.h>
30#include <linux/string.h>
31#include <linux/seq_file.h>
32#include <drm/drm_edid.h>
33#include <sound/asound.h>
34#include <sound/asoundef.h>
35
36#include "hdmi5_core.h"
37
38/* only 24 bit color depth used for now */
39static const struct csc_table csc_table_deepcolor[] = {
40 /* HDMI_DEEP_COLOR_24BIT */
41 [0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, },
42 /* HDMI_DEEP_COLOR_30BIT */
43 [1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, },
44 /* HDMI_DEEP_COLOR_36BIT */
45 [2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, },
46 /* FULL RANGE */
47 [3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, },
48};
49
50static void hdmi_core_ddc_init(struct hdmi_core_data *core)
51{
52 void __iomem *base = core->base;
53 const unsigned long long iclk = 266000000; /* DSS L3 ICLK */
54 const unsigned ss_scl_high = 4000; /* ns */
55 const unsigned ss_scl_low = 4700; /* ns */
56 const unsigned fs_scl_high = 600; /* ns */
57 const unsigned fs_scl_low = 1300; /* ns */
58 const unsigned sda_hold = 1000; /* ns */
59 const unsigned sfr_div = 10;
60 unsigned long long sfr;
61 unsigned v;
62
63 sfr = iclk / sfr_div; /* SFR_DIV */
64 sfr /= 1000; /* SFR clock in kHz */
65
66 /* Reset */
67 REG_FLD_MOD(base, HDMI_CORE_I2CM_SOFTRSTZ, 0, 0, 0);
68 if (hdmi_wait_for_bit_change(base, HDMI_CORE_I2CM_SOFTRSTZ,
69 0, 0, 1) != 1)
70 DSSERR("HDMI I2CM reset failed\n");
71
72 /* Standard (0) or Fast (1) Mode */
73 REG_FLD_MOD(base, HDMI_CORE_I2CM_DIV, 0, 3, 3);
74
75 /* Standard Mode SCL High counter */
76 v = DIV_ROUND_UP_ULL(ss_scl_high * sfr, 1000000);
77 REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR,
78 (v >> 8) & 0xff, 7, 0);
79 REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR,
80 v & 0xff, 7, 0);
81
82 /* Standard Mode SCL Low counter */
83 v = DIV_ROUND_UP_ULL(ss_scl_low * sfr, 1000000);
84 REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR,
85 (v >> 8) & 0xff, 7, 0);
86 REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR,
87 v & 0xff, 7, 0);
88
89 /* Fast Mode SCL High Counter */
90 v = DIV_ROUND_UP_ULL(fs_scl_high * sfr, 1000000);
91 REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR,
92 (v >> 8) & 0xff, 7, 0);
93 REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR,
94 v & 0xff, 7, 0);
95
96 /* Fast Mode SCL Low Counter */
97 v = DIV_ROUND_UP_ULL(fs_scl_low * sfr, 1000000);
98 REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR,
99 (v >> 8) & 0xff, 7, 0);
100 REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR,
101 v & 0xff, 7, 0);
102
103 /* SDA Hold Time */
104 v = DIV_ROUND_UP_ULL(sda_hold * sfr, 1000000);
105 REG_FLD_MOD(base, HDMI_CORE_I2CM_SDA_HOLD_ADDR, v & 0xff, 7, 0);
106
107 REG_FLD_MOD(base, HDMI_CORE_I2CM_SLAVE, 0x50, 6, 0);
108 REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGADDR, 0x30, 6, 0);
109
110 /* NACK_POL to high */
111 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 7, 7);
112
113 /* NACK_MASK to unmasked */
114 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 6, 6);
115
116 /* ARBITRATION_POL to high */
117 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 3, 3);
118
119 /* ARBITRATION_MASK to unmasked */
120 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 2, 2);
121
122 /* DONE_POL to high */
123 REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 3, 3);
124
125 /* DONE_MASK to unmasked */
126 REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2);
127}
128
129static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)
130{
131 void __iomem *base = core->base;
132
133 /* Mask I2C interrupts */
134 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
135 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
136 REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
137}
138
139static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
140{
141 void __iomem *base = core->base;
142 u8 cur_addr;
143 char checksum = 0;
144 const int retries = 1000;
145 u8 seg_ptr = ext / 2;
146 u8 edidbase = ((ext % 2) * 0x80);
147
148 REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0);
149
150 /*
151 * TODO: We use polling here, although we probably should use proper
152 * interrupts.
153 */
154 for (cur_addr = 0; cur_addr < 128; ++cur_addr) {
155 int i;
156
157 /* clear ERROR and DONE */
158 REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
159
160 REG_FLD_MOD(base, HDMI_CORE_I2CM_ADDRESS,
161 edidbase + cur_addr, 7, 0);
162
163 if (seg_ptr)
164 REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 1, 1);
165 else
166 REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 0, 0);
167
168 for (i = 0; i < retries; ++i) {
169 u32 stat;
170
171 stat = REG_GET(base, HDMI_CORE_IH_I2CM_STAT0, 1, 0);
172
173 /* I2CM_ERROR */
174 if (stat & 1) {
175 DSSERR("HDMI I2C Master Error\n");
176 return -EIO;
177 }
178
179 /* I2CM_DONE */
180 if (stat & (1 << 1))
181 break;
182
183 usleep_range(250, 1000);
184 }
185
186 if (i == retries) {
187 DSSERR("HDMI I2C timeout reading EDID\n");
188 return -EIO;
189 }
190
191 pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);
192 checksum += pedid[cur_addr];
193 }
194
195 return 0;
196
197}
198
199int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
200{
201 int r, n, i;
202 int max_ext_blocks = (len / 128) - 1;
203
204 if (len < 128)
205 return -EINVAL;
206
207 hdmi_core_ddc_init(core);
208
209 r = hdmi_core_ddc_edid(core, edid, 0);
210 if (r)
211 goto out;
212
213 n = edid[0x7e];
214
215 if (n > max_ext_blocks)
216 n = max_ext_blocks;
217
218 for (i = 1; i <= n; i++) {
219 r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i);
220 if (r)
221 goto out;
222 }
223
224out:
225 hdmi_core_ddc_uninit(core);
226
227 return r ? r : len;
228}
229
230void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
231{
232
233#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
234 hdmi_read_reg(core->base, r))
235
236 DUMPCORE(HDMI_CORE_FC_INVIDCONF);
237 DUMPCORE(HDMI_CORE_FC_INHACTIV0);
238 DUMPCORE(HDMI_CORE_FC_INHACTIV1);
239 DUMPCORE(HDMI_CORE_FC_INHBLANK0);
240 DUMPCORE(HDMI_CORE_FC_INHBLANK1);
241 DUMPCORE(HDMI_CORE_FC_INVACTIV0);
242 DUMPCORE(HDMI_CORE_FC_INVACTIV1);
243 DUMPCORE(HDMI_CORE_FC_INVBLANK);
244 DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY0);
245 DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY1);
246 DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH0);
247 DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH1);
248 DUMPCORE(HDMI_CORE_FC_VSYNCINDELAY);
249 DUMPCORE(HDMI_CORE_FC_VSYNCINWIDTH);
250 DUMPCORE(HDMI_CORE_FC_CTRLDUR);
251 DUMPCORE(HDMI_CORE_FC_EXCTRLDUR);
252 DUMPCORE(HDMI_CORE_FC_EXCTRLSPAC);
253 DUMPCORE(HDMI_CORE_FC_CH0PREAM);
254 DUMPCORE(HDMI_CORE_FC_CH1PREAM);
255 DUMPCORE(HDMI_CORE_FC_CH2PREAM);
256 DUMPCORE(HDMI_CORE_FC_AVICONF0);
257 DUMPCORE(HDMI_CORE_FC_AVICONF1);
258 DUMPCORE(HDMI_CORE_FC_AVICONF2);
259 DUMPCORE(HDMI_CORE_FC_AVIVID);
260 DUMPCORE(HDMI_CORE_FC_PRCONF);
261
262 DUMPCORE(HDMI_CORE_MC_CLKDIS);
263 DUMPCORE(HDMI_CORE_MC_SWRSTZREQ);
264 DUMPCORE(HDMI_CORE_MC_FLOWCTRL);
265 DUMPCORE(HDMI_CORE_MC_PHYRSTZ);
266 DUMPCORE(HDMI_CORE_MC_LOCKONCLOCK);
267
268 DUMPCORE(HDMI_CORE_I2CM_SLAVE);
269 DUMPCORE(HDMI_CORE_I2CM_ADDRESS);
270 DUMPCORE(HDMI_CORE_I2CM_DATAO);
271 DUMPCORE(HDMI_CORE_I2CM_DATAI);
272 DUMPCORE(HDMI_CORE_I2CM_OPERATION);
273 DUMPCORE(HDMI_CORE_I2CM_INT);
274 DUMPCORE(HDMI_CORE_I2CM_CTLINT);
275 DUMPCORE(HDMI_CORE_I2CM_DIV);
276 DUMPCORE(HDMI_CORE_I2CM_SEGADDR);
277 DUMPCORE(HDMI_CORE_I2CM_SOFTRSTZ);
278 DUMPCORE(HDMI_CORE_I2CM_SEGPTR);
279 DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR);
280 DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR);
281 DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR);
282 DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR);
283 DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR);
284 DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR);
285 DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR);
286 DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR);
287 DUMPCORE(HDMI_CORE_I2CM_SDA_HOLD_ADDR);
288}
289
290static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
291 struct hdmi_config *cfg)
292{
293 DSSDBG("hdmi_core_init\n");
294
295 /* video core */
296 video_cfg->data_enable_pol = 1; /* It is always 1*/
297 video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level;
298 video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res;
299 video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1;
300 video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp;
301 video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp;
302 video_cfg->hblank = cfg->timings.hfp +
303 cfg->timings.hbp + cfg->timings.hsw - 1;
304 video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level;
305 video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res;
306 video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw;
307 video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp;
308 video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp;
309 video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */
310 video_cfg->vblank = cfg->timings.vsw +
311 cfg->timings.vfp + cfg->timings.vbp;
312 video_cfg->v_fc_config.hdmi_dvi_mode = cfg->hdmi_dvi_mode;
313 video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace;
314}
315
316/* DSS_HDMI_CORE_VIDEO_CONFIG */
317static void hdmi_core_video_config(struct hdmi_core_data *core,
318 struct hdmi_core_vid_config *cfg)
319{
320 void __iomem *base = core->base;
321 unsigned char r = 0;
322 bool vsync_pol, hsync_pol;
323
324 vsync_pol =
325 cfg->v_fc_config.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
326 hsync_pol =
327 cfg->v_fc_config.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
328
329 /* Set hsync, vsync and data-enable polarity */
330 r = hdmi_read_reg(base, HDMI_CORE_FC_INVIDCONF);
331 r = FLD_MOD(r, vsync_pol, 6, 6);
332 r = FLD_MOD(r, hsync_pol, 5, 5);
333 r = FLD_MOD(r, cfg->data_enable_pol, 4, 4);
334 r = FLD_MOD(r, cfg->vblank_osc, 1, 1);
335 r = FLD_MOD(r, cfg->v_fc_config.timings.interlace, 0, 0);
336 hdmi_write_reg(base, HDMI_CORE_FC_INVIDCONF, r);
337
338 /* set x resolution */
339 REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV1,
340 cfg->v_fc_config.timings.x_res >> 8, 4, 0);
341 REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV0,
342 cfg->v_fc_config.timings.x_res & 0xFF, 7, 0);
343
344 /* set y resolution */
345 REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV1,
346 cfg->v_fc_config.timings.y_res >> 8, 4, 0);
347 REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV0,
348 cfg->v_fc_config.timings.y_res & 0xFF, 7, 0);
349
350 /* set horizontal blanking pixels */
351 REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK1, cfg->hblank >> 8, 4, 0);
352 REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK0, cfg->hblank & 0xFF, 7, 0);
353
354 /* set vertial blanking pixels */
355 REG_FLD_MOD(base, HDMI_CORE_FC_INVBLANK, cfg->vblank, 7, 0);
356
357 /* set horizontal sync offset */
358 REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY1,
359 cfg->v_fc_config.timings.hfp >> 8, 4, 0);
360 REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY0,
361 cfg->v_fc_config.timings.hfp & 0xFF, 7, 0);
362
363 /* set vertical sync offset */
364 REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINDELAY,
365 cfg->v_fc_config.timings.vfp, 7, 0);
366
367 /* set horizontal sync pulse width */
368 REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH1,
369 (cfg->v_fc_config.timings.hsw >> 8), 1, 0);
370 REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH0,
371 cfg->v_fc_config.timings.hsw & 0xFF, 7, 0);
372
373 /* set vertical sync pulse width */
374 REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINWIDTH,
375 cfg->v_fc_config.timings.vsw, 5, 0);
376
377 /* select DVI mode */
378 REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF,
379 cfg->v_fc_config.hdmi_dvi_mode, 3, 3);
380}
381
382static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core)
383{
384 void __iomem *base = core->base;
385 int clr_depth = 0; /* 24 bit color depth */
386
387 /* COLOR_DEPTH */
388 REG_FLD_MOD(base, HDMI_CORE_VP_PR_CD, clr_depth, 7, 4);
389 /* BYPASS_EN */
390 REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 1, 6, 6);
391 /* PP_EN */
392 REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 1 : 0, 5, 5);
393 /* YCC422_EN */
394 REG_FLD_MOD(base, HDMI_CORE_VP_CONF, 0, 3, 3);
395 /* PP_STUFFING */
396 REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, clr_depth ? 1 : 0, 1, 1);
397 /* YCC422_STUFFING */
398 REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, 1, 2, 2);
399 /* OUTPUT_SELECTOR */
400 REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 2, 1, 0);
401}
402
403static void hdmi_core_config_csc(struct hdmi_core_data *core)
404{
405 int clr_depth = 0; /* 24 bit color depth */
406
407 /* CSC_COLORDEPTH */
408 REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, clr_depth, 7, 4);
409}
410
411static void hdmi_core_config_video_sampler(struct hdmi_core_data *core)
412{
413 int video_mapping = 1; /* for 24 bit color depth */
414
415 /* VIDEO_MAPPING */
416 REG_FLD_MOD(core->base, HDMI_CORE_TX_INVID0, video_mapping, 4, 0);
417}
418
419static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core,
420 struct hdmi_avi_infoframe *frame)
421{
422 void __iomem *base = core->base;
423 u8 data[HDMI_INFOFRAME_SIZE(AVI)];
424 u8 *ptr;
425 unsigned y, a, b, s;
426 unsigned c, m, r;
427 unsigned itc, ec, q, sc;
428 unsigned vic;
429 unsigned yq, cn, pr;
430
431 hdmi_avi_infoframe_pack(frame, data, sizeof(data));
432
433 print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data,
434 HDMI_INFOFRAME_SIZE(AVI), false);
435
436 ptr = data + HDMI_INFOFRAME_HEADER_SIZE;
437
438 y = (ptr[0] >> 5) & 0x3;
439 a = (ptr[0] >> 4) & 0x1;
440 b = (ptr[0] >> 2) & 0x3;
441 s = (ptr[0] >> 0) & 0x3;
442
443 c = (ptr[1] >> 6) & 0x3;
444 m = (ptr[1] >> 4) & 0x3;
445 r = (ptr[1] >> 0) & 0x3;
446
447 itc = (ptr[2] >> 7) & 0x1;
448 ec = (ptr[2] >> 4) & 0x7;
449 q = (ptr[2] >> 2) & 0x3;
450 sc = (ptr[2] >> 0) & 0x3;
451
452 vic = ptr[3];
453
454 yq = (ptr[4] >> 6) & 0x3;
455 cn = (ptr[4] >> 4) & 0x3;
456 pr = (ptr[4] >> 0) & 0xf;
457
458 hdmi_write_reg(base, HDMI_CORE_FC_AVICONF0,
459 (a << 6) | (s << 4) | (b << 2) | (y << 0));
460
461 hdmi_write_reg(base, HDMI_CORE_FC_AVICONF1,
462 (c << 6) | (m << 4) | (r << 0));
463
464 hdmi_write_reg(base, HDMI_CORE_FC_AVICONF2,
465 (itc << 7) | (ec << 4) | (q << 2) | (sc << 0));
466
467 hdmi_write_reg(base, HDMI_CORE_FC_AVIVID, vic);
468
469 hdmi_write_reg(base, HDMI_CORE_FC_AVICONF3,
470 (yq << 2) | (cn << 0));
471
472 REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, pr, 3, 0);
473}
474
475static void hdmi_core_csc_config(struct hdmi_core_data *core,
476 struct csc_table csc_coeff)
477{
478 void __iomem *base = core->base;
479
480 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff.a1 >> 8 , 6, 0);
481 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff.a1, 7, 0);
482 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff.a2 >> 8, 6, 0);
483 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff.a2, 7, 0);
484 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff.a3 >> 8, 6, 0);
485 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff.a3, 7, 0);
486 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff.a4 >> 8, 6, 0);
487 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff.a4, 7, 0);
488 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff.b1 >> 8, 6, 0);
489 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff.b1, 7, 0);
490 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff.b2 >> 8, 6, 0);
491 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff.b2, 7, 0);
492 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff.b3 >> 8, 6, 0);
493 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff.b3, 7, 0);
494 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff.b4 >> 8, 6, 0);
495 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff.b4, 7, 0);
496 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff.c1 >> 8, 6, 0);
497 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff.c1, 7, 0);
498 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff.c2 >> 8, 6, 0);
499 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff.c2, 7, 0);
500 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff.c3 >> 8, 6, 0);
501 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff.c3, 7, 0);
502 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff.c4 >> 8, 6, 0);
503 REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff.c4, 7, 0);
504
505 REG_FLD_MOD(base, HDMI_CORE_MC_FLOWCTRL, 0x1, 0, 0);
506}
507
508static void hdmi_core_configure_range(struct hdmi_core_data *core)
509{
510 struct csc_table csc_coeff = { 0 };
511
512 /* support limited range with 24 bit color depth for now */
513 csc_coeff = csc_table_deepcolor[0];
514
515 hdmi_core_csc_config(core, csc_coeff);
516}
517
518static void hdmi_core_enable_video_path(struct hdmi_core_data *core)
519{
520 void __iomem *base = core->base;
521
522 DSSDBG("hdmi_core_enable_video_path\n");
523
524 REG_FLD_MOD(base, HDMI_CORE_FC_CTRLDUR, 0x0C, 7, 0);
525 REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLDUR, 0x20, 7, 0);
526 REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLSPAC, 0x01, 7, 0);
527 REG_FLD_MOD(base, HDMI_CORE_FC_CH0PREAM, 0x0B, 7, 0);
528 REG_FLD_MOD(base, HDMI_CORE_FC_CH1PREAM, 0x16, 5, 0);
529 REG_FLD_MOD(base, HDMI_CORE_FC_CH2PREAM, 0x21, 5, 0);
530 REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 0, 0);
531 REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 1, 1);
532}
533
534static void hdmi_core_mask_interrupts(struct hdmi_core_data *core)
535{
536 void __iomem *base = core->base;
537
538 /* Master IRQ mask */
539 REG_FLD_MOD(base, HDMI_CORE_IH_MUTE, 0x3, 1, 0);
540
541 /* Mask all the interrupts in HDMI core */
542
543 REG_FLD_MOD(base, HDMI_CORE_VP_MASK, 0xff, 7, 0);
544 REG_FLD_MOD(base, HDMI_CORE_FC_MASK0, 0xe7, 7, 0);
545 REG_FLD_MOD(base, HDMI_CORE_FC_MASK1, 0xfb, 7, 0);
546 REG_FLD_MOD(base, HDMI_CORE_FC_MASK2, 0x3, 1, 0);
547
548 REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 0x3, 3, 2);
549 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 0x3, 1, 0);
550
551 REG_FLD_MOD(base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0);
552
553 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
554 REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
555 REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
556
557 REG_FLD_MOD(base, HDMI_CORE_PHY_MASK0, 0xf3, 7, 0);
558
559 REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
560
561 /* Clear all the current interrupt bits */
562
563 REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
564 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xe7, 7, 0);
565 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xfb, 7, 0);
566 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0x3, 1, 0);
567
568 REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0x7, 2, 0);
569
570 REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0);
571
572 REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
573
574 REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
575}
576
577static void hdmi_core_enable_interrupts(struct hdmi_core_data *core)
578{
579 /* Unmute interrupts */
580 REG_FLD_MOD(core->base, HDMI_CORE_IH_MUTE, 0x0, 1, 0);
581}
582
583int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
584{
585 void __iomem *base = core->base;
586
587 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xff, 7, 0);
588 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xff, 7, 0);
589 REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0xff, 7, 0);
590 REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0xff, 7, 0);
591 REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
592 REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0xff, 7, 0);
593 REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0xff, 7, 0);
594 REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
595 REG_FLD_MOD(base, HDMI_CORE_IH_I2CMPHY_STAT0, 0xff, 7, 0);
596
597 return 0;
598}
599
600void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
601 struct hdmi_config *cfg)
602{
603 struct omap_video_timings video_timing;
604 struct hdmi_video_format video_format;
605 struct hdmi_core_vid_config v_core_cfg;
606
607 hdmi_core_mask_interrupts(core);
608
609 hdmi_core_init(&v_core_cfg, cfg);
610
611 hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
612
613 hdmi_wp_video_config_timing(wp, &video_timing);
614
615 /* video config */
616 video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
617
618 hdmi_wp_video_config_format(wp, &video_format);
619
620 hdmi_wp_video_config_interface(wp, &video_timing);
621
622 /* support limited range with 24 bit color depth for now */
623 hdmi_core_configure_range(core);
624 cfg->infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
625
626 /*
627 * configure core video part, set software reset in the core
628 */
629 v_core_cfg.packet_mode = HDMI_PACKETMODE24BITPERPIXEL;
630
631 hdmi_core_video_config(core, &v_core_cfg);
632
633 hdmi_core_config_video_packetizer(core);
634 hdmi_core_config_csc(core);
635 hdmi_core_config_video_sampler(core);
636
637 if (cfg->hdmi_dvi_mode == HDMI_HDMI)
638 hdmi_core_write_avi_infoframe(core, &cfg->infoframe);
639
640 hdmi_core_enable_video_path(core);
641
642 hdmi_core_enable_interrupts(core);
643}
644
645static void hdmi5_core_audio_config(struct hdmi_core_data *core,
646 struct hdmi_core_audio_config *cfg)
647{
648 void __iomem *base = core->base;
649 u8 val;
650
651 /* Mute audio before configuring */
652 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0xf, 7, 4);
653
654 /* Set the N parameter */
655 REG_FLD_MOD(base, HDMI_CORE_AUD_N1, cfg->n, 7, 0);
656 REG_FLD_MOD(base, HDMI_CORE_AUD_N2, cfg->n >> 8, 7, 0);
657 REG_FLD_MOD(base, HDMI_CORE_AUD_N3, cfg->n >> 16, 3, 0);
658
659 /*
660 * CTS manual mode. Automatic mode is not supported when using audio
661 * parallel interface.
662 */
663 REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, 1, 4, 4);
664 REG_FLD_MOD(base, HDMI_CORE_AUD_CTS1, cfg->cts, 7, 0);
665 REG_FLD_MOD(base, HDMI_CORE_AUD_CTS2, cfg->cts >> 8, 7, 0);
666 REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, cfg->cts >> 16, 3, 0);
667
668 /* Layout of Audio Sample Packets: 2-channel or multichannels */
669 if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
670 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 0, 0);
671 else
672 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 1, 0, 0);
673
674 /* Configure IEC-609580 Validity bits */
675 /* Channel 0 is valid */
676 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 0, 0);
677 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 4, 4);
678
679 if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
680 val = 1;
681 else
682 val = 0;
683
684 /* Channels 1, 2 setting */
685 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 1, 1);
686 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 5, 5);
687 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 2, 2);
688 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 6, 6);
689 /* Channel 3 setting */
690 if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH)
691 val = 1;
692 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 3, 3);
693 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 7, 7);
694
695 /* Configure IEC-60958 User bits */
696 /* TODO: should be set by user. */
697 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSU, 0, 7, 0);
698
699 /* Configure IEC-60958 Channel Status word */
700 /* CGMSA */
701 val = cfg->iec60958_cfg->status[5] & IEC958_AES5_CON_CGMSA;
702 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 5, 4);
703
704 /* Copyright */
705 val = (cfg->iec60958_cfg->status[0] &
706 IEC958_AES0_CON_NOT_COPYRIGHT) >> 2;
707 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 0, 0);
708
709 /* Category */
710 hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(1),
711 cfg->iec60958_cfg->status[1]);
712
713 /* PCM audio mode */
714 val = (cfg->iec60958_cfg->status[0] & IEC958_AES0_CON_MODE) >> 6;
715 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 6, 4);
716
717 /* Source number */
718 val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
719 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
720
721 /* Channel number right 0 */
722 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
723 /* Channel number right 1*/
724 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 4, 7, 4);
725 /* Channel number right 2 */
726 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 6, 3, 0);
727 /* Channel number right 3*/
728 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 8, 7, 4);
729 /* Channel number left 0 */
730 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 1, 3, 0);
731 /* Channel number left 1*/
732 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 3, 7, 4);
733 /* Channel number left 2 */
734 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 5, 3, 0);
735 /* Channel number left 3*/
736 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 7, 7, 4);
737
738 /* Clock accuracy and sample rate */
739 hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(7),
740 cfg->iec60958_cfg->status[3]);
741
742 /* Original sample rate and word length */
743 hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(8),
744 cfg->iec60958_cfg->status[4]);
745
746 /* Enable FIFO empty and full interrupts */
747 REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 3, 3, 2);
748
749 /* Configure GPA */
750 /* select HBR/SPDIF interfaces */
751 if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) {
752 /* select HBR/SPDIF interfaces */
753 REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
754 /* enable two channels in GPA */
755 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 3, 7, 0);
756 } else if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH) {
757 /* select HBR/SPDIF interfaces */
758 REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
759 /* enable six channels in GPA */
760 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0x3F, 7, 0);
761 } else {
762 /* select HBR/SPDIF interfaces */
763 REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
764 /* enable eight channels in GPA */
765 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0xFF, 7, 0);
766 }
767
768 /* disable HBR */
769 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 0, 0, 0);
770 /* enable PCUV */
771 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 1, 1, 1);
772 /* enable GPA FIFO full and empty mask */
773 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 3, 1, 0);
774 /* set polarity of GPA FIFO empty interrupts */
775 REG_FLD_MOD(base, HDMI_CORE_AUD_GP_POL, 1, 0, 0);
776
777 /* unmute audio */
778 REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 7, 4);
779}
780
781static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core,
782 struct snd_cea_861_aud_if *info_aud)
783{
784 void __iomem *base = core->base;
785
786 /* channel count and coding type fields in AUDICONF0 are swapped */
787 hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF0,
788 (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC) << 4 |
789 (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CT) >> 4);
790
791 hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud->db2_sf_ss);
792 hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud->db4_ca);
793 hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3,
794 (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_DM_INH) >> 3 |
795 (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_LSV));
796}
797
798int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
799 struct omap_dss_audio *audio, u32 pclk)
800{
801 struct hdmi_audio_format audio_format;
802 struct hdmi_audio_dma audio_dma;
803 struct hdmi_core_audio_config core_cfg;
804 int err, n, cts, channel_count;
805 unsigned int fs_nr;
806 bool word_length_16b = false;
807
808 if (!audio || !audio->iec || !audio->cea || !core)
809 return -EINVAL;
810
811 core_cfg.iec60958_cfg = audio->iec;
812
813 if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) &&
814 (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16))
815 word_length_16b = true;
816
817 /* only 16-bit word length supported atm */
818 if (!word_length_16b)
819 return -EINVAL;
820
821 switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
822 case IEC958_AES3_CON_FS_32000:
823 fs_nr = 32000;
824 break;
825 case IEC958_AES3_CON_FS_44100:
826 fs_nr = 44100;
827 break;
828 case IEC958_AES3_CON_FS_48000:
829 fs_nr = 48000;
830 break;
831 case IEC958_AES3_CON_FS_88200:
832 fs_nr = 88200;
833 break;
834 case IEC958_AES3_CON_FS_96000:
835 fs_nr = 96000;
836 break;
837 case IEC958_AES3_CON_FS_176400:
838 fs_nr = 176400;
839 break;
840 case IEC958_AES3_CON_FS_192000:
841 fs_nr = 192000;
842 break;
843 default:
844 return -EINVAL;
845 }
846
847 err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
848 core_cfg.n = n;
849 core_cfg.cts = cts;
850
851 /* Audio channels settings */
852 channel_count = (audio->cea->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC)
853 + 1;
854
855 if (channel_count == 2)
856 core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
857 else if (channel_count == 6)
858 core_cfg.layout = HDMI_AUDIO_LAYOUT_6CH;
859 else
860 core_cfg.layout = HDMI_AUDIO_LAYOUT_8CH;
861
862 /* DMA settings */
863 if (word_length_16b)
864 audio_dma.transfer_size = 0x10;
865 else
866 audio_dma.transfer_size = 0x20;
867 audio_dma.block_size = 0xC0;
868 audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
869 audio_dma.fifo_threshold = 0x20; /* in number of samples */
870
871 /* audio FIFO format settings for 16-bit samples*/
872 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
873 audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
874 audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
875 audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
876
877 /* only LPCM atm */
878 audio_format.type = HDMI_AUDIO_TYPE_LPCM;
879
880 /* only allowed option */
881 audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
882
883 /* disable start/stop signals of IEC 60958 blocks */
884 audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
885
886 /* configure DMA and audio FIFO format*/
887 hdmi_wp_audio_config_dma(wp, &audio_dma);
888 hdmi_wp_audio_config_format(wp, &audio_format);
889
890 /* configure the core */
891 hdmi5_core_audio_config(core, &core_cfg);
892
893 /* configure CEA 861 audio infoframe */
894 hdmi5_core_audio_infoframe_cfg(core, audio->cea);
895
896 return 0;
897}
898
899int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
900{
901 struct resource *res;
902
903 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
904 if (!res) {
905 DSSERR("can't get CORE IORESOURCE_MEM HDMI\n");
906 return -EINVAL;
907 }
908
909 core->base = devm_ioremap_resource(&pdev->dev, res);
910 if (IS_ERR(core->base)) {
911 DSSERR("can't ioremap HDMI core\n");
912 return PTR_ERR(core->base);
913 }
914
915 return 0;
916}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
new file mode 100644
index 000000000000..f2f1022c5516
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
@@ -0,0 +1,304 @@
1/*
2 * HDMI driver definition for TI OMAP5 processors.
3 *
4 * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _HDMI5_CORE_H_
20#define _HDMI5_CORE_H_
21
22#include "hdmi.h"
23
24/* HDMI IP Core System */
25
26/* HDMI Identification */
27#define HDMI_CORE_DESIGN_ID 0x00000
28#define HDMI_CORE_REVISION_ID 0x00004
29#define HDMI_CORE_PRODUCT_ID0 0x00008
30#define HDMI_CORE_PRODUCT_ID1 0x0000C
31#define HDMI_CORE_CONFIG0_ID 0x00010
32#define HDMI_CORE_CONFIG1_ID 0x00014
33#define HDMI_CORE_CONFIG2_ID 0x00018
34#define HDMI_CORE_CONFIG3_ID 0x0001C
35
36/* HDMI Interrupt */
37#define HDMI_CORE_IH_FC_STAT0 0x00400
38#define HDMI_CORE_IH_FC_STAT1 0x00404
39#define HDMI_CORE_IH_FC_STAT2 0x00408
40#define HDMI_CORE_IH_AS_STAT0 0x0040C
41#define HDMI_CORE_IH_PHY_STAT0 0x00410
42#define HDMI_CORE_IH_I2CM_STAT0 0x00414
43#define HDMI_CORE_IH_CEC_STAT0 0x00418
44#define HDMI_CORE_IH_VP_STAT0 0x0041C
45#define HDMI_CORE_IH_I2CMPHY_STAT0 0x00420
46#define HDMI_CORE_IH_MUTE 0x007FC
47
48/* HDMI Video Sampler */
49#define HDMI_CORE_TX_INVID0 0x00800
50#define HDMI_CORE_TX_INSTUFFING 0x00804
51#define HDMI_CORE_TX_RGYDATA0 0x00808
52#define HDMI_CORE_TX_RGYDATA1 0x0080C
53#define HDMI_CORE_TX_RCRDATA0 0x00810
54#define HDMI_CORE_TX_RCRDATA1 0x00814
55#define HDMI_CORE_TX_BCBDATA0 0x00818
56#define HDMI_CORE_TX_BCBDATA1 0x0081C
57
58/* HDMI Video Packetizer */
59#define HDMI_CORE_VP_STATUS 0x02000
60#define HDMI_CORE_VP_PR_CD 0x02004
61#define HDMI_CORE_VP_STUFF 0x02008
62#define HDMI_CORE_VP_REMAP 0x0200C
63#define HDMI_CORE_VP_CONF 0x02010
64#define HDMI_CORE_VP_STAT 0x02014
65#define HDMI_CORE_VP_INT 0x02018
66#define HDMI_CORE_VP_MASK 0x0201C
67#define HDMI_CORE_VP_POL 0x02020
68
69/* Frame Composer */
70#define HDMI_CORE_FC_INVIDCONF 0x04000
71#define HDMI_CORE_FC_INHACTIV0 0x04004
72#define HDMI_CORE_FC_INHACTIV1 0x04008
73#define HDMI_CORE_FC_INHBLANK0 0x0400C
74#define HDMI_CORE_FC_INHBLANK1 0x04010
75#define HDMI_CORE_FC_INVACTIV0 0x04014
76#define HDMI_CORE_FC_INVACTIV1 0x04018
77#define HDMI_CORE_FC_INVBLANK 0x0401C
78#define HDMI_CORE_FC_HSYNCINDELAY0 0x04020
79#define HDMI_CORE_FC_HSYNCINDELAY1 0x04024
80#define HDMI_CORE_FC_HSYNCINWIDTH0 0x04028
81#define HDMI_CORE_FC_HSYNCINWIDTH1 0x0402C
82#define HDMI_CORE_FC_VSYNCINDELAY 0x04030
83#define HDMI_CORE_FC_VSYNCINWIDTH 0x04034
84#define HDMI_CORE_FC_INFREQ0 0x04038
85#define HDMI_CORE_FC_INFREQ1 0x0403C
86#define HDMI_CORE_FC_INFREQ2 0x04040
87#define HDMI_CORE_FC_CTRLDUR 0x04044
88#define HDMI_CORE_FC_EXCTRLDUR 0x04048
89#define HDMI_CORE_FC_EXCTRLSPAC 0x0404C
90#define HDMI_CORE_FC_CH0PREAM 0x04050
91#define HDMI_CORE_FC_CH1PREAM 0x04054
92#define HDMI_CORE_FC_CH2PREAM 0x04058
93#define HDMI_CORE_FC_AVICONF3 0x0405C
94#define HDMI_CORE_FC_GCP 0x04060
95#define HDMI_CORE_FC_AVICONF0 0x04064
96#define HDMI_CORE_FC_AVICONF1 0x04068
97#define HDMI_CORE_FC_AVICONF2 0x0406C
98#define HDMI_CORE_FC_AVIVID 0x04070
99#define HDMI_CORE_FC_AVIETB0 0x04074
100#define HDMI_CORE_FC_AVIETB1 0x04078
101#define HDMI_CORE_FC_AVISBB0 0x0407C
102#define HDMI_CORE_FC_AVISBB1 0x04080
103#define HDMI_CORE_FC_AVIELB0 0x04084
104#define HDMI_CORE_FC_AVIELB1 0x04088
105#define HDMI_CORE_FC_AVISRB0 0x0408C
106#define HDMI_CORE_FC_AVISRB1 0x04090
107#define HDMI_CORE_FC_AUDICONF0 0x04094
108#define HDMI_CORE_FC_AUDICONF1 0x04098
109#define HDMI_CORE_FC_AUDICONF2 0x0409C
110#define HDMI_CORE_FC_AUDICONF3 0x040A0
111#define HDMI_CORE_FC_VSDIEEEID0 0x040A4
112#define HDMI_CORE_FC_VSDSIZE 0x040A8
113#define HDMI_CORE_FC_VSDIEEEID1 0x040C0
114#define HDMI_CORE_FC_VSDIEEEID2 0x040C4
115#define HDMI_CORE_FC_VSDPAYLOAD(n) (n * 4 + 0x040C8)
116#define HDMI_CORE_FC_SPDVENDORNAME(n) (n * 4 + 0x04128)
117#define HDMI_CORE_FC_SPDPRODUCTNAME(n) (n * 4 + 0x04148)
118#define HDMI_CORE_FC_SPDDEVICEINF 0x04188
119#define HDMI_CORE_FC_AUDSCONF 0x0418C
120#define HDMI_CORE_FC_AUDSSTAT 0x04190
121#define HDMI_CORE_FC_AUDSV 0x04194
122#define HDMI_CORE_FC_AUDSU 0x04198
123#define HDMI_CORE_FC_AUDSCHNLS(n) (n * 4 + 0x0419C)
124#define HDMI_CORE_FC_CTRLQHIGH 0x041CC
125#define HDMI_CORE_FC_CTRLQLOW 0x041D0
126#define HDMI_CORE_FC_ACP0 0x041D4
127#define HDMI_CORE_FC_ACP(n) ((16-n) * 4 + 0x04208)
128#define HDMI_CORE_FC_ISCR1_0 0x04248
129#define HDMI_CORE_FC_ISCR1(n) ((16-n) * 4 + 0x0424C)
130#define HDMI_CORE_FC_ISCR2(n) ((15-n) * 4 + 0x0428C)
131#define HDMI_CORE_FC_DATAUTO0 0x042CC
132#define HDMI_CORE_FC_DATAUTO1 0x042D0
133#define HDMI_CORE_FC_DATAUTO2 0x042D4
134#define HDMI_CORE_FC_DATMAN 0x042D8
135#define HDMI_CORE_FC_DATAUTO3 0x042DC
136#define HDMI_CORE_FC_RDRB(n) (n * 4 + 0x042E0)
137#define HDMI_CORE_FC_STAT0 0x04340
138#define HDMI_CORE_FC_INT0 0x04344
139#define HDMI_CORE_FC_MASK0 0x04348
140#define HDMI_CORE_FC_POL0 0x0434C
141#define HDMI_CORE_FC_STAT1 0x04350
142#define HDMI_CORE_FC_INT1 0x04354
143#define HDMI_CORE_FC_MASK1 0x04358
144#define HDMI_CORE_FC_POL1 0x0435C
145#define HDMI_CORE_FC_STAT2 0x04360
146#define HDMI_CORE_FC_INT2 0x04364
147#define HDMI_CORE_FC_MASK2 0x04368
148#define HDMI_CORE_FC_POL2 0x0436C
149#define HDMI_CORE_FC_PRCONF 0x04380
150#define HDMI_CORE_FC_GMD_STAT 0x04400
151#define HDMI_CORE_FC_GMD_EN 0x04404
152#define HDMI_CORE_FC_GMD_UP 0x04408
153#define HDMI_CORE_FC_GMD_CONF 0x0440C
154#define HDMI_CORE_FC_GMD_HB 0x04410
155#define HDMI_CORE_FC_GMD_PB(n) (n * 4 + 0x04414)
156#define HDMI_CORE_FC_DBGFORCE 0x04800
157#define HDMI_CORE_FC_DBGAUD0CH0 0x04804
158#define HDMI_CORE_FC_DBGAUD1CH0 0x04808
159#define HDMI_CORE_FC_DBGAUD2CH0 0x0480C
160#define HDMI_CORE_FC_DBGAUD0CH1 0x04810
161#define HDMI_CORE_FC_DBGAUD1CH1 0x04814
162#define HDMI_CORE_FC_DBGAUD2CH1 0x04818
163#define HDMI_CORE_FC_DBGAUD0CH2 0x0481C
164#define HDMI_CORE_FC_DBGAUD1CH2 0x04820
165#define HDMI_CORE_FC_DBGAUD2CH2 0x04824
166#define HDMI_CORE_FC_DBGAUD0CH3 0x04828
167#define HDMI_CORE_FC_DBGAUD1CH3 0x0482C
168#define HDMI_CORE_FC_DBGAUD2CH3 0x04830
169#define HDMI_CORE_FC_DBGAUD0CH4 0x04834
170#define HDMI_CORE_FC_DBGAUD1CH4 0x04838
171#define HDMI_CORE_FC_DBGAUD2CH4 0x0483C
172#define HDMI_CORE_FC_DBGAUD0CH5 0x04840
173#define HDMI_CORE_FC_DBGAUD1CH5 0x04844
174#define HDMI_CORE_FC_DBGAUD2CH5 0x04848
175#define HDMI_CORE_FC_DBGAUD0CH6 0x0484C
176#define HDMI_CORE_FC_DBGAUD1CH6 0x04850
177#define HDMI_CORE_FC_DBGAUD2CH6 0x04854
178#define HDMI_CORE_FC_DBGAUD0CH7 0x04858
179#define HDMI_CORE_FC_DBGAUD1CH7 0x0485C
180#define HDMI_CORE_FC_DBGAUD2CH7 0x04860
181#define HDMI_CORE_FC_DBGTMDS0 0x04864
182#define HDMI_CORE_FC_DBGTMDS1 0x04868
183#define HDMI_CORE_FC_DBGTMDS2 0x0486C
184#define HDMI_CORE_PHY_MASK0 0x0C018
185#define HDMI_CORE_PHY_I2CM_INT_ADDR 0x0C09C
186#define HDMI_CORE_PHY_I2CM_CTLINT_ADDR 0x0C0A0
187
188/* HDMI Audio */
189#define HDMI_CORE_AUD_CONF0 0x0C400
190#define HDMI_CORE_AUD_CONF1 0x0C404
191#define HDMI_CORE_AUD_INT 0x0C408
192#define HDMI_CORE_AUD_N1 0x0C800
193#define HDMI_CORE_AUD_N2 0x0C804
194#define HDMI_CORE_AUD_N3 0x0C808
195#define HDMI_CORE_AUD_CTS1 0x0C80C
196#define HDMI_CORE_AUD_CTS2 0x0C810
197#define HDMI_CORE_AUD_CTS3 0x0C814
198#define HDMI_CORE_AUD_INCLKFS 0x0C818
199#define HDMI_CORE_AUD_CC08 0x0CC08
200#define HDMI_CORE_AUD_GP_CONF0 0x0D400
201#define HDMI_CORE_AUD_GP_CONF1 0x0D404
202#define HDMI_CORE_AUD_GP_CONF2 0x0D408
203#define HDMI_CORE_AUD_D010 0x0D010
204#define HDMI_CORE_AUD_GP_STAT 0x0D40C
205#define HDMI_CORE_AUD_GP_INT 0x0D410
206#define HDMI_CORE_AUD_GP_POL 0x0D414
207#define HDMI_CORE_AUD_GP_MASK 0x0D418
208
209/* HDMI Main Controller */
210#define HDMI_CORE_MC_CLKDIS 0x10004
211#define HDMI_CORE_MC_SWRSTZREQ 0x10008
212#define HDMI_CORE_MC_FLOWCTRL 0x10010
213#define HDMI_CORE_MC_PHYRSTZ 0x10014
214#define HDMI_CORE_MC_LOCKONCLOCK 0x10018
215
216/* HDMI COLOR SPACE CONVERTER */
217#define HDMI_CORE_CSC_CFG 0x10400
218#define HDMI_CORE_CSC_SCALE 0x10404
219#define HDMI_CORE_CSC_COEF_A1_MSB 0x10408
220#define HDMI_CORE_CSC_COEF_A1_LSB 0x1040C
221#define HDMI_CORE_CSC_COEF_A2_MSB 0x10410
222#define HDMI_CORE_CSC_COEF_A2_LSB 0x10414
223#define HDMI_CORE_CSC_COEF_A3_MSB 0x10418
224#define HDMI_CORE_CSC_COEF_A3_LSB 0x1041C
225#define HDMI_CORE_CSC_COEF_A4_MSB 0x10420
226#define HDMI_CORE_CSC_COEF_A4_LSB 0x10424
227#define HDMI_CORE_CSC_COEF_B1_MSB 0x10428
228#define HDMI_CORE_CSC_COEF_B1_LSB 0x1042C
229#define HDMI_CORE_CSC_COEF_B2_MSB 0x10430
230#define HDMI_CORE_CSC_COEF_B2_LSB 0x10434
231#define HDMI_CORE_CSC_COEF_B3_MSB 0x10438
232#define HDMI_CORE_CSC_COEF_B3_LSB 0x1043C
233#define HDMI_CORE_CSC_COEF_B4_MSB 0x10440
234#define HDMI_CORE_CSC_COEF_B4_LSB 0x10444
235#define HDMI_CORE_CSC_COEF_C1_MSB 0x10448
236#define HDMI_CORE_CSC_COEF_C1_LSB 0x1044C
237#define HDMI_CORE_CSC_COEF_C2_MSB 0x10450
238#define HDMI_CORE_CSC_COEF_C2_LSB 0x10454
239#define HDMI_CORE_CSC_COEF_C3_MSB 0x10458
240#define HDMI_CORE_CSC_COEF_C3_LSB 0x1045C
241#define HDMI_CORE_CSC_COEF_C4_MSB 0x10460
242#define HDMI_CORE_CSC_COEF_C4_LSB 0x10464
243
244/* HDMI HDCP */
245#define HDMI_CORE_HDCP_MASK 0x14020
246
247/* HDMI CEC */
248#define HDMI_CORE_CEC_MASK 0x17408
249
250/* HDMI I2C Master */
251#define HDMI_CORE_I2CM_SLAVE 0x157C8
252#define HDMI_CORE_I2CM_ADDRESS 0x157CC
253#define HDMI_CORE_I2CM_DATAO 0x157D0
254#define HDMI_CORE_I2CM_DATAI 0X157D4
255#define HDMI_CORE_I2CM_OPERATION 0x157D8
256#define HDMI_CORE_I2CM_INT 0x157DC
257#define HDMI_CORE_I2CM_CTLINT 0x157E0
258#define HDMI_CORE_I2CM_DIV 0x157E4
259#define HDMI_CORE_I2CM_SEGADDR 0x157E8
260#define HDMI_CORE_I2CM_SOFTRSTZ 0x157EC
261#define HDMI_CORE_I2CM_SEGPTR 0x157F0
262#define HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR 0x157F4
263#define HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR 0x157F8
264#define HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR 0x157FC
265#define HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR 0x15800
266#define HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR 0x15804
267#define HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR 0x15808
268#define HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR 0x1580C
269#define HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR 0x15810
270#define HDMI_CORE_I2CM_SDA_HOLD_ADDR 0x15814
271
272enum hdmi_core_packet_mode {
273 HDMI_PACKETMODERESERVEDVALUE = 0,
274 HDMI_PACKETMODE24BITPERPIXEL = 4,
275 HDMI_PACKETMODE30BITPERPIXEL = 5,
276 HDMI_PACKETMODE36BITPERPIXEL = 6,
277 HDMI_PACKETMODE48BITPERPIXEL = 7,
278};
279
280struct hdmi_core_vid_config {
281 struct hdmi_config v_fc_config;
282 enum hdmi_core_packet_mode packet_mode;
283 int data_enable_pol;
284 int vblank_osc;
285 int hblank;
286 int vblank;
287};
288
289struct csc_table {
290 u16 a1, a2, a3, a4;
291 u16 b1, b2, b3, b4;
292 u16 c1, c2, c3, c4;
293};
294
295int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
296void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s);
297int hdmi5_core_handle_irqs(struct hdmi_core_data *core);
298void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
299 struct hdmi_config *cfg);
300int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
301
302int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
303 struct omap_dss_audio *audio, u32 pclk);
304#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_common.c b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c
new file mode 100644
index 000000000000..1b8fcc6c4ba1
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c
@@ -0,0 +1,148 @@
1
2#define DSS_SUBSYS_NAME "HDMI"
3
4#include <linux/kernel.h>
5#include <linux/err.h>
6#include <linux/of.h>
7#include <video/omapdss.h>
8
9#include "hdmi.h"
10
11int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
12 struct hdmi_phy_data *phy)
13{
14 struct property *prop;
15 int r, len;
16
17 prop = of_find_property(ep, "lanes", &len);
18 if (prop) {
19 u32 lanes[8];
20
21 if (len / sizeof(u32) != ARRAY_SIZE(lanes)) {
22 dev_err(&pdev->dev, "bad number of lanes\n");
23 return -EINVAL;
24 }
25
26 r = of_property_read_u32_array(ep, "lanes", lanes,
27 ARRAY_SIZE(lanes));
28 if (r) {
29 dev_err(&pdev->dev, "failed to read lane data\n");
30 return r;
31 }
32
33 r = hdmi_phy_parse_lanes(phy, lanes);
34 if (r) {
35 dev_err(&pdev->dev, "failed to parse lane data\n");
36 return r;
37 }
38 } else {
39 static const u32 default_lanes[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
40
41 r = hdmi_phy_parse_lanes(phy, default_lanes);
42 if (WARN_ON(r)) {
43 dev_err(&pdev->dev, "failed to parse lane data\n");
44 return r;
45 }
46 }
47
48 return 0;
49}
50
51int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
52{
53 u32 deep_color;
54 bool deep_color_correct = false;
55
56 if (n == NULL || cts == NULL)
57 return -EINVAL;
58
59 /* TODO: When implemented, query deep color mode here. */
60 deep_color = 100;
61
62 /*
63 * When using deep color, the default N value (as in the HDMI
64 * specification) yields to an non-integer CTS. Hence, we
65 * modify it while keeping the restrictions described in
66 * section 7.2.1 of the HDMI 1.4a specification.
67 */
68 switch (sample_freq) {
69 case 32000:
70 case 48000:
71 case 96000:
72 case 192000:
73 if (deep_color == 125)
74 if (pclk == 27027000 || pclk == 74250000)
75 deep_color_correct = true;
76 if (deep_color == 150)
77 if (pclk == 27027000)
78 deep_color_correct = true;
79 break;
80 case 44100:
81 case 88200:
82 case 176400:
83 if (deep_color == 125)
84 if (pclk == 27027000)
85 deep_color_correct = true;
86 break;
87 default:
88 return -EINVAL;
89 }
90
91 if (deep_color_correct) {
92 switch (sample_freq) {
93 case 32000:
94 *n = 8192;
95 break;
96 case 44100:
97 *n = 12544;
98 break;
99 case 48000:
100 *n = 8192;
101 break;
102 case 88200:
103 *n = 25088;
104 break;
105 case 96000:
106 *n = 16384;
107 break;
108 case 176400:
109 *n = 50176;
110 break;
111 case 192000:
112 *n = 32768;
113 break;
114 default:
115 return -EINVAL;
116 }
117 } else {
118 switch (sample_freq) {
119 case 32000:
120 *n = 4096;
121 break;
122 case 44100:
123 *n = 6272;
124 break;
125 case 48000:
126 *n = 6144;
127 break;
128 case 88200:
129 *n = 12544;
130 break;
131 case 96000:
132 *n = 12288;
133 break;
134 case 176400:
135 *n = 25088;
136 break;
137 case 192000:
138 *n = 24576;
139 break;
140 default:
141 return -EINVAL;
142 }
143 }
144 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
145 *cts = (pclk/1000) * (*n / 128) * deep_color / (sample_freq / 10);
146
147 return 0;
148}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
new file mode 100644
index 000000000000..1f5d19c119ce
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
@@ -0,0 +1,247 @@
1/*
2 * HDMI PHY
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <video/omapdss.h>
17
18#include "dss.h"
19#include "hdmi.h"
20
21struct hdmi_phy_features {
22 bool bist_ctrl;
23 bool ldo_voltage;
24 unsigned long max_phy;
25};
26
27static const struct hdmi_phy_features *phy_feat;
28
29void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
30{
31#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
32 hdmi_read_reg(phy->base, r))
33
34 DUMPPHY(HDMI_TXPHY_TX_CTRL);
35 DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
36 DUMPPHY(HDMI_TXPHY_POWER_CTRL);
37 DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
38 if (phy_feat->bist_ctrl)
39 DUMPPHY(HDMI_TXPHY_BIST_CONTROL);
40}
41
42int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes)
43{
44 int i;
45
46 for (i = 0; i < 8; i += 2) {
47 u8 lane, pol;
48 int dx, dy;
49
50 dx = lanes[i];
51 dy = lanes[i + 1];
52
53 if (dx < 0 || dx >= 8)
54 return -EINVAL;
55
56 if (dy < 0 || dy >= 8)
57 return -EINVAL;
58
59 if (dx & 1) {
60 if (dy != dx - 1)
61 return -EINVAL;
62 pol = 1;
63 } else {
64 if (dy != dx + 1)
65 return -EINVAL;
66 pol = 0;
67 }
68
69 lane = dx / 2;
70
71 phy->lane_function[lane] = i / 2;
72 phy->lane_polarity[lane] = pol;
73 }
74
75 return 0;
76}
77
78static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
79{
80 static const u16 pad_cfg_list[] = {
81 0x0123,
82 0x0132,
83 0x0312,
84 0x0321,
85 0x0231,
86 0x0213,
87 0x1023,
88 0x1032,
89 0x3012,
90 0x3021,
91 0x2031,
92 0x2013,
93 0x1203,
94 0x1302,
95 0x3102,
96 0x3201,
97 0x2301,
98 0x2103,
99 0x1230,
100 0x1320,
101 0x3120,
102 0x3210,
103 0x2310,
104 0x2130,
105 };
106
107 u16 lane_cfg = 0;
108 int i;
109 unsigned lane_cfg_val;
110 u16 pol_val = 0;
111
112 for (i = 0; i < 4; ++i)
113 lane_cfg |= phy->lane_function[i] << ((3 - i) * 4);
114
115 pol_val |= phy->lane_polarity[0] << 0;
116 pol_val |= phy->lane_polarity[1] << 3;
117 pol_val |= phy->lane_polarity[2] << 2;
118 pol_val |= phy->lane_polarity[3] << 1;
119
120 for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i)
121 if (pad_cfg_list[i] == lane_cfg)
122 break;
123
124 if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list)))
125 i = 0;
126
127 lane_cfg_val = i;
128
129 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22);
130 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
131}
132
133int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
134 unsigned long lfbitclk)
135{
136 u8 freqout;
137
138 /*
139 * Read address 0 in order to get the SCP reset done completed
140 * Dummy access performed to make sure reset is done
141 */
142 hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
143
144 /*
145 * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
146 * HDMI_PHYPWRCMD_LDOON command.
147 */
148 if (phy_feat->bist_ctrl)
149 REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
150
151 /*
152 * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
153 * to be used for TMDS.
154 */
155 if (hfbitclk != lfbitclk)
156 freqout = 0;
157 else if (hfbitclk / 10 < phy_feat->max_phy)
158 freqout = 1;
159 else
160 freqout = 2;
161
162 /*
163 * Write to phy address 0 to configure the clock
164 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
165 */
166 REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
167
168 /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
169 hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
170
171 /* Setup max LDO voltage */
172 if (phy_feat->ldo_voltage)
173 REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
174
175 hdmi_phy_configure_lanes(phy);
176
177 return 0;
178}
179
180static const struct hdmi_phy_features omap44xx_phy_feats = {
181 .bist_ctrl = false,
182 .ldo_voltage = true,
183 .max_phy = 185675000,
184};
185
186static const struct hdmi_phy_features omap54xx_phy_feats = {
187 .bist_ctrl = true,
188 .ldo_voltage = false,
189 .max_phy = 186000000,
190};
191
192static int hdmi_phy_init_features(struct platform_device *pdev)
193{
194 struct hdmi_phy_features *dst;
195 const struct hdmi_phy_features *src;
196
197 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
198 if (!dst) {
199 dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
200 return -ENOMEM;
201 }
202
203 switch (omapdss_get_version()) {
204 case OMAPDSS_VER_OMAP4430_ES1:
205 case OMAPDSS_VER_OMAP4430_ES2:
206 case OMAPDSS_VER_OMAP4:
207 src = &omap44xx_phy_feats;
208 break;
209
210 case OMAPDSS_VER_OMAP5:
211 case OMAPDSS_VER_DRA7xx:
212 src = &omap54xx_phy_feats;
213 break;
214
215 default:
216 return -ENODEV;
217 }
218
219 memcpy(dst, src, sizeof(*dst));
220 phy_feat = dst;
221
222 return 0;
223}
224
225int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
226{
227 int r;
228 struct resource *res;
229
230 r = hdmi_phy_init_features(pdev);
231 if (r)
232 return r;
233
234 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
235 if (!res) {
236 DSSERR("can't get PHY mem resource\n");
237 return -EINVAL;
238 }
239
240 phy->base = devm_ioremap_resource(&pdev->dev, res);
241 if (IS_ERR(phy->base)) {
242 DSSERR("can't ioremap TX PHY\n");
243 return PTR_ERR(phy->base);
244 }
245
246 return 0;
247}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
new file mode 100644
index 000000000000..06e23a7c432c
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
@@ -0,0 +1,255 @@
1/*
2 * HDMI PLL
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#define DSS_SUBSYS_NAME "HDMIPLL"
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <linux/clk.h>
19
20#include <video/omapdss.h>
21
22#include "dss.h"
23#include "hdmi.h"
24
25void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
26{
27#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
28 hdmi_read_reg(pll->base, r))
29
30 DUMPPLL(PLLCTRL_PLL_CONTROL);
31 DUMPPLL(PLLCTRL_PLL_STATUS);
32 DUMPPLL(PLLCTRL_PLL_GO);
33 DUMPPLL(PLLCTRL_CFG1);
34 DUMPPLL(PLLCTRL_CFG2);
35 DUMPPLL(PLLCTRL_CFG3);
36 DUMPPLL(PLLCTRL_SSC_CFG1);
37 DUMPPLL(PLLCTRL_SSC_CFG2);
38 DUMPPLL(PLLCTRL_CFG4);
39}
40
41void hdmi_pll_compute(struct hdmi_pll_data *pll,
42 unsigned long target_tmds, struct dss_pll_clock_info *pi)
43{
44 unsigned long fint, clkdco, clkout;
45 unsigned long target_bitclk, target_clkdco;
46 unsigned long min_dco;
47 unsigned n, m, mf, m2, sd;
48 unsigned long clkin;
49 const struct dss_pll_hw *hw = pll->pll.hw;
50
51 clkin = clk_get_rate(pll->pll.clkin);
52
53 DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
54
55 target_bitclk = target_tmds * 10;
56
57 /* Fint */
58 n = DIV_ROUND_UP(clkin, hw->fint_max);
59 fint = clkin / n;
60
61 /* adjust m2 so that the clkdco will be high enough */
62 min_dco = roundup(hw->clkdco_min, fint);
63 m2 = DIV_ROUND_UP(min_dco, target_bitclk);
64 if (m2 == 0)
65 m2 = 1;
66
67 target_clkdco = target_bitclk * m2;
68 m = target_clkdco / fint;
69
70 clkdco = fint * m;
71
72 /* adjust clkdco with fractional mf */
73 if (WARN_ON(target_clkdco - clkdco > fint))
74 mf = 0;
75 else
76 mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
77
78 if (mf > 0)
79 clkdco += (u32)div_u64((u64)mf * fint, 262144);
80
81 clkout = clkdco / m2;
82
83 /* sigma-delta */
84 sd = DIV_ROUND_UP(fint * m, 250000000);
85
86 DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
87 n, m, mf, m2, sd);
88 DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
89
90 pi->n = n;
91 pi->m = m;
92 pi->mf = mf;
93 pi->mX[0] = m2;
94 pi->sd = sd;
95
96 pi->fint = fint;
97 pi->clkdco = clkdco;
98 pi->clkout[0] = clkout;
99}
100
101static int hdmi_pll_enable(struct dss_pll *dsspll)
102{
103 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
104 struct hdmi_wp_data *wp = pll->wp;
105 u16 r = 0;
106
107 dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
108
109 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
110 if (r)
111 return r;
112
113 return 0;
114}
115
116static void hdmi_pll_disable(struct dss_pll *dsspll)
117{
118 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
119 struct hdmi_wp_data *wp = pll->wp;
120
121 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
122
123 dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
124}
125
126static const struct dss_pll_ops dsi_pll_ops = {
127 .enable = hdmi_pll_enable,
128 .disable = hdmi_pll_disable,
129 .set_config = dss_pll_write_config_type_b,
130};
131
132static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
133 .n_max = 255,
134 .m_min = 20,
135 .m_max = 4095,
136 .mX_max = 127,
137 .fint_min = 500000,
138 .fint_max = 2500000,
139
140 .clkdco_min = 500000000,
141 .clkdco_low = 1000000000,
142 .clkdco_max = 2000000000,
143
144 .n_msb = 8,
145 .n_lsb = 1,
146 .m_msb = 20,
147 .m_lsb = 9,
148
149 .mX_msb[0] = 24,
150 .mX_lsb[0] = 18,
151
152 .has_selfreqdco = true,
153};
154
155static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
156 .n_max = 255,
157 .m_min = 20,
158 .m_max = 2045,
159 .mX_max = 127,
160 .fint_min = 620000,
161 .fint_max = 2500000,
162
163 .clkdco_min = 750000000,
164 .clkdco_low = 1500000000,
165 .clkdco_max = 2500000000UL,
166
167 .n_msb = 8,
168 .n_lsb = 1,
169 .m_msb = 20,
170 .m_lsb = 9,
171
172 .mX_msb[0] = 24,
173 .mX_lsb[0] = 18,
174
175 .has_selfreqdco = true,
176 .has_refsel = true,
177};
178
179static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
180{
181 struct dss_pll *pll = &hpll->pll;
182 struct clk *clk;
183 int r;
184
185 clk = devm_clk_get(&pdev->dev, "sys_clk");
186 if (IS_ERR(clk)) {
187 DSSERR("can't get sys_clk\n");
188 return PTR_ERR(clk);
189 }
190
191 pll->name = "hdmi";
192 pll->id = DSS_PLL_HDMI;
193 pll->base = hpll->base;
194 pll->clkin = clk;
195
196 switch (omapdss_get_version()) {
197 case OMAPDSS_VER_OMAP4430_ES1:
198 case OMAPDSS_VER_OMAP4430_ES2:
199 case OMAPDSS_VER_OMAP4:
200 pll->hw = &dss_omap4_hdmi_pll_hw;
201 break;
202
203 case OMAPDSS_VER_OMAP5:
204 case OMAPDSS_VER_DRA7xx:
205 pll->hw = &dss_omap5_hdmi_pll_hw;
206 break;
207
208 default:
209 return -ENODEV;
210 }
211
212 pll->ops = &dsi_pll_ops;
213
214 r = dss_pll_register(pll);
215 if (r)
216 return r;
217
218 return 0;
219}
220
221int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
222 struct hdmi_wp_data *wp)
223{
224 int r;
225 struct resource *res;
226
227 pll->wp = wp;
228
229 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
230 if (!res) {
231 DSSERR("can't get PLL mem resource\n");
232 return -EINVAL;
233 }
234
235 pll->base = devm_ioremap_resource(&pdev->dev, res);
236 if (IS_ERR(pll->base)) {
237 DSSERR("can't ioremap PLLCTRL\n");
238 return PTR_ERR(pll->base);
239 }
240
241 r = dsi_init_pll_data(pdev, pll);
242 if (r) {
243 DSSERR("failed to init HDMI PLL\n");
244 return r;
245 }
246
247 return 0;
248}
249
250void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
251{
252 struct dss_pll *pll = &hpll->pll;
253
254 dss_pll_unregister(pll);
255}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
new file mode 100644
index 000000000000..7c544bc56fb5
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
@@ -0,0 +1,282 @@
1/*
2 * HDMI wrapper
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#define DSS_SUBSYS_NAME "HDMIWP"
12
13#include <linux/kernel.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/platform_device.h>
17#include <video/omapdss.h>
18
19#include "dss.h"
20#include "hdmi.h"
21
22void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
23{
24#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
25
26 DUMPREG(HDMI_WP_REVISION);
27 DUMPREG(HDMI_WP_SYSCONFIG);
28 DUMPREG(HDMI_WP_IRQSTATUS_RAW);
29 DUMPREG(HDMI_WP_IRQSTATUS);
30 DUMPREG(HDMI_WP_IRQENABLE_SET);
31 DUMPREG(HDMI_WP_IRQENABLE_CLR);
32 DUMPREG(HDMI_WP_IRQWAKEEN);
33 DUMPREG(HDMI_WP_PWR_CTRL);
34 DUMPREG(HDMI_WP_DEBOUNCE);
35 DUMPREG(HDMI_WP_VIDEO_CFG);
36 DUMPREG(HDMI_WP_VIDEO_SIZE);
37 DUMPREG(HDMI_WP_VIDEO_TIMING_H);
38 DUMPREG(HDMI_WP_VIDEO_TIMING_V);
39 DUMPREG(HDMI_WP_CLK);
40 DUMPREG(HDMI_WP_AUDIO_CFG);
41 DUMPREG(HDMI_WP_AUDIO_CFG2);
42 DUMPREG(HDMI_WP_AUDIO_CTRL);
43 DUMPREG(HDMI_WP_AUDIO_DATA);
44}
45
46u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
47{
48 return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
49}
50
51void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
52{
53 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
54 /* flush posted write */
55 hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
56}
57
58void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
59{
60 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
61}
62
63void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
64{
65 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
66}
67
68/* PHY_PWR_CMD */
69int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
70{
71 /* Return if already the state */
72 if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
73 return 0;
74
75 /* Command for power control of HDMI PHY */
76 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
77
78 /* Status of the power control of HDMI PHY */
79 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
80 != val) {
81 DSSERR("Failed to set PHY power mode to %d\n", val);
82 return -ETIMEDOUT;
83 }
84
85 return 0;
86}
87
88/* PLL_PWR_CMD */
89int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
90{
91 /* Command for power control of HDMI PLL */
92 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
93
94 /* wait till PHY_PWR_STATUS is set */
95 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
96 != val) {
97 DSSERR("Failed to set PLL_PWR_STATUS\n");
98 return -ETIMEDOUT;
99 }
100
101 return 0;
102}
103
104int hdmi_wp_video_start(struct hdmi_wp_data *wp)
105{
106 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
107
108 return 0;
109}
110
111void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
112{
113 int i;
114
115 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);
116
117 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
118
119 for (i = 0; i < 50; ++i) {
120 u32 v;
121
122 msleep(20);
123
124 v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
125 if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
126 return;
127 }
128
129 DSSERR("no HDMI FRAMEDONE when disabling output\n");
130}
131
132void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
133 struct hdmi_video_format *video_fmt)
134{
135 u32 l = 0;
136
137 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
138 10, 8);
139
140 l |= FLD_VAL(video_fmt->y_res, 31, 16);
141 l |= FLD_VAL(video_fmt->x_res, 15, 0);
142 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
143}
144
145void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
146 struct omap_video_timings *timings)
147{
148 u32 r;
149 bool vsync_pol, hsync_pol;
150 DSSDBG("Enter hdmi_wp_video_config_interface\n");
151
152 vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
153 hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
154
155 r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
156 r = FLD_MOD(r, vsync_pol, 7, 7);
157 r = FLD_MOD(r, hsync_pol, 6, 6);
158 r = FLD_MOD(r, timings->interlace, 3, 3);
159 r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
160 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
161}
162
163void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
164 struct omap_video_timings *timings)
165{
166 u32 timing_h = 0;
167 u32 timing_v = 0;
168
169 DSSDBG("Enter hdmi_wp_video_config_timing\n");
170
171 timing_h |= FLD_VAL(timings->hbp, 31, 20);
172 timing_h |= FLD_VAL(timings->hfp, 19, 8);
173 timing_h |= FLD_VAL(timings->hsw, 7, 0);
174 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
175
176 timing_v |= FLD_VAL(timings->vbp, 31, 20);
177 timing_v |= FLD_VAL(timings->vfp, 19, 8);
178 timing_v |= FLD_VAL(timings->vsw, 7, 0);
179 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
180}
181
182void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
183 struct omap_video_timings *timings, struct hdmi_config *param)
184{
185 DSSDBG("Enter hdmi_wp_video_init_format\n");
186
187 video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
188 video_fmt->y_res = param->timings.y_res;
189 video_fmt->x_res = param->timings.x_res;
190 if (param->timings.interlace)
191 video_fmt->y_res /= 2;
192
193 timings->hbp = param->timings.hbp;
194 timings->hfp = param->timings.hfp;
195 timings->hsw = param->timings.hsw;
196 timings->vbp = param->timings.vbp;
197 timings->vfp = param->timings.vfp;
198 timings->vsw = param->timings.vsw;
199 timings->vsync_level = param->timings.vsync_level;
200 timings->hsync_level = param->timings.hsync_level;
201 timings->interlace = param->timings.interlace;
202}
203
204void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
205 struct hdmi_audio_format *aud_fmt)
206{
207 u32 r;
208
209 DSSDBG("Enter hdmi_wp_audio_config_format\n");
210
211 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
212 if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
213 omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
214 omapdss_get_version() == OMAPDSS_VER_OMAP4) {
215 r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
216 r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
217 }
218 r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
219 r = FLD_MOD(r, aud_fmt->type, 4, 4);
220 r = FLD_MOD(r, aud_fmt->justification, 3, 3);
221 r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
222 r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
223 r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
224 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
225}
226
227void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
228 struct hdmi_audio_dma *aud_dma)
229{
230 u32 r;
231
232 DSSDBG("Enter hdmi_wp_audio_config_dma\n");
233
234 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
235 r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
236 r = FLD_MOD(r, aud_dma->block_size, 7, 0);
237 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
238
239 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
240 r = FLD_MOD(r, aud_dma->mode, 9, 9);
241 r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
242 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
243}
244
245int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
246{
247 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
248
249 return 0;
250}
251
252int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
253{
254 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
255
256 return 0;
257}
258
259int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
260{
261 struct resource *res;
262
263 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
264 if (!res) {
265 DSSERR("can't get WP mem resource\n");
266 return -EINVAL;
267 }
268 wp->phys_base = res->start;
269
270 wp->base = devm_ioremap_resource(&pdev->dev, res);
271 if (IS_ERR(wp->base)) {
272 DSSERR("can't ioremap HDMI WP\n");
273 return PTR_ERR(wp->base);
274 }
275
276 return 0;
277}
278
279phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
280{
281 return wp->phys_base + HDMI_WP_AUDIO_DATA;
282}
diff --git a/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c b/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c
new file mode 100644
index 000000000000..a7414fb12830
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c
@@ -0,0 +1,531 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "MANAGER"
22
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/jiffies.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33
34static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
35{
36 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
37}
38
39static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
40{
41 struct omap_dss_device *dssdev = mgr->get_device(mgr);
42
43 return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
44 dssdev->name : "<none>");
45}
46
47static int manager_display_match(struct omap_dss_device *dssdev, void *data)
48{
49 const char *str = data;
50
51 return sysfs_streq(dssdev->name, str);
52}
53
54static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
55 const char *buf, size_t size)
56{
57 int r = 0;
58 size_t len = size;
59 struct omap_dss_device *dssdev = NULL;
60 struct omap_dss_device *old_dssdev;
61
62 if (buf[size-1] == '\n')
63 --len;
64
65 if (len > 0)
66 dssdev = omap_dss_find_device((void *)buf,
67 manager_display_match);
68
69 if (len > 0 && dssdev == NULL)
70 return -EINVAL;
71
72 if (dssdev) {
73 DSSDBG("display %s found\n", dssdev->name);
74
75 if (omapdss_device_is_connected(dssdev)) {
76 DSSERR("new display is already connected\n");
77 r = -EINVAL;
78 goto put_device;
79 }
80
81 if (omapdss_device_is_enabled(dssdev)) {
82 DSSERR("new display is not disabled\n");
83 r = -EINVAL;
84 goto put_device;
85 }
86 }
87
88 old_dssdev = mgr->get_device(mgr);
89 if (old_dssdev) {
90 if (omapdss_device_is_enabled(old_dssdev)) {
91 DSSERR("old display is not disabled\n");
92 r = -EINVAL;
93 goto put_device;
94 }
95
96 old_dssdev->driver->disconnect(old_dssdev);
97 }
98
99 if (dssdev) {
100 r = dssdev->driver->connect(dssdev);
101 if (r) {
102 DSSERR("failed to connect new device\n");
103 goto put_device;
104 }
105
106 old_dssdev = mgr->get_device(mgr);
107 if (old_dssdev != dssdev) {
108 DSSERR("failed to connect device to this manager\n");
109 dssdev->driver->disconnect(dssdev);
110 goto put_device;
111 }
112
113 r = mgr->apply(mgr);
114 if (r) {
115 DSSERR("failed to apply dispc config\n");
116 goto put_device;
117 }
118 }
119
120put_device:
121 if (dssdev)
122 omap_dss_put_device(dssdev);
123
124 return r ? r : size;
125}
126
127static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
128 char *buf)
129{
130 struct omap_overlay_manager_info info;
131
132 mgr->get_manager_info(mgr, &info);
133
134 return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
135}
136
137static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
138 const char *buf, size_t size)
139{
140 struct omap_overlay_manager_info info;
141 u32 color;
142 int r;
143
144 r = kstrtouint(buf, 0, &color);
145 if (r)
146 return r;
147
148 mgr->get_manager_info(mgr, &info);
149
150 info.default_color = color;
151
152 r = mgr->set_manager_info(mgr, &info);
153 if (r)
154 return r;
155
156 r = mgr->apply(mgr);
157 if (r)
158 return r;
159
160 return size;
161}
162
163static const char *trans_key_type_str[] = {
164 "gfx-destination",
165 "video-source",
166};
167
168static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
169 char *buf)
170{
171 enum omap_dss_trans_key_type key_type;
172 struct omap_overlay_manager_info info;
173
174 mgr->get_manager_info(mgr, &info);
175
176 key_type = info.trans_key_type;
177 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
178
179 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
180}
181
182static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
183 const char *buf, size_t size)
184{
185 enum omap_dss_trans_key_type key_type;
186 struct omap_overlay_manager_info info;
187 int r;
188
189 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
190 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
191 if (sysfs_streq(buf, trans_key_type_str[key_type]))
192 break;
193 }
194
195 if (key_type == ARRAY_SIZE(trans_key_type_str))
196 return -EINVAL;
197
198 mgr->get_manager_info(mgr, &info);
199
200 info.trans_key_type = key_type;
201
202 r = mgr->set_manager_info(mgr, &info);
203 if (r)
204 return r;
205
206 r = mgr->apply(mgr);
207 if (r)
208 return r;
209
210 return size;
211}
212
213static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
214 char *buf)
215{
216 struct omap_overlay_manager_info info;
217
218 mgr->get_manager_info(mgr, &info);
219
220 return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
221}
222
223static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
224 const char *buf, size_t size)
225{
226 struct omap_overlay_manager_info info;
227 u32 key_value;
228 int r;
229
230 r = kstrtouint(buf, 0, &key_value);
231 if (r)
232 return r;
233
234 mgr->get_manager_info(mgr, &info);
235
236 info.trans_key = key_value;
237
238 r = mgr->set_manager_info(mgr, &info);
239 if (r)
240 return r;
241
242 r = mgr->apply(mgr);
243 if (r)
244 return r;
245
246 return size;
247}
248
249static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
250 char *buf)
251{
252 struct omap_overlay_manager_info info;
253
254 mgr->get_manager_info(mgr, &info);
255
256 return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
257}
258
259static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
260 const char *buf, size_t size)
261{
262 struct omap_overlay_manager_info info;
263 bool enable;
264 int r;
265
266 r = strtobool(buf, &enable);
267 if (r)
268 return r;
269
270 mgr->get_manager_info(mgr, &info);
271
272 info.trans_enabled = enable;
273
274 r = mgr->set_manager_info(mgr, &info);
275 if (r)
276 return r;
277
278 r = mgr->apply(mgr);
279 if (r)
280 return r;
281
282 return size;
283}
284
285static ssize_t manager_alpha_blending_enabled_show(
286 struct omap_overlay_manager *mgr, char *buf)
287{
288 struct omap_overlay_manager_info info;
289
290 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
291 return -ENODEV;
292
293 mgr->get_manager_info(mgr, &info);
294
295 return snprintf(buf, PAGE_SIZE, "%d\n",
296 info.partial_alpha_enabled);
297}
298
299static ssize_t manager_alpha_blending_enabled_store(
300 struct omap_overlay_manager *mgr,
301 const char *buf, size_t size)
302{
303 struct omap_overlay_manager_info info;
304 bool enable;
305 int r;
306
307 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
308 return -ENODEV;
309
310 r = strtobool(buf, &enable);
311 if (r)
312 return r;
313
314 mgr->get_manager_info(mgr, &info);
315
316 info.partial_alpha_enabled = enable;
317
318 r = mgr->set_manager_info(mgr, &info);
319 if (r)
320 return r;
321
322 r = mgr->apply(mgr);
323 if (r)
324 return r;
325
326 return size;
327}
328
329static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
330 char *buf)
331{
332 struct omap_overlay_manager_info info;
333
334 mgr->get_manager_info(mgr, &info);
335
336 return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
337}
338
339static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
340 const char *buf, size_t size)
341{
342 struct omap_overlay_manager_info info;
343 int r;
344 bool enable;
345
346 if (!dss_has_feature(FEAT_CPR))
347 return -ENODEV;
348
349 r = strtobool(buf, &enable);
350 if (r)
351 return r;
352
353 mgr->get_manager_info(mgr, &info);
354
355 if (info.cpr_enable == enable)
356 return size;
357
358 info.cpr_enable = enable;
359
360 r = mgr->set_manager_info(mgr, &info);
361 if (r)
362 return r;
363
364 r = mgr->apply(mgr);
365 if (r)
366 return r;
367
368 return size;
369}
370
371static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
372 char *buf)
373{
374 struct omap_overlay_manager_info info;
375
376 mgr->get_manager_info(mgr, &info);
377
378 return snprintf(buf, PAGE_SIZE,
379 "%d %d %d %d %d %d %d %d %d\n",
380 info.cpr_coefs.rr,
381 info.cpr_coefs.rg,
382 info.cpr_coefs.rb,
383 info.cpr_coefs.gr,
384 info.cpr_coefs.gg,
385 info.cpr_coefs.gb,
386 info.cpr_coefs.br,
387 info.cpr_coefs.bg,
388 info.cpr_coefs.bb);
389}
390
391static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
392 const char *buf, size_t size)
393{
394 struct omap_overlay_manager_info info;
395 struct omap_dss_cpr_coefs coefs;
396 int r, i;
397 s16 *arr;
398
399 if (!dss_has_feature(FEAT_CPR))
400 return -ENODEV;
401
402 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
403 &coefs.rr, &coefs.rg, &coefs.rb,
404 &coefs.gr, &coefs.gg, &coefs.gb,
405 &coefs.br, &coefs.bg, &coefs.bb) != 9)
406 return -EINVAL;
407
408 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
409 coefs.gr, coefs.gg, coefs.gb,
410 coefs.br, coefs.bg, coefs.bb };
411
412 for (i = 0; i < 9; ++i) {
413 if (arr[i] < -512 || arr[i] > 511)
414 return -EINVAL;
415 }
416
417 mgr->get_manager_info(mgr, &info);
418
419 info.cpr_coefs = coefs;
420
421 r = mgr->set_manager_info(mgr, &info);
422 if (r)
423 return r;
424
425 r = mgr->apply(mgr);
426 if (r)
427 return r;
428
429 return size;
430}
431
432struct manager_attribute {
433 struct attribute attr;
434 ssize_t (*show)(struct omap_overlay_manager *, char *);
435 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
436};
437
438#define MANAGER_ATTR(_name, _mode, _show, _store) \
439 struct manager_attribute manager_attr_##_name = \
440 __ATTR(_name, _mode, _show, _store)
441
442static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
443static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
444 manager_display_show, manager_display_store);
445static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
446 manager_default_color_show, manager_default_color_store);
447static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
448 manager_trans_key_type_show, manager_trans_key_type_store);
449static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
450 manager_trans_key_value_show, manager_trans_key_value_store);
451static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
452 manager_trans_key_enabled_show,
453 manager_trans_key_enabled_store);
454static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
455 manager_alpha_blending_enabled_show,
456 manager_alpha_blending_enabled_store);
457static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
458 manager_cpr_enable_show,
459 manager_cpr_enable_store);
460static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
461 manager_cpr_coef_show,
462 manager_cpr_coef_store);
463
464
465static struct attribute *manager_sysfs_attrs[] = {
466 &manager_attr_name.attr,
467 &manager_attr_display.attr,
468 &manager_attr_default_color.attr,
469 &manager_attr_trans_key_type.attr,
470 &manager_attr_trans_key_value.attr,
471 &manager_attr_trans_key_enabled.attr,
472 &manager_attr_alpha_blending_enabled.attr,
473 &manager_attr_cpr_enable.attr,
474 &manager_attr_cpr_coef.attr,
475 NULL
476};
477
478static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
479 char *buf)
480{
481 struct omap_overlay_manager *manager;
482 struct manager_attribute *manager_attr;
483
484 manager = container_of(kobj, struct omap_overlay_manager, kobj);
485 manager_attr = container_of(attr, struct manager_attribute, attr);
486
487 if (!manager_attr->show)
488 return -ENOENT;
489
490 return manager_attr->show(manager, buf);
491}
492
493static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
494 const char *buf, size_t size)
495{
496 struct omap_overlay_manager *manager;
497 struct manager_attribute *manager_attr;
498
499 manager = container_of(kobj, struct omap_overlay_manager, kobj);
500 manager_attr = container_of(attr, struct manager_attribute, attr);
501
502 if (!manager_attr->store)
503 return -ENOENT;
504
505 return manager_attr->store(manager, buf, size);
506}
507
508static const struct sysfs_ops manager_sysfs_ops = {
509 .show = manager_attr_show,
510 .store = manager_attr_store,
511};
512
513static struct kobj_type manager_ktype = {
514 .sysfs_ops = &manager_sysfs_ops,
515 .default_attrs = manager_sysfs_attrs,
516};
517
518int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
519 struct platform_device *pdev)
520{
521 return kobject_init_and_add(&mgr->kobj, &manager_ktype,
522 &pdev->dev.kobj, "manager%d", mgr->id);
523}
524
525void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
526{
527 kobject_del(&mgr->kobj);
528 kobject_put(&mgr->kobj);
529
530 memset(&mgr->kobj, 0, sizeof(mgr->kobj));
531}
diff --git a/drivers/gpu/drm/omapdrm/dss/manager.c b/drivers/gpu/drm/omapdrm/dss/manager.c
new file mode 100644
index 000000000000..08a67f4f6a20
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/manager.c
@@ -0,0 +1,263 @@
1/*
2 * linux/drivers/video/omap2/dss/manager.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "MANAGER"
24
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/jiffies.h>
30
31#include <video/omapdss.h>
32
33#include "dss.h"
34#include "dss_features.h"
35
36static int num_managers;
37static struct omap_overlay_manager *managers;
38
39int dss_init_overlay_managers(void)
40{
41 int i;
42
43 num_managers = dss_feat_get_num_mgrs();
44
45 managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
46 GFP_KERNEL);
47
48 BUG_ON(managers == NULL);
49
50 for (i = 0; i < num_managers; ++i) {
51 struct omap_overlay_manager *mgr = &managers[i];
52
53 switch (i) {
54 case 0:
55 mgr->name = "lcd";
56 mgr->id = OMAP_DSS_CHANNEL_LCD;
57 break;
58 case 1:
59 mgr->name = "tv";
60 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
61 break;
62 case 2:
63 mgr->name = "lcd2";
64 mgr->id = OMAP_DSS_CHANNEL_LCD2;
65 break;
66 case 3:
67 mgr->name = "lcd3";
68 mgr->id = OMAP_DSS_CHANNEL_LCD3;
69 break;
70 }
71
72 mgr->caps = 0;
73 mgr->supported_displays =
74 dss_feat_get_supported_displays(mgr->id);
75 mgr->supported_outputs =
76 dss_feat_get_supported_outputs(mgr->id);
77
78 INIT_LIST_HEAD(&mgr->overlays);
79 }
80
81 return 0;
82}
83
84int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
85{
86 int i, r;
87
88 for (i = 0; i < num_managers; ++i) {
89 struct omap_overlay_manager *mgr = &managers[i];
90
91 r = dss_manager_kobj_init(mgr, pdev);
92 if (r)
93 DSSERR("failed to create sysfs file\n");
94 }
95
96 return 0;
97}
98
99void dss_uninit_overlay_managers(void)
100{
101 kfree(managers);
102 managers = NULL;
103 num_managers = 0;
104}
105
106void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
107{
108 int i;
109
110 for (i = 0; i < num_managers; ++i) {
111 struct omap_overlay_manager *mgr = &managers[i];
112
113 dss_manager_kobj_uninit(mgr);
114 }
115}
116
117int omap_dss_get_num_overlay_managers(void)
118{
119 return num_managers;
120}
121EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
122
123struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
124{
125 if (num >= num_managers)
126 return NULL;
127
128 return &managers[num];
129}
130EXPORT_SYMBOL(omap_dss_get_overlay_manager);
131
132int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
133 const struct omap_overlay_manager_info *info)
134{
135 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
136 /*
137 * OMAP3 supports only graphics source transparency color key
138 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
139 * Alpha Mode.
140 */
141 if (info->partial_alpha_enabled && info->trans_enabled
142 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
143 DSSERR("check_manager: illegal transparency key\n");
144 return -EINVAL;
145 }
146 }
147
148 return 0;
149}
150
151static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
152 struct omap_overlay_info **overlay_infos)
153{
154 struct omap_overlay *ovl1, *ovl2;
155 struct omap_overlay_info *info1, *info2;
156
157 list_for_each_entry(ovl1, &mgr->overlays, list) {
158 info1 = overlay_infos[ovl1->id];
159
160 if (info1 == NULL)
161 continue;
162
163 list_for_each_entry(ovl2, &mgr->overlays, list) {
164 if (ovl1 == ovl2)
165 continue;
166
167 info2 = overlay_infos[ovl2->id];
168
169 if (info2 == NULL)
170 continue;
171
172 if (info1->zorder == info2->zorder) {
173 DSSERR("overlays %d and %d have the same "
174 "zorder %d\n",
175 ovl1->id, ovl2->id, info1->zorder);
176 return -EINVAL;
177 }
178 }
179 }
180
181 return 0;
182}
183
184int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
185 const struct omap_video_timings *timings)
186{
187 if (!dispc_mgr_timings_ok(mgr->id, timings)) {
188 DSSERR("check_manager: invalid timings\n");
189 return -EINVAL;
190 }
191
192 return 0;
193}
194
195static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
196 const struct dss_lcd_mgr_config *config)
197{
198 struct dispc_clock_info cinfo = config->clock_info;
199 int dl = config->video_port_width;
200 bool stallmode = config->stallmode;
201 bool fifohandcheck = config->fifohandcheck;
202
203 if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
204 return -EINVAL;
205
206 if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
207 return -EINVAL;
208
209 if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
210 return -EINVAL;
211
212 /* fifohandcheck should be used only with stallmode */
213 if (!stallmode && fifohandcheck)
214 return -EINVAL;
215
216 /*
217 * io pad mode can be only checked by using dssdev connected to the
218 * manager. Ignore checking these for now, add checks when manager
219 * is capable of holding information related to the connected interface
220 */
221
222 return 0;
223}
224
225int dss_mgr_check(struct omap_overlay_manager *mgr,
226 struct omap_overlay_manager_info *info,
227 const struct omap_video_timings *mgr_timings,
228 const struct dss_lcd_mgr_config *lcd_config,
229 struct omap_overlay_info **overlay_infos)
230{
231 struct omap_overlay *ovl;
232 int r;
233
234 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
235 r = dss_mgr_check_zorder(mgr, overlay_infos);
236 if (r)
237 return r;
238 }
239
240 r = dss_mgr_check_timings(mgr, mgr_timings);
241 if (r)
242 return r;
243
244 r = dss_mgr_check_lcd_config(mgr, lcd_config);
245 if (r)
246 return r;
247
248 list_for_each_entry(ovl, &mgr->overlays, list) {
249 struct omap_overlay_info *oi;
250 int r;
251
252 oi = overlay_infos[ovl->id];
253
254 if (oi == NULL)
255 continue;
256
257 r = dss_ovl_check(ovl, oi, mgr_timings);
258 if (r)
259 return r;
260 }
261
262 return 0;
263}
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
new file mode 100644
index 000000000000..136d30484d02
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2014 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/*
19 * As omapdss panel drivers are omapdss specific, but we want to define the
20 * DT-data in generic manner, we convert the compatible strings of the panel and
21 * encoder nodes from "panel-foo" to "omapdss,panel-foo". This way we can have
22 * both correct DT data and omapdss specific drivers.
23 *
24 * When we get generic panel drivers to the kernel, this file will be removed.
25 */
26
27#include <linux/kernel.h>
28#include <linux/of.h>
29#include <linux/of_graph.h>
30#include <linux/slab.h>
31#include <linux/list.h>
32
33static struct list_head dss_conv_list __initdata;
34
35static const char prefix[] __initconst = "omapdss,";
36
37struct dss_conv_node {
38 struct list_head list;
39 struct device_node *node;
40 bool root;
41};
42
43static int __init omapdss_count_strings(const struct property *prop)
44{
45 const char *p = prop->value;
46 int l = 0, total = 0;
47 int i;
48
49 for (i = 0; total < prop->length; total += l, p += l, i++)
50 l = strlen(p) + 1;
51
52 return i;
53}
54
55static void __init omapdss_update_prop(struct device_node *node, char *compat,
56 int len)
57{
58 struct property *prop;
59
60 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
61 if (!prop)
62 return;
63
64 prop->name = "compatible";
65 prop->value = compat;
66 prop->length = len;
67
68 of_update_property(node, prop);
69}
70
71static void __init omapdss_prefix_strcpy(char *dst, int dst_len,
72 const char *src, int src_len)
73{
74 size_t total = 0;
75
76 while (total < src_len) {
77 size_t l = strlen(src) + 1;
78
79 strcpy(dst, prefix);
80 dst += strlen(prefix);
81
82 strcpy(dst, src);
83 dst += l;
84
85 src += l;
86 total += l;
87 }
88}
89
90/* prepend compatible property strings with "omapdss," */
91static void __init omapdss_omapify_node(struct device_node *node)
92{
93 struct property *prop;
94 char *new_compat;
95 int num_strs;
96 int new_len;
97
98 prop = of_find_property(node, "compatible", NULL);
99
100 if (!prop || !prop->value)
101 return;
102
103 if (strnlen(prop->value, prop->length) >= prop->length)
104 return;
105
106 /* is it already prefixed? */
107 if (strncmp(prefix, prop->value, strlen(prefix)) == 0)
108 return;
109
110 num_strs = omapdss_count_strings(prop);
111
112 new_len = prop->length + strlen(prefix) * num_strs;
113 new_compat = kmalloc(new_len, GFP_KERNEL);
114
115 omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
116
117 omapdss_update_prop(node, new_compat, new_len);
118}
119
120static void __init omapdss_add_to_list(struct device_node *node, bool root)
121{
122 struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
123 GFP_KERNEL);
124 if (n) {
125 n->node = node;
126 n->root = root;
127 list_add(&n->list, &dss_conv_list);
128 }
129}
130
131static bool __init omapdss_list_contains(const struct device_node *node)
132{
133 struct dss_conv_node *n;
134
135 list_for_each_entry(n, &dss_conv_list, list) {
136 if (n->node == node)
137 return true;
138 }
139
140 return false;
141}
142
143static void __init omapdss_walk_device(struct device_node *node, bool root)
144{
145 struct device_node *n;
146
147 omapdss_add_to_list(node, root);
148
149 /*
150 * of_graph_get_remote_port_parent() prints an error if there is no
151 * port/ports node. To avoid that, check first that there's the node.
152 */
153 n = of_get_child_by_name(node, "ports");
154 if (!n)
155 n = of_get_child_by_name(node, "port");
156 if (!n)
157 return;
158
159 of_node_put(n);
160
161 n = NULL;
162 while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
163 struct device_node *pn;
164
165 pn = of_graph_get_remote_port_parent(n);
166
167 if (!pn)
168 continue;
169
170 if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
171 of_node_put(pn);
172 continue;
173 }
174
175 omapdss_walk_device(pn, false);
176 }
177}
178
179static const struct of_device_id omapdss_of_match[] __initconst = {
180 { .compatible = "ti,omap2-dss", },
181 { .compatible = "ti,omap3-dss", },
182 { .compatible = "ti,omap4-dss", },
183 { .compatible = "ti,omap5-dss", },
184 { .compatible = "ti,dra7-dss", },
185 {},
186};
187
188static int __init omapdss_boot_init(void)
189{
190 struct device_node *dss, *child;
191
192 INIT_LIST_HEAD(&dss_conv_list);
193
194 dss = of_find_matching_node(NULL, omapdss_of_match);
195
196 if (dss == NULL || !of_device_is_available(dss))
197 return 0;
198
199 omapdss_walk_device(dss, true);
200
201 for_each_available_child_of_node(dss, child) {
202 if (!of_find_property(child, "compatible", NULL))
203 continue;
204
205 omapdss_walk_device(child, true);
206 }
207
208 while (!list_empty(&dss_conv_list)) {
209 struct dss_conv_node *n;
210
211 n = list_first_entry(&dss_conv_list, struct dss_conv_node,
212 list);
213
214 if (!n->root)
215 omapdss_omapify_node(n->node);
216
217 list_del(&n->list);
218 of_node_put(n->node);
219 kfree(n);
220 }
221
222 return 0;
223}
224
225subsys_initcall(omapdss_boot_init);
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
new file mode 100644
index 000000000000..16072159bd24
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -0,0 +1,267 @@
1/*
2 * Copyright (C) 2012 Texas Instruments Ltd
3 * Author: Archit Taneja <archit@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#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23
24#include <video/omapdss.h>
25
26#include "dss.h"
27
28static LIST_HEAD(output_list);
29static DEFINE_MUTEX(output_lock);
30
31int omapdss_output_set_device(struct omap_dss_device *out,
32 struct omap_dss_device *dssdev)
33{
34 int r;
35
36 mutex_lock(&output_lock);
37
38 if (out->dst) {
39 DSSERR("output already has device %s connected to it\n",
40 out->dst->name);
41 r = -EINVAL;
42 goto err;
43 }
44
45 if (out->output_type != dssdev->type) {
46 DSSERR("output type and display type don't match\n");
47 r = -EINVAL;
48 goto err;
49 }
50
51 out->dst = dssdev;
52 dssdev->src = out;
53
54 mutex_unlock(&output_lock);
55
56 return 0;
57err:
58 mutex_unlock(&output_lock);
59
60 return r;
61}
62EXPORT_SYMBOL(omapdss_output_set_device);
63
64int omapdss_output_unset_device(struct omap_dss_device *out)
65{
66 int r;
67
68 mutex_lock(&output_lock);
69
70 if (!out->dst) {
71 DSSERR("output doesn't have a device connected to it\n");
72 r = -EINVAL;
73 goto err;
74 }
75
76 if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
77 DSSERR("device %s is not disabled, cannot unset device\n",
78 out->dst->name);
79 r = -EINVAL;
80 goto err;
81 }
82
83 out->dst->src = NULL;
84 out->dst = NULL;
85
86 mutex_unlock(&output_lock);
87
88 return 0;
89err:
90 mutex_unlock(&output_lock);
91
92 return r;
93}
94EXPORT_SYMBOL(omapdss_output_unset_device);
95
96int omapdss_register_output(struct omap_dss_device *out)
97{
98 list_add_tail(&out->list, &output_list);
99 return 0;
100}
101EXPORT_SYMBOL(omapdss_register_output);
102
103void omapdss_unregister_output(struct omap_dss_device *out)
104{
105 list_del(&out->list);
106}
107EXPORT_SYMBOL(omapdss_unregister_output);
108
109struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
110{
111 struct omap_dss_device *out;
112
113 list_for_each_entry(out, &output_list, list) {
114 if (out->id == id)
115 return out;
116 }
117
118 return NULL;
119}
120EXPORT_SYMBOL(omap_dss_get_output);
121
122struct omap_dss_device *omap_dss_find_output(const char *name)
123{
124 struct omap_dss_device *out;
125
126 list_for_each_entry(out, &output_list, list) {
127 if (strcmp(out->name, name) == 0)
128 return omap_dss_get_device(out);
129 }
130
131 return NULL;
132}
133EXPORT_SYMBOL(omap_dss_find_output);
134
135struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
136{
137 struct device_node *src_node;
138 struct omap_dss_device *out;
139 u32 reg;
140
141 src_node = dss_of_port_get_parent_device(port);
142 if (!src_node)
143 return NULL;
144
145 reg = dss_of_port_get_port_number(port);
146
147 list_for_each_entry(out, &output_list, list) {
148 if (out->dev->of_node == src_node && out->port_num == reg) {
149 of_node_put(src_node);
150 return omap_dss_get_device(out);
151 }
152 }
153
154 of_node_put(src_node);
155
156 return NULL;
157}
158EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
159
160struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
161{
162 while (dssdev->src)
163 dssdev = dssdev->src;
164
165 if (dssdev->id != 0)
166 return omap_dss_get_device(dssdev);
167
168 return NULL;
169}
170EXPORT_SYMBOL(omapdss_find_output_from_display);
171
172struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev)
173{
174 struct omap_dss_device *out;
175 struct omap_overlay_manager *mgr;
176
177 out = omapdss_find_output_from_display(dssdev);
178
179 if (out == NULL)
180 return NULL;
181
182 mgr = out->manager;
183
184 omap_dss_put_device(out);
185
186 return mgr;
187}
188EXPORT_SYMBOL(omapdss_find_mgr_from_display);
189
190static const struct dss_mgr_ops *dss_mgr_ops;
191
192int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
193{
194 if (dss_mgr_ops)
195 return -EBUSY;
196
197 dss_mgr_ops = mgr_ops;
198
199 return 0;
200}
201EXPORT_SYMBOL(dss_install_mgr_ops);
202
203void dss_uninstall_mgr_ops(void)
204{
205 dss_mgr_ops = NULL;
206}
207EXPORT_SYMBOL(dss_uninstall_mgr_ops);
208
209int dss_mgr_connect(struct omap_overlay_manager *mgr,
210 struct omap_dss_device *dst)
211{
212 return dss_mgr_ops->connect(mgr, dst);
213}
214EXPORT_SYMBOL(dss_mgr_connect);
215
216void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
217 struct omap_dss_device *dst)
218{
219 dss_mgr_ops->disconnect(mgr, dst);
220}
221EXPORT_SYMBOL(dss_mgr_disconnect);
222
223void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
224 const struct omap_video_timings *timings)
225{
226 dss_mgr_ops->set_timings(mgr, timings);
227}
228EXPORT_SYMBOL(dss_mgr_set_timings);
229
230void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
231 const struct dss_lcd_mgr_config *config)
232{
233 dss_mgr_ops->set_lcd_config(mgr, config);
234}
235EXPORT_SYMBOL(dss_mgr_set_lcd_config);
236
237int dss_mgr_enable(struct omap_overlay_manager *mgr)
238{
239 return dss_mgr_ops->enable(mgr);
240}
241EXPORT_SYMBOL(dss_mgr_enable);
242
243void dss_mgr_disable(struct omap_overlay_manager *mgr)
244{
245 dss_mgr_ops->disable(mgr);
246}
247EXPORT_SYMBOL(dss_mgr_disable);
248
249void dss_mgr_start_update(struct omap_overlay_manager *mgr)
250{
251 dss_mgr_ops->start_update(mgr);
252}
253EXPORT_SYMBOL(dss_mgr_start_update);
254
255int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
256 void (*handler)(void *), void *data)
257{
258 return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
259}
260EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
261
262void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
263 void (*handler)(void *), void *data)
264{
265 dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
266}
267EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);
diff --git a/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c b/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c
new file mode 100644
index 000000000000..4cc5ddebfb34
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c
@@ -0,0 +1,456 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "OVERLAY"
22
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/sysfs.h>
26#include <linux/kobject.h>
27#include <linux/platform_device.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33
34static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
35{
36 return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
37}
38
39static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
40{
41 return snprintf(buf, PAGE_SIZE, "%s\n",
42 ovl->manager ? ovl->manager->name : "<none>");
43}
44
45static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
46 size_t size)
47{
48 int i, r;
49 struct omap_overlay_manager *mgr = NULL;
50 struct omap_overlay_manager *old_mgr;
51 int len = size;
52
53 if (buf[size-1] == '\n')
54 --len;
55
56 if (len > 0) {
57 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
58 mgr = omap_dss_get_overlay_manager(i);
59
60 if (sysfs_streq(buf, mgr->name))
61 break;
62
63 mgr = NULL;
64 }
65 }
66
67 if (len > 0 && mgr == NULL)
68 return -EINVAL;
69
70 if (mgr)
71 DSSDBG("manager %s found\n", mgr->name);
72
73 if (mgr == ovl->manager)
74 return size;
75
76 old_mgr = ovl->manager;
77
78 r = dispc_runtime_get();
79 if (r)
80 return r;
81
82 /* detach old manager */
83 if (old_mgr) {
84 r = ovl->unset_manager(ovl);
85 if (r) {
86 DSSERR("detach failed\n");
87 goto err;
88 }
89
90 r = old_mgr->apply(old_mgr);
91 if (r)
92 goto err;
93 }
94
95 if (mgr) {
96 r = ovl->set_manager(ovl, mgr);
97 if (r) {
98 DSSERR("Failed to attach overlay\n");
99 goto err;
100 }
101
102 r = mgr->apply(mgr);
103 if (r)
104 goto err;
105 }
106
107 dispc_runtime_put();
108
109 return size;
110
111err:
112 dispc_runtime_put();
113 return r;
114}
115
116static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
117{
118 struct omap_overlay_info info;
119
120 ovl->get_overlay_info(ovl, &info);
121
122 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
123 info.width, info.height);
124}
125
126static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
127{
128 struct omap_overlay_info info;
129
130 ovl->get_overlay_info(ovl, &info);
131
132 return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
133}
134
135static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
136{
137 struct omap_overlay_info info;
138
139 ovl->get_overlay_info(ovl, &info);
140
141 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
142 info.pos_x, info.pos_y);
143}
144
145static ssize_t overlay_position_store(struct omap_overlay *ovl,
146 const char *buf, size_t size)
147{
148 int r;
149 char *last;
150 struct omap_overlay_info info;
151
152 ovl->get_overlay_info(ovl, &info);
153
154 info.pos_x = simple_strtoul(buf, &last, 10);
155 ++last;
156 if (last - buf >= size)
157 return -EINVAL;
158
159 info.pos_y = simple_strtoul(last, &last, 10);
160
161 r = ovl->set_overlay_info(ovl, &info);
162 if (r)
163 return r;
164
165 if (ovl->manager) {
166 r = ovl->manager->apply(ovl->manager);
167 if (r)
168 return r;
169 }
170
171 return size;
172}
173
174static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
175{
176 struct omap_overlay_info info;
177
178 ovl->get_overlay_info(ovl, &info);
179
180 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
181 info.out_width, info.out_height);
182}
183
184static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
185 const char *buf, size_t size)
186{
187 int r;
188 char *last;
189 struct omap_overlay_info info;
190
191 ovl->get_overlay_info(ovl, &info);
192
193 info.out_width = simple_strtoul(buf, &last, 10);
194 ++last;
195 if (last - buf >= size)
196 return -EINVAL;
197
198 info.out_height = simple_strtoul(last, &last, 10);
199
200 r = ovl->set_overlay_info(ovl, &info);
201 if (r)
202 return r;
203
204 if (ovl->manager) {
205 r = ovl->manager->apply(ovl->manager);
206 if (r)
207 return r;
208 }
209
210 return size;
211}
212
213static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
214{
215 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
216}
217
218static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
219 size_t size)
220{
221 int r;
222 bool enable;
223
224 r = strtobool(buf, &enable);
225 if (r)
226 return r;
227
228 if (enable)
229 r = ovl->enable(ovl);
230 else
231 r = ovl->disable(ovl);
232
233 if (r)
234 return r;
235
236 return size;
237}
238
239static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
240{
241 struct omap_overlay_info info;
242
243 ovl->get_overlay_info(ovl, &info);
244
245 return snprintf(buf, PAGE_SIZE, "%d\n",
246 info.global_alpha);
247}
248
249static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
250 const char *buf, size_t size)
251{
252 int r;
253 u8 alpha;
254 struct omap_overlay_info info;
255
256 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
257 return -ENODEV;
258
259 r = kstrtou8(buf, 0, &alpha);
260 if (r)
261 return r;
262
263 ovl->get_overlay_info(ovl, &info);
264
265 info.global_alpha = alpha;
266
267 r = ovl->set_overlay_info(ovl, &info);
268 if (r)
269 return r;
270
271 if (ovl->manager) {
272 r = ovl->manager->apply(ovl->manager);
273 if (r)
274 return r;
275 }
276
277 return size;
278}
279
280static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
281 char *buf)
282{
283 struct omap_overlay_info info;
284
285 ovl->get_overlay_info(ovl, &info);
286
287 return snprintf(buf, PAGE_SIZE, "%d\n",
288 info.pre_mult_alpha);
289}
290
291static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
292 const char *buf, size_t size)
293{
294 int r;
295 u8 alpha;
296 struct omap_overlay_info info;
297
298 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
299 return -ENODEV;
300
301 r = kstrtou8(buf, 0, &alpha);
302 if (r)
303 return r;
304
305 ovl->get_overlay_info(ovl, &info);
306
307 info.pre_mult_alpha = alpha;
308
309 r = ovl->set_overlay_info(ovl, &info);
310 if (r)
311 return r;
312
313 if (ovl->manager) {
314 r = ovl->manager->apply(ovl->manager);
315 if (r)
316 return r;
317 }
318
319 return size;
320}
321
322static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
323{
324 struct omap_overlay_info info;
325
326 ovl->get_overlay_info(ovl, &info);
327
328 return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
329}
330
331static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
332 const char *buf, size_t size)
333{
334 int r;
335 u8 zorder;
336 struct omap_overlay_info info;
337
338 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
339 return -ENODEV;
340
341 r = kstrtou8(buf, 0, &zorder);
342 if (r)
343 return r;
344
345 ovl->get_overlay_info(ovl, &info);
346
347 info.zorder = zorder;
348
349 r = ovl->set_overlay_info(ovl, &info);
350 if (r)
351 return r;
352
353 if (ovl->manager) {
354 r = ovl->manager->apply(ovl->manager);
355 if (r)
356 return r;
357 }
358
359 return size;
360}
361
362struct overlay_attribute {
363 struct attribute attr;
364 ssize_t (*show)(struct omap_overlay *, char *);
365 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
366};
367
368#define OVERLAY_ATTR(_name, _mode, _show, _store) \
369 struct overlay_attribute overlay_attr_##_name = \
370 __ATTR(_name, _mode, _show, _store)
371
372static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
373static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
374 overlay_manager_show, overlay_manager_store);
375static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
376static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
377static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
378 overlay_position_show, overlay_position_store);
379static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
380 overlay_output_size_show, overlay_output_size_store);
381static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
382 overlay_enabled_show, overlay_enabled_store);
383static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
384 overlay_global_alpha_show, overlay_global_alpha_store);
385static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
386 overlay_pre_mult_alpha_show,
387 overlay_pre_mult_alpha_store);
388static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
389 overlay_zorder_show, overlay_zorder_store);
390
391static struct attribute *overlay_sysfs_attrs[] = {
392 &overlay_attr_name.attr,
393 &overlay_attr_manager.attr,
394 &overlay_attr_input_size.attr,
395 &overlay_attr_screen_width.attr,
396 &overlay_attr_position.attr,
397 &overlay_attr_output_size.attr,
398 &overlay_attr_enabled.attr,
399 &overlay_attr_global_alpha.attr,
400 &overlay_attr_pre_mult_alpha.attr,
401 &overlay_attr_zorder.attr,
402 NULL
403};
404
405static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
406 char *buf)
407{
408 struct omap_overlay *overlay;
409 struct overlay_attribute *overlay_attr;
410
411 overlay = container_of(kobj, struct omap_overlay, kobj);
412 overlay_attr = container_of(attr, struct overlay_attribute, attr);
413
414 if (!overlay_attr->show)
415 return -ENOENT;
416
417 return overlay_attr->show(overlay, buf);
418}
419
420static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
421 const char *buf, size_t size)
422{
423 struct omap_overlay *overlay;
424 struct overlay_attribute *overlay_attr;
425
426 overlay = container_of(kobj, struct omap_overlay, kobj);
427 overlay_attr = container_of(attr, struct overlay_attribute, attr);
428
429 if (!overlay_attr->store)
430 return -ENOENT;
431
432 return overlay_attr->store(overlay, buf, size);
433}
434
435static const struct sysfs_ops overlay_sysfs_ops = {
436 .show = overlay_attr_show,
437 .store = overlay_attr_store,
438};
439
440static struct kobj_type overlay_ktype = {
441 .sysfs_ops = &overlay_sysfs_ops,
442 .default_attrs = overlay_sysfs_attrs,
443};
444
445int dss_overlay_kobj_init(struct omap_overlay *ovl,
446 struct platform_device *pdev)
447{
448 return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
449 &pdev->dev.kobj, "overlay%d", ovl->id);
450}
451
452void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
453{
454 kobject_del(&ovl->kobj);
455 kobject_put(&ovl->kobj);
456}
diff --git a/drivers/gpu/drm/omapdrm/dss/overlay.c b/drivers/gpu/drm/omapdrm/dss/overlay.c
new file mode 100644
index 000000000000..2f7cee985cdd
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/overlay.c
@@ -0,0 +1,202 @@
1/*
2 * linux/drivers/video/omap2/dss/overlay.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "OVERLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/err.h>
28#include <linux/sysfs.h>
29#include <linux/platform_device.h>
30#include <linux/delay.h>
31#include <linux/slab.h>
32
33#include <video/omapdss.h>
34
35#include "dss.h"
36#include "dss_features.h"
37
38static int num_overlays;
39static struct omap_overlay *overlays;
40
41int omap_dss_get_num_overlays(void)
42{
43 return num_overlays;
44}
45EXPORT_SYMBOL(omap_dss_get_num_overlays);
46
47struct omap_overlay *omap_dss_get_overlay(int num)
48{
49 if (num >= num_overlays)
50 return NULL;
51
52 return &overlays[num];
53}
54EXPORT_SYMBOL(omap_dss_get_overlay);
55
56void dss_init_overlays(struct platform_device *pdev)
57{
58 int i, r;
59
60 num_overlays = dss_feat_get_num_ovls();
61
62 overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
63 GFP_KERNEL);
64
65 BUG_ON(overlays == NULL);
66
67 for (i = 0; i < num_overlays; ++i) {
68 struct omap_overlay *ovl = &overlays[i];
69
70 switch (i) {
71 case 0:
72 ovl->name = "gfx";
73 ovl->id = OMAP_DSS_GFX;
74 break;
75 case 1:
76 ovl->name = "vid1";
77 ovl->id = OMAP_DSS_VIDEO1;
78 break;
79 case 2:
80 ovl->name = "vid2";
81 ovl->id = OMAP_DSS_VIDEO2;
82 break;
83 case 3:
84 ovl->name = "vid3";
85 ovl->id = OMAP_DSS_VIDEO3;
86 break;
87 }
88
89 ovl->caps = dss_feat_get_overlay_caps(ovl->id);
90 ovl->supported_modes =
91 dss_feat_get_supported_color_modes(ovl->id);
92
93 r = dss_overlay_kobj_init(ovl, pdev);
94 if (r)
95 DSSERR("failed to create sysfs file\n");
96 }
97}
98
99void dss_uninit_overlays(struct platform_device *pdev)
100{
101 int i;
102
103 for (i = 0; i < num_overlays; ++i) {
104 struct omap_overlay *ovl = &overlays[i];
105 dss_overlay_kobj_uninit(ovl);
106 }
107
108 kfree(overlays);
109 overlays = NULL;
110 num_overlays = 0;
111}
112
113int dss_ovl_simple_check(struct omap_overlay *ovl,
114 const struct omap_overlay_info *info)
115{
116 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
117 if (info->out_width != 0 && info->width != info->out_width) {
118 DSSERR("check_overlay: overlay %d doesn't support "
119 "scaling\n", ovl->id);
120 return -EINVAL;
121 }
122
123 if (info->out_height != 0 && info->height != info->out_height) {
124 DSSERR("check_overlay: overlay %d doesn't support "
125 "scaling\n", ovl->id);
126 return -EINVAL;
127 }
128 }
129
130 if ((ovl->supported_modes & info->color_mode) == 0) {
131 DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
132 ovl->id, info->color_mode);
133 return -EINVAL;
134 }
135
136 if (info->zorder >= omap_dss_get_num_overlays()) {
137 DSSERR("check_overlay: zorder %d too high\n", info->zorder);
138 return -EINVAL;
139 }
140
141 if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
142 DSSERR("check_overlay: rotation type %d not supported\n",
143 info->rotation_type);
144 return -EINVAL;
145 }
146
147 return 0;
148}
149
150int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
151 const struct omap_video_timings *mgr_timings)
152{
153 u16 outw, outh;
154 u16 dw, dh;
155
156 dw = mgr_timings->x_res;
157 dh = mgr_timings->y_res;
158
159 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
160 outw = info->width;
161 outh = info->height;
162 } else {
163 if (info->out_width == 0)
164 outw = info->width;
165 else
166 outw = info->out_width;
167
168 if (info->out_height == 0)
169 outh = info->height;
170 else
171 outh = info->out_height;
172 }
173
174 if (dw < info->pos_x + outw) {
175 DSSERR("overlay %d horizontally not inside the display area "
176 "(%d + %d >= %d)\n",
177 ovl->id, info->pos_x, outw, dw);
178 return -EINVAL;
179 }
180
181 if (dh < info->pos_y + outh) {
182 DSSERR("overlay %d vertically not inside the display area "
183 "(%d + %d >= %d)\n",
184 ovl->id, info->pos_y, outh, dh);
185 return -EINVAL;
186 }
187
188 return 0;
189}
190
191/*
192 * Checks if replication logic should be used. Only use when overlay is in
193 * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
194 */
195bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
196 enum omap_color_mode mode)
197{
198 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
199 return false;
200
201 return config.video_port_width > 16;
202}
diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c
new file mode 100644
index 000000000000..f974ddcd3b6e
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/pll.c
@@ -0,0 +1,389 @@
1/*
2 * Copyright (C) 2014 Texas Instruments Incorporated
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#define DSS_SUBSYS_NAME "PLL"
18
19#include <linux/clk.h>
20#include <linux/io.h>
21#include <linux/kernel.h>
22#include <linux/regulator/consumer.h>
23#include <linux/sched.h>
24
25#include <video/omapdss.h>
26
27#include "dss.h"
28
29#define PLL_CONTROL 0x0000
30#define PLL_STATUS 0x0004
31#define PLL_GO 0x0008
32#define PLL_CONFIGURATION1 0x000C
33#define PLL_CONFIGURATION2 0x0010
34#define PLL_CONFIGURATION3 0x0014
35#define PLL_SSC_CONFIGURATION1 0x0018
36#define PLL_SSC_CONFIGURATION2 0x001C
37#define PLL_CONFIGURATION4 0x0020
38
39static struct dss_pll *dss_plls[4];
40
41int dss_pll_register(struct dss_pll *pll)
42{
43 int i;
44
45 for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
46 if (!dss_plls[i]) {
47 dss_plls[i] = pll;
48 return 0;
49 }
50 }
51
52 return -EBUSY;
53}
54
55void dss_pll_unregister(struct dss_pll *pll)
56{
57 int i;
58
59 for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
60 if (dss_plls[i] == pll) {
61 dss_plls[i] = NULL;
62 return;
63 }
64 }
65}
66
67struct dss_pll *dss_pll_find(const char *name)
68{
69 int i;
70
71 for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
72 if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
73 return dss_plls[i];
74 }
75
76 return NULL;
77}
78
79int dss_pll_enable(struct dss_pll *pll)
80{
81 int r;
82
83 r = clk_prepare_enable(pll->clkin);
84 if (r)
85 return r;
86
87 if (pll->regulator) {
88 r = regulator_enable(pll->regulator);
89 if (r)
90 goto err_reg;
91 }
92
93 r = pll->ops->enable(pll);
94 if (r)
95 goto err_enable;
96
97 return 0;
98
99err_enable:
100 if (pll->regulator)
101 regulator_disable(pll->regulator);
102err_reg:
103 clk_disable_unprepare(pll->clkin);
104 return r;
105}
106
107void dss_pll_disable(struct dss_pll *pll)
108{
109 pll->ops->disable(pll);
110
111 if (pll->regulator)
112 regulator_disable(pll->regulator);
113
114 clk_disable_unprepare(pll->clkin);
115
116 memset(&pll->cinfo, 0, sizeof(pll->cinfo));
117}
118
119int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
120{
121 int r;
122
123 r = pll->ops->set_config(pll, cinfo);
124 if (r)
125 return r;
126
127 pll->cinfo = *cinfo;
128
129 return 0;
130}
131
132bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
133 unsigned long out_min, unsigned long out_max,
134 dss_hsdiv_calc_func func, void *data)
135{
136 const struct dss_pll_hw *hw = pll->hw;
137 int m, m_start, m_stop;
138 unsigned long out;
139
140 out_min = out_min ? out_min : 1;
141 out_max = out_max ? out_max : ULONG_MAX;
142
143 m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
144
145 m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
146
147 for (m = m_start; m <= m_stop; ++m) {
148 out = clkdco / m;
149
150 if (func(m, out, data))
151 return true;
152 }
153
154 return false;
155}
156
157bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
158 unsigned long pll_min, unsigned long pll_max,
159 dss_pll_calc_func func, void *data)
160{
161 const struct dss_pll_hw *hw = pll->hw;
162 int n, n_start, n_stop;
163 int m, m_start, m_stop;
164 unsigned long fint, clkdco;
165 unsigned long pll_hw_max;
166 unsigned long fint_hw_min, fint_hw_max;
167
168 pll_hw_max = hw->clkdco_max;
169
170 fint_hw_min = hw->fint_min;
171 fint_hw_max = hw->fint_max;
172
173 n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
174 n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
175
176 pll_max = pll_max ? pll_max : ULONG_MAX;
177
178 for (n = n_start; n <= n_stop; ++n) {
179 fint = clkin / n;
180
181 m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
182 1ul);
183 m_stop = min3((unsigned)(pll_max / fint / 2),
184 (unsigned)(pll_hw_max / fint / 2),
185 hw->m_max);
186
187 for (m = m_start; m <= m_stop; ++m) {
188 clkdco = 2 * m * fint;
189
190 if (func(n, m, fint, clkdco, data))
191 return true;
192 }
193 }
194
195 return false;
196}
197
198static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
199{
200 unsigned long timeout;
201 ktime_t wait;
202 int t;
203
204 /* first busyloop to see if the bit changes right away */
205 t = 100;
206 while (t-- > 0) {
207 if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
208 return value;
209 }
210
211 /* then loop for 500ms, sleeping for 1ms in between */
212 timeout = jiffies + msecs_to_jiffies(500);
213 while (time_before(jiffies, timeout)) {
214 if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
215 return value;
216
217 wait = ns_to_ktime(1000 * 1000);
218 set_current_state(TASK_UNINTERRUPTIBLE);
219 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
220 }
221
222 return !value;
223}
224
225int dss_pll_wait_reset_done(struct dss_pll *pll)
226{
227 void __iomem *base = pll->base;
228
229 if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)
230 return -ETIMEDOUT;
231 else
232 return 0;
233}
234
235static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
236{
237 int t = 100;
238
239 while (t-- > 0) {
240 u32 v = readl_relaxed(pll->base + PLL_STATUS);
241 v &= hsdiv_ack_mask;
242 if (v == hsdiv_ack_mask)
243 return 0;
244 }
245
246 return -ETIMEDOUT;
247}
248
249int dss_pll_write_config_type_a(struct dss_pll *pll,
250 const struct dss_pll_clock_info *cinfo)
251{
252 const struct dss_pll_hw *hw = pll->hw;
253 void __iomem *base = pll->base;
254 int r = 0;
255 u32 l;
256
257 l = 0;
258 if (hw->has_stopmode)
259 l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */
260 l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */
261 l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */
262 /* M4 */
263 l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
264 hw->mX_msb[0], hw->mX_lsb[0]);
265 /* M5 */
266 l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
267 hw->mX_msb[1], hw->mX_lsb[1]);
268 writel_relaxed(l, base + PLL_CONFIGURATION1);
269
270 l = 0;
271 /* M6 */
272 l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
273 hw->mX_msb[2], hw->mX_lsb[2]);
274 /* M7 */
275 l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
276 hw->mX_msb[3], hw->mX_lsb[3]);
277 writel_relaxed(l, base + PLL_CONFIGURATION3);
278
279 l = readl_relaxed(base + PLL_CONFIGURATION2);
280 if (hw->has_freqsel) {
281 u32 f = cinfo->fint < 1000000 ? 0x3 :
282 cinfo->fint < 1250000 ? 0x4 :
283 cinfo->fint < 1500000 ? 0x5 :
284 cinfo->fint < 1750000 ? 0x6 :
285 0x7;
286
287 l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */
288 } else if (hw->has_selfreqdco) {
289 u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
290
291 l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
292 }
293 l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */
294 l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */
295 l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */
296 l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */
297 l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */
298 if (hw->has_refsel)
299 l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */
300 l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */
301 l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
302 writel_relaxed(l, base + PLL_CONFIGURATION2);
303
304 writel_relaxed(1, base + PLL_GO); /* PLL_GO */
305
306 if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
307 DSSERR("DSS DPLL GO bit not going down.\n");
308 r = -EIO;
309 goto err;
310 }
311
312 if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
313 DSSERR("cannot lock DSS DPLL\n");
314 r = -EIO;
315 goto err;
316 }
317
318 l = readl_relaxed(base + PLL_CONFIGURATION2);
319 l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
320 l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */
321 l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */
322 l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */
323 l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */
324 l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */
325 writel_relaxed(l, base + PLL_CONFIGURATION2);
326
327 r = dss_wait_hsdiv_ack(pll,
328 (cinfo->mX[0] ? BIT(7) : 0) |
329 (cinfo->mX[1] ? BIT(8) : 0) |
330 (cinfo->mX[2] ? BIT(10) : 0) |
331 (cinfo->mX[3] ? BIT(11) : 0));
332 if (r) {
333 DSSERR("failed to enable HSDIV clocks\n");
334 goto err;
335 }
336
337err:
338 return r;
339}
340
341int dss_pll_write_config_type_b(struct dss_pll *pll,
342 const struct dss_pll_clock_info *cinfo)
343{
344 const struct dss_pll_hw *hw = pll->hw;
345 void __iomem *base = pll->base;
346 u32 l;
347
348 l = 0;
349 l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */
350 l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */
351 writel_relaxed(l, base + PLL_CONFIGURATION1);
352
353 l = readl_relaxed(base + PLL_CONFIGURATION2);
354 l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
355 l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */
356 l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */
357 if (hw->has_refsel)
358 l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */
359
360 /* PLL_SELFREQDCO */
361 if (cinfo->clkdco > hw->clkdco_low)
362 l = FLD_MOD(l, 0x4, 3, 1);
363 else
364 l = FLD_MOD(l, 0x2, 3, 1);
365 writel_relaxed(l, base + PLL_CONFIGURATION2);
366
367 l = readl_relaxed(base + PLL_CONFIGURATION3);
368 l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */
369 writel_relaxed(l, base + PLL_CONFIGURATION3);
370
371 l = readl_relaxed(base + PLL_CONFIGURATION4);
372 l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */
373 l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */
374 writel_relaxed(l, base + PLL_CONFIGURATION4);
375
376 writel_relaxed(1, base + PLL_GO); /* PLL_GO */
377
378 if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
379 DSSERR("DSS DPLL GO bit not going down.\n");
380 return -EIO;
381 }
382
383 if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
384 DSSERR("cannot lock DSS DPLL\n");
385 return -ETIMEDOUT;
386 }
387
388 return 0;
389}
diff --git a/drivers/gpu/drm/omapdrm/dss/rfbi.c b/drivers/gpu/drm/omapdrm/dss/rfbi.c
new file mode 100644
index 000000000000..aea6a1d0fb20
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/rfbi.c
@@ -0,0 +1,1078 @@
1/*
2 * linux/drivers/video/omap2/dss/rfbi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "RFBI"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/export.h>
28#include <linux/vmalloc.h>
29#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/delay.h>
32#include <linux/kfifo.h>
33#include <linux/ktime.h>
34#include <linux/hrtimer.h>
35#include <linux/seq_file.h>
36#include <linux/semaphore.h>
37#include <linux/platform_device.h>
38#include <linux/pm_runtime.h>
39#include <linux/component.h>
40
41#include <video/omapdss.h>
42#include "dss.h"
43
44struct rfbi_reg { u16 idx; };
45
46#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
47
48#define RFBI_REVISION RFBI_REG(0x0000)
49#define RFBI_SYSCONFIG RFBI_REG(0x0010)
50#define RFBI_SYSSTATUS RFBI_REG(0x0014)
51#define RFBI_CONTROL RFBI_REG(0x0040)
52#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
53#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
54#define RFBI_CMD RFBI_REG(0x004c)
55#define RFBI_PARAM RFBI_REG(0x0050)
56#define RFBI_DATA RFBI_REG(0x0054)
57#define RFBI_READ RFBI_REG(0x0058)
58#define RFBI_STATUS RFBI_REG(0x005c)
59
60#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
61#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
62#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
63#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
64#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
65#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
66
67#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
68#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
69
70#define REG_FLD_MOD(idx, val, start, end) \
71 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
72
73enum omap_rfbi_cycleformat {
74 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
75 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
76 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
77 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
78};
79
80enum omap_rfbi_datatype {
81 OMAP_DSS_RFBI_DATATYPE_12 = 0,
82 OMAP_DSS_RFBI_DATATYPE_16 = 1,
83 OMAP_DSS_RFBI_DATATYPE_18 = 2,
84 OMAP_DSS_RFBI_DATATYPE_24 = 3,
85};
86
87enum omap_rfbi_parallelmode {
88 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
89 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
90 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
91 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
92};
93
94static int rfbi_convert_timings(struct rfbi_timings *t);
95static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
96
97static struct {
98 struct platform_device *pdev;
99 void __iomem *base;
100
101 unsigned long l4_khz;
102
103 enum omap_rfbi_datatype datatype;
104 enum omap_rfbi_parallelmode parallelmode;
105
106 enum omap_rfbi_te_mode te_mode;
107 int te_enabled;
108
109 void (*framedone_callback)(void *data);
110 void *framedone_callback_data;
111
112 struct omap_dss_device *dssdev[2];
113
114 struct semaphore bus_lock;
115
116 struct omap_video_timings timings;
117 int pixel_size;
118 int data_lines;
119 struct rfbi_timings intf_timings;
120
121 struct omap_dss_device output;
122} rfbi;
123
124static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
125{
126 __raw_writel(val, rfbi.base + idx.idx);
127}
128
129static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
130{
131 return __raw_readl(rfbi.base + idx.idx);
132}
133
134static int rfbi_runtime_get(void)
135{
136 int r;
137
138 DSSDBG("rfbi_runtime_get\n");
139
140 r = pm_runtime_get_sync(&rfbi.pdev->dev);
141 WARN_ON(r < 0);
142 return r < 0 ? r : 0;
143}
144
145static void rfbi_runtime_put(void)
146{
147 int r;
148
149 DSSDBG("rfbi_runtime_put\n");
150
151 r = pm_runtime_put_sync(&rfbi.pdev->dev);
152 WARN_ON(r < 0 && r != -ENOSYS);
153}
154
155static void rfbi_bus_lock(void)
156{
157 down(&rfbi.bus_lock);
158}
159
160static void rfbi_bus_unlock(void)
161{
162 up(&rfbi.bus_lock);
163}
164
165static void rfbi_write_command(const void *buf, u32 len)
166{
167 switch (rfbi.parallelmode) {
168 case OMAP_DSS_RFBI_PARALLELMODE_8:
169 {
170 const u8 *b = buf;
171 for (; len; len--)
172 rfbi_write_reg(RFBI_CMD, *b++);
173 break;
174 }
175
176 case OMAP_DSS_RFBI_PARALLELMODE_16:
177 {
178 const u16 *w = buf;
179 BUG_ON(len & 1);
180 for (; len; len -= 2)
181 rfbi_write_reg(RFBI_CMD, *w++);
182 break;
183 }
184
185 case OMAP_DSS_RFBI_PARALLELMODE_9:
186 case OMAP_DSS_RFBI_PARALLELMODE_12:
187 default:
188 BUG();
189 }
190}
191
192static void rfbi_read_data(void *buf, u32 len)
193{
194 switch (rfbi.parallelmode) {
195 case OMAP_DSS_RFBI_PARALLELMODE_8:
196 {
197 u8 *b = buf;
198 for (; len; len--) {
199 rfbi_write_reg(RFBI_READ, 0);
200 *b++ = rfbi_read_reg(RFBI_READ);
201 }
202 break;
203 }
204
205 case OMAP_DSS_RFBI_PARALLELMODE_16:
206 {
207 u16 *w = buf;
208 BUG_ON(len & ~1);
209 for (; len; len -= 2) {
210 rfbi_write_reg(RFBI_READ, 0);
211 *w++ = rfbi_read_reg(RFBI_READ);
212 }
213 break;
214 }
215
216 case OMAP_DSS_RFBI_PARALLELMODE_9:
217 case OMAP_DSS_RFBI_PARALLELMODE_12:
218 default:
219 BUG();
220 }
221}
222
223static void rfbi_write_data(const void *buf, u32 len)
224{
225 switch (rfbi.parallelmode) {
226 case OMAP_DSS_RFBI_PARALLELMODE_8:
227 {
228 const u8 *b = buf;
229 for (; len; len--)
230 rfbi_write_reg(RFBI_PARAM, *b++);
231 break;
232 }
233
234 case OMAP_DSS_RFBI_PARALLELMODE_16:
235 {
236 const u16 *w = buf;
237 BUG_ON(len & 1);
238 for (; len; len -= 2)
239 rfbi_write_reg(RFBI_PARAM, *w++);
240 break;
241 }
242
243 case OMAP_DSS_RFBI_PARALLELMODE_9:
244 case OMAP_DSS_RFBI_PARALLELMODE_12:
245 default:
246 BUG();
247
248 }
249}
250
251static void rfbi_write_pixels(const void __iomem *buf, int scr_width,
252 u16 x, u16 y,
253 u16 w, u16 h)
254{
255 int start_offset = scr_width * y + x;
256 int horiz_offset = scr_width - w;
257 int i;
258
259 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
260 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
261 const u16 __iomem *pd = buf;
262 pd += start_offset;
263
264 for (; h; --h) {
265 for (i = 0; i < w; ++i) {
266 const u8 __iomem *b = (const u8 __iomem *)pd;
267 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
268 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
269 ++pd;
270 }
271 pd += horiz_offset;
272 }
273 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
274 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
275 const u32 __iomem *pd = buf;
276 pd += start_offset;
277
278 for (; h; --h) {
279 for (i = 0; i < w; ++i) {
280 const u8 __iomem *b = (const u8 __iomem *)pd;
281 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
282 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
283 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
284 ++pd;
285 }
286 pd += horiz_offset;
287 }
288 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
289 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
290 const u16 __iomem *pd = buf;
291 pd += start_offset;
292
293 for (; h; --h) {
294 for (i = 0; i < w; ++i) {
295 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
296 ++pd;
297 }
298 pd += horiz_offset;
299 }
300 } else {
301 BUG();
302 }
303}
304
305static int rfbi_transfer_area(struct omap_dss_device *dssdev,
306 void (*callback)(void *data), void *data)
307{
308 u32 l;
309 int r;
310 struct omap_overlay_manager *mgr = rfbi.output.manager;
311 u16 width = rfbi.timings.x_res;
312 u16 height = rfbi.timings.y_res;
313
314 /*BUG_ON(callback == 0);*/
315 BUG_ON(rfbi.framedone_callback != NULL);
316
317 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
318
319 dss_mgr_set_timings(mgr, &rfbi.timings);
320
321 r = dss_mgr_enable(mgr);
322 if (r)
323 return r;
324
325 rfbi.framedone_callback = callback;
326 rfbi.framedone_callback_data = data;
327
328 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
329
330 l = rfbi_read_reg(RFBI_CONTROL);
331 l = FLD_MOD(l, 1, 0, 0); /* enable */
332 if (!rfbi.te_enabled)
333 l = FLD_MOD(l, 1, 4, 4); /* ITE */
334
335 rfbi_write_reg(RFBI_CONTROL, l);
336
337 return 0;
338}
339
340static void framedone_callback(void *data)
341{
342 void (*callback)(void *data);
343
344 DSSDBG("FRAMEDONE\n");
345
346 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
347
348 callback = rfbi.framedone_callback;
349 rfbi.framedone_callback = NULL;
350
351 if (callback != NULL)
352 callback(rfbi.framedone_callback_data);
353}
354
355#if 1 /* VERBOSE */
356static void rfbi_print_timings(void)
357{
358 u32 l;
359 u32 time;
360
361 l = rfbi_read_reg(RFBI_CONFIG(0));
362 time = 1000000000 / rfbi.l4_khz;
363 if (l & (1 << 4))
364 time *= 2;
365
366 DSSDBG("Tick time %u ps\n", time);
367 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
368 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
369 "REONTIME %d, REOFFTIME %d\n",
370 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
371 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
372
373 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
374 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
375 "ACCESSTIME %d\n",
376 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
377 (l >> 22) & 0x3f);
378}
379#else
380static void rfbi_print_timings(void) {}
381#endif
382
383
384
385
386static u32 extif_clk_period;
387
388static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
389{
390 int bus_tick = extif_clk_period * div;
391 return (ps + bus_tick - 1) / bus_tick * bus_tick;
392}
393
394static int calc_reg_timing(struct rfbi_timings *t, int div)
395{
396 t->clk_div = div;
397
398 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
399
400 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
401 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
402 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
403
404 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
405 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
406 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
407
408 t->access_time = round_to_extif_ticks(t->access_time, div);
409 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
410 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
411
412 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
413 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
414 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
415 t->we_on_time, t->we_off_time, t->re_cycle_time,
416 t->we_cycle_time);
417 DSSDBG("[reg]rdaccess %d cspulse %d\n",
418 t->access_time, t->cs_pulse_width);
419
420 return rfbi_convert_timings(t);
421}
422
423static int calc_extif_timings(struct rfbi_timings *t)
424{
425 u32 max_clk_div;
426 int div;
427
428 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
429 for (div = 1; div <= max_clk_div; div++) {
430 if (calc_reg_timing(t, div) == 0)
431 break;
432 }
433
434 if (div <= max_clk_div)
435 return 0;
436
437 DSSERR("can't setup timings\n");
438 return -1;
439}
440
441
442static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
443{
444 int r;
445
446 if (!t->converted) {
447 r = calc_extif_timings(t);
448 if (r < 0)
449 DSSERR("Failed to calc timings\n");
450 }
451
452 BUG_ON(!t->converted);
453
454 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
455 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
456
457 /* TIMEGRANULARITY */
458 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
459 (t->tim[2] ? 1 : 0), 4, 4);
460
461 rfbi_print_timings();
462}
463
464static int ps_to_rfbi_ticks(int time, int div)
465{
466 unsigned long tick_ps;
467 int ret;
468
469 /* Calculate in picosecs to yield more exact results */
470 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
471
472 ret = (time + tick_ps - 1) / tick_ps;
473
474 return ret;
475}
476
477static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
478{
479 *clk_period = 1000000000 / rfbi.l4_khz;
480 *max_clk_div = 2;
481}
482
483static int rfbi_convert_timings(struct rfbi_timings *t)
484{
485 u32 l;
486 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
487 int actim, recyc, wecyc;
488 int div = t->clk_div;
489
490 if (div <= 0 || div > 2)
491 return -1;
492
493 /* Make sure that after conversion it still holds that:
494 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
495 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
496 */
497 weon = ps_to_rfbi_ticks(t->we_on_time, div);
498 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
499 if (weoff <= weon)
500 weoff = weon + 1;
501 if (weon > 0x0f)
502 return -1;
503 if (weoff > 0x3f)
504 return -1;
505
506 reon = ps_to_rfbi_ticks(t->re_on_time, div);
507 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
508 if (reoff <= reon)
509 reoff = reon + 1;
510 if (reon > 0x0f)
511 return -1;
512 if (reoff > 0x3f)
513 return -1;
514
515 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
516 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
517 if (csoff <= cson)
518 csoff = cson + 1;
519 if (csoff < max(weoff, reoff))
520 csoff = max(weoff, reoff);
521 if (cson > 0x0f)
522 return -1;
523 if (csoff > 0x3f)
524 return -1;
525
526 l = cson;
527 l |= csoff << 4;
528 l |= weon << 10;
529 l |= weoff << 14;
530 l |= reon << 20;
531 l |= reoff << 24;
532
533 t->tim[0] = l;
534
535 actim = ps_to_rfbi_ticks(t->access_time, div);
536 if (actim <= reon)
537 actim = reon + 1;
538 if (actim > 0x3f)
539 return -1;
540
541 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
542 if (wecyc < weoff)
543 wecyc = weoff;
544 if (wecyc > 0x3f)
545 return -1;
546
547 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
548 if (recyc < reoff)
549 recyc = reoff;
550 if (recyc > 0x3f)
551 return -1;
552
553 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
554 if (cs_pulse > 0x3f)
555 return -1;
556
557 l = wecyc;
558 l |= recyc << 6;
559 l |= cs_pulse << 12;
560 l |= actim << 22;
561
562 t->tim[1] = l;
563
564 t->tim[2] = div - 1;
565
566 t->converted = 1;
567
568 return 0;
569}
570
571/* xxx FIX module selection missing */
572static int rfbi_setup_te(enum omap_rfbi_te_mode mode,
573 unsigned hs_pulse_time, unsigned vs_pulse_time,
574 int hs_pol_inv, int vs_pol_inv, int extif_div)
575{
576 int hs, vs;
577 int min;
578 u32 l;
579
580 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
581 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
582 if (hs < 2)
583 return -EDOM;
584 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
585 min = 2;
586 else /* OMAP_DSS_RFBI_TE_MODE_1 */
587 min = 4;
588 if (vs < min)
589 return -EDOM;
590 if (vs == hs)
591 return -EINVAL;
592 rfbi.te_mode = mode;
593 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
594 mode, hs, vs, hs_pol_inv, vs_pol_inv);
595
596 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
597 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
598
599 l = rfbi_read_reg(RFBI_CONFIG(0));
600 if (hs_pol_inv)
601 l &= ~(1 << 21);
602 else
603 l |= 1 << 21;
604 if (vs_pol_inv)
605 l &= ~(1 << 20);
606 else
607 l |= 1 << 20;
608
609 return 0;
610}
611
612/* xxx FIX module selection missing */
613static int rfbi_enable_te(bool enable, unsigned line)
614{
615 u32 l;
616
617 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
618 if (line > (1 << 11) - 1)
619 return -EINVAL;
620
621 l = rfbi_read_reg(RFBI_CONFIG(0));
622 l &= ~(0x3 << 2);
623 if (enable) {
624 rfbi.te_enabled = 1;
625 l |= rfbi.te_mode << 2;
626 } else
627 rfbi.te_enabled = 0;
628 rfbi_write_reg(RFBI_CONFIG(0), l);
629 rfbi_write_reg(RFBI_LINE_NUMBER, line);
630
631 return 0;
632}
633
634static int rfbi_configure_bus(int rfbi_module, int bpp, int lines)
635{
636 u32 l;
637 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
638 enum omap_rfbi_cycleformat cycleformat;
639 enum omap_rfbi_datatype datatype;
640 enum omap_rfbi_parallelmode parallelmode;
641
642 switch (bpp) {
643 case 12:
644 datatype = OMAP_DSS_RFBI_DATATYPE_12;
645 break;
646 case 16:
647 datatype = OMAP_DSS_RFBI_DATATYPE_16;
648 break;
649 case 18:
650 datatype = OMAP_DSS_RFBI_DATATYPE_18;
651 break;
652 case 24:
653 datatype = OMAP_DSS_RFBI_DATATYPE_24;
654 break;
655 default:
656 BUG();
657 return 1;
658 }
659 rfbi.datatype = datatype;
660
661 switch (lines) {
662 case 8:
663 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
664 break;
665 case 9:
666 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
667 break;
668 case 12:
669 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
670 break;
671 case 16:
672 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
673 break;
674 default:
675 BUG();
676 return 1;
677 }
678 rfbi.parallelmode = parallelmode;
679
680 if ((bpp % lines) == 0) {
681 switch (bpp / lines) {
682 case 1:
683 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
684 break;
685 case 2:
686 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
687 break;
688 case 3:
689 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
690 break;
691 default:
692 BUG();
693 return 1;
694 }
695 } else if ((2 * bpp % lines) == 0) {
696 if ((2 * bpp / lines) == 3)
697 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
698 else {
699 BUG();
700 return 1;
701 }
702 } else {
703 BUG();
704 return 1;
705 }
706
707 switch (cycleformat) {
708 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
709 cycle1 = lines;
710 break;
711
712 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
713 cycle1 = lines;
714 cycle2 = lines;
715 break;
716
717 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
718 cycle1 = lines;
719 cycle2 = lines;
720 cycle3 = lines;
721 break;
722
723 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
724 cycle1 = lines;
725 cycle2 = (lines / 2) | ((lines / 2) << 16);
726 cycle3 = (lines << 16);
727 break;
728 }
729
730 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
731
732 l = 0;
733 l |= FLD_VAL(parallelmode, 1, 0);
734 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
735 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
736 l |= FLD_VAL(datatype, 6, 5);
737 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
738 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
739 l |= FLD_VAL(cycleformat, 10, 9);
740 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
741 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
742 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
743 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
744 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
745 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
746 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
747 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
748
749 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
750 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
751 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
752
753
754 l = rfbi_read_reg(RFBI_CONTROL);
755 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
756 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
757 rfbi_write_reg(RFBI_CONTROL, l);
758
759
760 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
761 bpp, lines, cycle1, cycle2, cycle3);
762
763 return 0;
764}
765
766static int rfbi_configure(struct omap_dss_device *dssdev)
767{
768 return rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
769 rfbi.data_lines);
770}
771
772static int rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
773 void *data)
774{
775 return rfbi_transfer_area(dssdev, callback, data);
776}
777
778static void rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
779{
780 rfbi.timings.x_res = w;
781 rfbi.timings.y_res = h;
782}
783
784static void rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
785{
786 rfbi.pixel_size = pixel_size;
787}
788
789static void rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
790{
791 rfbi.data_lines = data_lines;
792}
793
794static void rfbi_set_interface_timings(struct omap_dss_device *dssdev,
795 struct rfbi_timings *timings)
796{
797 rfbi.intf_timings = *timings;
798}
799
800static void rfbi_dump_regs(struct seq_file *s)
801{
802#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
803
804 if (rfbi_runtime_get())
805 return;
806
807 DUMPREG(RFBI_REVISION);
808 DUMPREG(RFBI_SYSCONFIG);
809 DUMPREG(RFBI_SYSSTATUS);
810 DUMPREG(RFBI_CONTROL);
811 DUMPREG(RFBI_PIXEL_CNT);
812 DUMPREG(RFBI_LINE_NUMBER);
813 DUMPREG(RFBI_CMD);
814 DUMPREG(RFBI_PARAM);
815 DUMPREG(RFBI_DATA);
816 DUMPREG(RFBI_READ);
817 DUMPREG(RFBI_STATUS);
818
819 DUMPREG(RFBI_CONFIG(0));
820 DUMPREG(RFBI_ONOFF_TIME(0));
821 DUMPREG(RFBI_CYCLE_TIME(0));
822 DUMPREG(RFBI_DATA_CYCLE1(0));
823 DUMPREG(RFBI_DATA_CYCLE2(0));
824 DUMPREG(RFBI_DATA_CYCLE3(0));
825
826 DUMPREG(RFBI_CONFIG(1));
827 DUMPREG(RFBI_ONOFF_TIME(1));
828 DUMPREG(RFBI_CYCLE_TIME(1));
829 DUMPREG(RFBI_DATA_CYCLE1(1));
830 DUMPREG(RFBI_DATA_CYCLE2(1));
831 DUMPREG(RFBI_DATA_CYCLE3(1));
832
833 DUMPREG(RFBI_VSYNC_WIDTH);
834 DUMPREG(RFBI_HSYNC_WIDTH);
835
836 rfbi_runtime_put();
837#undef DUMPREG
838}
839
840static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
841{
842 struct omap_overlay_manager *mgr = rfbi.output.manager;
843 struct dss_lcd_mgr_config mgr_config;
844
845 mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
846
847 mgr_config.stallmode = true;
848 /* Do we need fifohandcheck for RFBI? */
849 mgr_config.fifohandcheck = false;
850
851 mgr_config.video_port_width = rfbi.pixel_size;
852 mgr_config.lcden_sig_polarity = 0;
853
854 dss_mgr_set_lcd_config(mgr, &mgr_config);
855
856 /*
857 * Set rfbi.timings with default values, the x_res and y_res fields
858 * are expected to be already configured by the panel driver via
859 * omapdss_rfbi_set_size()
860 */
861 rfbi.timings.hsw = 1;
862 rfbi.timings.hfp = 1;
863 rfbi.timings.hbp = 1;
864 rfbi.timings.vsw = 1;
865 rfbi.timings.vfp = 0;
866 rfbi.timings.vbp = 0;
867
868 rfbi.timings.interlace = false;
869 rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
870 rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
871 rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
872 rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
873 rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
874
875 dss_mgr_set_timings(mgr, &rfbi.timings);
876}
877
878static int rfbi_display_enable(struct omap_dss_device *dssdev)
879{
880 struct omap_dss_device *out = &rfbi.output;
881 int r;
882
883 if (out->manager == NULL) {
884 DSSERR("failed to enable display: no output/manager\n");
885 return -ENODEV;
886 }
887
888 r = rfbi_runtime_get();
889 if (r)
890 return r;
891
892 r = dss_mgr_register_framedone_handler(out->manager,
893 framedone_callback, NULL);
894 if (r) {
895 DSSERR("can't get FRAMEDONE irq\n");
896 goto err1;
897 }
898
899 rfbi_config_lcd_manager(dssdev);
900
901 rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
902 rfbi.data_lines);
903
904 rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
905
906 return 0;
907err1:
908 rfbi_runtime_put();
909 return r;
910}
911
912static void rfbi_display_disable(struct omap_dss_device *dssdev)
913{
914 struct omap_dss_device *out = &rfbi.output;
915
916 dss_mgr_unregister_framedone_handler(out->manager,
917 framedone_callback, NULL);
918
919 rfbi_runtime_put();
920}
921
922static int rfbi_init_display(struct omap_dss_device *dssdev)
923{
924 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
925 return 0;
926}
927
928static void rfbi_init_output(struct platform_device *pdev)
929{
930 struct omap_dss_device *out = &rfbi.output;
931
932 out->dev = &pdev->dev;
933 out->id = OMAP_DSS_OUTPUT_DBI;
934 out->output_type = OMAP_DISPLAY_TYPE_DBI;
935 out->name = "rfbi.0";
936 out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
937 out->owner = THIS_MODULE;
938
939 omapdss_register_output(out);
940}
941
942static void rfbi_uninit_output(struct platform_device *pdev)
943{
944 struct omap_dss_device *out = &rfbi.output;
945
946 omapdss_unregister_output(out);
947}
948
949/* RFBI HW IP initialisation */
950static int rfbi_bind(struct device *dev, struct device *master, void *data)
951{
952 struct platform_device *pdev = to_platform_device(dev);
953 u32 rev;
954 struct resource *rfbi_mem;
955 struct clk *clk;
956 int r;
957
958 rfbi.pdev = pdev;
959
960 sema_init(&rfbi.bus_lock, 1);
961
962 rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
963 if (!rfbi_mem) {
964 DSSERR("can't get IORESOURCE_MEM RFBI\n");
965 return -EINVAL;
966 }
967
968 rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
969 resource_size(rfbi_mem));
970 if (!rfbi.base) {
971 DSSERR("can't ioremap RFBI\n");
972 return -ENOMEM;
973 }
974
975 clk = clk_get(&pdev->dev, "ick");
976 if (IS_ERR(clk)) {
977 DSSERR("can't get ick\n");
978 return PTR_ERR(clk);
979 }
980
981 rfbi.l4_khz = clk_get_rate(clk) / 1000;
982
983 clk_put(clk);
984
985 pm_runtime_enable(&pdev->dev);
986
987 r = rfbi_runtime_get();
988 if (r)
989 goto err_runtime_get;
990
991 msleep(10);
992
993 rev = rfbi_read_reg(RFBI_REVISION);
994 dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
995 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
996
997 rfbi_runtime_put();
998
999 dss_debugfs_create_file("rfbi", rfbi_dump_regs);
1000
1001 rfbi_init_output(pdev);
1002
1003 return 0;
1004
1005err_runtime_get:
1006 pm_runtime_disable(&pdev->dev);
1007 return r;
1008}
1009
1010static void rfbi_unbind(struct device *dev, struct device *master, void *data)
1011{
1012 struct platform_device *pdev = to_platform_device(dev);
1013
1014 rfbi_uninit_output(pdev);
1015
1016 pm_runtime_disable(&pdev->dev);
1017
1018 return 0;
1019}
1020
1021static const struct component_ops rfbi_component_ops = {
1022 .bind = rfbi_bind,
1023 .unbind = rfbi_unbind,
1024};
1025
1026static int rfbi_probe(struct platform_device *pdev)
1027{
1028 return component_add(&pdev->dev, &rfbi_component_ops);
1029}
1030
1031static int rfbi_remove(struct platform_device *pdev)
1032{
1033 component_del(&pdev->dev, &rfbi_component_ops);
1034 return 0;
1035}
1036
1037static int rfbi_runtime_suspend(struct device *dev)
1038{
1039 dispc_runtime_put();
1040
1041 return 0;
1042}
1043
1044static int rfbi_runtime_resume(struct device *dev)
1045{
1046 int r;
1047
1048 r = dispc_runtime_get();
1049 if (r < 0)
1050 return r;
1051
1052 return 0;
1053}
1054
1055static const struct dev_pm_ops rfbi_pm_ops = {
1056 .runtime_suspend = rfbi_runtime_suspend,
1057 .runtime_resume = rfbi_runtime_resume,
1058};
1059
1060static struct platform_driver omap_rfbihw_driver = {
1061 .probe = rfbi_probe,
1062 .remove = rfbi_remove,
1063 .driver = {
1064 .name = "omapdss_rfbi",
1065 .pm = &rfbi_pm_ops,
1066 .suppress_bind_attrs = true,
1067 },
1068};
1069
1070int __init rfbi_init_platform_driver(void)
1071{
1072 return platform_driver_register(&omap_rfbihw_driver);
1073}
1074
1075void rfbi_uninit_platform_driver(void)
1076{
1077 platform_driver_unregister(&omap_rfbihw_driver);
1078}
diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c
new file mode 100644
index 000000000000..d747cc6b59e1
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -0,0 +1,454 @@
1/*
2 * linux/drivers/video/omap2/dss/sdi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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#define DSS_SUBSYS_NAME "SDI"
21
22#include <linux/kernel.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/regulator/consumer.h>
26#include <linux/export.h>
27#include <linux/platform_device.h>
28#include <linux/string.h>
29#include <linux/of.h>
30#include <linux/component.h>
31
32#include <video/omapdss.h>
33#include "dss.h"
34
35static struct {
36 struct platform_device *pdev;
37
38 bool update_enabled;
39 struct regulator *vdds_sdi_reg;
40
41 struct dss_lcd_mgr_config mgr_config;
42 struct omap_video_timings timings;
43 int datapairs;
44
45 struct omap_dss_device output;
46
47 bool port_initialized;
48} sdi;
49
50struct sdi_clk_calc_ctx {
51 unsigned long pck_min, pck_max;
52
53 unsigned long fck;
54 struct dispc_clock_info dispc_cinfo;
55};
56
57static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
58 unsigned long pck, void *data)
59{
60 struct sdi_clk_calc_ctx *ctx = data;
61
62 ctx->dispc_cinfo.lck_div = lckd;
63 ctx->dispc_cinfo.pck_div = pckd;
64 ctx->dispc_cinfo.lck = lck;
65 ctx->dispc_cinfo.pck = pck;
66
67 return true;
68}
69
70static bool dpi_calc_dss_cb(unsigned long fck, void *data)
71{
72 struct sdi_clk_calc_ctx *ctx = data;
73
74 ctx->fck = fck;
75
76 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
77 dpi_calc_dispc_cb, ctx);
78}
79
80static int sdi_calc_clock_div(unsigned long pclk,
81 unsigned long *fck,
82 struct dispc_clock_info *dispc_cinfo)
83{
84 int i;
85 struct sdi_clk_calc_ctx ctx;
86
87 /*
88 * DSS fclk gives us very few possibilities, so finding a good pixel
89 * clock may not be possible. We try multiple times to find the clock,
90 * each time widening the pixel clock range we look for, up to
91 * +/- 1MHz.
92 */
93
94 for (i = 0; i < 10; ++i) {
95 bool ok;
96
97 memset(&ctx, 0, sizeof(ctx));
98 if (pclk > 1000 * i * i * i)
99 ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
100 else
101 ctx.pck_min = 0;
102 ctx.pck_max = pclk + 1000 * i * i * i;
103
104 ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx);
105 if (ok) {
106 *fck = ctx.fck;
107 *dispc_cinfo = ctx.dispc_cinfo;
108 return 0;
109 }
110 }
111
112 return -EINVAL;
113}
114
115static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
116{
117 struct omap_overlay_manager *mgr = sdi.output.manager;
118
119 sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
120
121 sdi.mgr_config.stallmode = false;
122 sdi.mgr_config.fifohandcheck = false;
123
124 sdi.mgr_config.video_port_width = 24;
125 sdi.mgr_config.lcden_sig_polarity = 1;
126
127 dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
128}
129
130static int sdi_display_enable(struct omap_dss_device *dssdev)
131{
132 struct omap_dss_device *out = &sdi.output;
133 struct omap_video_timings *t = &sdi.timings;
134 unsigned long fck;
135 struct dispc_clock_info dispc_cinfo;
136 unsigned long pck;
137 int r;
138
139 if (out->manager == NULL) {
140 DSSERR("failed to enable display: no output/manager\n");
141 return -ENODEV;
142 }
143
144 r = regulator_enable(sdi.vdds_sdi_reg);
145 if (r)
146 goto err_reg_enable;
147
148 r = dispc_runtime_get();
149 if (r)
150 goto err_get_dispc;
151
152 /* 15.5.9.1.2 */
153 t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
154 t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
155
156 r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo);
157 if (r)
158 goto err_calc_clock_div;
159
160 sdi.mgr_config.clock_info = dispc_cinfo;
161
162 pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
163
164 if (pck != t->pixelclock) {
165 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
166 t->pixelclock, pck);
167
168 t->pixelclock = pck;
169 }
170
171
172 dss_mgr_set_timings(out->manager, t);
173
174 r = dss_set_fck_rate(fck);
175 if (r)
176 goto err_set_dss_clock_div;
177
178 sdi_config_lcd_manager(dssdev);
179
180 /*
181 * LCLK and PCLK divisors are located in shadow registers, and we
182 * normally write them to DISPC registers when enabling the output.
183 * However, SDI uses pck-free as source clock for its PLL, and pck-free
184 * is affected by the divisors. And as we need the PLL before enabling
185 * the output, we need to write the divisors early.
186 *
187 * It seems just writing to the DISPC register is enough, and we don't
188 * need to care about the shadow register mechanism for pck-free. The
189 * exact reason for this is unknown.
190 */
191 dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
192
193 dss_sdi_init(sdi.datapairs);
194 r = dss_sdi_enable();
195 if (r)
196 goto err_sdi_enable;
197 mdelay(2);
198
199 r = dss_mgr_enable(out->manager);
200 if (r)
201 goto err_mgr_enable;
202
203 return 0;
204
205err_mgr_enable:
206 dss_sdi_disable();
207err_sdi_enable:
208err_set_dss_clock_div:
209err_calc_clock_div:
210 dispc_runtime_put();
211err_get_dispc:
212 regulator_disable(sdi.vdds_sdi_reg);
213err_reg_enable:
214 return r;
215}
216
217static void sdi_display_disable(struct omap_dss_device *dssdev)
218{
219 struct omap_overlay_manager *mgr = sdi.output.manager;
220
221 dss_mgr_disable(mgr);
222
223 dss_sdi_disable();
224
225 dispc_runtime_put();
226
227 regulator_disable(sdi.vdds_sdi_reg);
228}
229
230static void sdi_set_timings(struct omap_dss_device *dssdev,
231 struct omap_video_timings *timings)
232{
233 sdi.timings = *timings;
234}
235
236static void sdi_get_timings(struct omap_dss_device *dssdev,
237 struct omap_video_timings *timings)
238{
239 *timings = sdi.timings;
240}
241
242static int sdi_check_timings(struct omap_dss_device *dssdev,
243 struct omap_video_timings *timings)
244{
245 struct omap_overlay_manager *mgr = sdi.output.manager;
246
247 if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
248 return -EINVAL;
249
250 if (timings->pixelclock == 0)
251 return -EINVAL;
252
253 return 0;
254}
255
256static void sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
257{
258 sdi.datapairs = datapairs;
259}
260
261static int sdi_init_regulator(void)
262{
263 struct regulator *vdds_sdi;
264
265 if (sdi.vdds_sdi_reg)
266 return 0;
267
268 vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
269 if (IS_ERR(vdds_sdi)) {
270 if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
271 DSSERR("can't get VDDS_SDI regulator\n");
272 return PTR_ERR(vdds_sdi);
273 }
274
275 sdi.vdds_sdi_reg = vdds_sdi;
276
277 return 0;
278}
279
280static int sdi_connect(struct omap_dss_device *dssdev,
281 struct omap_dss_device *dst)
282{
283 struct omap_overlay_manager *mgr;
284 int r;
285
286 r = sdi_init_regulator();
287 if (r)
288 return r;
289
290 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
291 if (!mgr)
292 return -ENODEV;
293
294 r = dss_mgr_connect(mgr, dssdev);
295 if (r)
296 return r;
297
298 r = omapdss_output_set_device(dssdev, dst);
299 if (r) {
300 DSSERR("failed to connect output to new device: %s\n",
301 dst->name);
302 dss_mgr_disconnect(mgr, dssdev);
303 return r;
304 }
305
306 return 0;
307}
308
309static void sdi_disconnect(struct omap_dss_device *dssdev,
310 struct omap_dss_device *dst)
311{
312 WARN_ON(dst != dssdev->dst);
313
314 if (dst != dssdev->dst)
315 return;
316
317 omapdss_output_unset_device(dssdev);
318
319 if (dssdev->manager)
320 dss_mgr_disconnect(dssdev->manager, dssdev);
321}
322
323static const struct omapdss_sdi_ops sdi_ops = {
324 .connect = sdi_connect,
325 .disconnect = sdi_disconnect,
326
327 .enable = sdi_display_enable,
328 .disable = sdi_display_disable,
329
330 .check_timings = sdi_check_timings,
331 .set_timings = sdi_set_timings,
332 .get_timings = sdi_get_timings,
333
334 .set_datapairs = sdi_set_datapairs,
335};
336
337static void sdi_init_output(struct platform_device *pdev)
338{
339 struct omap_dss_device *out = &sdi.output;
340
341 out->dev = &pdev->dev;
342 out->id = OMAP_DSS_OUTPUT_SDI;
343 out->output_type = OMAP_DISPLAY_TYPE_SDI;
344 out->name = "sdi.0";
345 out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
346 /* We have SDI only on OMAP3, where it's on port 1 */
347 out->port_num = 1;
348 out->ops.sdi = &sdi_ops;
349 out->owner = THIS_MODULE;
350
351 omapdss_register_output(out);
352}
353
354static void sdi_uninit_output(struct platform_device *pdev)
355{
356 struct omap_dss_device *out = &sdi.output;
357
358 omapdss_unregister_output(out);
359}
360
361static int sdi_bind(struct device *dev, struct device *master, void *data)
362{
363 struct platform_device *pdev = to_platform_device(dev);
364
365 sdi.pdev = pdev;
366
367 sdi_init_output(pdev);
368
369 return 0;
370}
371
372static void sdi_unbind(struct device *dev, struct device *master, void *data)
373{
374 struct platform_device *pdev = to_platform_device(dev);
375
376 sdi_uninit_output(pdev);
377}
378
379static const struct component_ops sdi_component_ops = {
380 .bind = sdi_bind,
381 .unbind = sdi_unbind,
382};
383
384static int sdi_probe(struct platform_device *pdev)
385{
386 return component_add(&pdev->dev, &sdi_component_ops);
387}
388
389static int sdi_remove(struct platform_device *pdev)
390{
391 component_del(&pdev->dev, &sdi_component_ops);
392 return 0;
393}
394
395static struct platform_driver omap_sdi_driver = {
396 .probe = sdi_probe,
397 .remove = sdi_remove,
398 .driver = {
399 .name = "omapdss_sdi",
400 .suppress_bind_attrs = true,
401 },
402};
403
404int __init sdi_init_platform_driver(void)
405{
406 return platform_driver_register(&omap_sdi_driver);
407}
408
409void sdi_uninit_platform_driver(void)
410{
411 platform_driver_unregister(&omap_sdi_driver);
412}
413
414int sdi_init_port(struct platform_device *pdev, struct device_node *port)
415{
416 struct device_node *ep;
417 u32 datapairs;
418 int r;
419
420 ep = omapdss_of_get_next_endpoint(port, NULL);
421 if (!ep)
422 return 0;
423
424 r = of_property_read_u32(ep, "datapairs", &datapairs);
425 if (r) {
426 DSSERR("failed to parse datapairs\n");
427 goto err_datapairs;
428 }
429
430 sdi.datapairs = datapairs;
431
432 of_node_put(ep);
433
434 sdi.pdev = pdev;
435
436 sdi_init_output(pdev);
437
438 sdi.port_initialized = true;
439
440 return 0;
441
442err_datapairs:
443 of_node_put(ep);
444
445 return r;
446}
447
448void sdi_uninit_port(struct device_node *port)
449{
450 if (!sdi.port_initialized)
451 return;
452
453 sdi_uninit_output(sdi.pdev);
454}
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
new file mode 100644
index 000000000000..c9260a451ca6
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -0,0 +1,997 @@
1/*
2 * linux/drivers/video/omap2/dss/venc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * VENC settings from TI's DSS driver
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "VENC"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/clk.h>
27#include <linux/err.h>
28#include <linux/io.h>
29#include <linux/mutex.h>
30#include <linux/completion.h>
31#include <linux/delay.h>
32#include <linux/string.h>
33#include <linux/seq_file.h>
34#include <linux/platform_device.h>
35#include <linux/regulator/consumer.h>
36#include <linux/pm_runtime.h>
37#include <linux/of.h>
38#include <linux/component.h>
39
40#include <video/omapdss.h>
41
42#include "dss.h"
43#include "dss_features.h"
44
45/* Venc registers */
46#define VENC_REV_ID 0x00
47#define VENC_STATUS 0x04
48#define VENC_F_CONTROL 0x08
49#define VENC_VIDOUT_CTRL 0x10
50#define VENC_SYNC_CTRL 0x14
51#define VENC_LLEN 0x1C
52#define VENC_FLENS 0x20
53#define VENC_HFLTR_CTRL 0x24
54#define VENC_CC_CARR_WSS_CARR 0x28
55#define VENC_C_PHASE 0x2C
56#define VENC_GAIN_U 0x30
57#define VENC_GAIN_V 0x34
58#define VENC_GAIN_Y 0x38
59#define VENC_BLACK_LEVEL 0x3C
60#define VENC_BLANK_LEVEL 0x40
61#define VENC_X_COLOR 0x44
62#define VENC_M_CONTROL 0x48
63#define VENC_BSTAMP_WSS_DATA 0x4C
64#define VENC_S_CARR 0x50
65#define VENC_LINE21 0x54
66#define VENC_LN_SEL 0x58
67#define VENC_L21__WC_CTL 0x5C
68#define VENC_HTRIGGER_VTRIGGER 0x60
69#define VENC_SAVID__EAVID 0x64
70#define VENC_FLEN__FAL 0x68
71#define VENC_LAL__PHASE_RESET 0x6C
72#define VENC_HS_INT_START_STOP_X 0x70
73#define VENC_HS_EXT_START_STOP_X 0x74
74#define VENC_VS_INT_START_X 0x78
75#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
76#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
77#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
78#define VENC_VS_EXT_STOP_Y 0x88
79#define VENC_AVID_START_STOP_X 0x90
80#define VENC_AVID_START_STOP_Y 0x94
81#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
82#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
83#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
84#define VENC_TVDETGP_INT_START_STOP_X 0xB0
85#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
86#define VENC_GEN_CTRL 0xB8
87#define VENC_OUTPUT_CONTROL 0xC4
88#define VENC_OUTPUT_TEST 0xC8
89#define VENC_DAC_B__DAC_C 0xC8
90
91struct venc_config {
92 u32 f_control;
93 u32 vidout_ctrl;
94 u32 sync_ctrl;
95 u32 llen;
96 u32 flens;
97 u32 hfltr_ctrl;
98 u32 cc_carr_wss_carr;
99 u32 c_phase;
100 u32 gain_u;
101 u32 gain_v;
102 u32 gain_y;
103 u32 black_level;
104 u32 blank_level;
105 u32 x_color;
106 u32 m_control;
107 u32 bstamp_wss_data;
108 u32 s_carr;
109 u32 line21;
110 u32 ln_sel;
111 u32 l21__wc_ctl;
112 u32 htrigger_vtrigger;
113 u32 savid__eavid;
114 u32 flen__fal;
115 u32 lal__phase_reset;
116 u32 hs_int_start_stop_x;
117 u32 hs_ext_start_stop_x;
118 u32 vs_int_start_x;
119 u32 vs_int_stop_x__vs_int_start_y;
120 u32 vs_int_stop_y__vs_ext_start_x;
121 u32 vs_ext_stop_x__vs_ext_start_y;
122 u32 vs_ext_stop_y;
123 u32 avid_start_stop_x;
124 u32 avid_start_stop_y;
125 u32 fid_int_start_x__fid_int_start_y;
126 u32 fid_int_offset_y__fid_ext_start_x;
127 u32 fid_ext_start_y__fid_ext_offset_y;
128 u32 tvdetgp_int_start_stop_x;
129 u32 tvdetgp_int_start_stop_y;
130 u32 gen_ctrl;
131};
132
133/* from TRM */
134static const struct venc_config venc_config_pal_trm = {
135 .f_control = 0,
136 .vidout_ctrl = 1,
137 .sync_ctrl = 0x40,
138 .llen = 0x35F, /* 863 */
139 .flens = 0x270, /* 624 */
140 .hfltr_ctrl = 0,
141 .cc_carr_wss_carr = 0x2F7225ED,
142 .c_phase = 0,
143 .gain_u = 0x111,
144 .gain_v = 0x181,
145 .gain_y = 0x140,
146 .black_level = 0x3B,
147 .blank_level = 0x3B,
148 .x_color = 0x7,
149 .m_control = 0x2,
150 .bstamp_wss_data = 0x3F,
151 .s_carr = 0x2A098ACB,
152 .line21 = 0,
153 .ln_sel = 0x01290015,
154 .l21__wc_ctl = 0x0000F603,
155 .htrigger_vtrigger = 0,
156
157 .savid__eavid = 0x06A70108,
158 .flen__fal = 0x00180270,
159 .lal__phase_reset = 0x00040135,
160 .hs_int_start_stop_x = 0x00880358,
161 .hs_ext_start_stop_x = 0x000F035F,
162 .vs_int_start_x = 0x01A70000,
163 .vs_int_stop_x__vs_int_start_y = 0x000001A7,
164 .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
165 .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
166 .vs_ext_stop_y = 0x00000025,
167 .avid_start_stop_x = 0x03530083,
168 .avid_start_stop_y = 0x026C002E,
169 .fid_int_start_x__fid_int_start_y = 0x0001008A,
170 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
171 .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
172
173 .tvdetgp_int_start_stop_x = 0x00140001,
174 .tvdetgp_int_start_stop_y = 0x00010001,
175 .gen_ctrl = 0x00FF0000,
176};
177
178/* from TRM */
179static const struct venc_config venc_config_ntsc_trm = {
180 .f_control = 0,
181 .vidout_ctrl = 1,
182 .sync_ctrl = 0x8040,
183 .llen = 0x359,
184 .flens = 0x20C,
185 .hfltr_ctrl = 0,
186 .cc_carr_wss_carr = 0x043F2631,
187 .c_phase = 0,
188 .gain_u = 0x102,
189 .gain_v = 0x16C,
190 .gain_y = 0x12F,
191 .black_level = 0x43,
192 .blank_level = 0x38,
193 .x_color = 0x7,
194 .m_control = 0x1,
195 .bstamp_wss_data = 0x38,
196 .s_carr = 0x21F07C1F,
197 .line21 = 0,
198 .ln_sel = 0x01310011,
199 .l21__wc_ctl = 0x0000F003,
200 .htrigger_vtrigger = 0,
201
202 .savid__eavid = 0x069300F4,
203 .flen__fal = 0x0016020C,
204 .lal__phase_reset = 0x00060107,
205 .hs_int_start_stop_x = 0x008E0350,
206 .hs_ext_start_stop_x = 0x000F0359,
207 .vs_int_start_x = 0x01A00000,
208 .vs_int_stop_x__vs_int_start_y = 0x020701A0,
209 .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
210 .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
211 .vs_ext_stop_y = 0x00000006,
212 .avid_start_stop_x = 0x03480078,
213 .avid_start_stop_y = 0x02060024,
214 .fid_int_start_x__fid_int_start_y = 0x0001008A,
215 .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
216 .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
217
218 .tvdetgp_int_start_stop_x = 0x00140001,
219 .tvdetgp_int_start_stop_y = 0x00010001,
220 .gen_ctrl = 0x00F90000,
221};
222
223static const struct venc_config venc_config_pal_bdghi = {
224 .f_control = 0,
225 .vidout_ctrl = 0,
226 .sync_ctrl = 0,
227 .hfltr_ctrl = 0,
228 .x_color = 0,
229 .line21 = 0,
230 .ln_sel = 21,
231 .htrigger_vtrigger = 0,
232 .tvdetgp_int_start_stop_x = 0x00140001,
233 .tvdetgp_int_start_stop_y = 0x00010001,
234 .gen_ctrl = 0x00FB0000,
235
236 .llen = 864-1,
237 .flens = 625-1,
238 .cc_carr_wss_carr = 0x2F7625ED,
239 .c_phase = 0xDF,
240 .gain_u = 0x111,
241 .gain_v = 0x181,
242 .gain_y = 0x140,
243 .black_level = 0x3e,
244 .blank_level = 0x3e,
245 .m_control = 0<<2 | 1<<1,
246 .bstamp_wss_data = 0x42,
247 .s_carr = 0x2a098acb,
248 .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
249 .savid__eavid = 0x06A70108,
250 .flen__fal = 23<<16 | 624<<0,
251 .lal__phase_reset = 2<<17 | 310<<0,
252 .hs_int_start_stop_x = 0x00920358,
253 .hs_ext_start_stop_x = 0x000F035F,
254 .vs_int_start_x = 0x1a7<<16,
255 .vs_int_stop_x__vs_int_start_y = 0x000601A7,
256 .vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
257 .vs_ext_stop_x__vs_ext_start_y = 0x27101af,
258 .vs_ext_stop_y = 0x05,
259 .avid_start_stop_x = 0x03530082,
260 .avid_start_stop_y = 0x0270002E,
261 .fid_int_start_x__fid_int_start_y = 0x0005008A,
262 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
263 .fid_ext_start_y__fid_ext_offset_y = 0x01380005,
264};
265
266const struct omap_video_timings omap_dss_pal_timings = {
267 .x_res = 720,
268 .y_res = 574,
269 .pixelclock = 13500000,
270 .hsw = 64,
271 .hfp = 12,
272 .hbp = 68,
273 .vsw = 5,
274 .vfp = 5,
275 .vbp = 41,
276
277 .interlace = true,
278};
279EXPORT_SYMBOL(omap_dss_pal_timings);
280
281const struct omap_video_timings omap_dss_ntsc_timings = {
282 .x_res = 720,
283 .y_res = 482,
284 .pixelclock = 13500000,
285 .hsw = 64,
286 .hfp = 16,
287 .hbp = 58,
288 .vsw = 6,
289 .vfp = 6,
290 .vbp = 31,
291
292 .interlace = true,
293};
294EXPORT_SYMBOL(omap_dss_ntsc_timings);
295
296static struct {
297 struct platform_device *pdev;
298 void __iomem *base;
299 struct mutex venc_lock;
300 u32 wss_data;
301 struct regulator *vdda_dac_reg;
302
303 struct clk *tv_dac_clk;
304
305 struct omap_video_timings timings;
306 enum omap_dss_venc_type type;
307 bool invert_polarity;
308
309 struct omap_dss_device output;
310} venc;
311
312static inline void venc_write_reg(int idx, u32 val)
313{
314 __raw_writel(val, venc.base + idx);
315}
316
317static inline u32 venc_read_reg(int idx)
318{
319 u32 l = __raw_readl(venc.base + idx);
320 return l;
321}
322
323static void venc_write_config(const struct venc_config *config)
324{
325 DSSDBG("write venc conf\n");
326
327 venc_write_reg(VENC_LLEN, config->llen);
328 venc_write_reg(VENC_FLENS, config->flens);
329 venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
330 venc_write_reg(VENC_C_PHASE, config->c_phase);
331 venc_write_reg(VENC_GAIN_U, config->gain_u);
332 venc_write_reg(VENC_GAIN_V, config->gain_v);
333 venc_write_reg(VENC_GAIN_Y, config->gain_y);
334 venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
335 venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
336 venc_write_reg(VENC_M_CONTROL, config->m_control);
337 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
338 venc.wss_data);
339 venc_write_reg(VENC_S_CARR, config->s_carr);
340 venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
341 venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
342 venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
343 venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
344 venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
345 venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
346 venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
347 venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
348 config->vs_int_stop_x__vs_int_start_y);
349 venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
350 config->vs_int_stop_y__vs_ext_start_x);
351 venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
352 config->vs_ext_stop_x__vs_ext_start_y);
353 venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
354 venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
355 venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
356 venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
357 config->fid_int_start_x__fid_int_start_y);
358 venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
359 config->fid_int_offset_y__fid_ext_start_x);
360 venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
361 config->fid_ext_start_y__fid_ext_offset_y);
362
363 venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
364 venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
365 venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
366 venc_write_reg(VENC_X_COLOR, config->x_color);
367 venc_write_reg(VENC_LINE21, config->line21);
368 venc_write_reg(VENC_LN_SEL, config->ln_sel);
369 venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
370 venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
371 config->tvdetgp_int_start_stop_x);
372 venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
373 config->tvdetgp_int_start_stop_y);
374 venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
375 venc_write_reg(VENC_F_CONTROL, config->f_control);
376 venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
377}
378
379static void venc_reset(void)
380{
381 int t = 1000;
382
383 venc_write_reg(VENC_F_CONTROL, 1<<8);
384 while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
385 if (--t == 0) {
386 DSSERR("Failed to reset venc\n");
387 return;
388 }
389 }
390
391#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
392 /* the magical sleep that makes things work */
393 /* XXX more info? What bug this circumvents? */
394 msleep(20);
395#endif
396}
397
398static int venc_runtime_get(void)
399{
400 int r;
401
402 DSSDBG("venc_runtime_get\n");
403
404 r = pm_runtime_get_sync(&venc.pdev->dev);
405 WARN_ON(r < 0);
406 return r < 0 ? r : 0;
407}
408
409static void venc_runtime_put(void)
410{
411 int r;
412
413 DSSDBG("venc_runtime_put\n");
414
415 r = pm_runtime_put_sync(&venc.pdev->dev);
416 WARN_ON(r < 0 && r != -ENOSYS);
417}
418
419static const struct venc_config *venc_timings_to_config(
420 struct omap_video_timings *timings)
421{
422 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
423 return &venc_config_pal_trm;
424
425 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
426 return &venc_config_ntsc_trm;
427
428 BUG();
429 return NULL;
430}
431
432static int venc_power_on(struct omap_dss_device *dssdev)
433{
434 struct omap_overlay_manager *mgr = venc.output.manager;
435 u32 l;
436 int r;
437
438 r = venc_runtime_get();
439 if (r)
440 goto err0;
441
442 venc_reset();
443 venc_write_config(venc_timings_to_config(&venc.timings));
444
445 dss_set_venc_output(venc.type);
446 dss_set_dac_pwrdn_bgz(1);
447
448 l = 0;
449
450 if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
451 l |= 1 << 1;
452 else /* S-Video */
453 l |= (1 << 0) | (1 << 2);
454
455 if (venc.invert_polarity == false)
456 l |= 1 << 3;
457
458 venc_write_reg(VENC_OUTPUT_CONTROL, l);
459
460 dss_mgr_set_timings(mgr, &venc.timings);
461
462 r = regulator_enable(venc.vdda_dac_reg);
463 if (r)
464 goto err1;
465
466 r = dss_mgr_enable(mgr);
467 if (r)
468 goto err2;
469
470 return 0;
471
472err2:
473 regulator_disable(venc.vdda_dac_reg);
474err1:
475 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
476 dss_set_dac_pwrdn_bgz(0);
477
478 venc_runtime_put();
479err0:
480 return r;
481}
482
483static void venc_power_off(struct omap_dss_device *dssdev)
484{
485 struct omap_overlay_manager *mgr = venc.output.manager;
486
487 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
488 dss_set_dac_pwrdn_bgz(0);
489
490 dss_mgr_disable(mgr);
491
492 regulator_disable(venc.vdda_dac_reg);
493
494 venc_runtime_put();
495}
496
497static int venc_display_enable(struct omap_dss_device *dssdev)
498{
499 struct omap_dss_device *out = &venc.output;
500 int r;
501
502 DSSDBG("venc_display_enable\n");
503
504 mutex_lock(&venc.venc_lock);
505
506 if (out->manager == NULL) {
507 DSSERR("Failed to enable display: no output/manager\n");
508 r = -ENODEV;
509 goto err0;
510 }
511
512 r = venc_power_on(dssdev);
513 if (r)
514 goto err0;
515
516 venc.wss_data = 0;
517
518 mutex_unlock(&venc.venc_lock);
519
520 return 0;
521err0:
522 mutex_unlock(&venc.venc_lock);
523 return r;
524}
525
526static void venc_display_disable(struct omap_dss_device *dssdev)
527{
528 DSSDBG("venc_display_disable\n");
529
530 mutex_lock(&venc.venc_lock);
531
532 venc_power_off(dssdev);
533
534 mutex_unlock(&venc.venc_lock);
535}
536
537static void venc_set_timings(struct omap_dss_device *dssdev,
538 struct omap_video_timings *timings)
539{
540 DSSDBG("venc_set_timings\n");
541
542 mutex_lock(&venc.venc_lock);
543
544 /* Reset WSS data when the TV standard changes. */
545 if (memcmp(&venc.timings, timings, sizeof(*timings)))
546 venc.wss_data = 0;
547
548 venc.timings = *timings;
549
550 dispc_set_tv_pclk(13500000);
551
552 mutex_unlock(&venc.venc_lock);
553}
554
555static int venc_check_timings(struct omap_dss_device *dssdev,
556 struct omap_video_timings *timings)
557{
558 DSSDBG("venc_check_timings\n");
559
560 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
561 return 0;
562
563 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
564 return 0;
565
566 return -EINVAL;
567}
568
569static void venc_get_timings(struct omap_dss_device *dssdev,
570 struct omap_video_timings *timings)
571{
572 mutex_lock(&venc.venc_lock);
573
574 *timings = venc.timings;
575
576 mutex_unlock(&venc.venc_lock);
577}
578
579static u32 venc_get_wss(struct omap_dss_device *dssdev)
580{
581 /* Invert due to VENC_L21_WC_CTL:INV=1 */
582 return (venc.wss_data >> 8) ^ 0xfffff;
583}
584
585static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
586{
587 const struct venc_config *config;
588 int r;
589
590 DSSDBG("venc_set_wss\n");
591
592 mutex_lock(&venc.venc_lock);
593
594 config = venc_timings_to_config(&venc.timings);
595
596 /* Invert due to VENC_L21_WC_CTL:INV=1 */
597 venc.wss_data = (wss ^ 0xfffff) << 8;
598
599 r = venc_runtime_get();
600 if (r)
601 goto err;
602
603 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
604 venc.wss_data);
605
606 venc_runtime_put();
607
608err:
609 mutex_unlock(&venc.venc_lock);
610
611 return r;
612}
613
614static void venc_set_type(struct omap_dss_device *dssdev,
615 enum omap_dss_venc_type type)
616{
617 mutex_lock(&venc.venc_lock);
618
619 venc.type = type;
620
621 mutex_unlock(&venc.venc_lock);
622}
623
624static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
625 bool invert_polarity)
626{
627 mutex_lock(&venc.venc_lock);
628
629 venc.invert_polarity = invert_polarity;
630
631 mutex_unlock(&venc.venc_lock);
632}
633
634static int venc_init_regulator(void)
635{
636 struct regulator *vdda_dac;
637
638 if (venc.vdda_dac_reg != NULL)
639 return 0;
640
641 if (venc.pdev->dev.of_node)
642 vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
643 else
644 vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
645
646 if (IS_ERR(vdda_dac)) {
647 if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
648 DSSERR("can't get VDDA_DAC regulator\n");
649 return PTR_ERR(vdda_dac);
650 }
651
652 venc.vdda_dac_reg = vdda_dac;
653
654 return 0;
655}
656
657static void venc_dump_regs(struct seq_file *s)
658{
659#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
660
661 if (venc_runtime_get())
662 return;
663
664 DUMPREG(VENC_F_CONTROL);
665 DUMPREG(VENC_VIDOUT_CTRL);
666 DUMPREG(VENC_SYNC_CTRL);
667 DUMPREG(VENC_LLEN);
668 DUMPREG(VENC_FLENS);
669 DUMPREG(VENC_HFLTR_CTRL);
670 DUMPREG(VENC_CC_CARR_WSS_CARR);
671 DUMPREG(VENC_C_PHASE);
672 DUMPREG(VENC_GAIN_U);
673 DUMPREG(VENC_GAIN_V);
674 DUMPREG(VENC_GAIN_Y);
675 DUMPREG(VENC_BLACK_LEVEL);
676 DUMPREG(VENC_BLANK_LEVEL);
677 DUMPREG(VENC_X_COLOR);
678 DUMPREG(VENC_M_CONTROL);
679 DUMPREG(VENC_BSTAMP_WSS_DATA);
680 DUMPREG(VENC_S_CARR);
681 DUMPREG(VENC_LINE21);
682 DUMPREG(VENC_LN_SEL);
683 DUMPREG(VENC_L21__WC_CTL);
684 DUMPREG(VENC_HTRIGGER_VTRIGGER);
685 DUMPREG(VENC_SAVID__EAVID);
686 DUMPREG(VENC_FLEN__FAL);
687 DUMPREG(VENC_LAL__PHASE_RESET);
688 DUMPREG(VENC_HS_INT_START_STOP_X);
689 DUMPREG(VENC_HS_EXT_START_STOP_X);
690 DUMPREG(VENC_VS_INT_START_X);
691 DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
692 DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
693 DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
694 DUMPREG(VENC_VS_EXT_STOP_Y);
695 DUMPREG(VENC_AVID_START_STOP_X);
696 DUMPREG(VENC_AVID_START_STOP_Y);
697 DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
698 DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
699 DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
700 DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
701 DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
702 DUMPREG(VENC_GEN_CTRL);
703 DUMPREG(VENC_OUTPUT_CONTROL);
704 DUMPREG(VENC_OUTPUT_TEST);
705
706 venc_runtime_put();
707
708#undef DUMPREG
709}
710
711static int venc_get_clocks(struct platform_device *pdev)
712{
713 struct clk *clk;
714
715 if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
716 clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
717 if (IS_ERR(clk)) {
718 DSSERR("can't get tv_dac_clk\n");
719 return PTR_ERR(clk);
720 }
721 } else {
722 clk = NULL;
723 }
724
725 venc.tv_dac_clk = clk;
726
727 return 0;
728}
729
730static int venc_connect(struct omap_dss_device *dssdev,
731 struct omap_dss_device *dst)
732{
733 struct omap_overlay_manager *mgr;
734 int r;
735
736 r = venc_init_regulator();
737 if (r)
738 return r;
739
740 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
741 if (!mgr)
742 return -ENODEV;
743
744 r = dss_mgr_connect(mgr, dssdev);
745 if (r)
746 return r;
747
748 r = omapdss_output_set_device(dssdev, dst);
749 if (r) {
750 DSSERR("failed to connect output to new device: %s\n",
751 dst->name);
752 dss_mgr_disconnect(mgr, dssdev);
753 return r;
754 }
755
756 return 0;
757}
758
759static void venc_disconnect(struct omap_dss_device *dssdev,
760 struct omap_dss_device *dst)
761{
762 WARN_ON(dst != dssdev->dst);
763
764 if (dst != dssdev->dst)
765 return;
766
767 omapdss_output_unset_device(dssdev);
768
769 if (dssdev->manager)
770 dss_mgr_disconnect(dssdev->manager, dssdev);
771}
772
773static const struct omapdss_atv_ops venc_ops = {
774 .connect = venc_connect,
775 .disconnect = venc_disconnect,
776
777 .enable = venc_display_enable,
778 .disable = venc_display_disable,
779
780 .check_timings = venc_check_timings,
781 .set_timings = venc_set_timings,
782 .get_timings = venc_get_timings,
783
784 .set_type = venc_set_type,
785 .invert_vid_out_polarity = venc_invert_vid_out_polarity,
786
787 .set_wss = venc_set_wss,
788 .get_wss = venc_get_wss,
789};
790
791static void venc_init_output(struct platform_device *pdev)
792{
793 struct omap_dss_device *out = &venc.output;
794
795 out->dev = &pdev->dev;
796 out->id = OMAP_DSS_OUTPUT_VENC;
797 out->output_type = OMAP_DISPLAY_TYPE_VENC;
798 out->name = "venc.0";
799 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
800 out->ops.atv = &venc_ops;
801 out->owner = THIS_MODULE;
802
803 omapdss_register_output(out);
804}
805
806static void venc_uninit_output(struct platform_device *pdev)
807{
808 struct omap_dss_device *out = &venc.output;
809
810 omapdss_unregister_output(out);
811}
812
813static int venc_probe_of(struct platform_device *pdev)
814{
815 struct device_node *node = pdev->dev.of_node;
816 struct device_node *ep;
817 u32 channels;
818 int r;
819
820 ep = omapdss_of_get_first_endpoint(node);
821 if (!ep)
822 return 0;
823
824 venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
825
826 r = of_property_read_u32(ep, "ti,channels", &channels);
827 if (r) {
828 dev_err(&pdev->dev,
829 "failed to read property 'ti,channels': %d\n", r);
830 goto err;
831 }
832
833 switch (channels) {
834 case 1:
835 venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
836 break;
837 case 2:
838 venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
839 break;
840 default:
841 dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
842 r = -EINVAL;
843 goto err;
844 }
845
846 of_node_put(ep);
847
848 return 0;
849err:
850 of_node_put(ep);
851
852 return 0;
853}
854
855/* VENC HW IP initialisation */
856static int venc_bind(struct device *dev, struct device *master, void *data)
857{
858 struct platform_device *pdev = to_platform_device(dev);
859 u8 rev_id;
860 struct resource *venc_mem;
861 int r;
862
863 venc.pdev = pdev;
864
865 mutex_init(&venc.venc_lock);
866
867 venc.wss_data = 0;
868
869 venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
870 if (!venc_mem) {
871 DSSERR("can't get IORESOURCE_MEM VENC\n");
872 return -EINVAL;
873 }
874
875 venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
876 resource_size(venc_mem));
877 if (!venc.base) {
878 DSSERR("can't ioremap VENC\n");
879 return -ENOMEM;
880 }
881
882 r = venc_get_clocks(pdev);
883 if (r)
884 return r;
885
886 pm_runtime_enable(&pdev->dev);
887
888 r = venc_runtime_get();
889 if (r)
890 goto err_runtime_get;
891
892 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
893 dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
894
895 venc_runtime_put();
896
897 if (pdev->dev.of_node) {
898 r = venc_probe_of(pdev);
899 if (r) {
900 DSSERR("Invalid DT data\n");
901 goto err_probe_of;
902 }
903 }
904
905 dss_debugfs_create_file("venc", venc_dump_regs);
906
907 venc_init_output(pdev);
908
909 return 0;
910
911err_probe_of:
912err_runtime_get:
913 pm_runtime_disable(&pdev->dev);
914 return r;
915}
916
917static void venc_unbind(struct device *dev, struct device *master, void *data)
918{
919 struct platform_device *pdev = to_platform_device(dev);
920
921 venc_uninit_output(pdev);
922
923 pm_runtime_disable(&pdev->dev);
924}
925
926static const struct component_ops venc_component_ops = {
927 .bind = venc_bind,
928 .unbind = venc_unbind,
929};
930
931static int venc_probe(struct platform_device *pdev)
932{
933 return component_add(&pdev->dev, &venc_component_ops);
934}
935
936static int venc_remove(struct platform_device *pdev)
937{
938 component_del(&pdev->dev, &venc_component_ops);
939 return 0;
940}
941
942static int venc_runtime_suspend(struct device *dev)
943{
944 if (venc.tv_dac_clk)
945 clk_disable_unprepare(venc.tv_dac_clk);
946
947 dispc_runtime_put();
948
949 return 0;
950}
951
952static int venc_runtime_resume(struct device *dev)
953{
954 int r;
955
956 r = dispc_runtime_get();
957 if (r < 0)
958 return r;
959
960 if (venc.tv_dac_clk)
961 clk_prepare_enable(venc.tv_dac_clk);
962
963 return 0;
964}
965
966static const struct dev_pm_ops venc_pm_ops = {
967 .runtime_suspend = venc_runtime_suspend,
968 .runtime_resume = venc_runtime_resume,
969};
970
971static const struct of_device_id venc_of_match[] = {
972 { .compatible = "ti,omap2-venc", },
973 { .compatible = "ti,omap3-venc", },
974 { .compatible = "ti,omap4-venc", },
975 {},
976};
977
978static struct platform_driver omap_venchw_driver = {
979 .probe = venc_probe,
980 .remove = venc_remove,
981 .driver = {
982 .name = "omapdss_venc",
983 .pm = &venc_pm_ops,
984 .of_match_table = venc_of_match,
985 .suppress_bind_attrs = true,
986 },
987};
988
989int __init venc_init_platform_driver(void)
990{
991 return platform_driver_register(&omap_venchw_driver);
992}
993
994void venc_uninit_platform_driver(void)
995{
996 platform_driver_unregister(&omap_venchw_driver);
997}
diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c
new file mode 100644
index 000000000000..b1ec59e42940
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c
@@ -0,0 +1,211 @@
1/*
2* Copyright (C) 2014 Texas Instruments Ltd
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms of the GNU General Public License version 2 as published by
6* the Free Software Foundation.
7*
8* You should have received a copy of the GNU General Public License along with
9* this program. If not, see <http://www.gnu.org/licenses/>.
10*/
11
12#include <linux/clk.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
19
20#include <video/omapdss.h>
21
22#include "dss.h"
23#include "dss_features.h"
24
25struct dss_video_pll {
26 struct dss_pll pll;
27
28 struct device *dev;
29
30 void __iomem *clkctrl_base;
31};
32
33#define REG_MOD(reg, val, start, end) \
34 writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
35
36static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
37{
38 REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
39}
40
41static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
42{
43 REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
44}
45
46static void dss_dpll_power_enable(struct dss_video_pll *vpll)
47{
48 REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
49
50 /*
51 * DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
52 * so we have to use fixed delay here.
53 */
54 msleep(1);
55}
56
57static void dss_dpll_power_disable(struct dss_video_pll *vpll)
58{
59 REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
60}
61
62static int dss_video_pll_enable(struct dss_pll *pll)
63{
64 struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
65 int r;
66
67 r = dss_runtime_get();
68 if (r)
69 return r;
70
71 dss_ctrl_pll_enable(pll->id, true);
72
73 dss_dpll_enable_scp_clk(vpll);
74
75 r = dss_pll_wait_reset_done(pll);
76 if (r)
77 goto err_reset;
78
79 dss_dpll_power_enable(vpll);
80
81 return 0;
82
83err_reset:
84 dss_dpll_disable_scp_clk(vpll);
85 dss_ctrl_pll_enable(pll->id, false);
86 dss_runtime_put();
87
88 return r;
89}
90
91static void dss_video_pll_disable(struct dss_pll *pll)
92{
93 struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
94
95 dss_dpll_power_disable(vpll);
96
97 dss_dpll_disable_scp_clk(vpll);
98
99 dss_ctrl_pll_enable(pll->id, false);
100
101 dss_runtime_put();
102}
103
104static const struct dss_pll_ops dss_pll_ops = {
105 .enable = dss_video_pll_enable,
106 .disable = dss_video_pll_disable,
107 .set_config = dss_pll_write_config_type_a,
108};
109
110static const struct dss_pll_hw dss_dra7_video_pll_hw = {
111 .n_max = (1 << 8) - 1,
112 .m_max = (1 << 12) - 1,
113 .mX_max = (1 << 5) - 1,
114 .fint_min = 500000,
115 .fint_max = 2500000,
116 .clkdco_max = 1800000000,
117
118 .n_msb = 8,
119 .n_lsb = 1,
120 .m_msb = 20,
121 .m_lsb = 9,
122
123 .mX_msb[0] = 25,
124 .mX_lsb[0] = 21,
125 .mX_msb[1] = 30,
126 .mX_lsb[1] = 26,
127
128 .has_refsel = true,
129};
130
131struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
132 struct regulator *regulator)
133{
134 const char * const reg_name[] = { "pll1", "pll2" };
135 const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
136 const char * const clkin_name[] = { "video1_clk", "video2_clk" };
137
138 struct resource *res;
139 struct dss_video_pll *vpll;
140 void __iomem *pll_base, *clkctrl_base;
141 struct clk *clk;
142 struct dss_pll *pll;
143 int r;
144
145 /* PLL CONTROL */
146
147 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
148 if (!res) {
149 dev_err(&pdev->dev,
150 "missing platform resource data for pll%d\n", id);
151 return ERR_PTR(-ENODEV);
152 }
153
154 pll_base = devm_ioremap_resource(&pdev->dev, res);
155 if (IS_ERR(pll_base)) {
156 dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
157 return ERR_CAST(pll_base);
158 }
159
160 /* CLOCK CONTROL */
161
162 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
163 clkctrl_name[id]);
164 if (!res) {
165 dev_err(&pdev->dev,
166 "missing platform resource data for pll%d\n", id);
167 return ERR_PTR(-ENODEV);
168 }
169
170 clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
171 if (IS_ERR(clkctrl_base)) {
172 dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
173 return ERR_CAST(clkctrl_base);
174 }
175
176 /* CLKIN */
177
178 clk = devm_clk_get(&pdev->dev, clkin_name[id]);
179 if (IS_ERR(clk)) {
180 DSSERR("can't get video pll clkin\n");
181 return ERR_CAST(clk);
182 }
183
184 vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
185 if (!vpll)
186 return ERR_PTR(-ENOMEM);
187
188 vpll->dev = &pdev->dev;
189 vpll->clkctrl_base = clkctrl_base;
190
191 pll = &vpll->pll;
192
193 pll->name = id == 0 ? "video0" : "video1";
194 pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
195 pll->clkin = clk;
196 pll->regulator = regulator;
197 pll->base = pll_base;
198 pll->hw = &dss_dra7_video_pll_hw;
199 pll->ops = &dss_pll_ops;
200
201 r = dss_pll_register(pll);
202 if (r)
203 return ERR_PTR(r);
204
205 return pll;
206}
207
208void dss_video_pll_uninit(struct dss_pll *pll)
209{
210 dss_pll_unregister(pll);
211}