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_hdmi20.h"
16
17 static struct drv_model_info *hdmi20_drv;
18 static struct sunxi_hdmi *hwhdmi20;
19 static struct device_access reg_access;
20 struct system_functions low_functions;
21 u32 hdmi_printf;
22
23 #define DDC_PIN_STATE_ACTIVE "ddc_active"
24 #define DDC_PIN_STATE_SLEEP "ddc_sleep"
25 #define CEC_PIN_STATE_ACTIVE "cec_active"
26 #define CEC_PIN_STATE_SLEEP "cec_sleep"
27
28 #define ESM_REG_BASE_OFFSET 0x8000
29 #define HDCP22_FIRMWARE_SIZE (1024 * 256)
30 #define HDCP22_DATA_SIZE (1024 * 128)
31
sunxi_hdmi20_get_hdmi(void)32 static struct sunxi_hdmi *sunxi_hdmi20_get_hdmi(void)
33 {
34 if (hwhdmi20)
35 return hwhdmi20;
36 return NULL;
37 }
38
sunxi_hdmi_get_funcs(void)39 struct sunxi_hdmi_funcs *sunxi_hdmi_get_funcs(void)
40 {
41 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
42
43 return (struct sunxi_hdmi_funcs *)hdmi->funcs;
44 }
45
register_func_to_drm(struct hdmi_dev_func func)46 void register_func_to_drm(struct hdmi_dev_func func)
47 {
48 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
49
50 memcpy(&hdmi->dev_funcs, &func,
51 sizeof(struct hdmi_dev_func));
52 }
53
hdmi20_write(uintptr_t addr,u32 data)54 void hdmi20_write(uintptr_t addr, u32 data)
55 {
56 asm volatile("dsb st");
57 *((volatile u8 *)(hwhdmi20->reg_base + (addr >> 2))) = data;
58 }
59
hdmi20_read(uintptr_t addr)60 u32 hdmi20_read(uintptr_t addr)
61 {
62 return *((volatile u8 *)(hwhdmi20->reg_base + (addr >> 2)));
63 }
64
65 static int
sunxi_hdmi20_video_dts_parse(struct platform_device * pdev,struct sunxi_hdmi * hdmi)66 sunxi_hdmi20_video_dts_parse(struct platform_device *pdev,
67 struct sunxi_hdmi *hdmi)
68 {
69 struct sunxi_hdmi_work_mode *params = &hdmi->init_params;
70
71 if (of_property_read_u32(pdev->dev.of_node,
72 "dvi_hdmi", ¶ms->hdmi_mode)) {
73 HDMI_ERR("can NOT get dvi_hdmi\n");
74 return -1;
75 }
76
77 if (of_property_read_u32(pdev->dev.of_node,
78 "color_format", ¶ms->color_fmt)) {
79 HDMI_ERR("can NOT get color_format\n");
80 return -1;
81 }
82
83 if (of_property_read_u32(pdev->dev.of_node,
84 "color_depth", ¶ms->color_depth)) {
85 HDMI_ERR("can NOT get color_depth\n");
86 return -1;
87 }
88
89 if (of_property_read_u32(pdev->dev.of_node,
90 "color_space", ¶ms->color_space)) {
91 HDMI_ERR("can NOT get color_space\n");
92 return -1;
93 }
94
95 if (of_property_read_u32(pdev->dev.of_node,
96 "color_range", ¶ms->color_range)) {
97 HDMI_ERR("can NOT get color_range\n");
98 return -1;
99 }
100
101 if (of_property_read_u32(pdev->dev.of_node,
102 "eotf", ¶ms->eotf)) {
103 HDMI_ERR("can NOT get color_eotf\n");
104 return -1;
105 }
106
107 if (of_property_read_u32(pdev->dev.of_node,
108 "aspect_ratio", ¶ms->aspect_ratio)) {
109 HDMI_ERR("can NOT get aspect_ratio\n");
110 return -1;
111 }
112
113 return 0;
114 }
115
116 static int
sunxi_hdmi20_hdcp_dts_parse(struct platform_device * pdev,struct sunxi_hdmi * hdmi)117 sunxi_hdmi20_hdcp_dts_parse(struct platform_device *pdev,
118 struct sunxi_hdmi *hdmi)
119 {
120 struct device_node *esm_np;
121 u32 dts_esm_buff_phy_addr = 0, dts_esm_size_phy_addr = 0;
122 void *dts_esm_buff_vir_addr = NULL, *dts_esm_size_vir_addr = NULL;
123 u8 *esm_firm_vir_addr = NULL, *esm_data_vir_addr = NULL;
124
125 hdcpParams_t *hdcp = &hdmi->hdcp;
126
127 /*Parse if we use hdcp functions in hdmi driver*/
128 if (of_property_read_u32_array(pdev->dev.of_node,
129 "hdmi_hdcp_enable", (u32 *)&hdcp->use_hdcp, 1)) {
130 HDMI_INFO("WARN:can NOT get hdmi_hdcp_enable\n");
131 return 0;
132 }
133
134 if (hdcp->use_hdcp) {
135 DRM_INFO("NOT use hdcp\n");
136 return 0;
137 }
138
139 if (of_property_read_u32_array(pdev->dev.of_node,
140 "hdmi_hdcp22_enable", (u32 *)&hdcp->use_hdcp22, 1)) {
141 HDMI_INFO("WARN:can NOT get hdmi_hdcp22_enable\n");
142 return 0;
143 }
144
145 /*parse hdcp2.2*/
146 if (!hdcp->use_hdcp22) {
147 HDMI_INFO("NOT use hdcp2.2\n");
148 return 0;
149 }
150
151 /*allocate dma memory for esm as firmware storage ram and ram for running programs*/
152 esm_firm_vir_addr = dma_alloc_coherent(&pdev->dev,
153 HDCP22_FIRMWARE_SIZE, &hdcp->esm_firm_phy_addr,
154 GFP_KERNEL | __GFP_ZERO);
155 if (!esm_firm_vir_addr) {
156 HDMI_ERR("dma_alloc_coherent for esm firmware failed\n");
157 goto failed;
158 }
159
160 hdcp->esm_firm_vir_addr = (unsigned long)esm_firm_vir_addr;
161 hdcp->esm_firm_size = HDCP22_FIRMWARE_SIZE;
162
163 esm_data_vir_addr = dma_alloc_coherent(&pdev->dev,
164 HDCP22_FIRMWARE_SIZE, &hdcp->esm_data_phy_addr,
165 GFP_KERNEL | __GFP_ZERO);
166 if (!esm_firm_vir_addr) {
167 HDMI_ERR("dma_alloc_coherent for esm firmware failed\n");
168 goto failed;
169 }
170 hdcp->esm_data_vir_addr = (unsigned long)esm_data_vir_addr;
171 hdcp->esm_data_size = HDCP22_DATA_SIZE;
172
173 /*parse esm*/
174 esm_np = of_find_node_by_name(NULL, "esm");
175 if (!esm_np) {
176 HDMI_ERR("can NOT get esm device node\n");
177 goto failed;
178 }
179
180 /*obtain esm firmware size*/
181 /*get physical address of esm firmware size*/
182 if (of_property_read_u32_array(esm_np,
183 "esm_img_size_addr",
184 &dts_esm_size_phy_addr,
185 1) && !dts_esm_size_phy_addr) {
186 HDMI_ERR("read esm_img_size_addr form esm node failed\n");
187 goto failed;
188 }
189 /*get esm firmware size*/
190 dts_esm_size_vir_addr = __va(dts_esm_size_phy_addr);
191 memcpy((void *)(&hdcp->esm_firm_size), dts_esm_size_vir_addr, 4);
192
193 /*obtain esm firmware*/
194 /*get physical address of esm firmware*/
195 if (of_property_read_u32_array(esm_np,
196 "esm_img_buff_addr",
197 &dts_esm_buff_phy_addr,
198 1) && !dts_esm_buff_phy_addr) {
199 HDMI_ERR("read esm_img_buff_addr form esm node failed\n");
200 goto failed;
201 }
202 /*get esm firmware*/
203 dts_esm_buff_vir_addr = __va(dts_esm_buff_phy_addr);
204 if (hdcp->esm_firm_size <= HDCP22_FIRMWARE_SIZE) {
205 memcpy(esm_firm_vir_addr, dts_esm_buff_vir_addr,
206 hdcp->esm_firm_size);
207 return 0;
208 }
209 HDMI_ERR("get esm firmware failed\n");
210
211 failed:
212 if (esm_firm_vir_addr)
213 dma_free_coherent(&pdev->dev, HDCP22_FIRMWARE_SIZE,
214 esm_firm_vir_addr, hdcp->esm_firm_phy_addr);
215 if (esm_data_vir_addr)
216 dma_free_coherent(&pdev->dev, HDCP22_DATA_SIZE,
217 esm_data_vir_addr, hdcp->esm_data_phy_addr);
218 return -1;
219 }
220
221
222
223 static int
sunxi_hdmi20_cec_dts_parse(struct platform_device * pdev,struct sunxi_hdmi * hdmi)224 sunxi_hdmi20_cec_dts_parse(struct platform_device *pdev,
225 struct sunxi_hdmi *hdmi)
226 {
227 struct cec_params *cec = &hdmi->cec;
228
229 /*get cec config*/
230 if (of_property_read_u32(pdev->dev.of_node,
231 "hdmi_cec_support",
232 &cec->support)) {
233 HDMI_INFO("WARN:can NOT get hdmi_cec_support\n");
234 return 0;
235 }
236
237 if (!cec->support) {
238 DRM_INFO("WARN:NOT support cec\n");
239 return 0;
240 }
241
242 if (of_property_read_u32(pdev->dev.of_node,
243 "hdmi_cec_super_standby",
244 &cec->support_super_standby)) {
245 HDMI_INFO("WARN:can NOT get hdmi_cec_super_standby\n");
246 return 0;
247 }
248
249 return 0;
250 }
251
sunxi_hdmi20_hdcp_init(void)252 static int sunxi_hdmi20_hdcp_init(void)
253 {
254 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
255 hdcpParams_t *hdcp = &hdmi->hdcp;
256
257 if (!hdcp->use_hdcp)
258 return 0;
259
260 if (!hdcp->use_hdcp22)
261 return 0;
262
263 hdcp->hdcp_on = 0;
264 hdcp->mEnable11Feature = -1;
265 hdcp->mRiCheck = -1;
266 hdcp->mI2cFastMode = -1;
267 hdcp->mEnhancedLinkVerification = -1;
268 hdcp->maxDevices = 0;
269 hdcp->mKsvListBuffer = NULL;
270 hdcp->mAksv = NULL;
271 hdcp->mKeys = NULL;
272 hdcp->mSwEncKey = NULL;
273
274 hdcp->esm_hpi_base = (unsigned long)hdmi->reg_base
275 + ESM_REG_BASE_OFFSET;
276 return 0;
277 }
278
sunxi_hdmi20_audio_init(void)279 static int sunxi_hdmi20_audio_init(void)
280 {
281 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
282 audioParams_t *audio = &hdmi->audio;
283
284 audio->mInterfaceType = I2S;
285 audio->mCodingType = PCM;
286 audio->mSamplingFrequency = 44100;
287 audio->mChannelAllocation = 0;
288 audio->mChannelNum = 2;
289 audio->mSampleSize = 16;
290 audio->mClockFsFactor = 64;
291 audio->mPacketType = PACKET_NOT_DEFINED;
292 audio->mDmaBeatIncrement = DMA_NOT_DEFINED;
293
294 return 0;
295 }
296
297 static bool hdmi20_clk_enable;
sunxi_hdmi20_clk_enable(struct sunxi_hdmi * hdmi)298 int sunxi_hdmi20_clk_enable(struct sunxi_hdmi *hdmi)
299 {
300 int ret;
301 unsigned long tcon_tv_rate;
302 struct clk *tcon_tv_clk;
303
304 tcon_tv_clk = clk_get(NULL, "tcon_tv");
305 tcon_tv_rate = clk_get_rate(tcon_tv_clk);
306 clk_set_rate(hdmi->mclk, tcon_tv_rate);
307
308 if (hdmi20_clk_enable)
309 return 0;
310 hdmi20_clk_enable = true;
311
312 ret = clk_prepare_enable(hdmi->mclk);
313 if (ret < 0) {
314 HDMI_ERR("fail to enable hdmi mclk\n");
315 return -1;
316 }
317
318 ret = clk_prepare_enable(hdmi->ddc_clk);
319 if (ret < 0) {
320 HDMI_ERR("fail to enable hdmi ddc clk\n");
321 return -1;
322 }
323
324 if (hdmi->hdcp.use_hdcp) {
325 ret = clk_prepare_enable(hdmi->hdcp_clk);
326 if (ret < 0) {
327 HDMI_ERR("fail to enable hdmi hdcp clk\n");
328 return -1;
329 }
330 }
331
332 if (hdmi->cec.support) {
333 ret = clk_prepare_enable(hdmi->cec_clk);
334 if (ret < 0) {
335 HDMI_ERR("fail to enable hdmi cec clk\n");
336 return -1;
337 }
338 }
339
340 return 0;
341 }
342
sunxi_hdmi20_clk_disable(struct sunxi_hdmi * hdmi)343 static int sunxi_hdmi20_clk_disable(struct sunxi_hdmi *hdmi)
344 {
345 if (!hdmi20_clk_enable)
346 return 0;
347 hdmi20_clk_enable = false;
348
349 if (__clk_get_enable_count(hdmi->mclk))
350 clk_disable_unprepare(hdmi->mclk);
351
352 if (__clk_get_enable_count(hdmi->ddc_clk))
353 clk_disable_unprepare(hdmi->ddc_clk);
354
355 if (__clk_get_enable_count(hdmi->hdcp_clk))
356 clk_disable_unprepare(hdmi->hdcp_clk);
357
358 if (__clk_get_enable_count(hdmi->cec_clk))
359 clk_disable_unprepare(hdmi->cec_clk);
360
361 return 0;
362 }
363
sunxi_hdmi20_get_dtd(dtd_t * dtd,struct disp_video_timings * timing)364 static void sunxi_hdmi20_get_dtd(dtd_t *dtd,
365 struct disp_video_timings *timing)
366 {
367 dtd->mPixelRepetitionInput = timing->pixel_repeat;
368 dtd->mInterlaced = timing->b_interlace;
369
370 dtd->mCode = timing->vic;
371 dtd->mPixelClock = timing->pixel_clk * (timing->pixel_repeat + 1)
372 * (timing->b_interlace + 1) / 1000;
373
374 dtd->mHActive = timing->x_res * (timing->pixel_repeat + 1);
375 dtd->mHBlanking = (timing->hor_total_time- timing->x_res) * (timing->pixel_repeat + 1);
376 dtd->mHSyncOffset = timing->hor_front_porch * (timing->pixel_repeat + 1);
377 dtd->mHSyncPulseWidth = timing->hor_sync_time * (timing->pixel_repeat + 1);
378
379 dtd->mVActive = timing->y_res / (timing->b_interlace + 1);
380 dtd->mVBlanking = timing->ver_total_time- timing->y_res;
381 dtd->mVSyncOffset = timing->ver_front_porch;
382 dtd->mVSyncPulseWidth = timing->ver_sync_time;
383
384 dtd->mHSyncPolarity = timing->hor_sync_polarity;
385 dtd->mVSyncPolarity = timing->ver_sync_polarity;
386
387 DRM_INFO("dtd: vsync:%d hsync:%d timing: vysnc:%d hsync:%d\n",
388 dtd->mVSyncPolarity, dtd->mHSyncPolarity, timing->ver_sync_polarity, timing->hor_sync_polarity);
389 }
390
sunxi_hdmi20_fill_params(struct sunxi_hdmi * hdmi,struct disp_video_timings * timing)391 static int sunxi_hdmi20_fill_params(struct sunxi_hdmi *hdmi,
392 struct disp_video_timings *timing)
393 {
394 videoParams_t *video = &hdmi->video;
395 productParams_t *product = &hdmi->product;
396 dtd_t *dtd = &video->mDtd;
397 sink_edid_t *sink = &hdmi->sink_caps;
398
399 /*get dertailed timings from vic*/
400 sunxi_hdmi20_get_dtd(dtd, timing);
401
402 video->mCea_code = 0;
403 video->mHdmi_code = 0;
404
405 /*hdmi vic or cea vic for 4k*/
406 if ((timing->x_res == 3840 && timing->y_res == 2160)
407 || (timing->x_res == 4096 && timing->y_res == 2160)) {
408 if ((timing->vic <= 4) && (timing->vic >= 1)) {
409 video->mCea_code = 0;
410 video->mHdmi_code = timing->vic;
411 } else {
412 video->mCea_code = timing->vic;
413 video->mHdmi_code = 0;
414 }
415 } else {
416 video->mCea_code = timing->vic;
417 video->mHdmi_code = 0;
418 }
419
420 /*if hdmi sink support hdmi2.0*/
421 video->mHdmi20 = sink->edid_m20Sink;
422 video->scdc_ability = sink->edid_mHdmiForumvsdb.mSCDC_Present;
423
424 if (video->mHdmi_code) {
425 product->mVendorPayload[0] = 0x20;
426 product->mVendorPayload[1] = video->mHdmi_code;
427 product->mVendorPayload[2] = 0;
428 product->mVendorPayload[3] = 0;
429 product->mVendorPayloadLength = 4;
430 } else if (video->mCea_code) {
431 product->mVendorPayload[0] = 0;
432 product->mVendorPayload[1] = 0;
433 product->mVendorPayload[2] = 0;
434 product->mVendorPayload[3] = 0;
435 product->mVendorPayloadLength = 4;
436 }
437
438 /*set vendor speciffic info frame: IEEE codes and payload*/
439 /*hdmi20 video format: 4k50/4k60*/
440 if (video->mCea_code == 96 || video->mCea_code == 97
441 || video->mCea_code == 101 || video->mCea_code == 102) {
442 product->mOUI = 0xc45dd8;
443
444 product->mVendorPayload[0] = 0x01;
445 product->mVendorPayload[1] = 0;
446 product->mVendorPayload[2] = 0;
447 product->mVendorPayload[3] = 0;
448 product->mVendorPayloadLength = 4;
449 } else
450 product->mOUI = 0x000c03;
451
452 /*set info frame for 3d*/
453 if (timing->b_interlace) {
454 video->mHdmiVideoFormat = 0x02;
455 video->m3dStructure = 0;
456 } else if (video->mHdmi_code) {
457 video->mHdmiVideoFormat = 0x01;
458 video->m3dStructure = 0;
459 } else {
460 video->mHdmiVideoFormat = 0x0;
461 video->m3dStructure = 0;
462 }
463
464 return 0;
465 }
466
sunxi_hdmi20_get_connect_status(void)467 static int sunxi_hdmi20_get_connect_status(void)
468 {
469 int status, time_out = 5;
470 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
471 struct hdmi_dev_func *dev_funcs = &hdmi->dev_funcs;
472
473 /* read hdmi connected status with anti-shake check */
474 /* the connected status should remain unchanged for 20*5 ms */
475 status = dev_funcs->dev_hpd_status();
476 while (time_out) {
477 msleep(20);
478 if (status == dev_funcs->dev_hpd_status())
479 --time_out;
480 else {
481 time_out = 5;
482 status = dev_funcs->dev_hpd_status();
483 }
484 }
485
486 return status;
487 }
488
489 static void
sunxi_hdmi20_get_working_mode(struct sunxi_hdmi_work_mode * work_mode)490 sunxi_hdmi20_get_working_mode(struct sunxi_hdmi_work_mode *work_mode)
491 {
492 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
493 videoParams_t *video = &hdmi->video;
494
495 if (video->mHdmi == MODE_UNDEFINED
496 || video->mHdmi == DVI)
497 work_mode->hdmi_mode = DISP_DVI;
498 else if (video->mHdmi == HDMI)
499 work_mode->hdmi_mode = DISP_HDMI;
500
501 if (video->mEncodingIn == ENC_UNDEFINED
502 || video->mEncodingIn == RGB)
503 work_mode->color_fmt = DISP_CSC_TYPE_RGB;
504 else if (video->mEncodingIn == YCC444)
505 work_mode->color_fmt = DISP_CSC_TYPE_YUV444;
506 else if (video->mEncodingIn == YCC422)
507 work_mode->color_fmt = DISP_CSC_TYPE_YUV422;
508 else if (video->mEncodingIn == YCC420)
509 work_mode->color_fmt = DISP_CSC_TYPE_YUV420;
510
511
512 if (video->mColorResolution == COLOR_DEPTH_INVALID
513 || video->mColorResolution == COLOR_DEPTH_8)
514 work_mode->color_depth = DISP_DATA_8BITS;
515 else if (video->mColorResolution == COLOR_DEPTH_10)
516 work_mode->color_depth = DISP_DATA_10BITS;
517 else if (video->mColorResolution == COLOR_DEPTH_12)
518 work_mode->color_depth = DISP_DATA_12BITS;
519 else if (video->mColorResolution == COLOR_DEPTH_16)
520 work_mode->color_depth = DISP_DATA_16BITS;
521
522 if (video->mColorimetry == ITU601)
523 work_mode->color_space = DISP_BT601;
524 else if (video->mColorimetry == ITU709)
525 work_mode->color_space = DISP_BT709;
526 else if (video->mColorimetry == EXTENDED_COLORIMETRY
527 && video->mExtColorimetry == BT2020_Y_CB_CR)
528 work_mode->color_space = DISP_BT2020NC;
529
530 if (video->pb->eotf == SDR_LUMINANCE_RANGE)
531 work_mode->eotf = DISP_EOTF_GAMMA22;
532 else if (video->pb->eotf == HDR_LUMINANCE_RANGE)
533 work_mode->eotf = DISP_EOTF_SMPTE2084;
534 else if (video->pb->eotf == HLG)
535 work_mode->eotf = DISP_EOTF_ARIB_STD_B67;
536
537 if (video->mRgbQuantizationRange == 0)
538 work_mode->color_range = DISP_COLOR_RANGE_DEFAULT;
539 else if (video->mRgbQuantizationRange == 2)
540 work_mode->color_range = DISP_COLOR_RANGE_0_255;
541 else if (video->mRgbQuantizationRange == 1)
542 work_mode->color_range = DISP_COLOR_RANGE_16_235;
543
544 work_mode->aspect_ratio = video->mActiveFormatAspectRatio;
545 }
546
547 static int
sunxi_hdmi20_set_working_mode(struct sunxi_hdmi_work_mode * work_mode)548 sunxi_hdmi20_set_working_mode(struct sunxi_hdmi_work_mode *work_mode)
549 {
550 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
551 videoParams_t *video = &hdmi->video;
552
553 video->mHdmi = (work_mode->hdmi_mode == DISP_HDMI) ?
554 HDMI : DVI;
555
556 if (work_mode->color_fmt == DISP_CSC_TYPE_RGB) {
557 video->mEncodingIn = RGB;
558 video->mEncodingOut = RGB;
559 } else if (work_mode->color_fmt == DISP_CSC_TYPE_YUV444) {
560 video->mEncodingIn = YCC444;
561 video->mEncodingOut = YCC444;
562 } else if (work_mode->color_fmt == DISP_CSC_TYPE_YUV422) {
563 video->mEncodingIn = YCC422;
564 video->mEncodingOut = YCC422;
565 } else if (work_mode->color_fmt == DISP_CSC_TYPE_YUV420) {
566 video->mEncodingIn = YCC420;
567 video->mEncodingOut = YCC420;
568 }
569
570 if (work_mode->color_depth == DISP_DATA_8BITS)
571 video->mColorResolution = COLOR_DEPTH_8;
572 else if (work_mode->color_depth == DISP_DATA_10BITS)
573 video->mColorResolution = COLOR_DEPTH_10;
574 else if (work_mode->color_depth == DISP_DATA_12BITS)
575 video->mColorResolution = COLOR_DEPTH_12;
576 else if (work_mode->color_depth == DISP_DATA_16BITS)
577 video->mColorResolution = COLOR_DEPTH_16;
578
579 if (work_mode->color_space == DISP_BT601)
580 video->mColorimetry = ITU601;
581 else if (work_mode->color_space == DISP_BT709)
582 video->mColorimetry = ITU709;
583 else if (work_mode->color_space == DISP_BT2020NC) {
584 video->mColorimetry = EXTENDED_COLORIMETRY;
585 video->mExtColorimetry = BT2020_Y_CB_CR;
586 } else {
587 video->mColorimetry = ITU709;
588 }
589
590 if (work_mode->eotf == DISP_EOTF_GAMMA22)
591 video->pb->eotf = SDR_LUMINANCE_RANGE;
592 else if (work_mode->eotf == DISP_EOTF_SMPTE2084)
593 video->pb->eotf = HDR_LUMINANCE_RANGE;
594 else if (work_mode->eotf == DISP_EOTF_ARIB_STD_B67)
595 video->pb->eotf = HLG;
596 else
597 video->pb->eotf = SDR_LUMINANCE_RANGE;
598
599 video->mRgbQuantizationRange = work_mode->color_range;
600 video->mActiveFormatAspectRatio = work_mode->aspect_ratio;
601
602 return 0;
603 }
604
sunxi_hdmi20_get_edid_block(void * data,unsigned char * buf,unsigned int block,size_t len)605 static int sunxi_hdmi20_get_edid_block(void *data, unsigned char *buf,
606 unsigned int block, size_t len)
607 {
608 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
609
610 return hdmi->dev_funcs.get_edid_block(buf, block, len);
611 }
612
sunxi_hdmi20_get_sink_caps(void)613 static sink_edid_t *sunxi_hdmi20_get_sink_caps(void)
614 {
615 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
616
617 return &hdmi->sink_caps;
618 }
619
sunxi_hdmi20_get_init_params(void)620 static struct sunxi_hdmi_work_mode *sunxi_hdmi20_get_init_params(void)
621 {
622 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
623
624 return &hdmi->init_params;
625 }
626
hdmi20_dump_video_para(videoParams_t * para)627 static void hdmi20_dump_video_para(videoParams_t *para)
628 {
629 DRM_INFO("hdmi mode:%d cea_code:%d hdmi_code:%d\n",
630 para->mHdmi, para->mCea_code, para->mHdmi_code);
631 DRM_INFO("format in:%d out:%d\n", para->mEncodingOut, para->mEncodingIn);
632 DRM_INFO("depth:%d\n", para->mColorResolution);
633 DRM_INFO("pixel_repeat:%d\n", para->mPixelRepetitionFactor);
634 DRM_INFO("mColorimetry:%d\n", para->mColorimetry);
635 DRM_INFO("mHdmiVideoFormat:%d\n", para->mHdmiVideoFormat);
636 DRM_INFO("m3dStructure:%d\n", para->m3dStructure);
637 DRM_INFO("mHdmiVic:%d mHdmi20:%d scdc_ability:%d\n",
638 para->mHdmiVic, para->mHdmi20, para->scdc_ability);
639 DRM_INFO("mActiveFormatAspectRatio:%d\n", para->mActiveFormatAspectRatio);
640 DRM_INFO("mRgbQuantizationRange:%d\n", para->mRgbQuantizationRange);
641 }
642
643 static int
sunxi_hdmi20_enable(struct disp_video_timings * timing)644 sunxi_hdmi20_enable(struct disp_video_timings *timing)
645 {
646 int ret;
647 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
648 struct hdmi_dev_func *dev_funcs = &hdmi->dev_funcs;
649
650 ret = sunxi_hdmi20_fill_params(hdmi, timing);
651 if (ret < 0) {
652 HDMI_ERR("sunxi_hdmi20_fill_params failed\n");
653 return ret;
654 }
655
656 hdmi20_dump_video_para(&hdmi->video);
657 ret = dev_funcs->main_config(&hdmi->video, &hdmi->audio,
658 &hdmi->product, &hdmi->hdcp, 301);
659 if (ret < 0) {
660 HDMI_ERR("hdmi main_config failed!\n");
661 return ret;
662 }
663
664 return 0;
665 }
666
667 static int
sunxi_hdmi20_sw_enable(struct disp_video_timings * timing)668 sunxi_hdmi20_sw_enable(struct disp_video_timings *timing)
669 {
670 return 0;
671 }
672
sunxi_hdmi20_disable(void)673 static void sunxi_hdmi20_disable(void)
674 {
675 struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
676 struct hdmi_dev_func *dev_funcs = &hdmi->dev_funcs;
677
678 dev_funcs->avmute_enable(1);
679 dev_funcs->device_close();
680
681 sunxi_hdmi20_clk_disable(hdmi);
682 msleep(5);
683 sunxi_hdmi20_clk_enable(hdmi);
684 dev_funcs->hpd_enable(1);
685 }
686
687 static const struct sunxi_hdmi_funcs hdmi20_funcs = {
688 .get_init_params = sunxi_hdmi20_get_init_params,
689 .get_connect_status = sunxi_hdmi20_get_connect_status,
690
691 .set_working_mode = sunxi_hdmi20_set_working_mode,
692 .get_working_mode = sunxi_hdmi20_get_working_mode,
693
694 .get_edid_block = sunxi_hdmi20_get_edid_block,
695 .get_sink_caps = sunxi_hdmi20_get_sink_caps,
696
697 .enable = sunxi_hdmi20_enable,
698 .sw_enable = sunxi_hdmi20_sw_enable,
699 .disable = sunxi_hdmi20_disable,
700 };
701
sunxi_hdmi20_power_init(struct platform_device * pdev,struct sunxi_hdmi * hdmi)702 static int sunxi_hdmi20_power_init(struct platform_device *pdev,
703 struct sunxi_hdmi *hdmi)
704 {
705 int ret = 0, i;
706 char power_name[20];
707
708 if (of_property_read_u32(pdev->dev.of_node,
709 "hdmi_power_cnt",
710 &hdmi->power_count)) {
711 pr_err("ERROR: can not get hdmi_power_cnt\n");
712 return -1;
713 }
714
715 for (i = 0; i < hdmi->power_count; i++) {
716 const char *hdmi_power;
717
718 sprintf(power_name, "hdmi_power%d", i);
719 if (of_property_read_string(pdev->dev.of_node,
720 power_name, &hdmi_power)) {
721 pr_err("Error: get %s failed\n", power_name);
722 ret = -1;
723 } else {
724 DRM_INFO("Get hdmi_power%d:%s\n", i, hdmi_power);
725 memcpy((void *)hdmi->power[i], hdmi_power,
726 strlen(hdmi_power) + 1);
727 sunxi_drm_sys_power_enable(NULL, hdmi->power[i]); /* fix me */
728 }
729 }
730
731 return 0;
732 }
733
sunxi_hdmi20_clk_init(struct platform_device * pdev,struct sunxi_hdmi * hdmi)734 static int sunxi_hdmi20_clk_init(struct platform_device *pdev,
735 struct sunxi_hdmi *hdmi)
736 {
737 int ret;
738 int index = 0;
739
740 /* get hdmi main clk */
741 hdmi->mclk = of_clk_get(pdev->dev.of_node, index);
742 if (IS_ERR(hdmi->mclk)) {
743 HDMI_ERR("fail to get clk for hdmi\n");
744 return -1;
745 }
746
747 hdmi->mclk_parent = clk_get_parent(hdmi->mclk);
748 if (IS_ERR(hdmi->mclk_parent)) {
749 HDMI_ERR("fail to get clk parent for hdmi\n");
750 return -1;
751 }
752
753 if (__clk_get_enable_count(hdmi->mclk) == 0) {
754 ret = clk_prepare_enable(hdmi->mclk);
755 if (ret < 0) {
756 HDMI_ERR("fail to enable hdmi mclk\n");
757 return -1;
758 }
759 }
760
761 index++;
762 /* get ddc clk for hdmi ddc function like edid reading
763 * and hdcp authentication
764 */
765 hdmi->ddc_clk = of_clk_get(pdev->dev.of_node, index);
766 if (IS_ERR(hdmi->ddc_clk)) {
767 HDMI_ERR("fail to get clk for hdmi ddc\n");
768 return -1;
769 }
770
771 if (__clk_get_enable_count(hdmi->ddc_clk) == 0) {
772 ret = clk_prepare_enable(hdmi->ddc_clk);
773 if (ret < 0) {
774 HDMI_ERR("fail to enable hdmi ddc clk\n");
775 return -1;
776 }
777 }
778
779 index++;
780 /*get hdcp clk for hdmi hdcp2.2 function*/
781 hdmi->hdcp_clk = of_clk_get(pdev->dev.of_node, index);
782 if (IS_ERR_OR_NULL(hdmi->hdcp_clk)) {
783 HDMI_ERR("fail to get hdmi_cec_clk\n");
784 //return -1;
785 }
786
787 if (hdmi->hdcp.use_hdcp
788 && __clk_get_enable_count(hdmi->hdcp_clk) == 0) {
789 ret = clk_prepare_enable(hdmi->hdcp_clk);
790 if (ret < 0) {
791 HDMI_ERR("fail to enable hdmi hdcp clk\n");
792 //return -1;
793 }
794 }
795
796 index++;
797 /*get cec clk for hdmi cec function*/
798 hdmi->cec_clk = of_clk_get(pdev->dev.of_node, index);
799 if (IS_ERR_OR_NULL(hdmi->cec_clk)) {
800 HDMI_ERR("fail to get hdmi_cec_clk\n");
801 //return -1;
802 }
803
804 if (hdmi->cec.support
805 && __clk_get_enable_count(hdmi->cec_clk) == 0) {
806 ret = clk_prepare_enable(hdmi->cec_clk);
807 if (ret < 0) {
808 HDMI_ERR("fail to enable hdmi cec clk\n");
809 //return -1;
810 }
811 }
812
813 return 0;
814 }
815
sunxi_hdmi20_clk_exit(struct sunxi_hdmi * hdmi)816 static int sunxi_hdmi20_clk_exit(struct sunxi_hdmi *hdmi)
817 {
818 return sunxi_hdmi20_clk_disable(hdmi);
819 }
820
sunxi_hdmi20_pin_active(void)821 static int sunxi_hdmi20_pin_active(void)
822 {
823 /*set hdmi pin like ddc pin to active state*/
824 sunxi_drm_sys_pin_set_state("hdmi", DDC_PIN_STATE_ACTIVE);
825 /*set hdmi pin like ddc pin to active state*/
826 sunxi_drm_sys_pin_set_state("hdmi", CEC_PIN_STATE_ACTIVE);
827
828 return 0;
829 }
830
sunxi_hdmi20_pin_sleep(void)831 int sunxi_hdmi20_pin_sleep(void)
832 {
833 /*set hdmi pin like ddc pin to sleep state*/
834 sunxi_drm_sys_pin_set_state("hdmi", DDC_PIN_STATE_SLEEP);
835 /*set hdmi pin like ddc pin to sleep state*/
836 sunxi_drm_sys_pin_set_state("hdmi", CEC_PIN_STATE_SLEEP);
837
838 return 0;
839 }
840
hdmi_debug_show(struct device * dev,struct device_attribute * attr,char * buf)841 static ssize_t hdmi_debug_show(struct device *dev,
842 struct device_attribute *attr,
843 char *buf)
844 {
845 ssize_t n = 0;
846
847 n += sprintf(buf + n, "Current debug=%d\n\n", hdmi_printf);
848
849 n += sprintf(buf + n, "hdmi log debug level:\n");
850 n += sprintf(buf + n, "debug = 1, print video log\n");
851 n += sprintf(buf + n, "debug = 2, print edid log\n");
852 n += sprintf(buf + n, "debug = 3, print audio log\n");
853 n += sprintf(buf + n, "debug = 4, print video+edid+audio log\n");
854 n += sprintf(buf + n, "debug = 5, print cec log\n");
855 n += sprintf(buf + n, "debug = 6, print hdcp log\n");
856 n += sprintf(buf + n, "debug = 7, print all of the logs above\n");
857 n += sprintf(buf + n, "debug = 8, print all of the logs above and trace log\n");
858
859 return n;
860 }
861
hdmi_debug_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)862 static ssize_t hdmi_debug_store(struct device *dev,
863 struct device_attribute *attr,
864 const char *buf, size_t count)
865 {
866 if (count < 1)
867 return -EINVAL;
868
869 if (strncmp(buf, "9", 1) == 0)
870 hdmi_printf = 9;
871 else if (strncmp(buf, "8", 1) == 0)
872 hdmi_printf = 8;
873 else if (strncmp(buf, "7", 1) == 0)
874 hdmi_printf = 7;
875 else if (strncmp(buf, "6", 1) == 0)
876 hdmi_printf = 6;
877 else if (strncmp(buf, "5", 1) == 0)
878 hdmi_printf = 5;
879 else if (strncmp(buf, "4", 1) == 0)
880 hdmi_printf = 4;
881 else if (strncmp(buf, "3", 1) == 0)
882 hdmi_printf = 3;
883 else if (strncmp(buf, "2", 1) == 0)
884 hdmi_printf = 2;
885 else if (strncmp(buf, "1", 1) == 0)
886 hdmi_printf = 1;
887 else if (strncmp(buf, "0", 1) == 0)
888 hdmi_printf = 0;
889 else
890 pr_err("Error Input!\n");
891
892 pr_info("debug=%d\n", hdmi_printf);
893
894 return count;
895 }
896
897 static DEVICE_ATTR(debug, 0664, hdmi_debug_show, hdmi_debug_store);
898
899 static unsigned int reg_read_start, reg_read_end, reg_read_cmd;
sunxi_hdmi20_read_show(struct device * dev,struct device_attribute * attr,char * buf)900 static ssize_t sunxi_hdmi20_read_show(struct device *dev,
901 struct device_attribute *attr, char *buf)
902 {
903 ssize_t n = 0;
904 unsigned int reg;
905
906 if (!reg_read_cmd) {
907 n += sprintf(buf + n, "read hdmi register, Usage:\n");
908 n += sprintf(buf + n, "echo [reg_offset_start] [reg_offset_end] > read\n");
909 n += sprintf(buf + n, "OR:echo [reg_offset_start],[reg_offset_end] > read\n");
910 return n;
911 }
912
913 for (reg = reg_read_start; reg <= reg_read_end; reg++) {
914 if (reg % 16 == 0) {
915 n += sprintf(buf + n, "\n");
916 n += sprintf(buf + n, "0x%x: ", reg);
917 }
918
919 n += sprintf(buf + n, "0x%02x ", hdmi20_read(reg << 2));
920 }
921
922 n += sprintf(buf + n, "\n");
923
924 reg_read_cmd = 0;
925
926 return n;
927 }
928
sunxi_hdmi20_read_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)929 static ssize_t sunxi_hdmi20_read_store(struct device *dev,
930 struct device_attribute *attr,
931 const char *buf, size_t count)
932 {
933 char *end;
934
935 reg_read_start = (unsigned int)simple_strtoull(buf, &end, 0);
936
937 if ((*end != ' ') && (*end != ',')) {
938 HDMI_ERR("error separator:%c\n", *end);
939 return count;
940 }
941
942 reg_read_end = (unsigned int)simple_strtoull(end + 1, &end, 0);
943
944 reg_read_cmd = 1;
945
946 return count;
947 }
948
949 static DEVICE_ATTR(read, 0660,
950 sunxi_hdmi20_read_show, sunxi_hdmi20_read_store);
951
952
sunxi_hdmi20_write_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)953 static ssize_t sunxi_hdmi20_write_store(struct device *dev,
954 struct device_attribute *attr,
955 const char *buf, size_t count)
956 {
957 char *end;
958 unsigned int reg_addr;
959 unsigned char value;
960
961 reg_addr = (unsigned int)simple_strtoull(buf, &end, 0);
962
963 if ((*end != ' ') && (*end != ',')) {
964 HDMI_ERR("error separator:%c\n", *end);
965 return count;
966 }
967
968 value = (unsigned char)simple_strtoull(end + 1, &end, 0);
969
970 hdmi20_write(reg_addr << 2, value);
971
972 return count;
973 }
974
975 static DEVICE_ATTR(write, 0660, NULL, sunxi_hdmi20_write_store);
976
sunxi_hdmi20_source_para_show(struct device * dev,struct device_attribute * attr,char * buf)977 static ssize_t sunxi_hdmi20_source_para_show(struct device *dev,
978 struct device_attribute *attr, char *buf)
979 {
980 ssize_t n = 0;
981 /*struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
982 videoParams_t *video = &hdmi->video;
983 audioParams_t *audio = &hdmi->audio;
984 productParams_t *product = &hdmi->product;
985 hdcpParams_t *hdcp = &hdmi->hdcp;
986 struct cec_params *cec = &hdmi->cec;*/
987
988 return n;
989 }
990
991 static DEVICE_ATTR(source_para, 0660,
992 sunxi_hdmi20_source_para_show, NULL);
993
994
sunxi_hdmi20_hdcp_enable_show(struct device * dev,struct device_attribute * attr,char * buf)995 static ssize_t sunxi_hdmi20_hdcp_enable_show(struct device *dev,
996 struct device_attribute *attr, char *buf)
997 {
998 ssize_t n = 0;
999 //struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
1000
1001 //n += sprintf(buf + n, "%d", hdmi->video.is_hcts);
1002
1003 return n;
1004 }
1005
sunxi_hdmi20_hdcp_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1006 static ssize_t sunxi_hdmi20_hdcp_enable_store(struct device *dev,
1007 struct device_attribute *attr,
1008 const char *buf, size_t count)
1009 {
1010 //struct sunxi_hdmi *hdmi = sunxi_hdmi20_get_hdmi();
1011
1012 if (count < 1)
1013 return -EINVAL;
1014
1015 if (strncasecmp(buf, "on", 2) == 0 || strncasecmp(buf, "1", 1) == 0)
1016 ;
1017 else if (strncasecmp(buf, "off", 3) == 0 ||
1018 strncasecmp(buf, "0", 1) == 0)
1019 ;
1020 else
1021 return -EINVAL;
1022
1023 return count;
1024 }
1025
1026 static DEVICE_ATTR(hdcp_enable, 0660,
1027 sunxi_hdmi20_hdcp_enable_show, sunxi_hdmi20_hdcp_enable_store);
1028
1029 static struct attribute *hdmi20_attributes[] = {
1030 &dev_attr_hdcp_enable.attr,
1031 &dev_attr_source_para.attr,
1032 &dev_attr_read.attr,
1033 &dev_attr_write.attr,
1034 &dev_attr_debug.attr,
1035 NULL
1036 };
1037
1038
hdmi20_delay_us(int us)1039 static void hdmi20_delay_us(int us)
1040 {
1041 udelay(us);
1042 }
1043
sunxi_hdmi20_core_init(struct sunxi_hdmi * hdmi)1044 static int sunxi_hdmi20_core_init(struct sunxi_hdmi *hdmi)
1045 {
1046 low_functions.sleep = hdmi20_delay_us;
1047 reg_access.read = hdmi20_read;
1048 reg_access.write = hdmi20_write;
1049
1050 register_system_functions(&low_functions);
1051 register_bsp_functions(®_access);
1052
1053 /*set initial video timing*/
1054 // sunxi_hdmi20_get_video_mode_info(&hdmi->video_info,
1055 // DISP_TV_MOD_720P_50HZ);
1056
1057 hdmitx_api_init(&hdmi->hdmi_dev,
1058 &hdmi->video, &hdmi->audio, &hdmi->hdcp);
1059
1060 hdmi->dev_funcs.hpd_enable(1);
1061
1062 hdmi->video.pb = kzalloc(sizeof(fc_drm_pb_t), GFP_KERNEL);
1063 if (!hdmi->video.pb) {
1064 HDMI_ERR("kzalloc for fc_drm_pb_t failed\n");
1065 return -1;
1066 }
1067
1068 hdmi->funcs = &hdmi20_funcs;
1069 return 0;
1070 }
1071
sunxi_hdmi20_probe(struct platform_device * pdev)1072 static int sunxi_hdmi20_probe(struct platform_device *pdev)
1073 {
1074 int ret = -1;
1075 struct sunxi_hdmi *hdmi = NULL;
1076
1077 hdmi = kmalloc(sizeof(struct sunxi_hdmi), GFP_KERNEL | __GFP_ZERO);
1078 if (!hdmi) {
1079 HDMI_ERR("Malloc sunxi_hdmi fail!\n");
1080 goto OUT;
1081 }
1082
1083 hwhdmi20 = hdmi;
1084
1085 hdmi->pdev = pdev;
1086
1087 /* iomap */
1088 hdmi->reg_base = of_iomap(pdev->dev.of_node, 0);
1089 if (hdmi->reg_base == 0) {
1090 HDMI_ERR("unable to map hdmi registers\n");
1091 ret = -EINVAL;
1092 goto FREE_HDMI;
1093 }
1094
1095 ret = sunxi_hdmi20_video_dts_parse(pdev, hdmi);
1096 if (ret < 0) {
1097 HDMI_ERR("parse video dts failed\n");
1098 ret = -EINVAL;
1099 goto FREE_HDMI;
1100 }
1101
1102 ret = sunxi_hdmi20_hdcp_dts_parse(pdev, hdmi);
1103 if (ret < 0) {
1104 HDMI_ERR("parse hdcp dts failed\n");
1105 ret = -EINVAL;
1106 goto FREE_HDMI;
1107 }
1108
1109 ret = sunxi_hdmi20_cec_dts_parse(pdev, hdmi);
1110 if (ret < 0) {
1111 HDMI_ERR("parse cec dts failed\n");
1112 ret = -EINVAL;
1113 goto FREE_HDMI;
1114 }
1115
1116 sunxi_hdmi20_power_init(pdev, hdmi);
1117
1118 ret = sunxi_hdmi20_clk_init(pdev, hdmi);
1119 if (ret < 0) {
1120 HDMI_ERR("sunxi_hdmi_clk_init failed\n");
1121 goto err_iomap;
1122 }
1123
1124 sunxi_hdmi20_pin_active();
1125
1126 sunxi_hdmi20_hdcp_init();
1127 sunxi_hdmi20_audio_init();
1128
1129 ret = sunxi_hdmi20_core_init(hdmi);
1130 if (ret < 0) {
1131 HDMI_ERR("sunxi_hdmi20_core_init failed\n");
1132 goto err_iomap;
1133 }
1134
1135 return 0;
1136
1137 err_iomap:
1138 if (hdmi->reg_base)
1139 iounmap((char __iomem *)hdmi->reg_base);
1140 FREE_HDMI:
1141 kfree(hdmi);
1142 OUT:
1143 return ret;
1144 }
1145
sunxi_hdmi20_remove(struct platform_device * pdev)1146 static int sunxi_hdmi20_remove(struct platform_device *pdev)
1147 {
1148 int i;
1149 struct sunxi_hdmi *hdmi = hwhdmi20;
1150
1151 if (!hdmi) {
1152 HDMI_ERR("Null pointer!\n");
1153 return -1;
1154 }
1155
1156 sunxi_hdmi20_clk_exit(hdmi);
1157 for (i = 0; i < hdmi->power_count; i++)
1158 sunxi_drm_sys_power_disable(NULL, hdmi->power[i]); /* fix me */
1159 iounmap((char __iomem *)hdmi->reg_base);
1160 kfree(hdmi);
1161 return 0;
1162 }
1163
1164 static const struct of_device_id sunxi_hdmi20_match[] = {
1165 { .compatible = "allwinner,sunxi-hdmi", },
1166
1167 {},
1168 };
1169
1170 struct platform_driver sunxi_hdmi20_platform_driver = {
1171 .probe = sunxi_hdmi20_probe,
1172 .remove = sunxi_hdmi20_remove,
1173 .driver = {
1174 .name = "hdmi",
1175 .owner = THIS_MODULE,
1176 .of_match_table = sunxi_hdmi20_match,
1177 },
1178 };
1179
1180 static struct attribute_group hdmi20_attribute_group = {
1181 .name = "attr",
1182 .attrs = hdmi20_attributes,
1183 };
1184
sunxi_hdmi20_module_init(void)1185 int __init sunxi_hdmi20_module_init(void)
1186 {
1187 int ret = -1;
1188
1189 HDMI_INFO(" start\n");
1190 hdmi20_drv = kmalloc(sizeof(struct drv_model_info),
1191 GFP_KERNEL | __GFP_ZERO);
1192 if (!hdmi20_drv) {
1193 HDMI_ERR("Null drv_model_info pointer\n");
1194 goto OUT;
1195 }
1196 ret = alloc_chrdev_region(&hdmi20_drv->devid, 0, 1, "hdmi");
1197 if (ret < 0) {
1198 HDMI_ERR("alloc_chrdev_region failed\n");
1199 goto FREE_DRV;
1200 }
1201
1202 hdmi20_drv->cdev = cdev_alloc();
1203 if (!hdmi20_drv->cdev) {
1204 HDMI_ERR("cdev_alloc failed\n");
1205 goto FREE_DRV;
1206 }
1207
1208 cdev_init(hdmi20_drv->cdev, NULL);
1209 hdmi20_drv->cdev->owner = THIS_MODULE;
1210 ret = cdev_add(hdmi20_drv->cdev, hdmi20_drv->devid, 1);
1211 if (ret) {
1212 HDMI_ERR("cdev_add major number:%d failed\n",
1213 MAJOR(hdmi20_drv->devid));
1214 goto FREE_DRV;
1215 }
1216
1217 hdmi20_drv->sysclass = class_create(THIS_MODULE, "hdmi");
1218 if (IS_ERR(hdmi20_drv->sysclass)) {
1219 HDMI_ERR("create class error\n");
1220 goto FREE_DRV;
1221 }
1222
1223 hdmi20_drv->dev = device_create(hdmi20_drv->sysclass, NULL,
1224 hdmi20_drv->devid, NULL, "hdmi");
1225 if (!hdmi20_drv->dev) {
1226 HDMI_ERR("device_create failed\n");
1227 goto FREE_DRV;
1228 }
1229
1230 ret = platform_driver_register(&sunxi_hdmi20_platform_driver);
1231 if (ret) {
1232 HDMI_ERR("platform_driver_register failed\n");
1233 goto FREE_DEVICE;
1234 }
1235
1236 ret = sysfs_create_group(&hdmi20_drv->dev->kobj, &hdmi20_attribute_group);
1237 if (ret < 0) {
1238 HDMI_ERR("sysfs_create_file fail!\n");
1239 goto UNREGISTER;
1240 }
1241
1242 HDMI_INFO(" end\n");
1243 return ret;
1244
1245 UNREGISTER:
1246 platform_driver_unregister(&sunxi_hdmi20_platform_driver);
1247 FREE_DEVICE:
1248 device_destroy(hdmi20_drv->sysclass, hdmi20_drv->devid);
1249 FREE_DRV:
1250 kfree(hdmi20_drv);
1251 OUT:
1252 HDMI_ERR(" failed\n");
1253 return -EINVAL;
1254 }
1255
sunxi_hdmi20_module_exit(void)1256 void __exit sunxi_hdmi20_module_exit(void)
1257 {
1258 HDMI_INFO("\n");
1259 if (hdmi20_drv) {
1260 platform_driver_unregister(&sunxi_hdmi20_platform_driver);
1261
1262 device_destroy(hdmi20_drv->sysclass, hdmi20_drv->devid);
1263 class_destroy(hdmi20_drv->sysclass);
1264
1265 cdev_del(hdmi20_drv->cdev);
1266 kfree(hdmi20_drv);
1267 }
1268 }
1269
1270