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