blob: 324ecd00e4da88e92bf9ceb144bddb2db17fdb40 [file] [log] [blame]
Mythri P Kc3198a52011-03-12 12:04:27 +05301/*
Archit Tanejaef269582013-09-12 17:45:57 +05302 * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
Mythri P Kc3198a52011-03-12 12:04:27 +05303 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
4 * Authors: Yong Zhi
5 * Mythri pk <mythripk@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "HDMI"
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/interrupt.h>
27#include <linux/mutex.h>
28#include <linux/delay.h>
29#include <linux/string.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030030#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030031#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Tomi Valkeinencca35012012-04-26 14:48:32 +030033#include <linux/gpio.h>
Tomi Valkeinen17486942012-08-15 15:55:04 +030034#include <linux/regulator/consumer.h>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030035#include <video/omapdss.h>
Mythri P Kc3198a52011-03-12 12:04:27 +053036
Archit Tanejaef269582013-09-12 17:45:57 +053037#include "hdmi4_core.h"
Mythri P Kc3198a52011-03-12 12:04:27 +053038#include "dss.h"
Ricardo Neriad44cc32011-05-18 22:31:56 -050039#include "dss_features.h"
Mythri P Kc3198a52011-03-12 12:04:27 +053040
Mythri P K7c1f1ec2011-09-08 19:06:22 +053041/* HDMI EDID Length move this */
42#define HDMI_EDID_MAX_LENGTH 256
43#define EDID_TIMING_DESCRIPTOR_SIZE 0x12
44#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36
45#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80
46#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
47#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
48
Mythri P Kc3198a52011-03-12 12:04:27 +053049static struct {
50 struct mutex lock;
Mythri P Kc3198a52011-03-12 12:04:27 +053051 struct platform_device *pdev;
Ricardo Neri66a06b02012-11-06 00:19:14 -060052
Archit Taneja275cfa12013-10-08 14:22:03 +053053 struct hdmi_wp_data wp;
54 struct hdmi_pll_data pll;
55 struct hdmi_phy_data phy;
56 struct hdmi_core_data core;
57
58 struct hdmi_config cfg;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030059
60 struct clk *sys_clk;
Tomi Valkeinen17486942012-08-15 15:55:04 +030061 struct regulator *vdda_hdmi_dac_reg;
Tomi Valkeinencca35012012-04-26 14:48:32 +030062
Tomi Valkeinen0b450c32013-05-24 13:20:17 +030063 bool core_enabled;
64
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +030065 struct omap_dss_device output;
Mythri P Kc3198a52011-03-12 12:04:27 +053066} hdmi;
67
68/*
69 * Logic for the below structure :
70 * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
71 * There is a correspondence between CEA/VESA timing and code, please
72 * refer to section 6.3 in HDMI 1.3 specification for timing code.
73 *
74 * In the below structure, cea_vesa_timings corresponds to all OMAP4
75 * supported CEA and VESA timing values.code_cea corresponds to the CEA
76 * code, It is used to get the timing from cea_vesa_timing array.Similarly
77 * with code_vesa. Code_index is used for back mapping, that is once EDID
78 * is read from the TV, EDID is parsed to find the timing values and then
79 * map it to corresponding CEA or VESA index.
80 */
81
Mythri P K46095b22012-01-06 17:52:09 +053082static const struct hdmi_config cea_timings[] = {
Archit Tanejacc937e52012-06-24 13:08:10 +053083 {
84 { 640, 480, 25200, 96, 16, 48, 2, 10, 33,
85 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
86 false, },
87 { 1, HDMI_HDMI },
88 },
89 {
90 { 720, 480, 27027, 62, 16, 60, 6, 9, 30,
91 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
92 false, },
93 { 2, HDMI_HDMI },
94 },
95 {
96 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
97 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
98 false, },
99 { 4, HDMI_HDMI },
100 },
101 {
102 { 1920, 540, 74250, 44, 88, 148, 5, 2, 15,
103 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
104 true, },
105 { 5, HDMI_HDMI },
106 },
107 {
108 { 1440, 240, 27027, 124, 38, 114, 3, 4, 15,
109 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
110 true, },
111 { 6, HDMI_HDMI },
112 },
113 {
114 { 1920, 1080, 148500, 44, 88, 148, 5, 4, 36,
115 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
116 false, },
117 { 16, HDMI_HDMI },
118 },
119 {
120 { 720, 576, 27000, 64, 12, 68, 5, 5, 39,
121 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
122 false, },
123 { 17, HDMI_HDMI },
124 },
125 {
126 { 1280, 720, 74250, 40, 440, 220, 5, 5, 20,
127 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
128 false, },
129 { 19, HDMI_HDMI },
130 },
131 {
132 { 1920, 540, 74250, 44, 528, 148, 5, 2, 15,
133 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
134 true, },
135 { 20, HDMI_HDMI },
136 },
137 {
138 { 1440, 288, 27000, 126, 24, 138, 3, 2, 19,
139 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
140 true, },
141 { 21, HDMI_HDMI },
142 },
143 {
144 { 1440, 576, 54000, 128, 24, 136, 5, 5, 39,
145 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
146 false, },
147 { 29, HDMI_HDMI },
148 },
149 {
150 { 1920, 1080, 148500, 44, 528, 148, 5, 4, 36,
151 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
152 false, },
153 { 31, HDMI_HDMI },
154 },
155 {
156 { 1920, 1080, 74250, 44, 638, 148, 5, 4, 36,
157 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
158 false, },
159 { 32, HDMI_HDMI },
160 },
161 {
162 { 2880, 480, 108108, 248, 64, 240, 6, 9, 30,
163 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
164 false, },
165 { 35, HDMI_HDMI },
166 },
167 {
168 { 2880, 576, 108000, 256, 48, 272, 5, 5, 39,
169 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
170 false, },
171 { 37, HDMI_HDMI },
172 },
Mythri P K46095b22012-01-06 17:52:09 +0530173};
Archit Tanejacc937e52012-06-24 13:08:10 +0530174
Mythri P K46095b22012-01-06 17:52:09 +0530175static const struct hdmi_config vesa_timings[] = {
Mythri P Ka05ce782012-01-06 17:52:08 +0530176/* VESA From Here */
Archit Tanejacc937e52012-06-24 13:08:10 +0530177 {
178 { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
179 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
180 false, },
181 { 4, HDMI_DVI },
182 },
183 {
184 { 800, 600, 40000, 128, 40, 88, 4, 1, 23,
185 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
186 false, },
187 { 9, HDMI_DVI },
188 },
189 {
190 { 848, 480, 33750, 112, 16, 112, 8, 6, 23,
191 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
192 false, },
193 { 0xE, HDMI_DVI },
194 },
195 {
196 { 1280, 768, 79500, 128, 64, 192, 7, 3, 20,
197 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
198 false, },
199 { 0x17, HDMI_DVI },
200 },
201 {
202 { 1280, 800, 83500, 128, 72, 200, 6, 3, 22,
203 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
204 false, },
205 { 0x1C, HDMI_DVI },
206 },
207 {
208 { 1360, 768, 85500, 112, 64, 256, 6, 3, 18,
209 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
210 false, },
211 { 0x27, HDMI_DVI },
212 },
213 {
214 { 1280, 960, 108000, 112, 96, 312, 3, 1, 36,
215 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
216 false, },
217 { 0x20, HDMI_DVI },
218 },
219 {
220 { 1280, 1024, 108000, 112, 48, 248, 3, 1, 38,
221 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
222 false, },
223 { 0x23, HDMI_DVI },
224 },
225 {
226 { 1024, 768, 65000, 136, 24, 160, 6, 3, 29,
227 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
228 false, },
229 { 0x10, HDMI_DVI },
230 },
231 {
232 { 1400, 1050, 121750, 144, 88, 232, 4, 3, 32,
233 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
234 false, },
235 { 0x2A, HDMI_DVI },
236 },
237 {
238 { 1440, 900, 106500, 152, 80, 232, 6, 3, 25,
239 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
240 false, },
241 { 0x2F, HDMI_DVI },
242 },
243 {
244 { 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30,
245 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
246 false, },
247 { 0x3A, HDMI_DVI },
248 },
249 {
250 { 1366, 768, 85500, 143, 70, 213, 3, 3, 24,
251 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
252 false, },
253 { 0x51, HDMI_DVI },
254 },
255 {
256 { 1920, 1080, 148500, 44, 148, 80, 5, 4, 36,
257 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
258 false, },
259 { 0x52, HDMI_DVI },
260 },
261 {
262 { 1280, 768, 68250, 32, 48, 80, 7, 3, 12,
263 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
264 false, },
265 { 0x16, HDMI_DVI },
266 },
267 {
268 { 1400, 1050, 101000, 32, 48, 80, 4, 3, 23,
269 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
270 false, },
271 { 0x29, HDMI_DVI },
272 },
273 {
274 { 1680, 1050, 119000, 32, 48, 80, 6, 3, 21,
275 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
276 false, },
277 { 0x39, HDMI_DVI },
278 },
279 {
280 { 1280, 800, 79500, 32, 48, 80, 6, 3, 14,
281 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
282 false, },
283 { 0x1B, HDMI_DVI },
284 },
285 {
286 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
287 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
288 false, },
289 { 0x55, HDMI_DVI },
290 },
Tomi Valkeinen7a7ce2c2012-10-24 11:55:39 +0300291 {
292 { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26,
293 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
294 false, },
295 { 0x44, HDMI_DVI },
296 },
Mythri P Kc3198a52011-03-12 12:04:27 +0530297};
298
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300299static int hdmi_runtime_get(void)
300{
301 int r;
302
303 DSSDBG("hdmi_runtime_get\n");
304
305 r = pm_runtime_get_sync(&hdmi.pdev->dev);
306 WARN_ON(r < 0);
Archit Tanejaa247ce782012-02-10 11:45:52 +0530307 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +0200308 return r;
Archit Tanejaa247ce782012-02-10 11:45:52 +0530309
310 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300311}
312
313static void hdmi_runtime_put(void)
314{
315 int r;
316
317 DSSDBG("hdmi_runtime_put\n");
318
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200319 r = pm_runtime_put_sync(&hdmi.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300320 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300321}
322
Tomi Valkeinene25001d2013-05-10 15:20:52 +0300323static int hdmi_init_regulator(void)
324{
325 struct regulator *reg;
326
327 if (hdmi.vdda_hdmi_dac_reg != NULL)
328 return 0;
329
330 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
331
332 /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
333 if (IS_ERR(reg))
334 reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
335
336 if (IS_ERR(reg)) {
337 DSSERR("can't get VDDA_HDMI_DAC regulator\n");
338 return PTR_ERR(reg);
339 }
340
341 hdmi.vdda_hdmi_dac_reg = reg;
342
343 return 0;
344}
345
Mythri P K46095b22012-01-06 17:52:09 +0530346static const struct hdmi_config *hdmi_find_timing(
347 const struct hdmi_config *timings_arr,
348 int len)
Mythri P Kc3198a52011-03-12 12:04:27 +0530349{
Mythri P K46095b22012-01-06 17:52:09 +0530350 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530351
Mythri P K46095b22012-01-06 17:52:09 +0530352 for (i = 0; i < len; i++) {
Archit Taneja275cfa12013-10-08 14:22:03 +0530353 if (timings_arr[i].cm.code == hdmi.cfg.cm.code)
Mythri P K46095b22012-01-06 17:52:09 +0530354 return &timings_arr[i];
Mythri P Kc3198a52011-03-12 12:04:27 +0530355 }
Mythri P K46095b22012-01-06 17:52:09 +0530356 return NULL;
357}
358
359static const struct hdmi_config *hdmi_get_timings(void)
360{
Archit Tanejaef269582013-09-12 17:45:57 +0530361 const struct hdmi_config *arr;
362 int len;
Mythri P K46095b22012-01-06 17:52:09 +0530363
Archit Taneja275cfa12013-10-08 14:22:03 +0530364 if (hdmi.cfg.cm.mode == HDMI_DVI) {
365 arr = vesa_timings;
366 len = ARRAY_SIZE(vesa_timings);
367 } else {
368 arr = cea_timings;
369 len = ARRAY_SIZE(cea_timings);
370 }
Mythri P K46095b22012-01-06 17:52:09 +0530371
Archit Taneja275cfa12013-10-08 14:22:03 +0530372 return hdmi_find_timing(arr, len);
Mythri P K46095b22012-01-06 17:52:09 +0530373}
374
375static bool hdmi_timings_compare(struct omap_video_timings *timing1,
Archit Tanejacc937e52012-06-24 13:08:10 +0530376 const struct omap_video_timings *timing2)
Mythri P K46095b22012-01-06 17:52:09 +0530377{
378 int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
379
Tomi Valkeinenf236b892012-10-24 11:55:54 +0300380 if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) ==
381 DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) &&
Mythri P K46095b22012-01-06 17:52:09 +0530382 (timing2->x_res == timing1->x_res) &&
383 (timing2->y_res == timing1->y_res)) {
384
385 timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
386 timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
387 timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
388 timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
389
390 DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
391 "timing2_hsync = %d timing2_vsync = %d\n",
392 timing1_hsync, timing1_vsync,
393 timing2_hsync, timing2_vsync);
394
395 if ((timing1_hsync == timing2_hsync) &&
396 (timing1_vsync == timing2_vsync)) {
397 return true;
398 }
399 }
400 return false;
Mythri P Kc3198a52011-03-12 12:04:27 +0530401}
402
403static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
404{
Mythri P K46095b22012-01-06 17:52:09 +0530405 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530406 struct hdmi_cm cm = {-1};
407 DSSDBG("hdmi_get_code\n");
408
Mythri P K46095b22012-01-06 17:52:09 +0530409 for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
410 if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
411 cm = cea_timings[i].cm;
412 goto end;
413 }
414 }
415 for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
416 if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
417 cm = vesa_timings[i].cm;
418 goto end;
Mythri P Kc3198a52011-03-12 12:04:27 +0530419 }
420 }
421
Mythri P K46095b22012-01-06 17:52:09 +0530422end: return cm;
Mythri P Kc3198a52011-03-12 12:04:27 +0530423
Mythri P Kc3198a52011-03-12 12:04:27 +0530424}
425
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300426static int hdmi_power_on_core(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530427{
Mythri P K46095b22012-01-06 17:52:09 +0530428 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +0530429
Tomi Valkeinen17486942012-08-15 15:55:04 +0300430 r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
431 if (r)
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300432 return r;
Tomi Valkeinen17486942012-08-15 15:55:04 +0300433
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300434 r = hdmi_runtime_get();
435 if (r)
Tomi Valkeinencca35012012-04-26 14:48:32 +0300436 goto err_runtime_get;
Mythri P Kc3198a52011-03-12 12:04:27 +0530437
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300438 /* Make selection of HDMI in DSS */
439 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
440
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300441 hdmi.core_enabled = true;
442
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300443 return 0;
444
445err_runtime_get:
446 regulator_disable(hdmi.vdda_hdmi_dac_reg);
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300447
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300448 return r;
449}
450
451static void hdmi_power_off_core(struct omap_dss_device *dssdev)
452{
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300453 hdmi.core_enabled = false;
454
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300455 hdmi_runtime_put();
456 regulator_disable(hdmi.vdda_hdmi_dac_reg);
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300457}
458
459static int hdmi_power_on_full(struct omap_dss_device *dssdev)
460{
461 int r;
462 struct omap_video_timings *p;
Tomi Valkeinen7ae9a712013-05-10 15:27:07 +0300463 struct omap_overlay_manager *mgr = hdmi.output.manager;
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300464 unsigned long phy;
465
466 r = hdmi_power_on_core(dssdev);
467 if (r)
468 return r;
469
Archit Tanejacea87b92012-09-07 17:56:20 +0530470 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530471
Archit Taneja275cfa12013-10-08 14:22:03 +0530472 p = &hdmi.cfg.timings;
Mythri P Kc3198a52011-03-12 12:04:27 +0530473
Archit Taneja78493982012-08-08 16:50:42 +0530474 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 +0530475
Mythri P Kc3198a52011-03-12 12:04:27 +0530476 phy = p->pixel_clock;
477
Archit Taneja275cfa12013-10-08 14:22:03 +0530478 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
Mythri P Kc3198a52011-03-12 12:04:27 +0530479
Archit Taneja275cfa12013-10-08 14:22:03 +0530480 hdmi_wp_video_stop(&hdmi.wp);
Mythri P Kc3198a52011-03-12 12:04:27 +0530481
Mythri P K95a8aeb2011-09-08 19:06:18 +0530482 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
Archit Taneja275cfa12013-10-08 14:22:03 +0530483 r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
Mythri P Kc3198a52011-03-12 12:04:27 +0530484 if (r) {
485 DSSDBG("Failed to lock PLL\n");
Tomi Valkeinencca35012012-04-26 14:48:32 +0300486 goto err_pll_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530487 }
488
Archit Taneja275cfa12013-10-08 14:22:03 +0530489 r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg);
Mythri P Kc3198a52011-03-12 12:04:27 +0530490 if (r) {
491 DSSDBG("Failed to start PHY\n");
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500492 goto err_phy_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530493 }
494
Archit Taneja275cfa12013-10-08 14:22:03 +0530495 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
Mythri P Kc3198a52011-03-12 12:04:27 +0530496
Mythri P Kc3198a52011-03-12 12:04:27 +0530497 /* bypass TV gamma table */
498 dispc_enable_gamma_table(0);
499
500 /* tv size */
Archit Tanejacea87b92012-09-07 17:56:20 +0530501 dss_mgr_set_timings(mgr, p);
Mythri P Kc3198a52011-03-12 12:04:27 +0530502
Archit Taneja275cfa12013-10-08 14:22:03 +0530503 r = hdmi_wp_video_start(&hdmi.wp);
Ricardo Neric0456be2012-04-27 13:48:45 -0500504 if (r)
505 goto err_vid_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530506
Archit Tanejacea87b92012-09-07 17:56:20 +0530507 r = dss_mgr_enable(mgr);
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200508 if (r)
509 goto err_mgr_enable;
Tomi Valkeinen3870c902011-08-31 14:47:11 +0300510
Mythri P Kc3198a52011-03-12 12:04:27 +0530511 return 0;
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200512
513err_mgr_enable:
Archit Taneja275cfa12013-10-08 14:22:03 +0530514 hdmi_wp_video_stop(&hdmi.wp);
Ricardo Neric0456be2012-04-27 13:48:45 -0500515err_vid_enable:
Archit Taneja275cfa12013-10-08 14:22:03 +0530516 hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500517err_phy_enable:
Archit Taneja275cfa12013-10-08 14:22:03 +0530518 hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300519err_pll_enable:
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300520 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530521 return -EIO;
522}
523
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300524static void hdmi_power_off_full(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530525{
Tomi Valkeinen7ae9a712013-05-10 15:27:07 +0300526 struct omap_overlay_manager *mgr = hdmi.output.manager;
Archit Tanejacea87b92012-09-07 17:56:20 +0530527
528 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530529
Archit Taneja275cfa12013-10-08 14:22:03 +0530530 hdmi_wp_video_stop(&hdmi.wp);
531 hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
532 hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300533
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300534 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530535}
536
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300537static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
Mythri P Kc3198a52011-03-12 12:04:27 +0530538 struct omap_video_timings *timings)
539{
540 struct hdmi_cm cm;
541
542 cm = hdmi_get_code(timings);
Archit Tanejaef269582013-09-12 17:45:57 +0530543 if (cm.code == -1)
Mythri P Kc3198a52011-03-12 12:04:27 +0530544 return -EINVAL;
Mythri P Kc3198a52011-03-12 12:04:27 +0530545
546 return 0;
547
548}
549
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300550static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
Archit Taneja78493982012-08-08 16:50:42 +0530551 struct omap_video_timings *timings)
Mythri P Kc3198a52011-03-12 12:04:27 +0530552{
553 struct hdmi_cm cm;
Archit Taneja78493982012-08-08 16:50:42 +0530554 const struct hdmi_config *t;
Mythri P Kc3198a52011-03-12 12:04:27 +0530555
Archit Tanejaed1aa902012-08-15 00:40:31 +0530556 mutex_lock(&hdmi.lock);
557
Archit Taneja78493982012-08-08 16:50:42 +0530558 cm = hdmi_get_code(timings);
Archit Taneja275cfa12013-10-08 14:22:03 +0530559 hdmi.cfg.cm = cm;
Archit Taneja78493982012-08-08 16:50:42 +0530560
561 t = hdmi_get_timings();
Tomi Valkeinendb680c62013-08-27 14:11:48 +0300562 if (t != NULL) {
Archit Taneja275cfa12013-10-08 14:22:03 +0530563 hdmi.cfg = *t;
Tomi Valkeinenfa70dc52011-08-22 14:57:33 +0300564
Tomi Valkeinendb680c62013-08-27 14:11:48 +0300565 dispc_set_tv_pclk(t->timings.pixel_clock * 1000);
566 }
Tomi Valkeinen5391e872013-05-16 10:44:13 +0300567
Archit Tanejaed1aa902012-08-15 00:40:31 +0530568 mutex_unlock(&hdmi.lock);
Mythri P Kc3198a52011-03-12 12:04:27 +0530569}
570
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300571static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300572 struct omap_video_timings *timings)
573{
574 const struct hdmi_config *cfg;
575
576 cfg = hdmi_get_timings();
577 if (cfg == NULL)
578 cfg = &vesa_timings[0];
579
580 memcpy(timings, &cfg->timings, sizeof(cfg->timings));
581}
582
Tomi Valkeinene40402c2012-03-02 18:01:07 +0200583static void hdmi_dump_regs(struct seq_file *s)
Mythri P K162874d2011-09-22 13:37:45 +0530584{
585 mutex_lock(&hdmi.lock);
586
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800587 if (hdmi_runtime_get()) {
588 mutex_unlock(&hdmi.lock);
Mythri P K162874d2011-09-22 13:37:45 +0530589 return;
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800590 }
Mythri P K162874d2011-09-22 13:37:45 +0530591
Archit Taneja275cfa12013-10-08 14:22:03 +0530592 hdmi_wp_dump(&hdmi.wp, s);
593 hdmi_pll_dump(&hdmi.pll, s);
594 hdmi_phy_dump(&hdmi.phy, s);
595 hdmi4_core_dump(&hdmi.core, s);
Mythri P K162874d2011-09-22 13:37:45 +0530596
597 hdmi_runtime_put();
598 mutex_unlock(&hdmi.lock);
599}
600
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300601static int read_edid(u8 *buf, int len)
Tomi Valkeinen47024562011-08-25 17:12:56 +0300602{
603 int r;
604
605 mutex_lock(&hdmi.lock);
606
607 r = hdmi_runtime_get();
608 BUG_ON(r);
609
Archit Taneja275cfa12013-10-08 14:22:03 +0530610 r = hdmi4_read_edid(&hdmi.core, buf, len);
Tomi Valkeinen47024562011-08-25 17:12:56 +0300611
612 hdmi_runtime_put();
613 mutex_unlock(&hdmi.lock);
614
615 return r;
616}
617
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300618static int hdmi_display_enable(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530619{
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +0300620 struct omap_dss_device *out = &hdmi.output;
Mythri P Kc3198a52011-03-12 12:04:27 +0530621 int r = 0;
622
623 DSSDBG("ENTER hdmi_display_enable\n");
624
625 mutex_lock(&hdmi.lock);
626
Archit Tanejacea87b92012-09-07 17:56:20 +0530627 if (out == NULL || out->manager == NULL) {
628 DSSERR("failed to enable display: no output/manager\n");
Tomi Valkeinen05e1d602011-06-23 16:38:21 +0300629 r = -ENODEV;
630 goto err0;
631 }
632
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300633 r = hdmi_power_on_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530634 if (r) {
635 DSSERR("failed to power on device\n");
Tomi Valkeinend3923932013-04-25 13:12:07 +0300636 goto err0;
Mythri P Kc3198a52011-03-12 12:04:27 +0530637 }
638
639 mutex_unlock(&hdmi.lock);
640 return 0;
641
Mythri P Kc3198a52011-03-12 12:04:27 +0530642err0:
643 mutex_unlock(&hdmi.lock);
644 return r;
645}
646
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300647static void hdmi_display_disable(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530648{
649 DSSDBG("Enter hdmi_display_disable\n");
650
651 mutex_lock(&hdmi.lock);
652
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300653 hdmi_power_off_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530654
Mythri P Kc3198a52011-03-12 12:04:27 +0530655 mutex_unlock(&hdmi.lock);
656}
657
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300658static int hdmi_core_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen44898232012-10-19 17:42:27 +0300659{
660 int r = 0;
661
662 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
663
664 mutex_lock(&hdmi.lock);
665
Tomi Valkeinen44898232012-10-19 17:42:27 +0300666 r = hdmi_power_on_core(dssdev);
667 if (r) {
668 DSSERR("failed to power on device\n");
669 goto err0;
670 }
671
672 mutex_unlock(&hdmi.lock);
673 return 0;
674
675err0:
676 mutex_unlock(&hdmi.lock);
677 return r;
678}
679
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300680static void hdmi_core_disable(struct omap_dss_device *dssdev)
Tomi Valkeinen44898232012-10-19 17:42:27 +0300681{
682 DSSDBG("Enter omapdss_hdmi_core_disable\n");
683
684 mutex_lock(&hdmi.lock);
685
686 hdmi_power_off_core(dssdev);
687
688 mutex_unlock(&hdmi.lock);
689}
690
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300691static int hdmi_get_clocks(struct platform_device *pdev)
692{
693 struct clk *clk;
694
Archit Tanejab2c9c8e2013-04-08 11:55:00 +0300695 clk = devm_clk_get(&pdev->dev, "sys_clk");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300696 if (IS_ERR(clk)) {
697 DSSERR("can't get sys_clk\n");
698 return PTR_ERR(clk);
699 }
700
701 hdmi.sys_clk = clk;
702
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300703 return 0;
704}
705
Ricardo Neri35547622012-03-20 21:02:01 -0600706#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
707int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
708{
709 u32 deep_color;
Ricardo Neri25a65352012-03-23 15:49:02 -0600710 bool deep_color_correct = false;
Archit Taneja275cfa12013-10-08 14:22:03 +0530711 u32 pclk = hdmi.cfg.timings.pixel_clock;
Ricardo Neri35547622012-03-20 21:02:01 -0600712
713 if (n == NULL || cts == NULL)
714 return -EINVAL;
715
716 /* TODO: When implemented, query deep color mode here. */
717 deep_color = 100;
718
Ricardo Neri25a65352012-03-23 15:49:02 -0600719 /*
720 * When using deep color, the default N value (as in the HDMI
721 * specification) yields to an non-integer CTS. Hence, we
722 * modify it while keeping the restrictions described in
723 * section 7.2.1 of the HDMI 1.4a specification.
724 */
Ricardo Neri35547622012-03-20 21:02:01 -0600725 switch (sample_freq) {
726 case 32000:
Ricardo Neri25a65352012-03-23 15:49:02 -0600727 case 48000:
728 case 96000:
729 case 192000:
730 if (deep_color == 125)
731 if (pclk == 27027 || pclk == 74250)
732 deep_color_correct = true;
733 if (deep_color == 150)
734 if (pclk == 27027)
735 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600736 break;
737 case 44100:
Ricardo Neri25a65352012-03-23 15:49:02 -0600738 case 88200:
739 case 176400:
740 if (deep_color == 125)
741 if (pclk == 27027)
742 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600743 break;
744 default:
Ricardo Neri35547622012-03-20 21:02:01 -0600745 return -EINVAL;
746 }
747
Ricardo Neri25a65352012-03-23 15:49:02 -0600748 if (deep_color_correct) {
749 switch (sample_freq) {
750 case 32000:
751 *n = 8192;
752 break;
753 case 44100:
754 *n = 12544;
755 break;
756 case 48000:
757 *n = 8192;
758 break;
759 case 88200:
760 *n = 25088;
761 break;
762 case 96000:
763 *n = 16384;
764 break;
765 case 176400:
766 *n = 50176;
767 break;
768 case 192000:
769 *n = 32768;
770 break;
771 default:
772 return -EINVAL;
773 }
774 } else {
775 switch (sample_freq) {
776 case 32000:
777 *n = 4096;
778 break;
779 case 44100:
780 *n = 6272;
781 break;
782 case 48000:
783 *n = 6144;
784 break;
785 case 88200:
786 *n = 12544;
787 break;
788 case 96000:
789 *n = 12288;
790 break;
791 case 176400:
792 *n = 25088;
793 break;
794 case 192000:
795 *n = 24576;
796 break;
797 default:
798 return -EINVAL;
799 }
800 }
Ricardo Neri35547622012-03-20 21:02:01 -0600801 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
802 *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
803
804 return 0;
805}
Ricardo Nerif3a974912012-05-09 21:09:50 -0500806
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300807static bool hdmi_mode_has_audio(void)
Ricardo Nerif3a974912012-05-09 21:09:50 -0500808{
Archit Taneja275cfa12013-10-08 14:22:03 +0530809 if (hdmi.cfg.cm.mode == HDMI_HDMI)
Ricardo Nerif3a974912012-05-09 21:09:50 -0500810 return true;
811 else
812 return false;
813}
Archit Taneja275cfa12013-10-08 14:22:03 +0530814
Ricardo Neri35547622012-03-20 21:02:01 -0600815#endif
816
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300817static int hdmi_connect(struct omap_dss_device *dssdev,
818 struct omap_dss_device *dst)
819{
820 struct omap_overlay_manager *mgr;
821 int r;
822
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300823 r = hdmi_init_regulator();
824 if (r)
825 return r;
826
827 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
828 if (!mgr)
829 return -ENODEV;
830
831 r = dss_mgr_connect(mgr, dssdev);
832 if (r)
833 return r;
834
835 r = omapdss_output_set_device(dssdev, dst);
836 if (r) {
837 DSSERR("failed to connect output to new device: %s\n",
838 dst->name);
839 dss_mgr_disconnect(mgr, dssdev);
840 return r;
841 }
842
843 return 0;
844}
845
846static void hdmi_disconnect(struct omap_dss_device *dssdev,
847 struct omap_dss_device *dst)
848{
Tomi Valkeinen9560dc102013-07-24 13:06:54 +0300849 WARN_ON(dst != dssdev->dst);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300850
Tomi Valkeinen9560dc102013-07-24 13:06:54 +0300851 if (dst != dssdev->dst)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300852 return;
853
854 omapdss_output_unset_device(dssdev);
855
856 if (dssdev->manager)
857 dss_mgr_disconnect(dssdev->manager, dssdev);
858}
859
860static int hdmi_read_edid(struct omap_dss_device *dssdev,
861 u8 *edid, int len)
862{
863 bool need_enable;
864 int r;
865
866 need_enable = hdmi.core_enabled == false;
867
868 if (need_enable) {
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300869 r = hdmi_core_enable(dssdev);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300870 if (r)
871 return r;
872 }
873
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300874 r = read_edid(edid, len);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300875
876 if (need_enable)
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300877 hdmi_core_disable(dssdev);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300878
879 return r;
880}
881
882#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300883static int hdmi_audio_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300884{
885 int r;
886
887 mutex_lock(&hdmi.lock);
888
889 if (!hdmi_mode_has_audio()) {
890 r = -EPERM;
891 goto err;
892 }
893
Archit Taneja275cfa12013-10-08 14:22:03 +0530894 r = hdmi_wp_audio_enable(&hdmi.wp, true);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300895 if (r)
896 goto err;
897
898 mutex_unlock(&hdmi.lock);
899 return 0;
900
901err:
902 mutex_unlock(&hdmi.lock);
903 return r;
904}
905
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300906static void hdmi_audio_disable(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300907{
Archit Taneja275cfa12013-10-08 14:22:03 +0530908 hdmi_wp_audio_enable(&hdmi.wp, false);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300909}
910
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300911static int hdmi_audio_start(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300912{
Archit Taneja275cfa12013-10-08 14:22:03 +0530913 return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300914}
915
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300916static void hdmi_audio_stop(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300917{
Archit Taneja275cfa12013-10-08 14:22:03 +0530918 hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300919}
920
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300921static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300922{
923 bool r;
924
925 mutex_lock(&hdmi.lock);
926
927 r = hdmi_mode_has_audio();
928
929 mutex_unlock(&hdmi.lock);
930 return r;
931}
932
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300933static int hdmi_audio_config(struct omap_dss_device *dssdev,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300934 struct omap_dss_audio *audio)
935{
936 int r;
937
938 mutex_lock(&hdmi.lock);
939
940 if (!hdmi_mode_has_audio()) {
941 r = -EPERM;
942 goto err;
943 }
944
Archit Taneja275cfa12013-10-08 14:22:03 +0530945 r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio);
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300946 if (r)
947 goto err;
948
949 mutex_unlock(&hdmi.lock);
950 return 0;
951
952err:
953 mutex_unlock(&hdmi.lock);
954 return r;
955}
956#else
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300957static int hdmi_audio_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300958{
959 return -EPERM;
960}
961
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300962static void hdmi_audio_disable(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300963{
964}
965
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300966static int hdmi_audio_start(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300967{
968 return -EPERM;
969}
970
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300971static void hdmi_audio_stop(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300972{
973}
974
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300975static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300976{
977 return false;
978}
979
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300980static int hdmi_audio_config(struct omap_dss_device *dssdev,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300981 struct omap_dss_audio *audio)
982{
983 return -EPERM;
984}
985#endif
986
987static const struct omapdss_hdmi_ops hdmi_ops = {
988 .connect = hdmi_connect,
989 .disconnect = hdmi_disconnect,
990
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300991 .enable = hdmi_display_enable,
992 .disable = hdmi_display_disable,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300993
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +0300994 .check_timings = hdmi_display_check_timing,
995 .set_timings = hdmi_display_set_timing,
996 .get_timings = hdmi_display_get_timings,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +0300997
998 .read_edid = hdmi_read_edid,
999
Tomi Valkeinen164ebdd2013-05-15 10:48:45 +03001000 .audio_enable = hdmi_audio_enable,
1001 .audio_disable = hdmi_audio_disable,
1002 .audio_start = hdmi_audio_start,
1003 .audio_stop = hdmi_audio_stop,
1004 .audio_supported = hdmi_audio_supported,
1005 .audio_config = hdmi_audio_config,
Tomi Valkeinen0b450c32013-05-24 13:20:17 +03001006};
1007
Tomi Valkeinen17ae4e82013-04-26 14:48:43 +03001008static void hdmi_init_output(struct platform_device *pdev)
Archit Taneja81b87f52012-09-26 16:30:49 +05301009{
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +03001010 struct omap_dss_device *out = &hdmi.output;
Archit Taneja81b87f52012-09-26 16:30:49 +05301011
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +03001012 out->dev = &pdev->dev;
Archit Taneja81b87f52012-09-26 16:30:49 +05301013 out->id = OMAP_DSS_OUTPUT_HDMI;
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +03001014 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
Tomi Valkeinen7286a082013-02-18 13:06:01 +02001015 out->name = "hdmi.0";
Tomi Valkeinen2eea5ae2013-02-13 11:23:54 +02001016 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeinen0b450c32013-05-24 13:20:17 +03001017 out->ops.hdmi = &hdmi_ops;
Tomi Valkeinenb7328e12013-05-03 11:42:18 +03001018 out->owner = THIS_MODULE;
Archit Taneja81b87f52012-09-26 16:30:49 +05301019
Tomi Valkeinen5d47dbc2013-04-24 13:32:51 +03001020 omapdss_register_output(out);
Archit Taneja81b87f52012-09-26 16:30:49 +05301021}
1022
1023static void __exit hdmi_uninit_output(struct platform_device *pdev)
1024{
Tomi Valkeinen1f68d9c2013-04-19 15:09:34 +03001025 struct omap_dss_device *out = &hdmi.output;
Archit Taneja81b87f52012-09-26 16:30:49 +05301026
Tomi Valkeinen5d47dbc2013-04-24 13:32:51 +03001027 omapdss_unregister_output(out);
Archit Taneja81b87f52012-09-26 16:30:49 +05301028}
1029
Mythri P Kc3198a52011-03-12 12:04:27 +05301030/* HDMI HW IP initialisation */
Tomi Valkeinen17ae4e82013-04-26 14:48:43 +03001031static int omapdss_hdmihw_probe(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301032{
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001033 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301034
Mythri P Kc3198a52011-03-12 12:04:27 +05301035 hdmi.pdev = pdev;
1036
1037 mutex_init(&hdmi.lock);
1038
Archit Taneja275cfa12013-10-08 14:22:03 +05301039 r = hdmi_wp_init(pdev, &hdmi.wp);
Archit Tanejaf382d9e2013-08-06 14:56:55 +05301040 if (r)
1041 return r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301042
Archit Taneja275cfa12013-10-08 14:22:03 +05301043 r = hdmi_pll_init(pdev, &hdmi.pll);
Archit Tanejac1577c12013-10-08 12:55:26 +05301044 if (r)
1045 return r;
1046
Archit Taneja275cfa12013-10-08 14:22:03 +05301047 r = hdmi_phy_init(pdev, &hdmi.phy);
Archit Taneja5cac5ae2013-10-08 13:07:00 +05301048 if (r)
1049 return r;
Tomi Valkeinenddb1d5c2013-06-06 13:08:35 +03001050
Archit Taneja275cfa12013-10-08 14:22:03 +05301051 r = hdmi4_core_init(pdev, &hdmi.core);
Archit Taneja425f02f2013-10-08 14:16:05 +05301052 if (r)
1053 return r;
1054
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001055 r = hdmi_get_clocks(pdev);
1056 if (r) {
Ricardo Neri47e443b2012-11-06 00:19:12 -06001057 DSSERR("can't get clocks\n");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001058 return r;
1059 }
1060
1061 pm_runtime_enable(&pdev->dev);
1062
Tomi Valkeinen002d3682013-02-13 12:17:43 +02001063 hdmi_init_output(pdev);
1064
Tomi Valkeinene40402c2012-03-02 18:01:07 +02001065 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
1066
Tomi Valkeinencca35012012-04-26 14:48:32 +03001067 return 0;
1068}
1069
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001070static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301071{
Archit Taneja81b87f52012-09-26 16:30:49 +05301072 hdmi_uninit_output(pdev);
1073
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001074 pm_runtime_disable(&pdev->dev);
1075
Mythri P Kc3198a52011-03-12 12:04:27 +05301076 return 0;
1077}
1078
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001079static int hdmi_runtime_suspend(struct device *dev)
1080{
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301081 clk_disable_unprepare(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001082
1083 dispc_runtime_put();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001084
1085 return 0;
1086}
1087
1088static int hdmi_runtime_resume(struct device *dev)
1089{
1090 int r;
1091
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001092 r = dispc_runtime_get();
1093 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +02001094 return r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001095
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301096 clk_prepare_enable(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001097
1098 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001099}
1100
1101static const struct dev_pm_ops hdmi_pm_ops = {
1102 .runtime_suspend = hdmi_runtime_suspend,
1103 .runtime_resume = hdmi_runtime_resume,
1104};
1105
Mythri P Kc3198a52011-03-12 12:04:27 +05301106static struct platform_driver omapdss_hdmihw_driver = {
Tomi Valkeinen17ae4e82013-04-26 14:48:43 +03001107 .probe = omapdss_hdmihw_probe,
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001108 .remove = __exit_p(omapdss_hdmihw_remove),
Mythri P Kc3198a52011-03-12 12:04:27 +05301109 .driver = {
1110 .name = "omapdss_hdmi",
1111 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001112 .pm = &hdmi_pm_ops,
Mythri P Kc3198a52011-03-12 12:04:27 +05301113 },
1114};
1115
Archit Tanejaef269582013-09-12 17:45:57 +05301116int __init hdmi4_init_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301117{
Tomi Valkeinen17ae4e82013-04-26 14:48:43 +03001118 return platform_driver_register(&omapdss_hdmihw_driver);
Mythri P Kc3198a52011-03-12 12:04:27 +05301119}
1120
Archit Tanejaef269582013-09-12 17:45:57 +05301121void __exit hdmi4_uninit_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301122{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02001123 platform_driver_unregister(&omapdss_hdmihw_driver);
Mythri P Kc3198a52011-03-12 12:04:27 +05301124}