blob: a44e909d97a6454e4e1d65f53525abb4716fa350 [file] [log] [blame]
Ajay Singh Parmar2a2e3d62015-02-12 16:57:28 -08001/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#include <err.h>
30#include <debug.h>
31#include <reg.h>
Casey Piper77f69c52015-03-20 15:55:12 -070032#include <malloc.h>
33#include <string.h>
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -070034#include <msm_panel.h>
35#include <platform/timer.h>
36#include <platform/clock.h>
Casey Piper77f69c52015-03-20 15:55:12 -070037#include "mdp5.h"
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -070038#include <platform/iomap.h>
Casey Piper77f69c52015-03-20 15:55:12 -070039#include "mdss_hdmi.h"
Casey Piper6c2f1132015-03-24 11:37:19 -070040#include <target/display.h>
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -070041
42static struct msm_fb_panel_data panel;
Casey Piper77f69c52015-03-20 15:55:12 -070043extern int msm_display_init(struct msm_fb_panel_data *pdata);
Casey Piper7ab92992015-03-18 14:19:23 -070044static bool hdmi_power_enabled;
45static bool hdmi_panel_clock_enabled;
46static bool hdmi_pll_clock_enabled;
Casey Piper77f69c52015-03-20 15:55:12 -070047
Casey Piper1d3611d2015-03-17 15:45:44 -070048/* Supported HDMI Audio channels */
49#define MSM_HDMI_AUDIO_CHANNEL_2 1
50#define MSM_HDMI_AUDIO_CHANNEL_MAX 8
51
52enum msm_hdmi_supported_audio_sample_rates {
53 AUDIO_SAMPLE_RATE_32KHZ,
54 AUDIO_SAMPLE_RATE_44_1KHZ,
55 AUDIO_SAMPLE_RATE_48KHZ,
56 AUDIO_SAMPLE_RATE_88_2KHZ,
57 AUDIO_SAMPLE_RATE_96KHZ,
58 AUDIO_SAMPLE_RATE_176_4KHZ,
59 AUDIO_SAMPLE_RATE_192KHZ,
60 AUDIO_SAMPLE_RATE_MAX
61};
62
63struct hdmi_msm_audio_acr {
64 uint32_t n; /* N parameter for clock regeneration */
65 uint32_t cts; /* CTS parameter for clock regeneration */
66};
67
68struct hdmi_msm_audio_arcs {
69 uint32_t pclk;
70 struct hdmi_msm_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
71};
72
73#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { pclk, __VA_ARGS__ }
74
75/* Audio constants lookup table for hdmi_msm_audio_acr_setup */
76/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
77static struct hdmi_msm_audio_arcs hdmi_audio_acr_lut[] = {
78 /* 25.200MHz */
79 HDMI_MSM_AUDIO_ARCS(25200, {
80 {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000},
81 {12288, 25200}, {25088, 28000}, {24576, 25200} }),
82 /* 27.000MHz */
83 HDMI_MSM_AUDIO_ARCS(27000, {
84 {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
85 {12288, 27000}, {25088, 30000}, {24576, 27000} }),
86 /* 27.027MHz */
87 HDMI_MSM_AUDIO_ARCS(27030, {
88 {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
89 {12288, 27027}, {25088, 30030}, {24576, 27027} }),
90 /* 74.250MHz */
91 HDMI_MSM_AUDIO_ARCS(74250, {
92 {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500},
93 {12288, 74250}, {25088, 82500}, {24576, 74250} }),
94 /* 148.500MHz */
95 HDMI_MSM_AUDIO_ARCS(148500, {
96 {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000},
97 {12288, 148500}, {25088, 165000}, {24576, 148500} }),
98 /* 297.000MHz */
99 HDMI_MSM_AUDIO_ARCS(297000, {
100 {3072, 222750}, {4704, 247500}, {5120, 247500}, {9408, 247500},
101 {10240, 247500}, {18816, 247500}, {20480, 247500} }),
102};
103
Ajay Singh Parmar2a2e3d62015-02-12 16:57:28 -0800104extern int msm_display_init(struct msm_fb_panel_data *pdata);
105
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700106/* AVI INFOFRAME DATA */
107#define NUM_MODES_AVI 20
108#define AVI_MAX_DATA_BYTES 13
109
110enum {
111 DATA_BYTE_1,
112 DATA_BYTE_2,
113 DATA_BYTE_3,
114 DATA_BYTE_4,
115 DATA_BYTE_5,
116 DATA_BYTE_6,
117 DATA_BYTE_7,
118 DATA_BYTE_8,
119 DATA_BYTE_9,
120 DATA_BYTE_10,
121 DATA_BYTE_11,
122 DATA_BYTE_12,
123 DATA_BYTE_13,
124};
125
126#define IFRAME_PACKET_OFFSET 0x80
127/*
128 * InfoFrame Type Code:
129 * 0x0 - Reserved
130 * 0x1 - Vendor Specific
131 * 0x2 - Auxiliary Video Information
132 * 0x3 - Source Product Description
133 * 0x4 - AUDIO
134 * 0x5 - MPEG Source
135 * 0x6 - NTSC VBI
136 * 0x7 - 0xFF - Reserved
137 */
138#define AVI_IFRAME_TYPE 0x2
139#define AVI_IFRAME_VERSION 0x2
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -0800140#define AVI_IFRAME_LINE_NUMBER 1
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700141#define LEFT_SHIFT_BYTE(x) ((x) << 8)
142#define LEFT_SHIFT_WORD(x) ((x) << 16)
143#define LEFT_SHIFT_24BITS(x) ((x) << 24)
144
Casey Piper1d3611d2015-03-17 15:45:44 -0700145#define MAX_AUDIO_DATA_BLOCK_SIZE 0x80
Casey Piper97d25272015-03-17 15:10:34 -0700146#define DBC_START_OFFSET 4
147#define VIC_INDEX 3
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800148#define HDMI_VIC_STR_MAX 4
149#define MAX_EDID_BLOCK_SIZE 0x80
Casey Piper97d25272015-03-17 15:10:34 -0700150
151enum edid_data_block_type {
152 RESERVED_DATA_BLOCK1 = 0,
153 AUDIO_DATA_BLOCK,
154 VIDEO_DATA_BLOCK,
155 VENDOR_SPECIFIC_DATA_BLOCK,
156 SPEAKER_ALLOCATION_DATA_BLOCK,
157 VESA_DTC_DATA_BLOCK,
158 RESERVED_DATA_BLOCK2,
159 USE_EXTENDED_TAG
160};
161
162/* video formats defined by CEA 861D */
163#define HDMI_VFRMT_UNKNOWN 0
164#define HDMI_VFRMT_640x480p60_4_3 1
165#define HDMI_VFRMT_1280x720p60_16_9 4
166#define HDMI_VFRMT_1920x1080p60_16_9 16
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800167#define HDMI_VFRMT_4096x2160p24_256_135 98
168#define HDMI_VFRMT_4096x2160p25_256_135 99
169#define HDMI_VFRMT_4096x2160p30_256_135 100
170#define HDMI_VFRMT_3840x2160p24_64_27 103
171#define HDMI_VFRMT_3840x2160p25_64_27 104
172#define HDMI_VFRMT_3840x2160p30_64_27 105
173#define HDMI_EVFRMT_4096x2160p24_16_9 131
174#define HDMI_VFRMT_COUNT 10
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -0800175#define HDMI_VFRMT_END 127
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800176#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
177 (!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
Tatenda Chipeperekwaf4917642016-03-23 11:34:48 -0700178#define MSM_MDP_MAX_PIPE_WIDTH 2560
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800179static uint8_t mdss_hdmi_video_formats[HDMI_VFRMT_COUNT];
180static uint8_t mdss_hdmi_mode_count;
Casey Piper97d25272015-03-17 15:10:34 -0700181
182#define DEFAULT_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
183static uint8_t mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
184static uint8_t mdss_hdmi_pref_fmt = HDMI_VFRMT_UNKNOWN;
185static uint8_t pt_scan_info;
186static uint8_t it_scan_info;
187static uint8_t ce_scan_info;
188
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800189static uint8_t mdss_hdmi_edid_buf[MAX_EDID_BLOCK_SIZE];
Casey Piper97d25272015-03-17 15:10:34 -0700190
191enum aspect_ratio {
192 HDMI_RES_AR_INVALID,
193 HDMI_RES_AR_4_3,
194 HDMI_RES_AR_5_4,
195 HDMI_RES_AR_16_9,
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800196 HDMI_RES_AR_64_27,
Casey Piper97d25272015-03-17 15:10:34 -0700197 HDMI_RES_AR_16_10,
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800198 HDMI_RES_AR_256_135,
Casey Piper97d25272015-03-17 15:10:34 -0700199 HDMI_RES_AR_MAX,
200};
201
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -0800202enum hdmi_quantization_range {
203 HDMI_QUANTIZATION_DEFAULT,
204 HDMI_QUANTIZATION_LIMITED_RANGE,
205 HDMI_QUANTIZATION_FULL_RANGE
206};
207
208enum hdmi_scaling_info {
209 HDMI_SCALING_NONE,
210 HDMI_SCALING_HORZ,
211 HDMI_SCALING_VERT,
212 HDMI_SCALING_HORZ_VERT,
213};
214
215struct hdmi_avi_iframe_bar_info {
216 bool vert_binfo_present;
217 bool horz_binfo_present;
218 uint32_t end_of_top_bar;
219 uint32_t start_of_bottom_bar;
220 uint32_t end_of_left_bar;
221 uint32_t start_of_right_bar;
222};
223
224struct hdmi_avi_infoframe_config {
225 uint32_t pixel_format;
226 uint32_t scan_info;
227 bool act_fmt_info_present;
228 uint32_t colorimetry_info;
229 uint32_t ext_colorimetry_info;
230 uint32_t rgb_quantization_range;
231 uint32_t yuv_quantization_range;
232 uint32_t scaling_info;
233 bool is_it_content;
234 uint8_t content_type;
235 uint8_t pixel_rpt_factor;
236 struct hdmi_avi_iframe_bar_info bar_info;
237};
238
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700239struct mdss_hdmi_timing_info {
240 uint32_t video_format;
241 uint32_t active_h;
242 uint32_t front_porch_h;
243 uint32_t pulse_width_h;
244 uint32_t back_porch_h;
245 uint32_t active_low_h;
246 uint32_t active_v;
247 uint32_t front_porch_v;
248 uint32_t pulse_width_v;
249 uint32_t back_porch_v;
250 uint32_t active_low_v;
251 /* Must divide by 1000 to get the actual frequency in MHZ */
252 uint32_t pixel_freq;
253 /* Must divide by 1000 to get the actual frequency in HZ */
254 uint32_t refresh_rate;
255 uint32_t interlaced;
256 uint32_t supported;
Casey Piper97d25272015-03-17 15:10:34 -0700257 enum aspect_ratio ar;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700258};
259
Casey Piper97d25272015-03-17 15:10:34 -0700260#define HDMI_VFRMT_640x480p60_4_3_TIMING \
261 {HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true, \
262 480, 10, 2, 33, true, 25200, 60000, false, true, HDMI_RES_AR_4_3}
Ajay Singh Parmar392f07a2014-11-19 15:06:19 -0800263
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700264#define HDMI_VFRMT_1280x720p60_16_9_TIMING \
265 {HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false, \
Casey Piper97d25272015-03-17 15:10:34 -0700266 720, 5, 5, 20, false, 74250, 60000, false, true, HDMI_RES_AR_16_9}
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700267
Casey Piper97d25272015-03-17 15:10:34 -0700268#define HDMI_VFRMT_1920x1080p60_16_9_TIMING \
269 {HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false, \
270 1080, 4, 5, 36, false, 148500, 60000, false, true, HDMI_RES_AR_16_9}
271
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800272#define HDMI_VFRMT_4096x2160p24_256_135_TIMING \
273 {HDMI_VFRMT_4096x2160p24_256_135, 4096, 1020, 88, 296, false, \
274 2160, 8, 10, 72, false, 297000, 24000, false, true, \
275 HDMI_RES_AR_256_135}
276
277#define HDMI_VFRMT_4096x2160p25_256_135_TIMING \
278 {HDMI_VFRMT_4096x2160p25_256_135, 4096, 968, 88, 128, false, \
279 2160, 8, 10, 72, false, 297000, 25000, false, true, \
280 HDMI_RES_AR_256_135}
281
282#define HDMI_VFRMT_4096x2160p30_256_135_TIMING \
283 {HDMI_VFRMT_4096x2160p30_256_135, 4096, 88, 88, 128, false, \
284 2160, 8, 10, 72, false, 297000, 30000, false, true, \
285 HDMI_RES_AR_256_135}
286
287#define HDMI_EVFRMT_4096x2160p24_16_9_TIMING \
288 {HDMI_EVFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false, \
289 2160, 8, 10, 72, false, 297000, 24000, false, true, \
290 HDMI_RES_AR_16_9}
291
292#define HDMI_VFRMT_3840x2160p24_64_27_TIMING \
293 {HDMI_VFRMT_3840x2160p24_64_27, 3840, 1276, 88, 296, false, \
294 2160, 8, 10, 72, false, 297000, 24000, false, true, \
295 HDMI_RES_AR_64_27}
296
297#define HDMI_VFRMT_3840x2160p25_64_27_TIMING \
298 {HDMI_VFRMT_3840x2160p25_64_27, 3840, 1056, 88, 296, false, \
299 2160, 8, 10, 72, false, 297000, 25000, false, true, \
300 HDMI_RES_AR_64_27}
301
302#define HDMI_VFRMT_3840x2160p30_64_27_TIMING \
303 {HDMI_VFRMT_3840x2160p30_64_27, 3840, 176, 88, 296, false, \
304 2160, 8, 10, 72, false, 297000, 30000, false, true, \
305 HDMI_RES_AR_64_27}
306
Casey Piper97d25272015-03-17 15:10:34 -0700307#define MSM_HDMI_MODES_GET_DETAILS(mode, MODE) do { \
308 struct mdss_hdmi_timing_info info = MODE##_TIMING; \
309 *mode = info; \
310 } while (0)
311
312static inline int mdss_hdmi_get_timing_info(
313 struct mdss_hdmi_timing_info *mode, int id)
314{
315 int ret = 0;
316
317 switch (id) {
318 case HDMI_VFRMT_640x480p60_4_3:
319 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_640x480p60_4_3);
320 break;
321
322 case HDMI_VFRMT_1280x720p60_16_9:
323 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1280x720p60_16_9);
324 break;
325
326 case HDMI_VFRMT_1920x1080p60_16_9:
327 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1920x1080p60_16_9);
328 break;
329
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800330 case HDMI_VFRMT_4096x2160p24_256_135:
331 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p24_256_135);
332 break;
333
334 case HDMI_VFRMT_4096x2160p25_256_135:
335 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p25_256_135);
336 break;
337
338 case HDMI_VFRMT_4096x2160p30_256_135:
339 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p30_256_135);
340 break;
341
342 case HDMI_EVFRMT_4096x2160p24_16_9:
343 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_EVFRMT_4096x2160p24_16_9);
344 break;
345
346 case HDMI_VFRMT_3840x2160p24_64_27:
347 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p24_64_27);
348 break;
349
350 case HDMI_VFRMT_3840x2160p25_64_27:
351 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p25_64_27);
352 break;
353
354 case HDMI_VFRMT_3840x2160p30_64_27:
355 MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p30_64_27);
356 break;
357
Casey Piper97d25272015-03-17 15:10:34 -0700358 default:
359 ret = ERROR;
360 }
361
362 return ret;
363}
364
Casey Piper1d3611d2015-03-17 15:45:44 -0700365static void mdss_hdmi_audio_acr_setup(uint32_t sample_rate)
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700366{
Casey Piper1d3611d2015-03-17 15:45:44 -0700367 /* Read first before writing */
368 uint32_t acr_pck_ctrl_reg = readl(HDMI_ACR_PKT_CTRL);
369 struct mdss_hdmi_timing_info tinfo = {0};
370 uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
371 struct hdmi_msm_audio_arcs *audio_acr = &hdmi_audio_acr_lut[0];
372 uint32_t lut_size = sizeof(hdmi_audio_acr_lut)
373 / sizeof(*hdmi_audio_acr_lut);
374 uint32_t i, n, cts, layout, multiplier, aud_pck_ctrl_2_reg;
375 uint32_t channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700376
Casey Piper1d3611d2015-03-17 15:45:44 -0700377 if (ret || !tinfo.supported) {
378 dprintf(CRITICAL, "%s: video format %d not supported\n",
379 __func__, mdss_hdmi_video_fmt);
380 return;
381 }
382
383 for (i = 0; i < lut_size; audio_acr = &hdmi_audio_acr_lut[++i]) {
384 if (audio_acr->pclk == tinfo.pixel_freq)
385 break;
386 }
387
388 if (i >= lut_size) {
389 dprintf(CRITICAL, "%s: pixel clk %d not supported\n", __func__,
390 tinfo.pixel_freq);
391 return;
392 }
393
394 n = audio_acr->lut[sample_rate].n;
395 cts = audio_acr->lut[sample_rate].cts;
396 layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_num) ? 0 : 1;
397
398 if ((AUDIO_SAMPLE_RATE_192KHZ == sample_rate) ||
399 (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
400 multiplier = 4;
401 n >>= 2; /* divide N by 4 and use multiplier */
402 } else if ((AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
403 (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate)) {
404 multiplier = 2;
405 n >>= 1; /* divide N by 2 and use multiplier */
406 } else {
407 multiplier = 1;
408 }
409
410 dprintf(SPEW, "%s: n=%u, cts=%u, layout=%u\n", __func__, n, cts,
411 layout);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700412
413 /* AUDIO_PRIORITY | SOURCE */
414 acr_pck_ctrl_reg |= 0x80000100;
415
Casey Piper1d3611d2015-03-17 15:45:44 -0700416 /* Reset multiplier bits */
417 acr_pck_ctrl_reg &= ~(7 << 16);
418
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700419 /* N_MULTIPLE(multiplier) */
420 acr_pck_ctrl_reg |= (multiplier & 7) << 16;
421
Casey Piper1d3611d2015-03-17 15:45:44 -0700422 if ((AUDIO_SAMPLE_RATE_48KHZ == sample_rate) ||
423 (AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
424 (AUDIO_SAMPLE_RATE_192KHZ == sample_rate)) {
425 /* SELECT(3) */
426 acr_pck_ctrl_reg |= 3 << 4;
427 /* CTS_48 */
428 cts <<= 12;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700429
Casey Piper1d3611d2015-03-17 15:45:44 -0700430 /* CTS: need to determine how many fractional bits */
431 writel(cts, HDMI_ACR_48_0);
432 /* N */
433 writel(n, HDMI_ACR_48_1);
434 } else if ((AUDIO_SAMPLE_RATE_44_1KHZ == sample_rate) ||
435 (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate) ||
436 (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
437 /* SELECT(2) */
438 acr_pck_ctrl_reg |= 2 << 4;
439 /* CTS_44 */
440 cts <<= 12;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700441
Casey Piper1d3611d2015-03-17 15:45:44 -0700442 /* CTS: need to determine how many fractional bits */
443 writel(cts, HDMI_ACR_44_0);
444 /* N */
445 writel(n, HDMI_ACR_44_1);
446 } else { /* default to 32k */
447 /* SELECT(1) */
448 acr_pck_ctrl_reg |= 1 << 4;
449 /* CTS_32 */
450 cts <<= 12;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700451
Casey Piper1d3611d2015-03-17 15:45:44 -0700452 /* CTS: need to determine how many fractional bits */
453 writel(cts, HDMI_ACR_32_0);
454 /* N */
455 writel(n, HDMI_ACR_32_1);
456 }
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700457
458 /* Payload layout depends on number of audio channels */
Casey Piper1d3611d2015-03-17 15:45:44 -0700459 /* LAYOUT_SEL(layout) */
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700460 aud_pck_ctrl_2_reg = 1 | (layout << 1);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700461 /* override | layout */
462 writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
463
464 /* SEND | CONT */
Casey Piper1d3611d2015-03-17 15:45:44 -0700465 acr_pck_ctrl_reg |= 0x00000003;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700466
467 writel(acr_pck_ctrl_reg, HDMI_ACR_PKT_CTRL);
468}
469
Casey Piper1d3611d2015-03-17 15:45:44 -0700470static void mdss_hdmi_audio_info_setup(void)
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700471{
Casey Piper1d3611d2015-03-17 15:45:44 -0700472 uint32_t channel_count = MSM_HDMI_AUDIO_CHANNEL_2;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700473 uint32_t channel_allocation = 0;
474 uint32_t level_shift = 0;
475 uint32_t down_mix = 0;
476 uint32_t check_sum, audio_info_0_reg, audio_info_1_reg;
477 uint32_t audio_info_ctrl_reg;
478 uint32_t aud_pck_ctrl_2_reg;
479 uint32_t layout;
480
Casey Piper1d3611d2015-03-17 15:45:44 -0700481 layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_count) ? 0 : 1;;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700482 aud_pck_ctrl_2_reg = 1 | (layout << 1);
483 writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
484
485 /* Read first then write because it is bundled with other controls */
486 audio_info_ctrl_reg = readl(HDMI_INFOFRAME_CTRL0);
487
488 channel_allocation = 0; /* Default to FR,FL */
489
490 /* Program the Channel-Speaker allocation */
491 audio_info_1_reg = 0;
492
493 /* CA(channel_allocation) */
494 audio_info_1_reg |= channel_allocation & 0xff;
495
496 /* Program the Level shifter */
497 /* LSV(level_shift) */
498 audio_info_1_reg |= (level_shift << 11) & 0x00007800;
499
500 /* Program the Down-mix Inhibit Flag */
501 /* DM_INH(down_mix) */
502 audio_info_1_reg |= (down_mix << 15) & 0x00008000;
503
504 writel(audio_info_1_reg, HDMI_AUDIO_INFO1);
505
506 check_sum = 0;
507 /* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_TYPE[0x84] */
508 check_sum += 0x84;
509 /* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_VERSION[0x01] */
510 check_sum += 1;
511 /* HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH[0x0A] */
512 check_sum += 0x0A;
513 check_sum += channel_count;
514 check_sum += channel_allocation;
515 /* See Table 8.5 in HDMI spec */
516 check_sum += (level_shift & 0xF) << 3 | (down_mix & 0x1) << 7;
517 check_sum &= 0xFF;
518 check_sum = (256 - check_sum);
519
520 audio_info_0_reg = 0;
521 /* CHECKSUM(check_sum) */
522 audio_info_0_reg |= check_sum & 0xff;
523 /* CC(channel_count) */
524 audio_info_0_reg |= (channel_count << 8) & 0x00000700;
525
526 writel(audio_info_0_reg, HDMI_AUDIO_INFO0);
527
528 /* Set these flags */
529 /* AUDIO_INFO_UPDATE | AUDIO_INFO_SOURCE | AUDIO_INFO_CONT
530 | AUDIO_INFO_SEND */
531 audio_info_ctrl_reg |= 0xF0;
532
533 /* HDMI_INFOFRAME_CTRL0[0x002C] */
534 writel(audio_info_ctrl_reg, HDMI_INFOFRAME_CTRL0);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700535}
536
Casey Piper97d25272015-03-17 15:10:34 -0700537static uint8_t* hdmi_edid_find_block(uint32_t start_offset,
538 uint8_t type, uint8_t *len)
539{
540 /* the start of data block collection, start of Video Data Block */
541 uint8_t *in_buf = mdss_hdmi_edid_buf;
542 uint32_t offset = start_offset;
543 uint32_t end_dbc_offset = in_buf[2];
544
545 *len = 0;
546
547 /*
548 * edid buffer 1, byte 2 being 4 means no non-DTD/Data block collection
549 * present.
550 * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block collection
551 * present and no DTD data present.
552 */
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800553 if ((end_dbc_offset == 0) || (end_dbc_offset == 4) ||
554 (end_dbc_offset >= MAX_EDID_BLOCK_SIZE))
Casey Piper97d25272015-03-17 15:10:34 -0700555 return NULL;
556
557 while (offset < end_dbc_offset) {
558 uint8_t block_len = in_buf[offset] & 0x1F;
559 if ((in_buf[offset] >> 5) == type) {
560 *len = block_len;
561 dprintf(SPEW,
562 "EDID: block=%d found @ %d with length=%d\n",
563 type, offset, block_len);
564 return in_buf + offset;
565 }
566 offset += 1 + block_len;
567 }
568
569 return NULL;
570}
571
Casey Piper1d3611d2015-03-17 15:45:44 -0700572static bool mdss_hdmi_is_audio_freq_supported(uint32_t freq)
573{
574 uint8_t *in_buf = mdss_hdmi_edid_buf;
575 const uint8_t *adb = NULL;
576 uint32_t adb_size = 0;
577 uint8_t len = 0, count = 0;
578 uint32_t next_offset = DBC_START_OFFSET;
579 uint8_t audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE];
580
581 do {
582 adb = hdmi_edid_find_block(next_offset,
583 AUDIO_DATA_BLOCK, &len);
584
585 if ((adb_size + len) > MAX_AUDIO_DATA_BLOCK_SIZE) {
586 dprintf(INFO, "%s: invalid adb length\n", __func__);
587 break;
588 }
589
590 if (!adb)
591 break;
592
593 memcpy((audio_data_block + adb_size), adb + 1, len);
594 next_offset = (adb - in_buf) + 1 + len;
595
596 adb_size += len;
597
598 } while (adb);
599
600 count = adb_size/3;
601 adb = audio_data_block;
602
603 while (count--) {
604 uint8_t freq_lst = *(adb + 1) & 0xFF;
605
606 if (freq_lst & BIT(freq))
607 return true;
608
609 adb += 3;
610 }
611
612 return false;
613}
614
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700615static void mdss_hdmi_audio_playback(void)
616{
Casey Piper77f69c52015-03-20 15:55:12 -0700617 char *base_addr;
Casey Piper1d3611d2015-03-17 15:45:44 -0700618 uint32_t sample_rate;
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700619
Casey Piper77f69c52015-03-20 15:55:12 -0700620 base_addr = (char *) memalign(4096, 0x1000);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700621 if (base_addr == NULL) {
622 dprintf(CRITICAL, "%s: Error audio buffer alloc\n", __func__);
623 return;
624 }
625
626 memset(base_addr, 0, 0x1000);
627
628 writel(0x00000010, HDMI_AUDIO_PKT_CTRL);
629 writel(0x00000080, HDMI_AUDIO_CFG);
630
631 writel(0x0000096E, LPASS_LPAIF_RDDMA_CTL0);
632 writel(0x00000A6E, LPASS_LPAIF_RDDMA_CTL0);
633 writel(0x00002000, HDMI_VBI_PKT_CTRL);
634 writel(0x00000000, HDMI_GEN_PKT_CTRL);
635 writel(0x0000096E, LPASS_LPAIF_RDDMA_CTL0);
Casey Piper77f69c52015-03-20 15:55:12 -0700636 writel((uint32_t) base_addr, LPASS_LPAIF_RDDMA_BASE0);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700637 writel(0x000005FF, LPASS_LPAIF_RDDMA_BUFF_LEN0);
638 writel(0x000005FF, LPASS_LPAIF_RDDMA_PER_LEN0);
639 writel(0x0000096F, LPASS_LPAIF_RDDMA_CTL0);
640 writel(0x00000010, LPASS_LPAIF_DEBUG_CTL);
641 writel(0x00000000, HDMI_GC);
642 writel(0x00002030, HDMI_VBI_PKT_CTRL);
643 writel(0x00002030, HDMI_VBI_PKT_CTRL);
644 writel(0x00002030, HDMI_VBI_PKT_CTRL);
645
Casey Piper1d3611d2015-03-17 15:45:44 -0700646 if (mdss_hdmi_is_audio_freq_supported(AUDIO_SAMPLE_RATE_48KHZ))
647 sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
648 else
649 sample_rate = AUDIO_SAMPLE_RATE_32KHZ;
650
651 mdss_hdmi_audio_acr_setup(sample_rate);
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700652 mdss_hdmi_audio_info_setup();
653
654 writel(0x00000010, HDMI_AUDIO_PKT_CTRL);
655 writel(0x00000080, HDMI_AUDIO_CFG);
656 writel(0x00000011, HDMI_AUDIO_PKT_CTRL);
657 writel(0x00000081, HDMI_AUDIO_CFG);
Casey Piper1d3611d2015-03-17 15:45:44 -0700658
659 dprintf(SPEW, "audio sample rate %s\n",
660 sample_rate == AUDIO_SAMPLE_RATE_48KHZ ? "48KHz" : "32KHz");
Ajay Singh Parmara1771a12014-08-13 15:56:11 -0700661}
662
Casey Piper77f69c52015-03-20 15:55:12 -0700663static uint32_t mdss_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700664{
Casey Piper7ab92992015-03-18 14:19:23 -0700665 int ret = NO_ERROR;
666 if (hdmi_panel_clock_enabled)
667 return ret;
668
669 ret = target_hdmi_panel_clock(enable, pinfo);
670
671 hdmi_panel_clock_enabled = enable;
672
673 return ret;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700674}
675
Casey Piper6c2f1132015-03-24 11:37:19 -0700676static uint32_t mdss_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
677{
Casey Piper7ab92992015-03-18 14:19:23 -0700678 int ret = NO_ERROR;
679
680 if (hdmi_pll_clock_enabled)
681 return ret;
682
683 ret = target_hdmi_pll_clock(enable, pinfo);
684
685 hdmi_pll_clock_enabled = enable;
686
687 return ret;
Casey Piper6c2f1132015-03-24 11:37:19 -0700688}
689
Ajay Singh Parmar9d2ba152014-08-14 00:42:24 -0700690static int mdss_hdmi_enable_power(uint8_t enable, struct msm_panel_info *pinfo)
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700691{
Casey Piper7ab92992015-03-18 14:19:23 -0700692 int ret = NO_ERROR;
693
694 if (hdmi_power_enabled)
695 return ret;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700696
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700697 ret = target_hdmi_regulator_ctrl(enable);
698 if (ret) {
Ajay Singh Parmar9d2ba152014-08-14 00:42:24 -0700699 dprintf(CRITICAL, "hdmi regulator control enable failed\n");
700 goto bail_regulator_fail;
Casey Piper7ab92992015-03-18 14:19:23 -0700701 }
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700702
Ajay Singh Parmar9d2ba152014-08-14 00:42:24 -0700703 ret = target_hdmi_gpio_ctrl(enable);
704 if (ret) {
705 dprintf(CRITICAL, "hdmi gpio control enable failed\n");
706 goto bail_gpio_fail;
Casey Piper7ab92992015-03-18 14:19:23 -0700707 }
708
709 hdmi_power_enabled = enable;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700710
Ajay Singh Parmar9d2ba152014-08-14 00:42:24 -0700711 dprintf(SPEW, "HDMI Panel power %s done\n", enable ? "on" : "off");
712
713 return ret;
714
715bail_gpio_fail:
716 target_hdmi_regulator_ctrl(0);
717
718bail_regulator_fail:
Ajay Singh Parmar9d2ba152014-08-14 00:42:24 -0700719 return ret;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700720}
721
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -0800722static bool mdss_hdmi_is_dvi_mode(void)
723{
724 uint8_t len;
725 uint32_t ieee_tag;
726 const uint8_t *vsd = NULL;
727
728 vsd = hdmi_edid_find_block(DBC_START_OFFSET,
729 VENDOR_SPECIFIC_DATA_BLOCK, &len);
730
731 if (vsd == NULL || len == 0) {
732 dprintf(SPEW, "%s: Invalid VSDB\n", __func__);
733 return false;
734 }
735
736 ieee_tag = ((uint32_t) vsd[3] << 16) + ((uint32_t) vsd[2] << 8) +
737 (uint32_t) vsd[1];
738
739 if (ieee_tag == 0x0c03)
740 return false;
741 else
742 return true;
743}
744
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700745static void mdss_hdmi_set_mode(bool on)
746{
747 uint32_t val = 0;
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -0800748 if (on) {
749 /* tx on */
Tatenda Chipeperekwab12d7db2015-12-04 15:39:10 -0800750 val |= BIT(0);
751 /* hdcp legacy mode*/
752 val |= BIT(31);
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -0800753
754 if (!mdss_hdmi_is_dvi_mode())
Tatenda Chipeperekwab12d7db2015-12-04 15:39:10 -0800755 val |= BIT(1);
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -0800756 }
Casey Piper6c2f1132015-03-24 11:37:19 -0700757
758 writel(val, HDMI_CTRL);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700759}
760
Casey Piper97d25272015-03-17 15:10:34 -0700761
762static int mdss_hdmi_read_edid(void)
763{
764 uint8_t ndx;
765 uint32_t reg_val;
766 uint32_t dev_addr = 0xA0;
767 uint32_t len = 0x80;
768 uint32_t offset = 0x80;
769 uint32_t time_out;
770 uint32_t retry = 5;
771
772 dev_addr &= 0xFE;
773
774again:
775 time_out = 10;
776 writel(readl(HDMI_DDC_ARBITRATION) & ~BIT(4), HDMI_DDC_ARBITRATION);
777
778 /* Enable DDC Interrupts */
779 writel(BIT(1) | BIT(2), HDMI_DDC_INT_CTRL);
780
781 /* config DDC to read CEA block */
782 writel((10 << 16) | (2 << 0), HDMI_DDC_SPEED);
783 writel(0xFF000000, HDMI_DDC_SETUP);
784 writel((1 << 16) | (19 << 0), HDMI_DDC_REF);
785 writel(BIT(31) | (dev_addr << 8), HDMI_DDC_DATA);
786 writel(offset << 8, HDMI_DDC_DATA);
787 writel((dev_addr | BIT(0)) << 8, HDMI_DDC_DATA);
788 writel(BIT(12) | BIT(16), HDMI_DDC_TRANS0);
789 writel(BIT(0) | BIT(12) | BIT(13) | (len << 16), HDMI_DDC_TRANS1);
790 writel(BIT(0) | BIT(20), HDMI_DDC_CTRL);
791
792 /* poll for 100ms for read to complete */
793 reg_val = readl(HDMI_DDC_INT_CTRL);
794 while (!(reg_val & BIT(0)) && time_out) {
795 reg_val = readl(HDMI_DDC_INT_CTRL);
796 time_out--;
797 mdelay(10);
798 }
799
800 if (!time_out) {
801 dprintf(CRITICAL, "%s: Timeout reading EDID\n", __func__);
802 if (retry--)
803 goto again;
804 else
805 return ERROR;
806 }
807
808 /* clear interrupts */
809 writel(BIT(1), HDMI_DDC_INT_CTRL);
810
811 reg_val = readl(HDMI_DDC_SW_STATUS);
812 reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
813
814 /* Check if any NACK occurred */
815 if (reg_val) {
816 /* SW_STATUS_RESET */
817 writel(BIT(3), HDMI_DDC_CTRL);
818
819 /* SOFT_RESET */
820 writel(BIT(1), HDMI_DDC_CTRL);
821
822 dprintf(CRITICAL, "%s: NACK reading EDID\n", __func__);
823
824 if (retry--)
825 goto again;
826 else
827 return ERROR;
828 }
829
830 /* Write this data to DDC buffer */
831 writel(BIT(0) | (3 << 16) | BIT(31), HDMI_DDC_DATA);
832
833 /* Discard first byte */
834 readl(HDMI_DDC_DATA);
835
836 for (ndx = 0; ndx < 0x80; ndx++) {
837 reg_val = readl(HDMI_DDC_DATA);
838 mdss_hdmi_edid_buf[ndx] = (uint8_t)((reg_val & 0x0000FF00) >> 8);
839 }
840
841 dprintf(INFO, "%s: EDID read successful\n", __func__);
842
843 return NO_ERROR;
844}
845
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800846static void mdss_hdmi_add_video_format(uint32_t video_format)
847{
848 if (mdss_hdmi_mode_count >= HDMI_VFRMT_COUNT) {
849 dprintf(SPEW, "%s: unsupported format (%d)", __func__,
850 video_format);
851 return;
852 }
853
854 dprintf(SPEW, "%s: vic=%d\n", __func__, video_format);
855 mdss_hdmi_video_formats[mdss_hdmi_mode_count] = video_format;
856 mdss_hdmi_mode_count++;
857}
858
859static void mdss_hdmi_get_extended_video_formats()
860{
861 uint8_t db_len, offset, i;
862 uint8_t hdmi_vic_len;
863 uint32_t video_format;
864 const uint8_t *vsd = NULL;
865
866 vsd = hdmi_edid_find_block(DBC_START_OFFSET,
867 VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
868
869 if (!vsd || db_len == 0) {
870 dprintf(SPEW, "%s: No/Invalid Vendor Specific Data Block\n",
871 __func__);
872 return;
873 }
874
875 /* check if HDMI_Video_present flag is set or not */
876 if (!(vsd[8] & BIT(5))) {
877 dprintf(SPEW, "%s: extended vfmts not supported by the sink.\n",
878 __func__);
879 return;
880 }
881
882 offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
883
884 hdmi_vic_len = vsd[offset + 1] >> 5;
885 if (hdmi_vic_len) {
886 for (i = 0; i < hdmi_vic_len; i++) {
887 struct mdss_hdmi_timing_info tinfo = {0};
888 uint32_t ret = 0;
889
890 video_format = HDMI_VFRMT_END + vsd[offset + 2 + i];
891 ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
892
893 if (ret || !tinfo.supported)
894 continue;
895
896 mdss_hdmi_add_video_format(video_format);
897 }
898 }
899}
900
901static void mdss_hdmi_get_cea_video_formats()
Casey Piper97d25272015-03-17 15:10:34 -0700902{
903 uint8_t len, i;
904 uint32_t video_format;
Casey Piper97d25272015-03-17 15:10:34 -0700905
906 uint8_t *svd = hdmi_edid_find_block(DBC_START_OFFSET,
907 VIDEO_DATA_BLOCK, &len);
908
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800909 if (!svd || len == 0) {
910 dprintf(SPEW, "%s: No/Invalid Video Data Block\n",
911 __func__);
Ajay Singh Parmar392f07a2014-11-19 15:06:19 -0800912 return;
Casey Piper97d25272015-03-17 15:10:34 -0700913 }
Ajay Singh Parmar392f07a2014-11-19 15:06:19 -0800914
Casey Piper97d25272015-03-17 15:10:34 -0700915 ++svd;
916
917 for (i = 0; i < len; ++i, ++svd) {
918 struct mdss_hdmi_timing_info tinfo = {0};
919 uint32_t ret = 0;
920
921 video_format = (*svd & 0x7F);
922
923 if (i == 0)
924 mdss_hdmi_pref_fmt = video_format;
925
926 ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
927
928 if (ret || !tinfo.supported)
929 continue;
930
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800931 mdss_hdmi_add_video_format(video_format);
932 }
933}
Casey Piper97d25272015-03-17 15:10:34 -0700934
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800935static void mdss_hdmi_parse_res(void)
936{
937 int index, ret;
938 uint8_t current_video_format;
939 struct mdss_hdmi_timing_info current_timing_info = {0};
940
941 mdss_hdmi_mode_count = 0;
942 mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
943 current_video_format = mdss_hdmi_video_fmt;
944 mdss_hdmi_get_timing_info(&current_timing_info, mdss_hdmi_video_fmt);
945
946 mdss_hdmi_get_extended_video_formats();
947 mdss_hdmi_get_cea_video_formats();
948
949 for (index = 0; index < mdss_hdmi_mode_count; index++) {
950 struct mdss_hdmi_timing_info new_timing_info = {0};
951
952 if (!mdss_hdmi_video_formats[index])
953 break;
954
955 ret = mdss_hdmi_get_timing_info(&new_timing_info, mdss_hdmi_video_formats[index]);
956 if (ret || !new_timing_info.supported)
957 continue;
958
959 if (new_timing_info.active_h > current_timing_info.active_h) {
960 current_video_format = mdss_hdmi_video_formats[index];
961 } else if (new_timing_info.active_h ==
962 current_timing_info.active_h) {
963 if (new_timing_info.active_v >
964 current_timing_info.active_v) {
965 current_video_format = mdss_hdmi_video_formats[index];
966 } else if (new_timing_info.active_v ==
967 current_timing_info.active_v) {
Tatenda Chipeperekwad83a3002016-03-15 10:37:06 -0700968 if (new_timing_info.refresh_rate >
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800969 current_timing_info.refresh_rate) {
970 current_video_format = mdss_hdmi_video_formats[index];
971 }
972 }
Casey Piper97d25272015-03-17 15:10:34 -0700973 }
Tatenda Chipeperekwad83a3002016-03-15 10:37:06 -0700974
975 mdss_hdmi_get_timing_info(&current_timing_info, current_video_format);
Casey Piper97d25272015-03-17 15:10:34 -0700976 }
977
Tatenda Chipeperekwa3fe8bd82016-02-23 18:49:10 -0800978 if (mdss_hdmi_video_fmt != current_video_format)
979 mdss_hdmi_video_fmt = current_video_format;
Ajay Singh Parmar392f07a2014-11-19 15:06:19 -0800980}
981
Casey Piper6c2f1132015-03-24 11:37:19 -0700982void mdss_hdmi_get_vic(char *buf)
983{
984 struct mdss_hdmi_timing_info tinfo = {0};
985 uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
986
987 if (ret)
988 snprintf(buf, HDMI_VIC_STR_MAX, "%d", HDMI_VFRMT_UNKNOWN);
989 else
990 snprintf(buf, HDMI_VIC_STR_MAX, "%d", tinfo.video_format);
991
992}
993
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700994static void mdss_hdmi_panel_init(struct msm_panel_info *pinfo)
995{
Casey Piper97d25272015-03-17 15:10:34 -0700996 struct mdss_hdmi_timing_info tinfo = {0};
997 uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -0700998
Casey Piper97d25272015-03-17 15:10:34 -0700999 if (!pinfo || ret)
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001000 return;
1001
1002 pinfo->xres = tinfo.active_h;
1003 pinfo->yres = tinfo.active_v;
1004 pinfo->bpp = 24;
1005 pinfo->type = HDMI_PANEL;
Casey Piper97d25272015-03-17 15:10:34 -07001006 pinfo->clk_rate = tinfo.pixel_freq * 1000;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001007
Casey Piper97d25272015-03-17 15:10:34 -07001008 pinfo->lcdc.h_back_porch = tinfo.back_porch_h;
1009 pinfo->lcdc.h_front_porch = tinfo.front_porch_h;
1010 pinfo->lcdc.h_pulse_width = tinfo.pulse_width_h;
1011 pinfo->lcdc.v_back_porch = tinfo.back_porch_v;
1012 pinfo->lcdc.v_front_porch = tinfo.front_porch_v;
1013 pinfo->lcdc.v_pulse_width = tinfo.pulse_width_v;
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001014
Casey Piper97d25272015-03-17 15:10:34 -07001015 pinfo->lcdc.hsync_skew = 0;
1016 pinfo->lcdc.xres_pad = 0;
1017 pinfo->lcdc.yres_pad = 0;
Tatenda Chipeperekwaf4917642016-03-23 11:34:48 -07001018
1019 /* Add dual pipe configuration for resultions greater than
1020 * MSM_MDP_MAX_PIPE_WIDTH.
1021 */
1022 if (pinfo->xres > MSM_MDP_MAX_PIPE_WIDTH) {
1023 pinfo->lcdc.dual_pipe = 1;
1024 pinfo->lm_split[0] = pinfo->xres / 2;
1025 pinfo->lm_split[1] = pinfo->xres - pinfo->lm_split[0];
1026 }
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001027}
1028
Casey Piper7ab92992015-03-18 14:19:23 -07001029static uint8_t mdss_hdmi_cable_status(void)
1030{
1031 uint32_t reg_val;
1032 uint8_t cable_status;
1033
1034 mdss_hdmi_set_mode(true);
1035
1036 /* Enable USEC REF timer */
1037 writel(0x0001001B, HDMI_USEC_REFTIMER);
1038
1039 /* set timeout to 4.1ms (max) for hardware debounce */
1040 reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
1041
1042 /* enable HPD circuit */
1043 writel(reg_val | BIT(28), HDMI_HPD_CTRL);
1044
1045 writel(BIT(2) | BIT(1), HDMI_HPD_INT_CTRL);
1046
1047 /* Toggle HPD circuit to trigger HPD sense */
1048 reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
1049 writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
1050 writel(reg_val & BIT(28), HDMI_HPD_CTRL);
1051
1052 mdelay(20);
1053
1054 cable_status = (readl(HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
1055
1056 dprintf(INFO, "hdmi cable %s\n",
1057 cable_status ? "connected" : "not connected");
1058
1059 writel(BIT(0), HDMI_HPD_INT_CTRL);
1060 writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
1061
1062 mdss_hdmi_set_mode(false);
1063
1064 return cable_status;
1065}
1066
Casey Piper6c2f1132015-03-24 11:37:19 -07001067static int mdss_hdmi_update_panel_info(void)
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001068{
Casey Piper6c2f1132015-03-24 11:37:19 -07001069 mdss_hdmi_set_mode(true);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001070
Casey Piper6c2f1132015-03-24 11:37:19 -07001071 if (!mdss_hdmi_read_edid())
1072 mdss_hdmi_parse_res();
1073 else
1074 mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
1075
1076 mdss_hdmi_set_mode(false);
1077
1078 mdss_hdmi_panel_init(&(panel.panel_info));
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001079
1080 panel.fb.width = panel.panel_info.xres;
1081 panel.fb.height = panel.panel_info.yres;
1082 panel.fb.stride = panel.panel_info.xres;
1083 panel.fb.bpp = panel.panel_info.bpp;
1084 panel.fb.format = FB_FORMAT_RGB888;
1085
Casey Piper6c2f1132015-03-24 11:37:19 -07001086 return NO_ERROR;
1087}
1088
1089void mdss_hdmi_display_init(uint32_t rev, void *base)
1090{
1091 panel.power_func = mdss_hdmi_enable_power;
1092 panel.clk_func = mdss_hdmi_panel_clock;
1093 panel.update_panel_info = mdss_hdmi_update_panel_info;
1094 panel.pll_clk_func = mdss_hdmi_pll_clock;
1095
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001096 panel.fb.base = base;
1097 panel.mdp_rev = rev;
1098
1099 msm_display_init(&panel);
1100}
1101
1102static int mdss_hdmi_video_setup(void)
1103{
1104 uint32_t total_v = 0;
1105 uint32_t total_h = 0;
1106 uint32_t start_h = 0;
1107 uint32_t end_h = 0;
1108 uint32_t start_v = 0;
1109 uint32_t end_v = 0;
1110
Casey Piper97d25272015-03-17 15:10:34 -07001111 struct mdss_hdmi_timing_info tinfo = {0};
1112 uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
1113
1114 if (ret)
1115 return ERROR;
1116
1117 dprintf(INFO, "hdmi resolution %dx%d@p%dHz (%d)\n",
1118 tinfo.active_h, tinfo.active_v, tinfo.refresh_rate/1000,
1119 mdss_hdmi_video_fmt);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001120
1121 total_h = tinfo.active_h + tinfo.front_porch_h +
1122 tinfo.back_porch_h + tinfo.pulse_width_h - 1;
1123 total_v = tinfo.active_v + tinfo.front_porch_v +
1124 tinfo.back_porch_v + tinfo.pulse_width_v - 1;
1125 if (((total_v << 16) & 0xE0000000) || (total_h & 0xFFFFE000)) {
1126 dprintf(CRITICAL,
1127 "%s: total v=%d or h=%d is larger than supported\n",
1128 __func__, total_v, total_h);
1129 return ERROR;
1130 }
1131 writel((total_v << 16) | (total_h << 0), HDMI_TOTAL);
1132
1133 start_h = tinfo.back_porch_h + tinfo.pulse_width_h;
1134 end_h = (total_h + 1) - tinfo.front_porch_h;
1135 if (((end_h << 16) & 0xE0000000) || (start_h & 0xFFFFE000)) {
1136 dprintf(CRITICAL,
1137 "%s: end_h=%d or start_h=%d is larger than supported\n",
1138 __func__, end_h, start_h);
1139 return ERROR;
1140 }
1141 writel((end_h << 16) | (start_h << 0), HDMI_ACTIVE_H);
1142
1143 start_v = tinfo.back_porch_v + tinfo.pulse_width_v - 1;
1144 end_v = total_v - tinfo.front_porch_v;
1145 if (((end_v << 16) & 0xE0000000) || (start_v & 0xFFFFE000)) {
1146 dprintf(CRITICAL,
1147 "%s: end_v=%d or start_v=%d is larger than supported\n",
1148 __func__, end_v, start_v);
1149 return ERROR;
1150 }
1151 writel((end_v << 16) | (start_v << 0), HDMI_ACTIVE_V);
1152
1153 if (tinfo.interlaced) {
1154 writel((total_v + 1) << 0, HDMI_V_TOTAL_F2);
1155 writel(((end_v + 1) << 16) | ((start_v + 1) << 0),
1156 HDMI_ACTIVE_V_F2);
1157 } else {
1158 writel(0, HDMI_V_TOTAL_F2);
1159 writel(0, HDMI_ACTIVE_V_F2);
1160 }
1161
1162 writel(((tinfo.interlaced << 31) & 0x80000000) |
1163 ((tinfo.active_low_h << 29) & 0x20000000) |
1164 ((tinfo.active_low_v << 28) & 0x10000000), HDMI_FRAME_CTRL);
1165
1166 return 0;
1167}
1168
Casey Piper97d25272015-03-17 15:10:34 -07001169static void mdss_hdmi_extract_extended_data_blocks(void)
1170{
1171 uint8_t len = 0;
1172 uint32_t start_offset = DBC_START_OFFSET;
1173 uint8_t const *etag = NULL;
1174 uint8_t *in_buf = mdss_hdmi_edid_buf;
1175
1176 do {
1177 /* A Tage code of 7 identifies extended data blocks */
1178 etag = hdmi_edid_find_block(start_offset,
1179 USE_EXTENDED_TAG, &len);
1180
1181 start_offset = etag - in_buf + len + 1;
1182
1183 /* The extended data block should at least be 2 bytes long */
1184 if (len < 2) {
1185 dprintf(SPEW, "%s: data block of len < 2 bytes\n",
1186 __func__);
1187 continue;
1188 }
1189
1190 /*
1191 * The second byte of the extended data block has the
1192 * extended tag code
1193 */
1194 switch (etag[1]) {
1195 case 0:
1196 /*
1197 * Check if the sink specifies underscan
1198 * support for:
1199 * BIT 5: preferred video format
1200 * BIT 3: IT video format
1201 * BIT 1: CE video format
1202 */
1203 pt_scan_info = (etag[2] & (BIT(4) | BIT(5))) >> 4;
1204 it_scan_info = (etag[2] & (BIT(3) | BIT(2))) >> 2;
1205 ce_scan_info = etag[2] & (BIT(1) | BIT(0));
1206
1207 dprintf(INFO, "scan Info (pt|it|ce): (%d|%d|%d)\n",
1208 pt_scan_info, it_scan_info, ce_scan_info);
1209 break;
1210 default:
1211 dprintf(SPEW, "%s: Tag Code %d not supported\n",
1212 __func__, etag[1]);
1213 break;
1214 }
1215 } while (etag != NULL);
1216}
1217
1218/*
1219 * If the sink specified support for both underscan/overscan then, by default,
1220 * set the underscan bit. Only checking underscan support for preferred
1221 * format and cea formats.
1222 */
1223uint8_t mdss_hdmi_get_scan_info(void)
1224{
1225 uint8_t scaninfo = 0;
1226 bool use_ce_scan_info = true;
1227
1228 mdss_hdmi_extract_extended_data_blocks();
1229
1230 if (mdss_hdmi_video_fmt == mdss_hdmi_pref_fmt) {
1231 use_ce_scan_info = false;
1232
1233 switch (pt_scan_info) {
1234 case 0:
1235 use_ce_scan_info = true;
1236 break;
1237 case 3:
1238 scaninfo = BIT(1);
1239 break;
1240 default:
1241 break;
1242 }
1243 }
1244
1245 if (use_ce_scan_info) {
1246 if (3 == ce_scan_info)
1247 scaninfo |= BIT(1);
1248 }
1249
1250 return scaninfo;
1251}
1252
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001253void mdss_hdmi_avi_info_frame(void)
1254{
1255 uint32_t sum;
1256 uint32_t reg_val;
1257 uint8_t checksum;
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001258 uint32_t i;
1259 struct hdmi_avi_infoframe_config avi_info = {0};
1260 struct mdss_hdmi_timing_info tinfo = {0};
1261 uint8_t avi_iframe[AVI_MAX_DATA_BYTES] = {0};
Casey Piper97d25272015-03-17 15:10:34 -07001262
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001263 mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
1264
1265 /* Setup AVI Infoframe content */
1266 avi_info.scan_info = mdss_hdmi_get_scan_info();
1267 avi_info.bar_info.end_of_top_bar = 0x0;
1268 avi_info.bar_info.start_of_bottom_bar = tinfo.active_v + 1;
1269 avi_info.bar_info.end_of_left_bar = 0;
1270 avi_info.bar_info.start_of_right_bar = tinfo.active_h + 1;
1271 avi_info.act_fmt_info_present = true;
1272 avi_info.rgb_quantization_range = HDMI_QUANTIZATION_DEFAULT;
1273 avi_info.yuv_quantization_range = HDMI_QUANTIZATION_DEFAULT;
1274 avi_info.scaling_info = HDMI_SCALING_NONE;
1275 avi_info.colorimetry_info = 0;
1276 avi_info.ext_colorimetry_info = 0;
1277 avi_info.pixel_rpt_factor = 0;
1278
1279 /*
1280 * BYTE - 1:
1281 * 0:1 - Scan Information
1282 * 2:3 - Bar Info
1283 * 4 - Active Format Info present
1284 * 5:6 - Pixel format type;
1285 * 7 - Reserved;
1286 */
1287 avi_iframe[0] = (avi_info.scan_info & 0x3) |
1288 (avi_info.bar_info.vert_binfo_present ? BIT(2) : 0) |
1289 (avi_info.bar_info.horz_binfo_present ? BIT(3) : 0) |
1290 (avi_info.act_fmt_info_present ? BIT(4) : 0);
1291
1292 /*
1293 * BYTE - 2:
1294 * 0:3 - Active format info
1295 * 4:5 - Picture aspect ratio
1296 * 6:7 - Colorimetry info
1297 */
1298 avi_iframe[1] |= 0x08;
1299 if (tinfo.ar == HDMI_RES_AR_4_3)
1300 avi_iframe[1] |= (0x1 << 4);
1301 else if (tinfo.ar == HDMI_RES_AR_16_9)
1302 avi_iframe[1] |= (0x2 << 4);
1303
1304 avi_iframe[1] |= (avi_info.colorimetry_info & 0x3) << 6;
1305
1306 /*
1307 * BYTE - 3:
1308 * 0:1 - Scaling info
1309 * 2:3 - Quantization range
1310 * 4:6 - Extended Colorimetry
1311 * 7 - IT content
1312 */
1313 avi_iframe[2] |= (avi_info.scaling_info & 0x3) |
1314 ((avi_info.rgb_quantization_range & 0x3) << 2) |
1315 ((avi_info.ext_colorimetry_info & 0x7) << 4) |
1316 ((avi_info.is_it_content ? 0x1 : 0x0) << 7);
1317 /*
1318 * BYTE - 4:
1319 * 0:7 - VIC
1320 */
1321 if (tinfo.video_format < HDMI_VFRMT_END)
1322 avi_iframe[3] = tinfo.video_format;
1323
1324 /*
1325 * BYTE - 5:
1326 * 0:3 - Pixel Repeat factor
1327 * 4:5 - Content type
1328 * 6:7 - YCC Quantization range
1329 */
1330 avi_iframe[4] = (avi_info.pixel_rpt_factor & 0xF) |
1331 ((avi_info.content_type & 0x3) << 4) |
1332 ((avi_info.yuv_quantization_range & 0x3) << 6);
1333
1334 /* BYTE - 6,7: End of top bar */
1335 avi_iframe[5] = avi_info.bar_info.end_of_top_bar & 0xFF;
1336 avi_iframe[6] = ((avi_info.bar_info.end_of_top_bar & 0xFF00) >> 8);
1337
1338 /* BYTE - 8,9: Start of bottom bar */
1339 avi_iframe[7] = avi_info.bar_info.start_of_bottom_bar & 0xFF;
1340 avi_iframe[8] = ((avi_info.bar_info.start_of_bottom_bar & 0xFF00) >> 8);
1341
1342 /* BYTE - 10,11: Endof of left bar */
1343 avi_iframe[9] = avi_info.bar_info.end_of_left_bar & 0xFF;
1344 avi_iframe[10] = ((avi_info.bar_info.end_of_left_bar & 0xFF00) >> 8);
1345
1346 /* BYTE - 12,13: Start of right bar */
1347 avi_iframe[11] = avi_info.bar_info.start_of_right_bar & 0xFF;
1348 avi_iframe[12] = ((avi_info.bar_info.start_of_right_bar & 0xFF00) >> 8);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001349
1350 sum = IFRAME_PACKET_OFFSET + AVI_IFRAME_TYPE +
1351 AVI_IFRAME_VERSION + AVI_MAX_DATA_BYTES;
1352
1353 for (i = 0; i < AVI_MAX_DATA_BYTES; i++)
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001354 sum += avi_iframe[i];
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001355 sum &= 0xFF;
1356 sum = 256 - sum;
1357 checksum = (uint8_t) sum;
1358
1359 reg_val = checksum |
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001360 LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_1]) |
1361 LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_2]) |
1362 LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_3]);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001363 writel(reg_val, HDMI_AVI_INFO0);
1364
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001365 reg_val = avi_iframe[DATA_BYTE_4] |
1366 LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_5]) |
1367 LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_6]) |
1368 LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_7]);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001369 writel(reg_val, HDMI_AVI_INFO1);
1370
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001371 reg_val = avi_iframe[DATA_BYTE_8] |
1372 LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_9]) |
1373 LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_10]) |
1374 LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_11]);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001375 writel(reg_val, HDMI_AVI_INFO2);
1376
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001377 reg_val = avi_iframe[DATA_BYTE_12] |
1378 LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_13]) |
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001379 LEFT_SHIFT_24BITS(AVI_IFRAME_VERSION);
1380 writel(reg_val, HDMI_AVI_INFO3);
1381
1382 /* AVI InfFrame enable (every frame) */
1383 writel(readl(HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0),
Tatenda Chipeperekwac50c8dd2016-02-23 18:59:08 -08001384 HDMI_INFOFRAME_CTRL0);
1385
1386 reg_val = readl(HDMI_INFOFRAME_CTRL1);
1387 reg_val &= ~0x3F;
1388 reg_val |= AVI_IFRAME_LINE_NUMBER;
1389 writel(reg_val, HDMI_INFOFRAME_CTRL1);
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001390}
1391
1392int mdss_hdmi_init(void)
1393{
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -08001394 bool is_dvi_mode = mdss_hdmi_is_dvi_mode();
1395
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001396 mdss_hdmi_set_mode(false);
1397
Ajay Singh Parmara1771a12014-08-13 15:56:11 -07001398 /* Audio settings */
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -08001399 if (!is_dvi_mode)
1400 mdss_hdmi_audio_playback();
Ajay Singh Parmara1771a12014-08-13 15:56:11 -07001401
1402 /* Video settings */
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001403 mdss_hdmi_video_setup();
1404
Ajay Singh Parmara1771a12014-08-13 15:56:11 -07001405 /* AVI info settings */
Ajay Singh Parmar9ddfa572015-02-17 12:49:53 -08001406 if (!is_dvi_mode)
1407 mdss_hdmi_avi_info_frame();
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001408
Ajay Singh Parmara1771a12014-08-13 15:56:11 -07001409 /* Enable HDMI */
Ajay Singh Parmar243d82b2014-07-23 23:01:44 -07001410 mdss_hdmi_set_mode(true);
1411
1412 return 0;
1413}