• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
3  * Author: zhengwanyu <zhengwanyu@allwinnertech.com>
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 #include "sunxi_hdmi14.h"
16 static struct drv_model_info *hdmi_drv;
17 static struct sunxi_hdmi *hwhdmi;
18 
19 #define HDMI_PIN_STATE_ACTIVE "active"
20 #define HDMI_PIN_STATE_SLEEP "sleep"
21 
22 struct disp_video_timings hdmi_video_timing[] = {
23 	{
24 			.vic = HDMI1440_480I,
25 			.tv_mode = DISP_TV_MOD_480I,
26 			.pixel_clk = 13500000,
27 			.pixel_repeat = 1,
28 			.x_res = 720,
29 			.y_res = 480,
30 			.hor_total_time = 858,
31 			.hor_back_porch = 57,
32 			.hor_front_porch = 19,
33 			.hor_sync_time = 62,
34 			.ver_total_time = 525,
35 			.ver_back_porch = 15,
36 			.ver_front_porch = 4,
37 			.ver_sync_time = 3,
38 			.hor_sync_polarity = 0,
39 			.ver_sync_polarity = 0,
40 			.b_interlace = 1,
41 			.vactive_space = 0,
42 			.trd_mode = 0,
43 
44 		},
45 		{
46 			.vic = HDMI1440_576I,
47 			.tv_mode = DISP_TV_MOD_576I,
48 			.pixel_clk = 27000000,
49 			.pixel_repeat = 0,
50 			.x_res = 720,
51 			.y_res = 480,
52 			.hor_total_time = 858,
53 			.hor_back_porch = 60,
54 			.hor_front_porch = 16,
55 			.hor_sync_time = 62,
56 			.ver_total_time = 525,
57 			.ver_back_porch = 30,
58 			.ver_front_porch = 9,
59 			.ver_sync_time = 6,
60 			.hor_sync_polarity = 0,
61 			.ver_sync_polarity = 0,
62 			.b_interlace = 0,
63 			.vactive_space = 0,
64 			.trd_mode = 0,
65 		},
66 		{
67 			.vic = HDMI480P,
68 			.tv_mode = DISP_TV_MOD_480P,
69 			.pixel_clk = 27000000,
70 			.pixel_repeat = 0,
71 			.x_res = 720,
72 			.y_res = 480,
73 			.hor_total_time = 858,
74 			.hor_back_porch = 60,
75 			.hor_front_porch = 16,
76 			.hor_sync_time = 62,
77 			.ver_total_time = 525,
78 			.ver_back_porch = 30,
79 			.ver_front_porch = 9,
80 			.ver_sync_time = 6,
81 			.hor_sync_polarity = 0,
82 			.ver_sync_polarity = 0,
83 			.b_interlace = 0,
84 			.vactive_space = 0,
85 			.trd_mode = 0,
86 		},
87 		{
88 			.vic = HDMI576P,
89 			.tv_mode = DISP_TV_MOD_576P,
90 			.pixel_clk = 27000000,
91 			.pixel_repeat = 0,
92 			.x_res = 720,
93 			.y_res = 576,
94 			.hor_total_time = 864,
95 			.hor_back_porch = 68,
96 			.hor_front_porch = 12,
97 			.hor_sync_time = 64,
98 			.ver_total_time = 625,
99 			.ver_back_porch = 39,
100 			.ver_front_porch = 5,
101 			.ver_sync_time = 5,
102 			.hor_sync_polarity = 0,
103 			.ver_sync_polarity = 0,
104 			.b_interlace = 0,
105 			.vactive_space = 0,
106 			.trd_mode = 0,
107 		},
108 		{
109 			.vic = HDMI720P_50,
110 			.tv_mode = DISP_TV_MOD_720P_50HZ,
111 			.pixel_clk = 74250000,
112 			.pixel_repeat = 0,
113 			.x_res = 1280,
114 			.y_res = 720,
115 			.hor_total_time = 1980,
116 			.hor_back_porch = 220,
117 			.hor_front_porch = 440,
118 			.hor_sync_time = 40,
119 			.ver_total_time = 750,
120 			.ver_back_porch = 20,
121 			.ver_front_porch = 5,
122 			.ver_sync_time = 5,
123 			.hor_sync_polarity = 1,
124 			.ver_sync_polarity = 1,
125 			.b_interlace = 0,
126 			.vactive_space = 0,
127 			.trd_mode = 0,
128 		},
129 		{
130 			.vic = HDMI720P_60,
131 			.tv_mode = DISP_TV_MOD_720P_60HZ,
132 			.pixel_clk = 74250000,
133 			.pixel_repeat = 0,
134 			.x_res = 1280,
135 			.y_res = 720,
136 			.hor_total_time = 1650,
137 			.hor_back_porch = 220,
138 			.hor_front_porch = 110,
139 			.hor_sync_time = 40,
140 			.ver_total_time = 750,
141 			.ver_back_porch = 20,
142 			.ver_front_porch = 5,
143 			.ver_sync_time = 5,
144 			.hor_sync_polarity = 1,
145 			.ver_sync_polarity = 1,
146 			.b_interlace = 0,
147 			.vactive_space = 0,
148 			.trd_mode = 0,
149 		},
150 		{
151 			.vic = HDMI1080I_50,
152 			.tv_mode = DISP_TV_MOD_1080I_50HZ,
153 			.pixel_clk = 74250000,
154 			.pixel_repeat = 0,
155 			.x_res = 1920,
156 			.y_res = 1080,
157 			.hor_total_time = 2640,
158 			.hor_back_porch = 148,
159 			.hor_front_porch = 528,
160 			.hor_sync_time = 44,
161 			.ver_total_time = 1125,
162 			.ver_back_porch = 15,
163 			.ver_front_porch = 2,
164 			.ver_sync_time = 5,
165 			.hor_sync_polarity = 1,
166 			.ver_sync_polarity = 1,
167 			.b_interlace = 1,
168 			.vactive_space = 0,
169 			.trd_mode = 0,
170 		},
171 		{
172 			.vic = HDMI1080I_60,
173 			.tv_mode = 0,
174 			.pixel_clk = 74250000,
175 			.pixel_repeat = DISP_TV_MOD_1080I_60HZ,
176 			.x_res = 1920,
177 			.y_res = 1080,
178 			.hor_total_time = 2200,
179 			.hor_back_porch = 148,
180 			.hor_front_porch = 88,
181 			.hor_sync_time = 44,
182 			.ver_total_time = 1125,
183 			.ver_back_porch = 15,
184 			.ver_front_porch = 2,
185 			.ver_sync_time = 5,
186 			.hor_sync_polarity = 1,
187 			.ver_sync_polarity = 1,
188 			.b_interlace = 1,
189 			.vactive_space = 0,
190 			.trd_mode = 0,
191 		},
192 		{
193 			.vic = HDMI1080P_50,
194 			.tv_mode = DISP_TV_MOD_1080P_50HZ,
195 			.pixel_clk = 148500000,
196 			.pixel_repeat = 0,
197 			.x_res = 1920,
198 			.y_res = 1080,
199 			.hor_total_time = 2640,
200 			.hor_back_porch = 148,
201 			.hor_front_porch = 528,
202 			.hor_sync_time = 44,
203 			.ver_total_time = 1125,
204 			.ver_back_porch = 36,
205 			.ver_front_porch = 4,
206 			.ver_sync_time = 5,
207 			.hor_sync_polarity = 1,
208 			.ver_sync_polarity = 1,
209 			.b_interlace = 0,
210 			.vactive_space = 0,
211 			.trd_mode = 0,
212 		},
213 		{
214 			.vic = HDMI1080P_60,
215 			.tv_mode = DISP_TV_MOD_1080P_60HZ,
216 			.pixel_clk = 148500000,
217 			.pixel_repeat = 0,
218 			.x_res = 1920,
219 			.y_res = 1080,
220 			.hor_total_time = 2200,
221 			.hor_back_porch = 148,
222 			.hor_front_porch = 88,
223 			.hor_sync_time = 44,
224 			.ver_total_time = 1125,
225 			.ver_back_porch = 36,
226 			.ver_front_porch = 4,
227 			.ver_sync_time = 5,
228 			.hor_sync_polarity = 1,
229 			.ver_sync_polarity = 1,
230 			.b_interlace = 0,
231 			.vactive_space = 0,
232 			.trd_mode = 0,
233 		},
234 		{
235 			.vic = HDMI1080P_24,
236 			.tv_mode = DISP_TV_MOD_1080P_24HZ,
237 			.pixel_clk = 74250000,
238 			.pixel_repeat = 0,
239 			.x_res = 1920,
240 			.y_res = 1080,
241 			.hor_total_time = 2750,
242 			.hor_back_porch = 148,
243 			.hor_front_porch = 638,
244 			.hor_sync_time = 44,
245 			.ver_total_time = 1125,
246 			.ver_back_porch = 36,
247 			.ver_front_porch = 4,
248 			.ver_sync_time = 5,
249 			.hor_sync_polarity = 1,
250 			.ver_sync_polarity = 1,
251 			.b_interlace = 0,
252 			.vactive_space = 0,
253 			.trd_mode = 0,
254 		},
255 		{
256 			.vic = HDMI1080P_25,
257 			.tv_mode = DISP_TV_MOD_1080P_25HZ,
258 			.pixel_clk = 74250000,
259 			.pixel_repeat = 0,
260 			.x_res = 1920,
261 			.y_res = 1080,
262 			.hor_total_time = 2640,
263 			.hor_back_porch = 148,
264 			.hor_front_porch = 528,
265 			.hor_sync_time = 44,
266 			.ver_total_time = 1125,
267 			.ver_back_porch = 36,
268 			.ver_front_porch = 4,
269 			.ver_sync_time = 5,
270 			.hor_sync_polarity = 0,
271 			.ver_sync_polarity = 0,
272 			.b_interlace = 0,
273 			.vactive_space = 0,
274 			.trd_mode = 0,
275 		},
276 		{
277 			.vic = HDMI1080P_30,
278 			.tv_mode = DISP_TV_MOD_1080P_30HZ,
279 			.pixel_clk = 74250000,
280 			.pixel_repeat = 0,
281 			.x_res = 1920,
282 			.y_res = 1080,
283 			.hor_total_time = 2200,
284 			.hor_back_porch = 148,
285 			.hor_front_porch = 88,
286 			.hor_sync_time = 44,
287 			.ver_total_time = 1125,
288 			.ver_back_porch = 36,
289 			.ver_front_porch = 4,
290 			.ver_sync_time = 5,
291 			.hor_sync_polarity = 0,
292 			.ver_sync_polarity = 0,
293 			.b_interlace = 0,
294 			.vactive_space = 0,
295 			.trd_mode = 0,
296 		},
297 		{
298 			.vic = HDMI1080P_24_3D_FP,
299 			.tv_mode = DISP_TV_MOD_1080P_24HZ_3D_FP,
300 			.pixel_clk = 148500000,
301 			.pixel_repeat = 0,
302 			.x_res = 1920,
303 			.y_res = 2160,
304 			.hor_total_time = 2750,
305 			.hor_back_porch = 148,
306 			.hor_front_porch = 638,
307 			.hor_sync_time = 44,
308 			.ver_total_time = 1125,
309 			.ver_back_porch = 36,
310 			.ver_front_porch = 4,
311 			.ver_sync_time = 5,
312 			.hor_sync_polarity = 1,
313 			.ver_sync_polarity = 1,
314 			.b_interlace = 0,
315 			.vactive_space = 45,
316 			.trd_mode = 1,
317 		},
318 		{
319 			.vic = HDMI720P_50_3D_FP,
320 			.tv_mode = DISP_TV_MOD_720P_50HZ_3D_FP,
321 			.pixel_clk = 148500000,
322 			.pixel_repeat = 0,
323 			.x_res = 1280,
324 			.y_res = 1440,
325 			.hor_total_time = 1980,
326 			.hor_back_porch = 220,
327 			.hor_front_porch = 440,
328 			.hor_sync_time = 40,
329 			.ver_total_time = 750,
330 			.ver_back_porch = 20,
331 			.ver_front_porch = 5,
332 			.ver_sync_time = 5,
333 			.hor_sync_polarity = 1,
334 			.ver_sync_polarity = 1,
335 			.b_interlace = 0,
336 			.vactive_space = 30,
337 			.trd_mode = 1,
338 		},
339 		{
340 			.vic = HDMI720P_60_3D_FP,
341 			.tv_mode = DISP_TV_MOD_720P_60HZ_3D_FP,
342 			.pixel_clk = 148500000,
343 			.pixel_repeat = 0,
344 			.x_res = 1280,
345 			.y_res = 1440,
346 			.hor_total_time = 1650,
347 			.hor_back_porch = 220,
348 			.hor_front_porch = 110,
349 			.hor_sync_time = 40,
350 			.ver_total_time = 750,
351 			.ver_back_porch = 20,
352 			.ver_front_porch = 5,
353 			.ver_sync_time = 5,
354 			.hor_sync_polarity = 1,
355 			.ver_sync_polarity = 1,
356 			.b_interlace = 0,
357 			.vactive_space = 30,
358 			.trd_mode = 1,
359 		},
360 		{
361 			.vic = HDMI3840_2160P_30,
362 			.tv_mode = DISP_TV_MOD_3840_2160P_30HZ,
363 			.pixel_clk = 297000000,
364 			.pixel_repeat = 0,
365 			.x_res = 3840,
366 			.y_res = 2160,
367 			.hor_total_time = 4400,
368 			.hor_back_porch = 296,
369 			.hor_front_porch = 176,
370 			.hor_sync_time = 88,
371 			.ver_total_time = 2250,
372 			.ver_back_porch = 72,
373 			.ver_front_porch = 8,
374 			.ver_sync_time = 10,
375 			.hor_sync_polarity = 1,
376 			.ver_sync_polarity = 1,
377 			.b_interlace = 0,
378 			.vactive_space = 0,
379 			.trd_mode = 0,
380 		},
381 		{
382 			.vic = HDMI3840_2160P_25,
383 			.tv_mode = DISP_TV_MOD_3840_2160P_25HZ,
384 			.pixel_clk = 297000000,
385 			.pixel_repeat = 0,
386 			.x_res = 3840,
387 			.y_res = 2160,
388 			.hor_total_time = 5280,
389 			.hor_back_porch = 296,
390 			.hor_front_porch = 1056,
391 			.hor_sync_time = 88,
392 			.ver_total_time = 2250,
393 			.ver_back_porch = 72,
394 			.ver_front_porch = 8,
395 			.ver_sync_time = 10,
396 			.hor_sync_polarity = 1,
397 			.ver_sync_polarity = 1,
398 			.b_interlace = 0,
399 			.vactive_space = 0,
400 			.trd_mode = 0,
401 		},
402 		{
403 			.vic = HDMI3840_2160P_24,
404 			.tv_mode = DISP_TV_MOD_3840_2160P_24HZ,
405 			.pixel_clk = 297000000,
406 			.pixel_repeat = 0,
407 			.x_res = 3840,
408 			.y_res = 2160,
409 			.hor_total_time = 5500,
410 			.hor_back_porch = 296,
411 			.hor_front_porch = 1276,
412 			.hor_sync_time = 88,
413 			.ver_total_time = 2250,
414 			.ver_back_porch = 72,
415 			.ver_front_porch = 8,
416 			.ver_sync_time = 10,
417 			.hor_sync_polarity = 1,
418 			.ver_sync_polarity = 1,
419 			.b_interlace = 0,
420 			.vactive_space = 0,
421 			.trd_mode = 0,
422 		},
423 		{
424 			.vic = HDMI4096_2160P_24,
425 			.tv_mode = DISP_TV_MOD_4096_2160P_24HZ,
426 			.pixel_clk = 297000000,
427 			.pixel_repeat = 0,
428 			.x_res = 4096,
429 			.y_res = 2160,
430 			.hor_total_time = 5500,
431 			.hor_back_porch = 296,
432 			.hor_front_porch = 1020,
433 			.hor_sync_time = 88,
434 			.ver_total_time = 2250,
435 			.ver_back_porch = 72,
436 			.ver_front_porch = 8,
437 			.ver_sync_time = 10,
438 			.hor_sync_polarity = 1,
439 			.ver_sync_polarity = 1,
440 			.b_interlace = 0,
441 			.vactive_space = 0,
442 			.trd_mode = 0,
443 		},
444 };
445 
sunxi_hdmi_get_hdmi(void)446 static struct sunxi_hdmi *sunxi_hdmi_get_hdmi(void)
447 {
448 	if (hwhdmi)
449 		return hwhdmi;
450 	return NULL;
451 }
452 
sunxi_hdmi_get_funcs(void)453 struct sunxi_hdmi_funcs *sunxi_hdmi_get_funcs(void)
454 {
455 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
456 
457 	return (struct sunxi_hdmi_funcs *)hdmi->funcs;
458 }
459 
hdmi_get_soc_version(void)460 static unsigned int hdmi_get_soc_version(void)
461 {
462 	unsigned int version = 0;
463 #if defined(CONFIG_ARCH_SUN8IW7)
464 #if defined(SUN8IW7P1_REV_A) || defined(SUN8IW7P2_REV_B)
465 	unsigned int chip_ver = sunxi_get_soc_ver();
466 
467 	switch (chip_ver) {
468 	case SUN8IW7P1_REV_A:
469 	case SUN8IW7P2_REV_A:
470 		version = 0;
471 		break;
472 	case SUN8IW7P1_REV_B:
473 	case SUN8IW7P2_REV_B:
474 		version = 1;
475 	}
476 #else
477 	version = 1;
478 #endif /*endif  SUN8IW7P1_REV_A*/
479 #endif
480 	return version;
481 }
482 
483 
sunxi_hdmi_get_timing_list_num(struct sunxi_hdmi * hdmi)484 static int sunxi_hdmi_get_timing_list_num(struct sunxi_hdmi *hdmi)
485 {
486 	int ret = sizeof(hdmi_video_timing)
487 		/ sizeof(struct disp_video_timings);
488 
489 	return ret;
490 }
491 
492 static int
sunxi_hdmi_get_video_mode_info(struct disp_video_timings ** video_info,enum disp_tv_mode tv_mode)493 sunxi_hdmi_get_video_mode_info(struct disp_video_timings **video_info,
494 			       enum disp_tv_mode tv_mode)
495 {
496 	int i;
497 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
498 	int num = sunxi_hdmi_get_timing_list_num(hdmi);
499 
500 	for (i = 0; i < num; i++) {
501 		if (hdmi_video_timing[i].tv_mode == tv_mode)
502 			break;
503 	}
504 
505 	if (i >= num) {
506 		HDMI_INFO("can NOT get timing info of tv_mode:%d\n", tv_mode);
507 		*video_info = NULL;
508 		return -1;
509 	}
510 
511 	*video_info = &hdmi_video_timing[i];
512 
513 	return 0;
514 }
515 
hdmi_clk_get_div(void)516 unsigned int hdmi_clk_get_div(void)
517 {
518 	unsigned long rate = 1, rate_parent = 1;
519 	unsigned int div = 4;
520 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
521 
522 	if (hdmi->mclk)
523 		rate = clk_get_rate(hdmi->mclk);
524 	if (hdmi->mclk_parent)
525 		rate_parent = clk_get_rate(hdmi->mclk_parent);
526 
527 	if (rate != 0)
528 		div = rate_parent / rate;
529 	else
530 		HDMI_ERR("hdmi clk rate is ZERO!\n");
531 
532 	return div;
533 }
534 
535 /*get actually hdmi reg address*/
sunxi_hdmi_reg_mapping(u32 reg)536 static u32 sunxi_hdmi_reg_mapping(u32 reg)
537 {
538 	int i = 0;
539 	u32 reg_map = 0;
540 	unsigned int offset[16] = {1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0};
541 
542 	for (i = 0; i < 16; i++)
543 		reg_map |= ((((reg >> offset[i]) & 0x1)) << (15 - i));
544 
545 	return reg_map;
546 }
547 
sunxi_hdmi_write(u32 reg,u8 value)548 static void sunxi_hdmi_write(u32 reg, u8 value)
549 {
550 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
551 	unsigned long addr = (unsigned long)hdmi->reg_base;
552 	u32 actual_reg;
553 
554 	actual_reg = sunxi_hdmi_reg_mapping(reg);
555 	addr += actual_reg;
556 
557 	*((volatile unsigned char *)(hdmi->reg_base + 0x10010)) = 0x45;
558 	*((volatile unsigned char *)(hdmi->reg_base + 0x10011)) = 0x45;
559 	*((volatile unsigned char *)(hdmi->reg_base + 0x10012)) = 0x52;
560 	*((volatile unsigned char *)(hdmi->reg_base + 0x10013)) = 0x54;
561 
562 	*((volatile unsigned char *)(addr)) = value;
563 
564 	*((volatile unsigned char *)(hdmi->reg_base + 0x10010)) = 0x52;
565 	*((volatile unsigned char *)(hdmi->reg_base + 0x10011)) = 0x54;
566 	*((volatile unsigned char *)(hdmi->reg_base + 0x10012)) = 0x41;
567 	*((volatile unsigned char *)(hdmi->reg_base + 0x10013)) = 0x57;
568 }
569 
sunxi_hdmi_read(u32 reg)570 static u8 sunxi_hdmi_read(u32 reg)
571 {
572 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
573 	unsigned long addr = (unsigned long)hdmi->reg_base;
574 	u32 actual_reg;
575 	unsigned char val;
576 
577 	actual_reg = sunxi_hdmi_reg_mapping(reg);
578 
579 	addr += actual_reg;
580 
581 	*((volatile unsigned char *)(hdmi->reg_base + 0x10010)) = 0x45;
582 	*((volatile unsigned char *)(hdmi->reg_base + 0x10011)) = 0x45;
583 	*((volatile unsigned char *)(hdmi->reg_base + 0x10012)) = 0x52;
584 	*((volatile unsigned char *)(hdmi->reg_base + 0x10013)) = 0x54;
585 
586 	val = *((volatile unsigned char *)(addr));
587 
588 	*((volatile unsigned char *)(hdmi->reg_base + 0x10010)) = 0x52;
589 	*((volatile unsigned char *)(hdmi->reg_base + 0x10011)) = 0x54;
590 	*((volatile unsigned char *)(hdmi->reg_base + 0x10012)) = 0x41;
591 	*((volatile unsigned char *)(hdmi->reg_base + 0x10013)) = 0x57;
592 
593 	return val;
594 }
595 
596 
597 static void
sunxi_hdmi_timing_convert_to_video_para(struct disp_video_timings * timing,struct video_para * para)598 sunxi_hdmi_timing_convert_to_video_para(struct disp_video_timings *timing,
599 					struct video_para *para)
600 {
601 	para->vic = timing->vic;
602 	para->pixel_clk = timing->pixel_clk;
603 	para->clk_div = hdmi_clk_get_div();
604 	para->pixel_repeat = timing->pixel_repeat;
605 	para->x_res = timing->x_res;
606 	para->y_res = timing->y_res;
607 	para->hor_total_time = timing->hor_total_time;
608 	para->hor_back_porch = timing->hor_back_porch;
609 	para->hor_front_porch = timing->hor_front_porch;
610 	para->hor_sync_time = timing->hor_sync_time;
611 	para->ver_total_time = timing->ver_total_time;
612 	para->ver_back_porch = timing->ver_back_porch;
613 	para->ver_front_porch = timing->ver_front_porch;
614 	para->ver_sync_time = timing->ver_sync_time;
615 	para->hor_sync_polarity = timing->hor_sync_polarity;
616 	para->ver_sync_polarity = timing->ver_sync_polarity;
617 	para->b_interlace = timing->b_interlace;
618 }
619 
sunxi_dump_video_para(struct video_para * para)620 void sunxi_dump_video_para(struct video_para *para)
621 {
622 	HDMI_INFO("HDMI VIDEO PARA:\n");
623 	HDMI_INFO("vic:%u  csc:%u is_hdmi:%u is_yuv:%u is_hcts:%d\n",
624 		para->vic, para->csc, para->is_hdmi, para->is_yuv, para->is_hcts);
625 	HDMI_INFO("pixel_clk:%u clk_div:%u pixel_repeat:%u\n",
626 		para->pixel_clk, para->clk_div, para->pixel_repeat);
627 	HDMI_INFO("x-y:%ux%u "
628 		"htotal:%u hor_back_porch:%u hor_front_porch:%u hsync:%u "
629 		"vtotal:%u ver_back_porch:%u ver_front_porch:%u vsync:%u "
630 		"hpol:%u vpol:%u  interlace:%u\n",
631 		para->x_res, para->y_res,
632 		para->hor_total_time, para->hor_back_porch, para->hor_front_porch, para->hor_sync_time,
633 		para->ver_total_time, para->ver_back_porch, para->ver_front_porch, para->ver_sync_time,
634 		para->hor_sync_polarity, para->ver_sync_polarity, para->b_interlace);
635 }
636 
637 static bool hdmi_clk_enable;
sunxi_hdmi_clk_enable(struct sunxi_hdmi * hdmi)638 int sunxi_hdmi_clk_enable(struct sunxi_hdmi *hdmi)
639 {
640 	int ret;
641 
642 	if (hdmi_clk_enable)
643 		return 0;
644 	hdmi_clk_enable = true;
645 
646 	ret = clk_prepare_enable(hdmi->mclk);
647 	if (ret < 0) {
648 		HDMI_ERR("fail to enable hdmi mclk\n");
649 		return -1;
650 	}
651 
652 	ret = clk_prepare_enable(hdmi->ddc_clk);
653 	if (ret < 0) {
654 		HDMI_ERR("fail to enable hdmi ddc clk\n");
655 		return -1;
656 	}
657 
658 #if defined(CONFIG_ARCH_SUN8IW12)
659 	ret = clk_prepare_enable(hdmi->cec_clk);
660 	if (ret < 0) {
661 		HDMI_ERR("fail to enable hdmi cec clk\n");
662 		return -1;
663 	}
664 #endif
665 
666 	return 0;
667 }
668 
sunxi_hdmi_clk_disable(struct sunxi_hdmi * hdmi)669 static int sunxi_hdmi_clk_disable(struct sunxi_hdmi *hdmi)
670 {
671 	if (!hdmi_clk_enable)
672 		return 0;
673 	hdmi_clk_enable = false;
674 
675 	if (__clk_get_enable_count(hdmi->mclk))
676 		clk_disable_unprepare(hdmi->mclk);
677 
678 	if (__clk_get_enable_count(hdmi->ddc_clk))
679 		clk_disable_unprepare(hdmi->ddc_clk);
680 
681 #if defined(CONFIG_ARCH_SUN8IW12)
682 	if (__clk_get_enable_count(hdmi->cec_clk))
683 		clk_disable_unprepare(hdmi->cec_clk);
684 #endif
685 
686 	return 0;
687 }
688 
sunxi_hdmi_get_connect_status(void)689 static int sunxi_hdmi_get_connect_status(void)
690 {
691 	int status, time_out = 5;
692 
693 	/* read hdmi connected status with anti-shake check */
694 	/* the connected status should remain unchanged for 20*5 ms */
695 	status = bsp_hdmi_get_hpd();
696 	while (time_out) {
697 		msleep(20);
698 		if (status == bsp_hdmi_get_hpd())
699 			--time_out;
700 		else {
701 			time_out = 5;
702 			status = bsp_hdmi_get_hpd();
703 		}
704 	}
705 
706 	return status;
707 }
708 
sunxi_hdmi_get_support_tv_mode(unsigned int pixel_clk,unsigned int hdisplay,unsigned int vdisplay,unsigned int htotal,unsigned int vtotal,bool is_interlace,bool is_3d)709 static int sunxi_hdmi_get_support_tv_mode(unsigned int pixel_clk,
710 				       unsigned int hdisplay,
711 				       unsigned int vdisplay,
712 				       unsigned int htotal,
713 				       unsigned int vtotal,
714 				bool is_interlace, bool is_3d)
715 {
716 	int i;
717 	struct disp_video_timings *timing = hdmi_video_timing;
718 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
719 	int num = sunxi_hdmi_get_timing_list_num(hdmi);
720 
721 	DRM_DEBUG_DRIVER("pixel_clk:%u  %ux%u  total:%ux%u interlace:%d 3d:%d\n",
722 			pixel_clk, hdisplay, vdisplay, htotal, vtotal, is_interlace, is_3d);
723 
724 	for (i = 0; i < num; i++) {
725 		if (timing[i].pixel_clk * (1 + timing[i].pixel_repeat)
726 			/(1 + timing[i].b_interlace) == pixel_clk * (1 + is_3d)
727 			&& timing[i].x_res == hdisplay
728 			&& timing[i].y_res == (vdisplay * (1 + is_3d))
729 			&& timing[i].hor_total_time == htotal
730 			&& timing[i].ver_total_time == vtotal
731 			&& timing[i].b_interlace == is_interlace
732 			&& timing[i].trd_mode == is_3d)
733 			break;
734 	}
735 
736 	if (i >= num) {
737 		DRM_DEBUG_DRIVER("WARN:hdmi_source NOT support:%ux%u%c@%u %s\n",
738 			hdisplay, vdisplay, is_interlace ? 'I' : 'P',
739 			pixel_clk / (vtotal * htotal),
740 			is_3d ? "(3D)" : "(NOT 3D)");
741 		return -1;
742 	}
743 
744 	return timing[i].tv_mode;
745 }
746 
747 struct disp_video_timings *
sunxi_hdmi_get_timing_from_tv_mode(unsigned int tv_mode)748 sunxi_hdmi_get_timing_from_tv_mode(unsigned int tv_mode)
749 {
750 	struct disp_video_timings *timing;
751 
752 	sunxi_hdmi_get_video_mode_info(&timing, tv_mode);
753 
754 	return timing;
755 }
756 
sunxi_hdmi_get_resolution_from_tv_mode(unsigned int tv_mode,unsigned int * hdisplay,unsigned int * vdisplay,unsigned int * vrefresh,bool * is_interlace,bool * is_3d)757 static int sunxi_hdmi_get_resolution_from_tv_mode(
758 					   unsigned int tv_mode,
759 					   unsigned int *hdisplay,
760 					   unsigned int *vdisplay,
761 					   unsigned int *vrefresh,
762 					   bool *is_interlace, bool *is_3d)
763 {
764 	int i;
765 	struct disp_video_timings *timing = hdmi_video_timing;
766 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
767 	int num = sunxi_hdmi_get_timing_list_num(hdmi);
768 
769 	for (i = 0; i < num; i++)
770 		if (timing[i].tv_mode == tv_mode)
771 			break;
772 
773 	if (i >= num) {
774 		HDMI_INFO("WARN:NOT support tv_mode:%u\n", tv_mode);
775 		return -1;
776 	}
777 
778 	if (hdisplay)
779 		*hdisplay = timing[i].x_res;
780 	if (vdisplay)
781 		*vdisplay = timing[i].y_res;
782 	if (vrefresh)
783 		*vrefresh = (timing[i].pixel_clk * (timing[i].pixel_repeat + 1))
784 					/ (timing[i].b_interlace + 1)
785 					/ (timing[i].hor_total_time * timing[i].ver_total_time);
786 	if (is_interlace)
787 		*is_interlace = timing[i].b_interlace;
788 	if (is_3d)
789 		*is_3d = timing[i].trd_mode;
790 
791 	return 0;
792 }
793 
794 void
sunxi_hdmi_get_working_mode(struct sunxi_hdmi_work_mode * work_mode)795 sunxi_hdmi_get_working_mode(struct sunxi_hdmi_work_mode *work_mode)
796 {
797 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
798 
799 	work_mode->hdmi_mode = hdmi->video.is_hdmi ?
800 		 MODE_HDMI : MODE_DVI;
801 
802 	work_mode->color_fmt = hdmi->video.is_yuv ?
803 		 COLOR_FMT_YUV444 : COLOR_FMT_RGB444;
804 
805 	work_mode->color_depth = 8;
806 }
807 
808 static int
sunxi_hdmi_set_working_mode(struct sunxi_hdmi_work_mode * work_mode)809 sunxi_hdmi_set_working_mode(struct sunxi_hdmi_work_mode *work_mode)
810 {
811 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
812 
813 	if (work_mode->color_fmt == COLOR_FMT_RGB444)
814 		hdmi->video.is_yuv = 0;
815 	else if (work_mode->color_fmt == COLOR_FMT_YUV444)
816 		hdmi->video.is_yuv = 1;
817 	else {
818 		HDMI_ERR("invalid color format:%d\n", work_mode->color_fmt);
819 		return -1;
820 	}
821 
822 	if (work_mode->hdmi_mode == DISP_DVI)
823 		hdmi->video.is_hdmi = 0;
824 	else if (work_mode->hdmi_mode == DISP_HDMI)
825 		hdmi->video.is_hdmi = 1;
826 	else {
827 		HDMI_ERR("invalid hdmi mode:%d\n", work_mode->hdmi_mode);
828 		return -1;
829 	}
830 
831 	return 0;
832 }
833 
sunxi_hdmi_get_edid_block(void * data,unsigned char * buf,unsigned int block,size_t len)834 static int sunxi_hdmi_get_edid_block(void *data, unsigned char *buf,
835 		unsigned int block, size_t len)
836 {
837 	int ret = 0;
838 	unsigned char offset = (block & 0x01) ? 128:0;
839 
840 	ret = bsp_hdmi_ddc_read(Explicit_Offset_Address_E_DDC_Read,
841 		((unsigned char)block) >> 1, offset, len, buf);
842 
843 	/*dump hdmi raw data*/
844 	/*for (i = 0; i < len; i++) {
845 		if (((i % 16) == 0) && i)
846 			printk("\n");
847 		printk("0x%02x ", buf[i]);
848 	}*/
849 
850 	return ret;
851 }
852 
853 /*static void sunxi_hdmi_mode_related_params_correct(
854 		struct sunxi_mode_related_info *info)
855 {
856 	int i;
857 	struct color_format_depth *fmt_depth = info->fmt_depth;
858 
859 	for (i = 0; i < 16; i++) {
860 		if (((fmt_depth[i].format != COLOR_FMT_RGB444)
861 			&& (fmt_depth[i].format != COLOR_FMT_YUV444))
862 			|| (fmt_depth[i].depth != SUNXI_COLOR_DEPTH_8)) {
863 			fmt_depth[i].format = 0;
864 			fmt_depth[i].depth = 0;
865 		}
866 	}
867 }*/
868 
sunxi_hdmi_mode_independent_params_correct(struct sunxi_drm_display_info * info)869 static void sunxi_hdmi_mode_independent_params_correct(
870 		struct sunxi_drm_display_info *info)
871 {
872 	info->bpc = 8;
873 	info->support_yuv422 = false;
874 	info->support_yuv420 = false;
875 
876 	/*10/12/16bits*/
877 	info->support_deep_color30 = false;
878 	info->support_deep_color36 = false;
879 	info->support_deep_color48 = false;
880 
881 	/*HDMI2.0 HF_VSDB*/
882 	info->scramble_340mcs = false;
883 
884 	/*hdr*/
885 	memset(&info->hdr_static_metadata, 0,
886 		sizeof(struct hdr_static_metadata_data_block));
887 }
888 
sunxi_hdmi_enable(int tv_mode)889 static int sunxi_hdmi_enable(int tv_mode)
890 {
891 	int ret;
892 	struct disp_video_timings *timing;
893 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
894 	struct audio_para *audio_para = &hdmi->audio;
895 	struct video_para *video_para = &hdmi->video;
896 
897 	ret = sunxi_hdmi_get_video_mode_info(&timing, tv_mode);
898 	if (ret < 0) {
899 		HDMI_ERR("tv mode:%d has NO coresponsible timing\n", tv_mode);
900 		return ret;
901 	}
902 	hdmi->video_info = timing;
903 
904 	clk_set_rate(hdmi->mclk, timing->pixel_clk);
905 
906 	bsp_hdmi_hrst();
907 	bsp_hdmi_standby();
908 
909 	if (video_para->is_hcts)
910 		bsp_hdmi_hrst();
911 
912 	sunxi_hdmi_timing_convert_to_video_para(timing, video_para);
913 
914 	//sunxi_dump_video_para(video_para);
915 	ret = bsp_hdmi_video(video_para);
916 	if (ret) {
917 		HDMI_ERR("set hdmi video error!");
918 		return -1;
919 	}
920 
921 	bsp_hdmi_set_video_en(1);
922 
923 	if (video_para->is_hdmi) {
924 		ret = bsp_hdmi_audio(audio_para);
925 		if (ret) {
926 			HDMI_ERR("set hdmi audio error!\n");
927 			return -1;
928 		}
929 	}
930 
931 	return 0;
932 }
933 
sunxi_hdmi_sw_enable(int tv_mode)934 static int sunxi_hdmi_sw_enable(int tv_mode)
935 {
936 	int ret;
937 	struct disp_video_timings *timing;
938 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
939 	//struct audio_para *audio_para = &hdmi->audio;
940 	struct video_para *video_para = &hdmi->video;
941 
942 	ret = sunxi_hdmi_get_video_mode_info(&timing, tv_mode);
943 	if (ret < 0) {
944 		HDMI_ERR("tv mode:%d has NO coresponsible timing\n", tv_mode);
945 		return ret;
946 	}
947 	hdmi->video_info = timing;
948 	video_para->vic = timing->vic;
949 
950 	clk_set_rate(hdmi->mclk, timing->pixel_clk);
951 
952 	return 0;
953 }
954 
sunxi_hdmi_disable(void)955 static void sunxi_hdmi_disable(void)
956 {
957 	//struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
958 
959 	bsp_hdmi_set_video_en(0);
960 	//sunxi_hdmi_clk_disable();
961 }
962 
963 static unsigned int reg_read_start, reg_read_end, reg_read_cmd;
sunxi_hdmi_read_show(struct device * dev,struct device_attribute * attr,char * buf)964 static ssize_t sunxi_hdmi_read_show(struct device *dev,
965 		struct device_attribute *attr, char *buf)
966 {
967 	ssize_t n = 0;
968 	unsigned int reg;
969 
970 	if (!reg_read_cmd) {
971 		n += sprintf(buf + n, "read hdmi register, Usage:\n");
972 		n += sprintf(buf + n, "echo [reg_offset_start] [reg_offset_end] > read\n");
973 		n += sprintf(buf + n, "OR:echo [reg_offset_start],[reg_offset_end] > read\n");
974 		return n;
975 	}
976 
977 	for (reg = reg_read_start; reg <= reg_read_end; reg++) {
978 		if (reg % 16 == 0) {
979 			n += sprintf(buf + n, "\n");
980 			n += sprintf(buf + n, "0x%x: ", reg);
981 		}
982 
983 		n += sprintf(buf + n, "0x%02x ", sunxi_hdmi_read(reg));
984 	}
985 
986 	n += sprintf(buf + n, "\n");
987 
988 	reg_read_cmd = 0;
989 
990 	return n;
991 }
992 
sunxi_hdmi_read_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)993 static ssize_t sunxi_hdmi_read_store(struct device *dev,
994 				struct device_attribute *attr,
995 				const char *buf, size_t count)
996 {
997 	char *end;
998 
999 	reg_read_start = (unsigned int)simple_strtoull(buf, &end, 0);
1000 
1001 	if ((*end != ' ') && (*end != ',')) {
1002 		HDMI_ERR("error separator:%c\n", *end);
1003 		return count;
1004 	}
1005 
1006 	reg_read_end = (unsigned int)simple_strtoull(end + 1, &end, 0);
1007 
1008 	reg_read_cmd = 1;
1009 
1010 	return count;
1011 }
1012 
1013 static DEVICE_ATTR(read, 0660,
1014 		sunxi_hdmi_read_show, sunxi_hdmi_read_store);
1015 
sunxi_hdmi_write_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1016 static ssize_t sunxi_hdmi_write_store(struct device *dev,
1017 				struct device_attribute *attr,
1018 				const char *buf, size_t count)
1019 {
1020 	char *end;
1021 	unsigned int reg_addr;
1022 	unsigned char value;
1023 
1024 	reg_addr = (unsigned int)simple_strtoull(buf, &end, 0);
1025 
1026 	if ((*end != ' ') && (*end != ',')) {
1027 		HDMI_ERR("error separator:%c\n", *end);
1028 		return count;
1029 	}
1030 
1031 	value = (unsigned char)simple_strtoull(end + 1, &end, 0);
1032 
1033 	sunxi_hdmi_write(reg_addr, value);
1034 
1035 	return count;
1036 }
1037 
1038 static DEVICE_ATTR(write, 0660, NULL, sunxi_hdmi_write_store);
1039 
1040 
1041 
sunxi_hdmi_source_para_show(struct device * dev,struct device_attribute * attr,char * buf)1042 static ssize_t sunxi_hdmi_source_para_show(struct device *dev,
1043 		struct device_attribute *attr, char *buf)
1044 {
1045 	ssize_t n = 0;
1046 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
1047 	struct video_para *video = &hdmi->video;
1048 	struct audio_para *audio = &hdmi->audio;
1049 
1050 	n += sprintf(buf + n, "HDMI VIDEO PARA:\n");
1051 	n += sprintf(buf + n, "vic:%u  csc:%u is_hdmi:%u is_yuv:%u is_hcts:%d\n",
1052 		video->vic, video->csc, video->is_hdmi, video->is_yuv, video->is_hcts);
1053 	n += sprintf(buf + n, "pixel_clk:%u clk_div:%u pixel_repeat:%u\n",
1054 		video->pixel_clk, video->clk_div, video->pixel_repeat);
1055 	n += sprintf(buf + n, "x-y:%ux%u "
1056 		"htotal:%u hor_back_porch:%u hor_front_porch:%u hsync:%u "
1057 		"vtotal:%u ver_back_porch:%u ver_front_porch:%u vsync:%u "
1058 		"hpol:%u vpol:%u  interlace:%u\n",
1059 		video->x_res, video->y_res,
1060 		video->hor_total_time, video->hor_back_porch, video->hor_front_porch, video->hor_sync_time,
1061 		video->ver_total_time, video->ver_back_porch, video->ver_front_porch, video->ver_sync_time,
1062 		video->hor_sync_polarity, video->ver_sync_polarity, video->b_interlace);
1063 
1064 	n += sprintf(buf + n, "HDMI AUDIO PARA:\n");
1065 	n += sprintf(buf + n, "type:%u  chanel allocation:%u sample_rate:%u "
1066 		"sample_bit:%u  chanel_num:%u vic:%u\n",
1067 		audio->type, audio->ca, audio->sample_rate,
1068 		audio->sample_bit, audio->ch_num,
1069 		audio->vic);
1070 
1071 	return n;
1072 }
1073 
1074 static DEVICE_ATTR(source_para, 0660,
1075 		sunxi_hdmi_source_para_show, NULL);
1076 
1077 
sunxi_hdmi_hdcp_enable_show(struct device * dev,struct device_attribute * attr,char * buf)1078 static ssize_t sunxi_hdmi_hdcp_enable_show(struct device *dev,
1079 		struct device_attribute *attr, char *buf)
1080 {
1081 	ssize_t n = 0;
1082 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
1083 
1084 	n += sprintf(buf + n, "%d", hdmi->video.is_hcts);
1085 
1086 	return n;
1087 }
1088 
sunxi_hdmi_hdcp_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1089 static ssize_t sunxi_hdmi_hdcp_enable_store(struct device *dev,
1090 				struct device_attribute *attr,
1091 				const char *buf, size_t count)
1092 {
1093 	struct sunxi_hdmi *hdmi = sunxi_hdmi_get_hdmi();
1094 
1095 	if (count < 1)
1096 		return -EINVAL;
1097 
1098 	if (strncasecmp(buf, "on", 2) == 0 || strncasecmp(buf, "1", 1) == 0)
1099 		hdmi->video.is_hcts = 1;
1100 	else if (strncasecmp(buf, "off", 3) == 0 ||
1101 			strncasecmp(buf, "0", 1) == 0)
1102 		hdmi->video.is_hcts = 0;
1103 	else
1104 		return -EINVAL;
1105 
1106 	return count;
1107 }
1108 
1109 static DEVICE_ATTR(hdcp_enable, 0660,
1110 		sunxi_hdmi_hdcp_enable_show, sunxi_hdmi_hdcp_enable_store);
1111 
1112 static struct attribute *hdmi_attributes[] = {
1113 	&dev_attr_hdcp_enable.attr,
1114 	&dev_attr_source_para.attr,
1115 	&dev_attr_read.attr,
1116 	&dev_attr_write.attr,
1117 	NULL
1118 };
1119 
1120 static const struct sunxi_hdmi_funcs hdmi_funcs = {
1121 	.get_connect_status = sunxi_hdmi_get_connect_status,
1122 	.get_support_tv_mode = sunxi_hdmi_get_support_tv_mode,
1123 	.get_timing_from_tv_mode = sunxi_hdmi_get_timing_from_tv_mode,
1124 	.get_resolution_from_tv_mode = sunxi_hdmi_get_resolution_from_tv_mode,
1125 	.set_working_mode = sunxi_hdmi_set_working_mode,
1126 	.get_edid_block = sunxi_hdmi_get_edid_block,
1127 	//.mode_related_params_correct = sunxi_hdmi_mode_related_params_correct,
1128 	.mode_independent_params_correct = sunxi_hdmi_mode_independent_params_correct,
1129 	.enable = sunxi_hdmi_enable,
1130 	.sw_enable = sunxi_hdmi_sw_enable,
1131 	.disable = sunxi_hdmi_disable,
1132 };
1133 
sunxi_hdmi_para_init(struct sunxi_hdmi * hdmi)1134 static void sunxi_hdmi_para_init(struct sunxi_hdmi *hdmi)
1135 {
1136 	struct audio_para *audio = &hdmi->audio;
1137 	struct video_para *video = &hdmi->video;
1138 
1139 	video->vic = HDMI720P_50;
1140 	video->csc = BT601;
1141 	video->is_hdmi = 1;
1142 	video->is_yuv = 0;
1143 	video->is_hcts = 0;
1144 	audio->type = 1; /* default pcm */
1145 	audio->sample_rate = 44100;
1146 	audio->sample_bit = 16;
1147 	audio->ch_num = 2;
1148 	audio->ca = 0;
1149 }
1150 
sunxi_hdmi_clk_init(struct platform_device * pdev,struct sunxi_hdmi * hdmi)1151 static int sunxi_hdmi_clk_init(struct platform_device *pdev,
1152 				struct sunxi_hdmi *hdmi)
1153 {
1154 	int ret;
1155 
1156 	/* get hdmi main clk */
1157 	hdmi->mclk = of_clk_get(pdev->dev.of_node, 0);
1158 	if (IS_ERR(hdmi->mclk)) {
1159 		HDMI_ERR("fail to get clk for hdmi\n");
1160 		return -1;
1161 	}
1162 
1163 	hdmi->mclk_parent = clk_get_parent(hdmi->mclk);
1164 	if (IS_ERR(hdmi->mclk_parent)) {
1165 		HDMI_ERR("fail to get clk parent for hdmi\n");
1166 		return -1;
1167 	}
1168 
1169 	if (__clk_get_enable_count(hdmi->mclk) == 0) {
1170 		ret = clk_prepare_enable(hdmi->mclk);
1171 		if (ret < 0) {
1172 			HDMI_ERR("fail to enable hdmi mclk\n");
1173 			return -1;
1174 		}
1175 	}
1176 
1177 	/* get ddc clk for hdmi ddc function like edid reading
1178 	 * and hdcp authentication
1179 	 */
1180 	hdmi->ddc_clk = of_clk_get(pdev->dev.of_node, 1);
1181 	if (IS_ERR(hdmi->ddc_clk)) {
1182 		HDMI_ERR("fail to get clk for hdmi ddc\n");
1183 		return -1;
1184 	}
1185 
1186 	if (__clk_get_enable_count(hdmi->ddc_clk) == 0) {
1187 		ret = clk_prepare_enable(hdmi->ddc_clk);
1188 		if (ret < 0) {
1189 			HDMI_ERR("fail to enable hdmi ddc clk\n");
1190 			return -1;
1191 		}
1192 	}
1193 
1194 #if defined(CONFIG_ARCH_SUN8IW12)
1195 	/*get cec clk for hdmi cec function*/
1196 	hdmi->cec_clk = of_clk_get(pdev->dev.of_node, 2);
1197 	if (IS_ERR_OR_NULL(hdmi->cec_clk)) {
1198 		HDMI_ERR("fail to get hdmi_cec_clk\n");
1199 		goto HDMI_FREE;
1200 	}
1201 
1202 	if (__clk_get_enable_count(hdmi->cec_clk) == 0) {
1203 		ret = clk_prepare_enable(hdmi->cec_clk);
1204 		if (ret < 0) {
1205 			HDMI_ERR("fail to enable hdmi cec clk\n");
1206 			return -1;
1207 		}
1208 	}
1209 #endif
1210 	hdmi_clk_enable = true;
1211 
1212 	return 0;
1213 }
1214 
sunxi_hdmi_clk_exit(struct sunxi_hdmi * hdmi)1215 static int sunxi_hdmi_clk_exit(struct sunxi_hdmi *hdmi)
1216 {
1217 	return sunxi_hdmi_clk_disable(hdmi);
1218 }
1219 
hdmi_delay_us(unsigned long us)1220 static void hdmi_delay_us(unsigned long us)
1221 {
1222 	udelay(us);
1223 }
1224 
hdmi_delay_ms(unsigned long ms)1225 static void hdmi_delay_ms(unsigned long ms)
1226 {
1227 	mdelay(ms);
1228 }
1229 
sunxi_hdmi_core_init(struct sunxi_hdmi * hdmi)1230 static int sunxi_hdmi_core_init(struct sunxi_hdmi *hdmi)
1231 {
1232 	hdmi_bsp_func func;
1233 
1234 	sunxi_hdmi_para_init(hdmi);
1235 
1236 	bsp_hdmi_set_version(hdmi_get_soc_version());
1237 
1238 	func.delay_us = hdmi_delay_us;
1239 	func.delay_ms = hdmi_delay_ms;
1240 	bsp_hdmi_set_func(&func);
1241 
1242 	sunxi_hdmi_get_video_mode_info(&hdmi->video_info,
1243 				DISP_TV_MOD_720P_50HZ);
1244 #if defined(HDMI_USING_INNER_BIAS)
1245 	bsp_hdmi_set_bias_source(HDMI_USING_INNER_BIAS);
1246 #endif
1247 	bsp_hdmi_init();
1248 
1249 	hdmi->funcs = &hdmi_funcs;
1250 	return 0;
1251 }
1252 
sunxi_hdmi_probe(struct platform_device * pdev)1253 static int sunxi_hdmi_probe(struct platform_device *pdev)
1254 {
1255 	int ret = -1;
1256 	struct sunxi_hdmi *hdmi = NULL;
1257 
1258 	HDMI_INFO(" start\n");
1259 	hdmi = kmalloc(sizeof(struct sunxi_hdmi), GFP_KERNEL | __GFP_ZERO);
1260 	if (!hdmi) {
1261 		HDMI_ERR("Malloc sunxi_hdmi fail!\n");
1262 		goto OUT;
1263 	}
1264 
1265 	hwhdmi = hdmi;
1266 
1267 	hdmi->pdev = pdev;
1268 
1269 	/* iomap */
1270 	hdmi->reg_base = of_iomap(pdev->dev.of_node, 0);
1271 	if (hdmi->reg_base == 0) {
1272 		HDMI_ERR("unable to map hdmi registers\n");
1273 		ret = -EINVAL;
1274 		goto FREE_HDMI;
1275 	}
1276 	bsp_hdmi_set_addr((unsigned long)hdmi->reg_base);
1277 
1278 	ret = sunxi_hdmi_clk_init(pdev, hdmi);
1279 	if (ret < 0) {
1280 		HDMI_ERR("sunxi_hdmi_clk_init failed\n");
1281 		goto err_iomap;
1282 	}
1283 
1284 	/*set hdmi pin like ddc pin to active state*/
1285 	sunxi_drm_sys_pin_set_state("hdmi", HDMI_PIN_STATE_ACTIVE);
1286 
1287 	/*get hdmi power and enable it*/
1288 	if (of_property_read_string(pdev->dev.of_node, "hdmi_power",
1289 				    &hdmi->power))
1290 		HDMI_ERR("of_property_read_string hdmi_power failed!\n");
1291 	else
1292 		sunxi_drm_sys_power_enable(NULL, hdmi->power); /* fix me */
1293 
1294 	sunxi_hdmi_core_init(hdmi);
1295 
1296 	return 0;
1297 
1298 err_iomap:
1299 	if (hdmi->reg_base)
1300 		iounmap((char __iomem *)hdmi->reg_base);
1301 FREE_HDMI:
1302 	kfree(hdmi);
1303 OUT:
1304 	return ret;
1305 }
1306 
sunxi_hdmi_remove(struct platform_device * pdev)1307 static int sunxi_hdmi_remove(struct platform_device *pdev)
1308 {
1309 	struct sunxi_hdmi *hdmi = hwhdmi;
1310 
1311 	if (!hdmi) {
1312 		HDMI_ERR("Null pointer!\n");
1313 		return -1;
1314 	}
1315 
1316 	sunxi_hdmi_clk_exit(hdmi);
1317 	sunxi_drm_sys_power_disable(NULL, hdmi->power); /* fix me */
1318 	iounmap((char __iomem *)hdmi->reg_base);
1319 	kfree(hdmi);
1320 	return 0;
1321 }
1322 
1323 static const struct of_device_id sunxi_hdmi_match[] = {
1324 	{ .compatible = "allwinner,sunxi-hdmi", },
1325 
1326 	{},
1327 };
1328 
1329 struct platform_driver sunxi_hdmi_platform_driver = {
1330 	.probe = sunxi_hdmi_probe,
1331 	.remove = sunxi_hdmi_remove,
1332 	.driver = {
1333 		   .name = "hdmi",
1334 		   .owner = THIS_MODULE,
1335 		   .of_match_table = sunxi_hdmi_match,
1336 	},
1337 };
1338 
1339 static struct attribute_group hdmi_attribute_group = {
1340 	.name = "attr",
1341 	.attrs = hdmi_attributes,
1342 };
1343 
sunxi_hdmi_module_init(void)1344 int __init sunxi_hdmi_module_init(void)
1345 {
1346 	int ret = -1;
1347 
1348 	HDMI_INFO(" start\n");
1349 	hdmi_drv = kmalloc(sizeof(struct drv_model_info),
1350 				GFP_KERNEL | __GFP_ZERO);
1351 	if (!hdmi_drv) {
1352 		HDMI_ERR("Null drv_model_info pointer\n");
1353 		goto OUT;
1354 	}
1355 	ret = alloc_chrdev_region(&hdmi_drv->devid, 0, 1, "hdmi");
1356 	if (ret < 0) {
1357 		HDMI_ERR("alloc_chrdev_region failed\n");
1358 		goto FREE_DRV;
1359 	}
1360 
1361 	hdmi_drv->cdev = cdev_alloc();
1362 	if (!hdmi_drv->cdev) {
1363 		HDMI_ERR("cdev_alloc failed\n");
1364 		goto FREE_DRV;
1365 	}
1366 
1367 	cdev_init(hdmi_drv->cdev, NULL);
1368 	hdmi_drv->cdev->owner = THIS_MODULE;
1369 	ret = cdev_add(hdmi_drv->cdev, hdmi_drv->devid, 1);
1370 	if (ret) {
1371 		HDMI_ERR("cdev_add major number:%d failed\n",
1372 		       MAJOR(hdmi_drv->devid));
1373 		goto FREE_DRV;
1374 	}
1375 
1376 	hdmi_drv->sysclass = class_create(THIS_MODULE, "hdmi");
1377 	if (IS_ERR(hdmi_drv->sysclass)) {
1378 		HDMI_ERR("create class error\n");
1379 		goto FREE_DRV;
1380 	}
1381 
1382 	hdmi_drv->dev = device_create(hdmi_drv->sysclass, NULL,
1383 			hdmi_drv->devid, NULL, "hdmi");
1384 	if (!hdmi_drv->dev) {
1385 		HDMI_ERR("device_create failed\n");
1386 		goto FREE_DRV;
1387 	}
1388 
1389 	ret = platform_driver_register(&sunxi_hdmi_platform_driver);
1390 	if (ret) {
1391 		HDMI_ERR("platform_driver_register failed\n");
1392 		goto FREE_DEVICE;
1393 	}
1394 
1395 	ret = sysfs_create_group(&hdmi_drv->dev->kobj, &hdmi_attribute_group);
1396 	if (ret < 0) {
1397 		HDMI_ERR("sysfs_create_file fail!\n");
1398 		goto UNREGISTER;
1399 	}
1400 
1401 
1402 	HDMI_INFO(" end\n");
1403 	return ret;
1404 
1405 UNREGISTER:
1406 	platform_driver_unregister(&sunxi_hdmi_platform_driver);
1407 FREE_DEVICE:
1408 	device_destroy(hdmi_drv->sysclass, hdmi_drv->devid);
1409 FREE_DRV:
1410 	kfree(hdmi_drv);
1411 OUT:
1412 	HDMI_ERR(" failed\n");
1413 	return -EINVAL;
1414 }
1415 
sunxi_hdmi_module_exit(void)1416 void __exit sunxi_hdmi_module_exit(void)
1417 {
1418 	HDMI_INFO("\n");
1419 	if (hdmi_drv) {
1420 		platform_driver_unregister(&sunxi_hdmi_platform_driver);
1421 
1422 		device_destroy(hdmi_drv->sysclass, hdmi_drv->devid);
1423 		class_destroy(hdmi_drv->sysclass);
1424 
1425 		cdev_del(hdmi_drv->cdev);
1426 		kfree(hdmi_drv);
1427 	}
1428 }
1429