blob: 6cf2fe2ac23400dbb646f4612e614fdda1dbcfe1 [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
353 if (IS_ERR(reg)) {
354 DSSERR("can't get VDDA_HDMI_DAC regulator\n");
355 return PTR_ERR(reg);
356 }
357
358 hdmi.vdda_hdmi_dac_reg = reg;
359 }
360
Tomi Valkeinencca35012012-04-26 14:48:32 +0300361 r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
362 if (r)
363 return r;
364
Mythri P Kc3198a52011-03-12 12:04:27 +0530365 return 0;
366}
367
Ricardo Neri37584762012-11-06 21:37:14 -0600368static void hdmi_uninit_display(struct omap_dss_device *dssdev)
Tomi Valkeinencca35012012-04-26 14:48:32 +0300369{
370 DSSDBG("uninit_display\n");
371
372 gpio_free(hdmi.ct_cp_hpd_gpio);
373 gpio_free(hdmi.ls_oe_gpio);
374 gpio_free(hdmi.hpd_gpio);
375}
376
Mythri P K46095b22012-01-06 17:52:09 +0530377static const struct hdmi_config *hdmi_find_timing(
378 const struct hdmi_config *timings_arr,
379 int len)
Mythri P Kc3198a52011-03-12 12:04:27 +0530380{
Mythri P K46095b22012-01-06 17:52:09 +0530381 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530382
Mythri P K46095b22012-01-06 17:52:09 +0530383 for (i = 0; i < len; i++) {
Mythri P K9e4ed602012-01-06 17:52:10 +0530384 if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code)
Mythri P K46095b22012-01-06 17:52:09 +0530385 return &timings_arr[i];
Mythri P Kc3198a52011-03-12 12:04:27 +0530386 }
Mythri P K46095b22012-01-06 17:52:09 +0530387 return NULL;
388}
389
390static const struct hdmi_config *hdmi_get_timings(void)
391{
392 const struct hdmi_config *arr;
393 int len;
394
Mythri P K9e4ed602012-01-06 17:52:10 +0530395 if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) {
Mythri P K46095b22012-01-06 17:52:09 +0530396 arr = vesa_timings;
397 len = ARRAY_SIZE(vesa_timings);
398 } else {
399 arr = cea_timings;
400 len = ARRAY_SIZE(cea_timings);
401 }
402
403 return hdmi_find_timing(arr, len);
404}
405
406static bool hdmi_timings_compare(struct omap_video_timings *timing1,
Archit Tanejacc937e52012-06-24 13:08:10 +0530407 const struct omap_video_timings *timing2)
Mythri P K46095b22012-01-06 17:52:09 +0530408{
409 int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
410
Tomi Valkeinenf236b892012-10-24 11:55:54 +0300411 if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) ==
412 DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) &&
Mythri P K46095b22012-01-06 17:52:09 +0530413 (timing2->x_res == timing1->x_res) &&
414 (timing2->y_res == timing1->y_res)) {
415
416 timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
417 timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
418 timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
419 timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
420
421 DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
422 "timing2_hsync = %d timing2_vsync = %d\n",
423 timing1_hsync, timing1_vsync,
424 timing2_hsync, timing2_vsync);
425
426 if ((timing1_hsync == timing2_hsync) &&
427 (timing1_vsync == timing2_vsync)) {
428 return true;
429 }
430 }
431 return false;
Mythri P Kc3198a52011-03-12 12:04:27 +0530432}
433
434static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
435{
Mythri P K46095b22012-01-06 17:52:09 +0530436 int i;
Mythri P Kc3198a52011-03-12 12:04:27 +0530437 struct hdmi_cm cm = {-1};
438 DSSDBG("hdmi_get_code\n");
439
Mythri P K46095b22012-01-06 17:52:09 +0530440 for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
441 if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
442 cm = cea_timings[i].cm;
443 goto end;
444 }
445 }
446 for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
447 if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
448 cm = vesa_timings[i].cm;
449 goto end;
Mythri P Kc3198a52011-03-12 12:04:27 +0530450 }
451 }
452
Mythri P K46095b22012-01-06 17:52:09 +0530453end: return cm;
Mythri P Kc3198a52011-03-12 12:04:27 +0530454
Mythri P Kc3198a52011-03-12 12:04:27 +0530455}
456
Archit Tanejac3dc6a72011-09-13 18:28:41 +0530457unsigned long hdmi_get_pixel_clock(void)
458{
459 /* HDMI Pixel Clock in Mhz */
Mythri P Ka05ce782012-01-06 17:52:08 +0530460 return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
Archit Tanejac3dc6a72011-09-13 18:28:41 +0530461}
462
Archit Taneja6cb07b22011-04-12 13:52:25 +0530463static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
464 struct hdmi_pll_info *pi)
Mythri P Kc3198a52011-03-12 12:04:27 +0530465{
Archit Taneja6cb07b22011-04-12 13:52:25 +0530466 unsigned long clkin, refclk;
Mythri P Kc3198a52011-03-12 12:04:27 +0530467 u32 mf;
468
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300469 clkin = clk_get_rate(hdmi.sys_clk) / 10000;
Mythri P Kc3198a52011-03-12 12:04:27 +0530470 /*
471 * Input clock is predivided by N + 1
472 * out put of which is reference clk
473 */
Tomi Valkeinen8d88767a2011-08-22 13:02:52 +0300474 if (dssdev->clocks.hdmi.regn == 0)
475 pi->regn = HDMI_DEFAULT_REGN;
476 else
477 pi->regn = dssdev->clocks.hdmi.regn;
478
Tomi Valkeinenb44e4582011-08-22 13:16:24 +0300479 refclk = clkin / pi->regn;
Mythri P Kc3198a52011-03-12 12:04:27 +0530480
Tomi Valkeinen8d88767a2011-08-22 13:02:52 +0300481 if (dssdev->clocks.hdmi.regm2 == 0)
482 pi->regm2 = HDMI_DEFAULT_REGM2;
483 else
484 pi->regm2 = dssdev->clocks.hdmi.regm2;
Mythri P Kc3198a52011-03-12 12:04:27 +0530485
486 /*
Mythri P Kdd2116a2012-02-21 12:10:58 +0530487 * multiplier is pixel_clk/ref_clk
488 * Multiplying by 100 to avoid fractional part removal
489 */
490 pi->regm = phy * pi->regm2 / refclk;
491
492 /*
Mythri P Kc3198a52011-03-12 12:04:27 +0530493 * fractional multiplier is remainder of the difference between
494 * multiplier and actual phy(required pixel clock thus should be
495 * multiplied by 2^18(262144) divided by the reference clock
496 */
Mythri P Kdd2116a2012-02-21 12:10:58 +0530497 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
498 pi->regmf = pi->regm2 * mf / refclk;
Mythri P Kc3198a52011-03-12 12:04:27 +0530499
500 /*
501 * Dcofreq should be set to 1 if required pixel clock
502 * is greater than 1000MHz
503 */
504 pi->dcofreq = phy > 1000 * 100;
Tomi Valkeinenb44e4582011-08-22 13:16:24 +0300505 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
Mythri P Kc3198a52011-03-12 12:04:27 +0530506
Mythri P K7b27da52011-09-08 19:06:19 +0530507 /* Set the reference clock to sysclk reference */
508 pi->refsel = HDMI_REFSEL_SYSCLK;
509
Mythri P Kc3198a52011-03-12 12:04:27 +0530510 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
511 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
512}
513
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300514static int hdmi_power_on_core(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530515{
Mythri P K46095b22012-01-06 17:52:09 +0530516 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +0530517
Tomi Valkeinencca35012012-04-26 14:48:32 +0300518 gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
519 gpio_set_value(hdmi.ls_oe_gpio, 1);
520
Tomi Valkeinena84b20654b2012-04-26 14:58:41 +0300521 /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
522 udelay(300);
523
Tomi Valkeinen17486942012-08-15 15:55:04 +0300524 r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
525 if (r)
526 goto err_vdac_enable;
527
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300528 r = hdmi_runtime_get();
529 if (r)
Tomi Valkeinencca35012012-04-26 14:48:32 +0300530 goto err_runtime_get;
Mythri P Kc3198a52011-03-12 12:04:27 +0530531
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300532 /* Make selection of HDMI in DSS */
533 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
534
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300535 return 0;
536
537err_runtime_get:
538 regulator_disable(hdmi.vdda_hdmi_dac_reg);
539err_vdac_enable:
540 gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
541 gpio_set_value(hdmi.ls_oe_gpio, 0);
542 return r;
543}
544
545static void hdmi_power_off_core(struct omap_dss_device *dssdev)
546{
547 hdmi_runtime_put();
548 regulator_disable(hdmi.vdda_hdmi_dac_reg);
549 gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
550 gpio_set_value(hdmi.ls_oe_gpio, 0);
551}
552
553static int hdmi_power_on_full(struct omap_dss_device *dssdev)
554{
555 int r;
556 struct omap_video_timings *p;
557 struct omap_overlay_manager *mgr = dssdev->output->manager;
558 unsigned long phy;
559
560 r = hdmi_power_on_core(dssdev);
561 if (r)
562 return r;
563
Archit Tanejacea87b92012-09-07 17:56:20 +0530564 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530565
Archit Taneja78493982012-08-08 16:50:42 +0530566 p = &hdmi.ip_data.cfg.timings;
Mythri P Kc3198a52011-03-12 12:04:27 +0530567
Archit Taneja78493982012-08-08 16:50:42 +0530568 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 +0530569
Mythri P Kc3198a52011-03-12 12:04:27 +0530570 phy = p->pixel_clock;
571
Mythri P K7b27da52011-09-08 19:06:19 +0530572 hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530573
Ricardo Neric0456be2012-04-27 13:48:45 -0500574 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530575
Mythri P K95a8aeb2011-09-08 19:06:18 +0530576 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
Mythri P K60634a22011-09-08 19:06:26 +0530577 r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530578 if (r) {
579 DSSDBG("Failed to lock PLL\n");
Tomi Valkeinencca35012012-04-26 14:48:32 +0300580 goto err_pll_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530581 }
582
Mythri P K60634a22011-09-08 19:06:26 +0530583 r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530584 if (r) {
585 DSSDBG("Failed to start PHY\n");
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500586 goto err_phy_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530587 }
588
Mythri P K60634a22011-09-08 19:06:26 +0530589 hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
Mythri P Kc3198a52011-03-12 12:04:27 +0530590
Mythri P Kc3198a52011-03-12 12:04:27 +0530591 /* bypass TV gamma table */
592 dispc_enable_gamma_table(0);
593
594 /* tv size */
Archit Tanejacea87b92012-09-07 17:56:20 +0530595 dss_mgr_set_timings(mgr, p);
Mythri P Kc3198a52011-03-12 12:04:27 +0530596
Ricardo Neric0456be2012-04-27 13:48:45 -0500597 r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
598 if (r)
599 goto err_vid_enable;
Mythri P Kc3198a52011-03-12 12:04:27 +0530600
Archit Tanejacea87b92012-09-07 17:56:20 +0530601 r = dss_mgr_enable(mgr);
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200602 if (r)
603 goto err_mgr_enable;
Tomi Valkeinen3870c902011-08-31 14:47:11 +0300604
Mythri P Kc3198a52011-03-12 12:04:27 +0530605 return 0;
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200606
607err_mgr_enable:
Ricardo Neric0456be2012-04-27 13:48:45 -0500608 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
609err_vid_enable:
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200610 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
Ricardo Nerid3b4aa52012-07-30 19:12:02 -0500611err_phy_enable:
Tomi Valkeinen33ca2372011-11-21 13:42:58 +0200612 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300613err_pll_enable:
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300614 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530615 return -EIO;
616}
617
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300618static void hdmi_power_off_full(struct omap_dss_device *dssdev)
Mythri P Kc3198a52011-03-12 12:04:27 +0530619{
Archit Tanejacea87b92012-09-07 17:56:20 +0530620 struct omap_overlay_manager *mgr = dssdev->output->manager;
621
622 dss_mgr_disable(mgr);
Mythri P Kc3198a52011-03-12 12:04:27 +0530623
Ricardo Neric0456be2012-04-27 13:48:45 -0500624 hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
Mythri P K60634a22011-09-08 19:06:26 +0530625 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
626 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
Tomi Valkeinencca35012012-04-26 14:48:32 +0300627
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300628 hdmi_power_off_core(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530629}
630
631int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
632 struct omap_video_timings *timings)
633{
634 struct hdmi_cm cm;
635
636 cm = hdmi_get_code(timings);
637 if (cm.code == -1) {
Mythri P Kc3198a52011-03-12 12:04:27 +0530638 return -EINVAL;
639 }
640
641 return 0;
642
643}
644
Archit Taneja78493982012-08-08 16:50:42 +0530645void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
646 struct omap_video_timings *timings)
Mythri P Kc3198a52011-03-12 12:04:27 +0530647{
648 struct hdmi_cm cm;
Archit Taneja78493982012-08-08 16:50:42 +0530649 const struct hdmi_config *t;
Mythri P Kc3198a52011-03-12 12:04:27 +0530650
Archit Tanejaed1aa902012-08-15 00:40:31 +0530651 mutex_lock(&hdmi.lock);
652
Archit Taneja78493982012-08-08 16:50:42 +0530653 cm = hdmi_get_code(timings);
654 hdmi.ip_data.cfg.cm = cm;
655
656 t = hdmi_get_timings();
657 if (t != NULL)
658 hdmi.ip_data.cfg = *t;
Tomi Valkeinenfa70dc52011-08-22 14:57:33 +0300659
Archit Tanejaed1aa902012-08-15 00:40:31 +0530660 mutex_unlock(&hdmi.lock);
Mythri P Kc3198a52011-03-12 12:04:27 +0530661}
662
Tomi Valkeinene40402c2012-03-02 18:01:07 +0200663static void hdmi_dump_regs(struct seq_file *s)
Mythri P K162874d2011-09-22 13:37:45 +0530664{
665 mutex_lock(&hdmi.lock);
666
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800667 if (hdmi_runtime_get()) {
668 mutex_unlock(&hdmi.lock);
Mythri P K162874d2011-09-22 13:37:45 +0530669 return;
Wei Yongjunf8fb7d72012-10-21 20:54:26 +0800670 }
Mythri P K162874d2011-09-22 13:37:45 +0530671
672 hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s);
673 hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s);
674 hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s);
675 hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s);
676
677 hdmi_runtime_put();
678 mutex_unlock(&hdmi.lock);
679}
680
Tomi Valkeinen47024562011-08-25 17:12:56 +0300681int omapdss_hdmi_read_edid(u8 *buf, int len)
682{
683 int r;
684
685 mutex_lock(&hdmi.lock);
686
687 r = hdmi_runtime_get();
688 BUG_ON(r);
689
690 r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len);
691
692 hdmi_runtime_put();
693 mutex_unlock(&hdmi.lock);
694
695 return r;
696}
697
Tomi Valkeinen759593f2011-08-29 18:10:20 +0300698bool omapdss_hdmi_detect(void)
699{
700 int r;
701
702 mutex_lock(&hdmi.lock);
703
704 r = hdmi_runtime_get();
705 BUG_ON(r);
706
707 r = hdmi.ip_data.ops->detect(&hdmi.ip_data);
708
709 hdmi_runtime_put();
710 mutex_unlock(&hdmi.lock);
711
712 return r == 1;
713}
714
Mythri P Kc3198a52011-03-12 12:04:27 +0530715int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
716{
Archit Tanejacea87b92012-09-07 17:56:20 +0530717 struct omap_dss_output *out = dssdev->output;
Mythri P Kc3198a52011-03-12 12:04:27 +0530718 int r = 0;
719
720 DSSDBG("ENTER hdmi_display_enable\n");
721
722 mutex_lock(&hdmi.lock);
723
Archit Tanejacea87b92012-09-07 17:56:20 +0530724 if (out == NULL || out->manager == NULL) {
725 DSSERR("failed to enable display: no output/manager\n");
Tomi Valkeinen05e1d602011-06-23 16:38:21 +0300726 r = -ENODEV;
727 goto err0;
728 }
729
Tomi Valkeinencca35012012-04-26 14:48:32 +0300730 hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
Tomi Valkeinenc49d0052012-01-17 11:09:57 +0200731
Mythri P Kc3198a52011-03-12 12:04:27 +0530732 r = omap_dss_start_device(dssdev);
733 if (r) {
734 DSSERR("failed to start device\n");
735 goto err0;
736 }
737
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300738 r = hdmi_power_on_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530739 if (r) {
740 DSSERR("failed to power on device\n");
Tomi Valkeinencca35012012-04-26 14:48:32 +0300741 goto err1;
Mythri P Kc3198a52011-03-12 12:04:27 +0530742 }
743
744 mutex_unlock(&hdmi.lock);
745 return 0;
746
Mythri P Kc3198a52011-03-12 12:04:27 +0530747err1:
748 omap_dss_stop_device(dssdev);
749err0:
750 mutex_unlock(&hdmi.lock);
751 return r;
752}
753
754void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
755{
756 DSSDBG("Enter hdmi_display_disable\n");
757
758 mutex_lock(&hdmi.lock);
759
Tomi Valkeinenbb426fc92012-10-19 17:42:10 +0300760 hdmi_power_off_full(dssdev);
Mythri P Kc3198a52011-03-12 12:04:27 +0530761
Mythri P Kc3198a52011-03-12 12:04:27 +0530762 omap_dss_stop_device(dssdev);
763
764 mutex_unlock(&hdmi.lock);
765}
766
Tomi Valkeinen44898232012-10-19 17:42:27 +0300767int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev)
768{
769 int r = 0;
770
771 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
772
773 mutex_lock(&hdmi.lock);
774
775 hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
776
777 r = hdmi_power_on_core(dssdev);
778 if (r) {
779 DSSERR("failed to power on device\n");
780 goto err0;
781 }
782
783 mutex_unlock(&hdmi.lock);
784 return 0;
785
786err0:
787 mutex_unlock(&hdmi.lock);
788 return r;
789}
790
791void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev)
792{
793 DSSDBG("Enter omapdss_hdmi_core_disable\n");
794
795 mutex_lock(&hdmi.lock);
796
797 hdmi_power_off_core(dssdev);
798
799 mutex_unlock(&hdmi.lock);
800}
801
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300802static int hdmi_get_clocks(struct platform_device *pdev)
803{
804 struct clk *clk;
805
806 clk = clk_get(&pdev->dev, "sys_clk");
807 if (IS_ERR(clk)) {
808 DSSERR("can't get sys_clk\n");
809 return PTR_ERR(clk);
810 }
811
812 hdmi.sys_clk = clk;
813
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300814 return 0;
815}
816
817static void hdmi_put_clocks(void)
818{
819 if (hdmi.sys_clk)
820 clk_put(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300821}
822
Ricardo Neri35547622012-03-20 21:02:01 -0600823#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
Ricardo Neri14840b92012-11-06 00:19:17 -0600824static int hdmi_probe_audio(struct platform_device *pdev)
825{
826 struct resource *res;
827 struct platform_device *aud_pdev;
828 u32 port_offset, port_size;
829 struct resource aud_res[2] = {
830 DEFINE_RES_MEM(-1, -1),
831 DEFINE_RES_DMA(-1),
832 };
833
834 res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
835 if (!res) {
836 DSSERR("can't get IORESOURCE_MEM HDMI\n");
837 return -EINVAL;
838 }
839
840 /*
841 * Pass DMA audio port to audio drivers.
842 * Audio drivers should not ioremap it.
843 */
844 hdmi.ip_data.ops->audio_get_dma_port(&port_offset, &port_size);
845
846 aud_res[0].start = res->start + port_offset;
847 aud_res[0].end = aud_res[0].start + port_size - 1;
848
849 res = platform_get_resource(hdmi.pdev, IORESOURCE_DMA, 0);
850 if (!res) {
851 DSSERR("can't get IORESOURCE_DMA HDMI\n");
852 return -EINVAL;
853 }
854
855 /* Pass the audio DMA request resource to audio drivers. */
856 aud_res[1].start = res->start;
857
858 /* create platform device for HDMI audio driver */
859 aud_pdev = platform_device_register_simple("omap_hdmi_audio",
860 pdev->id, aud_res,
861 ARRAY_SIZE(aud_res));
862 if (IS_ERR(aud_pdev)) {
863 DSSERR("Can't instantiate hdmi-audio\n");
864 return -ENODEV;
865 }
866
867 hdmi.audio_pdev = aud_pdev;
868
869 return 0;
870}
871
Ricardo Neri35547622012-03-20 21:02:01 -0600872int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
873{
874 u32 deep_color;
Ricardo Neri25a65352012-03-23 15:49:02 -0600875 bool deep_color_correct = false;
Ricardo Neri35547622012-03-20 21:02:01 -0600876 u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock;
877
878 if (n == NULL || cts == NULL)
879 return -EINVAL;
880
881 /* TODO: When implemented, query deep color mode here. */
882 deep_color = 100;
883
Ricardo Neri25a65352012-03-23 15:49:02 -0600884 /*
885 * When using deep color, the default N value (as in the HDMI
886 * specification) yields to an non-integer CTS. Hence, we
887 * modify it while keeping the restrictions described in
888 * section 7.2.1 of the HDMI 1.4a specification.
889 */
Ricardo Neri35547622012-03-20 21:02:01 -0600890 switch (sample_freq) {
891 case 32000:
Ricardo Neri25a65352012-03-23 15:49:02 -0600892 case 48000:
893 case 96000:
894 case 192000:
895 if (deep_color == 125)
896 if (pclk == 27027 || pclk == 74250)
897 deep_color_correct = true;
898 if (deep_color == 150)
899 if (pclk == 27027)
900 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600901 break;
902 case 44100:
Ricardo Neri25a65352012-03-23 15:49:02 -0600903 case 88200:
904 case 176400:
905 if (deep_color == 125)
906 if (pclk == 27027)
907 deep_color_correct = true;
Ricardo Neri35547622012-03-20 21:02:01 -0600908 break;
909 default:
Ricardo Neri35547622012-03-20 21:02:01 -0600910 return -EINVAL;
911 }
912
Ricardo Neri25a65352012-03-23 15:49:02 -0600913 if (deep_color_correct) {
914 switch (sample_freq) {
915 case 32000:
916 *n = 8192;
917 break;
918 case 44100:
919 *n = 12544;
920 break;
921 case 48000:
922 *n = 8192;
923 break;
924 case 88200:
925 *n = 25088;
926 break;
927 case 96000:
928 *n = 16384;
929 break;
930 case 176400:
931 *n = 50176;
932 break;
933 case 192000:
934 *n = 32768;
935 break;
936 default:
937 return -EINVAL;
938 }
939 } else {
940 switch (sample_freq) {
941 case 32000:
942 *n = 4096;
943 break;
944 case 44100:
945 *n = 6272;
946 break;
947 case 48000:
948 *n = 6144;
949 break;
950 case 88200:
951 *n = 12544;
952 break;
953 case 96000:
954 *n = 12288;
955 break;
956 case 176400:
957 *n = 25088;
958 break;
959 case 192000:
960 *n = 24576;
961 break;
962 default:
963 return -EINVAL;
964 }
965 }
Ricardo Neri35547622012-03-20 21:02:01 -0600966 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
967 *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
968
969 return 0;
970}
Ricardo Nerif3a974912012-05-09 21:09:50 -0500971
972int hdmi_audio_enable(void)
973{
974 DSSDBG("audio_enable\n");
975
976 return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
977}
978
979void hdmi_audio_disable(void)
980{
981 DSSDBG("audio_disable\n");
982
983 hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
984}
985
986int hdmi_audio_start(void)
987{
988 DSSDBG("audio_start\n");
989
990 return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
991}
992
993void hdmi_audio_stop(void)
994{
995 DSSDBG("audio_stop\n");
996
997 hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
998}
999
1000bool hdmi_mode_has_audio(void)
1001{
1002 if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI)
1003 return true;
1004 else
1005 return false;
1006}
1007
1008int hdmi_audio_config(struct omap_dss_audio *audio)
1009{
1010 return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
1011}
1012
Ricardo Neri35547622012-03-20 21:02:01 -06001013#endif
1014
Tomi Valkeinen15216532012-09-06 14:29:31 +03001015static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001016{
1017 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
Tomi Valkeinen2bbcce52012-10-29 12:40:46 +02001018 const char *def_disp_name = omapdss_get_default_display_name();
Tomi Valkeinen15216532012-09-06 14:29:31 +03001019 struct omap_dss_device *def_dssdev;
1020 int i;
1021
1022 def_dssdev = NULL;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001023
1024 for (i = 0; i < pdata->num_devices; ++i) {
1025 struct omap_dss_device *dssdev = pdata->devices[i];
1026
1027 if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
1028 continue;
1029
Tomi Valkeinen15216532012-09-06 14:29:31 +03001030 if (def_dssdev == NULL)
1031 def_dssdev = dssdev;
Tomi Valkeinencca35012012-04-26 14:48:32 +03001032
Tomi Valkeinen15216532012-09-06 14:29:31 +03001033 if (def_disp_name != NULL &&
1034 strcmp(dssdev->name, def_disp_name) == 0) {
1035 def_dssdev = dssdev;
1036 break;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001037 }
Tomi Valkeinen15216532012-09-06 14:29:31 +03001038 }
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001039
Tomi Valkeinen15216532012-09-06 14:29:31 +03001040 return def_dssdev;
1041}
1042
1043static void __init hdmi_probe_pdata(struct platform_device *pdev)
1044{
Tomi Valkeinen52744842012-09-10 13:58:29 +03001045 struct omap_dss_device *plat_dssdev;
Tomi Valkeinen15216532012-09-06 14:29:31 +03001046 struct omap_dss_device *dssdev;
1047 struct omap_dss_hdmi_data *priv;
1048 int r;
1049
Tomi Valkeinen52744842012-09-10 13:58:29 +03001050 plat_dssdev = hdmi_find_dssdev(pdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001051
Tomi Valkeinen52744842012-09-10 13:58:29 +03001052 if (!plat_dssdev)
1053 return;
1054
1055 dssdev = dss_alloc_and_init_device(&pdev->dev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001056 if (!dssdev)
1057 return;
1058
Tomi Valkeinen52744842012-09-10 13:58:29 +03001059 dss_copy_device_pdata(dssdev, plat_dssdev);
1060
Tomi Valkeinen15216532012-09-06 14:29:31 +03001061 priv = dssdev->data;
1062
1063 hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
1064 hdmi.ls_oe_gpio = priv->ls_oe_gpio;
1065 hdmi.hpd_gpio = priv->hpd_gpio;
1066
Tomi Valkeinenbcb226a2012-09-07 15:21:36 +03001067 dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
1068
Tomi Valkeinen15216532012-09-06 14:29:31 +03001069 r = hdmi_init_display(dssdev);
1070 if (r) {
1071 DSSERR("device %s init failed: %d\n", dssdev->name, r);
Tomi Valkeinen52744842012-09-10 13:58:29 +03001072 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001073 return;
1074 }
1075
Tomi Valkeinen52744842012-09-10 13:58:29 +03001076 r = dss_add_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001077 if (r) {
1078 DSSERR("device %s register failed: %d\n", dssdev->name, r);
Ricardo Nerid18bc452012-11-06 00:19:15 -06001079 hdmi_uninit_display(dssdev);
Tomi Valkeinen52744842012-09-10 13:58:29 +03001080 dss_put_device(dssdev);
Tomi Valkeinen15216532012-09-06 14:29:31 +03001081 return;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001082 }
1083}
1084
Archit Taneja81b87f52012-09-26 16:30:49 +05301085static void __init hdmi_init_output(struct platform_device *pdev)
1086{
1087 struct omap_dss_output *out = &hdmi.output;
1088
1089 out->pdev = pdev;
1090 out->id = OMAP_DSS_OUTPUT_HDMI;
1091 out->type = OMAP_DISPLAY_TYPE_HDMI;
1092
1093 dss_register_output(out);
1094}
1095
1096static void __exit hdmi_uninit_output(struct platform_device *pdev)
1097{
1098 struct omap_dss_output *out = &hdmi.output;
1099
1100 dss_unregister_output(out);
1101}
1102
Mythri P Kc3198a52011-03-12 12:04:27 +05301103/* HDMI HW IP initialisation */
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001104static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301105{
Ricardo Neriaf23cb32012-11-06 00:19:11 -06001106 struct resource *res;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001107 int r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301108
Mythri P Kc3198a52011-03-12 12:04:27 +05301109 hdmi.pdev = pdev;
1110
1111 mutex_init(&hdmi.lock);
Ricardo Neri66a06b02012-11-06 00:19:14 -06001112 mutex_init(&hdmi.ip_data.lock);
Mythri P Kc3198a52011-03-12 12:04:27 +05301113
Ricardo Neriaf23cb32012-11-06 00:19:11 -06001114 res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
1115 if (!res) {
Mythri P Kc3198a52011-03-12 12:04:27 +05301116 DSSERR("can't get IORESOURCE_MEM HDMI\n");
1117 return -EINVAL;
1118 }
1119
1120 /* Base address taken from platform */
Ricardo Neri47e443b2012-11-06 00:19:12 -06001121 hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res);
Mythri P K95a8aeb2011-09-08 19:06:18 +05301122 if (!hdmi.ip_data.base_wp) {
Mythri P Kc3198a52011-03-12 12:04:27 +05301123 DSSERR("can't ioremap WP\n");
1124 return -ENOMEM;
1125 }
1126
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001127 r = hdmi_get_clocks(pdev);
1128 if (r) {
Ricardo Neri47e443b2012-11-06 00:19:12 -06001129 DSSERR("can't get clocks\n");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001130 return r;
1131 }
1132
1133 pm_runtime_enable(&pdev->dev);
1134
Mythri P K95a8aeb2011-09-08 19:06:18 +05301135 hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS;
1136 hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
1137 hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
1138 hdmi.ip_data.phy_offset = HDMI_PHY;
Archit Taneja78493982012-08-08 16:50:42 +05301139
Ricardo Neri66a06b02012-11-06 00:19:14 -06001140 r = hdmi_panel_init();
1141 if (r) {
1142 DSSERR("can't init panel\n");
1143 goto err_panel_init;
1144 }
Mythri P Kc3198a52011-03-12 12:04:27 +05301145
Tomi Valkeinene40402c2012-03-02 18:01:07 +02001146 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
1147
Archit Taneja81b87f52012-09-26 16:30:49 +05301148 hdmi_init_output(pdev);
1149
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001150 hdmi_probe_pdata(pdev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001151
Ricardo Neri14840b92012-11-06 00:19:17 -06001152#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
1153 r = hdmi_probe_audio(pdev);
1154 if (r)
1155 DSSWARN("could not create platform device for audio");
1156#endif
1157
Mythri P Kc3198a52011-03-12 12:04:27 +05301158 return 0;
Ricardo Neri66a06b02012-11-06 00:19:14 -06001159
1160err_panel_init:
1161 hdmi_put_clocks();
1162 return r;
Mythri P Kc3198a52011-03-12 12:04:27 +05301163}
1164
Tomi Valkeinencca35012012-04-26 14:48:32 +03001165static int __exit hdmi_remove_child(struct device *dev, void *data)
1166{
1167 struct omap_dss_device *dssdev = to_dss_device(dev);
1168 hdmi_uninit_display(dssdev);
1169 return 0;
1170}
1171
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001172static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
Mythri P Kc3198a52011-03-12 12:04:27 +05301173{
Ricardo Neri14840b92012-11-06 00:19:17 -06001174#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
1175 if (hdmi.audio_pdev != NULL)
1176 platform_device_unregister(hdmi.audio_pdev);
1177#endif
1178
Tomi Valkeinencca35012012-04-26 14:48:32 +03001179 device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
1180
Tomi Valkeinen52744842012-09-10 13:58:29 +03001181 dss_unregister_child_devices(&pdev->dev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001182
Mythri P Kc3198a52011-03-12 12:04:27 +05301183 hdmi_panel_exit();
1184
Archit Taneja81b87f52012-09-26 16:30:49 +05301185 hdmi_uninit_output(pdev);
1186
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001187 pm_runtime_disable(&pdev->dev);
1188
1189 hdmi_put_clocks();
1190
Mythri P Kc3198a52011-03-12 12:04:27 +05301191 return 0;
1192}
1193
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001194static int hdmi_runtime_suspend(struct device *dev)
1195{
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301196 clk_disable_unprepare(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001197
1198 dispc_runtime_put();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001199
1200 return 0;
1201}
1202
1203static int hdmi_runtime_resume(struct device *dev)
1204{
1205 int r;
1206
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001207 r = dispc_runtime_get();
1208 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +02001209 return r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001210
Rajendra Nayakf11766d2012-06-27 14:21:26 +05301211 clk_prepare_enable(hdmi.sys_clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001212
1213 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001214}
1215
1216static const struct dev_pm_ops hdmi_pm_ops = {
1217 .runtime_suspend = hdmi_runtime_suspend,
1218 .runtime_resume = hdmi_runtime_resume,
1219};
1220
Mythri P Kc3198a52011-03-12 12:04:27 +05301221static struct platform_driver omapdss_hdmihw_driver = {
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001222 .remove = __exit_p(omapdss_hdmihw_remove),
Mythri P Kc3198a52011-03-12 12:04:27 +05301223 .driver = {
1224 .name = "omapdss_hdmi",
1225 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001226 .pm = &hdmi_pm_ops,
Mythri P Kc3198a52011-03-12 12:04:27 +05301227 },
1228};
1229
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001230int __init hdmi_init_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301231{
Tomi Valkeinen61055d42012-03-07 12:53:38 +02001232 return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe);
Mythri P Kc3198a52011-03-12 12:04:27 +05301233}
1234
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001235void __exit hdmi_uninit_platform_driver(void)
Mythri P Kc3198a52011-03-12 12:04:27 +05301236{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02001237 platform_driver_unregister(&omapdss_hdmihw_driver);
Mythri P Kc3198a52011-03-12 12:04:27 +05301238}