diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 12:07:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 12:07:08 -0400 |
commit | 15b588303155b22edd559672905db8e59a44ef9a (patch) | |
tree | 5413973ea42014d71ac6d8ce36dbf05058a45646 /drivers/video | |
parent | d55696af8d91e8f21dacd74a236e6dcc4f6d78c4 (diff) | |
parent | f2dd36ac9974cc2353bcbb8e6b643fb96030564c (diff) |
Merge tag 'fbdev-omap-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into next
Pull omap fbdev changes from Tomi Valkeinen:
- DT support for the panel drivers that were still missing it
- TI AM43xx support
- TI OMAP5 support
* tag 'fbdev-omap-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (46 commits)
OMAPDSS: move 'compatible' converter to omapdss driver
OMAPDSS: HDMI: fix devm_ioremap_resource error checks
OMAPDSS: HDMI: remove unused defines
OMAPDSS: HDMI: cleanup WP ioremaps
OMAPDSS: panel NEC-NL8048HL11 DT support
Doc/DT: Add DT binding documentation for TPO td043mtea1 panel
OMAPDSS: Panel TPO-TD043MTEA1 DT support
Doc/DT: Add DT binding documentation for SHARP LS037V7DW01
OMAPDSS: panel sharp-ls037v7dw01 DT support
OMAPDSS: panel-sharp-ls037v7dw01: update to use gpiod
Doc/DT: Add binding doc for lgphilips,lb035q02.txt
OMAPDSS: panel-lgphilips-lb035q02: Add DT support
OMAPDSS: panel-lgphilips-lb035q02: use gpiod for enable gpio
OMAPDSS: hdmi5_core: Fix compilation with OMAP5_DSS_HDMI_AUDIO
OMAPDSS: panel-dpi: enable-gpio
OMAPDSS: Fix writes to DISPC_POL_FREQ
Doc/DT: Add OMAP5 DSS DT bindings
OMAPDSS: HDMI: cleanup ioremaps
OMAPDSS: HDMI: Add OMAP5 HDMI support
OMAPDSS: HDMI: PLL changes for OMAP5
...
Diffstat (limited to 'drivers/video')
29 files changed, 3310 insertions, 513 deletions
diff --git a/drivers/video/fbdev/omap2/Makefile b/drivers/video/fbdev/omap2/Makefile index bf8127df8c71..f8745ec369cc 100644 --- a/drivers/video/fbdev/omap2/Makefile +++ b/drivers/video/fbdev/omap2/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | 1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o |
2 | 2 | ||
3 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 3 | obj-y += dss/ |
4 | obj-y += displays-new/ | 4 | obj-y += displays-new/ |
5 | obj-$(CONFIG_FB_OMAP2) += omapfb/ | 5 | obj-$(CONFIG_FB_OMAP2) += omapfb/ |
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c index 29ed21b9dce5..4420ccb69aa9 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <linux/of_gpio.h> | ||
16 | 17 | ||
17 | #include <drm/drm_edid.h> | 18 | #include <drm/drm_edid.h> |
18 | 19 | ||
@@ -43,6 +44,8 @@ struct panel_drv_data { | |||
43 | struct device *dev; | 44 | struct device *dev; |
44 | 45 | ||
45 | struct omap_video_timings timings; | 46 | struct omap_video_timings timings; |
47 | |||
48 | int hpd_gpio; | ||
46 | }; | 49 | }; |
47 | 50 | ||
48 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | 51 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) |
@@ -161,7 +164,10 @@ static bool hdmic_detect(struct omap_dss_device *dssdev) | |||
161 | struct panel_drv_data *ddata = to_panel_data(dssdev); | 164 | struct panel_drv_data *ddata = to_panel_data(dssdev); |
162 | struct omap_dss_device *in = ddata->in; | 165 | struct omap_dss_device *in = ddata->in; |
163 | 166 | ||
164 | return in->ops.hdmi->detect(in); | 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); | ||
165 | } | 171 | } |
166 | 172 | ||
167 | static int hdmic_audio_enable(struct omap_dss_device *dssdev) | 173 | static int hdmic_audio_enable(struct omap_dss_device *dssdev) |
@@ -288,6 +294,8 @@ static int hdmic_probe_pdata(struct platform_device *pdev) | |||
288 | 294 | ||
289 | pdata = dev_get_platdata(&pdev->dev); | 295 | pdata = dev_get_platdata(&pdev->dev); |
290 | 296 | ||
297 | ddata->hpd_gpio = -ENODEV; | ||
298 | |||
291 | in = omap_dss_find_output(pdata->source); | 299 | in = omap_dss_find_output(pdata->source); |
292 | if (in == NULL) { | 300 | if (in == NULL) { |
293 | dev_err(&pdev->dev, "Failed to find video source\n"); | 301 | dev_err(&pdev->dev, "Failed to find video source\n"); |
@@ -307,6 +315,14 @@ static int hdmic_probe_of(struct platform_device *pdev) | |||
307 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | 315 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); |
308 | struct device_node *node = pdev->dev.of_node; | 316 | struct device_node *node = pdev->dev.of_node; |
309 | struct omap_dss_device *in; | 317 | struct omap_dss_device *in; |
318 | int gpio; | ||
319 | |||
320 | /* HPD GPIO */ | ||
321 | gpio = of_get_named_gpio(node, "hpd-gpios", 0); | ||
322 | if (gpio_is_valid(gpio)) | ||
323 | ddata->hpd_gpio = gpio; | ||
324 | else | ||
325 | ddata->hpd_gpio = -ENODEV; | ||
310 | 326 | ||
311 | in = omapdss_of_find_source_for_first_ep(node); | 327 | in = omapdss_of_find_source_for_first_ep(node); |
312 | if (IS_ERR(in)) { | 328 | if (IS_ERR(in)) { |
@@ -344,6 +360,13 @@ static int hdmic_probe(struct platform_device *pdev) | |||
344 | return -ENODEV; | 360 | return -ENODEV; |
345 | } | 361 | } |
346 | 362 | ||
363 | if (gpio_is_valid(ddata->hpd_gpio)) { | ||
364 | r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, | ||
365 | GPIOF_DIR_IN, "hdmi_hpd"); | ||
366 | if (r) | ||
367 | goto err_reg; | ||
368 | } | ||
369 | |||
347 | ddata->timings = hdmic_default_timings; | 370 | ddata->timings = hdmic_default_timings; |
348 | 371 | ||
349 | dssdev = &ddata->dssdev; | 372 | dssdev = &ddata->dssdev; |
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c index 5f8f7e7c81ef..3636b61dc9b4 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c | |||
@@ -13,9 +13,12 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/of.h> | ||
17 | #include <linux/of_gpio.h> | ||
16 | 18 | ||
17 | #include <video/omapdss.h> | 19 | #include <video/omapdss.h> |
18 | #include <video/omap-panel-data.h> | 20 | #include <video/omap-panel-data.h> |
21 | #include <video/of_display_timing.h> | ||
19 | 22 | ||
20 | struct panel_drv_data { | 23 | struct panel_drv_data { |
21 | struct omap_dss_device dssdev; | 24 | struct omap_dss_device dssdev; |
@@ -25,8 +28,10 @@ struct panel_drv_data { | |||
25 | 28 | ||
26 | struct omap_video_timings videomode; | 29 | struct omap_video_timings videomode; |
27 | 30 | ||
31 | /* used for non-DT boot, to be removed */ | ||
28 | int backlight_gpio; | 32 | int backlight_gpio; |
29 | int enable_gpio; | 33 | |
34 | struct gpio_desc *enable_gpio; | ||
30 | }; | 35 | }; |
31 | 36 | ||
32 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | 37 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) |
@@ -70,15 +75,16 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev) | |||
70 | if (omapdss_device_is_enabled(dssdev)) | 75 | if (omapdss_device_is_enabled(dssdev)) |
71 | return 0; | 76 | return 0; |
72 | 77 | ||
73 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 78 | if (ddata->data_lines) |
79 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
74 | in->ops.dpi->set_timings(in, &ddata->videomode); | 80 | in->ops.dpi->set_timings(in, &ddata->videomode); |
75 | 81 | ||
76 | r = in->ops.dpi->enable(in); | 82 | r = in->ops.dpi->enable(in); |
77 | if (r) | 83 | if (r) |
78 | return r; | 84 | return r; |
79 | 85 | ||
80 | if (gpio_is_valid(ddata->enable_gpio)) | 86 | if (ddata->enable_gpio) |
81 | gpio_set_value_cansleep(ddata->enable_gpio, 1); | 87 | gpiod_set_value_cansleep(ddata->enable_gpio, 1); |
82 | 88 | ||
83 | if (gpio_is_valid(ddata->backlight_gpio)) | 89 | if (gpio_is_valid(ddata->backlight_gpio)) |
84 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); | 90 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); |
@@ -96,8 +102,8 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev) | |||
96 | if (!omapdss_device_is_enabled(dssdev)) | 102 | if (!omapdss_device_is_enabled(dssdev)) |
97 | return; | 103 | return; |
98 | 104 | ||
99 | if (gpio_is_valid(ddata->enable_gpio)) | 105 | if (ddata->enable_gpio) |
100 | gpio_set_value_cansleep(ddata->enable_gpio, 0); | 106 | gpiod_set_value_cansleep(ddata->enable_gpio, 0); |
101 | 107 | ||
102 | if (gpio_is_valid(ddata->backlight_gpio)) | 108 | if (gpio_is_valid(ddata->backlight_gpio)) |
103 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); | 109 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); |
@@ -156,6 +162,7 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev) | |||
156 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | 162 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); |
157 | struct omap_dss_device *dssdev, *in; | 163 | struct omap_dss_device *dssdev, *in; |
158 | struct videomode vm; | 164 | struct videomode vm; |
165 | int r; | ||
159 | 166 | ||
160 | pdata = dev_get_platdata(&pdev->dev); | 167 | pdata = dev_get_platdata(&pdev->dev); |
161 | 168 | ||
@@ -176,10 +183,65 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev) | |||
176 | dssdev = &ddata->dssdev; | 183 | dssdev = &ddata->dssdev; |
177 | dssdev->name = pdata->name; | 184 | dssdev->name = pdata->name; |
178 | 185 | ||
179 | ddata->enable_gpio = pdata->enable_gpio; | 186 | r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio, |
187 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
188 | if (r) | ||
189 | goto err_gpio; | ||
190 | |||
191 | ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio); | ||
192 | |||
180 | ddata->backlight_gpio = pdata->backlight_gpio; | 193 | ddata->backlight_gpio = pdata->backlight_gpio; |
181 | 194 | ||
182 | return 0; | 195 | return 0; |
196 | |||
197 | err_gpio: | ||
198 | omap_dss_put_device(ddata->in); | ||
199 | return r; | ||
200 | } | ||
201 | |||
202 | static int panel_dpi_probe_of(struct platform_device *pdev) | ||
203 | { | ||
204 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
205 | struct device_node *node = pdev->dev.of_node; | ||
206 | struct omap_dss_device *in; | ||
207 | int r; | ||
208 | struct display_timing timing; | ||
209 | struct videomode vm; | ||
210 | struct gpio_desc *gpio; | ||
211 | |||
212 | gpio = devm_gpiod_get(&pdev->dev, "enable"); | ||
213 | |||
214 | if (IS_ERR(gpio)) { | ||
215 | if (PTR_ERR(gpio) != -ENOENT) | ||
216 | return PTR_ERR(gpio); | ||
217 | else | ||
218 | gpio = NULL; | ||
219 | } else { | ||
220 | gpiod_direction_output(gpio, 0); | ||
221 | } | ||
222 | |||
223 | ddata->enable_gpio = gpio; | ||
224 | |||
225 | ddata->backlight_gpio = -ENOENT; | ||
226 | |||
227 | r = of_get_display_timing(node, "panel-timing", &timing); | ||
228 | if (r) { | ||
229 | dev_err(&pdev->dev, "failed to get video timing\n"); | ||
230 | return r; | ||
231 | } | ||
232 | |||
233 | videomode_from_timing(&timing, &vm); | ||
234 | videomode_to_omap_video_timings(&vm, &ddata->videomode); | ||
235 | |||
236 | in = omapdss_of_find_source_for_first_ep(node); | ||
237 | if (IS_ERR(in)) { | ||
238 | dev_err(&pdev->dev, "failed to find video source\n"); | ||
239 | return PTR_ERR(in); | ||
240 | } | ||
241 | |||
242 | ddata->in = in; | ||
243 | |||
244 | return 0; | ||
183 | } | 245 | } |
184 | 246 | ||
185 | static int panel_dpi_probe(struct platform_device *pdev) | 247 | static int panel_dpi_probe(struct platform_device *pdev) |
@@ -198,17 +260,14 @@ static int panel_dpi_probe(struct platform_device *pdev) | |||
198 | r = panel_dpi_probe_pdata(pdev); | 260 | r = panel_dpi_probe_pdata(pdev); |
199 | if (r) | 261 | if (r) |
200 | return r; | 262 | return r; |
263 | } else if (pdev->dev.of_node) { | ||
264 | r = panel_dpi_probe_of(pdev); | ||
265 | if (r) | ||
266 | return r; | ||
201 | } else { | 267 | } else { |
202 | return -ENODEV; | 268 | return -ENODEV; |
203 | } | 269 | } |
204 | 270 | ||
205 | if (gpio_is_valid(ddata->enable_gpio)) { | ||
206 | r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio, | ||
207 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
208 | if (r) | ||
209 | goto err_gpio; | ||
210 | } | ||
211 | |||
212 | if (gpio_is_valid(ddata->backlight_gpio)) { | 271 | if (gpio_is_valid(ddata->backlight_gpio)) { |
213 | r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio, | 272 | r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio, |
214 | GPIOF_OUT_INIT_LOW, "panel backlight"); | 273 | GPIOF_OUT_INIT_LOW, "panel backlight"); |
@@ -254,12 +313,20 @@ static int __exit panel_dpi_remove(struct platform_device *pdev) | |||
254 | return 0; | 313 | return 0; |
255 | } | 314 | } |
256 | 315 | ||
316 | static const struct of_device_id panel_dpi_of_match[] = { | ||
317 | { .compatible = "omapdss,panel-dpi", }, | ||
318 | {}, | ||
319 | }; | ||
320 | |||
321 | MODULE_DEVICE_TABLE(of, panel_dpi_of_match); | ||
322 | |||
257 | static struct platform_driver panel_dpi_driver = { | 323 | static struct platform_driver panel_dpi_driver = { |
258 | .probe = panel_dpi_probe, | 324 | .probe = panel_dpi_probe, |
259 | .remove = __exit_p(panel_dpi_remove), | 325 | .remove = __exit_p(panel_dpi_remove), |
260 | .driver = { | 326 | .driver = { |
261 | .name = "panel-dpi", | 327 | .name = "panel-dpi", |
262 | .owner = THIS_MODULE, | 328 | .owner = THIS_MODULE, |
329 | .of_match_table = panel_dpi_of_match, | ||
263 | }, | 330 | }, |
264 | }; | 331 | }; |
265 | 332 | ||
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c index 2e6b513222d9..cc5b5124e0b4 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c | |||
@@ -50,9 +50,10 @@ struct panel_drv_data { | |||
50 | 50 | ||
51 | struct omap_video_timings videomode; | 51 | struct omap_video_timings videomode; |
52 | 52 | ||
53 | int reset_gpio; | 53 | /* used for non-DT boot, to be removed */ |
54 | int backlight_gpio; | 54 | int backlight_gpio; |
55 | int enable_gpio; | 55 | |
56 | struct gpio_desc *enable_gpio; | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | 59 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) |
@@ -158,15 +159,16 @@ static int lb035q02_enable(struct omap_dss_device *dssdev) | |||
158 | if (omapdss_device_is_enabled(dssdev)) | 159 | if (omapdss_device_is_enabled(dssdev)) |
159 | return 0; | 160 | return 0; |
160 | 161 | ||
161 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 162 | if (ddata->data_lines) |
163 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
162 | in->ops.dpi->set_timings(in, &ddata->videomode); | 164 | in->ops.dpi->set_timings(in, &ddata->videomode); |
163 | 165 | ||
164 | r = in->ops.dpi->enable(in); | 166 | r = in->ops.dpi->enable(in); |
165 | if (r) | 167 | if (r) |
166 | return r; | 168 | return r; |
167 | 169 | ||
168 | if (gpio_is_valid(ddata->enable_gpio)) | 170 | if (ddata->enable_gpio) |
169 | gpio_set_value_cansleep(ddata->enable_gpio, 1); | 171 | gpiod_set_value_cansleep(ddata->enable_gpio, 1); |
170 | 172 | ||
171 | if (gpio_is_valid(ddata->backlight_gpio)) | 173 | if (gpio_is_valid(ddata->backlight_gpio)) |
172 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); | 174 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); |
@@ -184,8 +186,8 @@ static void lb035q02_disable(struct omap_dss_device *dssdev) | |||
184 | if (!omapdss_device_is_enabled(dssdev)) | 186 | if (!omapdss_device_is_enabled(dssdev)) |
185 | return; | 187 | return; |
186 | 188 | ||
187 | if (gpio_is_valid(ddata->enable_gpio)) | 189 | if (ddata->enable_gpio) |
188 | gpio_set_value_cansleep(ddata->enable_gpio, 0); | 190 | gpiod_set_value_cansleep(ddata->enable_gpio, 0); |
189 | 191 | ||
190 | if (gpio_is_valid(ddata->backlight_gpio)) | 192 | if (gpio_is_valid(ddata->backlight_gpio)) |
191 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); | 193 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); |
@@ -243,6 +245,7 @@ static int lb035q02_probe_pdata(struct spi_device *spi) | |||
243 | const struct panel_lb035q02_platform_data *pdata; | 245 | const struct panel_lb035q02_platform_data *pdata; |
244 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | 246 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); |
245 | struct omap_dss_device *dssdev, *in; | 247 | struct omap_dss_device *dssdev, *in; |
248 | int r; | ||
246 | 249 | ||
247 | pdata = dev_get_platdata(&spi->dev); | 250 | pdata = dev_get_platdata(&spi->dev); |
248 | 251 | ||
@@ -260,10 +263,48 @@ static int lb035q02_probe_pdata(struct spi_device *spi) | |||
260 | dssdev = &ddata->dssdev; | 263 | dssdev = &ddata->dssdev; |
261 | dssdev->name = pdata->name; | 264 | dssdev->name = pdata->name; |
262 | 265 | ||
263 | ddata->enable_gpio = pdata->enable_gpio; | 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 | |||
264 | ddata->backlight_gpio = pdata->backlight_gpio; | 273 | ddata->backlight_gpio = pdata->backlight_gpio; |
265 | 274 | ||
266 | return 0; | 275 | return 0; |
276 | err_gpio: | ||
277 | omap_dss_put_device(ddata->in); | ||
278 | return r; | ||
279 | } | ||
280 | |||
281 | static 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"); | ||
289 | if (IS_ERR(gpio)) { | ||
290 | dev_err(&spi->dev, "failed to parse enable gpio\n"); | ||
291 | return PTR_ERR(gpio); | ||
292 | } else { | ||
293 | gpiod_direction_output(gpio, 0); | ||
294 | ddata->enable_gpio = gpio; | ||
295 | } | ||
296 | |||
297 | ddata->backlight_gpio = -ENOENT; | ||
298 | |||
299 | in = omapdss_of_find_source_for_first_ep(node); | ||
300 | if (IS_ERR(in)) { | ||
301 | dev_err(&spi->dev, "failed to find video source\n"); | ||
302 | return PTR_ERR(in); | ||
303 | } | ||
304 | |||
305 | ddata->in = in; | ||
306 | |||
307 | return 0; | ||
267 | } | 308 | } |
268 | 309 | ||
269 | static int lb035q02_panel_spi_probe(struct spi_device *spi) | 310 | static int lb035q02_panel_spi_probe(struct spi_device *spi) |
@@ -284,17 +325,14 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) | |||
284 | r = lb035q02_probe_pdata(spi); | 325 | r = lb035q02_probe_pdata(spi); |
285 | if (r) | 326 | if (r) |
286 | return r; | 327 | return r; |
328 | } else if (spi->dev.of_node) { | ||
329 | r = lb035q02_probe_of(spi); | ||
330 | if (r) | ||
331 | return r; | ||
287 | } else { | 332 | } else { |
288 | return -ENODEV; | 333 | return -ENODEV; |
289 | } | 334 | } |
290 | 335 | ||
291 | if (gpio_is_valid(ddata->enable_gpio)) { | ||
292 | r = devm_gpio_request_one(&spi->dev, ddata->enable_gpio, | ||
293 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
294 | if (r) | ||
295 | goto err_gpio; | ||
296 | } | ||
297 | |||
298 | if (gpio_is_valid(ddata->backlight_gpio)) { | 336 | if (gpio_is_valid(ddata->backlight_gpio)) { |
299 | r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, | 337 | r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, |
300 | GPIOF_OUT_INIT_LOW, "panel backlight"); | 338 | GPIOF_OUT_INIT_LOW, "panel backlight"); |
@@ -342,17 +380,26 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi) | |||
342 | return 0; | 380 | return 0; |
343 | } | 381 | } |
344 | 382 | ||
383 | static const struct of_device_id lb035q02_of_match[] = { | ||
384 | { .compatible = "omapdss,lgphilips,lb035q02", }, | ||
385 | {}, | ||
386 | }; | ||
387 | |||
388 | MODULE_DEVICE_TABLE(of, lb035q02_of_match); | ||
389 | |||
345 | static struct spi_driver lb035q02_spi_driver = { | 390 | static struct spi_driver lb035q02_spi_driver = { |
346 | .probe = lb035q02_panel_spi_probe, | 391 | .probe = lb035q02_panel_spi_probe, |
347 | .remove = lb035q02_panel_spi_remove, | 392 | .remove = lb035q02_panel_spi_remove, |
348 | .driver = { | 393 | .driver = { |
349 | .name = "panel_lgphilips_lb035q02", | 394 | .name = "panel_lgphilips_lb035q02", |
350 | .owner = THIS_MODULE, | 395 | .owner = THIS_MODULE, |
396 | .of_match_table = lb035q02_of_match, | ||
351 | }, | 397 | }, |
352 | }; | 398 | }; |
353 | 399 | ||
354 | module_spi_driver(lb035q02_spi_driver); | 400 | module_spi_driver(lb035q02_spi_driver); |
355 | 401 | ||
402 | MODULE_ALIAS("spi:lgphilips,lb035q02"); | ||
356 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | 403 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); |
357 | MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); | 404 | MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); |
358 | MODULE_LICENSE("GPL"); | 405 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c b/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c index 996fa004b48c..3595f111aa35 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/spi/spi.h> | 16 | #include <linux/spi/spi.h> |
17 | #include <linux/fb.h> | 17 | #include <linux/fb.h> |
18 | #include <linux/gpio.h> | 18 | #include <linux/gpio.h> |
19 | #include <linux/of_gpio.h> | ||
19 | 20 | ||
20 | #include <video/omapdss.h> | 21 | #include <video/omapdss.h> |
21 | #include <video/omap-panel-data.h> | 22 | #include <video/omap-panel-data.h> |
@@ -156,7 +157,8 @@ static int nec_8048_enable(struct omap_dss_device *dssdev) | |||
156 | if (omapdss_device_is_enabled(dssdev)) | 157 | if (omapdss_device_is_enabled(dssdev)) |
157 | return 0; | 158 | return 0; |
158 | 159 | ||
159 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 160 | if (ddata->data_lines) |
161 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
160 | in->ops.dpi->set_timings(in, &ddata->videomode); | 162 | in->ops.dpi->set_timings(in, &ddata->videomode); |
161 | 163 | ||
162 | r = in->ops.dpi->enable(in); | 164 | r = in->ops.dpi->enable(in); |
@@ -258,6 +260,34 @@ static int nec_8048_probe_pdata(struct spi_device *spi) | |||
258 | return 0; | 260 | return 0; |
259 | } | 261 | } |
260 | 262 | ||
263 | static 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 | |||
261 | static int nec_8048_probe(struct spi_device *spi) | 291 | static int nec_8048_probe(struct spi_device *spi) |
262 | { | 292 | { |
263 | struct panel_drv_data *ddata; | 293 | struct panel_drv_data *ddata; |
@@ -289,6 +319,10 @@ static int nec_8048_probe(struct spi_device *spi) | |||
289 | r = nec_8048_probe_pdata(spi); | 319 | r = nec_8048_probe_pdata(spi); |
290 | if (r) | 320 | if (r) |
291 | return r; | 321 | return r; |
322 | } else if (spi->dev.of_node) { | ||
323 | r = nec_8048_probe_of(spi); | ||
324 | if (r) | ||
325 | return r; | ||
292 | } else { | 326 | } else { |
293 | return -ENODEV; | 327 | return -ENODEV; |
294 | } | 328 | } |
@@ -377,11 +411,19 @@ static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend, | |||
377 | #define NEC_8048_PM_OPS NULL | 411 | #define NEC_8048_PM_OPS NULL |
378 | #endif | 412 | #endif |
379 | 413 | ||
414 | static const struct of_device_id nec_8048_of_match[] = { | ||
415 | { .compatible = "omapdss,nec,nl8048hl11", }, | ||
416 | {}, | ||
417 | }; | ||
418 | |||
419 | MODULE_DEVICE_TABLE(of, nec_8048_of_match); | ||
420 | |||
380 | static struct spi_driver nec_8048_driver = { | 421 | static struct spi_driver nec_8048_driver = { |
381 | .driver = { | 422 | .driver = { |
382 | .name = "panel-nec-nl8048hl11", | 423 | .name = "panel-nec-nl8048hl11", |
383 | .owner = THIS_MODULE, | 424 | .owner = THIS_MODULE, |
384 | .pm = NEC_8048_PM_OPS, | 425 | .pm = NEC_8048_PM_OPS, |
426 | .of_match_table = nec_8048_of_match, | ||
385 | }, | 427 | }, |
386 | .probe = nec_8048_probe, | 428 | .probe = nec_8048_probe, |
387 | .remove = nec_8048_remove, | 429 | .remove = nec_8048_remove, |
@@ -389,6 +431,7 @@ static struct spi_driver nec_8048_driver = { | |||
389 | 431 | ||
390 | module_spi_driver(nec_8048_driver); | 432 | module_spi_driver(nec_8048_driver); |
391 | 433 | ||
434 | MODULE_ALIAS("spi:nec,nl8048hl11"); | ||
392 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); | 435 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); |
393 | MODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); | 436 | MODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); |
394 | MODULE_LICENSE("GPL"); | 437 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c index b2f710be565d..f1f72ce50a17 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c | |||
@@ -12,25 +12,28 @@ | |||
12 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
13 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/of.h> | ||
16 | #include <linux/of_gpio.h> | ||
15 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
16 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
17 | 19 | #include <linux/regulator/consumer.h> | |
18 | #include <video/omapdss.h> | 20 | #include <video/omapdss.h> |
19 | #include <video/omap-panel-data.h> | 21 | #include <video/omap-panel-data.h> |
20 | 22 | ||
21 | struct panel_drv_data { | 23 | struct panel_drv_data { |
22 | struct omap_dss_device dssdev; | 24 | struct omap_dss_device dssdev; |
23 | struct omap_dss_device *in; | 25 | struct omap_dss_device *in; |
26 | struct regulator *vcc; | ||
24 | 27 | ||
25 | int data_lines; | 28 | int data_lines; |
26 | 29 | ||
27 | struct omap_video_timings videomode; | 30 | struct omap_video_timings videomode; |
28 | 31 | ||
29 | int resb_gpio; | 32 | struct gpio_desc *resb_gpio; /* low = reset active min 20 us */ |
30 | int ini_gpio; | 33 | struct gpio_desc *ini_gpio; /* high = power on */ |
31 | int mo_gpio; | 34 | struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */ |
32 | int lr_gpio; | 35 | struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */ |
33 | int ud_gpio; | 36 | struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */ |
34 | }; | 37 | }; |
35 | 38 | ||
36 | static const struct omap_video_timings sharp_ls_timings = { | 39 | static const struct omap_video_timings sharp_ls_timings = { |
@@ -95,21 +98,30 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev) | |||
95 | if (omapdss_device_is_enabled(dssdev)) | 98 | if (omapdss_device_is_enabled(dssdev)) |
96 | return 0; | 99 | return 0; |
97 | 100 | ||
98 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 101 | if (ddata->data_lines) |
102 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
99 | in->ops.dpi->set_timings(in, &ddata->videomode); | 103 | in->ops.dpi->set_timings(in, &ddata->videomode); |
100 | 104 | ||
105 | if (ddata->vcc) { | ||
106 | r = regulator_enable(ddata->vcc); | ||
107 | if (r != 0) | ||
108 | return r; | ||
109 | } | ||
110 | |||
101 | r = in->ops.dpi->enable(in); | 111 | r = in->ops.dpi->enable(in); |
102 | if (r) | 112 | if (r) { |
113 | regulator_disable(ddata->vcc); | ||
103 | return r; | 114 | return r; |
115 | } | ||
104 | 116 | ||
105 | /* wait couple of vsyncs until enabling the LCD */ | 117 | /* wait couple of vsyncs until enabling the LCD */ |
106 | msleep(50); | 118 | msleep(50); |
107 | 119 | ||
108 | if (gpio_is_valid(ddata->resb_gpio)) | 120 | if (ddata->resb_gpio) |
109 | gpio_set_value_cansleep(ddata->resb_gpio, 1); | 121 | gpiod_set_value_cansleep(ddata->resb_gpio, 1); |
110 | 122 | ||
111 | if (gpio_is_valid(ddata->ini_gpio)) | 123 | if (ddata->ini_gpio) |
112 | gpio_set_value_cansleep(ddata->ini_gpio, 1); | 124 | gpiod_set_value_cansleep(ddata->ini_gpio, 1); |
113 | 125 | ||
114 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 126 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
115 | 127 | ||
@@ -124,11 +136,11 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev) | |||
124 | if (!omapdss_device_is_enabled(dssdev)) | 136 | if (!omapdss_device_is_enabled(dssdev)) |
125 | return; | 137 | return; |
126 | 138 | ||
127 | if (gpio_is_valid(ddata->ini_gpio)) | 139 | if (ddata->ini_gpio) |
128 | gpio_set_value_cansleep(ddata->ini_gpio, 0); | 140 | gpiod_set_value_cansleep(ddata->ini_gpio, 0); |
129 | 141 | ||
130 | if (gpio_is_valid(ddata->resb_gpio)) | 142 | if (ddata->resb_gpio) |
131 | gpio_set_value_cansleep(ddata->resb_gpio, 0); | 143 | gpiod_set_value_cansleep(ddata->resb_gpio, 0); |
132 | 144 | ||
133 | /* wait at least 5 vsyncs after disabling the LCD */ | 145 | /* wait at least 5 vsyncs after disabling the LCD */ |
134 | 146 | ||
@@ -136,6 +148,9 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev) | |||
136 | 148 | ||
137 | in->ops.dpi->disable(in); | 149 | in->ops.dpi->disable(in); |
138 | 150 | ||
151 | if (ddata->vcc) | ||
152 | regulator_disable(ddata->vcc); | ||
153 | |||
139 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 154 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
140 | } | 155 | } |
141 | 156 | ||
@@ -182,11 +197,32 @@ static struct omap_dss_driver sharp_ls_ops = { | |||
182 | .get_resolution = omapdss_default_get_resolution, | 197 | .get_resolution = omapdss_default_get_resolution, |
183 | }; | 198 | }; |
184 | 199 | ||
200 | static 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 | |||
185 | static int sharp_ls_probe_pdata(struct platform_device *pdev) | 220 | static int sharp_ls_probe_pdata(struct platform_device *pdev) |
186 | { | 221 | { |
187 | const struct panel_sharp_ls037v7dw01_platform_data *pdata; | 222 | const struct panel_sharp_ls037v7dw01_platform_data *pdata; |
188 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | 223 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); |
189 | struct omap_dss_device *dssdev, *in; | 224 | struct omap_dss_device *dssdev, *in; |
225 | int r; | ||
190 | 226 | ||
191 | pdata = dev_get_platdata(&pdev->dev); | 227 | pdata = dev_get_platdata(&pdev->dev); |
192 | 228 | ||
@@ -204,11 +240,95 @@ static int sharp_ls_probe_pdata(struct platform_device *pdev) | |||
204 | dssdev = &ddata->dssdev; | 240 | dssdev = &ddata->dssdev; |
205 | dssdev->name = pdata->name; | 241 | dssdev->name = pdata->name; |
206 | 242 | ||
207 | ddata->resb_gpio = pdata->resb_gpio; | 243 | r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW, |
208 | ddata->ini_gpio = pdata->ini_gpio; | 244 | "lcd MO", &ddata->mo_gpio); |
209 | ddata->mo_gpio = pdata->mo_gpio; | 245 | if (r) |
210 | ddata->lr_gpio = pdata->lr_gpio; | 246 | return r; |
211 | ddata->ud_gpio = pdata->ud_gpio; | 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 | |||
267 | static 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 | int r; | ||
272 | |||
273 | *gpiod = NULL; | ||
274 | |||
275 | gd = devm_gpiod_get_index(dev, desc, index); | ||
276 | if (IS_ERR(gd)) | ||
277 | return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd); | ||
278 | |||
279 | r = gpiod_direction_output(gd, val); | ||
280 | if (r) | ||
281 | return r; | ||
282 | |||
283 | *gpiod = gd; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int sharp_ls_probe_of(struct platform_device *pdev) | ||
288 | { | ||
289 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
290 | struct device_node *node = pdev->dev.of_node; | ||
291 | struct omap_dss_device *in; | ||
292 | int r; | ||
293 | |||
294 | ddata->vcc = devm_regulator_get(&pdev->dev, "envdd"); | ||
295 | if (IS_ERR(ddata->vcc)) { | ||
296 | dev_err(&pdev->dev, "failed to get regulator\n"); | ||
297 | return PTR_ERR(ddata->vcc); | ||
298 | } | ||
299 | |||
300 | /* lcd INI */ | ||
301 | r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | /* lcd RESB */ | ||
306 | r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio); | ||
307 | if (r) | ||
308 | return r; | ||
309 | |||
310 | /* lcd MO */ | ||
311 | r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio); | ||
312 | if (r) | ||
313 | return r; | ||
314 | |||
315 | /* lcd LR */ | ||
316 | r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio); | ||
317 | if (r) | ||
318 | return r; | ||
319 | |||
320 | /* lcd UD */ | ||
321 | r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio); | ||
322 | if (r) | ||
323 | return r; | ||
324 | |||
325 | in = omapdss_of_find_source_for_first_ep(node); | ||
326 | if (IS_ERR(in)) { | ||
327 | dev_err(&pdev->dev, "failed to find video source\n"); | ||
328 | return PTR_ERR(in); | ||
329 | } | ||
330 | |||
331 | ddata->in = in; | ||
212 | 332 | ||
213 | return 0; | 333 | return 0; |
214 | } | 334 | } |
@@ -229,45 +349,14 @@ static int sharp_ls_probe(struct platform_device *pdev) | |||
229 | r = sharp_ls_probe_pdata(pdev); | 349 | r = sharp_ls_probe_pdata(pdev); |
230 | if (r) | 350 | if (r) |
231 | return r; | 351 | return r; |
352 | } else if (pdev->dev.of_node) { | ||
353 | r = sharp_ls_probe_of(pdev); | ||
354 | if (r) | ||
355 | return r; | ||
232 | } else { | 356 | } else { |
233 | return -ENODEV; | 357 | return -ENODEV; |
234 | } | 358 | } |
235 | 359 | ||
236 | if (gpio_is_valid(ddata->mo_gpio)) { | ||
237 | r = devm_gpio_request_one(&pdev->dev, ddata->mo_gpio, | ||
238 | GPIOF_OUT_INIT_LOW, "lcd MO"); | ||
239 | if (r) | ||
240 | goto err_gpio; | ||
241 | } | ||
242 | |||
243 | if (gpio_is_valid(ddata->lr_gpio)) { | ||
244 | r = devm_gpio_request_one(&pdev->dev, ddata->lr_gpio, | ||
245 | GPIOF_OUT_INIT_HIGH, "lcd LR"); | ||
246 | if (r) | ||
247 | goto err_gpio; | ||
248 | } | ||
249 | |||
250 | if (gpio_is_valid(ddata->ud_gpio)) { | ||
251 | r = devm_gpio_request_one(&pdev->dev, ddata->ud_gpio, | ||
252 | GPIOF_OUT_INIT_HIGH, "lcd UD"); | ||
253 | if (r) | ||
254 | goto err_gpio; | ||
255 | } | ||
256 | |||
257 | if (gpio_is_valid(ddata->resb_gpio)) { | ||
258 | r = devm_gpio_request_one(&pdev->dev, ddata->resb_gpio, | ||
259 | GPIOF_OUT_INIT_LOW, "lcd RESB"); | ||
260 | if (r) | ||
261 | goto err_gpio; | ||
262 | } | ||
263 | |||
264 | if (gpio_is_valid(ddata->ini_gpio)) { | ||
265 | r = devm_gpio_request_one(&pdev->dev, ddata->ini_gpio, | ||
266 | GPIOF_OUT_INIT_LOW, "lcd INI"); | ||
267 | if (r) | ||
268 | goto err_gpio; | ||
269 | } | ||
270 | |||
271 | ddata->videomode = sharp_ls_timings; | 360 | ddata->videomode = sharp_ls_timings; |
272 | 361 | ||
273 | dssdev = &ddata->dssdev; | 362 | dssdev = &ddata->dssdev; |
@@ -287,7 +376,6 @@ static int sharp_ls_probe(struct platform_device *pdev) | |||
287 | return 0; | 376 | return 0; |
288 | 377 | ||
289 | err_reg: | 378 | err_reg: |
290 | err_gpio: | ||
291 | omap_dss_put_device(ddata->in); | 379 | omap_dss_put_device(ddata->in); |
292 | return r; | 380 | return r; |
293 | } | 381 | } |
@@ -308,12 +396,20 @@ static int __exit sharp_ls_remove(struct platform_device *pdev) | |||
308 | return 0; | 396 | return 0; |
309 | } | 397 | } |
310 | 398 | ||
399 | static const struct of_device_id sharp_ls_of_match[] = { | ||
400 | { .compatible = "omapdss,sharp,ls037v7dw01", }, | ||
401 | {}, | ||
402 | }; | ||
403 | |||
404 | MODULE_DEVICE_TABLE(of, sharp_ls_of_match); | ||
405 | |||
311 | static struct platform_driver sharp_ls_driver = { | 406 | static struct platform_driver sharp_ls_driver = { |
312 | .probe = sharp_ls_probe, | 407 | .probe = sharp_ls_probe, |
313 | .remove = __exit_p(sharp_ls_remove), | 408 | .remove = __exit_p(sharp_ls_remove), |
314 | .driver = { | 409 | .driver = { |
315 | .name = "panel-sharp-ls037v7dw01", | 410 | .name = "panel-sharp-ls037v7dw01", |
316 | .owner = THIS_MODULE, | 411 | .owner = THIS_MODULE, |
412 | .of_match_table = sharp_ls_of_match, | ||
317 | }, | 413 | }, |
318 | }; | 414 | }; |
319 | 415 | ||
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c index fae6adc005a7..728808bcceeb 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c | |||
@@ -206,7 +206,8 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev) | |||
206 | if (omapdss_device_is_enabled(dssdev)) | 206 | if (omapdss_device_is_enabled(dssdev)) |
207 | return 0; | 207 | return 0; |
208 | 208 | ||
209 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 209 | if (ddata->data_lines) |
210 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
210 | in->ops.dpi->set_timings(in, &ddata->videomode); | 211 | in->ops.dpi->set_timings(in, &ddata->videomode); |
211 | 212 | ||
212 | r = in->ops.dpi->enable(in); | 213 | r = in->ops.dpi->enable(in); |
@@ -389,6 +390,23 @@ static int td028ttec1_panel_probe_pdata(struct spi_device *spi) | |||
389 | return 0; | 390 | return 0; |
390 | } | 391 | } |
391 | 392 | ||
393 | static 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 | |||
392 | static int td028ttec1_panel_probe(struct spi_device *spi) | 410 | static int td028ttec1_panel_probe(struct spi_device *spi) |
393 | { | 411 | { |
394 | struct panel_drv_data *ddata; | 412 | struct panel_drv_data *ddata; |
@@ -418,6 +436,10 @@ static int td028ttec1_panel_probe(struct spi_device *spi) | |||
418 | r = td028ttec1_panel_probe_pdata(spi); | 436 | r = td028ttec1_panel_probe_pdata(spi); |
419 | if (r) | 437 | if (r) |
420 | return r; | 438 | return r; |
439 | } else if (spi->dev.of_node) { | ||
440 | r = td028ttec1_probe_of(spi); | ||
441 | if (r) | ||
442 | return r; | ||
421 | } else { | 443 | } else { |
422 | return -ENODEV; | 444 | return -ENODEV; |
423 | } | 445 | } |
@@ -463,6 +485,13 @@ static int td028ttec1_panel_remove(struct spi_device *spi) | |||
463 | return 0; | 485 | return 0; |
464 | } | 486 | } |
465 | 487 | ||
488 | static const struct of_device_id td028ttec1_of_match[] = { | ||
489 | { .compatible = "omapdss,toppoly,td028ttec1", }, | ||
490 | {}, | ||
491 | }; | ||
492 | |||
493 | MODULE_DEVICE_TABLE(of, td028ttec1_of_match); | ||
494 | |||
466 | static struct spi_driver td028ttec1_spi_driver = { | 495 | static struct spi_driver td028ttec1_spi_driver = { |
467 | .probe = td028ttec1_panel_probe, | 496 | .probe = td028ttec1_panel_probe, |
468 | .remove = td028ttec1_panel_remove, | 497 | .remove = td028ttec1_panel_remove, |
@@ -470,11 +499,13 @@ static struct spi_driver td028ttec1_spi_driver = { | |||
470 | .driver = { | 499 | .driver = { |
471 | .name = "panel-tpo-td028ttec1", | 500 | .name = "panel-tpo-td028ttec1", |
472 | .owner = THIS_MODULE, | 501 | .owner = THIS_MODULE, |
502 | .of_match_table = td028ttec1_of_match, | ||
473 | }, | 503 | }, |
474 | }; | 504 | }; |
475 | 505 | ||
476 | module_spi_driver(td028ttec1_spi_driver); | 506 | module_spi_driver(td028ttec1_spi_driver); |
477 | 507 | ||
508 | MODULE_ALIAS("spi:toppoly,td028ttec1"); | ||
478 | MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>"); | 509 | MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>"); |
479 | MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); | 510 | MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); |
480 | MODULE_LICENSE("GPL"); | 511 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c index 875b40263b33..de78ab0caaa8 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/of_gpio.h> | ||
20 | 21 | ||
21 | #include <video/omapdss.h> | 22 | #include <video/omapdss.h> |
22 | #include <video/omap-panel-data.h> | 23 | #include <video/omap-panel-data.h> |
@@ -376,7 +377,8 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev) | |||
376 | if (omapdss_device_is_enabled(dssdev)) | 377 | if (omapdss_device_is_enabled(dssdev)) |
377 | return 0; | 378 | return 0; |
378 | 379 | ||
379 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | 380 | if (ddata->data_lines) |
381 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
380 | in->ops.dpi->set_timings(in, &ddata->videomode); | 382 | in->ops.dpi->set_timings(in, &ddata->videomode); |
381 | 383 | ||
382 | r = in->ops.dpi->enable(in); | 384 | r = in->ops.dpi->enable(in); |
@@ -489,6 +491,31 @@ static int tpo_td043_probe_pdata(struct spi_device *spi) | |||
489 | return 0; | 491 | return 0; |
490 | } | 492 | } |
491 | 493 | ||
494 | static 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 | |||
492 | static int tpo_td043_probe(struct spi_device *spi) | 519 | static int tpo_td043_probe(struct spi_device *spi) |
493 | { | 520 | { |
494 | struct panel_drv_data *ddata; | 521 | struct panel_drv_data *ddata; |
@@ -518,6 +545,10 @@ static int tpo_td043_probe(struct spi_device *spi) | |||
518 | r = tpo_td043_probe_pdata(spi); | 545 | r = tpo_td043_probe_pdata(spi); |
519 | if (r) | 546 | if (r) |
520 | return r; | 547 | return r; |
548 | } else if (spi->dev.of_node) { | ||
549 | r = tpo_td043_probe_of(spi); | ||
550 | if (r) | ||
551 | return r; | ||
521 | } else { | 552 | } else { |
522 | return -ENODEV; | 553 | return -ENODEV; |
523 | } | 554 | } |
@@ -629,11 +660,19 @@ static int tpo_td043_spi_resume(struct device *dev) | |||
629 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | 660 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, |
630 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | 661 | tpo_td043_spi_suspend, tpo_td043_spi_resume); |
631 | 662 | ||
663 | static const struct of_device_id tpo_td043_of_match[] = { | ||
664 | { .compatible = "omapdss,tpo,td043mtea1", }, | ||
665 | {}, | ||
666 | }; | ||
667 | |||
668 | MODULE_DEVICE_TABLE(of, tpo_td043_of_match); | ||
669 | |||
632 | static struct spi_driver tpo_td043_spi_driver = { | 670 | static struct spi_driver tpo_td043_spi_driver = { |
633 | .driver = { | 671 | .driver = { |
634 | .name = "panel-tpo-td043mtea1", | 672 | .name = "panel-tpo-td043mtea1", |
635 | .owner = THIS_MODULE, | 673 | .owner = THIS_MODULE, |
636 | .pm = &tpo_td043_spi_pm, | 674 | .pm = &tpo_td043_spi_pm, |
675 | .of_match_table = tpo_td043_of_match, | ||
637 | }, | 676 | }, |
638 | .probe = tpo_td043_probe, | 677 | .probe = tpo_td043_probe, |
639 | .remove = tpo_td043_remove, | 678 | .remove = tpo_td043_remove, |
@@ -641,6 +680,7 @@ static struct spi_driver tpo_td043_spi_driver = { | |||
641 | 680 | ||
642 | module_spi_driver(tpo_td043_spi_driver); | 681 | module_spi_driver(tpo_td043_spi_driver); |
643 | 682 | ||
683 | MODULE_ALIAS("spi:tpo,td043mtea1"); | ||
644 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); | 684 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); |
645 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | 685 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); |
646 | MODULE_LICENSE("GPL"); | 686 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig index dde4281663b1..285bcd103dce 100644 --- a/drivers/video/fbdev/omap2/dss/Kconfig +++ b/drivers/video/fbdev/omap2/dss/Kconfig | |||
@@ -1,6 +1,10 @@ | |||
1 | config OMAP2_DSS_INIT | ||
2 | bool | ||
3 | |||
1 | menuconfig OMAP2_DSS | 4 | menuconfig OMAP2_DSS |
2 | tristate "OMAP2+ Display Subsystem support" | 5 | tristate "OMAP2+ Display Subsystem support" |
3 | select VIDEOMODE_HELPERS | 6 | select VIDEOMODE_HELPERS |
7 | select OMAP2_DSS_INIT | ||
4 | help | 8 | help |
5 | OMAP2+ Display Subsystem support. | 9 | OMAP2+ Display Subsystem support. |
6 | 10 | ||
@@ -59,16 +63,32 @@ config OMAP2_DSS_VENC | |||
59 | help | 63 | help |
60 | OMAP Video Encoder support for S-Video and composite TV-out. | 64 | OMAP Video Encoder support for S-Video and composite TV-out. |
61 | 65 | ||
66 | config OMAP2_DSS_HDMI_COMMON | ||
67 | bool | ||
68 | |||
62 | config OMAP4_DSS_HDMI | 69 | config OMAP4_DSS_HDMI |
63 | bool "HDMI support" | 70 | bool "HDMI support for OMAP4" |
64 | default y | 71 | default y |
72 | select OMAP2_DSS_HDMI_COMMON | ||
65 | help | 73 | help |
66 | HDMI Interface. This adds the High Definition Multimedia Interface. | 74 | HDMI support for OMAP4 based SoCs. |
67 | See http://www.hdmi.org/ for HDMI specification. | ||
68 | 75 | ||
69 | config OMAP4_DSS_HDMI_AUDIO | 76 | config OMAP4_DSS_HDMI_AUDIO |
70 | bool | 77 | bool |
71 | 78 | ||
79 | config OMAP5_DSS_HDMI | ||
80 | bool "HDMI support for OMAP5" | ||
81 | default n | ||
82 | select OMAP2_DSS_HDMI_COMMON | ||
83 | help | ||
84 | HDMI Interface for OMAP5 and similar cores. This adds the High | ||
85 | Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI | ||
86 | specification. | ||
87 | |||
88 | config OMAP5_DSS_HDMI_AUDIO | ||
89 | depends on OMAP5_DSS_HDMI | ||
90 | bool | ||
91 | |||
72 | config OMAP2_DSS_SDI | 92 | config OMAP2_DSS_SDI |
73 | bool "SDI support" | 93 | bool "SDI support" |
74 | default n | 94 | default n |
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile index 8aec8bda27cc..245f933060ee 100644 --- a/drivers/video/fbdev/omap2/dss/Makefile +++ b/drivers/video/fbdev/omap2/dss/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o | ||
1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 2 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
2 | # Core DSS files | 3 | # Core DSS files |
3 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ | 4 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
@@ -10,6 +11,8 @@ omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | |||
10 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o | 11 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o |
11 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o | 12 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o |
12 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o | 13 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o |
13 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi_common.o hdmi_wp.o hdmi_pll.o \ | 14 | omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \ |
14 | hdmi_phy.o hdmi4_core.o | 15 | hdmi_phy.o |
16 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o | ||
17 | omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o | ||
15 | ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG | 18 | ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG |
diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c index ffa45c894cd4..6b74f73fb524 100644 --- a/drivers/video/fbdev/omap2/dss/core.c +++ b/drivers/video/fbdev/omap2/dss/core.c | |||
@@ -268,6 +268,9 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { | |||
268 | #ifdef CONFIG_OMAP4_DSS_HDMI | 268 | #ifdef CONFIG_OMAP4_DSS_HDMI |
269 | hdmi4_init_platform_driver, | 269 | hdmi4_init_platform_driver, |
270 | #endif | 270 | #endif |
271 | #ifdef CONFIG_OMAP5_DSS_HDMI | ||
272 | hdmi5_init_platform_driver, | ||
273 | #endif | ||
271 | }; | 274 | }; |
272 | 275 | ||
273 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | 276 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { |
@@ -289,6 +292,9 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | |||
289 | #ifdef CONFIG_OMAP4_DSS_HDMI | 292 | #ifdef CONFIG_OMAP4_DSS_HDMI |
290 | hdmi4_uninit_platform_driver, | 293 | hdmi4_uninit_platform_driver, |
291 | #endif | 294 | #endif |
295 | #ifdef CONFIG_OMAP5_DSS_HDMI | ||
296 | hdmi5_uninit_platform_driver, | ||
297 | #endif | ||
292 | }; | 298 | }; |
293 | 299 | ||
294 | static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; | 300 | static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; |
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index f18397c33e8f..7aa33b0f4a1f 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c | |||
@@ -2577,9 +2577,9 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | |||
2577 | 2577 | ||
2578 | channel = dispc_ovl_get_channel_out(plane); | 2578 | channel = dispc_ovl_get_channel_out(plane); |
2579 | 2579 | ||
2580 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | 2580 | DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" |
2581 | "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", | 2581 | " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", |
2582 | plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, | 2582 | plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x, |
2583 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, | 2583 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, |
2584 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); | 2584 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); |
2585 | 2585 | ||
@@ -2945,13 +2945,13 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | |||
2945 | BUG(); | 2945 | BUG(); |
2946 | } | 2946 | } |
2947 | 2947 | ||
2948 | l = dispc_read_reg(DISPC_POL_FREQ(channel)); | 2948 | l = FLD_VAL(onoff, 17, 17) | |
2949 | l |= FLD_VAL(onoff, 17, 17); | 2949 | FLD_VAL(rf, 16, 16) | |
2950 | l |= FLD_VAL(rf, 16, 16); | 2950 | FLD_VAL(de_level, 15, 15) | |
2951 | l |= FLD_VAL(de_level, 15, 15); | 2951 | FLD_VAL(ipc, 14, 14) | |
2952 | l |= FLD_VAL(ipc, 14, 14); | 2952 | FLD_VAL(hsync_level, 13, 13) | |
2953 | l |= FLD_VAL(hsync_level, 13, 13); | 2953 | FLD_VAL(vsync_level, 12, 12); |
2954 | l |= FLD_VAL(vsync_level, 12, 12); | 2954 | |
2955 | dispc_write_reg(DISPC_POL_FREQ(channel), l); | 2955 | dispc_write_reg(DISPC_POL_FREQ(channel), l); |
2956 | } | 2956 | } |
2957 | 2957 | ||
@@ -3656,6 +3656,7 @@ static int __init dispc_init_features(struct platform_device *pdev) | |||
3656 | case OMAPDSS_VER_OMAP34xx_ES3: | 3656 | case OMAPDSS_VER_OMAP34xx_ES3: |
3657 | case OMAPDSS_VER_OMAP3630: | 3657 | case OMAPDSS_VER_OMAP3630: |
3658 | case OMAPDSS_VER_AM35xx: | 3658 | case OMAPDSS_VER_AM35xx: |
3659 | case OMAPDSS_VER_AM43xx: | ||
3659 | src = &omap34xx_rev3_0_dispc_feats; | 3660 | src = &omap34xx_rev3_0_dispc_feats; |
3660 | break; | 3661 | break; |
3661 | 3662 | ||
@@ -3829,6 +3830,7 @@ static const struct of_device_id dispc_of_match[] = { | |||
3829 | { .compatible = "ti,omap2-dispc", }, | 3830 | { .compatible = "ti,omap2-dispc", }, |
3830 | { .compatible = "ti,omap3-dispc", }, | 3831 | { .compatible = "ti,omap3-dispc", }, |
3831 | { .compatible = "ti,omap4-dispc", }, | 3832 | { .compatible = "ti,omap4-dispc", }, |
3833 | { .compatible = "ti,omap5-dispc", }, | ||
3832 | {}, | 3834 | {}, |
3833 | }; | 3835 | }; |
3834 | 3836 | ||
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c index 157921db447a..9368972d6962 100644 --- a/drivers/video/fbdev/omap2/dss/dpi.c +++ b/drivers/video/fbdev/omap2/dss/dpi.c | |||
@@ -67,6 +67,7 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | |||
67 | case OMAPDSS_VER_OMAP34xx_ES3: | 67 | case OMAPDSS_VER_OMAP34xx_ES3: |
68 | case OMAPDSS_VER_OMAP3630: | 68 | case OMAPDSS_VER_OMAP3630: |
69 | case OMAPDSS_VER_AM35xx: | 69 | case OMAPDSS_VER_AM35xx: |
70 | case OMAPDSS_VER_AM43xx: | ||
70 | return NULL; | 71 | return NULL; |
71 | 72 | ||
72 | case OMAPDSS_VER_OMAP4430_ES1: | 73 | case OMAPDSS_VER_OMAP4430_ES1: |
@@ -103,6 +104,8 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) | |||
103 | return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; | 104 | return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; |
104 | case OMAP_DSS_CHANNEL_LCD2: | 105 | case OMAP_DSS_CHANNEL_LCD2: |
105 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | 106 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; |
107 | case OMAP_DSS_CHANNEL_LCD3: | ||
108 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | ||
106 | default: | 109 | default: |
107 | /* this shouldn't happen */ | 110 | /* this shouldn't happen */ |
108 | WARN_ON(1); | 111 | WARN_ON(1); |
@@ -595,6 +598,7 @@ static enum omap_channel dpi_get_channel(void) | |||
595 | case OMAPDSS_VER_OMAP34xx_ES3: | 598 | case OMAPDSS_VER_OMAP34xx_ES3: |
596 | case OMAPDSS_VER_OMAP3630: | 599 | case OMAPDSS_VER_OMAP3630: |
597 | case OMAPDSS_VER_AM35xx: | 600 | case OMAPDSS_VER_AM35xx: |
601 | case OMAPDSS_VER_AM43xx: | ||
598 | return OMAP_DSS_CHANNEL_LCD; | 602 | return OMAP_DSS_CHANNEL_LCD; |
599 | 603 | ||
600 | case OMAPDSS_VER_OMAP4430_ES1: | 604 | case OMAPDSS_VER_OMAP4430_ES1: |
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 8be9b04d8849..4755a34a5422 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c | |||
@@ -1161,6 +1161,7 @@ static int dsi_regulator_init(struct platform_device *dsidev) | |||
1161 | { | 1161 | { |
1162 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1162 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1163 | struct regulator *vdds_dsi; | 1163 | struct regulator *vdds_dsi; |
1164 | int r; | ||
1164 | 1165 | ||
1165 | if (dsi->vdds_dsi_reg != NULL) | 1166 | if (dsi->vdds_dsi_reg != NULL) |
1166 | return 0; | 1167 | return 0; |
@@ -1173,6 +1174,15 @@ static int dsi_regulator_init(struct platform_device *dsidev) | |||
1173 | return PTR_ERR(vdds_dsi); | 1174 | return PTR_ERR(vdds_dsi); |
1174 | } | 1175 | } |
1175 | 1176 | ||
1177 | if (regulator_can_change_voltage(vdds_dsi)) { | ||
1178 | r = regulator_set_voltage(vdds_dsi, 1800000, 1800000); | ||
1179 | if (r) { | ||
1180 | devm_regulator_put(vdds_dsi); | ||
1181 | DSSERR("can't set the DSI regulator voltage\n"); | ||
1182 | return r; | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1176 | dsi->vdds_dsi_reg = vdds_dsi; | 1186 | dsi->vdds_dsi_reg = vdds_dsi; |
1177 | 1187 | ||
1178 | return 0; | 1188 | return 0; |
@@ -5122,6 +5132,7 @@ static enum omap_channel dsi_get_channel(int module_id) | |||
5122 | { | 5132 | { |
5123 | switch (omapdss_get_version()) { | 5133 | switch (omapdss_get_version()) { |
5124 | case OMAPDSS_VER_OMAP24xx: | 5134 | case OMAPDSS_VER_OMAP24xx: |
5135 | case OMAPDSS_VER_AM43xx: | ||
5125 | DSSWARN("DSI not supported\n"); | 5136 | DSSWARN("DSI not supported\n"); |
5126 | return OMAP_DSS_CHANNEL_LCD; | 5137 | return OMAP_DSS_CHANNEL_LCD; |
5127 | 5138 | ||
@@ -5723,9 +5734,16 @@ static const struct dsi_module_id_data dsi_of_data_omap4[] = { | |||
5723 | { }, | 5734 | { }, |
5724 | }; | 5735 | }; |
5725 | 5736 | ||
5737 | static const struct dsi_module_id_data dsi_of_data_omap5[] = { | ||
5738 | { .address = 0x58004000, .id = 0, }, | ||
5739 | { .address = 0x58009000, .id = 1, }, | ||
5740 | { }, | ||
5741 | }; | ||
5742 | |||
5726 | static const struct of_device_id dsi_of_match[] = { | 5743 | static const struct of_device_id dsi_of_match[] = { |
5727 | { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, }, | 5744 | { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, }, |
5728 | { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, }, | 5745 | { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, }, |
5746 | { .compatible = "ti,omap5-dsi", .data = dsi_of_data_omap5, }, | ||
5729 | {}, | 5747 | {}, |
5730 | }; | 5748 | }; |
5731 | 5749 | ||
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c index d55266c0e029..6daeb7ed44c6 100644 --- a/drivers/video/fbdev/omap2/dss/dss.c +++ b/drivers/video/fbdev/omap2/dss/dss.c | |||
@@ -728,6 +728,13 @@ static const struct dss_features omap54xx_dss_feats __initconst = { | |||
728 | .dpi_select_source = &dss_dpi_select_source_omap5, | 728 | .dpi_select_source = &dss_dpi_select_source_omap5, |
729 | }; | 729 | }; |
730 | 730 | ||
731 | static const struct dss_features am43xx_dss_feats __initconst = { | ||
732 | .fck_div_max = 0, | ||
733 | .dss_fck_multiplier = 0, | ||
734 | .parent_clk_name = NULL, | ||
735 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
736 | }; | ||
737 | |||
731 | static int __init dss_init_features(struct platform_device *pdev) | 738 | static int __init dss_init_features(struct platform_device *pdev) |
732 | { | 739 | { |
733 | const struct dss_features *src; | 740 | const struct dss_features *src; |
@@ -764,6 +771,10 @@ static int __init dss_init_features(struct platform_device *pdev) | |||
764 | src = &omap54xx_dss_feats; | 771 | src = &omap54xx_dss_feats; |
765 | break; | 772 | break; |
766 | 773 | ||
774 | case OMAPDSS_VER_AM43xx: | ||
775 | src = &am43xx_dss_feats; | ||
776 | break; | ||
777 | |||
767 | default: | 778 | default: |
768 | return -ENODEV; | 779 | return -ENODEV; |
769 | } | 780 | } |
@@ -784,12 +795,8 @@ static int __init dss_init_ports(struct platform_device *pdev) | |||
784 | return 0; | 795 | return 0; |
785 | 796 | ||
786 | port = omapdss_of_get_next_port(parent, NULL); | 797 | port = omapdss_of_get_next_port(parent, NULL); |
787 | if (!port) { | 798 | if (!port) |
788 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
789 | dpi_init_port(pdev, parent); | ||
790 | #endif | ||
791 | return 0; | 799 | return 0; |
792 | } | ||
793 | 800 | ||
794 | do { | 801 | do { |
795 | u32 reg; | 802 | u32 reg; |
@@ -813,7 +820,7 @@ static int __init dss_init_ports(struct platform_device *pdev) | |||
813 | return 0; | 820 | return 0; |
814 | } | 821 | } |
815 | 822 | ||
816 | static void dss_uninit_ports(void) | 823 | static void __exit dss_uninit_ports(void) |
817 | { | 824 | { |
818 | #ifdef CONFIG_OMAP2_DSS_DPI | 825 | #ifdef CONFIG_OMAP2_DSS_DPI |
819 | dpi_uninit_port(); | 826 | dpi_uninit_port(); |
@@ -946,6 +953,7 @@ static const struct of_device_id dss_of_match[] = { | |||
946 | { .compatible = "ti,omap2-dss", }, | 953 | { .compatible = "ti,omap2-dss", }, |
947 | { .compatible = "ti,omap3-dss", }, | 954 | { .compatible = "ti,omap3-dss", }, |
948 | { .compatible = "ti,omap4-dss", }, | 955 | { .compatible = "ti,omap4-dss", }, |
956 | { .compatible = "ti,omap5-dss", }, | ||
949 | {}, | 957 | {}, |
950 | }; | 958 | }; |
951 | 959 | ||
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h index 560078fcb198..8ff22c134c62 100644 --- a/drivers/video/fbdev/omap2/dss/dss.h +++ b/drivers/video/fbdev/omap2/dss/dss.h | |||
@@ -419,6 +419,9 @@ void venc_uninit_platform_driver(void) __exit; | |||
419 | int hdmi4_init_platform_driver(void) __init; | 419 | int hdmi4_init_platform_driver(void) __init; |
420 | void hdmi4_uninit_platform_driver(void) __exit; | 420 | void hdmi4_uninit_platform_driver(void) __exit; |
421 | 421 | ||
422 | int hdmi5_init_platform_driver(void) __init; | ||
423 | void hdmi5_uninit_platform_driver(void) __exit; | ||
424 | |||
422 | /* RFBI */ | 425 | /* RFBI */ |
423 | int rfbi_init_platform_driver(void) __init; | 426 | int rfbi_init_platform_driver(void) __init; |
424 | void rfbi_uninit_platform_driver(void) __exit; | 427 | void rfbi_uninit_platform_driver(void) __exit; |
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c index 7f8969191dc6..15088df7bd16 100644 --- a/drivers/video/fbdev/omap2/dss/dss_features.c +++ b/drivers/video/fbdev/omap2/dss/dss_features.c | |||
@@ -93,6 +93,17 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { | |||
93 | [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 }, | 93 | [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 }, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static const struct dss_reg_field am43xx_dss_reg_fields[] = { | ||
97 | [FEAT_REG_FIRHINC] = { 12, 0 }, | ||
98 | [FEAT_REG_FIRVINC] = { 28, 16 }, | ||
99 | [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, | ||
100 | [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, | ||
101 | [FEAT_REG_FIFOSIZE] = { 10, 0 }, | ||
102 | [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, | ||
103 | [FEAT_REG_VERTICALACCU] = { 25, 16 }, | ||
104 | [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, | ||
105 | }; | ||
106 | |||
96 | static const struct dss_reg_field omap4_dss_reg_fields[] = { | 107 | static const struct dss_reg_field omap4_dss_reg_fields[] = { |
97 | [FEAT_REG_FIRHINC] = { 12, 0 }, | 108 | [FEAT_REG_FIRHINC] = { 12, 0 }, |
98 | [FEAT_REG_FIRVINC] = { 28, 16 }, | 109 | [FEAT_REG_FIRVINC] = { 28, 16 }, |
@@ -149,6 +160,11 @@ static const enum omap_display_type omap3630_dss_supported_displays[] = { | |||
149 | OMAP_DISPLAY_TYPE_VENC, | 160 | OMAP_DISPLAY_TYPE_VENC, |
150 | }; | 161 | }; |
151 | 162 | ||
163 | static const enum omap_display_type am43xx_dss_supported_displays[] = { | ||
164 | /* OMAP_DSS_CHANNEL_LCD */ | ||
165 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, | ||
166 | }; | ||
167 | |||
152 | static const enum omap_display_type omap4_dss_supported_displays[] = { | 168 | static const enum omap_display_type omap4_dss_supported_displays[] = { |
153 | /* OMAP_DSS_CHANNEL_LCD */ | 169 | /* OMAP_DSS_CHANNEL_LCD */ |
154 | OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, | 170 | OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, |
@@ -200,6 +216,11 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { | |||
200 | OMAP_DSS_OUTPUT_VENC, | 216 | OMAP_DSS_OUTPUT_VENC, |
201 | }; | 217 | }; |
202 | 218 | ||
219 | static const enum omap_dss_output_id am43xx_dss_supported_outputs[] = { | ||
220 | /* OMAP_DSS_CHANNEL_LCD */ | ||
221 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, | ||
222 | }; | ||
223 | |||
203 | static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { | 224 | static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { |
204 | /* OMAP_DSS_CHANNEL_LCD */ | 225 | /* OMAP_DSS_CHANNEL_LCD */ |
205 | OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1, | 226 | OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1, |
@@ -444,6 +465,13 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
444 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | 465 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, |
445 | }; | 466 | }; |
446 | 467 | ||
468 | static const struct dss_param_range am43xx_dss_param_range[] = { | ||
469 | [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, | ||
470 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, | ||
471 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | ||
472 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | ||
473 | }; | ||
474 | |||
447 | static const struct dss_param_range omap4_dss_param_range[] = { | 475 | static const struct dss_param_range omap4_dss_param_range[] = { |
448 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, | 476 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, |
449 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | 477 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, |
@@ -520,6 +548,21 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = { | |||
520 | FEAT_OMAP3_DSI_FIFO_BUG, | 548 | FEAT_OMAP3_DSI_FIFO_BUG, |
521 | }; | 549 | }; |
522 | 550 | ||
551 | static const enum dss_feat_id am43xx_dss_feat_list[] = { | ||
552 | FEAT_LCDENABLEPOL, | ||
553 | FEAT_LCDENABLESIGNAL, | ||
554 | FEAT_PCKFREEENABLE, | ||
555 | FEAT_FUNCGATED, | ||
556 | FEAT_LINEBUFFERSPLIT, | ||
557 | FEAT_ROWREPEATENABLE, | ||
558 | FEAT_RESIZECONF, | ||
559 | FEAT_CPR, | ||
560 | FEAT_PRELOAD, | ||
561 | FEAT_FIR_COEF_V, | ||
562 | FEAT_ALPHA_FIXED_ZORDER, | ||
563 | FEAT_FIFO_MERGE, | ||
564 | }; | ||
565 | |||
523 | static const enum dss_feat_id omap3630_dss_feat_list[] = { | 566 | static const enum dss_feat_id omap3630_dss_feat_list[] = { |
524 | FEAT_LCDENABLEPOL, | 567 | FEAT_LCDENABLEPOL, |
525 | FEAT_LCDENABLESIGNAL, | 568 | FEAT_LCDENABLESIGNAL, |
@@ -595,6 +638,7 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { | |||
595 | 638 | ||
596 | static const enum dss_feat_id omap5_dss_feat_list[] = { | 639 | static const enum dss_feat_id omap5_dss_feat_list[] = { |
597 | FEAT_MGR_LCD2, | 640 | FEAT_MGR_LCD2, |
641 | FEAT_MGR_LCD3, | ||
598 | FEAT_CORE_CLK_DIV, | 642 | FEAT_CORE_CLK_DIV, |
599 | FEAT_LCD_CLK_SRC, | 643 | FEAT_LCD_CLK_SRC, |
600 | FEAT_DSI_DCS_CMD_CONFIG_VC, | 644 | FEAT_DSI_DCS_CMD_CONFIG_VC, |
@@ -682,6 +726,26 @@ static const struct omap_dss_features am35xx_dss_features = { | |||
682 | .burst_size_unit = 8, | 726 | .burst_size_unit = 8, |
683 | }; | 727 | }; |
684 | 728 | ||
729 | static const struct omap_dss_features am43xx_dss_features = { | ||
730 | .reg_fields = am43xx_dss_reg_fields, | ||
731 | .num_reg_fields = ARRAY_SIZE(am43xx_dss_reg_fields), | ||
732 | |||
733 | .features = am43xx_dss_feat_list, | ||
734 | .num_features = ARRAY_SIZE(am43xx_dss_feat_list), | ||
735 | |||
736 | .num_mgrs = 1, | ||
737 | .num_ovls = 3, | ||
738 | .supported_displays = am43xx_dss_supported_displays, | ||
739 | .supported_outputs = am43xx_dss_supported_outputs, | ||
740 | .supported_color_modes = omap3_dss_supported_color_modes, | ||
741 | .overlay_caps = omap3430_dss_overlay_caps, | ||
742 | .clksrc_names = omap2_dss_clk_source_names, | ||
743 | .dss_params = am43xx_dss_param_range, | ||
744 | .supported_rotation_types = OMAP_DSS_ROT_DMA, | ||
745 | .buffer_size_unit = 1, | ||
746 | .burst_size_unit = 8, | ||
747 | }; | ||
748 | |||
685 | static const struct omap_dss_features omap3630_dss_features = { | 749 | static const struct omap_dss_features omap3630_dss_features = { |
686 | .reg_fields = omap3_dss_reg_fields, | 750 | .reg_fields = omap3_dss_reg_fields, |
687 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | 751 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), |
@@ -777,7 +841,7 @@ static const struct omap_dss_features omap5_dss_features = { | |||
777 | .features = omap5_dss_feat_list, | 841 | .features = omap5_dss_feat_list, |
778 | .num_features = ARRAY_SIZE(omap5_dss_feat_list), | 842 | .num_features = ARRAY_SIZE(omap5_dss_feat_list), |
779 | 843 | ||
780 | .num_mgrs = 3, | 844 | .num_mgrs = 4, |
781 | .num_ovls = 4, | 845 | .num_ovls = 4, |
782 | .supported_displays = omap5_dss_supported_displays, | 846 | .supported_displays = omap5_dss_supported_displays, |
783 | .supported_outputs = omap5_dss_supported_outputs, | 847 | .supported_outputs = omap5_dss_supported_outputs, |
@@ -928,6 +992,10 @@ void dss_features_init(enum omapdss_version version) | |||
928 | omap_current_dss_features = &am35xx_dss_features; | 992 | omap_current_dss_features = &am35xx_dss_features; |
929 | break; | 993 | break; |
930 | 994 | ||
995 | case OMAPDSS_VER_AM43xx: | ||
996 | omap_current_dss_features = &am43xx_dss_features; | ||
997 | break; | ||
998 | |||
931 | default: | 999 | default: |
932 | DSSWARN("Unsupported OMAP version"); | 1000 | DSSWARN("Unsupported OMAP version"); |
933 | break; | 1001 | break; |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index e25681ff5a70..fbee07816337 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h | |||
@@ -80,6 +80,7 @@ | |||
80 | #define HDMI_TXPHY_DIGITAL_CTRL 0x4 | 80 | #define HDMI_TXPHY_DIGITAL_CTRL 0x4 |
81 | #define HDMI_TXPHY_POWER_CTRL 0x8 | 81 | #define HDMI_TXPHY_POWER_CTRL 0x8 |
82 | #define HDMI_TXPHY_PAD_CFG_CTRL 0xC | 82 | #define HDMI_TXPHY_PAD_CFG_CTRL 0xC |
83 | #define HDMI_TXPHY_BIST_CONTROL 0x1C | ||
83 | 84 | ||
84 | enum hdmi_pll_pwr { | 85 | enum hdmi_pll_pwr { |
85 | HDMI_PLLPWRCMD_ALLOFF = 0, | 86 | HDMI_PLLPWRCMD_ALLOFF = 0, |
@@ -351,7 +352,8 @@ struct hdmi_pll_data { | |||
351 | struct hdmi_phy_data { | 352 | struct hdmi_phy_data { |
352 | void __iomem *base; | 353 | void __iomem *base; |
353 | 354 | ||
354 | int irq; | 355 | u8 lane_function[4]; |
356 | u8 lane_polarity[4]; | ||
355 | }; | 357 | }; |
356 | 358 | ||
357 | struct hdmi_core_data { | 359 | struct hdmi_core_data { |
@@ -360,13 +362,13 @@ struct hdmi_core_data { | |||
360 | struct hdmi_core_infoframe_avi avi_cfg; | 362 | struct hdmi_core_infoframe_avi avi_cfg; |
361 | }; | 363 | }; |
362 | 364 | ||
363 | static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx, | 365 | static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx, |
364 | u32 val) | 366 | u32 val) |
365 | { | 367 | { |
366 | __raw_writel(val, base_addr + idx); | 368 | __raw_writel(val, base_addr + idx); |
367 | } | 369 | } |
368 | 370 | ||
369 | static inline u32 hdmi_read_reg(void __iomem *base_addr, const u16 idx) | 371 | static inline u32 hdmi_read_reg(void __iomem *base_addr, const u32 idx) |
370 | { | 372 | { |
371 | return __raw_readl(base_addr + idx); | 373 | return __raw_readl(base_addr + idx); |
372 | } | 374 | } |
@@ -417,18 +419,19 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy); | |||
417 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); | 419 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); |
418 | 420 | ||
419 | /* HDMI PHY funcs */ | 421 | /* HDMI PHY funcs */ |
420 | int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp, | 422 | int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg); |
421 | struct hdmi_config *cfg); | ||
422 | void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp); | ||
423 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); | 423 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); |
424 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); | 424 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); |
425 | int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); | ||
425 | 426 | ||
426 | /* HDMI common funcs */ | 427 | /* HDMI common funcs */ |
427 | const struct hdmi_config *hdmi_default_timing(void); | 428 | const struct hdmi_config *hdmi_default_timing(void); |
428 | const struct hdmi_config *hdmi_get_timings(int mode, int code); | 429 | const struct hdmi_config *hdmi_get_timings(int mode, int code); |
429 | struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing); | 430 | struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing); |
431 | int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, | ||
432 | struct hdmi_phy_data *phy); | ||
430 | 433 | ||
431 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 434 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) |
432 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts); | 435 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts); |
433 | int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable); | 436 | int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable); |
434 | int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable); | 437 | int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable); |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index f5f7944a1fd1..626aad2bef46 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c | |||
@@ -81,8 +81,40 @@ static void hdmi_runtime_put(void) | |||
81 | WARN_ON(r < 0 && r != -ENOSYS); | 81 | WARN_ON(r < 0 && r != -ENOSYS); |
82 | } | 82 | } |
83 | 83 | ||
84 | static irqreturn_t hdmi_irq_handler(int irq, void *data) | ||
85 | { | ||
86 | struct hdmi_wp_data *wp = data; | ||
87 | u32 irqstatus; | ||
88 | |||
89 | irqstatus = hdmi_wp_get_irqstatus(wp); | ||
90 | hdmi_wp_set_irqstatus(wp, irqstatus); | ||
91 | |||
92 | if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && | ||
93 | irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | ||
94 | /* | ||
95 | * If we get both connect and disconnect interrupts at the same | ||
96 | * time, turn off the PHY, clear interrupts, and restart, which | ||
97 | * raises connect interrupt if a cable is connected, or nothing | ||
98 | * if cable is not connected. | ||
99 | */ | ||
100 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); | ||
101 | |||
102 | hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | | ||
103 | HDMI_IRQ_LINK_DISCONNECT); | ||
104 | |||
105 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | ||
106 | } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { | ||
107 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); | ||
108 | } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | ||
109 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | ||
110 | } | ||
111 | |||
112 | return IRQ_HANDLED; | ||
113 | } | ||
114 | |||
84 | static int hdmi_init_regulator(void) | 115 | static int hdmi_init_regulator(void) |
85 | { | 116 | { |
117 | int r; | ||
86 | struct regulator *reg; | 118 | struct regulator *reg; |
87 | 119 | ||
88 | if (hdmi.vdda_hdmi_dac_reg != NULL) | 120 | if (hdmi.vdda_hdmi_dac_reg != NULL) |
@@ -96,6 +128,15 @@ static int hdmi_init_regulator(void) | |||
96 | return PTR_ERR(reg); | 128 | return PTR_ERR(reg); |
97 | } | 129 | } |
98 | 130 | ||
131 | if (regulator_can_change_voltage(reg)) { | ||
132 | r = regulator_set_voltage(reg, 1800000, 1800000); | ||
133 | if (r) { | ||
134 | devm_regulator_put(reg); | ||
135 | DSSWARN("can't set the regulator voltage\n"); | ||
136 | return r; | ||
137 | } | ||
138 | } | ||
139 | |||
99 | hdmi.vdda_hdmi_dac_reg = reg; | 140 | hdmi.vdda_hdmi_dac_reg = reg; |
100 | 141 | ||
101 | return 0; | 142 | return 0; |
@@ -140,11 +181,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
140 | struct omap_video_timings *p; | 181 | struct omap_video_timings *p; |
141 | struct omap_overlay_manager *mgr = hdmi.output.manager; | 182 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
142 | unsigned long phy; | 183 | unsigned long phy; |
184 | struct hdmi_wp_data *wp = &hdmi.wp; | ||
143 | 185 | ||
144 | r = hdmi_power_on_core(dssdev); | 186 | r = hdmi_power_on_core(dssdev); |
145 | if (r) | 187 | if (r) |
146 | return r; | 188 | return r; |
147 | 189 | ||
190 | /* disable and clear irqs */ | ||
191 | hdmi_wp_clear_irqenable(wp, 0xffffffff); | ||
192 | hdmi_wp_set_irqstatus(wp, 0xffffffff); | ||
193 | |||
148 | p = &hdmi.cfg.timings; | 194 | p = &hdmi.cfg.timings; |
149 | 195 | ||
150 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); | 196 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); |
@@ -161,12 +207,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
161 | goto err_pll_enable; | 207 | goto err_pll_enable; |
162 | } | 208 | } |
163 | 209 | ||
164 | r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg); | 210 | r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); |
165 | if (r) { | 211 | if (r) { |
166 | DSSDBG("Failed to start PHY\n"); | 212 | DSSDBG("Failed to configure PHY\n"); |
167 | goto err_phy_enable; | 213 | goto err_phy_cfg; |
168 | } | 214 | } |
169 | 215 | ||
216 | r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | ||
217 | if (r) | ||
218 | goto err_phy_pwr; | ||
219 | |||
170 | hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); | 220 | hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); |
171 | 221 | ||
172 | /* bypass TV gamma table */ | 222 | /* bypass TV gamma table */ |
@@ -183,13 +233,17 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
183 | if (r) | 233 | if (r) |
184 | goto err_mgr_enable; | 234 | goto err_mgr_enable; |
185 | 235 | ||
236 | hdmi_wp_set_irqenable(wp, | ||
237 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); | ||
238 | |||
186 | return 0; | 239 | return 0; |
187 | 240 | ||
188 | err_mgr_enable: | 241 | err_mgr_enable: |
189 | hdmi_wp_video_stop(&hdmi.wp); | 242 | hdmi_wp_video_stop(&hdmi.wp); |
190 | err_vid_enable: | 243 | err_vid_enable: |
191 | hdmi_phy_disable(&hdmi.phy, &hdmi.wp); | 244 | err_phy_cfg: |
192 | err_phy_enable: | 245 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
246 | err_phy_pwr: | ||
193 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 247 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); |
194 | err_pll_enable: | 248 | err_pll_enable: |
195 | hdmi_power_off_core(dssdev); | 249 | hdmi_power_off_core(dssdev); |
@@ -200,10 +254,14 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) | |||
200 | { | 254 | { |
201 | struct omap_overlay_manager *mgr = hdmi.output.manager; | 255 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
202 | 256 | ||
257 | hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); | ||
258 | |||
203 | dss_mgr_disable(mgr); | 259 | dss_mgr_disable(mgr); |
204 | 260 | ||
205 | hdmi_wp_video_stop(&hdmi.wp); | 261 | hdmi_wp_video_stop(&hdmi.wp); |
206 | hdmi_phy_disable(&hdmi.phy, &hdmi.wp); | 262 | |
263 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | ||
264 | |||
207 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 265 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); |
208 | 266 | ||
209 | hdmi_power_off_core(dssdev); | 267 | hdmi_power_off_core(dssdev); |
@@ -600,15 +658,44 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) | |||
600 | omapdss_unregister_output(out); | 658 | omapdss_unregister_output(out); |
601 | } | 659 | } |
602 | 660 | ||
661 | static int hdmi_probe_of(struct platform_device *pdev) | ||
662 | { | ||
663 | struct device_node *node = pdev->dev.of_node; | ||
664 | struct device_node *ep; | ||
665 | int r; | ||
666 | |||
667 | ep = omapdss_of_get_first_endpoint(node); | ||
668 | if (!ep) | ||
669 | return 0; | ||
670 | |||
671 | r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); | ||
672 | if (r) | ||
673 | goto err; | ||
674 | |||
675 | of_node_put(ep); | ||
676 | return 0; | ||
677 | |||
678 | err: | ||
679 | of_node_put(ep); | ||
680 | return r; | ||
681 | } | ||
682 | |||
603 | /* HDMI HW IP initialisation */ | 683 | /* HDMI HW IP initialisation */ |
604 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | 684 | static int omapdss_hdmihw_probe(struct platform_device *pdev) |
605 | { | 685 | { |
606 | int r; | 686 | int r; |
687 | int irq; | ||
607 | 688 | ||
608 | hdmi.pdev = pdev; | 689 | hdmi.pdev = pdev; |
609 | 690 | ||
610 | mutex_init(&hdmi.lock); | 691 | mutex_init(&hdmi.lock); |
611 | 692 | ||
693 | if (pdev->dev.of_node) { | ||
694 | r = hdmi_probe_of(pdev); | ||
695 | if (r) | ||
696 | return r; | ||
697 | } | ||
698 | |||
612 | r = hdmi_wp_init(pdev, &hdmi.wp); | 699 | r = hdmi_wp_init(pdev, &hdmi.wp); |
613 | if (r) | 700 | if (r) |
614 | return r; | 701 | return r; |
@@ -631,6 +718,20 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
631 | return r; | 718 | return r; |
632 | } | 719 | } |
633 | 720 | ||
721 | irq = platform_get_irq(pdev, 0); | ||
722 | if (irq < 0) { | ||
723 | DSSERR("platform_get_irq failed\n"); | ||
724 | return -ENODEV; | ||
725 | } | ||
726 | |||
727 | r = devm_request_threaded_irq(&pdev->dev, irq, | ||
728 | NULL, hdmi_irq_handler, | ||
729 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); | ||
730 | if (r) { | ||
731 | DSSERR("HDMI IRQ request failed\n"); | ||
732 | return r; | ||
733 | } | ||
734 | |||
634 | pm_runtime_enable(&pdev->dev); | 735 | pm_runtime_enable(&pdev->dev); |
635 | 736 | ||
636 | hdmi_init_output(pdev); | 737 | hdmi_init_output(pdev); |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 2eb04dcf807c..8bde7b7e95ff 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c | |||
@@ -998,38 +998,20 @@ int hdmi4_audio_get_dma_port(u32 *offset, u32 *size) | |||
998 | 998 | ||
999 | #endif | 999 | #endif |
1000 | 1000 | ||
1001 | #define CORE_OFFSET 0x400 | ||
1002 | #define CORE_SIZE 0xc00 | ||
1003 | |||
1004 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) | 1001 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) |
1005 | { | 1002 | { |
1006 | struct resource *res; | 1003 | struct resource *res; |
1007 | struct resource temp_res; | ||
1008 | 1004 | ||
1009 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); | 1005 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); |
1010 | if (!res) { | 1006 | if (!res) { |
1011 | DSSDBG("can't get CORE mem resource by name\n"); | 1007 | DSSERR("can't get CORE mem resource\n"); |
1012 | /* | 1008 | return -EINVAL; |
1013 | * if hwmod/DT doesn't have the memory resource information | ||
1014 | * split into HDMI sub blocks by name, we try again by getting | ||
1015 | * the platform's first resource. this code will be removed when | ||
1016 | * the driver can get the mem resources by name | ||
1017 | */ | ||
1018 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1019 | if (!res) { | ||
1020 | DSSERR("can't get CORE mem resource\n"); | ||
1021 | return -EINVAL; | ||
1022 | } | ||
1023 | |||
1024 | temp_res.start = res->start + CORE_OFFSET; | ||
1025 | temp_res.end = temp_res.start + CORE_SIZE - 1; | ||
1026 | res = &temp_res; | ||
1027 | } | 1009 | } |
1028 | 1010 | ||
1029 | core->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | 1011 | core->base = devm_ioremap_resource(&pdev->dev, res); |
1030 | if (!core->base) { | 1012 | if (IS_ERR(core->base)) { |
1031 | DSSERR("can't ioremap CORE\n"); | 1013 | DSSERR("can't ioremap CORE\n"); |
1032 | return -ENOMEM; | 1014 | return PTR_ERR(core->base); |
1033 | } | 1015 | } |
1034 | 1016 | ||
1035 | return 0; | 1017 | return 0; |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c new file mode 100644 index 000000000000..c468b9e1f295 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c | |||
@@ -0,0 +1,829 @@ | |||
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 <video/omapdss.h> | ||
41 | |||
42 | #include "hdmi5_core.h" | ||
43 | #include "dss.h" | ||
44 | #include "dss_features.h" | ||
45 | |||
46 | static struct { | ||
47 | struct mutex lock; | ||
48 | struct platform_device *pdev; | ||
49 | |||
50 | struct hdmi_wp_data wp; | ||
51 | struct hdmi_pll_data pll; | ||
52 | struct hdmi_phy_data phy; | ||
53 | struct hdmi_core_data core; | ||
54 | |||
55 | struct hdmi_config cfg; | ||
56 | |||
57 | struct clk *sys_clk; | ||
58 | struct regulator *vdda_reg; | ||
59 | |||
60 | bool core_enabled; | ||
61 | |||
62 | struct omap_dss_device output; | ||
63 | } hdmi; | ||
64 | |||
65 | static int hdmi_runtime_get(void) | ||
66 | { | ||
67 | int r; | ||
68 | |||
69 | DSSDBG("hdmi_runtime_get\n"); | ||
70 | |||
71 | r = pm_runtime_get_sync(&hdmi.pdev->dev); | ||
72 | WARN_ON(r < 0); | ||
73 | if (r < 0) | ||
74 | return r; | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static void hdmi_runtime_put(void) | ||
80 | { | ||
81 | int r; | ||
82 | |||
83 | DSSDBG("hdmi_runtime_put\n"); | ||
84 | |||
85 | r = pm_runtime_put_sync(&hdmi.pdev->dev); | ||
86 | WARN_ON(r < 0 && r != -ENOSYS); | ||
87 | } | ||
88 | |||
89 | static irqreturn_t hdmi_irq_handler(int irq, void *data) | ||
90 | { | ||
91 | struct hdmi_wp_data *wp = data; | ||
92 | u32 irqstatus; | ||
93 | |||
94 | irqstatus = hdmi_wp_get_irqstatus(wp); | ||
95 | hdmi_wp_set_irqstatus(wp, irqstatus); | ||
96 | |||
97 | if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && | ||
98 | irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | ||
99 | u32 v; | ||
100 | /* | ||
101 | * If we get both connect and disconnect interrupts at the same | ||
102 | * time, turn off the PHY, clear interrupts, and restart, which | ||
103 | * raises connect interrupt if a cable is connected, or nothing | ||
104 | * if cable is not connected. | ||
105 | */ | ||
106 | |||
107 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); | ||
108 | |||
109 | /* | ||
110 | * We always get bogus CONNECT & DISCONNECT interrupts when | ||
111 | * setting the PHY to LDOON. To ignore those, we force the RXDET | ||
112 | * line to 0 until the PHY power state has been changed. | ||
113 | */ | ||
114 | v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL); | ||
115 | v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */ | ||
116 | v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */ | ||
117 | hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); | ||
118 | |||
119 | hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | | ||
120 | HDMI_IRQ_LINK_DISCONNECT); | ||
121 | |||
122 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | ||
123 | |||
124 | REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); | ||
125 | |||
126 | } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { | ||
127 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); | ||
128 | } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | ||
129 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | ||
130 | } | ||
131 | |||
132 | return IRQ_HANDLED; | ||
133 | } | ||
134 | |||
135 | static int hdmi_init_regulator(void) | ||
136 | { | ||
137 | int r; | ||
138 | struct regulator *reg; | ||
139 | |||
140 | if (hdmi.vdda_reg != NULL) | ||
141 | return 0; | ||
142 | |||
143 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); | ||
144 | if (IS_ERR(reg)) { | ||
145 | DSSERR("can't get VDDA regulator\n"); | ||
146 | return PTR_ERR(reg); | ||
147 | } | ||
148 | |||
149 | if (regulator_can_change_voltage(reg)) { | ||
150 | r = regulator_set_voltage(reg, 1800000, 1800000); | ||
151 | if (r) { | ||
152 | devm_regulator_put(reg); | ||
153 | DSSWARN("can't set the regulator voltage\n"); | ||
154 | return r; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | hdmi.vdda_reg = reg; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int hdmi_power_on_core(struct omap_dss_device *dssdev) | ||
164 | { | ||
165 | int r; | ||
166 | |||
167 | r = regulator_enable(hdmi.vdda_reg); | ||
168 | if (r) | ||
169 | return r; | ||
170 | |||
171 | r = hdmi_runtime_get(); | ||
172 | if (r) | ||
173 | goto err_runtime_get; | ||
174 | |||
175 | /* Make selection of HDMI in DSS */ | ||
176 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
177 | |||
178 | hdmi.core_enabled = true; | ||
179 | |||
180 | return 0; | ||
181 | |||
182 | err_runtime_get: | ||
183 | regulator_disable(hdmi.vdda_reg); | ||
184 | |||
185 | return r; | ||
186 | } | ||
187 | |||
188 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) | ||
189 | { | ||
190 | hdmi.core_enabled = false; | ||
191 | |||
192 | hdmi_runtime_put(); | ||
193 | regulator_disable(hdmi.vdda_reg); | ||
194 | } | ||
195 | |||
196 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | ||
197 | { | ||
198 | int r; | ||
199 | struct omap_video_timings *p; | ||
200 | struct omap_overlay_manager *mgr = hdmi.output.manager; | ||
201 | unsigned long phy; | ||
202 | |||
203 | r = hdmi_power_on_core(dssdev); | ||
204 | if (r) | ||
205 | return r; | ||
206 | |||
207 | p = &hdmi.cfg.timings; | ||
208 | |||
209 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); | ||
210 | |||
211 | /* the functions below use kHz pixel clock. TODO: change to Hz */ | ||
212 | phy = p->pixelclock / 1000; | ||
213 | |||
214 | hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy); | ||
215 | |||
216 | /* disable and clear irqs */ | ||
217 | hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); | ||
218 | hdmi_wp_set_irqstatus(&hdmi.wp, | ||
219 | hdmi_wp_get_irqstatus(&hdmi.wp)); | ||
220 | |||
221 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | ||
222 | r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp); | ||
223 | if (r) { | ||
224 | DSSDBG("Failed to lock PLL\n"); | ||
225 | goto err_pll_enable; | ||
226 | } | ||
227 | |||
228 | r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); | ||
229 | if (r) { | ||
230 | DSSDBG("Failed to start PHY\n"); | ||
231 | goto err_phy_cfg; | ||
232 | } | ||
233 | |||
234 | r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON); | ||
235 | if (r) | ||
236 | goto err_phy_pwr; | ||
237 | |||
238 | hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); | ||
239 | |||
240 | /* bypass TV gamma table */ | ||
241 | dispc_enable_gamma_table(0); | ||
242 | |||
243 | /* tv size */ | ||
244 | dss_mgr_set_timings(mgr, p); | ||
245 | |||
246 | r = hdmi_wp_video_start(&hdmi.wp); | ||
247 | if (r) | ||
248 | goto err_vid_enable; | ||
249 | |||
250 | r = dss_mgr_enable(mgr); | ||
251 | if (r) | ||
252 | goto err_mgr_enable; | ||
253 | |||
254 | hdmi_wp_set_irqenable(&hdmi.wp, | ||
255 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); | ||
256 | |||
257 | return 0; | ||
258 | |||
259 | err_mgr_enable: | ||
260 | hdmi_wp_video_stop(&hdmi.wp); | ||
261 | err_vid_enable: | ||
262 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | ||
263 | err_phy_pwr: | ||
264 | err_phy_cfg: | ||
265 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | ||
266 | err_pll_enable: | ||
267 | hdmi_power_off_core(dssdev); | ||
268 | return -EIO; | ||
269 | } | ||
270 | |||
271 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) | ||
272 | { | ||
273 | struct omap_overlay_manager *mgr = hdmi.output.manager; | ||
274 | |||
275 | hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); | ||
276 | |||
277 | dss_mgr_disable(mgr); | ||
278 | |||
279 | hdmi_wp_video_stop(&hdmi.wp); | ||
280 | |||
281 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | ||
282 | |||
283 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | ||
284 | |||
285 | hdmi_power_off_core(dssdev); | ||
286 | } | ||
287 | |||
288 | static int hdmi_display_check_timing(struct omap_dss_device *dssdev, | ||
289 | struct omap_video_timings *timings) | ||
290 | { | ||
291 | struct omap_dss_device *out = &hdmi.output; | ||
292 | |||
293 | if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) | ||
294 | return -EINVAL; | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void hdmi_display_set_timing(struct omap_dss_device *dssdev, | ||
300 | struct omap_video_timings *timings) | ||
301 | { | ||
302 | struct hdmi_cm cm; | ||
303 | const struct hdmi_config *t; | ||
304 | |||
305 | mutex_lock(&hdmi.lock); | ||
306 | |||
307 | cm = hdmi_get_code(timings); | ||
308 | hdmi.cfg.cm = cm; | ||
309 | |||
310 | t = hdmi_get_timings(cm.mode, cm.code); | ||
311 | if (t != NULL) { | ||
312 | hdmi.cfg = *t; | ||
313 | |||
314 | dispc_set_tv_pclk(t->timings.pixelclock); | ||
315 | } else { | ||
316 | hdmi.cfg.timings = *timings; | ||
317 | hdmi.cfg.cm.code = 0; | ||
318 | hdmi.cfg.cm.mode = HDMI_DVI; | ||
319 | |||
320 | dispc_set_tv_pclk(timings->pixelclock); | ||
321 | } | ||
322 | |||
323 | DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ? | ||
324 | "DVI" : "HDMI", hdmi.cfg.cm.code); | ||
325 | |||
326 | mutex_unlock(&hdmi.lock); | ||
327 | } | ||
328 | |||
329 | static void hdmi_display_get_timings(struct omap_dss_device *dssdev, | ||
330 | struct omap_video_timings *timings) | ||
331 | { | ||
332 | const struct hdmi_config *cfg; | ||
333 | struct hdmi_cm cm = hdmi.cfg.cm; | ||
334 | |||
335 | cfg = hdmi_get_timings(cm.mode, cm.code); | ||
336 | if (cfg == NULL) | ||
337 | cfg = hdmi_default_timing(); | ||
338 | |||
339 | memcpy(timings, &cfg->timings, sizeof(cfg->timings)); | ||
340 | } | ||
341 | |||
342 | static void hdmi_dump_regs(struct seq_file *s) | ||
343 | { | ||
344 | mutex_lock(&hdmi.lock); | ||
345 | |||
346 | if (hdmi_runtime_get()) { | ||
347 | mutex_unlock(&hdmi.lock); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | hdmi_wp_dump(&hdmi.wp, s); | ||
352 | hdmi_pll_dump(&hdmi.pll, s); | ||
353 | hdmi_phy_dump(&hdmi.phy, s); | ||
354 | hdmi5_core_dump(&hdmi.core, s); | ||
355 | |||
356 | hdmi_runtime_put(); | ||
357 | mutex_unlock(&hdmi.lock); | ||
358 | } | ||
359 | |||
360 | static int read_edid(u8 *buf, int len) | ||
361 | { | ||
362 | int r; | ||
363 | int idlemode; | ||
364 | |||
365 | mutex_lock(&hdmi.lock); | ||
366 | |||
367 | r = hdmi_runtime_get(); | ||
368 | BUG_ON(r); | ||
369 | |||
370 | idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); | ||
371 | /* No-idle mode */ | ||
372 | REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); | ||
373 | |||
374 | r = hdmi5_read_edid(&hdmi.core, buf, len); | ||
375 | |||
376 | REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); | ||
377 | |||
378 | hdmi_runtime_put(); | ||
379 | mutex_unlock(&hdmi.lock); | ||
380 | |||
381 | return r; | ||
382 | } | ||
383 | |||
384 | static int hdmi_display_enable(struct omap_dss_device *dssdev) | ||
385 | { | ||
386 | struct omap_dss_device *out = &hdmi.output; | ||
387 | int r = 0; | ||
388 | |||
389 | DSSDBG("ENTER hdmi_display_enable\n"); | ||
390 | |||
391 | mutex_lock(&hdmi.lock); | ||
392 | |||
393 | if (out == NULL || out->manager == NULL) { | ||
394 | DSSERR("failed to enable display: no output/manager\n"); | ||
395 | r = -ENODEV; | ||
396 | goto err0; | ||
397 | } | ||
398 | |||
399 | r = hdmi_power_on_full(dssdev); | ||
400 | if (r) { | ||
401 | DSSERR("failed to power on device\n"); | ||
402 | goto err0; | ||
403 | } | ||
404 | |||
405 | mutex_unlock(&hdmi.lock); | ||
406 | return 0; | ||
407 | |||
408 | err0: | ||
409 | mutex_unlock(&hdmi.lock); | ||
410 | return r; | ||
411 | } | ||
412 | |||
413 | static void hdmi_display_disable(struct omap_dss_device *dssdev) | ||
414 | { | ||
415 | DSSDBG("Enter hdmi_display_disable\n"); | ||
416 | |||
417 | mutex_lock(&hdmi.lock); | ||
418 | |||
419 | hdmi_power_off_full(dssdev); | ||
420 | |||
421 | mutex_unlock(&hdmi.lock); | ||
422 | } | ||
423 | |||
424 | static int hdmi_core_enable(struct omap_dss_device *dssdev) | ||
425 | { | ||
426 | int r = 0; | ||
427 | |||
428 | DSSDBG("ENTER omapdss_hdmi_core_enable\n"); | ||
429 | |||
430 | mutex_lock(&hdmi.lock); | ||
431 | |||
432 | r = hdmi_power_on_core(dssdev); | ||
433 | if (r) { | ||
434 | DSSERR("failed to power on device\n"); | ||
435 | goto err0; | ||
436 | } | ||
437 | |||
438 | mutex_unlock(&hdmi.lock); | ||
439 | return 0; | ||
440 | |||
441 | err0: | ||
442 | mutex_unlock(&hdmi.lock); | ||
443 | return r; | ||
444 | } | ||
445 | |||
446 | static void hdmi_core_disable(struct omap_dss_device *dssdev) | ||
447 | { | ||
448 | DSSDBG("Enter omapdss_hdmi_core_disable\n"); | ||
449 | |||
450 | mutex_lock(&hdmi.lock); | ||
451 | |||
452 | hdmi_power_off_core(dssdev); | ||
453 | |||
454 | mutex_unlock(&hdmi.lock); | ||
455 | } | ||
456 | |||
457 | static int hdmi_get_clocks(struct platform_device *pdev) | ||
458 | { | ||
459 | struct clk *clk; | ||
460 | |||
461 | clk = devm_clk_get(&pdev->dev, "sys_clk"); | ||
462 | if (IS_ERR(clk)) { | ||
463 | DSSERR("can't get sys_clk\n"); | ||
464 | return PTR_ERR(clk); | ||
465 | } | ||
466 | |||
467 | hdmi.sys_clk = clk; | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int hdmi_connect(struct omap_dss_device *dssdev, | ||
473 | struct omap_dss_device *dst) | ||
474 | { | ||
475 | struct omap_overlay_manager *mgr; | ||
476 | int r; | ||
477 | |||
478 | r = hdmi_init_regulator(); | ||
479 | if (r) | ||
480 | return r; | ||
481 | |||
482 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
483 | if (!mgr) | ||
484 | return -ENODEV; | ||
485 | |||
486 | r = dss_mgr_connect(mgr, dssdev); | ||
487 | if (r) | ||
488 | return r; | ||
489 | |||
490 | r = omapdss_output_set_device(dssdev, dst); | ||
491 | if (r) { | ||
492 | DSSERR("failed to connect output to new device: %s\n", | ||
493 | dst->name); | ||
494 | dss_mgr_disconnect(mgr, dssdev); | ||
495 | return r; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static void hdmi_disconnect(struct omap_dss_device *dssdev, | ||
502 | struct omap_dss_device *dst) | ||
503 | { | ||
504 | WARN_ON(dst != dssdev->dst); | ||
505 | |||
506 | if (dst != dssdev->dst) | ||
507 | return; | ||
508 | |||
509 | omapdss_output_unset_device(dssdev); | ||
510 | |||
511 | if (dssdev->manager) | ||
512 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
513 | } | ||
514 | |||
515 | static int hdmi_read_edid(struct omap_dss_device *dssdev, | ||
516 | u8 *edid, int len) | ||
517 | { | ||
518 | bool need_enable; | ||
519 | int r; | ||
520 | |||
521 | need_enable = hdmi.core_enabled == false; | ||
522 | |||
523 | if (need_enable) { | ||
524 | r = hdmi_core_enable(dssdev); | ||
525 | if (r) | ||
526 | return r; | ||
527 | } | ||
528 | |||
529 | r = read_edid(edid, len); | ||
530 | |||
531 | if (need_enable) | ||
532 | hdmi_core_disable(dssdev); | ||
533 | |||
534 | return r; | ||
535 | } | ||
536 | |||
537 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
538 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
539 | { | ||
540 | int r; | ||
541 | |||
542 | mutex_lock(&hdmi.lock); | ||
543 | |||
544 | if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { | ||
545 | r = -EPERM; | ||
546 | goto err; | ||
547 | } | ||
548 | |||
549 | r = hdmi_wp_audio_enable(&hdmi.wp, true); | ||
550 | if (r) | ||
551 | goto err; | ||
552 | |||
553 | mutex_unlock(&hdmi.lock); | ||
554 | return 0; | ||
555 | |||
556 | err: | ||
557 | mutex_unlock(&hdmi.lock); | ||
558 | return r; | ||
559 | } | ||
560 | |||
561 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
562 | { | ||
563 | hdmi_wp_audio_enable(&hdmi.wp, false); | ||
564 | } | ||
565 | |||
566 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
567 | { | ||
568 | return hdmi_wp_audio_core_req_enable(&hdmi.wp, true); | ||
569 | } | ||
570 | |||
571 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
572 | { | ||
573 | hdmi_wp_audio_core_req_enable(&hdmi.wp, false); | ||
574 | } | ||
575 | |||
576 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
577 | { | ||
578 | bool r; | ||
579 | |||
580 | mutex_lock(&hdmi.lock); | ||
581 | |||
582 | r = hdmi_mode_has_audio(hdmi.cfg.cm.mode); | ||
583 | |||
584 | mutex_unlock(&hdmi.lock); | ||
585 | return r; | ||
586 | } | ||
587 | |||
588 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
589 | struct omap_dss_audio *audio) | ||
590 | { | ||
591 | int r; | ||
592 | u32 pclk = hdmi.cfg.timings.pixelclock; | ||
593 | |||
594 | mutex_lock(&hdmi.lock); | ||
595 | |||
596 | if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { | ||
597 | r = -EPERM; | ||
598 | goto err; | ||
599 | } | ||
600 | |||
601 | r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk); | ||
602 | if (r) | ||
603 | goto err; | ||
604 | |||
605 | mutex_unlock(&hdmi.lock); | ||
606 | return 0; | ||
607 | |||
608 | err: | ||
609 | mutex_unlock(&hdmi.lock); | ||
610 | return r; | ||
611 | } | ||
612 | #else | ||
613 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
614 | { | ||
615 | return -EPERM; | ||
616 | } | ||
617 | |||
618 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
619 | { | ||
620 | } | ||
621 | |||
622 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
623 | { | ||
624 | return -EPERM; | ||
625 | } | ||
626 | |||
627 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
628 | { | ||
629 | } | ||
630 | |||
631 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
632 | { | ||
633 | return false; | ||
634 | } | ||
635 | |||
636 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
637 | struct omap_dss_audio *audio) | ||
638 | { | ||
639 | return -EPERM; | ||
640 | } | ||
641 | #endif | ||
642 | |||
643 | static const struct omapdss_hdmi_ops hdmi_ops = { | ||
644 | .connect = hdmi_connect, | ||
645 | .disconnect = hdmi_disconnect, | ||
646 | |||
647 | .enable = hdmi_display_enable, | ||
648 | .disable = hdmi_display_disable, | ||
649 | |||
650 | .check_timings = hdmi_display_check_timing, | ||
651 | .set_timings = hdmi_display_set_timing, | ||
652 | .get_timings = hdmi_display_get_timings, | ||
653 | |||
654 | .read_edid = hdmi_read_edid, | ||
655 | |||
656 | .audio_enable = hdmi_audio_enable, | ||
657 | .audio_disable = hdmi_audio_disable, | ||
658 | .audio_start = hdmi_audio_start, | ||
659 | .audio_stop = hdmi_audio_stop, | ||
660 | .audio_supported = hdmi_audio_supported, | ||
661 | .audio_config = hdmi_audio_config, | ||
662 | }; | ||
663 | |||
664 | static void hdmi_init_output(struct platform_device *pdev) | ||
665 | { | ||
666 | struct omap_dss_device *out = &hdmi.output; | ||
667 | |||
668 | out->dev = &pdev->dev; | ||
669 | out->id = OMAP_DSS_OUTPUT_HDMI; | ||
670 | out->output_type = OMAP_DISPLAY_TYPE_HDMI; | ||
671 | out->name = "hdmi.0"; | ||
672 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | ||
673 | out->ops.hdmi = &hdmi_ops; | ||
674 | out->owner = THIS_MODULE; | ||
675 | |||
676 | omapdss_register_output(out); | ||
677 | } | ||
678 | |||
679 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | ||
680 | { | ||
681 | struct omap_dss_device *out = &hdmi.output; | ||
682 | |||
683 | omapdss_unregister_output(out); | ||
684 | } | ||
685 | |||
686 | static int hdmi_probe_of(struct platform_device *pdev) | ||
687 | { | ||
688 | struct device_node *node = pdev->dev.of_node; | ||
689 | struct device_node *ep; | ||
690 | int r; | ||
691 | |||
692 | ep = omapdss_of_get_first_endpoint(node); | ||
693 | if (!ep) | ||
694 | return 0; | ||
695 | |||
696 | r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); | ||
697 | if (r) | ||
698 | goto err; | ||
699 | |||
700 | of_node_put(ep); | ||
701 | return 0; | ||
702 | |||
703 | err: | ||
704 | of_node_put(ep); | ||
705 | return r; | ||
706 | } | ||
707 | |||
708 | /* HDMI HW IP initialisation */ | ||
709 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | ||
710 | { | ||
711 | int r; | ||
712 | int irq; | ||
713 | |||
714 | hdmi.pdev = pdev; | ||
715 | |||
716 | mutex_init(&hdmi.lock); | ||
717 | |||
718 | if (pdev->dev.of_node) { | ||
719 | r = hdmi_probe_of(pdev); | ||
720 | if (r) | ||
721 | return r; | ||
722 | } | ||
723 | |||
724 | r = hdmi_wp_init(pdev, &hdmi.wp); | ||
725 | if (r) | ||
726 | return r; | ||
727 | |||
728 | r = hdmi_pll_init(pdev, &hdmi.pll); | ||
729 | if (r) | ||
730 | return r; | ||
731 | |||
732 | r = hdmi_phy_init(pdev, &hdmi.phy); | ||
733 | if (r) | ||
734 | return r; | ||
735 | |||
736 | r = hdmi5_core_init(pdev, &hdmi.core); | ||
737 | if (r) | ||
738 | return r; | ||
739 | |||
740 | r = hdmi_get_clocks(pdev); | ||
741 | if (r) { | ||
742 | DSSERR("can't get clocks\n"); | ||
743 | return r; | ||
744 | } | ||
745 | |||
746 | irq = platform_get_irq(pdev, 0); | ||
747 | if (irq < 0) { | ||
748 | DSSERR("platform_get_irq failed\n"); | ||
749 | return -ENODEV; | ||
750 | } | ||
751 | |||
752 | r = devm_request_threaded_irq(&pdev->dev, irq, | ||
753 | NULL, hdmi_irq_handler, | ||
754 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); | ||
755 | if (r) { | ||
756 | DSSERR("HDMI IRQ request failed\n"); | ||
757 | return r; | ||
758 | } | ||
759 | |||
760 | pm_runtime_enable(&pdev->dev); | ||
761 | |||
762 | hdmi_init_output(pdev); | ||
763 | |||
764 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | ||
770 | { | ||
771 | hdmi_uninit_output(pdev); | ||
772 | |||
773 | pm_runtime_disable(&pdev->dev); | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | static int hdmi_runtime_suspend(struct device *dev) | ||
779 | { | ||
780 | clk_disable_unprepare(hdmi.sys_clk); | ||
781 | |||
782 | dispc_runtime_put(); | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int hdmi_runtime_resume(struct device *dev) | ||
788 | { | ||
789 | int r; | ||
790 | |||
791 | r = dispc_runtime_get(); | ||
792 | if (r < 0) | ||
793 | return r; | ||
794 | |||
795 | clk_prepare_enable(hdmi.sys_clk); | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static const struct dev_pm_ops hdmi_pm_ops = { | ||
801 | .runtime_suspend = hdmi_runtime_suspend, | ||
802 | .runtime_resume = hdmi_runtime_resume, | ||
803 | }; | ||
804 | |||
805 | static const struct of_device_id hdmi_of_match[] = { | ||
806 | { .compatible = "ti,omap5-hdmi", }, | ||
807 | {}, | ||
808 | }; | ||
809 | |||
810 | static struct platform_driver omapdss_hdmihw_driver = { | ||
811 | .probe = omapdss_hdmihw_probe, | ||
812 | .remove = __exit_p(omapdss_hdmihw_remove), | ||
813 | .driver = { | ||
814 | .name = "omapdss_hdmi5", | ||
815 | .owner = THIS_MODULE, | ||
816 | .pm = &hdmi_pm_ops, | ||
817 | .of_match_table = hdmi_of_match, | ||
818 | }, | ||
819 | }; | ||
820 | |||
821 | int __init hdmi5_init_platform_driver(void) | ||
822 | { | ||
823 | return platform_driver_register(&omapdss_hdmihw_driver); | ||
824 | } | ||
825 | |||
826 | void __exit hdmi5_uninit_platform_driver(void) | ||
827 | { | ||
828 | platform_driver_unregister(&omapdss_hdmihw_driver); | ||
829 | } | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c new file mode 100644 index 000000000000..7528c7a42aa5 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c | |||
@@ -0,0 +1,922 @@ | |||
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 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
34 | #include <sound/asound.h> | ||
35 | #include <sound/asoundef.h> | ||
36 | #endif | ||
37 | |||
38 | #include "hdmi5_core.h" | ||
39 | |||
40 | /* only 24 bit color depth used for now */ | ||
41 | static const struct csc_table csc_table_deepcolor[] = { | ||
42 | /* HDMI_DEEP_COLOR_24BIT */ | ||
43 | [0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, }, | ||
44 | /* HDMI_DEEP_COLOR_30BIT */ | ||
45 | [1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, }, | ||
46 | /* HDMI_DEEP_COLOR_36BIT */ | ||
47 | [2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, }, | ||
48 | /* FULL RANGE */ | ||
49 | [3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, }, | ||
50 | }; | ||
51 | |||
52 | static void hdmi_core_ddc_init(struct hdmi_core_data *core) | ||
53 | { | ||
54 | void __iomem *base = core->base; | ||
55 | const unsigned long long iclk = 266000000; /* DSS L3 ICLK */ | ||
56 | const unsigned ss_scl_high = 4000; /* ns */ | ||
57 | const unsigned ss_scl_low = 4700; /* ns */ | ||
58 | const unsigned fs_scl_high = 600; /* ns */ | ||
59 | const unsigned fs_scl_low = 1300; /* ns */ | ||
60 | const unsigned sda_hold = 300; /* ns */ | ||
61 | const unsigned sfr_div = 10; | ||
62 | unsigned long long sfr; | ||
63 | unsigned v; | ||
64 | |||
65 | sfr = iclk / sfr_div; /* SFR_DIV */ | ||
66 | sfr /= 1000; /* SFR clock in kHz */ | ||
67 | |||
68 | /* Reset */ | ||
69 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SOFTRSTZ, 0, 0, 0); | ||
70 | if (hdmi_wait_for_bit_change(base, HDMI_CORE_I2CM_SOFTRSTZ, | ||
71 | 0, 0, 1) != 1) | ||
72 | DSSERR("HDMI I2CM reset failed\n"); | ||
73 | |||
74 | /* Standard (0) or Fast (1) Mode */ | ||
75 | REG_FLD_MOD(base, HDMI_CORE_I2CM_DIV, 0, 3, 3); | ||
76 | |||
77 | /* Standard Mode SCL High counter */ | ||
78 | v = DIV_ROUND_UP_ULL(ss_scl_high * sfr, 1000000); | ||
79 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR, | ||
80 | (v >> 8) & 0xff, 7, 0); | ||
81 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR, | ||
82 | v & 0xff, 7, 0); | ||
83 | |||
84 | /* Standard Mode SCL Low counter */ | ||
85 | v = DIV_ROUND_UP_ULL(ss_scl_low * sfr, 1000000); | ||
86 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR, | ||
87 | (v >> 8) & 0xff, 7, 0); | ||
88 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR, | ||
89 | v & 0xff, 7, 0); | ||
90 | |||
91 | /* Fast Mode SCL High Counter */ | ||
92 | v = DIV_ROUND_UP_ULL(fs_scl_high * sfr, 1000000); | ||
93 | REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR, | ||
94 | (v >> 8) & 0xff, 7, 0); | ||
95 | REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR, | ||
96 | v & 0xff, 7, 0); | ||
97 | |||
98 | /* Fast Mode SCL Low Counter */ | ||
99 | v = DIV_ROUND_UP_ULL(fs_scl_low * sfr, 1000000); | ||
100 | REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR, | ||
101 | (v >> 8) & 0xff, 7, 0); | ||
102 | REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR, | ||
103 | v & 0xff, 7, 0); | ||
104 | |||
105 | /* SDA Hold Time */ | ||
106 | v = DIV_ROUND_UP_ULL(sda_hold * sfr, 1000000); | ||
107 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SDA_HOLD_ADDR, v & 0xff, 7, 0); | ||
108 | |||
109 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SLAVE, 0x50, 6, 0); | ||
110 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGADDR, 0x30, 6, 0); | ||
111 | |||
112 | /* NACK_POL to high */ | ||
113 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 7, 7); | ||
114 | |||
115 | /* NACK_MASK to unmasked */ | ||
116 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 6, 6); | ||
117 | |||
118 | /* ARBITRATION_POL to high */ | ||
119 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 3, 3); | ||
120 | |||
121 | /* ARBITRATION_MASK to unmasked */ | ||
122 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 2, 2); | ||
123 | |||
124 | /* DONE_POL to high */ | ||
125 | REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 3, 3); | ||
126 | |||
127 | /* DONE_MASK to unmasked */ | ||
128 | REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2); | ||
129 | } | ||
130 | |||
131 | static void hdmi_core_ddc_uninit(struct hdmi_core_data *core) | ||
132 | { | ||
133 | void __iomem *base = core->base; | ||
134 | |||
135 | /* Mask I2C interrupts */ | ||
136 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6); | ||
137 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2); | ||
138 | REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2); | ||
139 | } | ||
140 | |||
141 | static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext) | ||
142 | { | ||
143 | void __iomem *base = core->base; | ||
144 | u8 cur_addr; | ||
145 | char checksum = 0; | ||
146 | const int retries = 1000; | ||
147 | u8 seg_ptr = ext / 2; | ||
148 | u8 edidbase = ((ext % 2) * 0x80); | ||
149 | |||
150 | REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0); | ||
151 | |||
152 | /* | ||
153 | * TODO: We use polling here, although we probably should use proper | ||
154 | * interrupts. | ||
155 | */ | ||
156 | for (cur_addr = 0; cur_addr < 128; ++cur_addr) { | ||
157 | int i; | ||
158 | |||
159 | /* clear ERROR and DONE */ | ||
160 | REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0); | ||
161 | |||
162 | REG_FLD_MOD(base, HDMI_CORE_I2CM_ADDRESS, | ||
163 | edidbase + cur_addr, 7, 0); | ||
164 | |||
165 | if (seg_ptr) | ||
166 | REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 1, 1); | ||
167 | else | ||
168 | REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 0, 0); | ||
169 | |||
170 | for (i = 0; i < retries; ++i) { | ||
171 | u32 stat; | ||
172 | |||
173 | stat = REG_GET(base, HDMI_CORE_IH_I2CM_STAT0, 1, 0); | ||
174 | |||
175 | /* I2CM_ERROR */ | ||
176 | if (stat & 1) { | ||
177 | DSSERR("HDMI I2C Master Error\n"); | ||
178 | return -EIO; | ||
179 | } | ||
180 | |||
181 | /* I2CM_DONE */ | ||
182 | if (stat & (1 << 1)) | ||
183 | break; | ||
184 | |||
185 | usleep_range(250, 1000); | ||
186 | } | ||
187 | |||
188 | if (i == retries) { | ||
189 | DSSERR("HDMI I2C timeout reading EDID\n"); | ||
190 | return -EIO; | ||
191 | } | ||
192 | |||
193 | pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0); | ||
194 | checksum += pedid[cur_addr]; | ||
195 | } | ||
196 | |||
197 | return 0; | ||
198 | |||
199 | } | ||
200 | |||
201 | int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len) | ||
202 | { | ||
203 | int r, n, i; | ||
204 | int max_ext_blocks = (len / 128) - 1; | ||
205 | |||
206 | if (len < 128) | ||
207 | return -EINVAL; | ||
208 | |||
209 | hdmi_core_ddc_init(core); | ||
210 | |||
211 | r = hdmi_core_ddc_edid(core, edid, 0); | ||
212 | if (r) | ||
213 | goto out; | ||
214 | |||
215 | n = edid[0x7e]; | ||
216 | |||
217 | if (n > max_ext_blocks) | ||
218 | n = max_ext_blocks; | ||
219 | |||
220 | for (i = 1; i <= n; i++) { | ||
221 | r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i); | ||
222 | if (r) | ||
223 | goto out; | ||
224 | } | ||
225 | |||
226 | out: | ||
227 | hdmi_core_ddc_uninit(core); | ||
228 | |||
229 | return r ? r : len; | ||
230 | } | ||
231 | |||
232 | void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s) | ||
233 | { | ||
234 | |||
235 | #define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
236 | hdmi_read_reg(core->base, r)) | ||
237 | |||
238 | DUMPCORE(HDMI_CORE_FC_INVIDCONF); | ||
239 | DUMPCORE(HDMI_CORE_FC_INHACTIV0); | ||
240 | DUMPCORE(HDMI_CORE_FC_INHACTIV1); | ||
241 | DUMPCORE(HDMI_CORE_FC_INHBLANK0); | ||
242 | DUMPCORE(HDMI_CORE_FC_INHBLANK1); | ||
243 | DUMPCORE(HDMI_CORE_FC_INVACTIV0); | ||
244 | DUMPCORE(HDMI_CORE_FC_INVACTIV1); | ||
245 | DUMPCORE(HDMI_CORE_FC_INVBLANK); | ||
246 | DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY0); | ||
247 | DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY1); | ||
248 | DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH0); | ||
249 | DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH1); | ||
250 | DUMPCORE(HDMI_CORE_FC_VSYNCINDELAY); | ||
251 | DUMPCORE(HDMI_CORE_FC_VSYNCINWIDTH); | ||
252 | DUMPCORE(HDMI_CORE_FC_CTRLDUR); | ||
253 | DUMPCORE(HDMI_CORE_FC_EXCTRLDUR); | ||
254 | DUMPCORE(HDMI_CORE_FC_EXCTRLSPAC); | ||
255 | DUMPCORE(HDMI_CORE_FC_CH0PREAM); | ||
256 | DUMPCORE(HDMI_CORE_FC_CH1PREAM); | ||
257 | DUMPCORE(HDMI_CORE_FC_CH2PREAM); | ||
258 | DUMPCORE(HDMI_CORE_FC_AVICONF0); | ||
259 | DUMPCORE(HDMI_CORE_FC_AVICONF1); | ||
260 | DUMPCORE(HDMI_CORE_FC_AVICONF2); | ||
261 | DUMPCORE(HDMI_CORE_FC_AVIVID); | ||
262 | DUMPCORE(HDMI_CORE_FC_PRCONF); | ||
263 | |||
264 | DUMPCORE(HDMI_CORE_MC_CLKDIS); | ||
265 | DUMPCORE(HDMI_CORE_MC_SWRSTZREQ); | ||
266 | DUMPCORE(HDMI_CORE_MC_FLOWCTRL); | ||
267 | DUMPCORE(HDMI_CORE_MC_PHYRSTZ); | ||
268 | DUMPCORE(HDMI_CORE_MC_LOCKONCLOCK); | ||
269 | |||
270 | DUMPCORE(HDMI_CORE_I2CM_SLAVE); | ||
271 | DUMPCORE(HDMI_CORE_I2CM_ADDRESS); | ||
272 | DUMPCORE(HDMI_CORE_I2CM_DATAO); | ||
273 | DUMPCORE(HDMI_CORE_I2CM_DATAI); | ||
274 | DUMPCORE(HDMI_CORE_I2CM_OPERATION); | ||
275 | DUMPCORE(HDMI_CORE_I2CM_INT); | ||
276 | DUMPCORE(HDMI_CORE_I2CM_CTLINT); | ||
277 | DUMPCORE(HDMI_CORE_I2CM_DIV); | ||
278 | DUMPCORE(HDMI_CORE_I2CM_SEGADDR); | ||
279 | DUMPCORE(HDMI_CORE_I2CM_SOFTRSTZ); | ||
280 | DUMPCORE(HDMI_CORE_I2CM_SEGPTR); | ||
281 | DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR); | ||
282 | DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR); | ||
283 | DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR); | ||
284 | DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR); | ||
285 | DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR); | ||
286 | DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR); | ||
287 | DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR); | ||
288 | DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR); | ||
289 | DUMPCORE(HDMI_CORE_I2CM_SDA_HOLD_ADDR); | ||
290 | } | ||
291 | |||
292 | static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg, | ||
293 | struct hdmi_core_infoframe_avi *avi_cfg, | ||
294 | struct hdmi_config *cfg) | ||
295 | { | ||
296 | DSSDBG("hdmi_core_init\n"); | ||
297 | |||
298 | /* video core */ | ||
299 | video_cfg->data_enable_pol = 1; /* It is always 1*/ | ||
300 | video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level; | ||
301 | video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res; | ||
302 | video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1; | ||
303 | video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp; | ||
304 | video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp; | ||
305 | video_cfg->hblank = cfg->timings.hfp + | ||
306 | cfg->timings.hbp + cfg->timings.hsw - 1; | ||
307 | video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level; | ||
308 | video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res; | ||
309 | video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw; | ||
310 | video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp; | ||
311 | video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp; | ||
312 | video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */ | ||
313 | video_cfg->vblank = cfg->timings.vsw + | ||
314 | cfg->timings.vfp + cfg->timings.vbp; | ||
315 | video_cfg->v_fc_config.cm.mode = cfg->cm.mode; | ||
316 | video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace; | ||
317 | |||
318 | /* info frame */ | ||
319 | avi_cfg->db1_format = 0; | ||
320 | avi_cfg->db1_active_info = 0; | ||
321 | avi_cfg->db1_bar_info_dv = 0; | ||
322 | avi_cfg->db1_scan_info = 0; | ||
323 | avi_cfg->db2_colorimetry = 0; | ||
324 | avi_cfg->db2_aspect_ratio = 0; | ||
325 | avi_cfg->db2_active_fmt_ar = 0; | ||
326 | avi_cfg->db3_itc = 0; | ||
327 | avi_cfg->db3_ec = 0; | ||
328 | avi_cfg->db3_q_range = 0; | ||
329 | avi_cfg->db3_nup_scaling = 0; | ||
330 | avi_cfg->db4_videocode = 0; | ||
331 | avi_cfg->db5_pixel_repeat = 0; | ||
332 | avi_cfg->db6_7_line_eoftop = 0; | ||
333 | avi_cfg->db8_9_line_sofbottom = 0; | ||
334 | avi_cfg->db10_11_pixel_eofleft = 0; | ||
335 | avi_cfg->db12_13_pixel_sofright = 0; | ||
336 | } | ||
337 | |||
338 | /* DSS_HDMI_CORE_VIDEO_CONFIG */ | ||
339 | static void hdmi_core_video_config(struct hdmi_core_data *core, | ||
340 | struct hdmi_core_vid_config *cfg) | ||
341 | { | ||
342 | void __iomem *base = core->base; | ||
343 | unsigned char r = 0; | ||
344 | bool vsync_pol, hsync_pol; | ||
345 | |||
346 | vsync_pol = | ||
347 | cfg->v_fc_config.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH; | ||
348 | hsync_pol = | ||
349 | cfg->v_fc_config.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH; | ||
350 | |||
351 | /* Set hsync, vsync and data-enable polarity */ | ||
352 | r = hdmi_read_reg(base, HDMI_CORE_FC_INVIDCONF); | ||
353 | r = FLD_MOD(r, vsync_pol, 6, 6); | ||
354 | r = FLD_MOD(r, hsync_pol, 5, 5); | ||
355 | r = FLD_MOD(r, cfg->data_enable_pol, 4, 4); | ||
356 | r = FLD_MOD(r, cfg->vblank_osc, 1, 1); | ||
357 | r = FLD_MOD(r, cfg->v_fc_config.timings.interlace, 0, 0); | ||
358 | hdmi_write_reg(base, HDMI_CORE_FC_INVIDCONF, r); | ||
359 | |||
360 | /* set x resolution */ | ||
361 | REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV1, | ||
362 | cfg->v_fc_config.timings.x_res >> 8, 4, 0); | ||
363 | REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV0, | ||
364 | cfg->v_fc_config.timings.x_res & 0xFF, 7, 0); | ||
365 | |||
366 | /* set y resolution */ | ||
367 | REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV1, | ||
368 | cfg->v_fc_config.timings.y_res >> 8, 4, 0); | ||
369 | REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV0, | ||
370 | cfg->v_fc_config.timings.y_res & 0xFF, 7, 0); | ||
371 | |||
372 | /* set horizontal blanking pixels */ | ||
373 | REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK1, cfg->hblank >> 8, 4, 0); | ||
374 | REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK0, cfg->hblank & 0xFF, 7, 0); | ||
375 | |||
376 | /* set vertial blanking pixels */ | ||
377 | REG_FLD_MOD(base, HDMI_CORE_FC_INVBLANK, cfg->vblank, 7, 0); | ||
378 | |||
379 | /* set horizontal sync offset */ | ||
380 | REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY1, | ||
381 | cfg->v_fc_config.timings.hfp >> 8, 4, 0); | ||
382 | REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY0, | ||
383 | cfg->v_fc_config.timings.hfp & 0xFF, 7, 0); | ||
384 | |||
385 | /* set vertical sync offset */ | ||
386 | REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINDELAY, | ||
387 | cfg->v_fc_config.timings.vfp, 7, 0); | ||
388 | |||
389 | /* set horizontal sync pulse width */ | ||
390 | REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH1, | ||
391 | (cfg->v_fc_config.timings.hsw >> 8), 1, 0); | ||
392 | REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH0, | ||
393 | cfg->v_fc_config.timings.hsw & 0xFF, 7, 0); | ||
394 | |||
395 | /* set vertical sync pulse width */ | ||
396 | REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINWIDTH, | ||
397 | cfg->v_fc_config.timings.vsw, 5, 0); | ||
398 | |||
399 | /* select DVI mode */ | ||
400 | REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF, | ||
401 | cfg->v_fc_config.cm.mode, 3, 3); | ||
402 | } | ||
403 | |||
404 | static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core) | ||
405 | { | ||
406 | void __iomem *base = core->base; | ||
407 | int clr_depth = 0; /* 24 bit color depth */ | ||
408 | |||
409 | /* COLOR_DEPTH */ | ||
410 | REG_FLD_MOD(base, HDMI_CORE_VP_PR_CD, clr_depth, 7, 4); | ||
411 | /* BYPASS_EN */ | ||
412 | REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 1, 6, 6); | ||
413 | /* PP_EN */ | ||
414 | REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 1 : 0, 5, 5); | ||
415 | /* YCC422_EN */ | ||
416 | REG_FLD_MOD(base, HDMI_CORE_VP_CONF, 0, 3, 3); | ||
417 | /* PP_STUFFING */ | ||
418 | REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, clr_depth ? 1 : 0, 1, 1); | ||
419 | /* YCC422_STUFFING */ | ||
420 | REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, 1, 2, 2); | ||
421 | /* OUTPUT_SELECTOR */ | ||
422 | REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 2, 1, 0); | ||
423 | } | ||
424 | |||
425 | static void hdmi_core_config_csc(struct hdmi_core_data *core) | ||
426 | { | ||
427 | int clr_depth = 0; /* 24 bit color depth */ | ||
428 | |||
429 | /* CSC_COLORDEPTH */ | ||
430 | REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, clr_depth, 7, 4); | ||
431 | } | ||
432 | |||
433 | static void hdmi_core_config_video_sampler(struct hdmi_core_data *core) | ||
434 | { | ||
435 | int video_mapping = 1; /* for 24 bit color depth */ | ||
436 | |||
437 | /* VIDEO_MAPPING */ | ||
438 | REG_FLD_MOD(core->base, HDMI_CORE_TX_INVID0, video_mapping, 4, 0); | ||
439 | } | ||
440 | |||
441 | static void hdmi_core_aux_infoframe_avi_config(struct hdmi_core_data *core) | ||
442 | { | ||
443 | void __iomem *base = core->base; | ||
444 | struct hdmi_core_infoframe_avi avi = core->avi_cfg; | ||
445 | |||
446 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_format, 1, 0); | ||
447 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_active_info, 6, 6); | ||
448 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_bar_info_dv, 3, 2); | ||
449 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_scan_info, 5, 4); | ||
450 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_colorimetry, 7, 6); | ||
451 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_aspect_ratio, 5, 4); | ||
452 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_active_fmt_ar, 3, 0); | ||
453 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_itc, 7, 7); | ||
454 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_ec, 6, 4); | ||
455 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_q_range, 3, 2); | ||
456 | REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_nup_scaling, 1, 0); | ||
457 | REG_FLD_MOD(base, HDMI_CORE_FC_AVIVID, avi.db4_videocode, 6, 0); | ||
458 | REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, avi.db5_pixel_repeat, 3, 0); | ||
459 | } | ||
460 | |||
461 | static void hdmi_core_csc_config(struct hdmi_core_data *core, | ||
462 | struct csc_table csc_coeff) | ||
463 | { | ||
464 | void __iomem *base = core->base; | ||
465 | |||
466 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff.a1 >> 8 , 6, 0); | ||
467 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff.a1, 7, 0); | ||
468 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff.a2 >> 8, 6, 0); | ||
469 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff.a2, 7, 0); | ||
470 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff.a3 >> 8, 6, 0); | ||
471 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff.a3, 7, 0); | ||
472 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff.a4 >> 8, 6, 0); | ||
473 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff.a4, 7, 0); | ||
474 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff.b1 >> 8, 6, 0); | ||
475 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff.b1, 7, 0); | ||
476 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff.b2 >> 8, 6, 0); | ||
477 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff.b2, 7, 0); | ||
478 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff.b3 >> 8, 6, 0); | ||
479 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff.b3, 7, 0); | ||
480 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff.b4 >> 8, 6, 0); | ||
481 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff.b4, 7, 0); | ||
482 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff.c1 >> 8, 6, 0); | ||
483 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff.c1, 7, 0); | ||
484 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff.c2 >> 8, 6, 0); | ||
485 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff.c2, 7, 0); | ||
486 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff.c3 >> 8, 6, 0); | ||
487 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff.c3, 7, 0); | ||
488 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff.c4 >> 8, 6, 0); | ||
489 | REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff.c4, 7, 0); | ||
490 | |||
491 | REG_FLD_MOD(base, HDMI_CORE_MC_FLOWCTRL, 0x1, 0, 0); | ||
492 | } | ||
493 | |||
494 | static void hdmi_core_configure_range(struct hdmi_core_data *core) | ||
495 | { | ||
496 | struct csc_table csc_coeff = { 0 }; | ||
497 | |||
498 | /* support limited range with 24 bit color depth for now */ | ||
499 | csc_coeff = csc_table_deepcolor[0]; | ||
500 | core->avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_LR; | ||
501 | |||
502 | hdmi_core_csc_config(core, csc_coeff); | ||
503 | hdmi_core_aux_infoframe_avi_config(core); | ||
504 | } | ||
505 | |||
506 | static void hdmi_core_enable_video_path(struct hdmi_core_data *core) | ||
507 | { | ||
508 | void __iomem *base = core->base; | ||
509 | |||
510 | DSSDBG("hdmi_core_enable_video_path\n"); | ||
511 | |||
512 | REG_FLD_MOD(base, HDMI_CORE_FC_CTRLDUR, 0x0C, 7, 0); | ||
513 | REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLDUR, 0x20, 7, 0); | ||
514 | REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLSPAC, 0x01, 7, 0); | ||
515 | REG_FLD_MOD(base, HDMI_CORE_FC_CH0PREAM, 0x0B, 7, 0); | ||
516 | REG_FLD_MOD(base, HDMI_CORE_FC_CH1PREAM, 0x16, 5, 0); | ||
517 | REG_FLD_MOD(base, HDMI_CORE_FC_CH2PREAM, 0x21, 5, 0); | ||
518 | REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 0, 0); | ||
519 | REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 1, 1); | ||
520 | } | ||
521 | |||
522 | static void hdmi_core_mask_interrupts(struct hdmi_core_data *core) | ||
523 | { | ||
524 | void __iomem *base = core->base; | ||
525 | |||
526 | /* Master IRQ mask */ | ||
527 | REG_FLD_MOD(base, HDMI_CORE_IH_MUTE, 0x3, 1, 0); | ||
528 | |||
529 | /* Mask all the interrupts in HDMI core */ | ||
530 | |||
531 | REG_FLD_MOD(base, HDMI_CORE_VP_MASK, 0xff, 7, 0); | ||
532 | REG_FLD_MOD(base, HDMI_CORE_FC_MASK0, 0xe7, 7, 0); | ||
533 | REG_FLD_MOD(base, HDMI_CORE_FC_MASK1, 0xfb, 7, 0); | ||
534 | REG_FLD_MOD(base, HDMI_CORE_FC_MASK2, 0x3, 1, 0); | ||
535 | |||
536 | REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 0x3, 3, 2); | ||
537 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 0x3, 1, 0); | ||
538 | |||
539 | REG_FLD_MOD(base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0); | ||
540 | |||
541 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6); | ||
542 | REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2); | ||
543 | REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2); | ||
544 | |||
545 | REG_FLD_MOD(base, HDMI_CORE_PHY_MASK0, 0xf3, 7, 0); | ||
546 | |||
547 | REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0); | ||
548 | |||
549 | /* Clear all the current interrupt bits */ | ||
550 | |||
551 | REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0); | ||
552 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xe7, 7, 0); | ||
553 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xfb, 7, 0); | ||
554 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0x3, 1, 0); | ||
555 | |||
556 | REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0x7, 2, 0); | ||
557 | |||
558 | REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0); | ||
559 | |||
560 | REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0); | ||
561 | |||
562 | REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0); | ||
563 | } | ||
564 | |||
565 | static void hdmi_core_enable_interrupts(struct hdmi_core_data *core) | ||
566 | { | ||
567 | /* Unmute interrupts */ | ||
568 | REG_FLD_MOD(core->base, HDMI_CORE_IH_MUTE, 0x0, 1, 0); | ||
569 | } | ||
570 | |||
571 | int hdmi5_core_handle_irqs(struct hdmi_core_data *core) | ||
572 | { | ||
573 | void __iomem *base = core->base; | ||
574 | |||
575 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xff, 7, 0); | ||
576 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xff, 7, 0); | ||
577 | REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0xff, 7, 0); | ||
578 | REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0xff, 7, 0); | ||
579 | REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0); | ||
580 | REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0xff, 7, 0); | ||
581 | REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0xff, 7, 0); | ||
582 | REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0); | ||
583 | REG_FLD_MOD(base, HDMI_CORE_IH_I2CMPHY_STAT0, 0xff, 7, 0); | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | ||
589 | struct hdmi_config *cfg) | ||
590 | { | ||
591 | struct omap_video_timings video_timing; | ||
592 | struct hdmi_video_format video_format; | ||
593 | struct hdmi_core_vid_config v_core_cfg; | ||
594 | struct hdmi_core_infoframe_avi *avi_cfg = &core->avi_cfg; | ||
595 | |||
596 | hdmi_core_mask_interrupts(core); | ||
597 | |||
598 | hdmi_core_init(&v_core_cfg, avi_cfg, cfg); | ||
599 | |||
600 | hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg); | ||
601 | |||
602 | hdmi_wp_video_config_timing(wp, &video_timing); | ||
603 | |||
604 | /* video config */ | ||
605 | video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; | ||
606 | |||
607 | hdmi_wp_video_config_format(wp, &video_format); | ||
608 | |||
609 | hdmi_wp_video_config_interface(wp, &video_timing); | ||
610 | |||
611 | hdmi_core_configure_range(core); | ||
612 | |||
613 | /* | ||
614 | * configure core video part, set software reset in the core | ||
615 | */ | ||
616 | v_core_cfg.packet_mode = HDMI_PACKETMODE24BITPERPIXEL; | ||
617 | |||
618 | hdmi_core_video_config(core, &v_core_cfg); | ||
619 | |||
620 | hdmi_core_config_video_packetizer(core); | ||
621 | hdmi_core_config_csc(core); | ||
622 | hdmi_core_config_video_sampler(core); | ||
623 | |||
624 | /* | ||
625 | * configure packet info frame video see doc CEA861-D page 65 | ||
626 | */ | ||
627 | avi_cfg->db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; | ||
628 | avi_cfg->db1_active_info = | ||
629 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; | ||
630 | avi_cfg->db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; | ||
631 | avi_cfg->db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; | ||
632 | avi_cfg->db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; | ||
633 | avi_cfg->db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; | ||
634 | avi_cfg->db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; | ||
635 | avi_cfg->db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; | ||
636 | avi_cfg->db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; | ||
637 | avi_cfg->db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; | ||
638 | avi_cfg->db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; | ||
639 | avi_cfg->db4_videocode = cfg->cm.code; | ||
640 | avi_cfg->db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; | ||
641 | avi_cfg->db6_7_line_eoftop = 0; | ||
642 | avi_cfg->db8_9_line_sofbottom = 0; | ||
643 | avi_cfg->db10_11_pixel_eofleft = 0; | ||
644 | avi_cfg->db12_13_pixel_sofright = 0; | ||
645 | |||
646 | hdmi_core_aux_infoframe_avi_config(core); | ||
647 | |||
648 | hdmi_core_enable_video_path(core); | ||
649 | |||
650 | hdmi_core_enable_interrupts(core); | ||
651 | } | ||
652 | |||
653 | |||
654 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
655 | |||
656 | static void hdmi5_core_audio_config(struct hdmi_core_data *core, | ||
657 | struct hdmi_core_audio_config *cfg) | ||
658 | { | ||
659 | void __iomem *base = core->base; | ||
660 | u8 val; | ||
661 | |||
662 | /* Mute audio before configuring */ | ||
663 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0xf, 7, 4); | ||
664 | |||
665 | /* Set the N parameter */ | ||
666 | REG_FLD_MOD(base, HDMI_CORE_AUD_N1, cfg->n, 7, 0); | ||
667 | REG_FLD_MOD(base, HDMI_CORE_AUD_N2, cfg->n >> 8, 7, 0); | ||
668 | REG_FLD_MOD(base, HDMI_CORE_AUD_N3, cfg->n >> 16, 3, 0); | ||
669 | |||
670 | /* | ||
671 | * CTS manual mode. Automatic mode is not supported when using audio | ||
672 | * parallel interface. | ||
673 | */ | ||
674 | REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, 1, 4, 4); | ||
675 | REG_FLD_MOD(base, HDMI_CORE_AUD_CTS1, cfg->cts, 7, 0); | ||
676 | REG_FLD_MOD(base, HDMI_CORE_AUD_CTS2, cfg->cts >> 8, 7, 0); | ||
677 | REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, cfg->cts >> 16, 3, 0); | ||
678 | |||
679 | /* Layout of Audio Sample Packets: 2-channel or multichannels */ | ||
680 | if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) | ||
681 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 0, 0); | ||
682 | else | ||
683 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 1, 0, 0); | ||
684 | |||
685 | /* Configure IEC-609580 Validity bits */ | ||
686 | /* Channel 0 is valid */ | ||
687 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 0, 0); | ||
688 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 4, 4); | ||
689 | |||
690 | if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) | ||
691 | val = 1; | ||
692 | else | ||
693 | val = 0; | ||
694 | |||
695 | /* Channels 1, 2 setting */ | ||
696 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 1, 1); | ||
697 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 5, 5); | ||
698 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 2, 2); | ||
699 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 6, 6); | ||
700 | /* Channel 3 setting */ | ||
701 | if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH) | ||
702 | val = 1; | ||
703 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 3, 3); | ||
704 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 7, 7); | ||
705 | |||
706 | /* Configure IEC-60958 User bits */ | ||
707 | /* TODO: should be set by user. */ | ||
708 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSU, 0, 7, 0); | ||
709 | |||
710 | /* Configure IEC-60958 Channel Status word */ | ||
711 | /* CGMSA */ | ||
712 | val = cfg->iec60958_cfg->status[5] & IEC958_AES5_CON_CGMSA; | ||
713 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 5, 4); | ||
714 | |||
715 | /* Copyright */ | ||
716 | val = (cfg->iec60958_cfg->status[0] & | ||
717 | IEC958_AES0_CON_NOT_COPYRIGHT) >> 2; | ||
718 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 0, 0); | ||
719 | |||
720 | /* Category */ | ||
721 | hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(1), | ||
722 | cfg->iec60958_cfg->status[1]); | ||
723 | |||
724 | /* PCM audio mode */ | ||
725 | val = (cfg->iec60958_cfg->status[0] & IEC958_AES0_CON_MODE) >> 6; | ||
726 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 6, 4); | ||
727 | |||
728 | /* Source number */ | ||
729 | val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE; | ||
730 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4); | ||
731 | |||
732 | /* Channel number right 0 */ | ||
733 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0); | ||
734 | /* Channel number right 1*/ | ||
735 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 4, 7, 4); | ||
736 | /* Channel number right 2 */ | ||
737 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 6, 3, 0); | ||
738 | /* Channel number right 3*/ | ||
739 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 8, 7, 4); | ||
740 | /* Channel number left 0 */ | ||
741 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 1, 3, 0); | ||
742 | /* Channel number left 1*/ | ||
743 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 3, 7, 4); | ||
744 | /* Channel number left 2 */ | ||
745 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 5, 3, 0); | ||
746 | /* Channel number left 3*/ | ||
747 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 7, 7, 4); | ||
748 | |||
749 | /* Clock accuracy and sample rate */ | ||
750 | hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(7), | ||
751 | cfg->iec60958_cfg->status[3]); | ||
752 | |||
753 | /* Original sample rate and word length */ | ||
754 | hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(8), | ||
755 | cfg->iec60958_cfg->status[4]); | ||
756 | |||
757 | /* Enable FIFO empty and full interrupts */ | ||
758 | REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 3, 3, 2); | ||
759 | |||
760 | /* Configure GPA */ | ||
761 | /* select HBR/SPDIF interfaces */ | ||
762 | if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) { | ||
763 | /* select HBR/SPDIF interfaces */ | ||
764 | REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5); | ||
765 | /* enable two channels in GPA */ | ||
766 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 3, 7, 0); | ||
767 | } else if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH) { | ||
768 | /* select HBR/SPDIF interfaces */ | ||
769 | REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5); | ||
770 | /* enable six channels in GPA */ | ||
771 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0x3F, 7, 0); | ||
772 | } else { | ||
773 | /* select HBR/SPDIF interfaces */ | ||
774 | REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5); | ||
775 | /* enable eight channels in GPA */ | ||
776 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0xFF, 7, 0); | ||
777 | } | ||
778 | |||
779 | /* disable HBR */ | ||
780 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 0, 0, 0); | ||
781 | /* enable PCUV */ | ||
782 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 1, 1, 1); | ||
783 | /* enable GPA FIFO full and empty mask */ | ||
784 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 3, 1, 0); | ||
785 | /* set polarity of GPA FIFO empty interrupts */ | ||
786 | REG_FLD_MOD(base, HDMI_CORE_AUD_GP_POL, 1, 0, 0); | ||
787 | |||
788 | /* unmute audio */ | ||
789 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 7, 4); | ||
790 | } | ||
791 | |||
792 | static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core, | ||
793 | struct snd_cea_861_aud_if *info_aud) | ||
794 | { | ||
795 | void __iomem *base = core->base; | ||
796 | |||
797 | /* channel count and coding type fields in AUDICONF0 are swapped */ | ||
798 | hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF0, | ||
799 | (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC) << 4 | | ||
800 | (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CT) >> 4); | ||
801 | |||
802 | hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud->db2_sf_ss); | ||
803 | hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud->db4_ca); | ||
804 | hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, info_aud->db5_dminh_lsv); | ||
805 | } | ||
806 | |||
807 | int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | ||
808 | struct omap_dss_audio *audio, u32 pclk) | ||
809 | { | ||
810 | struct hdmi_audio_format audio_format; | ||
811 | struct hdmi_audio_dma audio_dma; | ||
812 | struct hdmi_core_audio_config core_cfg; | ||
813 | int err, n, cts, channel_count; | ||
814 | unsigned int fs_nr; | ||
815 | bool word_length_16b = false; | ||
816 | |||
817 | if (!audio || !audio->iec || !audio->cea || !core) | ||
818 | return -EINVAL; | ||
819 | |||
820 | core_cfg.iec60958_cfg = audio->iec; | ||
821 | |||
822 | if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) && | ||
823 | (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)) | ||
824 | word_length_16b = true; | ||
825 | |||
826 | /* only 16-bit word length supported atm */ | ||
827 | if (!word_length_16b) | ||
828 | return -EINVAL; | ||
829 | |||
830 | switch (audio->iec->status[3] & IEC958_AES3_CON_FS) { | ||
831 | case IEC958_AES3_CON_FS_32000: | ||
832 | fs_nr = 32000; | ||
833 | break; | ||
834 | case IEC958_AES3_CON_FS_44100: | ||
835 | fs_nr = 44100; | ||
836 | break; | ||
837 | case IEC958_AES3_CON_FS_48000: | ||
838 | fs_nr = 48000; | ||
839 | break; | ||
840 | case IEC958_AES3_CON_FS_88200: | ||
841 | fs_nr = 88200; | ||
842 | break; | ||
843 | case IEC958_AES3_CON_FS_96000: | ||
844 | fs_nr = 96000; | ||
845 | break; | ||
846 | case IEC958_AES3_CON_FS_176400: | ||
847 | fs_nr = 176400; | ||
848 | break; | ||
849 | case IEC958_AES3_CON_FS_192000: | ||
850 | fs_nr = 192000; | ||
851 | break; | ||
852 | default: | ||
853 | return -EINVAL; | ||
854 | } | ||
855 | |||
856 | err = hdmi_compute_acr(pclk, fs_nr, &n, &cts); | ||
857 | core_cfg.n = n; | ||
858 | core_cfg.cts = cts; | ||
859 | |||
860 | /* Audio channels settings */ | ||
861 | channel_count = (audio->cea->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC) | ||
862 | + 1; | ||
863 | |||
864 | if (channel_count == 2) | ||
865 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
866 | else if (channel_count == 6) | ||
867 | core_cfg.layout = HDMI_AUDIO_LAYOUT_6CH; | ||
868 | else | ||
869 | core_cfg.layout = HDMI_AUDIO_LAYOUT_8CH; | ||
870 | |||
871 | /* DMA settings */ | ||
872 | if (word_length_16b) | ||
873 | audio_dma.transfer_size = 0x10; | ||
874 | else | ||
875 | audio_dma.transfer_size = 0x20; | ||
876 | audio_dma.block_size = 0xC0; | ||
877 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
878 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
879 | |||
880 | /* audio FIFO format settings for 16-bit samples*/ | ||
881 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
882 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
883 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
884 | |||
885 | /* only LPCM atm */ | ||
886 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
887 | |||
888 | /* disable start/stop signals of IEC 60958 blocks */ | ||
889 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; | ||
890 | |||
891 | /* configure DMA and audio FIFO format*/ | ||
892 | hdmi_wp_audio_config_dma(wp, &audio_dma); | ||
893 | hdmi_wp_audio_config_format(wp, &audio_format); | ||
894 | |||
895 | /* configure the core */ | ||
896 | hdmi5_core_audio_config(core, &core_cfg); | ||
897 | |||
898 | /* configure CEA 861 audio infoframe */ | ||
899 | hdmi5_core_audio_infoframe_cfg(core, audio->cea); | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | #endif | ||
904 | |||
905 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core) | ||
906 | { | ||
907 | struct resource *res; | ||
908 | |||
909 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); | ||
910 | if (!res) { | ||
911 | DSSERR("can't get CORE IORESOURCE_MEM HDMI\n"); | ||
912 | return -EINVAL; | ||
913 | } | ||
914 | |||
915 | core->base = devm_ioremap_resource(&pdev->dev, res); | ||
916 | if (IS_ERR(core->base)) { | ||
917 | DSSERR("can't ioremap HDMI core\n"); | ||
918 | return PTR_ERR(core->base); | ||
919 | } | ||
920 | |||
921 | return 0; | ||
922 | } | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/dss/hdmi5_core.h new file mode 100644 index 000000000000..ce7e9f376f04 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.h | |||
@@ -0,0 +1,306 @@ | |||
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 | |||
272 | enum 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 | |||
280 | struct 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 | |||
289 | struct csc_table { | ||
290 | u16 a1, a2, a3, a4; | ||
291 | u16 b1, b2, b3, b4; | ||
292 | u16 c1, c2, c3, c4; | ||
293 | }; | ||
294 | |||
295 | int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len); | ||
296 | void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s); | ||
297 | int hdmi5_core_handle_irqs(struct hdmi_core_data *core); | ||
298 | void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | ||
299 | struct hdmi_config *cfg); | ||
300 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core); | ||
301 | |||
302 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
303 | int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | ||
304 | struct omap_dss_audio *audio, u32 pclk); | ||
305 | #endif | ||
306 | #endif | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c index 0b12a3f62fe1..9a2c39cf297f 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_common.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/of.h> | ||
20 | #include <video/omapdss.h> | 21 | #include <video/omapdss.h> |
21 | 22 | ||
22 | #include "hdmi.h" | 23 | #include "hdmi.h" |
@@ -323,6 +324,46 @@ end: | |||
323 | return cm; | 324 | return cm; |
324 | } | 325 | } |
325 | 326 | ||
327 | int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, | ||
328 | struct hdmi_phy_data *phy) | ||
329 | { | ||
330 | struct property *prop; | ||
331 | int r, len; | ||
332 | |||
333 | prop = of_find_property(ep, "lanes", &len); | ||
334 | if (prop) { | ||
335 | u32 lanes[8]; | ||
336 | |||
337 | if (len / sizeof(u32) != ARRAY_SIZE(lanes)) { | ||
338 | dev_err(&pdev->dev, "bad number of lanes\n"); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | |||
342 | r = of_property_read_u32_array(ep, "lanes", lanes, | ||
343 | ARRAY_SIZE(lanes)); | ||
344 | if (r) { | ||
345 | dev_err(&pdev->dev, "failed to read lane data\n"); | ||
346 | return r; | ||
347 | } | ||
348 | |||
349 | r = hdmi_phy_parse_lanes(phy, lanes); | ||
350 | if (r) { | ||
351 | dev_err(&pdev->dev, "failed to parse lane data\n"); | ||
352 | return r; | ||
353 | } | ||
354 | } else { | ||
355 | static const u32 default_lanes[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; | ||
356 | |||
357 | r = hdmi_phy_parse_lanes(phy, default_lanes); | ||
358 | if (WARN_ON(r)) { | ||
359 | dev_err(&pdev->dev, "failed to parse lane data\n"); | ||
360 | return r; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
326 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 367 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
327 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) | 368 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) |
328 | { | 369 | { |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c index dd376ce8da01..e007ac892d79 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c | |||
@@ -12,11 +12,22 @@ | |||
12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/slab.h> | ||
15 | #include <video/omapdss.h> | 16 | #include <video/omapdss.h> |
16 | 17 | ||
17 | #include "dss.h" | 18 | #include "dss.h" |
18 | #include "hdmi.h" | 19 | #include "hdmi.h" |
19 | 20 | ||
21 | struct hdmi_phy_features { | ||
22 | bool bist_ctrl; | ||
23 | bool calc_freqout; | ||
24 | bool ldo_voltage; | ||
25 | unsigned long dcofreq_min; | ||
26 | unsigned long max_phy; | ||
27 | }; | ||
28 | |||
29 | static const struct hdmi_phy_features *phy_feat; | ||
30 | |||
20 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s) | 31 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s) |
21 | { | 32 | { |
22 | #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ | 33 | #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ |
@@ -26,53 +37,104 @@ void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s) | |||
26 | DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); | 37 | DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); |
27 | DUMPPHY(HDMI_TXPHY_POWER_CTRL); | 38 | DUMPPHY(HDMI_TXPHY_POWER_CTRL); |
28 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); | 39 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); |
40 | if (phy_feat->bist_ctrl) | ||
41 | DUMPPHY(HDMI_TXPHY_BIST_CONTROL); | ||
29 | } | 42 | } |
30 | 43 | ||
31 | static irqreturn_t hdmi_irq_handler(int irq, void *data) | 44 | int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes) |
32 | { | 45 | { |
33 | struct hdmi_wp_data *wp = data; | 46 | int i; |
34 | u32 irqstatus; | 47 | |
35 | 48 | for (i = 0; i < 8; i += 2) { | |
36 | irqstatus = hdmi_wp_get_irqstatus(wp); | 49 | u8 lane, pol; |
37 | hdmi_wp_set_irqstatus(wp, irqstatus); | 50 | int dx, dy; |
38 | 51 | ||
39 | if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && | 52 | dx = lanes[i]; |
40 | irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | 53 | dy = lanes[i + 1]; |
41 | /* | 54 | |
42 | * If we get both connect and disconnect interrupts at the same | 55 | if (dx < 0 || dx >= 8) |
43 | * time, turn off the PHY, clear interrupts, and restart, which | 56 | return -EINVAL; |
44 | * raises connect interrupt if a cable is connected, or nothing | 57 | |
45 | * if cable is not connected. | 58 | if (dy < 0 || dy >= 8) |
46 | */ | 59 | return -EINVAL; |
47 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); | 60 | |
48 | 61 | if (dx & 1) { | |
49 | hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | | 62 | if (dy != dx - 1) |
50 | HDMI_IRQ_LINK_DISCONNECT); | 63 | return -EINVAL; |
51 | 64 | pol = 1; | |
52 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | 65 | } else { |
53 | } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { | 66 | if (dy != dx + 1) |
54 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); | 67 | return -EINVAL; |
55 | } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | 68 | pol = 0; |
56 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | 69 | } |
70 | |||
71 | lane = dx / 2; | ||
72 | |||
73 | phy->lane_function[lane] = i / 2; | ||
74 | phy->lane_polarity[lane] = pol; | ||
57 | } | 75 | } |
58 | 76 | ||
59 | return IRQ_HANDLED; | 77 | return 0; |
60 | } | 78 | } |
61 | 79 | ||
62 | int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp, | 80 | static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) |
63 | struct hdmi_config *cfg) | ||
64 | { | 81 | { |
65 | u16 r = 0; | 82 | static const u16 pad_cfg_list[] = { |
66 | u32 irqstatus; | 83 | 0x0123, |
67 | 84 | 0x0132, | |
68 | hdmi_wp_clear_irqenable(wp, 0xffffffff); | 85 | 0x0312, |
69 | 86 | 0x0321, | |
70 | irqstatus = hdmi_wp_get_irqstatus(wp); | 87 | 0x0231, |
71 | hdmi_wp_set_irqstatus(wp, irqstatus); | 88 | 0x0213, |
89 | 0x1023, | ||
90 | 0x1032, | ||
91 | 0x3012, | ||
92 | 0x3021, | ||
93 | 0x2031, | ||
94 | 0x2013, | ||
95 | 0x1203, | ||
96 | 0x1302, | ||
97 | 0x3102, | ||
98 | 0x3201, | ||
99 | 0x2301, | ||
100 | 0x2103, | ||
101 | 0x1230, | ||
102 | 0x1320, | ||
103 | 0x3120, | ||
104 | 0x3210, | ||
105 | 0x2310, | ||
106 | 0x2130, | ||
107 | }; | ||
108 | |||
109 | u16 lane_cfg = 0; | ||
110 | int i; | ||
111 | unsigned lane_cfg_val; | ||
112 | u16 pol_val = 0; | ||
113 | |||
114 | for (i = 0; i < 4; ++i) | ||
115 | lane_cfg |= phy->lane_function[i] << ((3 - i) * 4); | ||
116 | |||
117 | pol_val |= phy->lane_polarity[0] << 0; | ||
118 | pol_val |= phy->lane_polarity[1] << 3; | ||
119 | pol_val |= phy->lane_polarity[2] << 2; | ||
120 | pol_val |= phy->lane_polarity[3] << 1; | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i) | ||
123 | if (pad_cfg_list[i] == lane_cfg) | ||
124 | break; | ||
125 | |||
126 | if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list))) | ||
127 | i = 0; | ||
128 | |||
129 | lane_cfg_val = i; | ||
130 | |||
131 | REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22); | ||
132 | REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); | ||
133 | } | ||
72 | 134 | ||
73 | r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); | 135 | int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) |
74 | if (r) | 136 | { |
75 | return r; | 137 | u8 freqout; |
76 | 138 | ||
77 | /* | 139 | /* |
78 | * Read address 0 in order to get the SCP reset done completed | 140 | * Read address 0 in order to get the SCP reset done completed |
@@ -81,79 +143,112 @@ int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp, | |||
81 | hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL); | 143 | hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL); |
82 | 144 | ||
83 | /* | 145 | /* |
146 | * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the | ||
147 | * HDMI_PHYPWRCMD_LDOON command. | ||
148 | */ | ||
149 | if (phy_feat->bist_ctrl) | ||
150 | REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); | ||
151 | |||
152 | if (phy_feat->calc_freqout) { | ||
153 | /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */ | ||
154 | u32 dco_min = phy_feat->dcofreq_min / 10; | ||
155 | u32 pclk = cfg->timings.pixelclock; | ||
156 | |||
157 | if (pclk < dco_min) | ||
158 | freqout = 0; | ||
159 | else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy)) | ||
160 | freqout = 1; | ||
161 | else | ||
162 | freqout = 2; | ||
163 | } else { | ||
164 | freqout = 1; | ||
165 | } | ||
166 | |||
167 | /* | ||
84 | * Write to phy address 0 to configure the clock | 168 | * Write to phy address 0 to configure the clock |
85 | * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field | 169 | * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field |
86 | */ | 170 | */ |
87 | REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); | 171 | REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30); |
88 | 172 | ||
89 | /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ | 173 | /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ |
90 | hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); | 174 | hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); |
91 | 175 | ||
92 | /* Setup max LDO voltage */ | 176 | /* Setup max LDO voltage */ |
93 | REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); | 177 | if (phy_feat->ldo_voltage) |
178 | REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); | ||
94 | 179 | ||
95 | /* Write to phy address 3 to change the polarity control */ | 180 | hdmi_phy_configure_lanes(phy); |
96 | REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | ||
97 | |||
98 | r = request_threaded_irq(phy->irq, NULL, hdmi_irq_handler, | ||
99 | IRQF_ONESHOT, "OMAP HDMI", wp); | ||
100 | if (r) { | ||
101 | DSSERR("HDMI IRQ request failed\n"); | ||
102 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); | ||
103 | return r; | ||
104 | } | ||
105 | |||
106 | hdmi_wp_set_irqenable(wp, | ||
107 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); | ||
108 | 181 | ||
109 | return 0; | 182 | return 0; |
110 | } | 183 | } |
111 | 184 | ||
112 | void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp) | 185 | static const struct hdmi_phy_features omap44xx_phy_feats = { |
186 | .bist_ctrl = false, | ||
187 | .calc_freqout = false, | ||
188 | .ldo_voltage = true, | ||
189 | .dcofreq_min = 500000000, | ||
190 | .max_phy = 185675000, | ||
191 | }; | ||
192 | |||
193 | static const struct hdmi_phy_features omap54xx_phy_feats = { | ||
194 | .bist_ctrl = true, | ||
195 | .calc_freqout = true, | ||
196 | .ldo_voltage = false, | ||
197 | .dcofreq_min = 750000000, | ||
198 | .max_phy = 186000000, | ||
199 | }; | ||
200 | |||
201 | static int hdmi_phy_init_features(struct platform_device *pdev) | ||
113 | { | 202 | { |
114 | free_irq(phy->irq, wp); | 203 | struct hdmi_phy_features *dst; |
204 | const struct hdmi_phy_features *src; | ||
115 | 205 | ||
116 | hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF); | 206 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); |
117 | } | 207 | if (!dst) { |
208 | dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); | ||
209 | return -ENOMEM; | ||
210 | } | ||
211 | |||
212 | switch (omapdss_get_version()) { | ||
213 | case OMAPDSS_VER_OMAP4430_ES1: | ||
214 | case OMAPDSS_VER_OMAP4430_ES2: | ||
215 | case OMAPDSS_VER_OMAP4: | ||
216 | src = &omap44xx_phy_feats; | ||
217 | break; | ||
118 | 218 | ||
119 | #define PHY_OFFSET 0x300 | 219 | case OMAPDSS_VER_OMAP5: |
120 | #define PHY_SIZE 0x100 | 220 | src = &omap54xx_phy_feats; |
221 | break; | ||
222 | |||
223 | default: | ||
224 | return -ENODEV; | ||
225 | } | ||
226 | |||
227 | memcpy(dst, src, sizeof(*dst)); | ||
228 | phy_feat = dst; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
121 | 232 | ||
122 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy) | 233 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy) |
123 | { | 234 | { |
235 | int r; | ||
124 | struct resource *res; | 236 | struct resource *res; |
125 | struct resource temp_res; | 237 | |
238 | r = hdmi_phy_init_features(pdev); | ||
239 | if (r) | ||
240 | return r; | ||
126 | 241 | ||
127 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); | 242 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); |
128 | if (!res) { | 243 | if (!res) { |
129 | DSSDBG("can't get PHY mem resource by name\n"); | 244 | DSSERR("can't get PHY mem resource\n"); |
130 | /* | 245 | return -EINVAL; |
131 | * if hwmod/DT doesn't have the memory resource information | ||
132 | * split into HDMI sub blocks by name, we try again by getting | ||
133 | * the platform's first resource. this code will be removed when | ||
134 | * the driver can get the mem resources by name | ||
135 | */ | ||
136 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
137 | if (!res) { | ||
138 | DSSERR("can't get PHY mem resource\n"); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | temp_res.start = res->start + PHY_OFFSET; | ||
143 | temp_res.end = temp_res.start + PHY_SIZE - 1; | ||
144 | res = &temp_res; | ||
145 | } | 246 | } |
146 | 247 | ||
147 | phy->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | 248 | phy->base = devm_ioremap_resource(&pdev->dev, res); |
148 | if (!phy->base) { | 249 | if (IS_ERR(phy->base)) { |
149 | DSSERR("can't ioremap TX PHY\n"); | 250 | DSSERR("can't ioremap TX PHY\n"); |
150 | return -ENOMEM; | 251 | return PTR_ERR(phy->base); |
151 | } | ||
152 | |||
153 | phy->irq = platform_get_irq(pdev, 0); | ||
154 | if (phy->irq < 0) { | ||
155 | DSSERR("platform_get_irq failed\n"); | ||
156 | return -ENODEV; | ||
157 | } | 252 | } |
158 | 253 | ||
159 | return 0; | 254 | return 0; |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c index 5fc71215c303..54df12a8d744 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c | |||
@@ -23,6 +23,18 @@ | |||
23 | #define HDMI_DEFAULT_REGN 16 | 23 | #define HDMI_DEFAULT_REGN 16 |
24 | #define HDMI_DEFAULT_REGM2 1 | 24 | #define HDMI_DEFAULT_REGM2 1 |
25 | 25 | ||
26 | struct hdmi_pll_features { | ||
27 | bool sys_reset; | ||
28 | /* this is a hack, need to replace it with a better computation of M2 */ | ||
29 | bool bound_dcofreq; | ||
30 | unsigned long fint_min, fint_max; | ||
31 | u16 regm_max; | ||
32 | unsigned long dcofreq_low_min, dcofreq_low_max; | ||
33 | unsigned long dcofreq_high_min, dcofreq_high_max; | ||
34 | }; | ||
35 | |||
36 | static const struct hdmi_pll_features *pll_feat; | ||
37 | |||
26 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) | 38 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) |
27 | { | 39 | { |
28 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ | 40 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ |
@@ -57,7 +69,11 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) | |||
57 | 69 | ||
58 | refclk = clkin / pi->regn; | 70 | refclk = clkin / pi->regn; |
59 | 71 | ||
60 | pi->regm2 = HDMI_DEFAULT_REGM2; | 72 | /* temorary hack to make sure DCO freq isn't calculated too low */ |
73 | if (pll_feat->bound_dcofreq && phy <= 65000) | ||
74 | pi->regm2 = 3; | ||
75 | else | ||
76 | pi->regm2 = HDMI_DEFAULT_REGM2; | ||
61 | 77 | ||
62 | /* | 78 | /* |
63 | * multiplier is pixel_clk/ref_clk | 79 | * multiplier is pixel_clk/ref_clk |
@@ -154,7 +170,7 @@ static int hdmi_pll_config(struct hdmi_pll_data *pll) | |||
154 | static int hdmi_pll_reset(struct hdmi_pll_data *pll) | 170 | static int hdmi_pll_reset(struct hdmi_pll_data *pll) |
155 | { | 171 | { |
156 | /* SYSRESET controlled by power FSM */ | 172 | /* SYSRESET controlled by power FSM */ |
157 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3); | 173 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3); |
158 | 174 | ||
159 | /* READ 0x0 reset is in progress */ | 175 | /* READ 0x0 reset is in progress */ |
160 | if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1) | 176 | if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1) |
@@ -194,38 +210,81 @@ void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) | |||
194 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); | 210 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); |
195 | } | 211 | } |
196 | 212 | ||
197 | #define PLL_OFFSET 0x200 | 213 | static const struct hdmi_pll_features omap44xx_pll_feats = { |
198 | #define PLL_SIZE 0x100 | 214 | .sys_reset = false, |
215 | .bound_dcofreq = false, | ||
216 | .fint_min = 500000, | ||
217 | .fint_max = 2500000, | ||
218 | .regm_max = 4095, | ||
219 | .dcofreq_low_min = 500000000, | ||
220 | .dcofreq_low_max = 1000000000, | ||
221 | .dcofreq_high_min = 1000000000, | ||
222 | .dcofreq_high_max = 2000000000, | ||
223 | }; | ||
224 | |||
225 | static const struct hdmi_pll_features omap54xx_pll_feats = { | ||
226 | .sys_reset = true, | ||
227 | .bound_dcofreq = true, | ||
228 | .fint_min = 620000, | ||
229 | .fint_max = 2500000, | ||
230 | .regm_max = 2046, | ||
231 | .dcofreq_low_min = 750000000, | ||
232 | .dcofreq_low_max = 1500000000, | ||
233 | .dcofreq_high_min = 1250000000, | ||
234 | .dcofreq_high_max = 2500000000UL, | ||
235 | }; | ||
236 | |||
237 | static int hdmi_pll_init_features(struct platform_device *pdev) | ||
238 | { | ||
239 | struct hdmi_pll_features *dst; | ||
240 | const struct hdmi_pll_features *src; | ||
241 | |||
242 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | ||
243 | if (!dst) { | ||
244 | dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); | ||
245 | return -ENOMEM; | ||
246 | } | ||
247 | |||
248 | switch (omapdss_get_version()) { | ||
249 | case OMAPDSS_VER_OMAP4430_ES1: | ||
250 | case OMAPDSS_VER_OMAP4430_ES2: | ||
251 | case OMAPDSS_VER_OMAP4: | ||
252 | src = &omap44xx_pll_feats; | ||
253 | break; | ||
254 | |||
255 | case OMAPDSS_VER_OMAP5: | ||
256 | src = &omap54xx_pll_feats; | ||
257 | break; | ||
258 | |||
259 | default: | ||
260 | return -ENODEV; | ||
261 | } | ||
262 | |||
263 | memcpy(dst, src, sizeof(*dst)); | ||
264 | pll_feat = dst; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
199 | 268 | ||
200 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) | 269 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) |
201 | { | 270 | { |
271 | int r; | ||
202 | struct resource *res; | 272 | struct resource *res; |
203 | struct resource temp_res; | 273 | |
274 | r = hdmi_pll_init_features(pdev); | ||
275 | if (r) | ||
276 | return r; | ||
204 | 277 | ||
205 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); | 278 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); |
206 | if (!res) { | 279 | if (!res) { |
207 | DSSDBG("can't get PLL mem resource by name\n"); | 280 | DSSERR("can't get PLL mem resource\n"); |
208 | /* | 281 | return -EINVAL; |
209 | * if hwmod/DT doesn't have the memory resource information | ||
210 | * split into HDMI sub blocks by name, we try again by getting | ||
211 | * the platform's first resource. this code will be removed when | ||
212 | * the driver can get the mem resources by name | ||
213 | */ | ||
214 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
215 | if (!res) { | ||
216 | DSSERR("can't get PLL mem resource\n"); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | temp_res.start = res->start + PLL_OFFSET; | ||
221 | temp_res.end = temp_res.start + PLL_SIZE - 1; | ||
222 | res = &temp_res; | ||
223 | } | 282 | } |
224 | 283 | ||
225 | pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | 284 | pll->base = devm_ioremap_resource(&pdev->dev, res); |
226 | if (!pll->base) { | 285 | if (IS_ERR(pll->base)) { |
227 | DSSERR("can't ioremap PLLCTRL\n"); | 286 | DSSERR("can't ioremap PLLCTRL\n"); |
228 | return -ENOMEM; | 287 | return PTR_ERR(pll->base); |
229 | } | 288 | } |
230 | 289 | ||
231 | return 0; | 290 | return 0; |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c index f5f4ccf50d90..496327e2b21b 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c | |||
@@ -185,7 +185,7 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, | |||
185 | timings->interlace = param->timings.interlace; | 185 | timings->interlace = param->timings.interlace; |
186 | } | 186 | } |
187 | 187 | ||
188 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 188 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) |
189 | void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, | 189 | void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, |
190 | struct hdmi_audio_format *aud_fmt) | 190 | struct hdmi_audio_format *aud_fmt) |
191 | { | 191 | { |
@@ -238,37 +238,20 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable) | |||
238 | } | 238 | } |
239 | #endif | 239 | #endif |
240 | 240 | ||
241 | #define WP_SIZE 0x200 | ||
242 | |||
243 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) | 241 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) |
244 | { | 242 | { |
245 | struct resource *res; | 243 | struct resource *res; |
246 | struct resource temp_res; | ||
247 | 244 | ||
248 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp"); | 245 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp"); |
249 | if (!res) { | 246 | if (!res) { |
250 | DSSDBG("can't get WP mem resource by name\n"); | 247 | DSSERR("can't get WP mem resource\n"); |
251 | /* | 248 | return -EINVAL; |
252 | * if hwmod/DT doesn't have the memory resource information | ||
253 | * split into HDMI sub blocks by name, we try again by getting | ||
254 | * the platform's first resource. this code will be removed when | ||
255 | * the driver can get the mem resources by name | ||
256 | */ | ||
257 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
258 | if (!res) { | ||
259 | DSSERR("can't get WP mem resource\n"); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | temp_res.start = res->start; | ||
264 | temp_res.end = temp_res.start + WP_SIZE - 1; | ||
265 | res = &temp_res; | ||
266 | } | 249 | } |
267 | 250 | ||
268 | wp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | 251 | wp->base = devm_ioremap_resource(&pdev->dev, res); |
269 | if (!wp->base) { | 252 | if (IS_ERR(wp->base)) { |
270 | DSSERR("can't ioremap HDMI WP\n"); | 253 | DSSERR("can't ioremap HDMI WP\n"); |
271 | return -ENOMEM; | 254 | return PTR_ERR(wp->base); |
272 | } | 255 | } |
273 | 256 | ||
274 | return 0; | 257 | return 0; |
diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c new file mode 100644 index 000000000000..99af9e88b2d8 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c | |||
@@ -0,0 +1,229 @@ | |||
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 | |||
33 | static struct list_head dss_conv_list __initdata; | ||
34 | |||
35 | static const char prefix[] __initconst = "omapdss,"; | ||
36 | |||
37 | struct dss_conv_node { | ||
38 | struct list_head list; | ||
39 | struct device_node *node; | ||
40 | bool root; | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
55 | static 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 | |||
71 | static 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," */ | ||
91 | static 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 | |||
120 | static 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 | n->node = node; | ||
125 | n->root = root; | ||
126 | list_add(&n->list, &dss_conv_list); | ||
127 | } | ||
128 | |||
129 | static bool __init omapdss_list_contains(const struct device_node *node) | ||
130 | { | ||
131 | struct dss_conv_node *n; | ||
132 | |||
133 | list_for_each_entry(n, &dss_conv_list, list) { | ||
134 | if (n->node == node) | ||
135 | return true; | ||
136 | } | ||
137 | |||
138 | return false; | ||
139 | } | ||
140 | |||
141 | static void __init omapdss_walk_device(struct device_node *node, bool root) | ||
142 | { | ||
143 | struct device_node *n; | ||
144 | |||
145 | omapdss_add_to_list(node, root); | ||
146 | |||
147 | /* | ||
148 | * of_graph_get_remote_port_parent() prints an error if there is no | ||
149 | * port/ports node. To avoid that, check first that there's the node. | ||
150 | */ | ||
151 | n = of_get_child_by_name(node, "ports"); | ||
152 | if (!n) | ||
153 | n = of_get_child_by_name(node, "port"); | ||
154 | if (!n) | ||
155 | return; | ||
156 | |||
157 | of_node_put(n); | ||
158 | |||
159 | n = NULL; | ||
160 | while ((n = of_graph_get_next_endpoint(node, n)) != NULL) { | ||
161 | struct device_node *pn; | ||
162 | |||
163 | pn = of_graph_get_remote_port_parent(n); | ||
164 | |||
165 | if (!pn) { | ||
166 | of_node_put(n); | ||
167 | continue; | ||
168 | } | ||
169 | |||
170 | if (!of_device_is_available(pn) || omapdss_list_contains(pn)) { | ||
171 | of_node_put(pn); | ||
172 | of_node_put(n); | ||
173 | continue; | ||
174 | } | ||
175 | |||
176 | omapdss_walk_device(pn, false); | ||
177 | |||
178 | of_node_put(n); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | static const struct of_device_id omapdss_of_match[] __initconst = { | ||
183 | { .compatible = "ti,omap2-dss", }, | ||
184 | { .compatible = "ti,omap3-dss", }, | ||
185 | { .compatible = "ti,omap4-dss", }, | ||
186 | { .compatible = "ti,omap5-dss", }, | ||
187 | {}, | ||
188 | }; | ||
189 | |||
190 | static int __init omapdss_boot_init(void) | ||
191 | { | ||
192 | struct device_node *dss, *child; | ||
193 | |||
194 | INIT_LIST_HEAD(&dss_conv_list); | ||
195 | |||
196 | dss = of_find_matching_node(NULL, omapdss_of_match); | ||
197 | |||
198 | if (dss == NULL || !of_device_is_available(dss)) | ||
199 | return 0; | ||
200 | |||
201 | omapdss_walk_device(dss, true); | ||
202 | |||
203 | for_each_available_child_of_node(dss, child) { | ||
204 | if (!of_find_property(child, "compatible", NULL)) { | ||
205 | of_node_put(child); | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | omapdss_walk_device(child, true); | ||
210 | } | ||
211 | |||
212 | while (!list_empty(&dss_conv_list)) { | ||
213 | struct dss_conv_node *n; | ||
214 | |||
215 | n = list_first_entry(&dss_conv_list, struct dss_conv_node, | ||
216 | list); | ||
217 | |||
218 | if (!n->root) | ||
219 | omapdss_omapify_node(n->node); | ||
220 | |||
221 | list_del(&n->list); | ||
222 | of_node_put(n->node); | ||
223 | kfree(n); | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | subsys_initcall(omapdss_boot_init); | ||
diff --git a/drivers/video/fbdev/omap2/dss/venc_panel.c b/drivers/video/fbdev/omap2/dss/venc_panel.c deleted file mode 100644 index af68cd444d7e..000000000000 --- a/drivers/video/fbdev/omap2/dss/venc_panel.c +++ /dev/null | |||
@@ -1,232 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * VENC panel driver | ||
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/err.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <video/omapdss.h> | ||
27 | |||
28 | #include "dss.h" | ||
29 | |||
30 | static struct { | ||
31 | struct mutex lock; | ||
32 | } venc_panel; | ||
33 | |||
34 | static ssize_t display_output_type_show(struct device *dev, | ||
35 | struct device_attribute *attr, char *buf) | ||
36 | { | ||
37 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
38 | const char *ret; | ||
39 | |||
40 | switch (dssdev->phy.venc.type) { | ||
41 | case OMAP_DSS_VENC_TYPE_COMPOSITE: | ||
42 | ret = "composite"; | ||
43 | break; | ||
44 | case OMAP_DSS_VENC_TYPE_SVIDEO: | ||
45 | ret = "svideo"; | ||
46 | break; | ||
47 | default: | ||
48 | return -EINVAL; | ||
49 | } | ||
50 | |||
51 | return snprintf(buf, PAGE_SIZE, "%s\n", ret); | ||
52 | } | ||
53 | |||
54 | static ssize_t display_output_type_store(struct device *dev, | ||
55 | struct device_attribute *attr, const char *buf, size_t size) | ||
56 | { | ||
57 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
58 | enum omap_dss_venc_type new_type; | ||
59 | |||
60 | if (sysfs_streq("composite", buf)) | ||
61 | new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; | ||
62 | else if (sysfs_streq("svideo", buf)) | ||
63 | new_type = OMAP_DSS_VENC_TYPE_SVIDEO; | ||
64 | else | ||
65 | return -EINVAL; | ||
66 | |||
67 | mutex_lock(&venc_panel.lock); | ||
68 | |||
69 | if (dssdev->phy.venc.type != new_type) { | ||
70 | dssdev->phy.venc.type = new_type; | ||
71 | omapdss_venc_set_type(dssdev, new_type); | ||
72 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
73 | omapdss_venc_display_disable(dssdev); | ||
74 | omapdss_venc_display_enable(dssdev); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | mutex_unlock(&venc_panel.lock); | ||
79 | |||
80 | return size; | ||
81 | } | ||
82 | |||
83 | static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, | ||
84 | display_output_type_show, display_output_type_store); | ||
85 | |||
86 | static int venc_panel_probe(struct omap_dss_device *dssdev) | ||
87 | { | ||
88 | /* set default timings to PAL */ | ||
89 | const struct omap_video_timings default_timings = { | ||
90 | .x_res = 720, | ||
91 | .y_res = 574, | ||
92 | .pixelclock = 13500000, | ||
93 | .hsw = 64, | ||
94 | .hfp = 12, | ||
95 | .hbp = 68, | ||
96 | .vsw = 5, | ||
97 | .vfp = 5, | ||
98 | .vbp = 41, | ||
99 | |||
100 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
101 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
102 | |||
103 | .interlace = true, | ||
104 | }; | ||
105 | |||
106 | mutex_init(&venc_panel.lock); | ||
107 | |||
108 | dssdev->panel.timings = default_timings; | ||
109 | |||
110 | return device_create_file(dssdev->dev, &dev_attr_output_type); | ||
111 | } | ||
112 | |||
113 | static void venc_panel_remove(struct omap_dss_device *dssdev) | ||
114 | { | ||
115 | device_remove_file(dssdev->dev, &dev_attr_output_type); | ||
116 | } | ||
117 | |||
118 | static int venc_panel_enable(struct omap_dss_device *dssdev) | ||
119 | { | ||
120 | int r; | ||
121 | |||
122 | dev_dbg(dssdev->dev, "venc_panel_enable\n"); | ||
123 | |||
124 | mutex_lock(&venc_panel.lock); | ||
125 | |||
126 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
127 | r = -EINVAL; | ||
128 | goto err; | ||
129 | } | ||
130 | |||
131 | omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); | ||
132 | omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); | ||
133 | omapdss_venc_invert_vid_out_polarity(dssdev, | ||
134 | dssdev->phy.venc.invert_polarity); | ||
135 | |||
136 | r = omapdss_venc_display_enable(dssdev); | ||
137 | if (r) | ||
138 | goto err; | ||
139 | |||
140 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
141 | |||
142 | mutex_unlock(&venc_panel.lock); | ||
143 | |||
144 | return 0; | ||
145 | err: | ||
146 | mutex_unlock(&venc_panel.lock); | ||
147 | |||
148 | return r; | ||
149 | } | ||
150 | |||
151 | static void venc_panel_disable(struct omap_dss_device *dssdev) | ||
152 | { | ||
153 | dev_dbg(dssdev->dev, "venc_panel_disable\n"); | ||
154 | |||
155 | mutex_lock(&venc_panel.lock); | ||
156 | |||
157 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | ||
158 | goto end; | ||
159 | |||
160 | omapdss_venc_display_disable(dssdev); | ||
161 | |||
162 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
163 | end: | ||
164 | mutex_unlock(&venc_panel.lock); | ||
165 | } | ||
166 | |||
167 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, | ||
168 | struct omap_video_timings *timings) | ||
169 | { | ||
170 | dev_dbg(dssdev->dev, "venc_panel_set_timings\n"); | ||
171 | |||
172 | mutex_lock(&venc_panel.lock); | ||
173 | |||
174 | omapdss_venc_set_timings(dssdev, timings); | ||
175 | dssdev->panel.timings = *timings; | ||
176 | |||
177 | mutex_unlock(&venc_panel.lock); | ||
178 | } | ||
179 | |||
180 | static int venc_panel_check_timings(struct omap_dss_device *dssdev, | ||
181 | struct omap_video_timings *timings) | ||
182 | { | ||
183 | dev_dbg(dssdev->dev, "venc_panel_check_timings\n"); | ||
184 | |||
185 | return omapdss_venc_check_timings(dssdev, timings); | ||
186 | } | ||
187 | |||
188 | static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) | ||
189 | { | ||
190 | dev_dbg(dssdev->dev, "venc_panel_get_wss\n"); | ||
191 | |||
192 | return omapdss_venc_get_wss(dssdev); | ||
193 | } | ||
194 | |||
195 | static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) | ||
196 | { | ||
197 | dev_dbg(dssdev->dev, "venc_panel_set_wss\n"); | ||
198 | |||
199 | return omapdss_venc_set_wss(dssdev, wss); | ||
200 | } | ||
201 | |||
202 | static struct omap_dss_driver venc_driver = { | ||
203 | .probe = venc_panel_probe, | ||
204 | .remove = venc_panel_remove, | ||
205 | |||
206 | .enable = venc_panel_enable, | ||
207 | .disable = venc_panel_disable, | ||
208 | |||
209 | .get_resolution = omapdss_default_get_resolution, | ||
210 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
211 | |||
212 | .set_timings = venc_panel_set_timings, | ||
213 | .check_timings = venc_panel_check_timings, | ||
214 | |||
215 | .get_wss = venc_panel_get_wss, | ||
216 | .set_wss = venc_panel_set_wss, | ||
217 | |||
218 | .driver = { | ||
219 | .name = "venc", | ||
220 | .owner = THIS_MODULE, | ||
221 | }, | ||
222 | }; | ||
223 | |||
224 | int venc_panel_init(void) | ||
225 | { | ||
226 | return omap_dss_register_driver(&venc_driver); | ||
227 | } | ||
228 | |||
229 | void venc_panel_exit(void) | ||
230 | { | ||
231 | omap_dss_unregister_driver(&venc_driver); | ||
232 | } | ||