blob: 49f104e7d1d09c46196e846e2e739d134f9db47a [file] [log] [blame]
Mythri P Kc3198a52011-03-12 12:04:27 +05301/*
2 * hdmi.c
3 *
4 * HDMI interface DSS driver setting for TI's OMAP4 family of processor.
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
6 * Authors: Yong Zhi
7 * Mythri pk <mythripk@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "HDMI"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/interrupt.h>
29#include <linux/mutex.h>
30#include <linux/delay.h>
31#include <linux/string.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030032#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030033#include <linux/pm_runtime.h>
34#include <linux/clk.h>
Tomi Valkeinencca35012012-04-26 14:48:32 +030035#include <linux/gpio.h>
Tomi Valkeinen17486942012-08-15 15:55:04 +030036#include <linux/regulator/consumer.h>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030037#include <video/omapdss.h>
Mythri P Kc3198a52011-03-12 12:04:27 +053038
Mythri P K94c52982011-09-08 19:06:21 +053039#include "ti_hdmi.h"
Mythri P Kc3198a52011-03-12 12:04:27 +053040#include "dss.h"
Ricardo Neriad44cc32011-05-18 22:31:56 -050041#include "dss_features.h"
Mythri P Kc3198a52011-03-12 12:04:27 +053042
Mythri P K95a8aeb2011-09-08 19:06:18 +053043#define HDMI_WP 0x0
44#define HDMI_CORE_SYS 0x400
45#define HDMI_CORE_AV 0x900
46#define HDMI_PLLCTRL 0x200
47#define HDMI_PHY 0x300
48
Mythri P K7c1f1ec2011-09-08 19:06:22 +053049/* HDMI EDID Length move this */
50#define HDMI_EDID_MAX_LENGTH 256
51#define EDID_TIMING_DESCRIPTOR_SIZE 0x12
52#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36
53#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80
54#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
55#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
56
Tomi Valkeinenb44e4582011-08-22 13:16:24 +030057#define HDMI_DEFAULT_REGN 16
Tomi Valkeinen8d88767a2011-08-22 13:02:52 +030058#define HDMI_DEFAULT_REGM2 1
59
Mythri P Kc3198a52011-03-12 12:04:27 +053060static struct {
61 struct mutex lock;
Mythri P Kc3198a52011-03-12 12:04:27 +053062 struct platform_device *pdev;
Ricardo Neri14840b92012-11-06 00:19:17 -060063#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
64 struct platform_device *audio_pdev;
65#endif
Ricardo Neri66a06b02012-11-06 00:19:14 -060066
Mythri P K95a8aeb2011-09-08 19:06:18 +053067 struct hdmi_ip_data ip_data;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030068
69 struct clk *sys_clk;
Tomi Valkeinen17486942012-08-15 15:55:04 +030070 struct regulator *vdda_hdmi_dac_reg;
Tomi Valkeinencca35012012-04-26 14:48:32 +030071
72 int ct_cp_hpd_gpio;
73 int ls_oe_gpio;
74 int hpd_gpio;
Archit Taneja81b87f52012-09-26 16:30:49 +053075
76 struct omap_dss_output output;
Mythri P Kc3198a52011-03-12 12:04:27 +053077} hdmi;
78
79/*
80 * Logic for the below structure :
81 * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
82 * There is a correspondence between CEA/VESA timing and code, please
83 * refer to section 6.3 in HDMI 1.3 specification for timing code.
84 *
85 * In the below structure, cea_vesa_timings corresponds to all OMAP4
86 * supported CEA and VESA timing values.code_cea corresponds to the CEA
87 * code, It is used to get the timing from cea_vesa_timing array.Similarly
88 * with code_vesa. Code_index is used for back mapping, that is once EDID
89 * is read from the TV, EDID is parsed to find the timing values and then
90 * map it to corresponding CEA or VESA index.
91 */
92
Mythri P K46095b22012-01-06 17:52:09 +053093static const struct hdmi_config cea_timings[] = {
Archit Tanejacc937e52012-06-24 13:08:10 +053094 {
95 { 640, 480, 25200, 96, 16, 48, 2, 10, 33,
96 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
97 false, },
98 { 1, HDMI_HDMI },
99 },
100 {
101 { 720, 480, 27027, 62, 16, 60, 6, 9, 30,
102 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
103 false, },
104 { 2, HDMI_HDMI },
105 },
106 {
107 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
108 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
109 false, },
110 { 4, HDMI_HDMI },
111 },
112 {
113 { 1920, 540, 74250, 44, 88, 148, 5, 2, 15,
114 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
115 true, },
116 { 5, HDMI_HDMI },
117 },
118 {
119 { 1440, 240, 27027, 124, 38, 114, 3, 4, 15,
120 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
121 true, },
122 { 6, HDMI_HDMI },
123 },
124 {
125 { 1920, 1080, 148500, 44, 88, 148, 5, 4, 36,
126 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
127 false, },
128 { 16, HDMI_HDMI },
129 },
130 {
131 { 720, 576, 27000, 64, 12, 68, 5, 5, 39,
132 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
133 false, },
134 { 17, HDMI_HDMI },
135 },
136 {
137 { 1280, 720, 74250, 40, 440, 220, 5, 5, 20,
138 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
139 false, },
140 { 19, HDMI_HDMI },
141 },
142 {
143 { 1920, 540, 74250, 44, 528, 148, 5, 2, 15,
144 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
145 true, },
146 { 20, HDMI_HDMI },
147 },
148 {
149 { 1440, 288, 27000, 126, 24, 138, 3, 2, 19,
150 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
151 true, },
152 { 21, HDMI_HDMI },
153 },
154 {
155 { 1440, 576, 54000, 128, 24, 136, 5, 5, 39,
156 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
157 false, },
158 { 29, HDMI_HDMI },
159 },
160 {
161 { 1920, 1080, 148500, 44, 528, 148, 5, 4, 36,
162 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
163 false, },
164 { 31, HDMI_HDMI },
165 },
166 {
167 { 1920, 1080, 74250, 44, 638, 148, 5, 4, 36,
168 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
169 false, },
170 { 32, HDMI_HDMI },
171 },
172 {
173 { 2880, 480, 108108, 248, 64, 240, 6, 9, 30,
174 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
175 false, },
176 { 35, HDMI_HDMI },
177 },
178 {
179 { 2880, 576, 108000, 256, 48, 272, 5, 5, 39,
180 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
181 false, },
182 { 37, HDMI_HDMI },
183 },
Mythri P K46095b22012-01-06 17:52:09 +0530184};
Archit Tanejacc937e52012-06-24 13:08:10 +0530185
Mythri P K46095b22012-01-06 17:52:09 +0530186static const struct hdmi_config vesa_timings[] = {
Mythri P Ka05ce782012-01-06 17:52:08 +0530187/* VESA From Here */
Archit Tanejacc937e52012-06-24 13:08:10 +0530188 {
189 { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
190 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
191 false, },
192 { 4, HDMI_DVI },
193 },
194 {
195 { 800, 600, 40000, 128, 40, 88, 4, 1, 23,
196 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
197 false, },
198 { 9, HDMI_DVI },
199 },
200 {
201 { 848, 480, 33750, 112, 16, 112, 8, 6, 23,
202 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
203 false, },
204 { 0xE, HDMI_DVI },
205 },
206 {
207 { 1280, 768, 79500, 128, 64, 192, 7, 3, 20,
208 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
209 false, },
210 { 0x17, HDMI_DVI },
211 },
212 {
213 { 1280, 800, 83500, 128, 72, 200, 6, 3, 22,
214 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
215 false, },
216 { 0x1C, HDMI_DVI },
217 },
218 {
219 { 1360, 768, 85500, 112, 64, 256, 6, 3, 18,
220 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
221 false, },
222 { 0x27, HDMI_DVI },
223 },
224 {
225 { 1280, 960, 108000, 112, 96, 312, 3, 1, 36,
226 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
227 false, },
228 { 0x20, HDMI_DVI },
229 },
230 {
231 { 1280, 1024, 108000, 112, 48, 248, 3, 1, 38,
232 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
233 false, },
234 { 0x23, HDMI_DVI },
235 },
236 {
237 { 1024, 768, 65000, 136, 24, 160, 6, 3, 29,
238 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
239 false, },
240 { 0x10, HDMI_DVI },
241 },
242 {
243 { 1400, 1050, 121750, 144, 88, 232, 4, 3, 32,
244 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
245 false, },
246 { 0x2A, HDMI_DVI },
247 },
248 {
249 { 1440, 900, 106500, 152, 80, 232, 6, 3, 25,
250 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
251 false, },
252 { 0x2F, HDMI_DVI },
253 },
254 {
255 { 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30,
256 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
257 false, },
258 { 0x3A, HDMI_DVI },
259 },
260 {
261 { 1366, 768, 85500, 143, 70, 213, 3, 3, 24,
262 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
263 false, },
264 { 0x51, HDMI_DVI },
265 },
266 {
267 { 1920, 1080, 148500, 44, 148, 80, 5, 4, 36,
268 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
269 false, },
270 { 0x52, HDMI_DVI },
271 },
272 {
273 { 1280, 768, 68250, 32, 48, 80, 7, 3, 12,
274 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
275 false, },
276 { 0x16, HDMI_DVI },
277 },
278 {
279 { 1400, 1050, 101000, 32, 48, 80, 4, 3, 23,
280 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
281 false, },
282 { 0x29, HDMI_DVI },
283 },
284 {
285 { 1680, 1050, 119000, 32, 48, 80, 6, 3, 21,
286 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
287 false, },
288 { 0x39, HDMI_DVI },
289 },
290 {
291 { 1280, 800, 79500, 32, 48, 80, 6, 3, 14,
292 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
293 false, },
294 { 0x1B, HDMI_DVI },
295 },
296 {
297 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
298 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
299 false, },
300 { 0x55, HDMI_DVI },
301 },
Tomi Valkeinen7a7ce2c2012-10-24 11:55:39 +0300302 {
303 { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26,
304 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
305 false, },
306 { 0x44, HDMI_DVI },
307 },
Mythri P Kc3198a52011-03-12 12:04:27 +0530308};
309
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300310static int hdmi_runtime_get(void)
311{
312 int r;
313
314 DSSDBG("hdmi_runtime_get\n");
315
316 r = pm_runtime_get_sync(&hdmi.pdev->dev);
317 WARN_ON(r < 0);
Archit Tanejaa247ce782012-02-10 11:45:52 +0530318 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +0200319 return r;
Archit Tanejaa247ce782012-02-10 11:45:52 +0530320
321 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300322}
323
324static void hdmi_runtime_put(void)
325{
326 int r;
327
328 DSSDBG("hdmi_runtime_put\n");
329
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200330 r = pm_runtime_put_sync(&hdmi.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300331 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300332}
333
Tomi Valkeinen9d8232a2012-03-01 16:58:39 +0200334static int __init hdmi_init_display(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530335{
Tomi Valkeinencca35012012-04-26 14:48:32 +0300336 int r;
337
338 struct gpio gpios[] = {
339 { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" },
340 { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" },
341 { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" },
342 };
343
Mythri P Kc3198a52011-03-12 12:04:27 +0530344 DSSDBG("init_display\n");
345
Tomi Valkeinenb2c7d542012-10-18 13:46:29 +0300346 dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version());
Tomi Valkeinencca35012012-04-26 14:48:32 +0300347
Tomi Valkeinen17486942012-08-15 15:55:04 +0300348 if (hdmi.vdda_hdmi_dac_reg == NULL) {
349 struct regulator *reg;
350
351 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
352
Tomi Valkeinen76eed4b2012-11-05 13:41:25 +0200353 /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
354 if (IS_ERR(reg))
355 reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
356
Tomi Valkeinen17486942012-08-15 15:55:04 +0300357 if (IS_ERR(reg)) {
358 DSSERR("can't get VDDA_HDMI_DAC regulator\n");
359 return PTR_ERR(reg);
360 }
361
362 hdmi.vdda_hdmi_dac_reg = reg;
363 }
364
Tomi Valkeinencca35012012-04-26 14:48:32 +0300365 r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
366 if (r)
367 return r;
368
Mythri P Kc3198a52011-03-12 12:04:27 +0530369 return 0;
370}
371
Ricardo Neri37584762012-11-06 21:37:14 -0600372static void hdmi_uninit_display(struct omap_dss_device *dssdev)
Tomi Valkeinencca35012012-04-26 14:48:32 +0300373{
374 DSSDBG("uninit_display\n");
375
376 gpio_free(hdmi.ct_cp_hpd_gpio);
377 gpio_free(hdmi.ls_oe_gpio);
378 gpio_free(hdmi.hpd_gpio);
379}
380
Mythri P K46095b22012-01-06 17:52:09 +0530381static const struct hdmi_config *hdmi_find_timing(
382 const struct hdmi_config *timings_arr,
383 int len)
Mythri P Kc3198a52011-03-12 12:04:27 +0530384{
Mythri P K46095b22012-01-06 17:52:09 +0530385 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530386
Mythri P K46095b22012-01-06 17:52:09 +0530387 for (i = 0; i < len; i++) {
Mythri P K9e4ed602012-01-06 17:52:10 +0530388 if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code)
Mythri P K46095b22012-01-06 17:52:09 +0530389 return &timings_arr[i];
Mythri P Kc3198a52011-03-12 12:04:27 +0530390 }
Mythri P K46095b22012-01-06 17:52:09 +0530391 return NULL;
392}
393
394static const struct hdmi_config *hdmi_get_timings(void)
395{
396 const struct hdmi_config *arr;
397 int len;
398
Mythri P K9e4ed602012-01-06 17:52:10 +0530399 if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) {
Mythri P K46095b22012-01-06 17:52:09 +0530400 arr = vesa_timings;
401 len = ARRAY_SIZE(vesa_timings);
402 } else {
403 arr = cea_timings;
404 len = ARRAY_SIZE(cea_timings);
405 }
406
407 return hdmi_find_timing(arr, len);
408}
409
410static bool hdmi_timings_compare(struct omap_video_timings *timing1,
Archit Tanejacc937e52012-06-24 13:08:10 +0530411 const struct omap_video_timings *timing2)
Mythri P K46095b22012-01-06 17:52:09 +0530412{
413 int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
414
Tomi Valkeinenf236b892012-10-24 11:55:54 +0300415 if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) ==
416 DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) &&
Mythri P K46095b22012-01-06 17:52:09 +0530417 (timing2->x_res == timing1->x_res) &&
418 (timing2->y_res == timing1->y_res)) {
419
420 timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
421 timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
422 timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
423 timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
424
425 DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
426 "timing2_hsync = %d timing2_vsync = %d\n",
427 timing1_hsync, timing1_vsync,
428 timing2_hsync, timing2_vsync);
429
430 if ((timing1_hsync == timing2_hsync) &&
431 (timing1_vsync == timing2_vsync)) {
432 return true;
433 }
434 }
435 return false;
Mythri P Kc3198a52011-03-12 12:04:27 +0530436}
437
438static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
439{
Mythri P K46095b22012-01-06 17:52:09 +0530440 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530441 struct hdmi_cm cm = {-1};
442 DSSDBG("hdmi_get_code\n");
443
Mythri P K46095b22012-01-06 17:52:09 +0530444 for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
445 if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
446 cm = cea_timings[i].cm;
447 goto end;
448 }
449 }
450 for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
451 if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
452 cm = vesa_timings[i].cm;
453 goto end;
Mythri P Kc3198a52011-03-12 12:04:27 +0530454 }
455 }
456
Mythri P K46095b22012-01-06 17:52:09 +0530457end: return cm;
Mythri P Kc3198a52011-03-12 12:04:27 +0530458
Mythri P Kc3198a52011-03-12 12:04:27 +0530459}
460
Archit Tanejac3dc6a72011-09-13 18:28:41 +0530461unsigned long hdmi_get_pixel_clock(void)
462{
463 /* HDMI Pixel Clock in Mhz */
Mythri P Ka05ce782012-01-06 17:52:08 +0530464 return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
Archit Tanejac3dc6a72011-09-13 18:28:41 +0530465}
466
Archit Taneja6cb07b22011-04-12 13:52:25 +0530467static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
468 struct hdmi_pll_info *pi)
Mythri P Kc3198a52011-03-12 12:04:27 +0530469{
Archit Taneja6cb07b22011-04-12 13:52:25 +0530470 unsigned long clkin, refclk;
Mythri P Kc3198a52011-03-12 12:04:27 +0530471 u32 mf;
472
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300473 clkin = clk_get_rate(hdmi.sys_clk) / 10000;
Mythri P Kc3198a52011-03-12 12:04:27 +0530474 /*
475 * Input clock is predivided by N + 1
476 * out put of which is reference clk
477 */
Tomi Valkeinen8d88767a2011-08-22 13:02:52 +0300478 if (dssdev->clocks.hdmi.regn == 0)
479 pi->regn = HDMI_DEFAULT_REGN;
480 else
481 pi->regn = dssdev->clocks.hdmi.regn;
482
Tomi Valkeinenb44e4582011-08-22 13:16:24 +0300483 refclk = clkin / pi->regn;
Mythri P Kc3198a52011-03-12 12:04:27 +0530484
Tomi Valkeinen8d88767a2011-08-22 13:02:52 +0300485 if (dssdev->clocks.hdmi.regm2 == 0)
486 pi->regm2 = HDMI_DEFAULT_REGM2;
487 else
488 pi->regm2 = dssdev->clocks.hdmi.regm2;
Mythri P Kc3198a52011-03-12 12:04:27 +0530489
490 /*
Mythri P Kdd2116a2012-02-21 12:10:58 +0530491 * multiplier is pixel_clk/ref_clk
492 * Multiplying by 100 to avoid fractional part removal
493 */
494 pi->regm = phy * pi->regm2 / refclk;
495
496 /*
Mythri P Kc3198a52011-03-12 12:04:27 +0530497 * fractional multiplier is remainder of the difference between
498 * multiplier and actual phy(required pixel clock thus should be
499 * multiplied by 2^18(262144) divided by the reference clock
500 */
Mythri P Kdd2116a2012-02-21 12:10:58 +0530501 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
502 pi->regmf = pi->regm2 * mf / refclk;
Mythri P Kc3198a52011-03-12 12:04:27 +0530503
504 /*
505 * Dcofreq should be set to 1 if required pixel clock
506 * is greater than 1000MHz
507 */
508 pi->dcofreq = phy > 1000 * 100;
Tomi Valkeinenb44e4582011-08-22 13:16:24 +0300509 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
Mythri P Kc3198a52011-03-12 12:04:27 +0530510
Mythri P K7b27da52011-09-08 19:06:19 +0530511 /* Set the reference clock to sysclk reference */
512 pi->refsel = HDMI_REFSEL_SYSCLK;
513
Mythri P Kc3198a52011-03-12 12:04:27 +0530514 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
515 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
516}
517
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300518static int hdmi_power_on_core(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530519{
Mythri P K46095b22012-01-06 17:52:09 +0530520 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +0530521
Tomi Valkeinencca35012012-04-26 14:48:32 +0300522 gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
523 gpio_set_value(hdmi.ls_oe_gpio, 1);
524
Tomi Valkeinena84b20654b2012-04-26 14:58:41 +0300525 /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
526 udelay(300);
527
Tomi Valkeinen17486942012-08-15 15:55:04 +0300528 r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
529 if (r)
530 goto err_vdac_enable;
531
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300532 r = hdmi_runtime_get();
533 if (r)
Tomi Valkeinencca35012012-04-26 14:48:32 +0300534 goto err_runtime_get;
Mythri P Kc3198a52011-03-12 12:04:27 +0530535
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300536 /* Make selection of HDMI in DSS */
537 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
538
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300539 return 0;
540
541err_runtime_get:
542 regulator_disable(hdmi.vdda_hdmi_dac_reg);
543err_vdac_enable:
544 gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
545 gpio_set_value(hdmi.ls_oe_gpio, 0);
546 return r;
547}
548
549static void hdmi_power_off_core(struct omap_dss_device *dssdev)
550{
551 hdmi_runtime_put();
552 regulator_disable(hdmi.vdda_hdmi_dac_reg);
553 gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
554 gpio_set_value(hdmi.ls_oe_gpio, 0);
555}
556
557static int hdmi_power_on_full(struct omap_dss_device *dssdev)
558{
559 int r;
560 struct omap_video_timings *p;
561 struct omap_overlay_manager *mgr = dssdev->output->manager;
562 unsigned long phy;
563
564 r = hdmi_power_on_core(dssdev);
565 if (r)
566 return r;
567
Archit Tanejacea87b92012-09-07 17:56:20 +0530568 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530569
Archit Taneja78493982012-08-08 16:50:42 +0530570 p = &hdmi.ip_data.cfg.timings;
Mythri P Kc3198a52011-03-12 12:04:27 +0530571
Archit Taneja78493982012-08-08 16:50:42 +0530572 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
Mythri P Kc3198a52011-03-12 12:04:27 +0530573
Mythri P Kc3198a52011-03-12 12:04:27 +0530574 phy = p->pixel_clock;
575
Mythri P K7b27da52011-09-08 19:06:19 +0530576 hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530577
Ricardo Neric0456be2012-04-27 13:48:45 -0500578 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530579
Mythri P K95a8aeb2011-09-08 19:06:18 +0530580 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
Mythri P K60634a22011-09-08 19:06:26 +0530581 r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530582 if (r) {
583 DSSDBG("Failed to lock PLL\n");
Tomi Valkeinencca35012012-04-26 14:48:32 +0300584 goto err_pll_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530585 }
586
Mythri P K60634a22011-09-08 19:06:26 +0530587 r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530588 if (r) {
589 DSSDBG("Failed to start PHY\n");
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500590 goto err_phy_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530591 }
592
Mythri P K60634a22011-09-08 19:06:26 +0530593 hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530594
Mythri P Kc3198a52011-03-12 12:04:27 +0530595 /* bypass TV gamma table */
596 dispc_enable_gamma_table(0);
597
598 /* tv size */
Archit Tanejacea87b92012-09-07 17:56:20 +0530599 dss_mgr_set_timings(mgr, p);
Mythri P Kc3198a52011-03-12 12:04:27 +0530600
Ricardo Neric0456be2012-04-27 13:48:45 -0500601 r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
602 if (r)
603 goto err_vid_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530604
Archit Tanejacea87b92012-09-07 17:56:20 +0530605 r = dss_mgr_enable(mgr);
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200606 if (r)
607 goto err_mgr_enable;
Tomi Valkeinen3870c902011-08-31 14:47:11 +0300608
Mythri P Kc3198a52011-03-12 12:04:27 +0530609 return 0;
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200610
611err_mgr_enable:
Ricardo Neric0456be2012-04-27 13:48:45 -0500612 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
613err_vid_enable:
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200614 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500615err_phy_enable:
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200616 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300617err_pll_enable:
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300618 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530619 return -EIO;
620}
621
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300622static void hdmi_power_off_full(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530623{
Archit Tanejacea87b92012-09-07 17:56:20 +0530624 struct omap_overlay_manager *mgr = dssdev->output->manager;
625
626 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530627
Ricardo Neric0456be2012-04-27 13:48:45 -0500628 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
Mythri P K60634a22011-09-08 19:06:26 +0530629 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
630 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300631
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300632 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530633}
634
635int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
636 struct omap_video_timings *timings)
637{
638 struct hdmi_cm cm;
639
640 cm = hdmi_get_code(timings);
641 if (cm.code == -1) {
Mythri P Kc3198a52011-03-12 12:04:27 +0530642 return -EINVAL;
643 }
644
645 return 0;
646
647}
648
Archit Taneja78493982012-08-08 16:50:42 +0530649void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
650 struct omap_video_timings *timings)
Mythri P Kc3198a52011-03-12 12:04:27 +0530651{
652 struct hdmi_cm cm;
Archit Taneja78493982012-08-08 16:50:42 +0530653 const struct hdmi_config *t;
Mythri P Kc3198a52011-03-12 12:04:27 +0530654
Archit Tanejaed1aa902012-08-15 00:40:31 +0530655 mutex_lock(&hdmi.lock);
656
Archit Taneja78493982012-08-08 16:50:42 +0530657 cm = hdmi_get_code(timings);
658 hdmi.ip_data.cfg.cm = cm;
659
660 t = hdmi_get_timings();
661 if (t != NULL)
662 hdmi.ip_data.cfg = *t;
Tomi Valkeinenfa70dc52011-08-22 14:57:33 +0300663
Archit Tanejaed1aa902012-08-15 00:40:31 +0530664 mutex_unlock(&hdmi.lock);
Mythri P Kc3198a52011-03-12 12:04:27 +0530665}
666
Tomi Valkeinene40402c2012-03-02 18:01:07 +0200667static void hdmi_dump_regs(struct seq_file *s)
Mythri P K162874d2011-09-22 13:37:45 +0530668{
669 mutex_lock(&hdmi.lock);
670
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800671 if (hdmi_runtime_get()) {
672 mutex_unlock(&hdmi.lock);
Mythri P K162874d2011-09-22 13:37:45 +0530673 return;
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800674 }
Mythri P K162874d2011-09-22 13:37:45 +0530675
676 hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s);
677 hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s);
678 hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s);
679 hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s);
680
681 hdmi_runtime_put();
682 mutex_unlock(&hdmi.lock);
683}
684
Tomi Valkeinen47024562011-08-25 17:12:56 +0300685int omapdss_hdmi_read_edid(u8 *buf, int len)
686{
687 int r;
688
689 mutex_lock(&hdmi.lock);
690
691 r = hdmi_runtime_get();
692 BUG_ON(r);
693
694 r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len);
695
696 hdmi_runtime_put();
697 mutex_unlock(&hdmi.lock);
698
699 return r;
700}
701
Tomi Valkeinen759593f2011-08-29 18:10:20 +0300702bool omapdss_hdmi_detect(void)
703{
704 int r;
705
706 mutex_lock(&hdmi.lock);
707
708 r = hdmi_runtime_get();
709 BUG_ON(r);
710
711 r = hdmi.ip_data.ops->detect(&hdmi.ip_data);
712
713 hdmi_runtime_put();
714 mutex_unlock(&hdmi.lock);
715
716 return r == 1;
717}
718
Mythri P Kc3198a52011-03-12 12:04:27 +0530719int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
720{
Archit Tanejacea87b92012-09-07 17:56:20 +0530721 struct omap_dss_output *out = dssdev->output;
Mythri P Kc3198a52011-03-12 12:04:27 +0530722 int r = 0;
723
724 DSSDBG("ENTER hdmi_display_enable\n");
725
726 mutex_lock(&hdmi.lock);
727
Archit Tanejacea87b92012-09-07 17:56:20 +0530728 if (out == NULL || out->manager == NULL) {
729 DSSERR("failed to enable display: no output/manager\n");
Tomi Valkeinen05e1d602011-06-23 16:38:21 +0300730 r = -ENODEV;
731 goto err0;
732 }
733
Tomi Valkeinencca35012012-04-26 14:48:32 +0300734 hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
Tomi Valkeinenc49d0052012-01-17 11:09:57 +0200735
Mythri P Kc3198a52011-03-12 12:04:27 +0530736 r = omap_dss_start_device(dssdev);
737 if (r) {
738 DSSERR("failed to start device\n");
739 goto err0;
740 }
741
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300742 r = hdmi_power_on_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530743 if (r) {
744 DSSERR("failed to power on device\n");
Tomi Valkeinencca35012012-04-26 14:48:32 +0300745 goto err1;
Mythri P Kc3198a52011-03-12 12:04:27 +0530746 }
747
748 mutex_unlock(&hdmi.lock);
749 return 0;
750
Mythri P Kc3198a52011-03-12 12:04:27 +0530751err1:
752 omap_dss_stop_device(dssdev);
753err0:
754 mutex_unlock(&hdmi.lock);
755 return r;
756}
757
758void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
759{
760 DSSDBG("Enter hdmi_display_disable\n");
761
762 mutex_lock(&hdmi.lock);
763
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300764 hdmi_power_off_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530765
Mythri P Kc3198a52011-03-12 12:04:27 +0530766 omap_dss_stop_device(dssdev);
767
768 mutex_unlock(&hdmi.lock);
769}
770
Tomi Valkeinen44898232012-10-19 17:42:27 +0300771int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev)
772{
773 int r = 0;
774
775 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
776
777 mutex_lock(&hdmi.lock);
778
779 hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
780
781 r = hdmi_power_on_core(dssdev);
782 if (r) {
783 DSSERR("failed to power on device\n");
784 goto err0;
785 }
786
787 mutex_unlock(&hdmi.lock);
788 return 0;
789
790err0:
791 mutex_unlock(&hdmi.lock);
792 return r;
793}
794
795void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev)
796{
797 DSSDBG("Enter omapdss_hdmi_core_disable\n");
798
799 mutex_lock(&hdmi.lock);
800
801 hdmi_power_off_core(dssdev);
802
803 mutex_unlock(&hdmi.lock);
804}
805
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300806static int hdmi_get_clocks(struct platform_device *pdev)
807{
808 struct clk *clk;
809
810 clk = clk_get(&pdev->dev, "sys_clk");
811 if (IS_ERR(clk)) {
812 DSSERR("can't get sys_clk\n");
813 return PTR_ERR(clk);
814 }
815
816 hdmi.sys_clk = clk;
817
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300818 return 0;
819}
820
821static void hdmi_put_clocks(void)
822{
823 if (hdmi.sys_clk)
824 clk_put(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300825}
826
Ricardo Neri35547622012-03-20 21:02:01 -0600827#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
Ricardo Neri14840b92012-11-06 00:19:17 -0600828static int hdmi_probe_audio(struct platform_device *pdev)
829{
830 struct resource *res;
831 struct platform_device *aud_pdev;
832 u32 port_offset, port_size;
833 struct resource aud_res[2] = {
834 DEFINE_RES_MEM(-1, -1),
835 DEFINE_RES_DMA(-1),
836 };
837
838 res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
839 if (!res) {
840 DSSERR("can't get IORESOURCE_MEM HDMI\n");
841 return -EINVAL;
842 }
843
844 /*
845 * Pass DMA audio port to audio drivers.
846 * Audio drivers should not ioremap it.
847 */
848 hdmi.ip_data.ops->audio_get_dma_port(&port_offset, &port_size);
849
850 aud_res[0].start = res->start + port_offset;
851 aud_res[0].end = aud_res[0].start + port_size - 1;
852
853 res = platform_get_resource(hdmi.pdev, IORESOURCE_DMA, 0);
854 if (!res) {
855 DSSERR("can't get IORESOURCE_DMA HDMI\n");
856 return -EINVAL;
857 }
858
859 /* Pass the audio DMA request resource to audio drivers. */
860 aud_res[1].start = res->start;
861
862 /* create platform device for HDMI audio driver */
863 aud_pdev = platform_device_register_simple("omap_hdmi_audio",
864 pdev->id, aud_res,
865 ARRAY_SIZE(aud_res));
866 if (IS_ERR(aud_pdev)) {
867 DSSERR("Can't instantiate hdmi-audio\n");
868 return -ENODEV;
869 }
870
871 hdmi.audio_pdev = aud_pdev;
872
873 return 0;
874}
875
Ricardo Neri35547622012-03-20 21:02:01 -0600876int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
877{
878 u32 deep_color;
Ricardo Neri25a65352012-03-23 15:49:02 -0600879 bool deep_color_correct = false;
Ricardo Neri35547622012-03-20 21:02:01 -0600880 u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock;
881
882 if (n == NULL || cts == NULL)
883 return -EINVAL;
884
885 /* TODO: When implemented, query deep color mode here. */
886 deep_color = 100;
887
Ricardo Neri25a65352012-03-23 15:49:02 -0600888 /*
889 * When using deep color, the default N value (as in the HDMI
890 * specification) yields to an non-integer CTS. Hence, we
891 * modify it while keeping the restrictions described in
892 * section 7.2.1 of the HDMI 1.4a specification.
893 */
Ricardo Neri35547622012-03-20 21:02:01 -0600894 switch (sample_freq) {
895 case 32000:
Ricardo Neri25a65352012-03-23 15:49:02 -0600896 case 48000:
897 case 96000:
898 case 192000:
899 if (deep_color == 125)
900 if (pclk == 27027 || pclk == 74250)
901 deep_color_correct = true;
902 if (deep_color == 150)
903 if (pclk == 27027)
904 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600905 break;
906 case 44100:
Ricardo Neri25a65352012-03-23 15:49:02 -0600907 case 88200:
908 case 176400:
909 if (deep_color == 125)
910 if (pclk == 27027)
911 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600912 break;
913 default:
Ricardo Neri35547622012-03-20 21:02:01 -0600914 return -EINVAL;
915 }
916
Ricardo Neri25a65352012-03-23 15:49:02 -0600917 if (deep_color_correct) {
918 switch (sample_freq) {
919 case 32000:
920 *n = 8192;
921 break;
922 case 44100:
923 *n = 12544;
924 break;
925 case 48000:
926 *n = 8192;
927 break;
928 case 88200:
929 *n = 25088;
930 break;
931 case 96000:
932 *n = 16384;
933 break;
934 case 176400:
935 *n = 50176;
936 break;
937 case 192000:
938 *n = 32768;
939 break;
940 default:
941 return -EINVAL;
942 }
943 } else {
944 switch (sample_freq) {
945 case 32000:
946 *n = 4096;
947 break;
948 case 44100:
949 *n = 6272;
950 break;
951 case 48000:
952 *n = 6144;
953 break;
954 case 88200:
955 *n = 12544;
956 break;
957 case 96000:
958 *n = 12288;
959 break;
960 case 176400:
961 *n = 25088;
962 break;
963 case 192000:
964 *n = 24576;
965 break;
966 default:
967 return -EINVAL;
968 }
969 }
Ricardo Neri35547622012-03-20 21:02:01 -0600970 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
971 *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
972
973 return 0;
974}
Ricardo Nerif3a974912012-05-09 21:09:50 -0500975
976int hdmi_audio_enable(void)
977{
978 DSSDBG("audio_enable\n");
979
980 return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
981}
982
983void hdmi_audio_disable(void)
984{
985 DSSDBG("audio_disable\n");
986
987 hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
988}
989
990int hdmi_audio_start(void)
991{
992 DSSDBG("audio_start\n");
993
994 return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
995}
996
997void hdmi_audio_stop(void)
998{
999 DSSDBG("audio_stop\n");
1000
1001 hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
1002}
1003
1004bool hdmi_mode_has_audio(void)
1005{
1006 if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI)
1007 return true;
1008 else
1009 return false;
1010}
1011
1012int hdmi_audio_config(struct omap_dss_audio *audio)
1013{
1014 return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
1015}
1016
Ricardo Neri35547622012-03-20 21:02:01 -06001017#endif
1018
Tomi Valkeinen15216532012-09-06 14:29:31 +03001019static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001020{
1021 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
Tomi Valkeinen2bbcce52012-10-29 12:40:46 +02001022 const char *def_disp_name = omapdss_get_default_display_name();
Tomi Valkeinen15216532012-09-06 14:29:31 +03001023 struct omap_dss_device *def_dssdev;
1024 int i;
1025
1026 def_dssdev = NULL;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001027
1028 for (i = 0; i < pdata->num_devices; ++i) {
1029 struct omap_dss_device *dssdev = pdata->devices[i];
1030
1031 if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
1032 continue;
1033
Tomi Valkeinen15216532012-09-06 14:29:31 +03001034 if (def_dssdev == NULL)
1035 def_dssdev = dssdev;
Tomi Valkeinencca35012012-04-26 14:48:32 +03001036
Tomi Valkeinen15216532012-09-06 14:29:31 +03001037 if (def_disp_name != NULL &&
1038 strcmp(dssdev->name, def_disp_name) == 0) {
1039 def_dssdev = dssdev;
1040 break;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001041 }
Tomi Valkeinen15216532012-09-06 14:29:31 +03001042 }
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001043
Tomi Valkeinen15216532012-09-06 14:29:31 +03001044 return def_dssdev;
1045}
1046
1047static void __init hdmi_probe_pdata(struct platform_device *pdev)
1048{
Tomi Valkeinen52744842012-09-10 13:58:29 +03001049 struct omap_dss_device *plat_dssdev;
Tomi Valkeinen15216532012-09-06 14:29:31 +03001050 struct omap_dss_device *dssdev;
1051 struct omap_dss_hdmi_data *priv;
1052 int r;
1053
Tomi Valkeinen52744842012-09-10 13:58:29 +03001054 plat_dssdev = hdmi_find_dssdev(pdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001055
Tomi Valkeinen52744842012-09-10 13:58:29 +03001056 if (!plat_dssdev)
1057 return;
1058
1059 dssdev = dss_alloc_and_init_device(&pdev->dev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001060 if (!dssdev)
1061 return;
1062
Tomi Valkeinen52744842012-09-10 13:58:29 +03001063 dss_copy_device_pdata(dssdev, plat_dssdev);
1064
Tomi Valkeinen15216532012-09-06 14:29:31 +03001065 priv = dssdev->data;
1066
1067 hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
1068 hdmi.ls_oe_gpio = priv->ls_oe_gpio;
1069 hdmi.hpd_gpio = priv->hpd_gpio;
1070
Tomi Valkeinenbcb226a2012-09-07 15:21:36 +03001071 dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
1072
Tomi Valkeinen15216532012-09-06 14:29:31 +03001073 r = hdmi_init_display(dssdev);
1074 if (r) {
1075 DSSERR("device %s init failed: %d\n", dssdev->name, r);
Tomi Valkeinen52744842012-09-10 13:58:29 +03001076 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001077 return;
1078 }
1079
Tomi Valkeinen52744842012-09-10 13:58:29 +03001080 r = dss_add_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001081 if (r) {
1082 DSSERR("device %s register failed: %d\n", dssdev->name, r);
Ricardo Nerid18bc452012-11-06 00:19:15 -06001083 hdmi_uninit_display(dssdev);
Tomi Valkeinen52744842012-09-10 13:58:29 +03001084 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001085 return;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001086 }
1087}
1088
Archit Taneja81b87f52012-09-26 16:30:49 +05301089static void __init hdmi_init_output(struct platform_device *pdev)
1090{
1091 struct omap_dss_output *out = &hdmi.output;
1092
1093 out->pdev = pdev;
1094 out->id = OMAP_DSS_OUTPUT_HDMI;
1095 out->type = OMAP_DISPLAY_TYPE_HDMI;
1096
1097 dss_register_output(out);
1098}
1099
1100static void __exit hdmi_uninit_output(struct platform_device *pdev)
1101{
1102 struct omap_dss_output *out = &hdmi.output;
1103
1104 dss_unregister_output(out);
1105}
1106
Mythri P Kc3198a52011-03-12 12:04:27 +05301107/* HDMI HW IP initialisation */
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001108static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301109{
Ricardo Neriaf23cb32012-11-06 00:19:11 -06001110 struct resource *res;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001111 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301112
Mythri P Kc3198a52011-03-12 12:04:27 +05301113 hdmi.pdev = pdev;
1114
1115 mutex_init(&hdmi.lock);
Ricardo Neri66a06b02012-11-06 00:19:14 -06001116 mutex_init(&hdmi.ip_data.lock);
Mythri P Kc3198a52011-03-12 12:04:27 +05301117
Ricardo Neriaf23cb32012-11-06 00:19:11 -06001118 res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
1119 if (!res) {
Mythri P Kc3198a52011-03-12 12:04:27 +05301120 DSSERR("can't get IORESOURCE_MEM HDMI\n");
1121 return -EINVAL;
1122 }
1123
1124 /* Base address taken from platform */
Ricardo Neri47e443b2012-11-06 00:19:12 -06001125 hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res);
Mythri P K95a8aeb2011-09-08 19:06:18 +05301126 if (!hdmi.ip_data.base_wp) {
Mythri P Kc3198a52011-03-12 12:04:27 +05301127 DSSERR("can't ioremap WP\n");
1128 return -ENOMEM;
1129 }
1130
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001131 r = hdmi_get_clocks(pdev);
1132 if (r) {
Ricardo Neri47e443b2012-11-06 00:19:12 -06001133 DSSERR("can't get clocks\n");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001134 return r;
1135 }
1136
1137 pm_runtime_enable(&pdev->dev);
1138
Mythri P K95a8aeb2011-09-08 19:06:18 +05301139 hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS;
1140 hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
1141 hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
1142 hdmi.ip_data.phy_offset = HDMI_PHY;
Archit Taneja78493982012-08-08 16:50:42 +05301143
Ricardo Neri66a06b02012-11-06 00:19:14 -06001144 r = hdmi_panel_init();
1145 if (r) {
1146 DSSERR("can't init panel\n");
1147 goto err_panel_init;
1148 }
Mythri P Kc3198a52011-03-12 12:04:27 +05301149
Tomi Valkeinene40402c2012-03-02 18:01:07 +02001150 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
1151
Archit Taneja81b87f52012-09-26 16:30:49 +05301152 hdmi_init_output(pdev);
1153
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001154 hdmi_probe_pdata(pdev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001155
Ricardo Neri14840b92012-11-06 00:19:17 -06001156#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
1157 r = hdmi_probe_audio(pdev);
1158 if (r)
1159 DSSWARN("could not create platform device for audio");
1160#endif
1161
Mythri P Kc3198a52011-03-12 12:04:27 +05301162 return 0;
Ricardo Neri66a06b02012-11-06 00:19:14 -06001163
1164err_panel_init:
1165 hdmi_put_clocks();
1166 return r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301167}
1168
Tomi Valkeinencca35012012-04-26 14:48:32 +03001169static int __exit hdmi_remove_child(struct device *dev, void *data)
1170{
1171 struct omap_dss_device *dssdev = to_dss_device(dev);
1172 hdmi_uninit_display(dssdev);
1173 return 0;
1174}
1175
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001176static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301177{
Ricardo Neri14840b92012-11-06 00:19:17 -06001178#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
1179 if (hdmi.audio_pdev != NULL)
1180 platform_device_unregister(hdmi.audio_pdev);
1181#endif
1182
Tomi Valkeinencca35012012-04-26 14:48:32 +03001183 device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
1184
Tomi Valkeinen52744842012-09-10 13:58:29 +03001185 dss_unregister_child_devices(&pdev->dev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001186
Mythri P Kc3198a52011-03-12 12:04:27 +05301187 hdmi_panel_exit();
1188
Archit Taneja81b87f52012-09-26 16:30:49 +05301189 hdmi_uninit_output(pdev);
1190
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001191 pm_runtime_disable(&pdev->dev);
1192
1193 hdmi_put_clocks();
1194
Mythri P Kc3198a52011-03-12 12:04:27 +05301195 return 0;
1196}
1197
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001198static int hdmi_runtime_suspend(struct device *dev)
1199{
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301200 clk_disable_unprepare(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001201
1202 dispc_runtime_put();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001203
1204 return 0;
1205}
1206
1207static int hdmi_runtime_resume(struct device *dev)
1208{
1209 int r;
1210
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001211 r = dispc_runtime_get();
1212 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +02001213 return r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001214
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301215 clk_prepare_enable(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001216
1217 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001218}
1219
1220static const struct dev_pm_ops hdmi_pm_ops = {
1221 .runtime_suspend = hdmi_runtime_suspend,
1222 .runtime_resume = hdmi_runtime_resume,
1223};
1224
Mythri P Kc3198a52011-03-12 12:04:27 +05301225static struct platform_driver omapdss_hdmihw_driver = {
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001226 .remove = __exit_p(omapdss_hdmihw_remove),
Mythri P Kc3198a52011-03-12 12:04:27 +05301227 .driver = {
1228 .name = "omapdss_hdmi",
1229 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001230 .pm = &hdmi_pm_ops,
Mythri P Kc3198a52011-03-12 12:04:27 +05301231 },
1232};
1233
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001234int __init hdmi_init_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301235{
Tomi Valkeinen61055d42012-03-07 12:53:38 +02001236 return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe);
Mythri P Kc3198a52011-03-12 12:04:27 +05301237}
1238
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001239void __exit hdmi_uninit_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301240{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02001241 platform_driver_unregister(&omapdss_hdmihw_driver);
Mythri P Kc3198a52011-03-12 12:04:27 +05301242}