6872 lines
215 KiB
C
6872 lines
215 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
||
/*
|
||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||
*/
|
||
|
||
#ifdef __linux__
|
||
//#include <linux/bits.h>
|
||
#include <linux/of_graph.h>
|
||
#include <linux/platform_device.h>
|
||
|
||
#include <linux/delay.h>
|
||
#include <linux/device.h>
|
||
#include <linux/err.h>
|
||
#include <linux/extcon.h>
|
||
#include <linux/fs.h>
|
||
#include <linux/gpio/consumer.h>
|
||
#include <linux/i2c.h>
|
||
#include <linux/interrupt.h>
|
||
#include <linux/kernel.h>
|
||
#include <linux/module.h>
|
||
#include <linux/pm_runtime.h>
|
||
#include <linux/regmap.h>
|
||
#include <linux/regulator/consumer.h>
|
||
#include <linux/types.h>
|
||
#include <linux/wait.h>
|
||
#include <drm/drm_mipi_dsi.h>
|
||
|
||
#include <crypto/hash.h>
|
||
#include <crypto/sha1.h>
|
||
|
||
#include <drm/drm_atomic_helper.h>
|
||
#include <drm/drm_bridge.h>
|
||
#include <drm/drm_crtc.h>
|
||
#include <drm/drm_crtc_helper.h>
|
||
#include <drm/display/drm_dp_helper.h>
|
||
#include <drm/drm_edid.h>
|
||
#include <drm/drm_print.h>
|
||
#include <drm/drm_mipi_dsi.h>
|
||
#include <drm/drm_probe_helper.h>
|
||
|
||
#include <sound/hdmi-codec.h>
|
||
#else
|
||
|
||
#include "platform.h"
|
||
|
||
#endif
|
||
#define IT6161_PRINT(fmt, ...) \
|
||
_DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
|
||
|
||
static int ite_debug = 0;
|
||
|
||
#define it6161_debug(fmt, ...) do { \
|
||
if (ite_debug) \
|
||
_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__); \
|
||
} while (0)
|
||
|
||
/* Vendor option */
|
||
#define AUDIO_SELECT I2S
|
||
#define AUDIO_TYPE LPCM
|
||
#define AUDIO_SAMPLE_RATE SAMPLE_RATE_48K
|
||
#define AUDIO_CHANNEL_COUNT 2
|
||
|
||
/*
|
||
* 0: Standard I2S
|
||
* 1: 32bit I2S
|
||
*/
|
||
#define I2S_INPUT_FORMAT 1
|
||
|
||
/*
|
||
* 0: Left-justified
|
||
* 1: Right-justified
|
||
*/
|
||
#define I2S_JUSTIFIED 0
|
||
|
||
/*
|
||
* 0: Data delay 1T correspond to WS
|
||
* 1: No data delay correspond to WS
|
||
*/
|
||
#define I2S_DATA_DELAY 0
|
||
|
||
/*
|
||
* 0: Left channel
|
||
* 1: Right channel
|
||
*/
|
||
#define I2S_WS_CHANNEL 0
|
||
|
||
/*
|
||
* 0: MSB shift first
|
||
* 1: LSB shift first
|
||
*/
|
||
#define I2S_DATA_SEQUENCE 0
|
||
|
||
#define AUX_WAIT_TIMEOUT_MS 100
|
||
#define PIXEL_CLK_DELAY 1
|
||
#define PIXEL_CLK_INVERSE 0
|
||
#define ADJUST_PHASE_THRESHOLD 80000
|
||
#define MAX_PIXEL_CLK 95000
|
||
#define DEFAULT_DRV_HOLD 0
|
||
#define DEFAULT_PWR_ON 0
|
||
|
||
enum hdmi_tx_mode {
|
||
HDMI_TX_NONE,
|
||
HDMI_TX_BY_PASS,
|
||
HDMI_TX_ENABLE_DE_ONLY,
|
||
HDMI_TX_ENABLE_PATTERN_GENERATOR,
|
||
};
|
||
|
||
enum it6161_audio_select {
|
||
I2S = 0,
|
||
SPDIF,
|
||
TDM,
|
||
};
|
||
|
||
enum it6161_audio_sample_rate {
|
||
SAMPLE_RATE_24K = 0x6,
|
||
SAMPLE_RATE_32K = 0x3,
|
||
SAMPLE_RATE_48K = 0x2,
|
||
SAMPLE_RATE_96K = 0xA,
|
||
SAMPLE_RATE_192K = 0xE,
|
||
SAMPLE_RATE_44_1K = 0x0,
|
||
SAMPLE_RATE_88_2K = 0x8,
|
||
SAMPLE_RATE_176_4K = 0xC,
|
||
};
|
||
|
||
enum it6161_audio_type {
|
||
LPCM = 0,
|
||
NLPCM,
|
||
DSS,
|
||
};
|
||
|
||
enum it6161_audio_u32_length {
|
||
u32_LENGTH_16BIT = 0,
|
||
u32_LENGTH_18BIT,
|
||
u32_LENGTH_20BIT,
|
||
u32_LENGTH_24BIT,
|
||
};
|
||
|
||
/*
|
||
* Audio Sample u32 Length
|
||
* u32_LENGTH_16BIT
|
||
* u32_LENGTH_18BIT
|
||
* u32_LENGTH_20BIT
|
||
* u32_LENGTH_24BIT
|
||
*/
|
||
#define AUDIO_u32_LENGTH u32_LENGTH_24BIT
|
||
|
||
enum it6161_active_level {
|
||
LOW,
|
||
HIGH,
|
||
};
|
||
|
||
enum dsi_data_id {
|
||
RGB_24b = 0x3E,
|
||
RGB_30b = 0x0D,
|
||
RGB_36b = 0x1D,
|
||
RGB_18b = 0x1E,
|
||
RGB_18b_L = 0x2E,
|
||
YCbCr_16b = 0x2C,
|
||
YCbCr_20b = 0x0C,
|
||
YCbCr_24b = 0x1C,
|
||
};
|
||
|
||
#include "ite_it6161_hdmi_tx.h"
|
||
#include "ite_it6161_mipi_rx.h"
|
||
|
||
// for sample clock
|
||
#define AUDFS_22p05KHz 4
|
||
#define AUDFS_44p1KHz 0
|
||
#define AUDFS_88p2KHz 8
|
||
#define AUDFS_176p4KHz 12
|
||
|
||
#define AUDFS_24KHz 6
|
||
#define AUDFS_48KHz 2
|
||
#define AUDFS_96KHz 10
|
||
#define AUDFS_192KHz 14
|
||
|
||
#define AUDFS_768KHz 9
|
||
|
||
#define AUDFS_32KHz 3
|
||
#define AUDFS_OTHER 1
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// HDMI VTable
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
static HDMI_VTiming const s_VMTable[] = {
|
||
{ 1,0,640,480,800,525,25175000L,0x89,16,96,48,10,2,33,PROG,Vneg,Hneg},//640x480@60Hz
|
||
{ 2,0,720,480,858,525,27000000L,0x80,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@60Hz
|
||
{ 3,0,720,480,858,525,27000000L,0x80,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@60Hz
|
||
{ 4,0,1280,720,1650,750,74250000L,0x2E,110,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@60Hz
|
||
{ 5,0,1920,540,2200,562,74250000L,0x2E,88,44,148,2,5,15,INTERLACE,Vpos,Hpos},//1920x1080(I)@60Hz
|
||
{ 6,1,720,240,858,262,13500000L,0x100,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@60Hz
|
||
{ 7,1,720,240,858,262,13500000L,0x100,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@60Hz
|
||
{ 8,1,720,240,858,262,13500000L,0x100,19,62,57,4,3,15,PROG,Vneg,Hneg},//720x480(I)@60Hz
|
||
{ 9,1,720,240,858,262,13500000L,0x100,19,62,57,4,3,15,PROG,Vneg,Hneg},//720x480(I)@60Hz
|
||
{10,2,720,240,858,262,54000000L,0x40,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@60Hz
|
||
{11,2,720,240,858,262,54000000L,0x40,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@60Hz
|
||
{12,2,720,240,858,262,54000000L,0x40,19,62,57,4,3,15,PROG,Vneg,Hneg},//720x480(I)@60Hz
|
||
{13,2,720,240,858,262,54000000L,0x40,19,62,57,4,3,15,PROG,Vneg,Hneg},//720x480(I)@60Hz
|
||
{14,1,1440,480,1716,525,54000000L,0x40,32,124,120,9,6,30,PROG,Vneg,Hneg},//1440x480@60Hz
|
||
{15,1,1440,480,1716,525,54000000L,0x40,32,124,120,9,6,30,PROG,Vneg,Hneg},//1440x480@60Hz
|
||
{16,0,1920,1080,2200,1125,148500000L,0x17,88,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@60Hz
|
||
{17,0,720,576,864,625,27000000L,0x80,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@50Hz
|
||
{18,0,720,576,864,625,27000000L,0x80,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@50Hz
|
||
{19,0,1280,720,1980,750,74250000L,0x2E,440,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@50Hz
|
||
{20,0,1920,540,2640,562,74250000L,0x2E,528,44,148,2,5,15,INTERLACE,Vpos,Hpos},//1920x1080(I)@50Hz
|
||
{21,1,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@50Hz
|
||
{22,1,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@50Hz
|
||
{23,1,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,PROG,Vneg,Hneg},//1440x288@50Hz
|
||
{24,1,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,PROG,Vneg,Hneg},//1440x288@50Hz
|
||
{25,2,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@50Hz
|
||
{26,2,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@50Hz
|
||
{27,2,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,PROG,Vneg,Hneg},//1440x288@50Hz
|
||
{28,2,720,288,864,312,13500000L,0x100,12,63,69,2,3,19,PROG,Vneg,Hneg},//1440x288@50Hz
|
||
{29,1,1440,576,1728,625,54000000L,0x40,24,128,136,5,5,39,PROG,Vpos,Hneg},//1440x576@50Hz
|
||
{30,1,1440,576,1728,625,54000000L,0x40,24,128,136,5,5,39,PROG,Vpos,Hneg},//1440x576@50Hz
|
||
{31,0,1920,1080,2640,1125,148500000L,0x17,528,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@50Hz
|
||
{32,0,1920,1080,2750,1125,74250000L,0x2E,638,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@24Hz
|
||
{33,0,1920,1080,2640,1125,74250000L,0x2E,528,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@25Hz
|
||
{34,0,1920,1080,2200,1125,74250000L,0x2E,88,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@30Hz
|
||
{35,2,2880,480,1716*2,525,108000000L,0x20,32*2,124*2,120*2,9,6,30,PROG,Vneg,Hneg},//2880x480@60Hz
|
||
{36,2,2880,480,1716*2,525,108000000L,0x20,32*2,124*2,120*2,9,6,30,PROG,Vneg,Hneg},//2880x480@60Hz
|
||
{37,1,2880,576,3456,625,108000000L,0x20,24*2,128*2,136*2,5,5,39,PROG,Vneg,Hneg},//2880x576@50Hz
|
||
{38,2,2880,576,3456,625,108000000L,0x20,24*2,128*2,136*2,5,5,39,PROG,Vneg,Hneg},//2880x576@50Hz
|
||
{39,0,1920,540,2304,625,72000000L,0x17,32,168,184,23,5,57,INTERLACE,Vneg,Hpos},//1920x1080@50Hz
|
||
// 100Hz
|
||
{40,0,1920,540,2640,562,148500000L,0x17,528,44,148,2,5,15,INTERLACE,Vpos,Hpos},//1920x1080(I)@100Hz
|
||
{41,0,1280,720,1980,750,148500000L,0x17,440,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@100Hz
|
||
{42,0,720,576,864,625, 54000000L,0x40,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@100Hz
|
||
{43,0,720,576,864,625, 54000000L,0x40,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@100Hz
|
||
{44,1,720,288,864,312, 27000000L,0x80,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@100Hz
|
||
{45,1,720,288,864,312, 27000000L,0x80,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@100Hz
|
||
// 120Hz
|
||
{46,0,1920,540,2200,562,148500000L,0x17,88,44,148,2,5,15,INTERLACE,Vpos,Hpos},//1920x1080(I)@120Hz
|
||
{47,0,1280,720,1650,750,148500000L,0x17,110,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@120Hz
|
||
{48,0, 720,480, 858,525, 54000000L,0x40,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@120Hz
|
||
{49,0, 720,480, 858,525, 54000000L,0x40,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@120Hz
|
||
{50,1, 720,240, 858,262, 27000000L,0x80,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@120Hz
|
||
{51,1, 720,240, 858,262, 27000000L,0x80,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@120Hz
|
||
|
||
// 200Hz
|
||
{52,0,720,576,864,625,108000000L,0x20,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@200Hz
|
||
{53,0,720,576,864,625,108000000L,0x20,12,64,68,5,5,39,PROG,Vneg,Hneg},//720x576@200Hz
|
||
{54,1,720,288,864,312, 54000000L,0x40,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@200Hz
|
||
{55,1,720,288,864,312, 54000000L,0x40,12,63,69,2,3,19,INTERLACE,Vneg,Hneg},//1440x576(I)@200Hz
|
||
// 240Hz
|
||
{56,0,720,480,858,525,108000000L,0x20,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@120Hz
|
||
{57,0,720,480,858,525,108000000L,0x20,16,62,60,9,6,30,PROG,Vneg,Hneg},//720x480@120Hz
|
||
{58,1,720,240,858,262, 54000000L,0x40,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@120Hz
|
||
{59,1,720,240,858,262, 54000000L,0x40,19,62,57,4,3,15,INTERLACE,Vneg,Hneg},//720x480(I)@120Hz
|
||
// 720p low resolution
|
||
{60,0,1280, 720,3300, 750, 59400000L,0x3A,1760,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@24Hz
|
||
{61,0,1280, 720,3960, 750, 74250000L,0x2E,2420,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@25Hz
|
||
{62,0,1280, 720,3300, 750, 74250000L,0x2E,1760,40,220,5,5,20,PROG,Vpos,Hpos},//1280x720@30Hz
|
||
// 1080p high refresh rate
|
||
{63,0,1920,1080,2200,1125,297000000L,0x0B, 88,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@120Hz
|
||
{64,0,1920,1080,2640,1125,297000000L,0x0B,528,44,148,4,5,36,PROG,Vpos,Hpos},//1920x1080@100Hz
|
||
// VESA mode
|
||
{0,0,640,350,832,445,31500000L,0x6D,32,64,96,32,3,60,PROG,Vneg,Hpos},// 640x350@85
|
||
{0,0,640,400,832,445,31500000L,0x6D,32,64,96,1,3,41,PROG,Vneg,Hneg},// 640x400@85
|
||
{0,0,832,624,1152,667,57283000L,0x3C,32,64,224,1,3,39,PROG,Vneg,Hneg},// 832x624@75Hz
|
||
{0,0,720,350,900,449,28322000L,0x7A,18,108,54,59,2,38,PROG,Vneg,Hneg},// 720x350@70Hz
|
||
{0,0,720,400,900,449,28322000L,0x7A,18,108,54,13,2,34,PROG,Vpos,Hneg},// 720x400@70Hz
|
||
{0,0,720,400,936,446,35500000L,0x61,36,72,108,1,3,42,PROG,Vpos,Hneg},// 720x400@85
|
||
{0,0,640,480,800,525,25175000L,0x89,16,96,48,10,2,33,PROG,Vneg,Hneg},// 640x480@60
|
||
{0,0,640,480,832,520,31500000L,0x6D,24,40,128,9,3,28,PROG,Vneg,Hneg},// 640x480@72
|
||
{0,0,640,480,840,500,31500000L,0x6D,16,64,120,1,3,16,PROG,Vneg,Hneg},// 640x480@75
|
||
{0,0,640,480,832,509,36000000L,0x60,56,56,80,1,3,25,PROG,Vneg,Hneg},// 640x480@85
|
||
{0,0,800,600,1024,625,36000000L,0x60,24,72,128,1,2,22,PROG,Vpos,Hpos},// 800x600@56
|
||
{0,0,800,600,1056,628,40000000L,0x56,40,128,88,1,4,23,PROG,Vpos,Hpos},// 800x600@60
|
||
{0,0,800,600,1040,666,50000000L,0x45,56,120,64,37,6,23,PROG,Vpos,Hpos},// 800x600@72
|
||
{0,0,800,600,1056,625,49500000L,0x45,16,80,160,1,3,21,PROG,Vpos,Hpos},// 800x600@75
|
||
{0,0,800,600,1048,631,56250000L,0x3D,32,64,152,1,3,27,PROG,Vpos,Hpos},// 800X600@85
|
||
{0,0,848,480,1088,517,33750000L,0x66,16,112,112,6,8,23,PROG,Vpos,Hpos},// 840X480@60
|
||
{0,0,1024,384,1264,408,44900000L,0x4C,8,176,56,0,4,20,INTERLACE,Vpos,Hpos},//1024x768(I)@87Hz
|
||
{0,0,1024,768,1344,806,65000000L,0x35,24,136,160,3,6,29,PROG,Vneg,Hneg},// 1024x768@60
|
||
{0,0,1024,768,1328,806,75000000L,0x2E,24,136,144,3,6,29,PROG,Vneg,Hneg},// 1024x768@70
|
||
{0,0,1024,768,1312,800,78750000L,0x2B,16,96,176,1,3,28,PROG,Vpos,Hpos},// 1024x768@75
|
||
{0,0,1024,768,1376,808,94500000L,0x24,48,96,208,1,3,36,PROG,Vpos,Hpos},// 1024x768@85
|
||
{0,0,1152,864,1600,900,108000000L,0x20,64,128,256,1,3,32,PROG,Vpos,Hpos},// 1152x864@75
|
||
{0,0,1280,768,1440,790,68250000L,0x32,48,32,80,3,7,12,PROG,Vneg,Hpos},// 1280x768@60-R
|
||
{0,0,1280,768,1664,798,79500000L,0x2B,64,128,192,3,7,20,PROG,Vpos,Hneg},// 1280x768@60
|
||
{0,0,1280,768,1696,805,102250000L,0x21,80,128,208,3,7,27,PROG,Vpos,Hneg},// 1280x768@75
|
||
{0,0,1280,768,1712,809,117500000L,0x1D,80,136,216,3,7,31,PROG,Vpos,Hneg},// 1280x768@85
|
||
{0,0,1280,800,1440, 823, 71000000L,0x31, 48, 32, 80,3,6,14,PROG,Vpos,Hneg},// 1280x800@60Hz
|
||
{0,0,1280,800,1680, 831, 83500000L,0x29, 72,128,200,3,6,22,PROG,Vpos,Hneg},// 1280x800@60Hz
|
||
{0,0,1280,800,1696, 838,106500000L,0x20, 80,128,208,3,6,29,PROG,Vpos,Hneg},// 1280x800@75Hz
|
||
{0,0,1280,800,1712, 843,122500000L,0x1C, 80,136,216,3,6,34,PROG,Vpos,Hneg},// 1280x800@85Hz
|
||
{0,0,1280,960,1800,1000,108000000L,0x20,96,112,312,1,3,36,PROG,Vpos,Hpos},// 1280x960@60
|
||
{0,0,1280,960,1728,1011,148500000L,0x17,64,160,224,1,3,47,PROG,Vpos,Hpos},// 1280x960@85
|
||
{0,0,1280,1024,1688,1066,108000000L,0x20,48,112,248,1,3,38,PROG,Vpos,Hpos},// 1280x1024@60
|
||
{0,0,1280,1024,1688,1066,135000000L,0x19,16,144,248,1,3,38,PROG,Vpos,Hpos},// 1280x1024@75
|
||
{0,0,1280,1024,1728,1072,157500000L,0x15,64,160,224,1,3,44,PROG,Vpos,Hpos},// 1280X1024@85
|
||
{0,0,1360,768,1792,795,85500000L,0x28,64,112,256,3,6,18,PROG,Vpos,Hpos},// 1360X768@60
|
||
{0,0,1366,768,1792,798,85500000L,0x28, 70,143,213,3,3,24,PROG,Vpos,Hpos},// 1366X768@60
|
||
{0,0,1366,768,1500,800,72000000L,0x30, 14, 56, 64,1,3,28,PROG,Vpos,Hpos},// 1360X768@60
|
||
{0,0,1400,1050,1560,1080,101000000L,0x22,48,32,80,3,4,23,PROG,Vneg,Hpos},// 1400x768@60-R
|
||
{0,0,1400,1050,1864,1089,121750000L,0x1C,88,144,232,3,4,32,PROG,Vpos,Hneg},// 1400x768@60
|
||
{0,0,1400,1050,1896,1099,156000000L,0x16,104,144,248,3,4,42,PROG,Vpos,Hneg},// 1400x1050@75
|
||
{0,0,1400,1050,1912,1105,179500000L,0x13,104,152,256,3,4,48,PROG,Vpos,Hneg},// 1400x1050@85
|
||
{0,0,1440,900,1600,926,88750000L,0x26,48,32,80,3,6,17,PROG,Vneg,Hpos},// 1440x900@60-R
|
||
{0,0,1440,900,1904,934,106500000L,0x20,80,152,232,3,6,25,PROG,Vpos,Hneg},// 1440x900@60
|
||
{0,0,1440,900,1936,942,136750000L,0x19,96,152,248,3,6,33,PROG,Vpos,Hneg},// 1440x900@75
|
||
{0,0,1440,900,1952,948,157000000L,0x16,104,152,256,3,6,39,PROG,Vpos,Hneg},// 1440x900@85
|
||
{0,0,1600,1200,2160,1250,162000000L,0x15,64,192,304,1,3,46,PROG,Vpos,Hpos},// 1600x1200@60
|
||
{0,0,1600,1200,2160,1250,175500000L,0x13,64,192,304,1,3,46,PROG,Vpos,Hpos},// 1600x1200@65
|
||
{0,0,1600,1200,2160,1250,189000000L,0x12,64,192,304,1,3,46,PROG,Vpos,Hpos},// 1600x1200@70
|
||
{0,0,1600,1200,2160,1250,202500000L,0x11,64,192,304,1,3,46,PROG,Vpos,Hpos},// 1600x1200@75
|
||
{0,0,1600,1200,2160,1250,229500000L,0x0F,64,192,304,1,3,46,PROG,Vpos,Hpos},// 1600x1200@85
|
||
{0,0,1680,1050,1840,1080,119000000L,0x1D,48,32,80,3,6,21,PROG,Vneg,Hpos},// 1680x1050@60-R
|
||
{0,0,1680,1050,2240,1089,146250000L,0x17,104,176,280,3,6,30,PROG,Vpos,Hneg},// 1680x1050@60
|
||
{0,0,1680,1050,2272,1099,187000000L,0x12,120,176,296,3,6,40,PROG,Vpos,Hneg},// 1680x1050@75
|
||
{0,0,1680,1050,2288,1105,214750000L,0x10,128,176,304,3,6,46,PROG,Vpos,Hneg},// 1680x1050@85
|
||
{0,0,1792,1344,2448,1394,204750000L,0x10,128,200,328,1,3,46,PROG,Vpos,Hneg},// 1792x1344@60
|
||
{0,0,1792,1344,2456,1417,261000000L,0x0D,96,216,352,1,3,69,PROG,Vpos,Hneg},// 1792x1344@75
|
||
{0,0,1856,1392,2528,1439,218250000L,0x0F,96,224,352,1,3,43,PROG,Vpos,Hneg},// 1856x1392@60
|
||
{0,0,1856,1392,2560,1500,288000000L,0x0C,128,224,352,1,3,104,PROG,Vpos,Hneg},// 1856x1392@75
|
||
{0,0,1920,1200,2080,1235,154000000L,0x16,48,32,80,3,6,26,PROG,Vneg,Hpos},// 1920x1200@60-R
|
||
{0,0,1920,1200,2592,1245,193250000L,0x11,136,200,336,3,6,36,PROG,Vpos,Hneg},// 1920x1200@60
|
||
{0,0,1920,1200,2608,1255,245250000L,0x0E,136,208,344,3,6,46,PROG,Vpos,Hneg},// 1920x1200@75
|
||
{0,0,1920,1200,2624,1262,281250000L,0x0C,144,208,352,3,6,53,PROG,Vpos,Hneg},// 1920x1200@85
|
||
{0,0,1920,1440,2600,1500,234000000L,0x0E,128,208,344,1,3,56,PROG,Vpos,Hneg},// 1920x1440@60
|
||
{0,0,1920,1440,2640,1500,297000000L,0x0B,144,224,352,1,3,56,PROG,Vpos,Hneg},// 1920x1440@75
|
||
};
|
||
|
||
#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a)))
|
||
|
||
static bool bChangeMode = false ;
|
||
static unsigned char CommunBuff[128] ;
|
||
|
||
static const u8 CA[] = { 0,0,0, 02, 0x3, 0x7, 0xB, 0xF, 0x1F } ;
|
||
|
||
static u32 VideoPixelClock ;
|
||
static u8 pixelrep ; // no pixelrepeating
|
||
// static HDMI_Aspec aspec ;
|
||
// static HDMI_Colorimetry Colorimetry ;
|
||
|
||
static u32 ulAudioSampleFS = INPUT_SAMPLE_FREQ_HZ;
|
||
// u8 bAudioSampleFreq = INPUT_SAMPLE_FREQ ;
|
||
static u8 bOutputAudioChannel = OUTPUT_CHANNEL;
|
||
static u8 bOutputAudioType=CNOFIG_INPUT_AUDIO_TYPE;
|
||
|
||
#define MSCOUNT 1000
|
||
#define LOADING_UPDATE_TIMEOUT (3000/32) // 3sec
|
||
|
||
static HDMITXDEV hdmiTxDev[HDMITX_MAX_DEV_COUNT];
|
||
|
||
/* configuration */
|
||
//#define ENABLE_HDCP
|
||
#define ENABLE_MIPI_RX_EXTERNAL_CLOCK false
|
||
#define MPLaneSwap FALSE
|
||
#define MPPNSwap FALSE /* TRUE: MTK , FALSE: Solomon */
|
||
#define MIPI_RX_LANE_COUNT 4 /* 1~4 */
|
||
|
||
#define OUTPUT_COLOR_MODE F_MODE_RGB444 /* F_MODE_YUV444, F_MODE_YUV422, F_MODE_RGB444 */
|
||
#define HDMI_TX_MODE HDMI_TX_ENABLE_DE_ONLY /* HDMI_TX_NONE, HDMI_TX_BY_PASS, HDMI_TX_ENABLE_DE_ONLY, HDMI_TX_ENABLE_PATTERN_GENERATOR */
|
||
#define HDMI_TX_PATTERN_GENERATOR_FORMAT 16 /* support format 2, 4, 16*/
|
||
#define HDMI_TX_PATTERN_COLLOR_R 0x03
|
||
#define HDMI_TX_PATTERN_COLLOR_G 0x00
|
||
#define HDMI_TX_PATTERN_COLLOR_B 0x00
|
||
|
||
/* vendor option */
|
||
#define EOTPSel 0 /* LM option 0~15 */
|
||
#define EnDeSkew TRUE
|
||
#define PPIDbgSel 12/* 0~15 */
|
||
#define RegIgnrNull 1
|
||
#define RegIgnrBlk 1
|
||
#define RegEnDummyECC 0
|
||
#define LMDbgSel 0 /* 0~7 */
|
||
#define EnContCK TRUE
|
||
#define HSSetNum 3
|
||
#define EnMBPM FALSE /* enable MIPI Bypass Mode */
|
||
|
||
#if (EnMBPM == TRUE)
|
||
#define PREC_Update TRUE//int PREC_Update = FALSE; // enable P-timing update
|
||
#define MREC_Update TRUE//int MREC_Update = FALSE; // enable M-timing update
|
||
#define EnTBPM TRUE /* enable HDMITX Bypass Mode */
|
||
#else
|
||
#define PREC_Update FALSE//int PREC_Update = FALSE; // enable P-timing update
|
||
#define MREC_Update FALSE//int MREC_Update = FALSE; // enable M-timing update
|
||
#define EnTBPM FALSE /* enable HDMITX Bypass Mode */
|
||
#endif
|
||
|
||
#define REGSELDEF FALSE
|
||
#define MPForceStb FALSE
|
||
#define EnHReSync FALSE
|
||
#define EnVReSync FALSE
|
||
#define EnFReSync FALSE
|
||
#define EnVREnh FALSE
|
||
#define EnVREnhSel 1 /* 0:Div2, 1:Div4, 2:Div8, 3:Div16, 4:Div32 */
|
||
#define EnMAvg TRUE
|
||
|
||
#if (IC_VERSION == 0xC0)
|
||
#define SkipStg 4
|
||
#else
|
||
#define SkipStg 2
|
||
#endif
|
||
|
||
#if (IC_VERSION == 0xC0)
|
||
#define PDREFCLK FALSE
|
||
#else
|
||
#define PDREFCLK TRUE
|
||
#endif
|
||
|
||
#define PDREFCNT 0 /* when PDREFCLK=TRUE, 0:div2, 1:div4, 2:div8, 3:divg16 */
|
||
#define EnIntWakeU3 FALSE
|
||
#define EnIOIDDQ FALSE
|
||
#define EnStb2Rst FALSE
|
||
#define EnExtStdby FALSE
|
||
#define EnStandby FALSE
|
||
|
||
#if (IC_VERSION == 0xC0)
|
||
#define MShift 4//int MShift = 5; // default: 0 //fmt2 fmt4 :4
|
||
#define PPSFFRdStg 0x04//int PPSFFRdStg = 0x10; //PPSFFRdStg(2:0)
|
||
#define RegAutoSync TRUE//int RegAutoSync = TRUE;//add sync falling //pet:D0 20200211
|
||
#else
|
||
#define MShift 5//int MShift = 5; // default: 0 //fmt2 fmt4 :4
|
||
#define PPSFFRdStg 0x10//int PPSFFRdStg = 0x10; //PPSFFRdStg(2:0)
|
||
#endif //#if (IC_VERSION == 0xC0)
|
||
|
||
#define PShift 3
|
||
#define EnFFAutoRst TRUE
|
||
|
||
#define RegEnSyncErr FALSE//int RegEnSyncErr = FALSE;
|
||
#define EnTxCRC TRUE//int EnTxCRC = TRUE;
|
||
#define TxCRCnum (0x20) //D0 20200211//(0x00)//TxCRCnum(6:0)//int TxCRCnum = 0x00; //TxCRCnum(6:0)
|
||
|
||
#if (IC_VERSION == 0xC0)
|
||
#define InvMCLK TRUE //FALSE for solomon, if NonUFO, MCLK max = 140MHz with InvMCLK=TRUE
|
||
#else
|
||
#define InvMCLK FALSE //FALSE for solomon, if NonUFO, MCLK max = 140MHz with InvMCLK=TRUE
|
||
#endif
|
||
|
||
#define InvPCLK FALSE
|
||
|
||
#ifndef INV_INPUT_PCLK
|
||
#define PCLKINV 0
|
||
#else
|
||
#define PCLKINV B_TX_VDO_LATCH_EDGE
|
||
#endif
|
||
|
||
#ifndef INV_INPUT_ACLK
|
||
#define InvAudCLK 0
|
||
#else
|
||
#define InvAudCLK B_TX_AUDFMT_FALL_EDGE_SAMPLE_WS
|
||
#endif
|
||
|
||
// #define INIT_CLK_LOW
|
||
|
||
#define TxChSwap 0
|
||
#define TxPNSwap 0
|
||
|
||
#define NRTXRCLK 1//int NRTXRCLK = true;//it6161b0 option true:set TRCLK by self
|
||
#define RCLKFreqSel 1// int RCLKFreqSel = true; // false: 10MHz(div1), true : 20 MHz(OSSDIV2)
|
||
// #ifdef REDUCE_HDMITX_SRC_JITTER
|
||
// #define ForceTxCLKStb true// int ForceTxCLKStb = false; //true:define _hdmitx_jitter_
|
||
// #else
|
||
#define ForceTxCLKStb true //20200220 C code set true-> false
|
||
// #endif //#ifdef REDUCE_HDMITX_SRC_JITTER
|
||
static const RegSetEntry HDMITX_Init_Table[] = {
|
||
{0x0F, 0x40, 0x00},
|
||
//PLL Reset
|
||
{0x62, 0x08, 0x00}, // XP_RESETB
|
||
{0x64, 0x04, 0x00}, // IP_RESETB
|
||
{0x0F, 0x01, 0x00}, // bank 0 ;3
|
||
#ifdef INIT_CLK_LOW
|
||
{0x62, 0x90, 0x10},
|
||
{0x64, 0x89, 0x09},
|
||
{0x68, 0x10, 0x10},
|
||
#endif
|
||
|
||
|
||
|
||
// {0xD1, 0x0E, 0x0C},
|
||
// {0x65, 0x03, 0x00},
|
||
// #ifdef NON_SEQUENTIAL_YCBCR422 // for ITE HDMIRX
|
||
// {0x71, 0xFC, 0x1C},
|
||
// #else
|
||
// {0x71, 0xFC, 0x18},
|
||
// #endif
|
||
|
||
{0x8D, 0xFF, CEC_I2C_SLAVE_ADDR},//EnCEC
|
||
//{0x0F, 0x08, 0x08},
|
||
{0xA9, 0x80, (EnTBPM<<7)},// hdmitxset(0xa9, 0xc0, (EnTBPM<<7) + (EnTxPatMux<<6))
|
||
{0xBF, 0x80, (NRTXRCLK<<7)},//from c code hdmitxset(0xbf, 0x80, (NRTXRCLK<<7));
|
||
|
||
// Initial Value
|
||
{0xF8,0xFF,0xC3},
|
||
{0xF8,0xFF,0xA5},
|
||
//{0x05,0x1E,0x0C},//hdmitxset(0x05, 0x1E, (ForceRxOn<<4)+(RCLKPDSel<<2)+(RCLKPDEn<<1));ForceRxOn:F,RCLKPDSel=3,RCLKPDSel=false
|
||
{0xF4,0x0C,0x00},//hdmitxset(0xF4, 0x0C, DDCSpeed<<2);//DDC75K
|
||
{0xF3,0x02,0x00},//hdmitxset(0xF3, 0x02, ForceVOut<<1);//ForceVOut:false
|
||
// {0x20, 0x80, 0x80},//TODO: check need or not?
|
||
// {0x37, 0x01, 0x00},//TODO: check need or not?
|
||
// {0x20, 0x80, 0x00},//TODO: check need or not?
|
||
{0xF8,0xFF,0xFF},
|
||
{0x5A,0x0C,0x0C},//hdmitxset(0x5A, 0x0C, 0x0C);
|
||
{0xD1,0x0A,((ForceTxCLKStb)<<3)+0x02},//hdmitxset(0xD1, 0x0A, (ForceTxCLKStb<<3)+0x02); // High Sensitivity , modified by junjie force "CLK_stable"
|
||
{0x5D,0x04,((RCLKFreqSel)<<2)},//hdmitxset(0x5D, 0x04, (RCLKFreqSel<<2));//int RCLKFreqSel = true; // false: 10MHz(div1), true : 20 MHz(OSSDIV2)
|
||
{0x65,0x03,0x00},//hdmitxset(0x65, 0x03, RINGOSC);
|
||
{0x71,0xF9,((0<<6)+(0<<5)+(1<<4)+(1<<3)+0)},//hdmitxset(0x71, 0xF9, (XPStableTime<<6)+(EnXPLockChk<<5)+(EnPLLBufRst<<4)+(EnFFAutoRst<<3)+ EnFFManualRst);
|
||
{0xCF,0xFF,(0<<7)+(0<<6)+(0<<4)+(0<<2)+0},//hdmitxset(0xCF, 0xFF, (EnPktLimitGB<<7)+(EnPktBlankGB<<6)+(KeepOutGBSel<<4)+(PktLimitGBSel<<2)+PktBlankGBSel);
|
||
|
||
{0xd1,0x02,0x00},//hdmitxset(0xd1, 0x02, 0x00);//VidStbSen = false
|
||
// 2014/01/07 HW Request for ROSC stable
|
||
|
||
// {0x5D,0x03,0x01},
|
||
//~2014/01/07
|
||
// #ifdef USE_IT66120
|
||
// {0x5A, 0x02, 0x00},
|
||
// {0xE2, 0xFF, 0xFF},
|
||
// #endif
|
||
|
||
{0x59, 0xD0, (((2-1)<<6)+(0<<4))},//hdmitxset(0x59, 0xD0, ((ManuallPR-1)<<6)+(DisLockPR<<4));ManuallPR=2, DisLockPR = 0
|
||
// {0x59, 0xD8, 0x40|PCLKINV},
|
||
#if((TxChSwap == 1) || (TxPNSwap == 1))
|
||
{0x6b,0xC0,((TxChSwap<<7)+ (TxPNSwap<<6))},// hdmitxset(0x6b, 0xC0,(TxChSwap<<7)+ (TxPNSwap<<6));
|
||
{0x61,0x40,0x40},// hdmitxset(0x61, 0x40,0x40);
|
||
#endif //#if((TxChSwap ==true) || (TxPNSwap ==true))
|
||
|
||
|
||
{0xE1, 0x20, InvAudCLK},// Inverse Audio Latch Edge of IACLK
|
||
{0xF5, 0x40, 0x00},//hdmitxset(0xF5,0x40,ForceTMDSStable<<6);
|
||
|
||
{0x05, 0xC0, 0x40},// Setup INT Pin: Active Low & Open-Drain
|
||
|
||
// {REG_TX_INT_MASK1, 0xFF, ~(B_TX_RXSEN_MASK|B_TX_HPD_MASK)},
|
||
// {REG_TX_INT_MASK2, 0xFF, ~(B_TX_KSVLISTCHK_MASK|B_TX_AUTH_DONE_MASK|B_TX_AUTH_FAIL_MASK)},
|
||
// {REG_TX_INT_MASK3, 0xFF, ~(B_TX_VIDSTABLE_MASK)},
|
||
{0x0C, 0xFF, 0xFF},
|
||
{0x0D, 0xFF, 0xFF},
|
||
{0x0E, 0x03, 0x03},// Clear all Interrupt
|
||
|
||
{0x0C, 0xFF, 0x00},
|
||
{0x0D, 0xFF, 0x00},
|
||
{0x0E, 0x02, 0x00},
|
||
//{0x09, 0x03, 0x00}, // Enable HPD and RxSen Interrupt//remove for interrupt mode allen
|
||
{0x20,0x01,0x00}
|
||
};
|
||
|
||
static const RegSetEntry HDMITX_DefaultVideo_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default output format.
|
||
////////////////////////////////////////////////////
|
||
{0x72, 0xff, 0x00},
|
||
{0x70, 0xff, 0x00},
|
||
#ifndef DEFAULT_INPUT_YCBCR
|
||
// GenCSC\RGB2YUV_ITU709_16_235.c
|
||
{0x72, 0xFF, 0x02},
|
||
{0x73, 0xFF, 0x00},
|
||
{0x74, 0xFF, 0x80},
|
||
{0x75, 0xFF, 0x00},
|
||
{0x76, 0xFF, 0xB8},
|
||
{0x77, 0xFF, 0x05},
|
||
{0x78, 0xFF, 0xB4},
|
||
{0x79, 0xFF, 0x01},
|
||
{0x7A, 0xFF, 0x93},
|
||
{0x7B, 0xFF, 0x00},
|
||
{0x7C, 0xFF, 0x49},
|
||
{0x7D, 0xFF, 0x3C},
|
||
{0x7E, 0xFF, 0x18},
|
||
{0x7F, 0xFF, 0x04},
|
||
{0x80, 0xFF, 0x9F},
|
||
{0x81, 0xFF, 0x3F},
|
||
{0x82, 0xFF, 0xD9},
|
||
{0x83, 0xFF, 0x3C},
|
||
{0x84, 0xFF, 0x10},
|
||
{0x85, 0xFF, 0x3F},
|
||
{0x86, 0xFF, 0x18},
|
||
{0x87, 0xFF, 0x04},
|
||
#else
|
||
// GenCSC\YUV2RGB_ITU709_16_235.c
|
||
{0x0F, 0x01, 0x00},
|
||
{0x72, 0xFF, 0x03},
|
||
{0x73, 0xFF, 0x00},
|
||
{0x74, 0xFF, 0x80},
|
||
{0x75, 0xFF, 0x00},
|
||
{0x76, 0xFF, 0x00},
|
||
{0x77, 0xFF, 0x08},
|
||
{0x78, 0xFF, 0x53},
|
||
{0x79, 0xFF, 0x3C},
|
||
{0x7A, 0xFF, 0x89},
|
||
{0x7B, 0xFF, 0x3E},
|
||
{0x7C, 0xFF, 0x00},
|
||
{0x7D, 0xFF, 0x08},
|
||
{0x7E, 0xFF, 0x51},
|
||
{0x7F, 0xFF, 0x0C},
|
||
{0x80, 0xFF, 0x00},
|
||
{0x81, 0xFF, 0x00},
|
||
{0x82, 0xFF, 0x00},
|
||
{0x83, 0xFF, 0x08},
|
||
{0x84, 0xFF, 0x00},
|
||
{0x85, 0xFF, 0x00},
|
||
{0x86, 0xFF, 0x87},
|
||
{0x87, 0xFF, 0x0E},
|
||
#endif
|
||
// 2012/12/20 added by Keming's suggestion test
|
||
{0x88, 0xF0, 0x00},
|
||
};
|
||
static const RegSetEntry HDMITX_SetHDMI_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default HDMI Mode
|
||
////////////////////////////////////////////////////
|
||
{0xC0, 0x01, 0x01},
|
||
{0xC1, 0x03, 0x03},
|
||
{0xC6, 0x03, 0x03}
|
||
};
|
||
|
||
static const RegSetEntry HDMITX_SetDVI_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default HDMI Mode
|
||
////////////////////////////////////////////////////
|
||
{0x0F, 0x01, 0x01},
|
||
{0x58, 0xFF, 0x00},
|
||
{0x0F, 0x01, 0x00},
|
||
{0xC0, 0x01, 0x00},
|
||
{0xC1, 0x03, 0x02},
|
||
{0xC6, 0x03, 0x00}
|
||
};
|
||
|
||
static const RegSetEntry HDMITX_DefaultAVIInfo_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default avi infoframe
|
||
////////////////////////////////////////////////////
|
||
{0x0F, 0x01, 0x01},
|
||
{0x58, 0xFF, 0x10},
|
||
{0x59, 0xFF, 0x08},
|
||
{0x5A, 0xFF, 0x00},
|
||
{0x5B, 0xFF, 0x00},
|
||
{0x5C, 0xFF, 0x00},
|
||
{0x5D, 0xFF, 0x57},
|
||
{0x5E, 0xFF, 0x00},
|
||
{0x5F, 0xFF, 0x00},
|
||
{0x60, 0xFF, 0x00},
|
||
{0x61, 0xFF, 0x00},
|
||
{0x62, 0xFF, 0x00},
|
||
{0x63, 0xFF, 0x00},
|
||
{0x64, 0xFF, 0x00},
|
||
{0x65, 0xFF, 0x00},
|
||
{0x0F, 0x01, 0x00},
|
||
{0xCD, 0x03, 0x03}
|
||
};
|
||
static const RegSetEntry HDMITX_DeaultAudioInfo_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default audio infoframe
|
||
////////////////////////////////////////////////////
|
||
{0x0F, 0x01, 0x01},
|
||
{0x68, 0xFF, 0x00},
|
||
{0x69, 0xFF, 0x00},
|
||
{0x6A, 0xFF, 0x00},
|
||
{0x6B, 0xFF, 0x00},
|
||
{0x6C, 0xFF, 0x00},
|
||
{0x6D, 0xFF, 0x71},
|
||
{0x0F, 0x01, 0x00},
|
||
{0xCE, 0x03, 0x03}
|
||
};
|
||
|
||
static const RegSetEntry HDMITX_Aud_CHStatus_LPCM_20bit_48Khz[] =
|
||
{
|
||
{0x0F, 0x01, 0x01},
|
||
{0x33, 0xFF, 0x00},
|
||
{0x34, 0xFF, 0x18},
|
||
{0x35, 0xFF, 0x00},
|
||
{0x91, 0xFF, 0x00},
|
||
{0x92, 0xFF, 0x00},
|
||
{0x93, 0xFF, 0x01},
|
||
{0x94, 0xFF, 0x00},
|
||
{0x98, 0xFF, 0x02},
|
||
{0x99, 0xFF, 0xDA},
|
||
{0x0F, 0x01, 0x00}
|
||
} ;
|
||
|
||
static const RegSetEntry HDMITX_AUD_SPDIF_2ch_24bit[] =
|
||
{
|
||
{0x0F, 0x11, 0x00},
|
||
{0x04, 0x14, 0x04},
|
||
{0xE0, 0xFF, 0xD1},
|
||
{0xE1, 0xFF, 0x01},
|
||
{0xE2, 0xFF, 0xE4},
|
||
{0xE3, 0xFF, 0x10},
|
||
{0xE4, 0xFF, 0x00},
|
||
{0xE5, 0xFF, 0x00},
|
||
{0x04, 0x14, 0x00}
|
||
} ;
|
||
|
||
static const RegSetEntry HDMITX_AUD_I2S_2ch_24bit[] =
|
||
{
|
||
{0x0F, 0x11, 0x00},
|
||
{0x04, 0x14, 0x04},
|
||
{0xE0, 0xFF, 0xC1},
|
||
{0xE1, 0xFF, 0x01},
|
||
#ifdef USE_IT66120
|
||
{0x5A, 0x02, 0x00},
|
||
{0xE2, 0xFF, 0xFF},
|
||
#else
|
||
{0xE2, 0xFF, 0xE4},
|
||
#endif
|
||
{0xE3, 0xFF, 0x00},
|
||
{0xE4, 0xFF, 0x00},
|
||
{0xE5, 0xFF, 0x00},
|
||
{0x04, 0x14, 0x00}
|
||
} ;
|
||
|
||
static const RegSetEntry HDMITX_DefaultAudio_Table[] = {
|
||
|
||
////////////////////////////////////////////////////
|
||
// Config default audio output format.
|
||
////////////////////////////////////////////////////
|
||
{0x0F, 0x21, 0x00},
|
||
{0x04, 0x14, 0x04},
|
||
{0xE0, 0xFF, 0xC1},
|
||
{0xE1, 0xFF, 0x01},
|
||
#ifdef USE_IT66120
|
||
{0xE2, 0xFF, 0xFF},
|
||
#else
|
||
{0xE2, 0xFF, 0xE4},
|
||
#endif
|
||
{0xE3, 0xFF, 0x00},
|
||
{0xE4, 0xFF, 0x00},
|
||
{0xE5, 0xFF, 0x00},
|
||
{0x0F, 0x01, 0x01},
|
||
{0x33, 0xFF, 0x00},
|
||
{0x34, 0xFF, 0x18},
|
||
{0x35, 0xFF, 0x00},
|
||
{0x91, 0xFF, 0x00},
|
||
{0x92, 0xFF, 0x00},
|
||
{0x93, 0xFF, 0x01},
|
||
{0x94, 0xFF, 0x00},
|
||
{0x98, 0xFF, 0x02},
|
||
{0x99, 0xFF, 0xDB},
|
||
{0x0F, 0x01, 0x00},
|
||
{0x04, 0x14, 0x00}
|
||
} ;
|
||
|
||
static const RegSetEntry HDMITX_PwrDown_Table[] = {
|
||
{0x05, 0x60, 0x60},
|
||
{0xf8, 0xc3},
|
||
{0xf8, 0xa5},
|
||
{0xe8, 0x60},
|
||
{0xE0, 0x0F, 0x00},
|
||
// Enable GRCLK
|
||
// #if (IC_VERSION == 0xC0)
|
||
// {0x0F, 0x40, 0x00},
|
||
// #else
|
||
// {0x0F, 0x70, 0x70},// PwrDown RCLK , IACLK ,TXCLK
|
||
// #endif //#if (IC_VERSION == 0xC0)
|
||
// PLL Reset
|
||
{0x61, 0x10, 0x10}, // DRV_RST
|
||
{0x62, 0x08, 0x00}, // XP_RESETB
|
||
{0x64, 0x04, 0x00}, // IP_RESETB
|
||
{0x01, 0x00, 0x00}, // idle(100);
|
||
|
||
{0x61, 0x60, 0x60},
|
||
|
||
{0x70, 0xFF, 0x00},//hdmitxwr(0x70, 0x00); // Select TXCLK power-down path
|
||
// PLL PwrDn
|
||
// {0x61, 0x20, 0x20}, // PwrDn DRV
|
||
// {0x62, 0x44, 0x44}, // PwrDn XPLL
|
||
// {0x64, 0x40, 0x40}, // PwrDn IPLL
|
||
|
||
// HDMITX PwrDn
|
||
// {0x05, 0x01, 0x01}, // PwrDn PCLK
|
||
// {0xE0, 0x0F, 0x00},// hdmitxset(0xE0, 0x0F, 0x00); // PwrDn GIACLK, IACLK
|
||
// {0x72, 0x03, 0x00},// hdmitxset(0x72, 0x03, 0x00); // PwrDn GTxCLK (QCLK)
|
||
// {0x0F, 0x78, 0x78}, // PwrDn GRCLK
|
||
{0x0F, 0x70, 0x70}//Gate RCLK IACLK TXCLK
|
||
};
|
||
|
||
static const RegSetEntry HDMITX_PwrOn_Table[] = {
|
||
{0x0F, 0x70, 0x00}, // // PwrOn RCLK , IACLK ,TXCLK
|
||
// {0x0F, 0x78, 0x38}, // PwrOn GRCLK
|
||
// {0x05, 0x01, 0x00}, // PwrOn PCLK
|
||
|
||
// PLL PwrOn
|
||
{0x61, 0x20, 0x00}, // PwrOn DRV
|
||
{0x62, 0x44, 0x00}, // PwrOn XPLL
|
||
{0x64, 0x40, 0x00}, // PwrOn IPLL
|
||
|
||
// PLL Reset OFF
|
||
{0x61, 0x10, 0x00}, // DRV_RST
|
||
{0x62, 0x08, 0x08}, // XP_RESETB
|
||
{0x64, 0x04, 0x04} // IP_RESETB
|
||
// {0x0F, 0x78, 0x08}, // PwrOn IACLK
|
||
};
|
||
|
||
static const RegSetEntry hdmi_tx_pg_1080p60_table[] = {
|
||
// 1920x1080@60.00Hz VIC = 16
|
||
{0x0F, 0xFF, 0x00},
|
||
{0x90, 0xFF, 0x76},
|
||
{0x91, 0xFF, 0x89},
|
||
{0x92, 0xFF, 0xC0},
|
||
{0x93, 0xFF, 0x40},
|
||
{0x94, 0xFF, 0x80},
|
||
{0x95, 0xFF, 0x00},
|
||
{0x96, 0xFF, 0x2C},
|
||
{0x97, 0xFF, 0x00},
|
||
{0x98, 0xFF, 0x64},
|
||
{0x99, 0xFF, 0x04},
|
||
{0x9A, 0xFF, 0x28},
|
||
{0x9B, 0xFF, 0x60},
|
||
{0x9C, 0xFF, 0x40},
|
||
{0x9D, 0xFF, 0xFF},
|
||
{0x9E, 0xFF, 0xFF},
|
||
{0x9F, 0xFF, 0xFF},
|
||
{0xA0, 0xFF, 0x00},
|
||
{0xA1, 0xFF, 0x50},
|
||
{0xA2, 0xFF, 0xFF},
|
||
{0xA3, 0xFF, 0xFF},
|
||
{0xA4, 0xFF, 0x4C},
|
||
{0xA5, 0xFF, 0x04},
|
||
{0xA6, 0xFF, 0xF0},
|
||
{0xB1, 0xFF, 0x00},
|
||
{0xB2, 0xFF, 0x00},
|
||
{0xA9, 0xFF, 0x70},
|
||
{0xAA, 0xFF, 0x00},
|
||
{0xAB, 0xFF, 0x00},
|
||
{0xAC, 0xFF, 0x00},
|
||
{0xAF, 0xFF, 0x00},
|
||
{0xB0, 0xFF, 0x00}
|
||
};
|
||
|
||
static const RegSetEntry hdmi_tx_pg_720p60_table[] = {
|
||
// PatGen\fmt4_PatGen.c
|
||
// 1280x720@60.00Hz VIC = 4
|
||
{0x0F, 0x01, 0x00},
|
||
{0x90, 0xFF, 0x16},
|
||
{0x91, 0xFF, 0x67},
|
||
{0x92, 0xFF, 0x04},
|
||
{0x93, 0xFF, 0x04},
|
||
{0x94, 0xFF, 0x61},
|
||
{0x95, 0xFF, 0x00},
|
||
{0x96, 0xFF, 0x28},
|
||
{0x97, 0xFF, 0x00},
|
||
{0x98, 0xFF, 0xED},
|
||
{0x99, 0xFF, 0x02},
|
||
{0x9A, 0xFF, 0x18},
|
||
{0x9B, 0xFF, 0xE8},
|
||
{0x9C, 0xFF, 0x20},
|
||
{0x9D, 0xFF, 0xFF},
|
||
{0x9E, 0xFF, 0xFF},
|
||
{0x9F, 0xFF, 0xFF},
|
||
{0xA0, 0xFF, 0x00},
|
||
{0xA1, 0xFF, 0x50},
|
||
{0xA2, 0xFF, 0xFF},
|
||
{0xA3, 0xFF, 0xFF},
|
||
{0xA4, 0xFF, 0x39},
|
||
{0xA5, 0xFF, 0x03},
|
||
{0xA6, 0xFF, 0xF0},
|
||
{0xB1, 0xFF, 0x00},
|
||
{0xB2, 0xFF, 0x00},
|
||
{0xA9, 0xFF, 0x70},
|
||
{0xAA, 0xFF, 0x00},
|
||
{0xAB, 0xFF, 0x00},
|
||
{0xAC, 0xFF, 0x00},
|
||
{0xAF, 0xFF, 0x00},
|
||
{0xB0, 0xFF, 0x00}
|
||
};
|
||
static const RegSetEntry hdmi_tx_pg_480p60_table[] = {
|
||
// PatGen\fmt2_PatGen.c
|
||
// 720x480@59.94Hz VIC = 2
|
||
{0x0F, 0x01, 0x00},
|
||
{0x90, 0xFF, 0x90},
|
||
{0x91, 0xFF, 0x35},
|
||
{0x92, 0xFF, 0x7A},
|
||
{0x93, 0xFF, 0x4A},
|
||
{0x94, 0xFF, 0x30},
|
||
{0x95, 0xFF, 0x00},
|
||
{0x96, 0xFF, 0x3E},
|
||
{0x97, 0xFF, 0x00},
|
||
{0x98, 0xFF, 0x0C},
|
||
{0x99, 0xFF, 0x02},
|
||
{0x9A, 0xFF, 0x23},
|
||
{0x9B, 0xFF, 0x03},
|
||
{0x9C, 0xFF, 0x20},
|
||
{0x9D, 0xFF, 0x30},
|
||
{0x9E, 0xFF, 0x10},
|
||
{0x9F, 0xFF, 0x42},
|
||
{0xA0, 0xFF, 0x00},
|
||
{0xA1, 0xFF, 0x60},
|
||
{0xA2, 0xFF, 0x0D},
|
||
{0xA3, 0xFF, 0x32},
|
||
{0xA4, 0xFF, 0xAC},
|
||
{0xA5, 0xFF, 0x01},
|
||
{0xA6, 0xFF, 0x10},
|
||
{0xB1, 0xFF, 0x00},
|
||
{0xB2, 0xFF, 0x00},
|
||
// {0xA9, 0xFF, 0x7F},
|
||
{0xA9, 0xFF, 0x70},
|
||
{0xAA, 0xFF, 0x00},
|
||
{0xAB, 0xFF, 0x00},
|
||
{0xAC, 0xFF, 0x00},
|
||
{0xAF, 0xFF, 0x00},
|
||
{0xB0, 0xFF, 0x00}
|
||
};
|
||
|
||
#ifdef DETECT_VSYNC_CHG_IN_SAV
|
||
static bool EnSavVSync = false ;
|
||
#endif
|
||
|
||
/* Period of hdcp checks (to ensure we're still authenticated) */
|
||
#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16)
|
||
#define DRM_HDCP2_CHECK_PERIOD_MS 500
|
||
|
||
/* Shared lengths/masks between HDMI/DVI/DisplayPort */
|
||
#define DRM_HDCP_AN_LEN 8
|
||
#define DRM_HDCP_BSTATUS_LEN 2
|
||
#define DRM_HDCP_KSV_LEN 5
|
||
#define DRM_HDCP_RI_LEN 2
|
||
#define DRM_HDCP_V_PRIME_PART_LEN 4
|
||
#define DRM_HDCP_V_PRIME_NUM_PARTS 5
|
||
#define DRM_HDCP_NUM_DOWNSTREAM(x) (x & 0x7f)
|
||
#define DRM_HDCP_MAX_CASCADE_EXCEEDED(x) (x & BIT(3))
|
||
#define DRM_HDCP_MAX_DEVICE_EXCEEDED(x) (x & BIT(7))
|
||
|
||
/* Slave address for the HDCP registers in the receiver */
|
||
#define DRM_HDCP_DDC_ADDR 0x3A
|
||
|
||
/* Value to use at the end of the SHA-1 bytestream used for repeaters */
|
||
#define DRM_HDCP_SHA1_TERMINATOR 0x80
|
||
|
||
/* HDCP register offsets for HDMI/DVI devices */
|
||
#define DRM_HDCP_DDC_BKSV 0x00
|
||
#define DRM_HDCP_DDC_RI_PRIME 0x08
|
||
#define DRM_HDCP_DDC_AKSV 0x10
|
||
#define DRM_HDCP_DDC_AN 0x18
|
||
#define DRM_HDCP_DDC_V_PRIME(h) (0x20 + h * 4)
|
||
#define DRM_HDCP_DDC_BCAPS 0x40
|
||
#define DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT BIT(6)
|
||
#define DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY BIT(5)
|
||
#define DRM_HDCP_DDC_BSTATUS 0x41
|
||
#define DRM_HDCP_DDC_KSV_FIFO 0x43
|
||
|
||
#define MAX_HDCP_DOWN_STREAM_COUNT 10
|
||
#define HDCP_SHA1_FIFO_LEN (MAX_HDCP_DOWN_STREAM_COUNT * 5 + 10)
|
||
#define HDMI_TX_HDCP_RETRY 3
|
||
#define HDMI_TX_PCLK_DIV2 false
|
||
|
||
#ifndef __linux__
|
||
|
||
extern const struct drm_display_mode edid_cea_modes[];
|
||
|
||
#endif
|
||
|
||
struct it6161 {
|
||
struct device *dev;
|
||
struct drm_bridge bridge;
|
||
struct i2c_client *i2c_mipi_rx;
|
||
struct i2c_client *i2c_hdmi_tx;
|
||
struct i2c_client *i2c_cec;
|
||
struct edid *edid;
|
||
struct drm_connector connector;
|
||
struct mutex mode_lock;
|
||
struct regmap *regmap_mipi_rx;
|
||
struct regmap *regmap_hdmi_tx;
|
||
struct regmap *regmap_cec;
|
||
u32 it6161_addr_hdmi_tx;
|
||
u32 it6161_addr_cec;
|
||
struct device_node *host_node;
|
||
struct mipi_dsi_device *dsi;
|
||
struct completion wait_hdcp_event;
|
||
struct completion wait_edid_complete;
|
||
struct delayed_work hdcp_work;
|
||
struct work_struct wait_hdcp_ksv_list;
|
||
u8 hdmi_tx_hdcp_retry;
|
||
/* kHz */
|
||
u32 hdmi_tx_rclk;
|
||
/* kHz */
|
||
u32 hdmi_tx_pclk;
|
||
/* kHz */
|
||
u32 mipi_rx_mclk;
|
||
/* kHz */
|
||
u32 mipi_rx_rclk;
|
||
/* kHz */
|
||
u32 mipi_rx_pclk;
|
||
struct drm_display_mode mipi_rx_p_display_mode;
|
||
struct drm_display_mode hdmi_tx_display_mode;
|
||
struct drm_display_mode source_display_mode;
|
||
struct hdmi_avi_infoframe source_avi_infoframe;
|
||
u32 vic;
|
||
u8 mipi_rx_lane_count;
|
||
bool is_repeater;
|
||
u8 hdcp_downstream_count;
|
||
u8 bksv[DRM_HDCP_KSV_LEN];
|
||
u8 sha1_transform_input[HDCP_SHA1_FIFO_LEN];
|
||
u16 bstatus;
|
||
bool enable_drv_hold;
|
||
u8 hdmi_tx_output_color_space;
|
||
u8 hdmi_tx_input_color_space;
|
||
u8 hdmi_tx_mode;
|
||
u8 support_audio;
|
||
|
||
u8 bOutputAudioMode;
|
||
u8 bAudioChannelSwap;
|
||
u8 bAudioChannelEnable;
|
||
u8 bAudFs ;
|
||
u32 TMDSClock ;
|
||
u32 RCLK ;
|
||
#ifdef _SUPPORT_HDCP_REPEATER_
|
||
HDMITX_HDCP_State TxHDCP_State ;
|
||
u16 usHDCPTimeOut ;
|
||
u16 Tx_BStatus ;
|
||
#endif
|
||
u8 bAuthenticated:1 ;
|
||
bool hdmi_mode;
|
||
u8 bAudInterface;
|
||
|
||
struct gpio_desc *reset_gpio;
|
||
struct gpio_desc *enable_gpio;
|
||
struct gpio_desc *test_gpio;
|
||
|
||
struct timer_list timer;
|
||
struct delayed_work restart;
|
||
};
|
||
|
||
static struct it6161 *it6161;
|
||
//static struct it6161 *it6161_dump;
|
||
static struct drm_bridge *it6161_bridge;
|
||
|
||
static const struct regmap_range it6161_mipi_rx_bridge_volatile_ranges[] = {
|
||
{ .range_min = 0, .range_max = 0xFF },
|
||
};
|
||
|
||
static const struct regmap_access_table it6161_mipi_rx_bridge_volatile_table = {
|
||
.yes_ranges = it6161_mipi_rx_bridge_volatile_ranges,
|
||
.n_yes_ranges = ARRAY_SIZE(it6161_mipi_rx_bridge_volatile_ranges),
|
||
};
|
||
|
||
static const struct regmap_config it6161_mipi_rx_bridge_regmap_config = {
|
||
.reg_bits = 8,
|
||
.val_bits = 8,
|
||
.volatile_table = &it6161_mipi_rx_bridge_volatile_table,
|
||
.cache_type = REGCACHE_NONE,
|
||
};
|
||
|
||
static const struct regmap_range it6161_hdmi_tx_bridge_volatile_ranges[] = {
|
||
{ .range_min = 0, .range_max = 0xFF },
|
||
};
|
||
|
||
static const struct regmap_access_table it6161_hdmi_tx_bridge_volatile_table = {
|
||
.yes_ranges = it6161_hdmi_tx_bridge_volatile_ranges,
|
||
.n_yes_ranges = ARRAY_SIZE(it6161_hdmi_tx_bridge_volatile_ranges),
|
||
};
|
||
|
||
static const struct regmap_config it6161_hdmi_tx_bridge_regmap_config = {
|
||
.reg_bits = 8,
|
||
.val_bits = 8,
|
||
.volatile_table = &it6161_hdmi_tx_bridge_volatile_table,
|
||
.cache_type = REGCACHE_NONE,
|
||
};
|
||
|
||
static const struct regmap_range it6161_cec_bridge_volatile_ranges[] = {
|
||
{ .range_min = 0, .range_max = 0xFF },
|
||
};
|
||
|
||
static const struct regmap_access_table it6161_cec_bridge_volatile_table = {
|
||
.yes_ranges = it6161_cec_bridge_volatile_ranges,
|
||
.n_yes_ranges = ARRAY_SIZE(it6161_cec_bridge_volatile_ranges),
|
||
};
|
||
|
||
static const struct regmap_config it6161_cec_bridge_regmap_config = {
|
||
.reg_bits = 8,
|
||
.val_bits = 8,
|
||
.volatile_table = &it6161_cec_bridge_volatile_table,
|
||
.cache_type = REGCACHE_NONE,
|
||
};
|
||
|
||
static int it6161_mipi_rx_read(struct it6161 *it6161, unsigned int reg_addr)
|
||
{
|
||
unsigned int value;
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_read(it6161->regmap_mipi_rx, reg_addr, &value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "mipi rx read failed reg[0x%x] err: %d", reg_addr,
|
||
err);
|
||
return err;
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
static int mipi_rx_read_word(struct it6161 *it6161, unsigned int reg)
|
||
{
|
||
int val_0, val_1;
|
||
|
||
val_0 = it6161_mipi_rx_read(it6161, reg);
|
||
|
||
if (val_0 < 0)
|
||
return val_0;
|
||
|
||
val_1 = it6161_mipi_rx_read(it6161, reg + 1);
|
||
|
||
if (val_1 < 0)
|
||
return val_1;
|
||
|
||
return (val_1 << 8) | val_0;
|
||
}
|
||
|
||
static int it6161_mipi_rx_write(struct it6161 *it6161, unsigned int reg_addr,
|
||
unsigned int reg_val)
|
||
{
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_write(it6161->regmap_mipi_rx, reg_addr, reg_val);
|
||
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "mipi rx write failed reg[0x%x] = 0x%x err = %d",
|
||
reg_addr, reg_val, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int it6161_mipi_rx_set_bits(struct it6161 *it6161, unsigned int reg,
|
||
unsigned int mask, unsigned int value)
|
||
{
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_update_bits(it6161->regmap_mipi_rx, reg, mask, value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(
|
||
dev, "mipi rx set reg[0x%x] = 0x%x mask = 0x%x failed err %d",
|
||
reg, value, mask, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#if 0
|
||
static void it6161_mipi_rx_dump(struct it6161 *it6161)
|
||
{
|
||
unsigned int i, j;
|
||
u8 regs[16];
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
it6161_debug("mipi rx dump:");
|
||
for (i = 0; i <= 0xff; i += 16) {
|
||
for (j = 0; j < 16; j++)
|
||
regs[j] = it6161_mipi_rx_read(it6161, i + j);
|
||
|
||
it6161_debug("[0x%02x] = %16ph", i, regs);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
static int it6161_hdmi_tx_read(struct it6161 *it6161, unsigned int reg_addr)
|
||
{
|
||
unsigned int value;
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_read(it6161->regmap_hdmi_tx, reg_addr, &value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "hdmi tx read failed reg[0x%x] err: %d", reg_addr,
|
||
err);
|
||
return err;
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
static int hdmi_tx_read_word(struct it6161 *it6161, unsigned int reg)
|
||
{
|
||
int val_0, val_1;
|
||
|
||
val_0 = it6161_hdmi_tx_read(it6161, reg);
|
||
|
||
if (val_0 < 0)
|
||
return val_0;
|
||
|
||
val_1 = it6161_hdmi_tx_read(it6161, reg + 1);
|
||
|
||
if (val_1 < 0)
|
||
return val_1;
|
||
|
||
return (val_1 << 8) | val_0;
|
||
}
|
||
|
||
#ifdef HDCP
|
||
static int it6161_hdmi_tx_burst_read(struct it6161 *it6161, unsigned int reg_addr, void *buffer, size_t size)
|
||
{
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
int ret;
|
||
|
||
ret = regmap_bulk_read(it6161->regmap_hdmi_tx, reg_addr, buffer, size);
|
||
if (ret < 0)
|
||
DRM_DEV_ERROR(dev, "hdmi tx burst read failed reg[0x%x] ret: %d",
|
||
reg_addr, ret);
|
||
|
||
return ret;
|
||
}
|
||
#endif
|
||
static int it6161_hdmi_tx_write(struct it6161 *it6161, unsigned int reg_addr,
|
||
unsigned int reg_val)
|
||
{
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
int err;
|
||
|
||
err = regmap_write(it6161->regmap_hdmi_tx, reg_addr, reg_val);
|
||
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "hdmi tx write failed reg[0x%x] = 0x%x err = %d",
|
||
reg_addr, reg_val, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#if 0
|
||
static int hdmi_tx_burst_write(struct it6161 *it6161, unsigned int reg_addr,
|
||
void *buffer, size_t size)
|
||
{
|
||
struct device *dev = &it6161->i2c_hdmi_tx->dev;
|
||
int ret;
|
||
|
||
ret = regmap_bulk_write(it6161->regmap_hdmi_tx, reg_addr,
|
||
(u8 *)buffer, size);
|
||
|
||
if (ret < 0) {
|
||
DRM_DEV_ERROR(dev, "hdmi tx burst write failed reg[0x%x] ret = %d",
|
||
reg_addr, ret);
|
||
return ret;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
static int it6161_hdmi_tx_set_bits(struct it6161 *it6161, unsigned int reg,
|
||
unsigned int mask, unsigned int value)
|
||
{
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_update_bits(it6161->regmap_hdmi_tx, reg, mask, value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(
|
||
dev, "hdmi tx set reg[0x%x] = 0x%x mask = 0x%x failed err %d",
|
||
reg, value, mask, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int inline it6161_hdmi_tx_change_bank(struct it6161 *it6161, int x)
|
||
{
|
||
return it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x03, x & 0x03);
|
||
}
|
||
|
||
#if 0
|
||
static void it6161_hdmi_tx_dump(struct it6161 *it6161, unsigned int bank)
|
||
{
|
||
unsigned int i, j;
|
||
u8 regs[16];
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
it6161_debug("hdmi tx dump bank: %d", bank);
|
||
it6161_hdmi_tx_change_bank(it6161, bank);
|
||
|
||
for (i = 0; i <= 0xff; i += 16) {
|
||
for (j = 0; j < 16; j++)
|
||
regs[j] = it6161_hdmi_tx_read(it6161, i + j);
|
||
|
||
it6161_debug("[0x%02x] = %16ph", i, regs);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
static int it6161_cec_read(struct it6161 *it6161, unsigned int reg_addr)
|
||
{
|
||
unsigned int value;
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_read(it6161->regmap_cec, reg_addr, &value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "cec read failed reg[0x%x] err: %d", reg_addr,
|
||
err);
|
||
return err;
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
static int it6161_cec_write(struct it6161 *it6161, unsigned int reg_addr,
|
||
unsigned int reg_val)
|
||
{
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_write(it6161->regmap_cec, reg_addr, reg_val);
|
||
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "cec write failed reg[0x%x] = 0x%x err = %d",
|
||
reg_addr, reg_val, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#if 0
|
||
static int it6161_cec_set_bits(struct it6161 *it6161, unsigned int reg,
|
||
unsigned int mask, unsigned int value)
|
||
{
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
err = regmap_update_bits(it6161->regmap_cec, reg, mask, value);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(
|
||
dev, "cec set reg[0x%x] = 0x%x mask = 0x%x failed err %d",
|
||
reg, value, mask, err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
#endif
|
||
|
||
static inline struct it6161 *connector_to_it6161(struct drm_connector *c)
|
||
{
|
||
return container_of(c, struct it6161, connector);
|
||
}
|
||
|
||
static inline struct it6161 *bridge_to_it6161(struct drm_bridge *bridge)
|
||
{
|
||
return container_of(bridge, struct it6161, bridge);
|
||
}
|
||
|
||
static void mipi_rx_logic_reset(struct it6161 *it6161)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x08, 0x08);
|
||
}
|
||
|
||
static void mipi_rx_logic_reset_release(struct it6161 *it6161)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x08, 0x00);
|
||
}
|
||
|
||
static void hdmi_tx_logic_reset(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0x04, 0x20, 0x20);
|
||
}
|
||
|
||
static void it6161_mipi_rx_int_mask_disable(struct it6161 *it6161)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_mipi_rx_write(it6161, 0x09, 0x00);
|
||
it6161_mipi_rx_write(it6161, 0x0A, 0x00);
|
||
it6161_mipi_rx_write(it6161, 0x0B, 0x00);
|
||
}
|
||
|
||
static void it6161_mipi_rx_int_mask_enable(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_mipi_rx_write(it6161, 0x09, EnMBPM ? 0x11 : 0xBF);
|
||
it6161_mipi_rx_write(it6161, 0x0A, 0xFF);
|
||
it6161_mipi_rx_write(it6161, 0x0B, 0x3F);
|
||
}
|
||
|
||
static void hdmi_tx_hdcp_int_mask_disable(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_INT_MASK2, B_TX_AUTH_FAIL_MASK | B_TX_AUTH_DONE_MASK | B_TX_KSVLISTCHK_MASK, B_TX_AUTH_FAIL_MASK | B_TX_AUTH_DONE_MASK | B_TX_KSVLISTCHK_MASK);
|
||
}
|
||
|
||
#ifdef HDCP
|
||
static void hdmi_tx_hdcp_int_mask_enable(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_INT_MASK2, B_TX_AUTH_FAIL_MASK | B_TX_AUTH_DONE_MASK | B_TX_KSVLISTCHK_MASK, ~(B_TX_AUTH_FAIL_MASK | B_TX_AUTH_DONE_MASK | B_TX_KSVLISTCHK_MASK));
|
||
}
|
||
#endif
|
||
/*
|
||
static void it6161_hdmi_tx_int_mask_disable(struct it6161 *it6161)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK1, 0xFF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK2, 0xFF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK3, 0xFF);
|
||
}
|
||
*/
|
||
static void it6161_hdmi_tx_int_mask_enable(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x03, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK1, ~(B_TX_AUDIO_OVFLW_MASK | B_TX_DDC_FIFO_ERR_MASK | B_TX_DDC_BUS_HANG_MASK | B_TX_HPD_MASK | B_TX_RXSEN_MASK));//0x7C);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK2, ~(B_TX_AUTH_FAIL_MASK | B_TX_AUTH_DONE_MASK | B_TX_KSVLISTCHK_MASK | B_TX_PKT_VID_UNSTABLE_MASK));
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_MASK3, ~B_TX_VIDSTABLE_MASK);
|
||
}
|
||
|
||
static void it6161_hdmi_tx_write_table(struct it6161 *it6161, const RegSetEntry table[], int size)
|
||
{
|
||
int i ;
|
||
|
||
for (i = 0; i < size; i++) {
|
||
if (table[i].mask == 0 && table[i].value == 0) {
|
||
msleep(table[i].offset);
|
||
} else if (table[i].mask == 0xFF) {
|
||
it6161_hdmi_tx_write(it6161, table[i].offset,
|
||
table[i].value);
|
||
} else {
|
||
it6161_hdmi_tx_set_bits(it6161, table[i].offset, table[i].mask,
|
||
table[i].value);
|
||
}
|
||
}
|
||
}
|
||
|
||
static inline void hdmi_tx_enable_pattern_generator(struct it6161 *it6161)
|
||
{
|
||
it6161_debug("enable pattern generator");
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA8, 0x01, 0x01);
|
||
}
|
||
|
||
static inline void hdmi_tx_disable_pattern_generator(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA8, 0x01, 0x00);
|
||
}
|
||
|
||
static inline void hdmi_tx_pattern_generator_setup_color(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA9, 0x3F, (HDMI_TX_PATTERN_COLLOR_B << 4) | (HDMI_TX_PATTERN_COLLOR_G << 2) | HDMI_TX_PATTERN_COLLOR_R);
|
||
}
|
||
|
||
static void hdmi_tx_setup_pattern_generator(struct it6161 *it6161)
|
||
{
|
||
switch (HDMI_TX_PATTERN_GENERATOR_FORMAT) {
|
||
case 2:
|
||
it6161_hdmi_tx_write_table(it6161, hdmi_tx_pg_480p60_table, sizeof(hdmi_tx_pg_480p60_table) / sizeof(RegSetEntry));
|
||
DRM_INFO("use 480p60 pattern");
|
||
break;
|
||
|
||
case 4:
|
||
it6161_hdmi_tx_write_table(it6161, hdmi_tx_pg_720p60_table, sizeof(hdmi_tx_pg_720p60_table) / sizeof(RegSetEntry));
|
||
DRM_INFO("use 720p60 pattern");
|
||
break;
|
||
|
||
case 16:
|
||
it6161_hdmi_tx_write_table(it6161, hdmi_tx_pg_1080p60_table, sizeof(hdmi_tx_pg_1080p60_table) / sizeof(RegSetEntry));
|
||
DRM_INFO("use 1080p60 pattern");
|
||
break;
|
||
|
||
default:
|
||
it6161_hdmi_tx_write_table(it6161, hdmi_tx_pg_1080p60_table, sizeof(hdmi_tx_pg_1080p60_table) / sizeof(RegSetEntry));
|
||
DRM_INFO("other format, will use 1080p60 pattern");
|
||
}
|
||
|
||
hdmi_tx_pattern_generator_setup_color(it6161);
|
||
hdmi_tx_enable_pattern_generator(it6161);
|
||
}
|
||
|
||
static void show_display_mode(struct it6161 *it6161, struct drm_display_mode *display_mode, u8 select)
|
||
{
|
||
char *name[3] = { "source output", "it6161 hdmi tx receive", "mipi rx p receive" };
|
||
|
||
DRM_INFO("%s timing:", name[select]);
|
||
DRM_INFO("timing name:%s", display_mode->name);
|
||
DRM_INFO("clock = %dkHz", display_mode->clock);
|
||
DRM_INFO("htotal = %d", display_mode->htotal);
|
||
DRM_INFO("hactive = %d", display_mode->hdisplay);
|
||
DRM_INFO("hfront_porch = %d", display_mode->hsync_start - display_mode->hdisplay);
|
||
DRM_INFO("hsyncw = %d", display_mode->hsync_end - display_mode->hsync_start);
|
||
DRM_INFO("hback_porch = %d", display_mode->htotal - display_mode->hsync_end);
|
||
|
||
DRM_INFO("vtotal = %d", display_mode->vtotal);
|
||
DRM_INFO("vactive = %d", display_mode->vdisplay);
|
||
DRM_INFO("vfront_porch = %d", display_mode->vsync_start - display_mode->vdisplay);
|
||
DRM_INFO("vsyncw = %d", display_mode->vsync_end - display_mode->vsync_start);
|
||
DRM_INFO("vback_porch = %d", display_mode->vtotal - display_mode->vsync_end);
|
||
DRM_INFO("drm_display_mode flags = 0x%04x", display_mode->flags);
|
||
|
||
}
|
||
|
||
static void inline it6161_set_interrupts_active_level(enum it6161_active_level level)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x0D, 0x02, level == HIGH ? 0x02 : 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x05, 0xC0, level == HIGH ? 0x80 : 0x40);
|
||
}
|
||
|
||
static void hdmi_tx_init(struct it6161 *it6161)
|
||
{
|
||
it6161_debug("init hdmi tx");
|
||
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_Init_Table, ARRAY_SIZE(HDMITX_Init_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_PwrOn_Table, ARRAY_SIZE(HDMITX_PwrOn_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_DefaultVideo_Table, ARRAY_SIZE(HDMITX_DefaultVideo_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_SetHDMI_Table, ARRAY_SIZE(HDMITX_SetHDMI_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_DefaultAVIInfo_Table, ARRAY_SIZE(HDMITX_DefaultAVIInfo_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_DeaultAudioInfo_Table, ARRAY_SIZE(HDMITX_DeaultAudioInfo_Table));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_Aud_CHStatus_LPCM_20bit_48Khz, ARRAY_SIZE(HDMITX_Aud_CHStatus_LPCM_20bit_48Khz));
|
||
it6161_hdmi_tx_write_table(it6161, HDMITX_AUD_SPDIF_2ch_24bit, ARRAY_SIZE(HDMITX_AUD_SPDIF_2ch_24bit));
|
||
|
||
#ifdef SUPPORT_CEC
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x8D, 0x01, 0x01);//it6161_hdmi_tx_write(it6161, 0xf, 0 ); //pet
|
||
|
||
Initial_Ext_Int1();
|
||
HDMITX_CEC_Init();
|
||
#endif // SUPPORT_CEC
|
||
}
|
||
|
||
static bool mipi_rx_get_m_video_stable(struct it6161 *it6161)
|
||
{
|
||
return !!(it6161_mipi_rx_read(it6161, 0x0D) & 0x10);
|
||
}
|
||
|
||
static bool mipi_rx_get_p_video_stable(struct it6161 *it6161)
|
||
{
|
||
return !!(it6161_mipi_rx_read(it6161, 0x0D) & 0x20);
|
||
}
|
||
|
||
static void mipi_rx_setup_polarity(struct it6161 *it6161)
|
||
{
|
||
struct drm_display_mode *display_mode = &it6161->source_display_mode;
|
||
u8 polarity;
|
||
|
||
polarity = ((display_mode->flags & DRM_MODE_FLAG_PHSYNC) == DRM_MODE_FLAG_PHSYNC) ? 0x01 : 0x00;
|
||
polarity |= ((display_mode->flags & DRM_MODE_FLAG_PVSYNC) == DRM_MODE_FLAG_PVSYNC) ? 0x02 : 0x00;
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x4E, 0x03, polarity);
|
||
}
|
||
|
||
static void mipi_rx_afe_configuration(struct it6161 *it6161, u8 data_id)
|
||
{
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
u8 MPLaneNum = (it6161->mipi_rx_lane_count - 1);
|
||
|
||
it6161_debug("afe configuration data_id:0x%02x", data_id);
|
||
|
||
if (data_id == RGB_18b) {
|
||
if( MPLaneNum==3 ) {
|
||
// if( EnMPx1PCLK )
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x02); // MPPCLKSel = 1; // 4-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
// {
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x02); // MPPCLKSel = 1; // 4-lane : MCLK = 1/1 PCLK
|
||
DRM_INFO("Solomon is impossible TXPLL= 9/2 PCLK !!! \n");
|
||
DRM_INFO("MCLK=3/4PCLK Change to MCLK=PCLK ...\n");
|
||
// }
|
||
} else if( MPLaneNum==1 ) {
|
||
// if( EnMPx1PCLK )
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x05); // MPPCLKSel = 6; // 2-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
// {
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x05); // MPPCLKSel = 6; // 2-lane : MCLK = 1/1 PCLK
|
||
DRM_INFO("IT6121 is impossible RXPLL= 2/9 PCLK !!! \n");
|
||
DRM_INFO("MCLK=3/4PCLK Change to MCLK=PCLK ...\n");
|
||
// }
|
||
} else if( MPLaneNum==0 ) {
|
||
// if( EnMPx1PCLK )
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x0b);// MPPCLKSel = 7; // 1-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x08); // MPPCLKSel = 8; // 1-lane : MCLK = 3/4 PCLK
|
||
}
|
||
} else {
|
||
if( MPLaneNum==3 ) {
|
||
// if( EnMPx1PCLK )
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x03);// MPPCLKSel = 0; // 4-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x02);// MPPCLKSel = 1; // 4-lane : MCLK = 3/4 PCLK
|
||
} else if( MPLaneNum==1 ) {
|
||
// if( EnMPx1PCLK )
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x07); // MPPCLKSel = 2; // 2-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x05); // MPPCLKSel = 3; // 2-lane : MCLK = 3/4 PCLK
|
||
} else if( MPLaneNum==0 ) {
|
||
// if( EnMPx1PCLK )
|
||
// it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x0f);// MPPCLKSel = 4; // 1-lane : MCLK = 1/1 PCLK
|
||
// else
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x1F, 0x0b); // MPPCLKSel = 5; // 1-lane : MCLK = 3/4 PCLK
|
||
}
|
||
}
|
||
}
|
||
|
||
static void mipi_rx_configuration(struct it6161 *it6161)
|
||
{
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
u8 mipi_lane_config = (it6161->mipi_rx_lane_count - 1);
|
||
|
||
//20200211 D0
|
||
it6161_mipi_rx_set_bits(it6161, 0x10, 0x0F, 0x0F);
|
||
msleep(1);//idle(100);
|
||
it6161_mipi_rx_set_bits(it6161, 0x10, 0x0F, 0x00);
|
||
|
||
// MPRX Software Reset
|
||
// it6161_mipi_rx_set_bits(it6161, 0x05, 0x07, 0x07);
|
||
// msleep(1);
|
||
// it6161_mipi_rx_set_bits(it6161, 0x05, 0x08, 0x08);
|
||
mipi_rx_logic_reset(it6161);
|
||
msleep(1);
|
||
mipi_rx_logic_reset_release(it6161);
|
||
|
||
it6161_mipi_rx_int_mask_disable(it6161);
|
||
|
||
/* setup INT pin: active low */
|
||
it6161_mipi_rx_set_bits(it6161, 0x0d, 0x02, 0x00);
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x0C, 0x0F, (MPLaneSwap<<3) + (MPPNSwap<<2) + mipi_lane_config);
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x11, 0x3F, (EnIOIDDQ<<5)+(EnStb2Rst<<4)+(EnExtStdby<<3)+(EnStandby<<2)+(InvPCLK<<1)+InvMCLK);
|
||
it6161_mipi_rx_set_bits(it6161, 0x12, 0x03, (PDREFCNT<<1)+PDREFCLK);
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x18, 0xf7, (RegEnSyncErr<<7)+(SkipStg<<4)+HSSetNum);
|
||
it6161_mipi_rx_set_bits(it6161, 0x19, 0xf3, (PPIDbgSel<<4)+(EnContCK<<1)+EnDeSkew);
|
||
it6161_mipi_rx_set_bits(it6161, 0x20, 0xf7, (EOTPSel<<4)+(RegEnDummyECC<<2)+(RegIgnrBlk<<1)+RegIgnrNull);
|
||
it6161_mipi_rx_set_bits(it6161, 0x21, 0x07, LMDbgSel);
|
||
|
||
// it6161_mipi_rx_set_bits(it6161, 0x44, 0x38, (MREC_Update<<5)+(PREC_Update<<4)+(REGSELDEF<<3));
|
||
it6161_mipi_rx_set_bits(it6161, 0x44, 0x3a, (MREC_Update<<5)+(PREC_Update<<4)+(REGSELDEF<<3)+(RegAutoSync<<1));//D0 20200211
|
||
it6161_mipi_rx_set_bits(it6161, 0x4B, 0x1f, (EnFReSync<<4)+(EnVREnh<<3)+EnVREnhSel);
|
||
it6161_mipi_rx_write(it6161, 0x4C, PPSFFRdStg);
|
||
it6161_mipi_rx_set_bits(it6161, 0x4D, 0x01, (PPSFFRdStg>>8)&0x01);
|
||
it6161_mipi_rx_set_bits(it6161, 0x4E, 0x0C, (EnVReSync<<3)+(EnHReSync<<2));
|
||
it6161_mipi_rx_set_bits(it6161, 0x4F, 0x03, EnFFAutoRst);
|
||
|
||
//it6161_mipi_rx_write(it6161, 0x27, MPVidType);
|
||
it6161_mipi_rx_set_bits(it6161, 0x70, 0x01, EnMAvg);
|
||
it6161_mipi_rx_write(it6161, 0x72, MShift);
|
||
it6161_mipi_rx_write(it6161, 0x73, PShift);
|
||
it6161_mipi_rx_set_bits(it6161, 0x80, 0x20, ENABLE_MIPI_RX_EXTERNAL_CLOCK << 5);
|
||
it6161_mipi_rx_write(it6161, 0x21, 0x00); //debug sel
|
||
// it6161_mipi_rx_set_bits(it6161, 0x84, 0x70, 0x70); // max swing
|
||
// it6161_mipi_rx_set_bits(it6161, 0x84, 0x70, 0x40); // def swing
|
||
it6161_mipi_rx_set_bits(it6161, 0x84, 0x70, 0x00); // min swing
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0xA0, 0x01, EnMBPM);
|
||
|
||
/* enable auto detect format */
|
||
it6161_mipi_rx_set_bits(it6161, 0x21, 0x08, 0x08);
|
||
|
||
|
||
// if( REGSELDEF == true )
|
||
// {
|
||
// DRM_INFO("REGSELDEF MODE !!! ...\n");
|
||
// PHFP = 0x10;
|
||
// PHSW = 0x3e;
|
||
// PHBP = 0x3c;
|
||
// it6161_mipi_rx_write(it6161, 0x30, PHFP); // HFP
|
||
// it6161_mipi_rx_write(it6161, 0x31, 0x80+((PHFP&0x3F00)>>8));
|
||
// it6161_mipi_rx_write(it6161, 0x32, PHSW); // HBP
|
||
// it6161_mipi_rx_write(it6161, 0x33, 0x80+((PHSW&0x3F00)>>8));
|
||
// it6161_mipi_rx_write(it6161, 0x34, PHBP); // HBP
|
||
// it6161_mipi_rx_write(it6161, 0x35, 0x80+((PHFP&0x3F00)>>8));
|
||
// }
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x70, 0x01, EnMAvg);
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x02, 0x02); // Video Clock Domain Reset
|
||
|
||
if( EnMBPM ) {
|
||
//HSW = pSetVTiming->HSyncWidth;
|
||
//VSW = pSetVTiming->VSyncWidth;
|
||
|
||
it6161_mipi_rx_write(it6161, 0xA1, 0x00); // HRS offset
|
||
it6161_mipi_rx_write(it6161, 0xA2, 0x00); // VRS offset
|
||
|
||
// it6161_mipi_rx_write(it6161, 0xA3, 44);//HSW); // HSW
|
||
// it6161_mipi_rx_write(it6161, 0xA5, 5);//VSW); // VSW
|
||
it6161_mipi_rx_write(it6161, 0xA3, 0x08);//0x10); // HSW
|
||
it6161_mipi_rx_write(it6161, 0xA5, 0x04); // VSw
|
||
|
||
// it6161_hdmi_tx_set_bits(it6161, 0xa9, 0xc0, (EnTBPM<<7)/* + (EnTxPatMux<<6)*/);
|
||
// it6161_hdmi_tx_set_bits(it6161, 0xbf, 0x80, (NRTXRCLK<<7));
|
||
}
|
||
if( MPForceStb == true ){
|
||
// mprxwr(0x30, HFP); // HSP
|
||
// mprxwr(0x31, 0x80+((HFP&0x3F00)>>8));
|
||
// mprxwr(0x32, HSW); // HSW
|
||
// mprxwr(0x33, 0x80+((HSW&0x3F00)>>8));
|
||
// mprxwr(0x34, HBP&0xFF); // HBP
|
||
// mprxwr(0x35, 0x80+((HBP&0x3F00)>>8));
|
||
// mprxwr(0x36, HDEW&0xFF); // HDEW
|
||
// mprxwr(0x37, 0x80+((HDEW&0x3F00)>>8));
|
||
// mprxwr(0x38, HVR2nd&0xFF); // HVR2nd
|
||
// mprxwr(0x39, 0x80+((HVR2nd&0x3F00)>>8));
|
||
|
||
// mprxwr(0x3A, VFP); // VSP
|
||
// mprxwr(0x3B, 0x80+((VFP&0x3F00)>>8));
|
||
// mprxwr(0x3C, VSW); // VSW
|
||
// mprxwr(0x3D, 0x80+((VSW&0x3F00)>>8));
|
||
// mprxwr(0x3E, VBP&0xFF); // VBP
|
||
// mprxwr(0x3F, 0x80+((VBP&0x3F00)>>8));
|
||
// mprxwr(0x40, VDEW&0xFF); // VDEW
|
||
// mprxwr(0x41, 0x80+((VDEW&0x3F00)>>8));
|
||
// mprxwr(0x42, VFP2nd&0xFF); // VFP2nd
|
||
// mprxwr(0x43, 0x80+((VFP2nd&0x3F00)>>8));
|
||
|
||
// mprxset(0x4e, 0x03, 0xC0+(VPol<<1)+HPol);
|
||
}
|
||
else
|
||
{
|
||
if( REGSELDEF == false ) {
|
||
it6161_mipi_rx_set_bits(it6161, 0x31, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x33, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x35, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x37, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x39, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x3A, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x3C, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x3E, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x41, 0x80, 0x00);
|
||
it6161_mipi_rx_set_bits(it6161, 0x43, 0x80, 0x00);
|
||
}
|
||
|
||
// mprxset(0x4e, 0x03, 0x00+(VPol<<1)+HPol);
|
||
}
|
||
}
|
||
|
||
static void mipi_rx_init(struct it6161 *it6161)
|
||
{
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
it6161_debug("init mpip rx");
|
||
mipi_rx_configuration(it6161);
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x03, 0x00); // Enable MPRX clock domain
|
||
}
|
||
|
||
static void hdmi_tx_video_reset(struct it6161 *it6161)
|
||
{
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
it6161_debug("%s reg04:0x%02x reg05:0x%02x reg6:0x%02x reg07:0x%02x reg08:0x%02x reg0e:0x%02x", __func__, it6161_hdmi_tx_read(it6161, 0x04), it6161_hdmi_tx_read(it6161, 0x05), it6161_hdmi_tx_read(it6161, 0x06), it6161_hdmi_tx_read(it6161, 0x07), it6161_hdmi_tx_read(it6161, 0x08), it6161_hdmi_tx_read(it6161, 0x0e));
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_VID_RST, B_HDMITX_VID_RST);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_VID_RST, 0x00);
|
||
msleep(10);
|
||
}
|
||
/*
|
||
static void hdmi_tx_audio_fifo_reset(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_AUD_RST, B_HDMITX_AUD_RST);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_AUD_RST, 0x00);
|
||
}
|
||
*/
|
||
/* DDC master will set to be host */
|
||
|
||
static void it6161_hdmi_tx_clear_ddc_fifo(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD, CMD_FIFO_CLR);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHOST, 0x00);
|
||
}
|
||
|
||
#ifdef HDCP
|
||
static void it6161_hdmi_tx_generate_ddc_sclk(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL,B_TX_MASTERDDC|B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD,CMD_GEN_SCLCLK);
|
||
}
|
||
#endif
|
||
static void hdmi_tx_generate_blank_timing(struct it6161 *it6161)
|
||
{
|
||
struct drm_display_mode *display_mode = &it6161->source_display_mode;
|
||
bool force_hdmi_tx_clock_stable = true, force_hdmi_tx_video_stable = true, hdmi_tx_by_pass_mode = false, de_generation = false, enable_de_only = true;
|
||
u8 polarity;
|
||
u16 hsync_start, hsync_end, vsync_start, vsync_end, htotal, hde_start, vtotal;
|
||
u16 vsync_start_2nd = 0, vsync_end_2nd = 0, vsync_rising_at_h_2nd;
|
||
|
||
it6161_debug("start %s", __func__);
|
||
polarity = ((display_mode->flags & DRM_MODE_FLAG_PHSYNC) == DRM_MODE_FLAG_PHSYNC) ? 0x02 : 0x00;
|
||
polarity |= ((display_mode->flags & DRM_MODE_FLAG_PVSYNC) == DRM_MODE_FLAG_PVSYNC) ? 0x04 : 0x00;
|
||
|
||
hsync_start = display_mode->hsync_start - display_mode->hdisplay - 1;
|
||
hsync_end = hsync_start + display_mode->hsync_end - display_mode->hsync_start;
|
||
vsync_rising_at_h_2nd = hsync_start + display_mode->htotal / 2;
|
||
hde_start = display_mode->htotal - display_mode->hsync_start;
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, 0xD1, 0x0C, force_hdmi_tx_clock_stable << 3 | force_hdmi_tx_video_stable << 2);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA9, 0x80, hdmi_tx_by_pass_mode << 7);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x90, 0x01, de_generation);
|
||
it6161_hdmi_tx_write(it6161, 0x91, vsync_rising_at_h_2nd >> 4);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x90, 0xF0, (vsync_rising_at_h_2nd & 0x00F) << 4);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x90, 0x06, polarity);
|
||
it6161_hdmi_tx_write(it6161, 0x95, (u8)hsync_start);
|
||
it6161_hdmi_tx_write(it6161, 0x96, (u8)hsync_end);
|
||
it6161_hdmi_tx_write(it6161, 0x97, (hsync_end & 0x0F00) >> 4 | hsync_start >> 8);
|
||
|
||
vsync_start = display_mode->vsync_start - display_mode->vdisplay;
|
||
vsync_end = display_mode->vsync_end - display_mode->vdisplay;
|
||
|
||
if ((display_mode->flags & DRM_MODE_FLAG_INTERLACE) != DRM_MODE_FLAG_INTERLACE) {
|
||
vsync_start_2nd = 0x0FFF;
|
||
vsync_end_2nd = 0x3F;
|
||
vtotal = display_mode->vtotal - 1;
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA5, 0x10, 0x00);
|
||
} else {
|
||
vtotal = display_mode->vtotal * 2;
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA5, 0x10, 0x10);
|
||
}
|
||
it6161_hdmi_tx_write(it6161, 0xA0, (u8)vsync_start);
|
||
it6161_hdmi_tx_write(it6161, 0xA1, (vsync_end & 0x0F) << 4 | vsync_start >> 8);
|
||
it6161_hdmi_tx_write(it6161, 0xA2, (u8)vsync_start_2nd);
|
||
it6161_hdmi_tx_write(it6161, 0xA6, (vsync_end_2nd & 0xF0) | vsync_end >> 4);
|
||
it6161_hdmi_tx_write(it6161, 0xA3, (vsync_end_2nd & 0x0F) << 4 | vsync_start_2nd >> 8);
|
||
it6161_hdmi_tx_write(it6161, 0xA4, vsync_rising_at_h_2nd);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xB1, 0x51, (hsync_end & 0x1000) >> 6 | (hsync_start & 0x1000) >> 8 | hde_start >> 12);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA5, 0x2F, enable_de_only << 5 | vsync_rising_at_h_2nd >> 8);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xB2, 0x05, (vsync_rising_at_h_2nd & 0x1000) >> 10 | (vsync_rising_at_h_2nd & 0x1000) >> 12);
|
||
|
||
htotal = display_mode->htotal - 1;
|
||
it6161_hdmi_tx_set_bits(it6161, 0x90, 0xF0, (htotal & 0x0F) << 4);
|
||
it6161_hdmi_tx_write(it6161, 0x91, (htotal & 0x0FF0) >> 4);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xB2, 0x01, (htotal & 0x1000) >> 12);
|
||
it6161_hdmi_tx_write(it6161, 0x98, vtotal & 0x0FF);
|
||
it6161_hdmi_tx_write(it6161, 0x99, (vtotal & 0xF00) >> 8);
|
||
}
|
||
|
||
/* force abort DDC and reset DDC bus */
|
||
|
||
static void it6161_hdmi_tx_abort_ddc(struct it6161 *it6161)
|
||
{
|
||
u8 cp_desire, sw_reset, ddc_master, retry = 2;
|
||
u8 uc, timeout, i;
|
||
|
||
it6161_debug("%s", __func__);
|
||
/* save the sw reset, ddc master and cp desire setting */
|
||
sw_reset = it6161_hdmi_tx_read(it6161, REG_TX_SW_RST);
|
||
cp_desire = it6161_hdmi_tx_read(it6161, REG_TX_HDCP_DESIRE);
|
||
ddc_master = it6161_hdmi_tx_read(it6161, REG_TX_DDC_MASTER_CTRL);
|
||
|
||
// it6161_hdmi_tx_write(it6161, REG_TX_HDCP_DESIRE,CPDesire&(~B_TX_CPDESIRE)); // @emily change order
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, sw_reset | B_TX_HDCP_RST_HDMITX); // @emily change order
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
|
||
|
||
/* do abort DDC */
|
||
for (i = 0; i < retry; i++) {
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD, CMD_DDC_ABORT);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD, CMD_GEN_SCLCLK);//hdmitxwr(0x15, 0x0A); //it6161A0 // Generate SCL Clock
|
||
|
||
for (timeout = 0; timeout < 200; timeout++) {
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_DDC_STATUS);
|
||
if (uc&B_TX_DDC_DONE)
|
||
break ;
|
||
|
||
if (uc & (B_TX_DDC_NOACK | B_TX_DDC_WAITBUS | B_TX_DDC_ARBILOSE)) {
|
||
DRM_INFO("it6161_hdmi_tx_abort_ddc Fail by reg16=%02X\n",(int)uc);//pet
|
||
break ;
|
||
}
|
||
/* delay 1 ms to stable */
|
||
msleep(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
static bool hdmi_tx_get_video_state(struct it6161 *it6161)
|
||
{
|
||
return !!(B_TXVIDSTABLE & it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS));
|
||
}
|
||
|
||
static bool inline hdmi_tx_get_sink_hpd(struct it6161 *it6161)
|
||
{
|
||
return !!(it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS) & B_TX_HPDETECT);
|
||
}
|
||
|
||
static bool it6161_ddc_op_finished(struct it6161 *it6161)
|
||
{
|
||
int reg16 = it6161_hdmi_tx_read(it6161, REG_TX_DDC_STATUS);
|
||
|
||
if (reg16 < 0)
|
||
return false;
|
||
|
||
return (reg16 & B_TX_DDC_DONE) == B_TX_DDC_DONE;
|
||
}
|
||
|
||
static int it6161_ddc_wait(struct it6161 *it6161)
|
||
{
|
||
int status;
|
||
unsigned long timeout;
|
||
//struct device *dev = &it6161->client->dev;
|
||
|
||
timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
|
||
|
||
while (!it6161_ddc_op_finished(it6161)) {
|
||
if (time_after(jiffies, timeout)) {
|
||
DRM_INFO("Timed out waiting AUX to finish");
|
||
return -ETIMEDOUT;
|
||
}
|
||
usleep_range(1000, 2000);
|
||
}
|
||
|
||
status = it6161_hdmi_tx_read(it6161, REG_TX_DDC_STATUS);
|
||
if (status < 0) {
|
||
DRM_INFO("Failed to read DDC channel: 0x%02x", status);
|
||
return status;
|
||
}
|
||
|
||
if(status & B_TX_DDC_DONE) {
|
||
return 0;
|
||
} else {
|
||
DRM_INFO("DDC error: 0x%02x", status);
|
||
return -EIO;
|
||
}
|
||
}
|
||
|
||
static void hdmi_tx_ddc_operation(struct it6161 *it6161, u8 addr, u8 offset, u8 size, u8 segment, u8 cmd)
|
||
{
|
||
size = min(size, (u8)DDC_FIFO_MAXREQ);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_HEADER, addr);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQOFF, offset);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQCOUNT, size);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_EDIDSEG, segment);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD, cmd);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: it6161_ddc_get_edid_operation
|
||
// Parameter: buffer - the pointer of buffer to receive EDID ucdata.
|
||
// segment - the segment of EDID readback.
|
||
// offset - the offset of EDID ucdata in the segment. in byte.
|
||
// size - the read back bytes count,cannot exceed 32
|
||
// Return: ER_SUCCESS if successfully getting EDID. ER_FAIL otherwise.
|
||
// Remark: function for read EDID ucdata from reciever.
|
||
// Side-Effect: DDC master will set to be HOST. DDC FIFO will be used and dirty.
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
static int it6161_ddc_get_edid_operation(struct it6161 *it6161, u8 *buffer, u8 segment, u8 offset, int size)
|
||
{
|
||
u8 status, i;
|
||
|
||
if(!buffer)
|
||
return -ENOMEM;
|
||
|
||
if(it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1) & B_TX_INT_DDC_BUS_HANG) {
|
||
DRM_INFO("Called it6161_hdmi_tx_abort_ddc()");
|
||
it6161_hdmi_tx_abort_ddc(it6161);
|
||
}
|
||
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
status = it6161_ddc_wait(it6161);
|
||
|
||
if (status < 0)
|
||
goto error;
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_EDID_ADDRESS, offset, size, segment, CMD_EDID_READ);
|
||
status = it6161_ddc_wait(it6161);
|
||
|
||
if (status < 0)
|
||
goto error;
|
||
|
||
for (i = 0; i < size; i++) {
|
||
status = it6161_hdmi_tx_read(it6161, REG_TX_DDC_READFIFO);
|
||
|
||
if (status < 0)
|
||
goto error;
|
||
|
||
buffer[i] = status;
|
||
}
|
||
|
||
return i;
|
||
|
||
error:
|
||
return status;
|
||
}
|
||
|
||
static int it6161_get_edid_block(void *data, u8 *buf, unsigned int block_num,
|
||
size_t len)
|
||
{
|
||
struct it6161 *it6161 = data;
|
||
u8 offset, ret, step = 8;
|
||
|
||
step = min(step, (u8)DDC_FIFO_MAXREQ);
|
||
DRM_INFO("[%s] edid block number:%d read step:%d", __func__, block_num, step);
|
||
|
||
for (offset = 0; offset < len; offset += step) {
|
||
ret = it6161_ddc_get_edid_operation(it6161, buf + offset, block_num / 2, (block_num % 2) * EDID_LENGTH + offset, step);
|
||
|
||
if(ret < 0)
|
||
return ret;
|
||
#ifdef __linux__
|
||
DRM_INFO("[0x%02x]: %*ph", offset, step, buf + offset);
|
||
#else
|
||
DRM_INFO("[0x%02x]:", offset);
|
||
|
||
for (ret = 0; ret < step; ret++)
|
||
printf(" 0x%02x", (buf + offset)[ret]);
|
||
printf("\n\r");
|
||
#endif
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void hdmi_tx_set_capability_from_edid_parse(struct it6161 *it6161)
|
||
{
|
||
struct drm_display_info *info = &it6161->connector.display_info;
|
||
|
||
it6161->hdmi_mode = drm_detect_hdmi_monitor(it6161->edid);
|
||
it6161->support_audio = drm_detect_monitor_audio(it6161->edid);
|
||
if (it6161->hdmi_tx_output_color_space == F_MODE_YUV444) {
|
||
if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) != DRM_COLOR_FORMAT_YCBCR444) {
|
||
it6161->hdmi_tx_output_color_space &= ~F_MODE_CLRMOD_MASK;
|
||
it6161->hdmi_tx_output_color_space |= F_MODE_RGB444;
|
||
}
|
||
}
|
||
|
||
if (it6161->hdmi_tx_output_color_space == F_MODE_YUV422) {
|
||
if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR422) != DRM_COLOR_FORMAT_YCBCR422) {
|
||
it6161->hdmi_tx_output_color_space &= ~F_MODE_CLRMOD_MASK;
|
||
it6161->hdmi_tx_output_color_space |= F_MODE_RGB444;
|
||
}
|
||
}
|
||
DRM_INFO("%s mode, monitor %ssupport audio, outputcolormode:%d color_formats:0x%08x color_depth:%d",
|
||
it6161->hdmi_mode ? "HDMI" : "DVI", it6161->support_audio ? "" : "not ", it6161->hdmi_tx_output_color_space, info->color_formats, info->bpc);
|
||
|
||
if ((info->color_formats & DRM_COLOR_FORMAT_RGB444) == DRM_COLOR_FORMAT_RGB444)
|
||
DRM_INFO("support RGB444 output");
|
||
if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) == DRM_COLOR_FORMAT_YCBCR444)
|
||
DRM_INFO("support YUV444 output");
|
||
if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR422) == DRM_COLOR_FORMAT_YCBCR422)
|
||
DRM_INFO("support YUV422 output");
|
||
}
|
||
|
||
static void it6161_variable_config(struct it6161 *it6161)
|
||
{
|
||
it6161->hdmi_tx_hdcp_retry = HDMI_TX_HDCP_RETRY;
|
||
it6161->hdmi_tx_mode = HDMI_TX_MODE;
|
||
it6161->mipi_rx_lane_count = MIPI_RX_LANE_COUNT;
|
||
}
|
||
|
||
#ifdef __linux__
|
||
|
||
static int it6161_get_modes(struct drm_connector *connector)
|
||
{
|
||
struct it6161 *it6161 = connector_to_it6161(connector);
|
||
int err, num_modes = 0, i, retry = 3;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
it6161_debug("%s start", __func__);
|
||
|
||
if (it6161->edid)
|
||
return drm_add_edid_modes(connector, it6161->edid);
|
||
mutex_lock(&it6161->mode_lock);
|
||
reinit_completion(&it6161->wait_edid_complete);
|
||
|
||
for (i = 0; i < retry; i++) {
|
||
it6161->edid =
|
||
drm_do_get_edid(&it6161->connector, it6161_get_edid_block, it6161);
|
||
|
||
if (it6161->edid)
|
||
break;
|
||
}
|
||
if (!it6161->edid) {
|
||
DRM_DEV_ERROR(dev, "Failed to read EDID");
|
||
goto unlock;
|
||
}
|
||
|
||
err = drm_connector_update_edid_property(connector, it6161->edid);
|
||
if (err) {
|
||
DRM_DEV_ERROR(dev, "Failed to update EDID property: %d", err);
|
||
goto unlock;
|
||
}
|
||
|
||
num_modes = drm_add_edid_modes(connector, it6161->edid);
|
||
|
||
unlock:
|
||
complete(&it6161->wait_edid_complete);
|
||
DRM_INFO("edid mode number:%d", num_modes);
|
||
mutex_unlock(&it6161->mode_lock);
|
||
|
||
return num_modes;
|
||
}
|
||
|
||
static const struct drm_connector_helper_funcs it6161_connector_helper_funcs = {
|
||
.get_modes = it6161_get_modes,
|
||
};
|
||
|
||
static enum drm_connector_status it6161_detect(struct drm_connector *connector,
|
||
bool force)
|
||
{
|
||
struct it6161 *it6161 = connector_to_it6161(connector);
|
||
enum drm_connector_status status = connector_status_disconnected;
|
||
bool hpd = hdmi_tx_get_sink_hpd(it6161);
|
||
|
||
DRM_INFO("hpd:%s", hpd ? "high" : "low");
|
||
//mutex_lock(&it6161->mode_lock);
|
||
|
||
if (hpd) {
|
||
it6161_variable_config(it6161);
|
||
status = connector_status_connected;
|
||
}
|
||
|
||
it6161_set_interrupts_active_level(HIGH);
|
||
it6161_mipi_rx_int_mask_enable(it6161);
|
||
it6161_hdmi_tx_int_mask_enable(it6161);
|
||
|
||
//mutex_lock(&it6161->mode_lock);
|
||
return status;
|
||
}
|
||
|
||
static const struct drm_connector_funcs it6161_connector_funcs = {
|
||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||
.detect = it6161_detect,
|
||
.destroy = drm_connector_cleanup,
|
||
.reset = drm_atomic_helper_connector_reset,
|
||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||
};
|
||
|
||
static int it6161_attach_dsi(struct it6161 *it6161)
|
||
{
|
||
struct mipi_dsi_host *host;
|
||
struct mipi_dsi_device *dsi;
|
||
int ret = 0;
|
||
const struct mipi_dsi_device_info info = { .type = "it6161",
|
||
};
|
||
|
||
host = of_find_mipi_dsi_host_by_node(it6161->host_node);
|
||
if (!host) {
|
||
DRM_INFO("it6161 failed to find dsi host\n");
|
||
return -EPROBE_DEFER;
|
||
}
|
||
|
||
dsi = mipi_dsi_device_register_full(host, &info);
|
||
if (IS_ERR(dsi)) {
|
||
DRM_INFO("it6161 failed to create dsi device\n");
|
||
ret = PTR_ERR(dsi);
|
||
goto err_dsi_device;
|
||
}
|
||
|
||
it6161->dsi = dsi;
|
||
|
||
dsi->lanes = 4;
|
||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
|
||
MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
|
||
|
||
ret = mipi_dsi_attach(dsi);
|
||
if (ret < 0) {
|
||
DRM_INFO("it6161 failed to attach dsi to host\n");
|
||
goto err_dsi_attach;
|
||
}
|
||
|
||
return 0;
|
||
|
||
err_dsi_attach:
|
||
mipi_dsi_device_unregister(dsi);
|
||
err_dsi_device:
|
||
return ret;
|
||
}
|
||
|
||
static int it6161_bridge_attach(struct drm_bridge *bridge,
|
||
enum drm_bridge_attach_flags flags)
|
||
{
|
||
struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
struct device *dev;
|
||
int err;
|
||
|
||
dev = &it6161->i2c_mipi_rx->dev;
|
||
if (!bridge->encoder) {
|
||
DRM_DEV_ERROR(dev, "Parent encoder object not found");
|
||
return -ENODEV;
|
||
}
|
||
|
||
err = drm_connector_init(bridge->dev, &it6161->connector,
|
||
&it6161_connector_funcs,
|
||
DRM_MODE_CONNECTOR_HDMIA);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "Failed to initialize connector: %d", err);
|
||
return err;
|
||
}
|
||
|
||
drm_connector_helper_add(&it6161->connector,
|
||
&it6161_connector_helper_funcs);
|
||
|
||
it6161->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||
|
||
err = drm_connector_attach_encoder(&it6161->connector, bridge->encoder);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "Failed to link up connector to encoder: %d",
|
||
err);
|
||
goto cleanup_connector;
|
||
}
|
||
|
||
err = drm_connector_register(&it6161->connector);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "Failed to register connector: %d", err);
|
||
goto cleanup_connector;
|
||
}
|
||
it6161_debug("%s finish", __func__);
|
||
|
||
return 0;
|
||
|
||
// unregister_connector:
|
||
// drm_connector_unregister(&it6161->connector);
|
||
cleanup_connector:
|
||
drm_connector_cleanup(&it6161->connector);
|
||
return err;
|
||
}
|
||
|
||
static void it6161_detach_dsi(struct it6161 *it6161)
|
||
{
|
||
mipi_dsi_detach(it6161->dsi);
|
||
mipi_dsi_device_unregister(it6161->dsi);
|
||
}
|
||
|
||
static void it6161_bridge_detach(struct drm_bridge *bridge)
|
||
{
|
||
struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
|
||
drm_connector_unregister(&it6161->connector);
|
||
drm_connector_cleanup(&it6161->connector);
|
||
it6161_detach_dsi(it6161);
|
||
}
|
||
|
||
static enum drm_mode_status
|
||
it6161_bridge_mode_valid(struct drm_bridge *bridge,
|
||
const struct drm_display_info *info,
|
||
const struct drm_display_mode *mode)
|
||
{
|
||
//struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
|
||
// if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||
// return MODE_NO_INTERLACE;
|
||
it6161_debug("%s\n", __func__);
|
||
// /* Max 1200p at 5.4 Ghz, one lane */
|
||
// if (mode->clock > MAX_PIXEL_CLK)
|
||
// return MODE_CLOCK_HIGH;
|
||
|
||
if (mode->clock == 27027)
|
||
return MODE_BAD;
|
||
|
||
if (mode->clock > 165000)
|
||
return MODE_CLOCK_HIGH;
|
||
|
||
//DRM_INFO("%s end", __func__);
|
||
|
||
return MODE_OK;
|
||
}
|
||
|
||
// static int it6161_send_video_infoframe(struct it6161 *it6161,
|
||
// struct hdmi_avi_infoframe *frame)
|
||
// {
|
||
// u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||
// int err;
|
||
// struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
// err = hdmi_avi_infoframe_pack(frame, buffer, sizeof(buffer));
|
||
// if (err < 0) {
|
||
// DRM_DEV_ERROR(dev, "Failed to pack AVI infoframe: %d\n", err);
|
||
// return err;
|
||
// }
|
||
|
||
// err = dptx_set_bits(it6161, 0xE8, 0x01, 0x00);
|
||
// if (err)
|
||
// return err;
|
||
|
||
// err = regmap_bulk_write(it6161->regmap_mipi_rx, 0xE9,
|
||
// buffer + HDMI_INFOFRAME_HEADER_SIZE,
|
||
// frame->length);
|
||
// if (err)
|
||
// return err;
|
||
|
||
// err = dptx_set_bits(it6161, 0xE8, 0x01, 0x01);
|
||
// if (err)
|
||
// return err;
|
||
|
||
// return 0;
|
||
// }
|
||
|
||
static void it6161_bridge_mode_set(struct drm_bridge *bridge,
|
||
const struct drm_display_mode *mode,
|
||
const struct drm_display_mode *adjusted_mode)
|
||
{
|
||
struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
struct drm_display_mode *display_mode = &it6161->source_display_mode;
|
||
int err;
|
||
|
||
mutex_lock(&it6161->mode_lock);
|
||
err = drm_hdmi_avi_infoframe_from_display_mode(&it6161->source_avi_infoframe, &it6161->connector,
|
||
mode);
|
||
if (err) {
|
||
DRM_DEV_ERROR(dev, "Failed to setup AVI infoframe: %d", err);
|
||
goto unlock;
|
||
}
|
||
|
||
//it6161->hdmi_tx_display_mode.base.id = adjusted_mode->base.id;
|
||
strlcpy(it6161->hdmi_tx_display_mode.name, adjusted_mode->name,
|
||
DRM_DISPLAY_MODE_LEN);
|
||
it6161->hdmi_tx_display_mode.type = adjusted_mode->type;
|
||
it6161->hdmi_tx_display_mode.flags = adjusted_mode->flags;
|
||
//err = it6161_send_video_infoframe(it6161, &frame);
|
||
strlcpy(display_mode->name, adjusted_mode->name,
|
||
DRM_DISPLAY_MODE_LEN);
|
||
display_mode->clock = mode->clock;
|
||
display_mode->hdisplay = mode->hdisplay;
|
||
display_mode->hsync_start = mode->hsync_start;
|
||
display_mode->hsync_end = mode->hsync_end;
|
||
display_mode->htotal = mode->htotal;
|
||
display_mode->vdisplay = mode->vdisplay;
|
||
display_mode->vsync_start = mode->vsync_start;
|
||
display_mode->vsync_end = mode->vsync_end;
|
||
display_mode->vtotal = mode->vtotal;
|
||
display_mode->flags = mode->flags;
|
||
it6161->vic = it6161->source_avi_infoframe.video_code;
|
||
DRM_INFO("config display mode clk: %d\n", display_mode->clock);
|
||
DRM_INFO("config display mode hdisplay: %d\n", display_mode->hdisplay);
|
||
DRM_INFO("config display mode hsync_start: %d\n", display_mode->hsync_start);
|
||
DRM_INFO("config display mode hsync_end: %d\n", display_mode->hsync_end);
|
||
DRM_INFO("config display mode htotal: %d\n", display_mode->htotal);
|
||
DRM_INFO("config display mode vdisplay: %d\n", display_mode->vdisplay);
|
||
DRM_INFO("config display mode vsync_start: %d\n", display_mode->vsync_start);
|
||
DRM_INFO("config display mode vsync_end: %d\n", display_mode->vsync_end);
|
||
DRM_INFO("config display mode vtotal: %d\n", display_mode->vtotal);
|
||
|
||
if (err)
|
||
DRM_DEV_ERROR(dev, "Failed to send AVI infoframe: %d", err);
|
||
|
||
unlock:
|
||
mutex_unlock(&it6161->mode_lock);
|
||
}
|
||
|
||
static void it6161_bridge_enable(struct drm_bridge *bridge)
|
||
{
|
||
struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
it6161_bridge = bridge;
|
||
|
||
it6161_debug("%s start", __func__);
|
||
mipi_rx_init(it6161);//allen
|
||
hdmi_tx_init(it6161);//allen
|
||
it6161_set_interrupts_active_level(HIGH);
|
||
it6161_mipi_rx_int_mask_enable(it6161);
|
||
it6161_hdmi_tx_int_mask_enable(it6161);
|
||
|
||
it6161_debug("%s start restart delayed work\n", __func__);
|
||
schedule_delayed_work(&it6161->restart, msecs_to_jiffies(2000));
|
||
|
||
//if (enable_de_only)
|
||
// hdmi_tx_generate_blank_timing(it6161);
|
||
|
||
//hdmi_tx_video_reset(it6161);
|
||
// if (!it6161->enable_drv_hold) {
|
||
// it6161_int_mask_on(it6161);
|
||
// dptx_sys_chg(it6161, SYS_HPD);
|
||
// }
|
||
}
|
||
|
||
static void it6161_bridge_disable(struct drm_bridge *bridge)
|
||
{
|
||
struct it6161 *it6161 = bridge_to_it6161(bridge);
|
||
|
||
it6161_debug("%s start", __func__);//----TODO
|
||
mipi_rx_logic_reset(it6161);
|
||
hdmi_tx_logic_reset(it6161);
|
||
it6161_set_interrupts_active_level(HIGH);
|
||
it6161_mipi_rx_int_mask_enable(it6161);
|
||
it6161_hdmi_tx_int_mask_enable(it6161);//---
|
||
//kfree(it6161->edid);
|
||
//it6161->edid = NULL;
|
||
}
|
||
|
||
static const struct drm_bridge_funcs it6161_bridge_funcs = {
|
||
.attach = it6161_bridge_attach,
|
||
.detach = it6161_bridge_detach,
|
||
.mode_valid = it6161_bridge_mode_valid,
|
||
.mode_set = it6161_bridge_mode_set,
|
||
.enable = it6161_bridge_enable,// set NULL for old linux version
|
||
.disable = it6161_bridge_disable,
|
||
};
|
||
|
||
#endif
|
||
|
||
#define InitCEC() it6161_hdmi_tx_write(it6161, 0x8D, (CEC_I2C_SLAVE_ADDR|0x01))//HDMITX_SetI2C_Byte(0x8D, 0x01, 0x01)//HDMITX_SetI2C_Byte(0x0F, 0x08, 0x00)
|
||
#define DisableCEC() it6161_hdmi_tx_set_bits(it6161, 0x8D, 0x01, 0x00)//HDMITX_SetI2C_Byte(0x0F, 0x08, 0x08)
|
||
|
||
static bool it6161_check_device_ready(struct it6161 *it6161)
|
||
{
|
||
u8 Vendor_ID[2], Device_ID[2];
|
||
|
||
Vendor_ID[0] = it6161_mipi_rx_read(it6161, 0x00);
|
||
Vendor_ID[1] = it6161_mipi_rx_read(it6161, 0x01);
|
||
Device_ID[0] = it6161_mipi_rx_read(it6161, 0x02);
|
||
Device_ID[1] = it6161_mipi_rx_read(it6161, 0x03);
|
||
// Version_ID = MIPIRX_ReadI2C_Byte(0x04);
|
||
if (Vendor_ID[0] == 0x54 && Vendor_ID[1] == 0x49 && Device_ID[0] == 0x61 && Device_ID[1] == 0x61)
|
||
{
|
||
DRM_INFO("Find 6161 revision: 0x%2x", (u32)it6161_mipi_rx_read(it6161, 0x04));
|
||
return true;
|
||
}
|
||
DRM_INFO("find it6161 Fail");
|
||
return false;
|
||
}
|
||
|
||
static u32 hdmi_tx_calc_rclk(struct it6161 *it6161)//in c code: cal_txrclk
|
||
{
|
||
// u8 uc ;
|
||
int i ;
|
||
long sum = 0, RCLKCNT, TimeLoMax, retry = 5;
|
||
|
||
InitCEC();
|
||
// it6161_hdmi_tx_write(it6161, 0x8D, (CEC_I2C_SLAVE_ADDR|0x01));// Enable CRCLK
|
||
msleep(10);
|
||
|
||
for (i = 0; i < retry; i++) {
|
||
// uc = it6161_cec_read(it6161, 0x09) & 0xFE ;
|
||
it6161_cec_write(it6161, 0x09, 1);
|
||
msleep(100);
|
||
it6161_cec_write(it6161, 0x09, 0);
|
||
RCLKCNT = it6161_cec_read(it6161, 0x47);
|
||
RCLKCNT <<= 8 ;
|
||
RCLKCNT |= it6161_cec_read(it6161, 0x46);
|
||
RCLKCNT <<= 8 ;
|
||
RCLKCNT |= it6161_cec_read(it6161, 0x45);
|
||
// DRM_INFO1(("RCLK = %d\n",RCLKCNT) );
|
||
sum += RCLKCNT ;
|
||
}
|
||
sum /= retry;
|
||
RCLKCNT = sum/1000;
|
||
it6161_cec_write(it6161, 0x0C, (RCLKCNT & 0xFF));
|
||
|
||
DisableCEC();
|
||
|
||
// it6161->hdmi_tx_rclk = (sum << 4) / 108;//actually nxp platform msleep(100) is 108ms
|
||
it6161->hdmi_tx_rclk = (sum << 4) / 104;//actually nxp platform msleep(100) is 108ms
|
||
DRM_INFO("hdmi tx rclk = %d.%dMHz", it6161->hdmi_tx_rclk / 1000, it6161->hdmi_tx_rclk % 1000);
|
||
|
||
TimeLoMax = (sum << 4)/10;//10*TxRCLK;
|
||
|
||
// add HDCP TimeLomax over-flow protection
|
||
if(TimeLoMax>0x3FFFF)
|
||
TimeLoMax = 0x3FFFF;
|
||
|
||
DRM_INFO("TimeLoMax=%08lx\n", TimeLoMax);
|
||
it6161_hdmi_tx_write(it6161, 0x47, (TimeLoMax&0xFF));
|
||
it6161_hdmi_tx_write(it6161, 0x48, ((TimeLoMax&0xFF00)>>8));
|
||
it6161_hdmi_tx_set_bits(it6161, 0x49, 0x03, ((TimeLoMax&0x30000)>>16));
|
||
|
||
return it6161->hdmi_tx_rclk;
|
||
}
|
||
|
||
static u32 hdmi_tx_calc_pclk(struct it6161 *it6161) //c code void cal_txclk( void )
|
||
{
|
||
u8 uc, RCLKFreqSelRead;
|
||
int div, i;
|
||
u32 sum , count;
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
// uc = it6161_hdmi_tx_read(it6161, 0x5F) & 0x80 ;
|
||
|
||
// if( ! uc )
|
||
// {
|
||
// return 0 ;
|
||
// }
|
||
RCLKFreqSelRead = (it6161_hdmi_tx_read(it6161, 0x5D) & 0x04)>>2;//hdmitxset(0x5D, 0x04, (RCLKFreqSel<<2));
|
||
/* PCLK Count Pre-Test */
|
||
it6161_hdmi_tx_set_bits(it6161, 0xD7, 0xF0, 0x80);
|
||
msleep(1);
|
||
it6161_hdmi_tx_set_bits(it6161, 0xD7, 0x80, 0x00);
|
||
|
||
count = it6161_hdmi_tx_read(it6161, 0xD7) & 0xF ;
|
||
count <<= 8 ;
|
||
count |= it6161_hdmi_tx_read(it6161, 0xD8);
|
||
|
||
if (RCLKFreqSelRead)
|
||
count <<= 1;
|
||
|
||
for ( div = 7 ; div > 0 ; div-- ) {
|
||
if (count < (1<<(11-div)))
|
||
break ;
|
||
}
|
||
|
||
if (div < 0)
|
||
{
|
||
div = 0;
|
||
}
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, 0xD7, 0x70, div<<4);
|
||
|
||
uc = it6161_hdmi_tx_read(it6161, 0xD7) & 0x7F ;
|
||
for( i = 0 , sum = 0 ; i < 100 ; i ++ )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, 0xD7, uc|0x80) ;
|
||
msleep(1);
|
||
it6161_hdmi_tx_write(it6161, 0xD7, uc) ;
|
||
|
||
count = it6161_hdmi_tx_read(it6161, 0xD7) & 0xF ;
|
||
count <<= 8 ;
|
||
count |= it6161_hdmi_tx_read(it6161, 0xD8);
|
||
if (RCLKFreqSelRead)
|
||
{
|
||
count <<= 1;
|
||
}
|
||
sum += count;
|
||
}
|
||
sum /= 100;
|
||
count = sum;
|
||
|
||
it6161->hdmi_tx_pclk = it6161->hdmi_tx_rclk * 128 / count * 16 ;//128*16=2048
|
||
it6161->hdmi_tx_pclk *= (1<<div);
|
||
|
||
// if( it6161_hdmi_tx_read(it6161, 0x70) & 0x10 )
|
||
// {
|
||
// it6161->hdmi_tx_pclk /= 2 ;
|
||
// }
|
||
|
||
DRM_INFO("hdmi tx pclk = %d.%dMHz", it6161->hdmi_tx_pclk / 1000, it6161->hdmi_tx_pclk % 1000);
|
||
return it6161->hdmi_tx_pclk;
|
||
}
|
||
|
||
static void hdmi_tx_get_display_mode(struct it6161 *it6161)
|
||
{
|
||
struct drm_display_mode *display_mode = &it6161->hdmi_tx_display_mode;
|
||
u32 hsyncpol, vsyncpol, interlaced;
|
||
u32 htotal, hdes, hdee, hsyncw, hactive, hfront_porch, H2ndVRRise;
|
||
u32 vtotal, vdes, vdee, vsyncw, vactive, vfront_porch, vdes2nd, vdee2nd, vsyncw2nd, VRS2nd;
|
||
u32 vdew2nd, vfph2nd, vbph2nd;
|
||
u8 rega9;
|
||
|
||
hdmi_tx_calc_rclk(it6161);
|
||
hdmi_tx_calc_pclk(it6161);
|
||
|
||
/* enable video timing read back */
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA8, 0x08, 0x08);
|
||
|
||
rega9 = it6161_hdmi_tx_read(it6161, 0xa9);
|
||
|
||
hsyncpol = rega9 & 0x01;
|
||
vsyncpol = (rega9 & 0x02) >> 1;
|
||
interlaced = (rega9 & 0x04) >> 2;
|
||
|
||
htotal = hdmi_tx_read_word(it6161, 0x98) & 0x0FFF;
|
||
hdes = hdmi_tx_read_word(it6161, 0x90) & 0x0FFF;
|
||
hdee = hdmi_tx_read_word(it6161, 0x92) & 0x0FFF;
|
||
hsyncw = hdmi_tx_read_word(it6161, 0x94) & 0x0FFF;
|
||
hactive = hdee - hdes;
|
||
hfront_porch = htotal - hdee;
|
||
|
||
vtotal = hdmi_tx_read_word(it6161, 0xA6) & 0x0FFF;
|
||
vdes = hdmi_tx_read_word(it6161, 0x9C) & 0x0FFF;
|
||
vdee = hdmi_tx_read_word(it6161, 0x9E) & 0x0FFF;
|
||
vsyncw = it6161_hdmi_tx_read(it6161, 0xA0);
|
||
vactive = vdee - vdes;
|
||
vfront_porch = (interlaced == 0x01) ? (vtotal / 2 - vdee) : (vtotal - vdee);
|
||
|
||
display_mode->clock = it6161->hdmi_tx_pclk;
|
||
display_mode->hdisplay = hactive;
|
||
display_mode->hsync_start = hactive + hfront_porch;
|
||
display_mode->hsync_end = hactive + hfront_porch + hsyncw;
|
||
display_mode->htotal = htotal;
|
||
display_mode->vdisplay = vactive;
|
||
display_mode->vsync_start = vactive + vfront_porch;
|
||
display_mode->vsync_end = vactive + vfront_porch + vsyncw;
|
||
display_mode->vtotal = vtotal;
|
||
display_mode->flags = ((hsyncpol == 0x01) ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC) |
|
||
((vsyncpol == 0x01) ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC) |
|
||
((interlaced == 0x01) ? DRM_MODE_FLAG_INTERLACE : 0x00);
|
||
|
||
if (interlaced) {
|
||
vdes2nd = hdmi_tx_read_word(it6161, 0xA2) & 0x0FFF;
|
||
vdee2nd = hdmi_tx_read_word(it6161, 0xA4) & 0x0FFF;
|
||
VRS2nd = hdmi_tx_read_word(it6161, 0xB1) & 0x0FFF;
|
||
vsyncw2nd = it6161_hdmi_tx_read(it6161, 0xA1);
|
||
H2ndVRRise = hdmi_tx_read_word(it6161, 0x96) & 0x0FFF;
|
||
vdew2nd = vdee2nd-vdes2nd;
|
||
vfph2nd = VRS2nd-vdee;
|
||
vbph2nd = vdes2nd-VRS2nd-vsyncw2nd;
|
||
DRM_INFO("vdew2nd = %d\n", vdew2nd);
|
||
DRM_INFO("vfph2nd = %d\n", vfph2nd);
|
||
DRM_INFO("VSyncW2nd = %d\n", vsyncw2nd);
|
||
DRM_INFO("vbph2nd = %d\n", vbph2nd);
|
||
DRM_INFO("H2ndVRRise = %d\n", H2ndVRRise);
|
||
}
|
||
|
||
/* disable video timing read back */
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA8, 0x08, 0x00);
|
||
}
|
||
|
||
static void it6161_hdmi_tx_set_av_mute(struct it6161 *it6161, u8 bEnable)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_GCP,B_TX_SETAVMUTE, bEnable?B_TX_SETAVMUTE:0 );
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_GENERAL_CTRL,B_TX_ENABLE_PKT|B_TX_REPEAT_PKT);
|
||
}
|
||
|
||
#ifdef HDCP
|
||
#ifdef SUPPORT_SHA
|
||
static u8 SHABuff[64] ;
|
||
static u8 V[20] ;
|
||
static u8 KSVList[32] ;
|
||
static u8 Vr[20] ;
|
||
static u8 M0[8] ;
|
||
#endif
|
||
|
||
static bool hdmi_tx_hdcp_auth_status(struct it6161 *it6161)
|
||
{
|
||
return !!(it6161_hdmi_tx_read(it6161, REG_TX_AUTH_STAT) & B_TX_AUTH_DONE);
|
||
}
|
||
|
||
static bool hdmi_tx_hdcp_get_auth_done(struct it6161 *it6161)
|
||
{
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
}
|
||
|
||
static void hdmi_tx_hdcp_clear_auth_interrupt(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_INT_MASK2, B_TX_KSVLISTCHK_MASK | B_TX_AUTH_DONE_MASK | B_TX_AUTH_FAIL_MASK, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR0, B_TX_CLR_AUTH_FAIL | B_TX_CLR_AUTH_DONE | B_TX_CLR_KSVLISTCHK);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR1, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS, B_TX_INTACTDONE);
|
||
}
|
||
|
||
static void hdmi_tx_hdcp_reset_auth(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_HDCP_DESIRE, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_TX_HDCP_RST_HDMITX, B_TX_HDCP_RST_HDMITX);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
it6161_hdmi_tx_abort_ddc(it6161);
|
||
}
|
||
|
||
/* write anything to reg21 to enable HDCP authentication by HW */
|
||
|
||
static void hdmi_tx_hdcp_auth_fire(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHDCP); // MASTERHDCP,no need command but fire.
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUTHFIRE, 0x01);
|
||
}
|
||
|
||
/*
|
||
* Start the Cipher to free run for random number. When stop
|
||
* An is ready in Reg30
|
||
*/
|
||
|
||
static void hdmi_tx_hdcp_start_an_cipher(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AN_GENERATE, B_TX_START_CIPHER_GEN);
|
||
}
|
||
|
||
/* Stop the Cipher,and An is ready in Reg30 */
|
||
|
||
static void hdmi_tx_hdcp_stop_an_cipher(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AN_GENERATE, B_TX_STOP_CIPHER_GEN);
|
||
}
|
||
|
||
/*
|
||
* start An ciper random run at first,then stop it. Software can get
|
||
* An in reg30~reg38,the write to reg28~2F
|
||
*/
|
||
|
||
static void hdmi_tx_hdcp_generate_an(struct it6161 *it6161)
|
||
{
|
||
u8 an[DRM_HDCP_AN_LEN], i;
|
||
|
||
hdmi_tx_hdcp_start_an_cipher(it6161);
|
||
usleep_range(2000, 3000);
|
||
hdmi_tx_hdcp_stop_an_cipher(it6161);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
/* new An is ready in reg30 */
|
||
it6161_hdmi_tx_burst_read(it6161, REG_TX_AN_GEN, an, DRM_HDCP_AN_LEN);
|
||
|
||
for (i = 0; i < DRM_HDCP_AN_LEN; i++)
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AN + i, an[i]);
|
||
}
|
||
|
||
/*
|
||
* Parameter: pBCaps - pointer of byte to get BCaps.
|
||
* pBStatus - pointer of two bytes to get BStatus
|
||
* Return: ER_SUCCESS if successfully got BCaps and BStatus.
|
||
* Remark: get B status and capability from HDCP reciever via DDC bus.
|
||
*/
|
||
|
||
static SYS_STATUS hdmi_tx_get_hdcp_bcaps_bstatus(struct it6161 *it6161, u8 *pBCaps, u16 *pBStatus)
|
||
{
|
||
int ucdata;
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL,B_TX_MASTERDDC|B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_HEADER,DDC_HDCP_ADDRESS);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQOFF,0x40); // BCaps offset
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQCOUNT,3);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD);
|
||
|
||
ucdata = it6161_ddc_wait(it6161);
|
||
|
||
if (ucdata < 0) {
|
||
DRM_INFO("get bcaps/bstatus failed");
|
||
return ER_FAIL;
|
||
}
|
||
|
||
#if 1
|
||
ucdata = it6161_hdmi_tx_read(it6161, REG_TX_BSTAT + 1);
|
||
*pBStatus = (u16)ucdata;
|
||
*pBStatus <<= 8;
|
||
ucdata = it6161_hdmi_tx_read(it6161, REG_TX_BSTAT);
|
||
*pBStatus |= ((u16)ucdata & 0xFF);
|
||
*pBCaps = it6161_hdmi_tx_read(it6161, REG_TX_BCAP);
|
||
#else
|
||
*pBCaps = it6161_hdmi_tx_read(it6161, 0x17);
|
||
*pBStatus = it6161_hdmi_tx_read(it6161, 0x17) & 0xFF ;
|
||
*pBStatus |= (int)(it6161_hdmi_tx_read(it6161, 0x17)&0xFF)<<8;
|
||
DRM_INFO("hdmi_tx_get_hdcp_bcaps_bstatus(): ucdata = %02X\n",(int)it6161_hdmi_tx_read(it6161, 0x16));
|
||
#endif
|
||
#ifdef _SUPPORT_HDCP_REPEATER_
|
||
TxBstatus = *pBStatus;
|
||
#endif
|
||
return ER_SUCCESS;
|
||
}
|
||
|
||
/* Get bksv from HDCP sink */
|
||
|
||
static int hdmi_tx_hdcp_get_bksv(struct it6161 *it6161, u8 *bksv, size_t size)
|
||
{
|
||
int ret;
|
||
#ifdef _SUPPORT_HDMI_REPEATER_
|
||
int timeout;
|
||
#endif
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_HDCP_ADDRESS, DRM_HDCP_DDC_BKSV, size, 0x00, CMD_DDC_SEQ_BURSTREAD);
|
||
|
||
ret = it6161_ddc_wait(it6161);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("ddc get bksv failed");
|
||
return ret;
|
||
}
|
||
|
||
ret = it6161_hdmi_tx_burst_read(it6161, REG_TX_BKSV, bksv, size);
|
||
|
||
if (ret < 0)
|
||
DRM_INFO("i2c get bksv failed");
|
||
|
||
return ret;
|
||
|
||
#ifdef _SUPPORT_HDMI_REPEATER_
|
||
for (timeout = 0; timeout < 5; timeout++)
|
||
KSVList[timeout] = *(bksv+timeout);
|
||
#endif
|
||
}
|
||
|
||
static u8 countbit(u8 b)
|
||
{
|
||
u8 i, count ;
|
||
|
||
for (i = 0, count = 0; i < 8; i++) {
|
||
if (b & (1 << i))
|
||
count++;
|
||
}
|
||
|
||
return count;
|
||
}
|
||
|
||
static void hdmitx_hdcp_CancelRepeaterAuthenticate(struct it6161 *it6161)
|
||
{
|
||
it6161_debug("hdmitx_hdcp_CancelRepeaterAuthenticate");
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_abort_ddc(it6161);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, B_TX_LISTFAIL | B_TX_LISTDONE);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, 0x00);
|
||
hdmi_tx_hdcp_clear_auth_interrupt(it6161);
|
||
}
|
||
|
||
static void hdmitx_hdcp_ResumeRepeaterAuthenticate(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, B_TX_LISTDONE);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHDCP);
|
||
}
|
||
|
||
#define WCOUNT 17
|
||
u32 VH[5];
|
||
u32 w[WCOUNT];
|
||
|
||
#define rol(x,y)(((x)<< (y))| (((u32)x)>> (32-y)))
|
||
|
||
static void SHATransform(u32 * h)
|
||
{
|
||
int t;
|
||
u32 tmp;
|
||
|
||
h[0]=0x67452301;
|
||
h[1]=0xefcdab89;
|
||
h[2]=0x98badcfe;
|
||
h[3]=0x10325476;
|
||
h[4]=0xc3d2e1f0;
|
||
|
||
for (t=0; t < 20; t++){
|
||
if(t>=16)
|
||
{
|
||
tmp=w[(t - 3)% WCOUNT] ^ w[(t - 8)% WCOUNT] ^ w[(t - 14)% WCOUNT] ^ w[(t - 16)% WCOUNT];
|
||
w[(t)% WCOUNT]=rol(tmp,1);
|
||
}
|
||
DRM_INFO("w[%d]=%08X\n",t,w[(t)% WCOUNT]);
|
||
|
||
tmp=rol(h[0],5)+ ((h[1] & h[2])| (h[3] & ~h[1]))+ h[4] + w[(t)% WCOUNT] + 0x5a827999;
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
|
||
h[4]=h[3];
|
||
h[3]=h[2];
|
||
h[2]=rol(h[1],30);
|
||
h[1]=h[0];
|
||
h[0]=tmp;
|
||
|
||
}
|
||
for (t=20; t < 40; t++){
|
||
tmp=w[(t - 3)% WCOUNT] ^ w[(t - 8)% WCOUNT] ^ w[(t - 14)% WCOUNT] ^ w[(t - 16)% WCOUNT];
|
||
w[(t)% WCOUNT]=rol(tmp,1);
|
||
DRM_INFO("w[%d]=%08X\n",t,w[(t)% WCOUNT]);
|
||
tmp=rol(h[0],5)+ (h[1] ^ h[2] ^ h[3])+ h[4] + w[(t)% WCOUNT] + 0x6ed9eba1;
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
h[4]=h[3];
|
||
h[3]=h[2];
|
||
h[2]=rol(h[1],30);
|
||
h[1]=h[0];
|
||
h[0]=tmp;
|
||
}
|
||
for (t=40; t < 60; t++){
|
||
tmp=w[(t - 3)% WCOUNT] ^ w[(t - 8)% WCOUNT] ^ w[(t - 14)% WCOUNT] ^ w[(t - 16)% WCOUNT];
|
||
w[(t)% WCOUNT]=rol(tmp,1);
|
||
DRM_INFO("w[%d]=%08X\n",t,w[(t)% WCOUNT]);
|
||
tmp=rol(h[0],5)+ ((h[1] & h[2])| (h[1] & h[3])| (h[2] & h[3]))+ h[4] + w[(t)% WCOUNT] + 0x8f1bbcdc;
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
h[4]=h[3];
|
||
h[3]=h[2];
|
||
h[2]=rol(h[1],30);
|
||
h[1]=h[0];
|
||
h[0]=tmp;
|
||
}
|
||
for (t=60; t < 80; t++)
|
||
{
|
||
tmp=w[(t - 3)% WCOUNT] ^ w[(t - 8)% WCOUNT] ^ w[(t - 14)% WCOUNT] ^ w[(t - 16)% WCOUNT];
|
||
w[(t)% WCOUNT]=rol(tmp,1);
|
||
DRM_INFO("w[%d]=%08X\n",t,w[(t)% WCOUNT]);
|
||
tmp=rol(h[0],5)+ (h[1] ^ h[2] ^ h[3])+ h[4] + w[(t)% WCOUNT] + 0xca62c1d6;
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
h[4]=h[3];
|
||
h[3]=h[2];
|
||
h[2]=rol(h[1],30);
|
||
h[1]=h[0];
|
||
h[0]=tmp;
|
||
}
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
h[0] +=0x67452301;
|
||
h[1] +=0xefcdab89;
|
||
h[2] +=0x98badcfe;
|
||
h[3] +=0x10325476;
|
||
h[4] +=0xc3d2e1f0;
|
||
|
||
DRM_INFO("%08X %08X %08X %08X %08X\n",h[0],h[1],h[2],h[3],h[4]);
|
||
}
|
||
|
||
static void SHA_Simple(void *p,u32 len,u8 *output)
|
||
{
|
||
// SHA_State s;
|
||
u32 i,t;
|
||
u32 c;
|
||
u8 *pBuff=p;
|
||
|
||
for(i=0;i < len;i++)
|
||
{
|
||
t=i/4;
|
||
if(i%4==0)
|
||
{
|
||
w[t]=0;
|
||
}
|
||
c=pBuff[i];
|
||
c <<=(3-(i%4))*8;
|
||
w[t] |=c;
|
||
DRM_INFO("pBuff[%d]=%02X,c=%08X,w[%d]=%08X\n",(int)i,(int)pBuff[i],c,(int)t,w[t]);
|
||
}
|
||
t=i/4;
|
||
if(i%4==0)
|
||
{
|
||
w[t]=0;
|
||
}
|
||
//c=0x80 << ((3-i%4)*24);
|
||
c=0x80;
|
||
c <<=((3-i%4)*8);
|
||
w[t]|=c;t++;
|
||
for(; t < 15;t++)
|
||
{
|
||
w[t]=0;
|
||
}
|
||
w[15]=len*8;
|
||
|
||
for(i = 0; i < 16; i++)
|
||
{
|
||
DRM_INFO("w[%d] = %08X\n",i,w[i]);
|
||
}
|
||
SHATransform(VH);
|
||
|
||
for(i=0;i < 5;i++)
|
||
{
|
||
output[i*4+3]=(u8)((VH[i]>>24)&0xFF);
|
||
output[i*4+2]=(u8)((VH[i]>>16)&0xFF);
|
||
output[i*4+1]=(u8)((VH[i]>>8)&0xFF);
|
||
output[i*4+0]=(u8)(VH[i]&0xFF);
|
||
}
|
||
}
|
||
|
||
#ifdef SUPPORT_SHA
|
||
|
||
static SYS_STATUS hdmitx_hdcp_CheckSHA(u8 pM0[],u16 BStatus,u8 pKSVList[],int cDownStream,u8 Vr[])
|
||
{
|
||
int i,n ;
|
||
|
||
for(i = 0 ; i < cDownStream*5 ; i++)
|
||
{
|
||
SHABuff[i] = pKSVList[i] ;
|
||
}
|
||
SHABuff[i++] = BStatus & 0xFF ;
|
||
SHABuff[i++] = (BStatus>>8) & 0xFF ;
|
||
for(n = 0 ; n < 8 ; n++,i++)
|
||
{
|
||
SHABuff[i] = pM0[n] ;
|
||
}
|
||
n = i ;
|
||
// SHABuff[i++] = 0x80 ; // end mask
|
||
for(; i < 64 ; i++)
|
||
{
|
||
SHABuff[i] = 0 ;
|
||
}
|
||
// n = cDownStream * 5 + 2 /* for BStatus */ + 8 /* for M0 */ ;
|
||
// n *= 8 ;
|
||
// SHABuff[62] = (n>>8) & 0xff ;
|
||
// SHABuff[63] = (n>>8) & 0xff ;
|
||
/*
|
||
for(i = 0 ; i < 64 ; i++)
|
||
{
|
||
if(i % 16 == 0)
|
||
{
|
||
DRM_INFO("SHA[]: ");
|
||
}
|
||
DRM_INFO(" %02X",SHABuff[i]);
|
||
if((i%16)==15)
|
||
{
|
||
DRM_INFO("\n");
|
||
}
|
||
}
|
||
*/
|
||
SHA_Simple(SHABuff,n,V);
|
||
for(i = 0 ; i < 20 ; i++)
|
||
{
|
||
if(V[i] != Vr[i])
|
||
{
|
||
DRM_INFO("V[] =");
|
||
for(i = 0 ; i < 20 ; i++)
|
||
{
|
||
DRM_INFO(" %02X",(int)V[i]);
|
||
}
|
||
DRM_INFO("\nVr[] =");
|
||
for(i = 0 ; i < 20 ; i++)
|
||
{
|
||
DRM_INFO(" %02X",(int)Vr[i]);
|
||
}
|
||
return ER_FAIL ;
|
||
}
|
||
}
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
#endif // SUPPORT_SHA
|
||
|
||
static SYS_STATUS hdmi_tx_hdcp_get_ksv_list(struct it6161 *it6161, u8 *pKSVList,u8 cDownStream)
|
||
{
|
||
u8 timeout = 100, ucdata;
|
||
|
||
if( cDownStream == 0 )
|
||
{
|
||
return ER_SUCCESS ;
|
||
}
|
||
if( /* cDownStream == 0 || */ pKSVList == NULL)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_HEADER, 0x74);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQOFF, 0x43);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQCOUNT, cDownStream * 5);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD, CMD_DDC_SEQ_BURSTREAD);
|
||
|
||
ucdata = it6161_ddc_wait(it6161);
|
||
|
||
if (ucdata < 0)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
DRM_INFO("hdmi_tx_hdcp_get_ksv_list(): KSV");
|
||
for(timeout = 0 ; timeout < cDownStream * 5 ; timeout++)
|
||
{
|
||
pKSVList[timeout] = it6161_hdmi_tx_read(it6161, REG_TX_DDC_READFIFO);
|
||
#ifdef _SUPPORT_HDCP_REPEATER_
|
||
KSVList[timeout] = pKSVList[timeout];
|
||
DRM_INFO(" %x",(int)pKSVList[timeout]);
|
||
DRM_INFO(" %02X",(int)pKSVList[timeout]);
|
||
#endif
|
||
}
|
||
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
static SYS_STATUS hdmitx_hdcp_GetVr(struct it6161 *it6161, u8 *pVr)
|
||
{
|
||
u8 timeout, ucdata;
|
||
|
||
if(pVr == NULL)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_MASTER_CTRL,B_TX_MASTERHOST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_HEADER,0x74);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQOFF,0x20);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_REQCOUNT,20);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD);
|
||
|
||
ucdata = it6161_ddc_wait(it6161);
|
||
if (ucdata < 0)
|
||
{
|
||
DRM_INFO("hdmitx_hdcp_GetVr(): DDC fail by timeout.\n");
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
|
||
for(timeout = 0 ; timeout < 5 ; timeout++)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL ,timeout);
|
||
pVr[timeout*4] = (u32)it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE1);
|
||
pVr[timeout*4+1] = (u32)it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE2);
|
||
pVr[timeout*4+2] = (u32)it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE3);
|
||
pVr[timeout*4+3] = (u32)it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE4);
|
||
// DRM_INFO("V' = %02X %02X %02X %02X\n",(int)pVr[timeout*4],(int)pVr[timeout*4+1],(int)pVr[timeout*4+2],(int)pVr[timeout*4+3]);
|
||
}
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
static SYS_STATUS hdmitx_hdcp_GetM0(struct it6161 *it6161, u8 *pM0)
|
||
{
|
||
int i ;
|
||
|
||
if(!pM0)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL,5); // read m0[31:0] from reg51~reg54
|
||
pM0[0] = it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE1);
|
||
pM0[1] = it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE2);
|
||
pM0[2] = it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE3);
|
||
pM0[3] = it6161_hdmi_tx_read(it6161, REG_TX_SHA_RD_BYTE4);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL,0); // read m0[39:32] from reg55
|
||
pM0[4] = it6161_hdmi_tx_read(it6161, REG_TX_AKSV_RD_BYTE5);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL,1); // read m0[47:40] from reg55
|
||
pM0[5] = it6161_hdmi_tx_read(it6161, REG_TX_AKSV_RD_BYTE5);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL,2); // read m0[55:48] from reg55
|
||
pM0[6] = it6161_hdmi_tx_read(it6161, REG_TX_AKSV_RD_BYTE5);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL,3); // read m0[63:56] from reg55
|
||
pM0[7] = it6161_hdmi_tx_read(it6161, REG_TX_AKSV_RD_BYTE5);
|
||
|
||
DRM_INFO("M[] =");
|
||
for(i = 0 ; i < 8 ; i++)
|
||
{
|
||
DRM_INFO("0x%02x,",(int)pM0[i]);
|
||
}
|
||
DRM_INFO("\n");
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
#ifdef _SUPPORT_HDCP_REPEATER_
|
||
|
||
static void TxHDCP_chg(HDMITX_HDCP_State state)
|
||
{
|
||
if( state == hdmiTxDev[0].TxHDCP_State )
|
||
{
|
||
return ;
|
||
}
|
||
DRM_INFO("TxHDCP %d -> %d\n",hdmiTxDev[0].TxHDCP_State,state);
|
||
hdmiTxDev[0].TxHDCP_State = state ;
|
||
|
||
switch(state)
|
||
{
|
||
case TxHDCP_Off:
|
||
hdmiTxDev[0].bAuthenticated=false;
|
||
hdmiTxDev[0].usHDCPTimeOut = 0 ;
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
break;
|
||
|
||
case TxHDCP_AuthRestart:
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
hdmiTxDev[0].usHDCPTimeOut = 5 ;
|
||
break;
|
||
|
||
case TxHDCP_AuthStart:
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
hdmiTxDev[0].usHDCPTimeOut = 80 ;
|
||
break;
|
||
|
||
case TxHDCP_Receiver:
|
||
hdmiTxDev[0].usHDCPTimeOut = 250 ; // set the count as the 5000ms/interval
|
||
break;
|
||
|
||
case TxHDCP_Repeater:
|
||
hdmiTxDev[0].usHDCPTimeOut = 250 ; // set the count as the 5000ms/interval
|
||
break;
|
||
|
||
case TxHDCP_CheckFIFORDY:
|
||
|
||
hdmiTxDev[0].usHDCPTimeOut = 300 ; // set the count as the 6000ms/interval
|
||
break;
|
||
|
||
case TxHDCP_VerifyRevocationList:
|
||
break;
|
||
|
||
|
||
case TxHDCP_AuthFail:
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
break;
|
||
|
||
case TxHDCP_RepeaterFail:
|
||
hdmitx_hdcp_CancelRepeaterAuthenticate(it6161);
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
break;
|
||
|
||
case TxHDCP_RepeaterSuccess:
|
||
hdmitx_hdcp_ResumeRepeaterAuthenticate(it6161);
|
||
case TxHDCP_Authenticated:
|
||
it6161_hdmi_tx_set_av_mute(it6161, false) ;
|
||
hdmiTxDev[0].bAuthenticated = true ;
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
static void TxHDCP_fsm()
|
||
{
|
||
u8 ucdata ;
|
||
int i ;
|
||
|
||
static u8 BCaps ;
|
||
static u16 BStatus ;
|
||
static u8 cDownStream ;// this value will be use in the function....
|
||
static u8 bksv[5] ;
|
||
|
||
|
||
switch(hdmiTxDev[0].TxHDCP_State)
|
||
{
|
||
case TxHDCP_Off:
|
||
break;
|
||
|
||
case TxHDCP_AuthRestart:
|
||
if(hdmiTxDev[0].usHDCPTimeOut>0)
|
||
{
|
||
hdmiTxDev[0].usHDCPTimeOut -- ;
|
||
}
|
||
if( hdmiTxDev[0].usHDCPTimeOut == 0 )
|
||
{
|
||
TxHDCP_chg(TxHDCP_AuthStart) ;
|
||
}
|
||
break;
|
||
|
||
case TxHDCP_AuthStart:
|
||
cDownStream = 0 ;
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
if(hdmiTxDev[0].usHDCPTimeOut>0)
|
||
{
|
||
hdmiTxDev[0].usHDCPTimeOut -- ;
|
||
ucdata = it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS)& (B_TX_HPDETECT|B_TX_RXSENDETECT);
|
||
|
||
if(ucdata != (B_TX_HPDETECT|B_TX_RXSENDETECT))
|
||
{
|
||
// if no Rx sense, do not start authentication.
|
||
// Eventhough start it, cannot work.
|
||
return ;
|
||
}
|
||
|
||
if(hdmi_tx_get_hdcp_bcaps_bstatus(it6161, &BCaps,&BStatus) != ER_SUCCESS)
|
||
{
|
||
DRM_INFO("hdmi_tx_get_hdcp_bcaps_bstatus fail.\n");
|
||
return;
|
||
}
|
||
// wait for HDMI State
|
||
|
||
if(B_TX_HDMI_MODE == (it6161_hdmi_tx_read(it6161, REG_TX_HDMI_MODE) & B_TX_HDMI_MODE ))
|
||
{
|
||
if((BStatus & B_TX_CAP_HDMI_MODE)!=B_TX_CAP_HDMI_MODE)
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if((BStatus & B_TX_CAP_HDMI_MODE)==B_TX_CAP_HDMI_MODE)
|
||
{
|
||
return ;
|
||
}
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
TxHDCP_chg(TxHDCP_AuthRestart) ;
|
||
}
|
||
|
||
DRM_INFO("BCAPS = %x BSTATUS = %X\n", (int)BCaps, BStatus);
|
||
hdmi_tx_hdcp_get_bksv(it6161, bksv, ARRAY_SIZE(bksv));
|
||
DRM_INFO("bksv %X %X %X %X %X\n",(int)bksv[0],(int)bksv[1],(int)bksv[2],(int)bksv[3],(int)bksv[4]);
|
||
|
||
for(i = 0, ucdata = 0 ; i < 5 ; i ++)
|
||
{
|
||
ucdata += countbit(bksv[i]);
|
||
}
|
||
if( ucdata != 20 )
|
||
{
|
||
DRM_INFO("countbit error\n");
|
||
TxHDCP_chg(TxHDCP_AuthFail) ;
|
||
return ;
|
||
|
||
}
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0); // switch bank action should start on direct register writting of each function.
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_TX_HDCP_RST_HDMITX, 0x00);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_HDCP_DESIRE,8|B_TX_CPDESIRE);
|
||
hdmi_tx_hdcp_clear_auth_interrupt(it6161);
|
||
|
||
hdmi_tx_hdcp_generate_an(it6161);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL,0);
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
hdmi_tx_hdcp_auth_fire(it6161);
|
||
hdmiTxDev[0].Tx_BStatus = BStatus ;
|
||
if(BCaps & B_TX_CAP_HDMI_REPEATER)
|
||
{
|
||
TxHDCP_chg(TxHDCP_Repeater) ;
|
||
}
|
||
else
|
||
{
|
||
|
||
for(i = 0; i < 5 ; i ++)
|
||
{
|
||
KSVList[i] = bksv[i] ;
|
||
}
|
||
TxHDCP_chg(TxHDCP_Receiver) ;
|
||
}
|
||
break;
|
||
|
||
case TxHDCP_Receiver:
|
||
|
||
if(hdmiTxDev[0].usHDCPTimeOut >0)
|
||
{
|
||
hdmiTxDev[0].usHDCPTimeOut -- ;
|
||
}
|
||
|
||
if(hdmiTxDev[0].usHDCPTimeOut==0)
|
||
{
|
||
TxHDCP_chg(TxHDCP_AuthFail) ;
|
||
return ;
|
||
}
|
||
else
|
||
{
|
||
DRM_INFO("[Fsm] Receiver: usHDCPTimeOut = %d\n",hdmiTxDev[0].usHDCPTimeOut);
|
||
ucdata = it6161_hdmi_tx_read(it6161, REG_TX_AUTH_STAT);
|
||
DRM_INFO("[Fsm] Receiver: ucdata = %X, BStatus = %X\n",ucdata,BStatus);
|
||
|
||
if(ucdata & B_TX_AUTH_DONE)
|
||
{
|
||
//BStatus += 0x101 ;
|
||
IT680X_DownStream_AuthDoneCallback(bksv, BStatus);
|
||
TxHDCP_chg(TxHDCP_Authenticated) ;
|
||
break ;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TxHDCP_Repeater:
|
||
if(hdmiTxDev[0].usHDCPTimeOut >0)
|
||
{
|
||
hdmiTxDev[0].usHDCPTimeOut -- ;
|
||
}
|
||
|
||
if(hdmiTxDev[0].usHDCPTimeOut==0)
|
||
{
|
||
TxHDCP_chg(TxHDCP_AuthFail) ;
|
||
return ;
|
||
}
|
||
break;
|
||
|
||
case TxHDCP_CheckFIFORDY:
|
||
if(hdmiTxDev[0].usHDCPTimeOut >0)
|
||
{
|
||
hdmiTxDev[0].usHDCPTimeOut -- ;
|
||
}
|
||
|
||
if(hdmiTxDev[0].usHDCPTimeOut==0)
|
||
{
|
||
TxHDCP_chg(TxHDCP_RepeaterFail) ;
|
||
return ;
|
||
}
|
||
|
||
if(hdmi_tx_get_hdcp_bcaps_bstatus(it6161, &BCaps,&BStatus) == ER_FAIL)
|
||
{
|
||
DRM_INFO("Get BCaps fail\n");
|
||
break ; // get fail, again.
|
||
}
|
||
|
||
|
||
if(BCaps & B_TX_CAP_KSV_FIFO_RDY)
|
||
{
|
||
DRM_INFO("FIFO Ready\n");
|
||
|
||
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
it6161_hdmi_tx_generate_ddc_sclk(it6161);
|
||
hdmiTxDev[0].Tx_BStatus = BStatus ;
|
||
cDownStream=(BStatus & M_TX_DOWNSTREAM_COUNT);
|
||
//+++++++++++++++++++++++++++++++++++++
|
||
DRM_INFO("Downstream=%X \n",cDownStream);
|
||
|
||
if( cDownStream > (MAX_REPEATER_DOWNSTREAM_COUNT-1))
|
||
{
|
||
hdmiTxDev[0].Tx_BStatus |= B_TX_DOWNSTREAM_OVER ;
|
||
}
|
||
if( cDownStream > (MAX_REPEATER_DOWNSTREAM_COUNT-1) ||
|
||
BStatus & (B_TX_MAX_CASCADE_EXCEEDED|B_TX_DOWNSTREAM_OVER))
|
||
{
|
||
DRM_INFO("Invalid Down stream count,fail\n");
|
||
|
||
// RxAuthSetBStatus(B_DOWNSTREAM_OVER|B_MAX_CASCADE_EXCEEDED); //for ALLION HDCP 3C-2-06
|
||
// ForceKSVFIFOReady(B_DOWNSTREAM_OVER|B_MAX_CASCADE_EXCEEDED) ;
|
||
IT680X_DownStream_AuthDoneCallback(KSVList, 0xFFF);
|
||
TxHDCP_chg(TxHDCP_RepeaterFail);
|
||
break;
|
||
}
|
||
|
||
TxHDCP_chg(TxHDCP_VerifyRevocationList) ;
|
||
break ;
|
||
}
|
||
|
||
break;
|
||
|
||
case TxHDCP_VerifyRevocationList:
|
||
|
||
#ifdef SUPPORT_SHA
|
||
DRM_INFO("TxHDCP_VerifyRevocationList: cDownStream = %d",cDownStream);
|
||
if(hdmi_tx_hdcp_get_ksv_list(it6161, KSVList,cDownStream) == ER_FAIL)
|
||
{
|
||
DRM_INFO("hdmitx_hdcp_Repeater_Fail 2\n");
|
||
TxHDCP_chg(TxHDCP_RepeaterFail);
|
||
break;
|
||
}
|
||
|
||
if(hdmitx_hdcp_GetVr(it6161, Vr) == ER_FAIL)
|
||
{
|
||
DRM_INFO("hdmitx_hdcp_Repeater_Fail 3\n");
|
||
TxHDCP_chg(TxHDCP_RepeaterFail);
|
||
break;
|
||
}
|
||
if(hdmitx_hdcp_GetM0(it6161, M0) == ER_FAIL)
|
||
{
|
||
DRM_INFO("hdmitx_hdcp_Repeater_Fail 4\n");
|
||
TxHDCP_chg(TxHDCP_RepeaterFail);
|
||
break;
|
||
}
|
||
// do check SHA
|
||
if(hdmitx_hdcp_CheckSHA(M0,BStatus,KSVList,cDownStream,Vr) == ER_FAIL)
|
||
{
|
||
DRM_INFO("hdmitx_hdcp_Repeater_Fail 5\n");
|
||
TxHDCP_chg(TxHDCP_RepeaterFail);
|
||
break;
|
||
}
|
||
#endif // SUPPORT_SHA
|
||
// checkSHA success, append the bksv to KSV List
|
||
for(i = 0; i < 5 ; i ++)
|
||
{
|
||
KSVList[cDownStream*5+i] = bksv[i] ;
|
||
}
|
||
|
||
for( i = 0 ; i < ((cDownStream+1)*5) ; i ++ )
|
||
{
|
||
DRM_INFO("KSVLIST[%d] = %X\n",i,KSVList[i]);
|
||
}
|
||
|
||
//BStatus += 0x101 ;
|
||
IT680X_DownStream_AuthDoneCallback(KSVList, BStatus);
|
||
|
||
TxHDCP_chg(TxHDCP_RepeaterSuccess) ;
|
||
break;
|
||
|
||
|
||
case TxHDCP_Authenticated:
|
||
break;
|
||
|
||
case TxHDCP_AuthFail:
|
||
// force revoke the KSVList
|
||
// IT680X_DownStream_AuthDoneCallback(KSVList, 0xFFF);
|
||
TxHDCP_chg(TxHDCP_AuthRestart);
|
||
break;
|
||
|
||
case TxHDCP_RepeaterFail:
|
||
TxHDCP_chg(TxHDCP_AuthFail);
|
||
break;
|
||
|
||
case TxHDCP_RepeaterSuccess:
|
||
TxHDCP_chg(TxHDCP_Authenticated);
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmi_tx_hdcp_auth_process_Repeater
|
||
// Parameter: BCaps and BStatus
|
||
// Return: ER_SUCCESS if success,if AUTH_FAIL interrupt status,return fail.
|
||
// Remark:
|
||
// Side-Effect: as Authentication
|
||
//////////////////////////////////////////////////////////////////////
|
||
#ifdef HDCP
|
||
static SYS_STATUS hdmi_tx_hdcp_auth_process_Repeater(struct it6161 *it6161)
|
||
{
|
||
u8 uc ,ii;
|
||
// u8 revoked ;
|
||
// int i ;
|
||
u8 cDownStream ;
|
||
|
||
u8 BCaps;
|
||
u16 BStatus ;
|
||
u16 timeout ;
|
||
|
||
DRM_INFO("Authentication for repeater\n");
|
||
// emily add for test,abort HDCP
|
||
// 2007/10/01 marked by jj_tseng@chipadvanced.com
|
||
// it6161_hdmi_tx_write(it6161, 0x20,0x00);
|
||
// it6161_hdmi_tx_write(it6161, 0x04,0x01);
|
||
// it6161_hdmi_tx_write(it6161, 0x10,0x01);
|
||
// it6161_hdmi_tx_write(it6161, 0x15,0x0F);
|
||
// msleep(100);
|
||
// it6161_hdmi_tx_write(it6161, 0x04,0x00);
|
||
// it6161_hdmi_tx_write(it6161, 0x10,0x00);
|
||
// it6161_hdmi_tx_write(it6161, 0x20,0x01);
|
||
// msleep(100);
|
||
// test07 = it6161_hdmi_tx_read(it6161, 0x7);
|
||
// test06 = it6161_hdmi_tx_read(it6161, 0x6);
|
||
// test08 = it6161_hdmi_tx_read(it6161, 0x8);
|
||
//~jj_tseng@chipadvanced.com
|
||
// end emily add for test
|
||
//////////////////////////////////////
|
||
// Authenticate Fired
|
||
//////////////////////////////////////
|
||
|
||
hdmi_tx_get_hdcp_bcaps_bstatus(it6161, &BCaps,&BStatus);
|
||
msleep(2);
|
||
if((B_TX_INT_HPD_PLUG|B_TX_INT_RX_SENSE)&it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1))
|
||
{
|
||
DRM_INFO("HPD Before Fire Auth\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
hdmi_tx_hdcp_auth_fire(it6161);
|
||
//msleep(550); // emily add for test
|
||
for(ii=0;ii<55;ii++) //msleep(550); // emily add for test
|
||
{
|
||
if((B_TX_INT_HPD_PLUG|B_TX_INT_RX_SENSE)&it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1))
|
||
{
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
msleep(10);
|
||
}
|
||
for(timeout = /*250*6*/10 ; timeout > 0 ; timeout --)
|
||
{
|
||
DRM_INFO("timeout = %d wait part 1\n",timeout);
|
||
if((B_TX_INT_HPD_PLUG|B_TX_INT_RX_SENSE)&it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1))
|
||
{
|
||
DRM_INFO("HPD at wait part 1\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1);
|
||
if(uc & B_TX_INT_DDC_BUS_HANG)
|
||
{
|
||
DRM_INFO("DDC Bus hang\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT2);
|
||
|
||
if(uc & B_TX_INT_AUTH_FAIL)
|
||
{
|
||
/*
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR0,B_TX_CLR_AUTH_FAIL);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR1,0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS,B_TX_INTACTDONE);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS,0);
|
||
*/
|
||
DRM_INFO("hdmi_tx_hdcp_auth_process_Repeater(): B_TX_INT_AUTH_FAIL.\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
// emily add for test
|
||
// test =(it6161_hdmi_tx_read(it6161, 0x7)&0x4)>>2 ;
|
||
if(uc & B_TX_INT_KSVLIST_CHK)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR0,B_TX_CLR_KSVLISTCHK);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR1,0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS,B_TX_INTACTDONE);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS,0);
|
||
DRM_INFO("B_TX_INT_KSVLIST_CHK\n");
|
||
break ;
|
||
}
|
||
msleep(5);
|
||
}
|
||
if(timeout == 0)
|
||
{
|
||
DRM_INFO("Time out for wait KSV List checking interrupt\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
///////////////////////////////////////
|
||
// clear KSVList check interrupt.
|
||
///////////////////////////////////////
|
||
|
||
for(timeout = 500 ; timeout > 0 ; timeout --)
|
||
{
|
||
DRM_INFO("timeout=%d at wait FIFO ready\n",timeout);
|
||
if((B_TX_INT_HPD_PLUG|B_TX_INT_RX_SENSE)&it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1))
|
||
{
|
||
DRM_INFO("HPD at wait FIFO ready\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
if(hdmi_tx_get_hdcp_bcaps_bstatus(it6161, &BCaps,&BStatus) == ER_FAIL)
|
||
{
|
||
DRM_INFO("Get BCaps fail\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
if(BCaps & B_TX_CAP_KSV_FIFO_RDY)
|
||
{
|
||
DRM_INFO("FIFO Ready\n");
|
||
break ;
|
||
}
|
||
msleep(5);
|
||
|
||
}
|
||
if(timeout == 0)
|
||
{
|
||
DRM_INFO("Get KSV FIFO ready timeout\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
DRM_INFO("Wait timeout = %d\n",timeout);
|
||
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
it6161_hdmi_tx_generate_ddc_sclk(it6161);
|
||
cDownStream = (BStatus & M_TX_DOWNSTREAM_COUNT);
|
||
|
||
if(/*cDownStream == 0 ||*/ cDownStream > 6 || BStatus & (B_TX_MAX_CASCADE_EXCEEDED|B_TX_DOWNSTREAM_OVER))
|
||
{
|
||
DRM_INFO("Invalid Down stream count,fail\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
#ifdef SUPPORT_SHA
|
||
if(hdmi_tx_hdcp_get_ksv_list(it6161, KSVList,cDownStream) == ER_FAIL)
|
||
{
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
#if 0
|
||
for(i = 0 ; i < cDownStream ; i++)
|
||
{
|
||
revoked=false ; uc = 0 ;
|
||
for( timeout = 0 ; timeout < 5 ; timeout++ )
|
||
{
|
||
// check bit count
|
||
uc += countbit(KSVList[i*5+timeout]);
|
||
}
|
||
if( uc != 20 ) revoked = true ;
|
||
|
||
if(revoked)
|
||
{
|
||
DRM_INFO("KSVFIFO[%d] = %02X %02X %02X %02X %02X is revoked\n",i,(int)KSVList[i*5],(int)KSVList[i*5+1],(int)KSVList[i*5+2],(int)KSVList[i*5+3],(int)KSVList[i*5+4]);
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if(hdmitx_hdcp_GetVr(it6161, Vr) == ER_FAIL)
|
||
{
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
if(hdmitx_hdcp_GetM0(it6161, M0) == ER_FAIL)
|
||
{
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
// do check SHA
|
||
if(hdmitx_hdcp_CheckSHA(M0,BStatus,KSVList,cDownStream,Vr) == ER_FAIL)
|
||
{
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
if((B_TX_INT_HPD_PLUG|B_TX_INT_RX_SENSE)&it6161_hdmi_tx_read(it6161, REG_TX_INT_STAT1))
|
||
{
|
||
DRM_INFO("HPD at Final\n");
|
||
goto hdmitx_hdcp_Repeater_Fail ;
|
||
}
|
||
#endif // SUPPORT_SHA
|
||
|
||
hdmitx_hdcp_ResumeRepeaterAuthenticate(it6161);
|
||
hdmiTxDev[0].bAuthenticated = true ;
|
||
return ER_SUCCESS ;
|
||
|
||
hdmitx_hdcp_Repeater_Fail:
|
||
hdmitx_hdcp_CancelRepeaterAuthenticate(it6161);
|
||
return ER_FAIL ;
|
||
}
|
||
#endif
|
||
#if 0
|
||
static int hdmi_tx_hdcp_get_m0(struct it6161 *it6161, u8 *m0)
|
||
{
|
||
int ret, i;
|
||
|
||
if(!m0)
|
||
return -ENOMEM;
|
||
|
||
/* read m0[31:0] from reg51~reg54 */
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL, 5);
|
||
ret = it6161_hdmi_tx_burst_read(it6161, REG_TX_SHA_RD_BYTE1, m0, 4);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c read m0 failed");
|
||
return ret;
|
||
}
|
||
|
||
/* read m0[39 + i * 8 : 32 + i * 8] from reg55 */
|
||
for (i = 0; i < 4; i++) {
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL, i);
|
||
m0[4 + i] = it6161_hdmi_tx_read(it6161, REG_TX_AKSV_RD_BYTE5);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
static int hdmi_tx_hdcp_get_bcaps(struct it6161 *it6161)
|
||
{
|
||
int ret;
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_HDCP_ADDRESS, DRM_HDCP_DDC_BCAPS, 0x01, 0x00, CMD_DDC_SEQ_BURSTREAD);
|
||
ret = it6161_ddc_wait(it6161);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("ddc get bcaps failed");
|
||
return ret;
|
||
}
|
||
|
||
ret = it6161_hdmi_tx_read(it6161, REG_TX_BCAP);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c get bcaps failed");
|
||
return ret;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
static int hdmi_tx_hdcp_get_bstatus(struct it6161 *it6161)
|
||
{
|
||
int ret, bstatus;
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_HDCP_ADDRESS, DRM_HDCP_DDC_BSTATUS, 0x02, 0x00, CMD_DDC_SEQ_BURSTREAD);
|
||
ret = it6161_ddc_wait(it6161);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("ddc get bstatus failed");
|
||
return ret;
|
||
}
|
||
|
||
ret = it6161_hdmi_tx_read(it6161, REG_TX_BSTAT);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c get bstatus failed");
|
||
return ret;
|
||
}
|
||
|
||
bstatus = ret;
|
||
|
||
ret = it6161_hdmi_tx_read(it6161, REG_TX_BSTAT + 1);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c get bstatus failed");
|
||
return ret;
|
||
}
|
||
|
||
bstatus |= ret << 8;
|
||
|
||
return bstatus;
|
||
}
|
||
|
||
#if 0
|
||
static void hdmi_tx_hdcp_show_ksv_list(struct it6161 *it6161, u8 *ksvlist)
|
||
{
|
||
u8 i;
|
||
|
||
for (i = 0; i < it6161->hdcp_downstream_count; i++, ksvlist += DRM_HDCP_KSV_LEN)
|
||
DRM_INFO("device%d ksv:0x %*ph", i, DRM_HDCP_KSV_LEN, ksvlist);
|
||
}
|
||
|
||
static int hdmi_tx_hdcp_get_ksv_list1(struct it6161 *it6161, u8 *ksvlist, size_t size)
|
||
{
|
||
int i, ret;
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_HDCP_ADDRESS, DRM_HDCP_DDC_KSV_FIFO, size, 0x00, CMD_DDC_SEQ_BURSTREAD);
|
||
ret = it6161_ddc_wait(it6161);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("ddc get ksv list failed");
|
||
return ret;
|
||
}
|
||
|
||
for (i = 0; i < size; i++) {
|
||
ret = it6161_hdmi_tx_read(it6161, REG_TX_DDC_READFIFO);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c get ksv list failed");
|
||
return ret;
|
||
}
|
||
|
||
ksvlist[i] = ret;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int hdmi_tx_hdcp_get_v_prime(struct it6161 *it6161, u8 *v_prime, size_t size)
|
||
{
|
||
int i, ret;
|
||
|
||
hdmi_tx_ddc_operation(it6161, DDC_HDCP_ADDRESS, DRM_HDCP_DDC_V_PRIME(0), size, 0x00, CMD_DDC_SEQ_BURSTREAD);
|
||
ret = it6161_ddc_wait(it6161);
|
||
|
||
if (ret < 0) {
|
||
DRM_INFO("ddc get v prime failed");
|
||
return ret;
|
||
}
|
||
|
||
for(i = 0 ; i < DRM_HDCP_V_PRIME_NUM_PARTS ; i++) {
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SHA_SEL ,i);
|
||
ret = it6161_hdmi_tx_burst_read(it6161, REG_TX_SHA_RD_BYTE1, v_prime, DRM_HDCP_V_PRIME_PART_LEN);
|
||
if (ret < 0) {
|
||
DRM_INFO("i2c get v prime failed");
|
||
return ret;
|
||
}
|
||
|
||
v_prime += DRM_HDCP_V_PRIME_PART_LEN;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int hdmi_tx_setup_sha1_input(struct it6161 *it6161, u8 *ksvlist, u8 *sha1_input)
|
||
{
|
||
u8 i, m0[8], msg_count = 0;
|
||
|
||
hdmi_tx_hdcp_get_m0(it6161, m0);
|
||
|
||
for (i = 0; i < it6161->hdcp_downstream_count * DRM_HDCP_KSV_LEN; i++)
|
||
sha1_input[i] = ksvlist[i];
|
||
|
||
msg_count += i;
|
||
sha1_input[msg_count++] = (u8)it6161->bstatus;
|
||
sha1_input[msg_count++] = (u8)(it6161->bstatus >> 8);
|
||
i = 0;
|
||
|
||
while (i < ARRAY_SIZE(m0))
|
||
sha1_input[msg_count++] = m0[i++];
|
||
|
||
return msg_count;
|
||
}
|
||
|
||
static int it6161_sha1_digest(struct it6161 *it6161, u8 *sha1_input,
|
||
unsigned int size, u8 *output_av)
|
||
{
|
||
struct shash_desc *desc;
|
||
struct crypto_shash *tfm;
|
||
int err;
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
|
||
tfm = crypto_alloc_shash("sha1", 0, 0);
|
||
if (IS_ERR(tfm)) {
|
||
DRM_DEV_ERROR(dev, "crypto_alloc_shash sha1 failed");
|
||
return PTR_ERR(tfm);
|
||
}
|
||
desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
|
||
if (!desc) {
|
||
crypto_free_shash(tfm);
|
||
return -ENOMEM;
|
||
}
|
||
|
||
desc->tfm = tfm;
|
||
err = crypto_shash_digest(desc, sha1_input, size, output_av);
|
||
if (err)
|
||
DRM_DEV_ERROR(dev, "crypto_shash_digest sha1 failed");
|
||
|
||
crypto_free_shash(tfm);
|
||
kfree(desc);
|
||
return err;
|
||
}
|
||
|
||
static bool hdmi_tX_hdcp_compare_sha1_v_prime_v(struct it6161 *it6161, u8 *v_array, u8 *v_prime_array)
|
||
{
|
||
int i, j;
|
||
|
||
u8 (*v)[DRM_HDCP_V_PRIME_PART_LEN] = (u8 (*)[DRM_HDCP_V_PRIME_PART_LEN])v_array;
|
||
u8 (*v_prime)[DRM_HDCP_V_PRIME_PART_LEN] = (u8 (*)[DRM_HDCP_V_PRIME_PART_LEN])v_prime_array;
|
||
|
||
for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
|
||
for (j = 0; j < DRM_HDCP_V_PRIME_PART_LEN; j++) {
|
||
if (v[i][j] !=
|
||
v_prime[i][DRM_HDCP_V_PRIME_PART_LEN - 1- j])
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
static void hdmi_tx_hdcp_auth_part2_process(struct work_struct *work)
|
||
{
|
||
struct it6161 *it6161 = container_of(work, struct it6161,
|
||
wait_hdcp_ksv_list);
|
||
int timeout = 5000, ret, i;
|
||
//u8 bcaps, ksvlist[DRM_HDCP_KSV_LEN * it6161->hdcp_downstream_count], *tmp;
|
||
u8 bcaps, ksvlist[DRM_HDCP_KSV_LEN], *tmp;
|
||
u8 v[DRM_HDCP_V_PRIME_NUM_PARTS][DRM_HDCP_V_PRIME_PART_LEN], v_prime[DRM_HDCP_V_PRIME_NUM_PARTS][DRM_HDCP_V_PRIME_PART_LEN];
|
||
|
||
while (timeout > 0) {
|
||
if (!hdmi_tx_get_sink_hpd(it6161))
|
||
return;
|
||
|
||
ret = hdmi_tx_hdcp_get_bcaps(it6161);
|
||
|
||
if (ret < 0)
|
||
return;
|
||
|
||
bcaps = ret;
|
||
if (!!(bcaps & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY)) {
|
||
DRM_INFO("ksv list fifo ready");
|
||
break;
|
||
}
|
||
usleep_range(1000, 2000);
|
||
}
|
||
|
||
if (timeout <= 0) {
|
||
DRM_INFO("wait ksv list ready timeout");
|
||
return;
|
||
}
|
||
|
||
ret = hdmi_tx_hdcp_get_ksv_list1(it6161, ksvlist, ARRAY_SIZE(ksvlist));
|
||
|
||
if (ret != 0)
|
||
return;
|
||
|
||
hdmi_tx_hdcp_show_ksv_list(it6161, ksvlist);
|
||
ret = hdmi_tx_setup_sha1_input(it6161, ksvlist, it6161->sha1_transform_input);
|
||
DRM_INFO("sha1 msg_count :%d \nsha1_input:0x %*ph", ret, ret, it6161->sha1_transform_input);
|
||
ret = it6161_sha1_digest(it6161, it6161->sha1_transform_input, ret, (u8 *)v);
|
||
if (ret != 0)
|
||
return;
|
||
|
||
tmp = (u8 *)v;
|
||
for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++, tmp += DRM_HDCP_V_PRIME_PART_LEN)
|
||
DRM_INFO("v:0x %*ph", DRM_HDCP_V_PRIME_PART_LEN, tmp);
|
||
|
||
ret = hdmi_tx_hdcp_get_v_prime(it6161, (u8 *)v_prime, sizeof(v_prime));
|
||
|
||
if (ret != 0)
|
||
return;
|
||
|
||
tmp = (u8 *)v_prime;
|
||
for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++, tmp += DRM_HDCP_V_PRIME_PART_LEN)
|
||
DRM_INFO("v_prime:0x %*ph", DRM_HDCP_V_PRIME_PART_LEN, tmp);
|
||
|
||
ret = hdmi_tX_hdcp_compare_sha1_v_prime_v(it6161, (u8 *)v, (u8 *)v_prime);
|
||
DRM_INFO("sha1 check result: %s", ret ? "pass" : "failed");
|
||
|
||
if (ret) {
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_LISTCTRL, B_TX_LISTDONE , B_TX_LISTDONE);
|
||
} else {
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_LISTCTRL, B_TX_LISTDONE | B_TX_LISTFAIL, B_TX_LISTDONE | B_TX_LISTFAIL);
|
||
}
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_LISTCTRL, B_TX_LISTDONE | B_TX_LISTFAIL, 0x00);
|
||
}
|
||
#endif
|
||
|
||
static bool hdmi_tx_hdcp_enable_auth_part1(struct it6161 *it6161)
|
||
{
|
||
int ret;
|
||
u8 i, count = 0;
|
||
|
||
ret = hdmi_tx_hdcp_get_bksv(it6161, it6161->bksv, (int)ARRAY_SIZE(it6161->bksv));
|
||
if (ret < 0)
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
DRM_INFO("bksv: 0x %*ph", (int)ARRAY_SIZE(it6161->bksv), it6161->bksv);
|
||
|
||
for (i = 0; i < ARRAY_SIZE(it6161->bksv); i++)
|
||
count += countbit(it6161->bksv[i]);
|
||
|
||
if (count != 20) {
|
||
DRM_INFO("not a valid bksv");
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
}
|
||
|
||
if ((it6161->bksv[4] == 0x93) &&
|
||
(it6161->bksv[3] == 0x43) &&
|
||
(it6161->bksv[2] == 0x5C) &&
|
||
(it6161->bksv[1] == 0xDE) &&
|
||
(it6161->bksv[0] == 0x23)) {
|
||
DRM_INFO("Revoked bksv");
|
||
return hdmiTxDev[0].bAuthenticated ;
|
||
}
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_HDCP_DESIRE, 0x08 | B_TX_CPDESIRE);
|
||
hdmi_tx_hdcp_generate_an(it6161);
|
||
hdmi_tx_hdcp_auth_fire(it6161);
|
||
|
||
return true;
|
||
}
|
||
|
||
static bool hdmi_tx_hdcp_auth_process(struct it6161 *it6161)
|
||
{
|
||
u8 bcaps;
|
||
u16 i, retry = 3;
|
||
int ret;
|
||
|
||
/* Authenticate should be called after AFE setup up */
|
||
|
||
DRM_INFO("start");
|
||
hdmiTxDev[0].bAuthenticated = false ;
|
||
it6161->hdmi_tx_hdcp_retry--;
|
||
hdmi_tx_hdcp_reset_auth(it6161);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_TX_HDCP_RST_HDMITX, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_LISTCTRL, 0x00);
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
hdmi_tx_hdcp_int_mask_enable(it6161);
|
||
|
||
for (i = 0; i < retry; i++) {
|
||
ret = hdmi_tx_hdcp_get_bstatus(it6161);
|
||
if(ret < 0)
|
||
continue;
|
||
it6161->bstatus = (u16)ret;
|
||
|
||
ret = hdmi_tx_hdcp_get_bcaps(it6161);
|
||
if (ret < 0)
|
||
continue;
|
||
bcaps = ret;
|
||
break;
|
||
}
|
||
|
||
if (i == retry)
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
|
||
DRM_INFO("bcaps: 0x%02x, bstatus: 0x%04x, hdmi_mode: %d", bcaps, it6161->bstatus,
|
||
it6161->bstatus & B_TX_CAP_HDMI_MODE);
|
||
it6161->is_repeater = !!(bcaps & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT);
|
||
DRM_INFO("downstream is hdcp %s", it6161->is_repeater ? "repeater" : "receiver");
|
||
if (it6161->is_repeater) {
|
||
it6161->hdcp_downstream_count = (u8)DRM_HDCP_NUM_DOWNSTREAM(it6161->bstatus);
|
||
DRM_INFO("down stream Count %d", it6161->hdcp_downstream_count);
|
||
if (it6161->hdcp_downstream_count > 6) {
|
||
DRM_INFO("over maximum supported number 6");
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
}
|
||
}
|
||
|
||
ret = hdmi_tx_hdcp_enable_auth_part1(it6161);
|
||
|
||
if (!ret)
|
||
return ret;
|
||
|
||
if (!it6161->is_repeater) {
|
||
ret = wait_for_completion_timeout(&it6161->wait_hdcp_event, msecs_to_jiffies(1000));
|
||
DRM_INFO("completion:%d", ret);
|
||
if (ret == 0)
|
||
DRM_INFO("hdcp-receiver: timeout");
|
||
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
}
|
||
return hdmiTxDev[0].bAuthenticated;
|
||
}
|
||
#endif
|
||
|
||
static void hdmitx_hdcp_ResumeAuthentication(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_av_mute(it6161, true);
|
||
if(hdmi_tx_hdcp_auth_process(it6161) == ER_SUCCESS)
|
||
{
|
||
}
|
||
it6161_hdmi_tx_set_av_mute(it6161, false);
|
||
}
|
||
|
||
static void hdmi_tx_hdcp_work(struct work_struct *work)
|
||
{
|
||
struct it6161 *it6161 = container_of(work, struct it6161,
|
||
hdcp_work.work);
|
||
//struct device *dev = &it6161->i2c_hdmi_tx->dev;
|
||
bool ret, sink_hpd = hdmi_tx_get_sink_hpd(it6161), video_state = hdmi_tx_get_video_state(it6161);
|
||
|
||
if (it6161->hdmi_tx_hdcp_retry <= 0 || !sink_hpd || !video_state) {
|
||
DRM_INFO("hdcp_retry:%d sink_hpd:%d video_stable_state:%d", it6161->hdmi_tx_hdcp_retry, sink_hpd, video_state);
|
||
return;
|
||
}
|
||
|
||
ret = hdmi_tx_hdcp_auth_process(it6161);
|
||
if (it6161->is_repeater) {
|
||
DRM_INFO("is repeater and wait for ksv list interrupt");
|
||
return;
|
||
}
|
||
|
||
DRM_INFO("hdcp_auth_process %s", ret ? "pass" : "failed");
|
||
}
|
||
|
||
static void hdmi_tx_enable_hdcp(struct it6161 *it6161)
|
||
{
|
||
struct device *dev = &it6161->i2c_hdmi_tx->dev;
|
||
|
||
DRM_DEV_DEBUG_DRIVER(dev, "start");
|
||
queue_delayed_work(system_wq, &it6161->hdcp_work,
|
||
msecs_to_jiffies(500));
|
||
}
|
||
#endif
|
||
|
||
static bool getHDMITX_LinkStatus(void)
|
||
{
|
||
it6161_debug("%s reg0E:0x%02x reg0x61:0x%02x", __func__, it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS), it6161_hdmi_tx_read(it6161, REG_TX_AFE_DRV_CTRL));//allen
|
||
if(B_TX_RXSENDETECT & it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS)) {
|
||
if(0==it6161_hdmi_tx_read(it6161, REG_TX_AFE_DRV_CTRL))
|
||
{
|
||
//DRM_INFO("getHDMITX_LinkStatus()!!\n");
|
||
return true;
|
||
}
|
||
}
|
||
DRM_INFO("GetTMDS not Ready()!!\n");
|
||
|
||
return false;
|
||
}
|
||
|
||
// static void HDMITX_PowerDown()
|
||
// {
|
||
// it6161_hdmi_tx_write_table(it6161, HDMITX_PwrDown_Table, ARRAY_SIZE(HDMITX_PwrDown_Table));
|
||
// }
|
||
|
||
static void hdmi_tx_setup_pclk_div2(struct it6161 *it6161)
|
||
{
|
||
if (HDMI_TX_PCLK_DIV2) {
|
||
DRM_INFO("PCLK Divided by 2 mode");
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_INPUT_MODE, B_TX_PCLKDIV2, B_TX_PCLKDIV2);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmi_tx_setup_csc
|
||
// Parameter: input_mode -
|
||
// D[1:0] - Color Mode
|
||
// D[4] - Colorimetry 0: ITU_BT601 1: ITU_BT709
|
||
// D[5] - Quantization 0: 0_255 1: 16_235
|
||
// D[6] - Up/Dn Filter 'Required'
|
||
// 0: no up/down filter
|
||
// 1: enable up/down filter when csc need.
|
||
// D[7] - Dither Filter 'Required'
|
||
// 0: no dither enabled.
|
||
// 1: enable dither and dither free go "when required".
|
||
// output_mode -
|
||
// D[1:0] - Color mode.
|
||
// Return: N/A
|
||
// Remark: reg72~reg8D will be programmed depended the input with table.
|
||
// Side-Effect:
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
static void hdmi_tx_setup_csc(struct it6161 *it6161)
|
||
{
|
||
u8 ucData, csc = 0, i, filter = 0; // filter is for Video CTRL DN_FREE_GO,EN_DITHER,and ENUDFILT
|
||
u8 input_mode = it6161->hdmi_tx_input_color_space;
|
||
u8 output_mode = it6161->hdmi_tx_output_color_space;
|
||
|
||
// (1) YUV422 in,RGB/YUV444 output (Output is 8-bit,input is 12-bit)
|
||
// (2) YUV444/422 in,RGB output (CSC enable,and output is not YUV422)
|
||
// (3) RGB in,YUV444 output (CSC enable,and output is not YUV422)
|
||
//
|
||
// YUV444/RGB24 <-> YUV422 need set up/down filter.
|
||
DRM_INFO("hdmi_tx_setup_csc(u8 input_mode = %x,u8 output_mode = %x)\n", (int)input_mode, (int)output_mode);
|
||
switch(input_mode&F_MODE_CLRMOD_MASK)
|
||
{
|
||
#ifdef SUPPORT_INPUTYUV444
|
||
case F_MODE_YUV444:
|
||
DRM_INFO("Input mode is YUV444 ");
|
||
switch(output_mode&F_MODE_CLRMOD_MASK)
|
||
{
|
||
case F_MODE_YUV444:
|
||
DRM_INFO("Output mode is YUV444\n");
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
break ;
|
||
|
||
case F_MODE_YUV422:
|
||
DRM_INFO("Output mode is YUV422\n");
|
||
if(input_mode & F_VIDMODE_EN_UDFILT) // YUV444 to YUV422 need up/down filter for processing.
|
||
{
|
||
filter |= B_TX_EN_UDFILTER ;
|
||
}
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
break ;
|
||
case F_MODE_RGB444:
|
||
DRM_INFO("Output mode is RGB24\n");
|
||
csc = B_HDMITX_CSC_YUV2RGB ;
|
||
if(input_mode & F_VIDMODE_EN_DITHER) // YUV444 to RGB24 need dither
|
||
{
|
||
filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
|
||
}
|
||
break ;
|
||
}
|
||
break ;
|
||
#endif
|
||
|
||
#ifdef SUPPORT_INPUTYUV422
|
||
case F_MODE_YUV422:
|
||
DRM_INFO("Input mode is YUV422\n");
|
||
switch(output_mode&F_MODE_CLRMOD_MASK)
|
||
{
|
||
case F_MODE_YUV444:
|
||
DRM_INFO("Output mode is YUV444\n");
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
if(input_mode & F_VIDMODE_EN_UDFILT) // YUV422 to YUV444 need up filter
|
||
{
|
||
filter |= B_TX_EN_UDFILTER ;
|
||
}
|
||
if(input_mode & F_VIDMODE_EN_DITHER) // YUV422 to YUV444 need dither
|
||
{
|
||
filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
|
||
}
|
||
break ;
|
||
case F_MODE_YUV422:
|
||
DRM_INFO("Output mode is YUV422\n");
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
|
||
break ;
|
||
|
||
case F_MODE_RGB444:
|
||
DRM_INFO("Output mode is RGB24\n");
|
||
csc = B_HDMITX_CSC_YUV2RGB ;
|
||
if(input_mode & F_VIDMODE_EN_UDFILT) // YUV422 to RGB24 need up/dn filter.
|
||
{
|
||
filter |= B_TX_EN_UDFILTER ;
|
||
}
|
||
if(input_mode & F_VIDMODE_EN_DITHER) // YUV422 to RGB24 need dither
|
||
{
|
||
filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
|
||
}
|
||
break ;
|
||
}
|
||
break ;
|
||
#endif
|
||
|
||
#ifdef SUPPORT_INPUTRGB
|
||
case F_MODE_RGB444:
|
||
DRM_INFO("Input mode is RGB24\n");
|
||
switch(output_mode&F_MODE_CLRMOD_MASK)
|
||
{
|
||
case F_MODE_YUV444:
|
||
DRM_INFO("Output mode is YUV444\n");
|
||
csc = B_HDMITX_CSC_RGB2YUV ;
|
||
|
||
if(input_mode & F_VIDMODE_EN_DITHER) // RGB24 to YUV444 need dither
|
||
{
|
||
filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
|
||
}
|
||
break ;
|
||
|
||
case F_MODE_YUV422:
|
||
DRM_INFO("Output mode is YUV422\n");
|
||
if(input_mode & F_VIDMODE_EN_UDFILT) // RGB24 to YUV422 need down filter.
|
||
{
|
||
filter |= B_TX_EN_UDFILTER ;
|
||
}
|
||
if(input_mode & F_VIDMODE_EN_DITHER) // RGB24 to YUV422 need dither
|
||
{
|
||
filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
|
||
}
|
||
csc = B_HDMITX_CSC_RGB2YUV ;
|
||
break ;
|
||
|
||
case F_MODE_RGB444:
|
||
DRM_INFO("Output mode is RGB24\n");
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
break ;
|
||
}
|
||
break ;
|
||
#endif
|
||
}
|
||
#ifndef DISABLE_HDMITX_CSC
|
||
|
||
#ifdef SUPPORT_INPUTRGB
|
||
// set the CSC metrix registers by colorimetry and quantization
|
||
if(csc == B_HDMITX_CSC_RGB2YUV)
|
||
{
|
||
DRM_INFO("CSC = RGB2YUV %x ",csc);
|
||
switch(input_mode&(F_VIDMODE_ITU709|F_VIDMODE_16_235))
|
||
{
|
||
case F_VIDMODE_ITU709|F_VIDMODE_16_235:
|
||
DRM_INFO("ITU709 16-235 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_RGB2YUV_ITU709_16_235[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_RGB2YUV_ITU709_16_235[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU709|F_VIDMODE_0_255:
|
||
DRM_INFO("ITU709 0-255 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_RGB2YUV_ITU709_0_255[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_RGB2YUV_ITU709_0_255[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU601|F_VIDMODE_16_235:
|
||
DRM_INFO("ITU601 16-235 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_RGB2YUV_ITU601_16_235[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_RGB2YUV_ITU601_16_235[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU601|F_VIDMODE_0_255:
|
||
default:
|
||
DRM_INFO("ITU601 0-255 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_RGB2YUV_ITU601_0_255[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_RGB2YUV_ITU601_0_255[i]);}
|
||
break ;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifdef SUPPORT_INPUTYUV
|
||
if (csc == B_HDMITX_CSC_YUV2RGB)
|
||
{
|
||
DRM_INFO("CSC = YUV2RGB %x ",csc);
|
||
|
||
switch(input_mode&(F_VIDMODE_ITU709|F_VIDMODE_16_235))
|
||
{
|
||
case F_VIDMODE_ITU709|F_VIDMODE_16_235:
|
||
DRM_INFO("ITU709 16-235 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_YUV2RGB_ITU709_16_235[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_YUV2RGB_ITU709_16_235[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU709|F_VIDMODE_0_255:
|
||
DRM_INFO("ITU709 0-255 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_YUV2RGB_ITU709_0_255[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_YUV2RGB_ITU709_0_255[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU601|F_VIDMODE_16_235:
|
||
DRM_INFO("ITU601 16-235 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_YUV2RGB_ITU601_16_235[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_YUV2RGB_ITU601_16_235[i]);}
|
||
break ;
|
||
case F_VIDMODE_ITU601|F_VIDMODE_0_255:
|
||
default:
|
||
DRM_INFO("ITU601 0-255 ");
|
||
for( i = 0 ; i < SIZEOF_CSCMTX ; i++ ){ it6161_hdmi_tx_write(it6161, REG_TX_CSC_YOFF+i,bCSCMtx_YUV2RGB_ITU601_0_255[i]) ; DRM_INFO("reg%02X <- %02X\n",(int)(i+REG_TX_CSC_YOFF),(int)bCSCMtx_YUV2RGB_ITU601_0_255[i]);}
|
||
break ;
|
||
}
|
||
}
|
||
#endif
|
||
#else// DISABLE_HDMITX_CSC
|
||
csc = B_HDMITX_CSC_BYPASS ;
|
||
#endif// DISABLE_HDMITX_CSC
|
||
|
||
if( csc == B_HDMITX_CSC_BYPASS )
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0xF, 0x10, 0x10);
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, 0xF, 0x10, 0x00);
|
||
}
|
||
ucData = it6161_hdmi_tx_read(it6161, REG_TX_CSC_CTRL) & ~(M_TX_CSC_SEL|B_TX_DNFREE_GO|B_TX_EN_DITHER|B_TX_EN_UDFILTER);
|
||
ucData |= filter|csc ;
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_CSC_CTRL,ucData);
|
||
}
|
||
|
||
// Parameter: VIDEOPCLKLEVEL level
|
||
// PCLK_LOW - for 13.5MHz (for mode less than 1080p)
|
||
// PCLK MEDIUM - for 25MHz~74MHz
|
||
// PCLK HIGH - PCLK > 80Hz (for 1080p mode or above)
|
||
// Remark: set reg62~reg65 depended on HighFreqMode
|
||
// reg61 have to be programmed at last and after video stable input.
|
||
|
||
static void hdmi_tx_setup_afe(struct it6161 *it6161, VIDEOPCLKLEVEL level)
|
||
{
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AFE_DRV_CTRL, B_TX_AFE_DRV_RST);
|
||
switch(level)
|
||
{
|
||
case PCLK_HIGH:
|
||
it6161_hdmi_tx_set_bits(it6161, 0x62, 0x90, 0x80);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x64, 0x89, 0x80);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x68, 0x10, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x66, 0x80, 0x80);//hdmitxset(0x66, 0x80, 0x80);// mark fix 6017
|
||
break ;
|
||
default:
|
||
it6161_hdmi_tx_set_bits(it6161, 0x62, 0x90, 0x10);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x64, 0x89, 0x09);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x68, 0x10, 0x10);
|
||
break ;
|
||
}
|
||
DRM_INFO("setup afe: %s", level ? "high" : "low");
|
||
#ifdef REDUCE_HDMITX_SRC_JITTER
|
||
//it6161_hdmi_tx_set_bits(it6161, 0x64, 0x01, 0x00); //pet: TODO need check
|
||
// it6161_hdmi_tx_set_bits(it6161, 0x6A, 0xFF, 0xFF);
|
||
|
||
// 2019/02/15 modified by jjtseng,
|
||
// Dr. Liu:
|
||
// it6161 <20>b<EFBFBD><62> Solomon mipi TX (<28>Ψ<EFBFBD>Ljitter <20>ܤj<DCA4><6A>source<63><65>), <20>Х[<5B>H<EFBFBD>U<EFBFBD>]<5D>w
|
||
// reg[6A]=0x5D
|
||
// Note: Register 6A is REG_XP_TEST[7:0], its eye and jitter CTS report please see attached file
|
||
//
|
||
// it6161 <20>b<EFBFBD><62> ite mipi TX (<28>Ψ<EFBFBD>Ljitter OK<4F><4B>source<63><65>), keep
|
||
// [6A]=0x00 (default setting)
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, 0x6A, 0xFF, 0x5D);
|
||
#endif
|
||
}
|
||
|
||
// Remark: write reg61 with 0x04
|
||
// When program reg61 with 0x04,then audio and video circuit work.
|
||
|
||
static void hdmi_tx_fire_afe(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AFE_DRV_CTRL, 0x00);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// utility function for main..
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
// #ifndef DISABLE_HDMITX_CSC
|
||
// #if (defined (SUPPORT_OUTPUTYUV)) && (defined (SUPPORT_INPUTRGB))
|
||
// extern const u8 bCSCMtx_RGB2YUV_ITU601_16_235[] ;
|
||
// extern const u8 bCSCMtx_RGB2YUV_ITU601_0_255[] ;
|
||
// extern const u8 bCSCMtx_RGB2YUV_ITU709_16_235[] ;
|
||
// extern const u8 bCSCMtx_RGB2YUV_ITU709_0_255[] ;
|
||
// #endif
|
||
|
||
// #if (defined (SUPPORT_OUTPUTRGB)) && (defined (SUPPORT_INPUTYUV))
|
||
// extern const u8 bCSCMtx_YUV2RGB_ITU601_16_235[] ;
|
||
// extern const u8 bCSCMtx_YUV2RGB_ITU601_0_255[] ;
|
||
// extern const u8 bCSCMtx_YUV2RGB_ITU709_16_235[] ;
|
||
// extern const u8 bCSCMtx_YUV2RGB_ITU709_0_255[] ;
|
||
|
||
// #endif
|
||
// #endif// DISABLE_HDMITX_CSC
|
||
|
||
|
||
static void hdmi_tx_disable_video_output(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_VID_RST, B_HDMITX_VID_RST);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AFE_DRV_CTRL,B_TX_AFE_DRV_RST|B_TX_AFE_DRV_PWD);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x62, 0x90, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, 0x64, 0x89, 0x00);
|
||
}
|
||
|
||
static void hdmi_tx_enable_video_output(struct it6161 *it6161, VIDEOPCLKLEVEL level)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, B_HDMITX_AUD_RST | B_TX_AREF_RST | B_TX_HDCP_RST_HDMITX);
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB1, 0x00);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
|
||
if(it6161->hdmi_mode)
|
||
it6161_hdmi_tx_set_av_mute(it6161, true);
|
||
|
||
hdmi_tx_setup_pclk_div2(it6161);
|
||
hdmi_tx_setup_csc(it6161);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_HDMI_MODE, it6161->hdmi_mode ? B_TX_HDMI_MODE : B_TX_DVI_MODE);
|
||
hdmi_tx_setup_afe(it6161, level);
|
||
hdmi_tx_fire_afe(it6161);
|
||
}
|
||
|
||
static u8 AudioDelayCnt=0;
|
||
static u8 LastRefaudfreqnum=0;
|
||
static bool bForceCTS = false;
|
||
|
||
static void setHDMITX_ChStat(struct it6161 *it6161, u8 ucIEC60958ChStat[])
|
||
{
|
||
u8 uc ;
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
uc = (ucIEC60958ChStat[0] <<1)& 0x7C ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_MODE,uc);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_CAT,ucIEC60958ChStat[1]); // 192, audio CATEGORY
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_SRCNUM,ucIEC60958ChStat[2]&0xF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD0CHST_CHTNUM,(ucIEC60958ChStat[2]>>4)&0xF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_CA_FS,ucIEC60958ChStat[3]); // choose clock
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_OFS_WL,ucIEC60958ChStat[4]);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
}
|
||
/*
|
||
void setHDMITX_UpdateChStatFs(u32 Fs)
|
||
{
|
||
u8 uc ;
|
||
|
||
/////////////////////////////////////
|
||
// Fs should be the following value.
|
||
// #define AUDFS_22p05KHz 4
|
||
// #define AUDFS_44p1KHz 0
|
||
// #define AUDFS_88p2KHz 8
|
||
// #define AUDFS_176p4KHz 12
|
||
//
|
||
// #define AUDFS_24KHz 6
|
||
// #define AUDFS_48KHz 2
|
||
// #define AUDFS_96KHz 10
|
||
// #define AUDFS_192KHz 14
|
||
//
|
||
// #define AUDFS_768KHz 9
|
||
//
|
||
// #define AUDFS_32KHz 3
|
||
// #define AUDFS_OTHER 1
|
||
/////////////////////////////////////
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_AUDCHST_CA_FS); // choose clock
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_CA_FS,uc); // choose clock
|
||
uc &= 0xF0 ;
|
||
uc |= (Fs&0xF);
|
||
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_AUDCHST_OFS_WL);
|
||
uc &= 0xF ;
|
||
uc |= ((~Fs) << 4)&0xF0 ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_OFS_WL,uc);
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
}
|
||
*/
|
||
static void setHDMITX_LPCMAudio(u8 AudioSrcNum, u8 AudSWL, u8 bAudInterface /*I2S/SPDIF/TDM*/)
|
||
{
|
||
|
||
u8 AudioEnable, AudioFormat ;
|
||
u8 bTDMSetting ;
|
||
AudioEnable = 0 ;
|
||
AudioFormat = hdmiTxDev[0].bOutputAudioMode ;
|
||
|
||
switch(AudSWL)
|
||
{
|
||
case 16:
|
||
AudioEnable |= M_TX_AUD_16BIT ;
|
||
break ;
|
||
case 18:
|
||
AudioEnable |= M_TX_AUD_18BIT ;
|
||
break ;
|
||
case 20:
|
||
AudioEnable |= M_TX_AUD_20BIT ;
|
||
break ;
|
||
case 24:
|
||
default:
|
||
AudioEnable |= M_TX_AUD_24BIT ;
|
||
break ;
|
||
}
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
AudioFormat &= ~0x40 ;
|
||
AudioEnable |= B_TX_AUD_SPDIF|B_TX_AUD_EN_I2S0 ;
|
||
}
|
||
else
|
||
{
|
||
AudioFormat |= 0x40 ;
|
||
switch(AudioSrcNum)
|
||
{
|
||
case 4:
|
||
AudioEnable |= B_TX_AUD_EN_I2S3|B_TX_AUD_EN_I2S2|B_TX_AUD_EN_I2S1|B_TX_AUD_EN_I2S0 ;
|
||
break ;
|
||
|
||
case 3:
|
||
AudioEnable |= B_TX_AUD_EN_I2S2|B_TX_AUD_EN_I2S1|B_TX_AUD_EN_I2S0 ;
|
||
break ;
|
||
|
||
case 2:
|
||
AudioEnable |= B_TX_AUD_EN_I2S1|B_TX_AUD_EN_I2S0 ;
|
||
break ;
|
||
|
||
case 1:
|
||
default:
|
||
AudioFormat &= ~0x40 ;
|
||
AudioEnable |= B_TX_AUD_EN_I2S0 ;
|
||
break ;
|
||
|
||
}
|
||
}
|
||
AudioFormat|=0x01;//mingchih add
|
||
hdmiTxDev[0].bAudioChannelEnable=AudioEnable;
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0,AudioEnable&0xF0);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL1,AudioFormat); // regE1 bOutputAudioMode should be loaded from ROM image.
|
||
#ifdef USE_IT66120
|
||
it6161_hdmi_tx_set_bits(it6161, 0x5A,0x02, 0x00);
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xFF); // default mapping.
|
||
}
|
||
#else
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
#endif
|
||
|
||
#ifdef USE_SPDIF_CHSTAT
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,B_TX_CHSTSEL);
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,0);
|
||
}
|
||
#else // not USE_SPDIF_CHSTAT
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,0);
|
||
#endif // USE_SPDIF_CHSTAT
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_SRCVALID_FLAT,0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO,0x00); // regE5 = 0 ;
|
||
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
u8 i ;
|
||
it6161_hdmi_tx_set_bits(it6161, 0x5c,(1<<6), (1<<6));
|
||
for( i = 0 ; i < 100 ; i++ )
|
||
{
|
||
if(it6161_hdmi_tx_read(it6161, REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
|
||
{
|
||
break ; // stable clock.
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bTDMSetting = it6161_hdmi_tx_read(it6161, REG_TX_AUD_HDAUDIO) ;
|
||
if( bAudInterface == TDM )
|
||
{
|
||
bTDMSetting |= B_TX_TDM ;
|
||
bTDMSetting &= 0x9F ;
|
||
bTDMSetting |= (AudioSrcNum-1)<< 5;
|
||
}
|
||
else
|
||
{
|
||
bTDMSetting &= ~B_TX_TDM ;
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO, bTDMSetting) ; // 2 channel NLPCM, no TDM mode.
|
||
}
|
||
}
|
||
|
||
static void setHDMITX_NLPCMAudio(u8 bAudInterface /*I2S/SPDIF/TDM*/) // no Source Num, no I2S.
|
||
{
|
||
u8 AudioEnable, AudioFormat ;
|
||
u8 i ;
|
||
|
||
AudioFormat = 0x01 ; // NLPCM must use standard I2S mode.
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
AudioEnable = M_TX_AUD_24BIT|B_TX_AUD_SPDIF;
|
||
}
|
||
else
|
||
{
|
||
AudioEnable = M_TX_AUD_24BIT;
|
||
}
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
// it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_SPDIF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, AudioEnable);
|
||
//it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_AUD_RST|B_TX_AREF_RST, 0x00);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL1,0x01); // regE1 bOutputAudioMode should be loaded from ROM image.
|
||
#ifdef USE_IT66120
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xFF); // default mapping.
|
||
}
|
||
#else
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
#endif
|
||
|
||
#ifdef USE_SPDIF_CHSTAT
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,B_TX_CHSTSEL);
|
||
#else // not USE_SPDIF_CHSTAT
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,0);
|
||
#endif // USE_SPDIF_CHSTAT
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_SRCVALID_FLAT,0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO,0x00); // regE5 = 0 ;
|
||
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
for( i = 0 ; i < 100 ; i++ )
|
||
{
|
||
if(it6161_hdmi_tx_read(it6161, REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
|
||
{
|
||
break ; // stable clock.
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
i = it6161_hdmi_tx_read(it6161, REG_TX_AUD_HDAUDIO) ;
|
||
i &= ~B_TX_TDM ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO, i) ; // 2 channel NLPCM, no TDM mode.
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, AudioEnable|B_TX_AUD_EN_I2S0);
|
||
}
|
||
|
||
static void setHDMITX_HBRAudio(u8 bAudInterface /*I2S/SPDIF/TDM*/)
|
||
{
|
||
// u8 rst;
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
|
||
// rst = it6161_hdmi_tx_read(it6161, REG_TX_SW_RST);
|
||
// rst &= ~(B_HDMITX_AUD_RST|B_TX_AREF_RST);
|
||
|
||
// it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, rst | B_HDMITX_AUD_RST );
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL1,0x47); // regE1 bOutputAudioMode should be loaded from ROM image.
|
||
#ifdef USE_IT66120
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xFF); // default mapping.
|
||
}
|
||
#else
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
#endif
|
||
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_SPDIF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,B_TX_CHSTSEL);
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,0);
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_SRCVALID_FLAT,0x08);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO,B_TX_HBR); // regE5 = 0 ;
|
||
|
||
//uc = it6161_hdmi_tx_read(it6161, REG_TX_CLK_CTRL1);
|
||
//uc &= ~M_TX_AUD_DIV ;
|
||
//it6161_hdmi_tx_write(it6161, REG_TX_CLK_CTRL1, uc);
|
||
|
||
if( bAudInterface == SPDIF )
|
||
{
|
||
u8 i ;
|
||
for( i = 0 ; i < 100 ; i++ )
|
||
{
|
||
if(it6161_hdmi_tx_read(it6161, REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
|
||
{
|
||
break ; // stable clock.
|
||
}
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_SPDIF|B_TX_AUD_EN_SPDIF);
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_EN_I2S3|B_TX_AUD_EN_I2S2|B_TX_AUD_EN_I2S1|B_TX_AUD_EN_I2S0);
|
||
}
|
||
it6161_hdmi_tx_set_bits(it6161, 0x5c, BIT(6), 0x00);
|
||
hdmiTxDev[0].bAudioChannelEnable=it6161_hdmi_tx_read(it6161, REG_TX_AUDIO_CTRL0);
|
||
// it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, rst );
|
||
}
|
||
|
||
static void setHDMITX_DSDAudio(void)
|
||
{
|
||
// to be continue
|
||
// u8 rst;
|
||
// rst = it6161_hdmi_tx_read(it6161, REG_TX_SW_RST);
|
||
|
||
//it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, rst | (B_HDMITX_AUD_RST|B_TX_AREF_RST) );
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL1,0x41); // regE1 bOutputAudioMode should be loaded from ROM image.
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_FIFOMAP,0xE4); // default mapping.
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL3,0);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_SRCVALID_FLAT,0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_HDAUDIO,B_TX_DSD); // regE5 = 0 ;
|
||
//it6161_hdmi_tx_write(it6161, REG_TX_SW_RST, rst & ~(B_HDMITX_AUD_RST|B_TX_AREF_RST) );
|
||
|
||
//uc = it6161_hdmi_tx_read(it6161, REG_TX_CLK_CTRL1);
|
||
//uc &= ~M_TX_AUD_DIV ;
|
||
//it6161_hdmi_tx_write(it6161, REG_TX_CLK_CTRL1, uc);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_EN_I2S3|B_TX_AUD_EN_I2S2|B_TX_AUD_EN_I2S1|B_TX_AUD_EN_I2S0);
|
||
}
|
||
|
||
static void HDMITX_DisableAudioOutput(struct it6161 *it6161)
|
||
{
|
||
//u8 uc = (it6161_hdmi_tx_read(it6161, REG_TX_SW_RST) | (B_HDMITX_AUD_RST | B_TX_AREF_RST));
|
||
//it6161_hdmi_tx_write(it6161, REG_TX_SW_RST,uc);
|
||
AudioDelayCnt=AudioOutDelayCnt;
|
||
LastRefaudfreqnum=0;
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST), (B_HDMITX_AUD_RST | B_TX_AREF_RST) );
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x10, 0x10 );
|
||
}
|
||
|
||
static void HDMITX_EnableAudioOutput(struct it6161 *it6161, u8 AudioType, u8 bAudInterface /*I2S/SPDIF/TDM*/, u32 SampleFreq, u8 ChNum, u8 *pIEC60958ChStat, u32 TMDSClock)
|
||
{
|
||
static u8 ucIEC60958ChStat[5] ;
|
||
|
||
u8 Fs ;
|
||
AudioDelayCnt=36;
|
||
LastRefaudfreqnum=0;
|
||
hdmiTxDev[0].TMDSClock=TMDSClock;
|
||
hdmiTxDev[0].bAudioChannelEnable=0;
|
||
hdmiTxDev[0].bAudInterface=bAudInterface;
|
||
|
||
//DRM_INFO1(("HDMITX_EnableAudioOutput(%02X, %s, %d, %d, %p, %d);\n",
|
||
// AudioType, bSPDIF?"SPDIF":"I2S",SampleFreq, ChNum, pIEC60958ChStat, TMDSClock
|
||
// ));
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST,(B_HDMITX_AUD_RST | B_TX_AREF_RST), (B_HDMITX_AUD_RST | B_TX_AREF_RST));
|
||
it6161_hdmi_tx_write(it6161, REG_TX_CLK_CTRL0,B_TX_AUTO_OVER_SAMPLING_CLOCK|B_TX_EXT_256FS|0x01);
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, 0x0F, 0x10, 0x00 ); // power on the ACLK
|
||
|
||
if(bAudInterface == SPDIF)
|
||
{
|
||
if(AudioType==T_AUDIO_HBR)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, REG_TX_CLK_CTRL0,0x81);
|
||
}
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_AUDIO_CTRL0,B_TX_AUD_SPDIF, B_TX_AUD_SPDIF);
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_AUDIO_CTRL0, B_TX_AUD_SPDIF, 0x00);
|
||
}
|
||
if( AudioType != T_AUDIO_DSD)
|
||
{
|
||
// one bit audio have no channel status.
|
||
switch(SampleFreq)
|
||
{
|
||
case 44100L: Fs = AUDFS_44p1KHz ; break ;
|
||
case 88200L: Fs = AUDFS_88p2KHz ; break ;
|
||
case 176400L: Fs = AUDFS_176p4KHz ; break ;
|
||
case 32000L: Fs = AUDFS_32KHz ; break ;
|
||
case 48000L: Fs = AUDFS_48KHz ; break ;
|
||
case 96000L: Fs = AUDFS_96KHz ; break ;
|
||
case 192000L: Fs = AUDFS_192KHz ; break ;
|
||
case 768000L: Fs = AUDFS_768KHz ; break ;
|
||
default:
|
||
SampleFreq = 48000L ;
|
||
Fs = AUDFS_48KHz ;
|
||
break ; // default, set Fs = 48KHz.
|
||
}
|
||
#ifdef SUPPORT_AUDIO_MONITOR
|
||
hdmiTxDev[0].bAudFs=Fs;// AUDFS_OTHER;
|
||
#else
|
||
hdmiTxDev[0].bAudFs=Fs;
|
||
#endif
|
||
setHDMITX_NCTS(hdmiTxDev[0].bAudFs);
|
||
if( pIEC60958ChStat == NULL )
|
||
{
|
||
ucIEC60958ChStat[0] = 0 ;
|
||
ucIEC60958ChStat[1] = 0 ;
|
||
ucIEC60958ChStat[2] = (ChNum+1)/2 ;
|
||
|
||
if(ucIEC60958ChStat[2]<1)
|
||
{
|
||
ucIEC60958ChStat[2] = 1 ;
|
||
}
|
||
else if( ucIEC60958ChStat[2] >4 )
|
||
{
|
||
ucIEC60958ChStat[2] = 4 ;
|
||
}
|
||
ucIEC60958ChStat[3] = Fs ;
|
||
ucIEC60958ChStat[4] = (((~Fs)<<4) & 0xF0) | CHTSTS_SWCODE ; // Fs | 24bit u32 length
|
||
pIEC60958ChStat = ucIEC60958ChStat ;
|
||
}
|
||
}
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST,(B_HDMITX_AUD_RST|B_TX_AREF_RST),B_TX_AREF_RST);
|
||
|
||
switch(AudioType)
|
||
{
|
||
case T_AUDIO_HBR:
|
||
DRM_INFO("T_AUDIO_HBR\n");
|
||
pIEC60958ChStat[0] |= 1<<1 ;
|
||
pIEC60958ChStat[2] = 0;
|
||
pIEC60958ChStat[3] &= 0xF0 ;
|
||
pIEC60958ChStat[3] |= AUDFS_768KHz ;
|
||
pIEC60958ChStat[4] |= (((~AUDFS_768KHz)<<4) & 0xF0)| 0xB ;
|
||
setHDMITX_ChStat(it6161, pIEC60958ChStat);
|
||
setHDMITX_HBRAudio(bAudInterface);
|
||
|
||
break ;
|
||
case T_AUDIO_DSD:
|
||
DRM_INFO("T_AUDIO_DSD\n");
|
||
setHDMITX_DSDAudio();
|
||
break ;
|
||
case T_AUDIO_NLPCM:
|
||
DRM_INFO("T_AUDIO_NLPCM\n");
|
||
pIEC60958ChStat[0] |= 1<<1 ;
|
||
setHDMITX_ChStat(it6161, pIEC60958ChStat);
|
||
setHDMITX_NLPCMAudio(bAudInterface);
|
||
break ;
|
||
case T_AUDIO_LPCM:
|
||
DRM_INFO("T_AUDIO_LPCM\n");
|
||
pIEC60958ChStat[0] &= ~(1<<1);
|
||
|
||
setHDMITX_ChStat(it6161, pIEC60958ChStat);
|
||
setHDMITX_LPCMAudio((ChNum+1)/2, SUPPORT_AUDI_AudSWL, bAudInterface);
|
||
// can add auto adjust
|
||
break ;
|
||
}
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_INT_MASK1, B_TX_AUDIO_OVFLW_MASK, 0x00);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, hdmiTxDev[0].bAudioChannelEnable);
|
||
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST,(B_HDMITX_AUD_RST|B_TX_AREF_RST),0);
|
||
}
|
||
#ifdef SUPPORT_AUDIO_MONITOR
|
||
void hdmitx_AutoAdjustAudio()
|
||
{
|
||
u32 SampleFreq,cTMDSClock ;
|
||
u32 N ;
|
||
u32 aCTS=0;
|
||
u8 fs, uc,LoopCnt=10;
|
||
if(bForceCTS)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xC3);
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xA5);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL, B_TX_SW_CTS, 0x00); // D[1] = 0, HW auto count CTS
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xFF);
|
||
}
|
||
//msleep(50);
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
N = ((u32)it6161_hdmi_tx_read(it6161, REGPktAudN2)&0xF) << 16 ;
|
||
N |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudN1)) <<8 ;
|
||
N |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudN0));
|
||
|
||
while(LoopCnt--)
|
||
{ u32 TempCTS=0;
|
||
aCTS = ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt2)) << 12 ;
|
||
aCTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt1)) <<4 ;
|
||
aCTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt0)&0xf0)>>4 ;
|
||
if(aCTS==TempCTS)
|
||
{break;}
|
||
TempCTS=aCTS;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
if( aCTS == 0)
|
||
{
|
||
DRM_INFO("aCTS== 0");
|
||
return;
|
||
}
|
||
uc = it6161_hdmi_tx_read(it6161, REG_TX_GCP);
|
||
|
||
cTMDSClock = hdmiTxDev[0].TMDSClock ;
|
||
//TMDSClock=GetInputPclk();
|
||
DRM_INFO("PCLK = %u0,000\n",(u32)(cTMDSClock/10000));
|
||
switch(uc & 0x70)
|
||
{
|
||
case 0x50:
|
||
cTMDSClock *= 5 ;
|
||
cTMDSClock /= 4 ;
|
||
break ;
|
||
case 0x60:
|
||
cTMDSClock *= 3 ;
|
||
cTMDSClock /= 2 ;
|
||
}
|
||
SampleFreq = cTMDSClock/aCTS ;
|
||
SampleFreq *= N ;
|
||
SampleFreq /= 128 ;
|
||
//SampleFreq=48000;
|
||
|
||
DRM_INFO("SampleFreq = %u0\n",(u32)(SampleFreq/10));
|
||
if( SampleFreq>31000L && SampleFreq<=38050L ){fs = AUDFS_32KHz ;}
|
||
else if (SampleFreq < 46550L ) {fs = AUDFS_44p1KHz ;}//46050
|
||
else if (SampleFreq < 68100L ) {fs = AUDFS_48KHz ;}
|
||
else if (SampleFreq < 92100L ) {fs = AUDFS_88p2KHz ;}
|
||
else if (SampleFreq < 136200L ) {fs = AUDFS_96KHz ;}
|
||
else if (SampleFreq < 184200L ) {fs = AUDFS_176p4KHz ;}
|
||
else if (SampleFreq < 240200L ) {fs = AUDFS_192KHz ;}
|
||
else if (SampleFreq < 800000L ) {fs = AUDFS_768KHz ;}
|
||
else
|
||
{
|
||
fs = AUDFS_OTHER;
|
||
DRM_INFO("fs = AUDFS_OTHER\n");
|
||
}
|
||
if(hdmiTxDev[0].bAudFs != fs)
|
||
{
|
||
hdmiTxDev[0].bAudFs=fs;
|
||
setHDMITX_NCTS(hdmiTxDev[0].bAudFs); // set N, CTS by new generated clock.
|
||
//CurrCTS=0;
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
bool hdmitx_IsAudioChang()
|
||
{
|
||
//u32 pCTS=0;
|
||
u8 FreDiff=0,Refaudfreqnum;
|
||
|
||
//it6161_hdmi_tx_change_bank(it6161, 1);
|
||
//pCTS = ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt2)) << 12 ;
|
||
//pCTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt1)) <<4 ;
|
||
//pCTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt0)&0xf0)>>4 ;
|
||
//it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
Refaudfreqnum=it6161_hdmi_tx_read(it6161, 0x60);
|
||
//"Refaudfreqnum=%X pCTS= %u",(u32)Refaudfreqnum,(u32)(pCTS/10000)));
|
||
//if((pCTS%10000)<1000)DRM_INFO("0");
|
||
//if((pCTS%10000)<100)DRM_INFO("0");
|
||
//if((pCTS%10000)<10)DRM_INFO("0");
|
||
//DRM_INFO("%u\n",(u32)(pCTS%10000));
|
||
if((1<<4)&it6161_hdmi_tx_read(it6161, 0x5f))
|
||
{
|
||
//printf("=======XXXXXXXXXXX=========\n");
|
||
return false;
|
||
}
|
||
if(LastRefaudfreqnum>Refaudfreqnum)
|
||
{FreDiff=LastRefaudfreqnum-Refaudfreqnum;}
|
||
else
|
||
{FreDiff=Refaudfreqnum-LastRefaudfreqnum;}
|
||
LastRefaudfreqnum=Refaudfreqnum;
|
||
if(3<FreDiff)
|
||
{
|
||
DRM_INFO("Aduio FreDiff=%d\n",(int)FreDiff);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL,(1<<5), (1<<5));
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_AUDIO_CTRL0, 0x0F, 0x00);
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
/*
|
||
void setHDMITX_AudioChannelEnable(bool EnableAudio_b)
|
||
{
|
||
static bool AudioOutStatus=false;
|
||
if(EnableAudio_b)
|
||
{
|
||
if(AudioDelayCnt==0)
|
||
{
|
||
//if(hdmiTxDev[0].bAuthenticated==false)
|
||
//{
|
||
#ifdef SUPPORT_AUDIO_MONITOR
|
||
if(hdmitx_IsAudioChang())
|
||
{
|
||
hdmitx_AutoAdjustAudio();
|
||
#else
|
||
if(AudioOutStatus==false)
|
||
{
|
||
setHDMITX_NCTS(hdmiTxDev[0].bAudFs);
|
||
#endif
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUD_SRCVALID_FLAT,0);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL,(1<<5), (1<<5));
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDIO_CTRL0, hdmiTxDev[0].bAudioChannelEnable);
|
||
//it6161_hdmi_tx_set_bits(it6161, 0x59,(1<<2), (1<<2)); //for test
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL, 0x3C, 0x00);
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL, 1<<5, 0x00);
|
||
printf("Audio Out Enable\n");
|
||
#ifndef SUPPORT_AUDIO_MONITOR
|
||
AudioOutStatus=true;
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AudioOutStatus=false;
|
||
if(0==(it6161_hdmi_tx_read(it6161, REG_TX_CLK_STATUS2)&0x10))
|
||
{
|
||
AudioDelayCnt--;
|
||
}
|
||
else
|
||
{
|
||
AudioDelayCnt=AudioOutDelayCnt;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// CurrCTS=0;
|
||
}
|
||
}*/
|
||
#endif //#ifdef SUPPORT_AUDIO_MONITOR
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: setHDMITX_NCTS
|
||
// Parameter: PCLK - video clock in Hz.
|
||
// Fs - Encoded audio sample rate
|
||
// AUDFS_22p05KHz 4
|
||
// AUDFS_44p1KHz 0
|
||
// AUDFS_88p2KHz 8
|
||
// AUDFS_176p4KHz 12
|
||
//
|
||
// AUDFS_24KHz 6
|
||
// AUDFS_48KHz 2
|
||
// AUDFS_96KHz 10
|
||
// AUDFS_192KHz 14
|
||
//
|
||
// AUDFS_768KHz 9
|
||
//
|
||
// AUDFS_32KHz 3
|
||
// AUDFS_OTHER 1
|
||
// Return: ER_SUCCESS if success
|
||
// Remark: set N value,the CTS will be auto generated by HW.
|
||
// Side-Effect: register bank will reset to bank 0.
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
static void setHDMITX_NCTS(u8 Fs)
|
||
{
|
||
u32 n;
|
||
u8 LoopCnt=255,CTSStableCnt=0;
|
||
u32 diff;
|
||
u32 CTS=0,LastCTS=0;
|
||
bool HBR_mode;
|
||
// u8 aVIC;
|
||
|
||
if(B_TX_HBR & it6161_hdmi_tx_read(it6161, REG_TX_AUD_HDAUDIO))
|
||
{
|
||
HBR_mode=true;
|
||
}
|
||
else
|
||
{
|
||
HBR_mode=false;
|
||
}
|
||
switch(Fs)
|
||
{
|
||
case AUDFS_32KHz: n = 4096; break;
|
||
case AUDFS_44p1KHz: n = 6272; break;
|
||
case AUDFS_48KHz: n = 6144; break;
|
||
case AUDFS_88p2KHz: n = 12544; break;
|
||
case AUDFS_96KHz: n = 12288; break;
|
||
case AUDFS_176p4KHz: n = 25088; break;
|
||
case AUDFS_192KHz: n = 24576; break;
|
||
case AUDFS_768KHz: n = 24576; break ;
|
||
default: n = 6144;
|
||
}
|
||
// tr_printf((" n = %d\n",n));
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
it6161_hdmi_tx_write(it6161, REGPktAudN0,(u8)((n)&0xFF));
|
||
it6161_hdmi_tx_write(it6161, REGPktAudN1,(u8)((n>>8)&0xFF));
|
||
it6161_hdmi_tx_write(it6161, REGPktAudN2,(u8)((n>>16)&0xF));
|
||
|
||
if(bForceCTS)
|
||
{
|
||
u32 SumCTS=0;
|
||
while(LoopCnt--)
|
||
{
|
||
msleep(30);
|
||
CTS = ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt2)) << 12 ;
|
||
CTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt1)) <<4 ;
|
||
CTS |= ((u32)it6161_hdmi_tx_read(it6161, REGPktAudCTSCnt0)&0xf0)>>4 ;
|
||
if( CTS == 0)
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
if(LastCTS>CTS )
|
||
{diff=LastCTS-CTS;}
|
||
else
|
||
{diff=CTS-LastCTS;}
|
||
//DRM_INFO("LastCTS= %u%u",(u32)(LastCTS/10000),(u32)(LastCTS%10000));
|
||
//DRM_INFO(" CTS= %u%u\n",(u32)(CTS/10000),(u32)(CTS%10000));
|
||
LastCTS=CTS;
|
||
if(5>diff)
|
||
{
|
||
CTSStableCnt++;
|
||
SumCTS+=CTS;
|
||
}
|
||
else
|
||
{
|
||
CTSStableCnt=0;
|
||
SumCTS=0;
|
||
continue;
|
||
}
|
||
if(CTSStableCnt>=32)
|
||
{
|
||
LastCTS=(SumCTS>>5);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
it6161_hdmi_tx_write(it6161, REGPktAudCTS0,(u8)((LastCTS)&0xFF));
|
||
it6161_hdmi_tx_write(it6161, REGPktAudCTS1,(u8)((LastCTS>>8)&0xFF));
|
||
it6161_hdmi_tx_write(it6161, REGPktAudCTS2,(u8)((LastCTS>>16)&0xF));
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
#ifdef Force_CTS
|
||
bForceCTS = true;
|
||
#endif
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xC3);
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xA5);
|
||
if(bForceCTS)
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL,B_TX_SW_CTS, B_TX_SW_CTS); // D[1] = 0, HW auto count CTS
|
||
}
|
||
else
|
||
{
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_PKT_SINGLE_CTRL, B_TX_SW_CTS, 0x00); // D[1] = 0, HW auto count CTS
|
||
}
|
||
it6161_hdmi_tx_write(it6161, 0xF8, 0xFF);
|
||
|
||
if(false==HBR_mode) //LPCM
|
||
{
|
||
u8 uData;
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
Fs = AUDFS_768KHz ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_CA_FS,0x00|Fs);
|
||
Fs = ~Fs ; // OFS is the one's complement of FS
|
||
uData = (0x0f&it6161_hdmi_tx_read(it6161, REG_TX_AUDCHST_OFS_WL));
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AUDCHST_OFS_WL,(Fs<<4)|uData);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmitx_SetAudioInfoFrame()
|
||
// Parameter: pAudioInfoFrame - the pointer to HDMI Audio Infoframe ucData
|
||
// Return: N/A
|
||
// Remark: Fill the Audio InfoFrame ucData,and count checksum,then fill into
|
||
// Audio InfoFrame registers.
|
||
// Side-Effect: N/A
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
static SYS_STATUS hdmitx_SetAudioInfoFrame(struct it6161 *it6161, Audio_InfoFrame *pAudioInfoFrame)
|
||
{
|
||
u8 checksum ;
|
||
|
||
if(!pAudioInfoFrame)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
checksum = 0x100-(AUDIO_INFOFRAME_VER+AUDIO_INFOFRAME_TYPE+AUDIO_INFOFRAME_LEN );
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_AUDINFO_CC,pAudioInfoFrame->pktbyte.AUD_DB[0]);
|
||
checksum -= it6161_hdmi_tx_read(it6161, REG_TX_PKT_AUDINFO_CC); checksum &= 0xFF ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_AUDINFO_SF,pAudioInfoFrame->pktbyte.AUD_DB[1]);
|
||
checksum -= it6161_hdmi_tx_read(it6161, REG_TX_PKT_AUDINFO_SF); checksum &= 0xFF ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_AUDINFO_CA,pAudioInfoFrame->pktbyte.AUD_DB[3]);
|
||
checksum -= it6161_hdmi_tx_read(it6161, REG_TX_PKT_AUDINFO_CA); checksum &= 0xFF ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_AUDINFO_DM_LSV,pAudioInfoFrame->pktbyte.AUD_DB[4]);
|
||
checksum -= it6161_hdmi_tx_read(it6161, REG_TX_PKT_AUDINFO_DM_LSV); checksum &= 0xFF ;
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_AUDINFO_SUM,checksum);
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
hdmitx_ENABLE_AUD_INFOFRM_PKT();
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmitx_SetAVIInfoFrame()
|
||
// Parameter: pAVIInfoFrame - the pointer to HDMI AVI Infoframe ucData
|
||
// Return: N/A
|
||
// Remark: Fill the AVI InfoFrame ucData,and count checksum,then fill into
|
||
// AVI InfoFrame registers.
|
||
// Side-Effect: N/A
|
||
//////////////////////////////////////////////////////////////////////
|
||
#if 0
|
||
static SYS_STATUS hdmitx_SetAVIInfoFrame(struct it6161 *it6161, AVI_InfoFrame *pAVIInfoFrame)
|
||
{
|
||
int i ;
|
||
u8 checksum ;
|
||
|
||
if(!pAVIInfoFrame)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB1,pAVIInfoFrame->pktbyte.AVI_DB[0]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB2,pAVIInfoFrame->pktbyte.AVI_DB[1]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB3,pAVIInfoFrame->pktbyte.AVI_DB[2]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB4,pAVIInfoFrame->pktbyte.AVI_DB[3]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB5,pAVIInfoFrame->pktbyte.AVI_DB[4]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB6,pAVIInfoFrame->pktbyte.AVI_DB[5]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB7,pAVIInfoFrame->pktbyte.AVI_DB[6]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB8,pAVIInfoFrame->pktbyte.AVI_DB[7]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB9,pAVIInfoFrame->pktbyte.AVI_DB[8]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB10,pAVIInfoFrame->pktbyte.AVI_DB[9]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB11,pAVIInfoFrame->pktbyte.AVI_DB[10]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB12,pAVIInfoFrame->pktbyte.AVI_DB[11]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB13,pAVIInfoFrame->pktbyte.AVI_DB[12]);
|
||
for(i = 0,checksum = 0; i < 13 ; i++)
|
||
{
|
||
checksum -= pAVIInfoFrame->pktbyte.AVI_DB[i] ;
|
||
}
|
||
/*
|
||
DRM_INFO("SetAVIInfo(): ");
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB1));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB2));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB3));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB4));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB5));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB6));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB7));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB8));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB9));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB10));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB11));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB12));
|
||
DRM_INFO("%02X ",(int)it6161_hdmi_tx_read(it6161, REG_TX_AVIINFO_DB13));
|
||
DRM_INFO("\n");
|
||
*/
|
||
checksum -= AVI_INFOFRAME_VER+AVI_INFOFRAME_TYPE+AVI_INFOFRAME_LEN ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_SUM,checksum);
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
hdmitx_ENABLE_AVI_INFOFRM_PKT();
|
||
return ER_SUCCESS ;
|
||
}
|
||
#endif
|
||
static SYS_STATUS hdmitx_SetVSIInfoFrame(struct it6161 *it6161, VendorSpecific_InfoFrame *pVSIInfoFrame)
|
||
{
|
||
u8 ucData=0 ;
|
||
|
||
if(!pVSIInfoFrame)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
it6161_hdmi_tx_write(it6161, 0x80,pVSIInfoFrame->pktbyte.VS_DB[3]);
|
||
it6161_hdmi_tx_write(it6161, 0x81,pVSIInfoFrame->pktbyte.VS_DB[4]);
|
||
|
||
ucData -= pVSIInfoFrame->pktbyte.VS_DB[3] ;
|
||
ucData -= pVSIInfoFrame->pktbyte.VS_DB[4] ;
|
||
|
||
if( pVSIInfoFrame->pktbyte.VS_DB[4] & (1<<7 ))
|
||
{
|
||
ucData -= pVSIInfoFrame->pktbyte.VS_DB[5] ;
|
||
it6161_hdmi_tx_write(it6161, 0x82,pVSIInfoFrame->pktbyte.VS_DB[5]);
|
||
ucData -= VENDORSPEC_INFOFRAME_TYPE + VENDORSPEC_INFOFRAME_VER + 6 + 0x0C + 0x03 ;
|
||
}
|
||
else
|
||
{
|
||
ucData -= VENDORSPEC_INFOFRAME_TYPE + VENDORSPEC_INFOFRAME_VER + 5 + 0x0C + 0x03 ;
|
||
}
|
||
|
||
pVSIInfoFrame->pktbyte.CheckSum=ucData;
|
||
|
||
it6161_hdmi_tx_write(it6161, 0x83,pVSIInfoFrame->pktbyte.CheckSum);
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_3D_INFO_CTRL,B_TX_ENABLE_PKT|B_TX_REPEAT_PKT);
|
||
return ER_SUCCESS ;
|
||
}
|
||
|
||
static bool HDMITX_EnableVSInfoFrame(struct it6161 *it6161, u8 bEnable,u8 *pVSInfoFrame)
|
||
{
|
||
if(!bEnable)
|
||
{
|
||
hdmitx_DISABLE_VSDB_PKT();
|
||
return true ;
|
||
}
|
||
if(hdmitx_SetVSIInfoFrame(it6161, (VendorSpecific_InfoFrame *)pVSInfoFrame) == ER_SUCCESS)
|
||
{
|
||
return true ;
|
||
}
|
||
return false ;
|
||
}
|
||
/*
|
||
static bool HDMITX_EnableAVIInfoFrame(struct it6161 *it6161, u8 bEnable,u8 *pAVIInfoFrame)
|
||
{
|
||
if(!bEnable)
|
||
{
|
||
hdmitx_DISABLE_AVI_INFOFRM_PKT();
|
||
return true ;
|
||
}
|
||
if(hdmitx_SetAVIInfoFrame(it6161, (AVI_InfoFrame *)pAVIInfoFrame) == ER_SUCCESS)
|
||
{
|
||
return true ;
|
||
}
|
||
return false ;
|
||
}
|
||
*/
|
||
static bool HDMITX_EnableAudioInfoFrame(struct it6161 *it6161, u8 bEnable,u8 *pAudioInfoFrame)
|
||
{
|
||
if(!bEnable)
|
||
{
|
||
hdmitx_DISABLE_AVI_INFOFRM_PKT();
|
||
return true ;
|
||
}
|
||
if(hdmitx_SetAudioInfoFrame(it6161, (Audio_InfoFrame *)pAudioInfoFrame) == ER_SUCCESS)
|
||
{
|
||
return true ;
|
||
}
|
||
return false ;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmitx_SetSPDInfoFrame()
|
||
// Parameter: pSPDInfoFrame - the pointer to HDMI SPD Infoframe ucData
|
||
// Return: N/A
|
||
// Remark: Fill the SPD InfoFrame ucData,and count checksum,then fill into
|
||
// SPD InfoFrame registers.
|
||
// Side-Effect: N/A
|
||
//////////////////////////////////////////////////////////////////////
|
||
/*
|
||
SYS_STATUS hdmitx_SetSPDInfoFrame(SPD_InfoFrame *pSPDInfoFrame)
|
||
{
|
||
int i ;
|
||
u8 ucData ;
|
||
|
||
if(!pSPDInfoFrame)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
for(i = 0,ucData = 0 ; i < 25 ; i++)
|
||
{
|
||
ucData -= pSPDInfoFrame->pktbyte.SPD_DB[i] ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_SPDINFO_PB1+i,pSPDInfoFrame->pktbyte.SPD_DB[i]);
|
||
}
|
||
ucData -= SPD_INFOFRAME_VER+SPD_INFOFRAME_TYPE+SPD_INFOFRAME_LEN ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_SPDINFO_SUM,ucData); // checksum
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
hdmitx_ENABLE_SPD_INFOFRM_PKT();
|
||
return ER_SUCCESS ;
|
||
}
|
||
*/
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Function: hdmitx_SetMPEGInfoFrame()
|
||
// Parameter: pMPEGInfoFrame - the pointer to HDMI MPEG Infoframe ucData
|
||
// Return: N/A
|
||
// Remark: Fill the MPEG InfoFrame ucData,and count checksum,then fill into
|
||
// MPEG InfoFrame registers.
|
||
// Side-Effect: N/A
|
||
//////////////////////////////////////////////////////////////////////
|
||
/*
|
||
SYS_STATUS hdmitx_SetMPEGInfoFrame(MPEG_InfoFrame *pMPGInfoFrame)
|
||
{
|
||
int i ;
|
||
u8 ucData ;
|
||
|
||
if(!pMPGInfoFrame)
|
||
{
|
||
return ER_FAIL ;
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKT_MPGINFO_FMT,pMPGInfoFrame->info.FieldRepeat|(pMPGInfoFrame->info.MpegFrame<<1));
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKG_MPGINFO_DB0,pMPGInfoFrame->pktbyte.MPG_DB[0]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKG_MPGINFO_DB1,pMPGInfoFrame->pktbyte.MPG_DB[1]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKG_MPGINFO_DB2,pMPGInfoFrame->pktbyte.MPG_DB[2]);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKG_MPGINFO_DB3,pMPGInfoFrame->pktbyte.MPG_DB[3]);
|
||
|
||
for(ucData = 0,i = 0 ; i < 5 ; i++)
|
||
{
|
||
ucData -= pMPGInfoFrame->pktbyte.MPG_DB[i] ;
|
||
}
|
||
ucData -= MPEG_INFOFRAME_VER+MPEG_INFOFRAME_TYPE+MPEG_INFOFRAME_LEN ;
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_PKG_MPGINFO_SUM,ucData);
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
hdmitx_ENABLE_SPD_INFOFRM_PKT();
|
||
|
||
return ER_SUCCESS ;
|
||
}
|
||
*/
|
||
// 2009/12/04 added by Ming-chih.lung@ite.com.tw
|
||
|
||
/*
|
||
SYS_STATUS hdmitx_Set_GeneralPurpose_PKT(u8 *pData)
|
||
{
|
||
int i ;
|
||
|
||
if( pData == NULL )
|
||
{
|
||
return ER_FAIL ;
|
||
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
for( i = 0x38 ; i <= 0x56 ; i++)
|
||
{
|
||
it6161_hdmi_tx_write(it6161, i, pData[i-0x38] );
|
||
}
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
hdmitx_ENABLE_GeneralPurpose_PKT();
|
||
//hdmitx_ENABLE_NULL_PKT();
|
||
return ER_SUCCESS ;
|
||
}
|
||
*/
|
||
/*
|
||
static void ConfigAVIInfoFrame(u8 VIC, u8 pixelrep)
|
||
{
|
||
AVI_InfoFrame *AviInfo;
|
||
AviInfo = (AVI_InfoFrame *)CommunBuff ;
|
||
|
||
AviInfo->pktbyte.AVI_HB[0] = AVI_INFOFRAME_TYPE|0x80 ;
|
||
AviInfo->pktbyte.AVI_HB[1] = AVI_INFOFRAME_VER ;
|
||
AviInfo->pktbyte.AVI_HB[2] = AVI_INFOFRAME_LEN ;
|
||
|
||
switch(it6161->hdmi_tx_output_color_space)
|
||
{
|
||
case F_MODE_YUV444:
|
||
// AviInfo->info.ColorMode = 2 ;
|
||
AviInfo->pktbyte.AVI_DB[0] = (2<<5)|(1<<4);
|
||
break ;
|
||
case F_MODE_YUV422:
|
||
// AviInfo->info.ColorMode = 1 ;
|
||
AviInfo->pktbyte.AVI_DB[0] = (1<<5)|(1<<4);
|
||
break ;
|
||
case F_MODE_RGB444:
|
||
default:
|
||
// AviInfo->info.ColorMode = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[0] = (0<<5)|(1<<4);
|
||
break ;
|
||
}
|
||
AviInfo->pktbyte.AVI_DB[1] = 8 ;
|
||
AviInfo->pktbyte.AVI_DB[1] |= (aspec != HDMI_16x9)?(1<<4):(2<<4); // 4:3 or 16:9
|
||
AviInfo->pktbyte.AVI_DB[1] |= (Colorimetry != HDMI_ITU709)?(1<<6):(2<<6); // 4:3 or 16:9
|
||
AviInfo->pktbyte.AVI_DB[2] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[3] = VIC ;
|
||
AviInfo->pktbyte.AVI_DB[4] = pixelrep & 3 ;
|
||
AviInfo->pktbyte.AVI_DB[5] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[6] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[7] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[8] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[9] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[10] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[11] = 0 ;
|
||
AviInfo->pktbyte.AVI_DB[12] = 0 ;
|
||
|
||
HDMITX_EnableAVIInfoFrame(it6161, true, (unsigned char *)AviInfo);
|
||
}
|
||
*/
|
||
static void ConfigAudioInfoFrm(struct it6161 *it6161, u8 channel_count)
|
||
{
|
||
int i;
|
||
Audio_InfoFrame *AudioInfo ;
|
||
AudioInfo = (Audio_InfoFrame *)CommunBuff ;
|
||
|
||
DRM_INFO("ConfigAudioInfoFrm channel count: %d", channel_count);
|
||
|
||
AudioInfo->pktbyte.AUD_HB[0] = AUDIO_INFOFRAME_TYPE ;
|
||
AudioInfo->pktbyte.AUD_HB[1] = 1 ;
|
||
AudioInfo->pktbyte.AUD_HB[2] = AUDIO_INFOFRAME_LEN ;
|
||
AudioInfo->pktbyte.AUD_DB[0] = channel_count - 1;
|
||
|
||
for (i = 1 ;i < AUDIO_INFOFRAME_LEN ; i++) {
|
||
AudioInfo->pktbyte.AUD_DB[i] = 0 ;
|
||
}
|
||
|
||
/* audio_infoframe_ca */
|
||
switch (channel_count) {
|
||
case 0 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0xFF;
|
||
break; // no audio
|
||
case 2 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x00;
|
||
break;
|
||
case 3 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x01;
|
||
break; // 0x01,0x02,0x04
|
||
case 4 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x03;
|
||
break; // 0x03,0x05,0x06,0x08,0x14
|
||
case 5 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x07;
|
||
break; // 0x07,0x09,0x0A,0x0C,0x15,0x16,0x18
|
||
case 6 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x0B;
|
||
break; // 0x0B,0x0D,0x0E,0x10,0x17,0x19,0x1A,0x1C
|
||
case 7 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x0F;
|
||
break; // 0x0F,0x11,0x12,0x1B,0x1D,0x1E
|
||
case 8 :
|
||
AudioInfo->pktbyte.AUD_DB[3] = 0x1F;
|
||
break; // 0x13,0x1F
|
||
default :
|
||
DRM_INFO("Error: Audio Channel Number Error!");
|
||
}
|
||
|
||
HDMITX_EnableAudioInfoFrame(it6161, TRUE, (unsigned char *)AudioInfo);
|
||
}
|
||
|
||
#ifdef OUTPUT_3D_MODE
|
||
void ConfigfHdmiVendorSpecificInfoFrame(struct it6161 *it6161, u8 _3D_Stru)
|
||
{
|
||
VendorSpecific_InfoFrame *VS_Info;
|
||
|
||
VS_Info=(VendorSpecific_InfoFrame *)CommunBuff ;
|
||
|
||
VS_Info->pktbyte.VS_HB[0] = VENDORSPEC_INFOFRAME_TYPE|0x80;
|
||
VS_Info->pktbyte.VS_HB[1] = VENDORSPEC_INFOFRAME_VER;
|
||
VS_Info->pktbyte.VS_HB[2] = (_3D_Stru == Side_by_Side)?6:5;
|
||
VS_Info->pktbyte.VS_DB[0] = 0x03;
|
||
VS_Info->pktbyte.VS_DB[1] = 0x0C;
|
||
VS_Info->pktbyte.VS_DB[2] = 0x00;
|
||
VS_Info->pktbyte.VS_DB[3] = 0x40;
|
||
switch(_3D_Stru)
|
||
{
|
||
case Side_by_Side:
|
||
case Frame_Pcaking:
|
||
case Top_and_Botton:
|
||
VS_Info->pktbyte.VS_DB[4] = (_3D_Stru<<4);
|
||
break;
|
||
default:
|
||
VS_Info->pktbyte.VS_DB[4] = (Frame_Pcaking<<4);
|
||
break ;
|
||
}
|
||
VS_Info->pktbyte.VS_DB[5] = 0x00;
|
||
HDMITX_EnableVSInfoFrame(it6161, true,(u8 *)VS_Info);
|
||
}
|
||
#endif //#ifdef OUTPUT_3D_MODE
|
||
|
||
static void hdmi_tx_audio_process(struct it6161 *it6161)
|
||
{
|
||
if (it6161->support_audio) {
|
||
ConfigAudioInfoFrm(it6161, bOutputAudioChannel);
|
||
// HDMITX_EnableAudioOutput(T_AUDIO_LPCM, false, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,TMDSClock);
|
||
HDMITX_EnableAudioOutput(it6161,
|
||
//CNOFIG_INPUT_AUDIO_TYPE,
|
||
bOutputAudioType,
|
||
CONFIG_INPUT_AUDIO_INTERFACE,
|
||
ulAudioSampleFS,
|
||
bOutputAudioChannel,
|
||
NULL, // pointer to cahnnel status.
|
||
VideoPixelClock*(pixelrep+1));
|
||
// if you have channel status , set here.
|
||
// setHDMITX_ChStat(it6161, u8 ucIEC60958ChStat[]);
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
|
||
{
|
||
u8 csum = 0;
|
||
size_t i;
|
||
|
||
/* compute checksum */
|
||
for (i = 0; i < size; i++)
|
||
csum += ptr[i];
|
||
|
||
return 256 - csum;
|
||
}
|
||
|
||
static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
|
||
{
|
||
u8 *ptr = buffer;
|
||
|
||
ptr[3] = hdmi_infoframe_checksum(buffer, size);
|
||
}
|
||
#endif
|
||
|
||
static int hdmi_tx_get_avi_infoframe_from_source(struct it6161 *it6161, u8 *buffer, size_t size)
|
||
{
|
||
struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
int err;
|
||
|
||
err = hdmi_avi_infoframe_pack(&it6161->source_avi_infoframe, buffer, size);
|
||
if (err < 0) {
|
||
DRM_DEV_ERROR(dev, "Failed to pack AVI infoframe: %d", err);
|
||
return err;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int hdmi_tx_get_avi_infoframe_from_user_define(struct it6161 *it6161, u8 *buffer, size_t size)
|
||
{
|
||
struct device *dev = &it6161->i2c_hdmi_tx->dev;
|
||
struct hdmi_avi_infoframe *frame = &it6161->source_avi_infoframe;
|
||
struct drm_display_mode *display_mode = &it6161->source_display_mode;
|
||
int ret;
|
||
|
||
DRM_INFO( "user define to setup AVI infoframe");
|
||
|
||
ret = drm_hdmi_avi_infoframe_from_display_mode(frame, &it6161->connector, display_mode);
|
||
if (ret) {
|
||
DRM_DEV_ERROR(dev, "Failed to setup AVI infoframe: %d", ret);
|
||
return ret;
|
||
}
|
||
|
||
if ((it6161->hdmi_tx_output_color_space & F_MODE_CLRMOD_MASK) == F_MODE_RGB444)
|
||
frame->colorspace = HDMI_COLORSPACE_RGB;
|
||
|
||
if ((it6161->hdmi_tx_output_color_space & F_MODE_CLRMOD_MASK) == F_MODE_YUV444)
|
||
frame->colorspace = HDMI_COLORSPACE_YUV444;
|
||
|
||
if ((it6161->hdmi_tx_output_color_space & F_MODE_CLRMOD_MASK) == F_MODE_YUV422)
|
||
frame->colorspace = HDMI_COLORSPACE_YUV422;
|
||
|
||
ret = hdmi_tx_get_avi_infoframe_from_source(it6161, buffer, size);
|
||
if (ret) {
|
||
DRM_DEV_ERROR(dev, "Failed to pack AVI infoframe: %d", ret);
|
||
return ret;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int (*hdmi_tx_get_avi_infoframe)(struct it6161*, u8*, size_t) = hdmi_tx_get_avi_infoframe_from_user_define;
|
||
|
||
static void hdmi_tx_setup_avi_infoframe(struct it6161 *it6161, u8 *buffer, size_t size)
|
||
{
|
||
u8 i, *ptr = buffer + HDMI_INFOFRAME_HEADER_SIZE;
|
||
|
||
it6161_hdmi_tx_change_bank(it6161, 1);
|
||
|
||
for (i = 0; i < it6161->source_avi_infoframe.length; i++)
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_DB1 + i, ptr[i]);
|
||
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVIINFO_SUM, buffer[3]);
|
||
}
|
||
|
||
static inline void hdmi_tx_disable_avi_infoframe(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVI_INFOFRM_CTRL, 0x00);
|
||
}
|
||
|
||
static inline void hdmi_tx_enable_avi_infoframe(struct it6161 *it6161)
|
||
{
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_AVI_INFOFRM_CTRL, B_TX_ENABLE_PKT | B_TX_REPEAT_PKT);
|
||
}
|
||
|
||
static int hdmi_tx_avi_infoframe_process(struct it6161 *it6161)
|
||
{
|
||
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||
int err;
|
||
|
||
hdmi_tx_disable_avi_infoframe(it6161);
|
||
err = hdmi_tx_get_avi_infoframe(it6161, buffer, sizeof(buffer));
|
||
|
||
if (err)
|
||
return err;
|
||
|
||
hdmi_tx_setup_avi_infoframe(it6161, buffer, sizeof(buffer));
|
||
hdmi_tx_enable_avi_infoframe(it6161);
|
||
|
||
DRM_INFO("avi_infoframe:0x%*ph", (int)ARRAY_SIZE(buffer), buffer);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void hdmi_tx_set_output_process(struct it6161 *it6161)
|
||
{
|
||
VIDEOPCLKLEVEL level;
|
||
u32 TMDSClock;
|
||
|
||
TMDSClock = it6161->hdmi_tx_pclk * 1000 * (it6161->source_avi_infoframe.pixel_repeat + 1);
|
||
|
||
HDMITX_DisableAudioOutput(it6161);
|
||
//hdmi_tx_hdcp_reset_auth(it6161);
|
||
hdmi_tx_disable_avi_infoframe(it6161);
|
||
HDMITX_EnableVSInfoFrame(it6161, false,NULL);
|
||
|
||
if (TMDSClock > 80000000L) {
|
||
level = PCLK_HIGH ;
|
||
} else if(TMDSClock > 20000000L) {
|
||
level = PCLK_MEDIUM ;
|
||
} else {
|
||
level = PCLK_LOW ;
|
||
}
|
||
|
||
hdmi_tx_enable_video_output(it6161, level);
|
||
|
||
if (it6161->hdmi_mode) {
|
||
#ifdef OUTPUT_3D_MODE
|
||
ConfigfHdmiVendorSpecificInfoFrame(it6161, OUTPUT_3D_MODE);
|
||
#endif
|
||
|
||
hdmi_tx_avi_infoframe_process(it6161);
|
||
hdmi_tx_audio_process(it6161);
|
||
|
||
// if( it6161->support_audio )
|
||
// {
|
||
// ConfigAudioInfoFrm(it6161);
|
||
// #ifdef SUPPORT_HBR_AUDIO
|
||
// HDMITX_EnableAudioOutput(it6161, T_AUDIO_HBR, CONFIG_INPUT_AUDIO_INTERFACE, 768000L,8,NULL,TMDSClock);
|
||
// #else
|
||
// // HDMITX_EnableAudioOutput(it6161, T_AUDIO_LPCM, false, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,TMDSClock);
|
||
// HDMITX_EnableAudioOutput(it6161, CNOFIG_INPUT_AUDIO_TYPE, CONFIG_INPUT_AUDIO_INTERFACE, ulAudioSampleFS,bOutputAudioChannel,NULL,TMDSClock);
|
||
// #endif
|
||
// }
|
||
|
||
}
|
||
|
||
#ifdef SUPPORT_CEC
|
||
it6161_hdmi_tx_change_bank(it6161, 0);
|
||
it6161_hdmi_tx_write(it6161, 0xf, 0 );
|
||
Initial_Ext_Int1();
|
||
HDMITX_CEC_Init();
|
||
#endif // SUPPORT_CEC
|
||
it6161_hdmi_tx_set_av_mute(it6161, false);
|
||
bChangeMode = false ;
|
||
}
|
||
|
||
/*void HDMITX_ChangeAudioOption(u8 Option, u8 channelNum, u8 AudioFs)
|
||
{
|
||
|
||
switch(Option )
|
||
{
|
||
case T_AUDIO_HBR :
|
||
bOutputAudioType = T_AUDIO_HBR ;
|
||
ulAudioSampleFS = 768000L ;
|
||
bOutputAudioChannel = 8 ;
|
||
return ;
|
||
case T_AUDIO_NLPCM :
|
||
bOutputAudioType = T_AUDIO_NLPCM ;
|
||
bOutputAudioChannel = 2 ;
|
||
break ;
|
||
default:
|
||
bOutputAudioType = T_AUDIO_LPCM ;
|
||
if( channelNum < 1 )
|
||
{
|
||
bOutputAudioChannel = 1 ;
|
||
}
|
||
else if( channelNum > 8 )
|
||
{
|
||
bOutputAudioChannel = 8 ;
|
||
}
|
||
else
|
||
{
|
||
bOutputAudioChannel = channelNum ;
|
||
}
|
||
break ;
|
||
}
|
||
|
||
switch(AudioFs)
|
||
{
|
||
case AUDFS_44p1KHz:
|
||
ulAudioSampleFS = 44100L ;
|
||
break ;
|
||
case AUDFS_88p2KHz:
|
||
ulAudioSampleFS = 88200L ;
|
||
break ;
|
||
case AUDFS_176p4KHz:
|
||
ulAudioSampleFS = 176400L ;
|
||
break ;
|
||
|
||
case AUDFS_48KHz:
|
||
ulAudioSampleFS = 48000L ;
|
||
break ;
|
||
case AUDFS_96KHz:
|
||
ulAudioSampleFS = 96000L ;
|
||
break ;
|
||
case AUDFS_192KHz:
|
||
ulAudioSampleFS = 192000L ;
|
||
break ;
|
||
|
||
case AUDFS_768KHz:
|
||
ulAudioSampleFS = 768000L ;
|
||
break ;
|
||
|
||
case AUDFS_32KHz:
|
||
ulAudioSampleFS = 32000L ;
|
||
break ;
|
||
default:
|
||
ulAudioSampleFS = 48000L ;
|
||
break ;
|
||
}
|
||
DRM_INFO("HDMITX_ChangeAudioOption():bOutputAudioType = %02X, ulAudioSampleFS = %8ld, bOutputAudioChannel = %d\n",(int)bOutputAudioType,ulAudioSampleFS,(int)bOutputAudioChannel);
|
||
}
|
||
*/
|
||
|
||
#ifdef HDMITX_AUTO_MONITOR_INPUT
|
||
|
||
void HDMITX_MonitorInputAudioChange()
|
||
{
|
||
static u32 prevAudioSampleFS = 0 ;
|
||
u32 AudioFS ;
|
||
|
||
if( !it6161->support_audio )
|
||
{
|
||
prevAudioSampleFS = 0 ;
|
||
}
|
||
else
|
||
{
|
||
AudioFS = CalcAudFS() ;
|
||
DRM_INFO1(("Audio Chagne, Audio clock = %dHz\n",AudioFS)) ;
|
||
if( AudioFS > 188000L ) // 192KHz
|
||
{
|
||
ulAudioSampleFS = 192000L ;
|
||
}
|
||
else if( AudioFS > 144000L ) // 176.4KHz
|
||
{
|
||
ulAudioSampleFS = 176400L ;
|
||
}
|
||
else if( AudioFS > 93000L ) // 96KHz
|
||
{
|
||
ulAudioSampleFS = 96000L ;
|
||
}
|
||
else if( AudioFS > 80000L ) // 88.2KHz
|
||
{
|
||
ulAudioSampleFS = 88200L ;
|
||
}
|
||
else if( AudioFS > 45000L ) // 48 KHz
|
||
{
|
||
ulAudioSampleFS = 48000L ;
|
||
}
|
||
else if( AudioFS > 36000L ) // 44.1KHz
|
||
{
|
||
ulAudioSampleFS = 44100L ;
|
||
}
|
||
else // 32KHz
|
||
{
|
||
ulAudioSampleFS = 32000L ;
|
||
}
|
||
|
||
if(!bChangeMode)
|
||
{
|
||
if( ulAudioSampleFS != prevAudioSampleFS )
|
||
{
|
||
DRM_INFO("ulAudioSampleFS = %dHz -> %dHz\n",ulAudioSampleFS,ulAudioSampleFS);
|
||
ConfigAudioInfoFrm(it6161, 2);
|
||
HDMITX_EnableAudioOutput(it6161, CNOFIG_INPUT_AUDIO_TYPE, CONFIG_INPUT_AUDIO_INTERFACE, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,0);
|
||
// HDMITX_EnableAudioOutput(it6161, T_AUDIO_LPCM, false, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,0);
|
||
|
||
}
|
||
}
|
||
|
||
prevAudioSampleFS = ulAudioSampleFS ;
|
||
|
||
}
|
||
}
|
||
|
||
#endif // HDMITX_AUTO_MONITOR_INPUT
|
||
|
||
static void mipi_rx_calc_rclk(struct it6161 *it6161)
|
||
{
|
||
u32 sum = 0, i, retry = 5;
|
||
int t10usint;
|
||
|
||
//it6161_hdmi_tx_write(it6161, 0x8D, (CEC_I2C_SLAVE_ADDR|0x01));// Enable CRCLK
|
||
for (i = 0; i < retry; i++) {
|
||
it6161_mipi_rx_set_bits(it6161, 0x94, 0x80, 0x80); // Enable RCLK 100ms count
|
||
msleep(100);
|
||
it6161_mipi_rx_set_bits(it6161, 0x94, 0x80, 0x00); // Disable RCLK 100ms count
|
||
|
||
it6161->mipi_rx_rclk = it6161_mipi_rx_read(it6161, 0x97);
|
||
it6161->mipi_rx_rclk <<= 8;
|
||
it6161->mipi_rx_rclk += it6161_mipi_rx_read(it6161, 0x96);
|
||
it6161->mipi_rx_rclk <<=8;
|
||
it6161->mipi_rx_rclk += it6161_mipi_rx_read(it6161, 0x95);
|
||
sum += it6161->mipi_rx_rclk;
|
||
}
|
||
|
||
sum /= retry;
|
||
DRM_INFO("rclk: %d\n", sum);
|
||
//it6161->mipi_rx_rclk = sum / 100;
|
||
it6161->mipi_rx_rclk = sum / 104;
|
||
t10usint = it6161->mipi_rx_rclk / 108;//actually nxp platform msleep(100) is 108ms
|
||
DRM_INFO("it6161->mipi_rx_rclk = %d,%03d,%03d\n",(sum*10)/1000000,((sum*10)%1000000)/1000,((sum*10)%100));
|
||
DRM_INFO("T10usInt=0x%03X\n", (int)t10usint);
|
||
it6161_mipi_rx_write(it6161, 0x91, t10usint&0xFF);
|
||
}
|
||
|
||
static void mipi_rx_calc_mclk(struct it6161 *it6161)
|
||
{
|
||
u32 i, rddata, sum = 0, calc_time = 3;
|
||
|
||
for (i = 0; i < calc_time; i++) {
|
||
it6161_mipi_rx_set_bits(it6161, 0x9B, 0x80, 0x80);
|
||
msleep(5);
|
||
it6161_mipi_rx_set_bits(it6161, 0x9B, 0x80, 0x00);
|
||
|
||
rddata = it6161_mipi_rx_read(it6161, 0x9B) & 0x0F;
|
||
rddata <<= 8;
|
||
rddata += it6161_mipi_rx_read(it6161, 0x9A);
|
||
|
||
sum += rddata;
|
||
}
|
||
|
||
sum /= calc_time;
|
||
it6161->mipi_rx_mclk = it6161->mipi_rx_rclk * 2048 / sum;
|
||
DRM_INFO("MCLK = %d.%03dMHz", it6161->mipi_rx_mclk / 1000, it6161->mipi_rx_mclk % 1000);
|
||
}
|
||
|
||
static void mipi_rx_calc_pclk(struct it6161 *it6161)
|
||
{
|
||
u32 rddata, sum = 0, retry = 3;
|
||
u8 i;
|
||
|
||
it6161_mipi_rx_set_bits(it6161, 0x99, 0x80, 0x00);
|
||
|
||
for (i = 0; i < retry; i++) {
|
||
it6161_mipi_rx_set_bits(it6161, 0x99, 0x80, 0x80);
|
||
msleep(5);
|
||
it6161_mipi_rx_set_bits(it6161, 0x99, 0x80, 0x00);
|
||
msleep(1);
|
||
|
||
rddata = it6161_mipi_rx_read(it6161, 0x99) & 0x0F;
|
||
rddata <<= 8;
|
||
rddata += it6161_mipi_rx_read(it6161, 0x98);
|
||
sum += rddata;
|
||
}
|
||
|
||
sum /= retry;
|
||
DRM_INFO("pclk: %d\n", sum);
|
||
it6161->mipi_rx_pclk = it6161->mipi_rx_rclk * 2048 / sum;
|
||
//it6161->mipi_rx_pclk = it6161->mipi_rx_rclk * 1960 / sum;
|
||
DRM_INFO("it6161->mipi_rx_pclk = %d.%03dMHz", it6161->mipi_rx_pclk / 1000, it6161->mipi_rx_pclk % 1000);
|
||
}
|
||
|
||
static void mipi_rx_show_mrec(struct it6161 *it6161)
|
||
{
|
||
int m_hfront_porch, m_hsyncw, m_hback_porch, m_hactive, MHVR2nd, MHBlank;
|
||
int m_vfront_porch, m_vsyncw, m_vback_porch, m_vactive, MVFP2nd, MVTotal;
|
||
|
||
|
||
m_hfront_porch = mipi_rx_read_word(it6161, 0x50) & 0x3FFF;
|
||
m_hsyncw = mipi_rx_read_word(it6161, 0x52) & 0x3FFF;
|
||
m_hback_porch = mipi_rx_read_word(it6161, 0x54) & 0x3FFF;
|
||
m_hactive = mipi_rx_read_word(it6161, 0x56) & 0x3FFF;
|
||
MHVR2nd = mipi_rx_read_word(it6161, 0x58) & 0x3FFF;
|
||
|
||
MHBlank = m_hfront_porch + m_hsyncw + m_hback_porch;
|
||
|
||
m_vfront_porch = mipi_rx_read_word(it6161, 0x5A) & 0x3FFF;
|
||
m_vsyncw = mipi_rx_read_word(it6161, 0x5C) & 0x3FFF;
|
||
m_vback_porch = mipi_rx_read_word(it6161, 0x5E) & 0x3FFF;
|
||
m_vactive = mipi_rx_read_word(it6161, 0x60) & 0x3FFF;
|
||
MVFP2nd = mipi_rx_read_word(it6161, 0x62) & 0x3FFF;
|
||
|
||
MVTotal = m_vfront_porch + m_vsyncw + m_vback_porch + m_vactive ;
|
||
|
||
DRM_INFO("m_hfront_porch = %d\n", m_hfront_porch);
|
||
DRM_INFO("m_hsyncw = %d\n", m_hsyncw);
|
||
DRM_INFO("m_hback_porch = %d\n", m_hback_porch);
|
||
DRM_INFO("m_hactive = %d\n", m_hactive);
|
||
DRM_INFO("MHVR2nd = %d\n", MHVR2nd);
|
||
DRM_INFO("MHBlank = %d\n", MHBlank);
|
||
|
||
DRM_INFO("m_vfront_porch = %d\n", m_vfront_porch);
|
||
DRM_INFO("m_vsyncw = %d\n", m_vsyncw);
|
||
DRM_INFO("m_vback_porch = %d\n", m_vback_porch);
|
||
DRM_INFO("m_vactive = %d\n", m_vactive);
|
||
DRM_INFO("MVFP2nd = %d\n", MVFP2nd);
|
||
DRM_INFO("MVTotal = %d\n", MVTotal);
|
||
}
|
||
|
||
static void mipi_rx_prec_get_display_mode(struct it6161 *it6161)
|
||
{
|
||
struct drm_display_mode *display_mode = &it6161->mipi_rx_p_display_mode;
|
||
struct device *dev = &it6161->i2c_hdmi_tx->dev;
|
||
int p_hfront_porch, p_hsyncw, p_hback_porch, p_hactive, p_htotal;
|
||
int p_vfront_porch, p_vsyncw, p_vback_porch, p_vactive, p_vtotal;
|
||
|
||
p_hfront_porch = mipi_rx_read_word(it6161, 0x30) & 0x3FFF;
|
||
p_hsyncw = mipi_rx_read_word(it6161, 0x32) & 0x3FFF;
|
||
p_hback_porch = mipi_rx_read_word(it6161, 0x34) & 0x3FFF;
|
||
p_hactive = mipi_rx_read_word(it6161, 0x36) & 0x3FFF;
|
||
p_htotal = mipi_rx_read_word(it6161, 0x38) & 0x3FFF;
|
||
|
||
//p_htotal = p_hfront_porch + p_hsyncw + p_hback_porch + p_hactive ;
|
||
|
||
p_vfront_porch = mipi_rx_read_word(it6161, 0x3A) & 0x3FFF;
|
||
p_vsyncw = mipi_rx_read_word(it6161, 0x3C) & 0x3FFF;
|
||
p_vback_porch = mipi_rx_read_word(it6161, 0x3E) & 0x3FFF;
|
||
p_vactive = mipi_rx_read_word(it6161, 0x40) & 0x3FFF;
|
||
p_vtotal = mipi_rx_read_word(it6161, 0x42) & 0x3FFF;
|
||
|
||
//p_vtotal = p_vfront_porch + p_vsyncw + p_vback_porch + p_vactive ;
|
||
|
||
display_mode->clock = it6161->mipi_rx_pclk;
|
||
display_mode->hdisplay = p_hactive;
|
||
display_mode->hsync_start = p_hactive + p_hfront_porch;
|
||
display_mode->hsync_end = p_hactive + p_hfront_porch + p_hsyncw;
|
||
display_mode->htotal = p_htotal;
|
||
display_mode->vdisplay = p_vactive;
|
||
display_mode->vsync_start = p_vactive + p_vfront_porch;
|
||
display_mode->vsync_end = p_vactive + p_vfront_porch + p_vsyncw;
|
||
display_mode->vtotal = p_vtotal;
|
||
|
||
DRM_DEV_DEBUG_DRIVER(dev, "mipi pixel clock: %d KHz", display_mode->clock);
|
||
DRM_INFO("p_hfront_porch = %d\r\n", p_hfront_porch);
|
||
DRM_INFO("p_hsyncw = %d\r\n", p_hsyncw);
|
||
DRM_INFO("p_hback_porch = %d\r\n", p_hback_porch);
|
||
DRM_INFO("p_hactive = %d\r\n", p_hactive);
|
||
DRM_INFO("p_htotal = %d\r\n", p_htotal);
|
||
|
||
DRM_INFO("p_vfront_porch = %d\r\n", p_vfront_porch);
|
||
DRM_INFO("p_vsyncw = %d\r\n", p_vsyncw);
|
||
DRM_INFO("p_vback_porch = %d\r\n", p_vback_porch);
|
||
DRM_INFO("p_vactive = %d\r\n", p_vactive);
|
||
DRM_INFO("p_vtotal = %d\r\n", p_vtotal);
|
||
}
|
||
|
||
static void mipi_rx_reset_p_domain(struct it6161 *it6161)
|
||
{
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x04, 0x04); // Video Clock Domain Reset
|
||
it6161_mipi_rx_set_bits(it6161, 0x05, 0x04, 0x00); // Release Video Clock Domain Reset
|
||
}
|
||
|
||
static void it6161_mipi_rx_interrupt_clear(struct it6161 *it6161, u8 reg06, u8 reg07, u8 reg08)
|
||
{
|
||
it6161_mipi_rx_write(it6161, 0x06, reg06);
|
||
it6161_mipi_rx_write(it6161, 0x07, reg07);
|
||
it6161_mipi_rx_write(it6161, 0x08, reg08);
|
||
it6161_debug("mipi rx i2c read reg06:0x%02x reg07:0x%02x reg08:0x%02x",
|
||
it6161_mipi_rx_read(it6161, 0x06), it6161_mipi_rx_read(it6161, 0x07), it6161_mipi_rx_read(it6161, 0x08));
|
||
}
|
||
|
||
static void it6161_mipi_rx_interrupt_reg06_process(struct it6161 *it6161, u8 reg06)
|
||
{
|
||
bool m_video_stable, p_video_stable;
|
||
#ifndef __linux__
|
||
struct drm_display_mode *dmt_display_mode;
|
||
#endif
|
||
u8 data_id;
|
||
|
||
if (reg06 == 0x00)
|
||
return;
|
||
|
||
if (reg06 & 0x01) {
|
||
m_video_stable = mipi_rx_get_m_video_stable(it6161);
|
||
DRM_INFO("PPS M video stable Change Interrupt, %sstable", m_video_stable ? "" : "un");
|
||
|
||
if (m_video_stable) {
|
||
data_id = it6161_mipi_rx_read(it6161, 0x28);
|
||
DRM_INFO("mipi receive video format: 0x%02x", data_id);
|
||
mipi_rx_calc_rclk(it6161);
|
||
mipi_rx_calc_mclk(it6161);
|
||
mipi_rx_show_mrec(it6161);
|
||
mipi_rx_afe_configuration(it6161, data_id);
|
||
mipi_rx_reset_p_domain(it6161);
|
||
}
|
||
}
|
||
|
||
if(reg06 & 0x02)
|
||
{
|
||
DRM_INFO("PPS MHSync error interrupt");
|
||
}
|
||
|
||
if(reg06 & 0x04)
|
||
{
|
||
DRM_INFO("PPS MHDE Error Interrupt");
|
||
}
|
||
|
||
if(reg06 & 0x08)
|
||
{
|
||
DRM_INFO("PPS MVSync Error Interrupt");
|
||
}
|
||
|
||
if (reg06 & 0x10) {
|
||
p_video_stable = mipi_rx_get_p_video_stable(it6161);
|
||
DRM_INFO("PPS P video stable Change Interrupt, %sstable", p_video_stable ? "" : "un");
|
||
it6161_debug("cancel restart work\n");
|
||
cancel_delayed_work(&it6161->restart);
|
||
|
||
if (p_video_stable) {
|
||
DRM_INFO("PVidStb Change to HIGH");
|
||
mipi_rx_calc_rclk(it6161);
|
||
mipi_rx_calc_pclk(it6161);
|
||
mipi_rx_prec_get_display_mode(it6161);
|
||
it6161->vic = drm_match_cea_mode(&it6161->mipi_rx_p_display_mode);
|
||
|
||
#ifndef __linux__
|
||
if (it6161->vic == 0) {
|
||
dmt_display_mode = drm_match_dmt_mode(&it6161->mipi_rx_p_display_mode);
|
||
|
||
if (dmt_display_mode)
|
||
drm_mode_copy(&it6161->source_display_mode, dmt_display_mode);
|
||
|
||
DRM_INFO("%sfind dmt timing", dmt_display_mode ? "" : "not ");
|
||
} else {
|
||
drm_mode_copy(&it6161->source_display_mode, &edid_cea_modes[it6161->vic]);
|
||
}
|
||
#endif
|
||
|
||
DRM_INFO("source output vic: %d, %s cea timing", it6161->vic, it6161->vic ? " standard" : " not");
|
||
show_display_mode(it6161, &it6161->source_display_mode, 0);
|
||
|
||
show_display_mode(it6161, &it6161->mipi_rx_p_display_mode, 2);
|
||
mipi_rx_setup_polarity(it6161);
|
||
it6161_mipi_rx_write(it6161, 0xC0,(EnTxCRC<<7) +TxCRCnum);
|
||
// setup 1 sec timer interrupt
|
||
it6161_mipi_rx_set_bits(it6161, 0x0b,0x40, 0x40);
|
||
|
||
switch (it6161->hdmi_tx_mode) {
|
||
case HDMI_TX_BY_PASS:
|
||
it6161_hdmi_tx_set_bits(it6161, 0xA9, 0x80, 0x80);
|
||
break;
|
||
|
||
case HDMI_TX_ENABLE_DE_ONLY:
|
||
hdmi_tx_generate_blank_timing(it6161);
|
||
break;
|
||
|
||
case HDMI_TX_ENABLE_PATTERN_GENERATOR:
|
||
hdmi_tx_setup_pattern_generator(it6161);
|
||
break;
|
||
|
||
default:
|
||
DRM_INFO("use hdmi tx normal mode");
|
||
break;
|
||
}
|
||
|
||
hdmi_tx_video_reset(it6161);
|
||
}
|
||
}
|
||
|
||
if(reg06 & 0x20)
|
||
{
|
||
if(DisPHSyncErr == false)
|
||
{
|
||
DRM_INFO("PPS PHSync Error Interrupt");
|
||
}
|
||
}
|
||
|
||
if(reg06 & 0x40)
|
||
{
|
||
DRM_INFO("PPS PHDE Error Interrupt");
|
||
}
|
||
|
||
if(reg06 & 0x80)
|
||
{
|
||
DRM_INFO("PPS MVDE Error Interrupt");
|
||
}
|
||
}
|
||
|
||
static void it6161_mipi_rx_interrupt_reg07_process(struct it6161 *it6161, u8 reg07)
|
||
{
|
||
if (reg07 == 0x00)
|
||
return;
|
||
|
||
if(reg07 & 0x01)
|
||
{
|
||
DRM_INFO("PatGen PPGVidStb change interrupt !!!\n");
|
||
}
|
||
|
||
if(reg07 & 0x02)
|
||
{
|
||
DRM_INFO("PPS Data Byte Error Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg07 & 0x04)
|
||
{
|
||
DRM_INFO("PPS CMOff Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg07 & 0x08)
|
||
{
|
||
DRM_INFO("PPS CMOn Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg07 & 0x10)
|
||
{
|
||
DRM_INFO("PPS ShutDone cmd Interrupt !!! \n");
|
||
}
|
||
|
||
if(reg07 & 0x20)
|
||
{
|
||
DRM_INFO("PPS TurnOn Interrupt !!!\n");
|
||
}
|
||
|
||
if((reg07 & 0x40) || (reg07 & 0x80))
|
||
{
|
||
if( reg07&0x40 ) {
|
||
DRM_INFO("PPS FIFO over read Interrupt !!! tx video stable:%d", hdmi_tx_get_video_state(it6161));
|
||
it6161_mipi_rx_set_bits(it6161, 0x07, 0x40, 0x40);
|
||
}
|
||
if( reg07&0x80 ) {
|
||
DRM_INFO("PPS FIFO over write Interrupt !!!\n");
|
||
it6161_mipi_rx_set_bits(it6161, 0x07, 0x80, 0x80);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void it6161_mipi_rx_interrupt_reg08_process(struct it6161 *it6161, u8 reg08)
|
||
{
|
||
int crc;
|
||
|
||
if (reg08 == 0x00)
|
||
return;
|
||
|
||
if(reg08 & 0x01)
|
||
{
|
||
if(DisECCErr == false)
|
||
{
|
||
DRM_INFO("ECC 1-bit Error Interrupt !!!\n");
|
||
}
|
||
}
|
||
|
||
if(reg08 & 0x02)
|
||
{
|
||
if(DisECCErr == false)
|
||
{
|
||
DRM_INFO("ECC 2-bit Error Interrupt !!!\n");
|
||
}
|
||
}
|
||
|
||
if(reg08 & 0x04)
|
||
{
|
||
DRM_INFO("LM FIFO Error Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg08 & 0x08)
|
||
{
|
||
DRM_INFO("CRC Error Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg08 & 0x10)
|
||
{
|
||
DRM_INFO("MCLK Off Interrupt !!!\n");
|
||
//DRM_INFO("setP1_6 High Mipi not Stable\n");
|
||
//P1_6=1;
|
||
}
|
||
|
||
if(reg08 & 0x20)
|
||
{
|
||
DRM_INFO("PPI FIFO OverWrite Interrupt !!!\n");
|
||
}
|
||
|
||
if(reg08 & 0x40)
|
||
{
|
||
DRM_INFO("FW Timer Interrupt !!!\n");
|
||
it6161_mipi_rx_set_bits(it6161, 0x0b, 0x40, 0x00);
|
||
|
||
if((it6161_mipi_rx_read(it6161, 0xC1)&0x03) == 0x03)
|
||
{
|
||
DRM_INFO("CRC Fail !!!\n");
|
||
}
|
||
if((it6161_mipi_rx_read(it6161, 0xC1)&0x05) == 0x05)
|
||
{
|
||
DRM_INFO("CRC Pass !!!\n");
|
||
crc = it6161_mipi_rx_read(it6161, 0xC2) + (it6161_mipi_rx_read(it6161, 0xC3) <<8);
|
||
DRM_INFO("CRCR = 0x%x !!!\n" , crc);
|
||
crc = it6161_mipi_rx_read(it6161, 0xC4) + (it6161_mipi_rx_read(it6161, 0xC5) <<8);
|
||
DRM_INFO("CRCG = 0x%x !!!\n" , crc);
|
||
crc = it6161_mipi_rx_read(it6161, 0xC6) + (it6161_mipi_rx_read(it6161, 0xC7) <<8);
|
||
DRM_INFO("CRCB = 0x%x !!!\n" , crc);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void it6161_hdmi_tx_interrupt_clear(struct it6161 *it6161, u8 reg06, u8 reg07, u8 reg08, u8 regee)
|
||
{
|
||
u8 int_clear;
|
||
|
||
if(reg06 & B_TX_INT_AUD_OVERFLOW) {
|
||
DRM_INFO("B_TX_INT_AUD_OVERFLOW");
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST,(B_HDMITX_AUD_RST|B_TX_AREF_RST), (B_HDMITX_AUD_RST|B_TX_AREF_RST));
|
||
it6161_hdmi_tx_set_bits(it6161, REG_TX_SW_RST, B_HDMITX_AUD_RST|B_TX_AREF_RST, 0x00);
|
||
//AudioDelayCnt=AudioOutDelayCnt;
|
||
//LastRefaudfreqnum=0;
|
||
}
|
||
|
||
if(reg06 & B_TX_INT_DDCFIFO_ERR) {
|
||
DRM_INFO("DDC FIFO Error");
|
||
it6161_hdmi_tx_clear_ddc_fifo(it6161);
|
||
hdmiTxDev[0].bAuthenticated= false ;
|
||
}
|
||
|
||
if(reg06 & B_TX_INT_DDC_BUS_HANG) {
|
||
DRM_INFO("DDC BUS HANG");
|
||
it6161_hdmi_tx_abort_ddc(it6161);
|
||
|
||
if (hdmiTxDev[0].bAuthenticated) {
|
||
DRM_INFO("when DDC hang,and aborted DDC,the HDCP authentication need to restart");
|
||
#ifndef _SUPPORT_HDCP_REPEATER_
|
||
#ifdef ENABLE_HDCP
|
||
hdmitx_hdcp_ResumeAuthentication(it6161);
|
||
#endif
|
||
#else
|
||
TxHDCP_chg(TxHDCP_AuthFail);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/* clear ext interrupt */
|
||
it6161_hdmi_tx_write(it6161, 0xEE, regee);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR0, 0xFF);
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_CLR1, 0xFF);
|
||
/* write B_TX_INTACTDONE '1' to trigger clear interrupt */
|
||
int_clear = (it6161_hdmi_tx_read(it6161, REG_TX_SYS_STATUS)) | B_TX_CLR_AUD_CTS | B_TX_INTACTDONE ;
|
||
it6161_hdmi_tx_write(it6161, REG_TX_SYS_STATUS, int_clear);
|
||
|
||
it6161_debug("hdmi tx i2c read reg06:0x%02x reg07:0x%02x reg08:0x%02x regee:0x%02x", it6161_hdmi_tx_read(it6161, 0x06), it6161_hdmi_tx_read(it6161, 0x07), it6161_hdmi_tx_read(it6161, 0x08), it6161_hdmi_tx_read(it6161, 0xEE));
|
||
}
|
||
|
||
static void it6161_hdmi_tx_interrupt_reg06_process(struct it6161 *it6161, u8 reg06)
|
||
{
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
u8 ret;//, reg0e = it6161_hdmi_tx_read(it6161, 0x0e);
|
||
|
||
if(reg06 & B_TX_INT_HPD_PLUG) {
|
||
drm_helper_hpd_irq_event(it6161->connector.dev);
|
||
if(hdmi_tx_get_sink_hpd(it6161)) {
|
||
DRM_INFO("hpd on");
|
||
ret = wait_for_completion_timeout(&it6161->wait_edid_complete, msecs_to_jiffies(2000));
|
||
|
||
if (ret == 0)
|
||
DRM_INFO("wait edid timeout");
|
||
|
||
it6161->hdmi_tx_output_color_space = OUTPUT_COLOR_MODE;
|
||
it6161->hdmi_tx_input_color_space = INPUT_COLOR_MODE;
|
||
hdmi_tx_set_capability_from_edid_parse(it6161);
|
||
reinit_completion(&it6161->wait_hdcp_event);
|
||
hdmi_tx_video_reset(it6161);
|
||
|
||
bChangeMode=true;
|
||
// 1. not only HDMI but DVI need the set the upstream HPD
|
||
// 2. Before set upstream HPD , the EDID must be ready.
|
||
} else {
|
||
DRM_INFO("hpd off");
|
||
hdmi_tx_disable_video_output(it6161);
|
||
kfree(it6161->edid);
|
||
it6161->edid = NULL;
|
||
|
||
if (it6161->hdmi_tx_mode == HDMI_TX_ENABLE_PATTERN_GENERATOR)
|
||
hdmi_tx_disable_pattern_generator(it6161);
|
||
}
|
||
}
|
||
|
||
if (reg06 & B_TX_INT_RX_SENSE) {
|
||
DRM_INFO("rx sense interrupt");
|
||
hdmiTxDev[0].bAuthenticated = false;
|
||
}
|
||
}
|
||
|
||
static void it6161_hdmi_tx_interrupt_reg07_process(struct it6161 *it6161, u8 reg07)
|
||
{
|
||
bool video_state = hdmi_tx_get_video_state(it6161);
|
||
|
||
if(reg07 & B_TX_INT_AUTH_DONE) {
|
||
DRM_INFO("hdmi tx authenticate done interrupt");
|
||
hdmi_tx_hdcp_int_mask_disable(it6161);
|
||
hdmiTxDev[0].bAuthenticated = true ;
|
||
it6161_hdmi_tx_set_av_mute(it6161, false);
|
||
complete(&it6161->wait_hdcp_event);
|
||
}
|
||
if(reg07 & B_TX_INT_AUTH_FAIL) {
|
||
hdmiTxDev[0].bAuthenticated = false;
|
||
DRM_INFO("hdmi tx interrupt authenticate fail reg46:0x%02x, start HDCP again", it6161_hdmi_tx_read(it6161, 0x46));
|
||
complete(&it6161->wait_hdcp_event);
|
||
#ifdef ENABLE_HDCP
|
||
hdmi_tx_enable_hdcp(it6161);
|
||
#ifdef _SUPPORT_HDCP_REPEATER_
|
||
TxHDCP_chg(TxHDCP_AuthFail) ;
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
if(reg07 & B_TX_INT_KSVLIST_CHK ) {
|
||
DRM_INFO("ksv list event interrupt");
|
||
schedule_work(&it6161->wait_hdcp_ksv_list);
|
||
}
|
||
|
||
if (reg07 & B_TX_INT_VID_UNSTABLE) {
|
||
if (!video_state)
|
||
DRM_INFO("hdmi tx interrupt video unstable!");
|
||
}
|
||
}
|
||
|
||
static void it6161_hdmi_tx_interrupt_reg08_process(struct it6161 *it6161, u8 reg08)
|
||
{
|
||
if (reg08 & B_TX_INT_VIDSTABLE) {
|
||
it6161_hdmi_tx_write(it6161, REG_TX_INT_STAT3, reg08);
|
||
if (hdmi_tx_get_video_state(it6161)) {
|
||
DRM_INFO("hdmi tx interrupt video stable link status:%d, rx reg0d:0x%02x start HDCP", getHDMITX_LinkStatus(), it6161_mipi_rx_read(it6161, 0x0D));
|
||
hdmi_tx_get_display_mode(it6161);
|
||
show_display_mode(it6161, &it6161->source_display_mode, 0);
|
||
show_display_mode(it6161, &it6161->hdmi_tx_display_mode, 1);
|
||
hdmi_tx_set_output_process(it6161);
|
||
#ifdef ENABLE_HDCP
|
||
hdmi_tx_enable_hdcp(it6161);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
static void it6161_hdmi_tx_interrupt_regee_process(struct it6161 *it6161, u8 regee)
|
||
{
|
||
if (regee != 0x00) {
|
||
DRM_INFO("%s%s%s%s%s%s%s",
|
||
(regee & 0x40) ? "video parameter change ":"",
|
||
(regee & 0x20) ? "HDCP Pj check done ":"",
|
||
(regee & 0x10) ? "HDCP Ri check done ":"",
|
||
(regee & 0x8) ? "DDC bus hang ":"",
|
||
(regee & 0x4) ? "Video input FIFO auto reset ":"",
|
||
(regee & 0x2) ? "No audio input interrupt ":"",
|
||
(regee & 0x1) ? "Audio decode error interrupt ":"");
|
||
}
|
||
}
|
||
|
||
static irqreturn_t it6161_intp_threaded_handler(int unused, void *data)
|
||
{
|
||
struct it6161 *it6161 = data;
|
||
//struct device *dev = &it6161->i2c_mipi_rx->dev;
|
||
u8 mipi_rx_reg06, mipi_rx_reg07, mipi_rx_reg08, mipi_rx_reg0d;
|
||
u8 hdmi_tx_reg06, hdmi_tx_reg07, hdmi_tx_reg08, hdmi_tx_regee, hdmi_tx_reg0e;
|
||
//it6161_dump = data;
|
||
|
||
if (it6161->enable_drv_hold)
|
||
goto unlock;
|
||
|
||
mipi_rx_reg06 = it6161_mipi_rx_read(it6161, 0x06);
|
||
mipi_rx_reg07 = it6161_mipi_rx_read(it6161, 0x07);
|
||
mipi_rx_reg08 = it6161_mipi_rx_read(it6161, 0x08);
|
||
mipi_rx_reg0d = it6161_mipi_rx_read(it6161, 0x0D);
|
||
|
||
hdmi_tx_reg06 = it6161_hdmi_tx_read(it6161, 0x06);
|
||
hdmi_tx_reg07 = it6161_hdmi_tx_read(it6161, 0x07);
|
||
hdmi_tx_reg08 = it6161_hdmi_tx_read(it6161, 0x08);
|
||
hdmi_tx_reg0e = it6161_hdmi_tx_read(it6161, 0x0E);
|
||
hdmi_tx_regee = it6161_hdmi_tx_read(it6161, 0xEE);
|
||
|
||
if ((mipi_rx_reg06 != 0) || (mipi_rx_reg07 != 0) || (mipi_rx_reg08 != 0)) {
|
||
it6161_debug("rx reg06: 0x%02x reg07:0x%02x reg08:0x%02x reg0d:0x%02x", mipi_rx_reg06, mipi_rx_reg07, mipi_rx_reg08, mipi_rx_reg0d);
|
||
it6161_mipi_rx_interrupt_clear(it6161, mipi_rx_reg06, mipi_rx_reg07, mipi_rx_reg08);
|
||
}
|
||
|
||
if ((hdmi_tx_reg06 != 0) || (hdmi_tx_reg07 != 0) || (hdmi_tx_reg08 != 0)) {
|
||
it6161_debug("tx reg06: 0x%02x reg07: 0x%02x reg08: 0x%02x reg0e: 0x%02x regee: 0x%02x", hdmi_tx_reg06, hdmi_tx_reg07, hdmi_tx_reg08, hdmi_tx_reg0e, hdmi_tx_regee);
|
||
it6161_hdmi_tx_interrupt_clear(it6161, hdmi_tx_reg06, hdmi_tx_reg07, hdmi_tx_reg08, hdmi_tx_regee);
|
||
}
|
||
|
||
it6161_mipi_rx_interrupt_reg08_process(it6161, mipi_rx_reg08);
|
||
it6161_mipi_rx_interrupt_reg06_process(it6161, mipi_rx_reg06);
|
||
it6161_mipi_rx_interrupt_reg07_process(it6161, mipi_rx_reg07);
|
||
it6161_hdmi_tx_interrupt_reg06_process(it6161, hdmi_tx_reg06);
|
||
it6161_hdmi_tx_interrupt_reg07_process(it6161, hdmi_tx_reg07);
|
||
it6161_hdmi_tx_interrupt_reg08_process(it6161, hdmi_tx_reg08);
|
||
it6161_hdmi_tx_interrupt_regee_process(it6161, hdmi_tx_regee);
|
||
it6161_debug("end %s", __func__);
|
||
|
||
unlock:
|
||
return IRQ_HANDLED;
|
||
}
|
||
|
||
static void mipirx_restart(struct work_struct *work)
|
||
{
|
||
it6161_debug("****it6161: %s\n", __func__);
|
||
it6161_bridge_enable(it6161_bridge);
|
||
}
|
||
|
||
#if 0
|
||
static ssize_t enable_drv_hold_show(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
|
||
return scnprintf(buf, PAGE_SIZE, "drv_hold: %d\n", it6161->enable_drv_hold);
|
||
}
|
||
|
||
static ssize_t enable_drv_hold_store(struct device *dev,
|
||
struct device_attribute *attr,
|
||
const char *buf, size_t count)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
unsigned int drv_hold;
|
||
|
||
if (kstrtoint(buf, 10, &drv_hold) < 0)
|
||
return -EINVAL;
|
||
|
||
it6161->enable_drv_hold = !!drv_hold;
|
||
|
||
if (it6161->enable_drv_hold) {
|
||
it6161_mipi_rx_int_mask_disable(it6161);
|
||
it6161_hdmi_tx_int_mask_disable(it6161);
|
||
} else {
|
||
it6161_mipi_rx_interrupt_clear(it6161, 0xFF, 0xFF, 0xFF);
|
||
it6161_hdmi_tx_interrupt_clear(it6161, 0xFF, 0xFF, 0xFF, 0xFF);
|
||
it6161_mipi_rx_int_mask_enable(it6161);
|
||
it6161_hdmi_tx_int_mask_enable(it6161);
|
||
}
|
||
return count;
|
||
}
|
||
|
||
static ssize_t hdmi_output_color_space_store(struct device *dev,
|
||
struct device_attribute *attr,
|
||
const char *buf, size_t count)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
|
||
DRM_INFO("config color space: %s", buf);
|
||
it6161->hdmi_tx_output_color_space &= ~F_MODE_CLRMOD_MASK;
|
||
|
||
if (strncmp(buf, "ycbcr444", strlen(buf) - 1) == 0 || strncmp(buf, "yuv444", strlen(buf) - 1) == 0) {
|
||
it6161->hdmi_tx_output_color_space |= F_MODE_YUV444;
|
||
goto end;
|
||
}
|
||
|
||
if (strncmp(buf, "ycbcr422", strlen(buf) - 1) == 0 || strncmp(buf, "yuv422", strlen(buf) - 1) == 0) {
|
||
it6161->hdmi_tx_output_color_space |= F_MODE_YUV422;
|
||
goto end;
|
||
}
|
||
|
||
if (strncmp(buf, "rgb444", strlen(buf) - 1) == 0) {
|
||
it6161->hdmi_tx_output_color_space |= F_MODE_RGB444;
|
||
goto end;
|
||
}
|
||
|
||
DRM_INFO("not support this color space, only support ycbcr444/yuv444, ycbcr422/yuv422, rgb444");
|
||
return count;
|
||
|
||
end:
|
||
DRM_INFO("config color space: %s value:0x%02x", buf, it6161->hdmi_tx_output_color_space);
|
||
return count;
|
||
}
|
||
|
||
static ssize_t hdmi_output_color_space_show(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
char *str = buf, *end = buf + PAGE_SIZE;
|
||
|
||
str += scnprintf(str, end - str, "it6161->hdmi_tx_output_color_space:%d\n", it6161->hdmi_tx_output_color_space);
|
||
|
||
return str - buf;
|
||
}
|
||
#endif
|
||
|
||
#if 0
|
||
static ssize_t print_timing_show(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
struct drm_display_mode *vid = &it6161->source_display_mode;
|
||
char *str = buf, *end = buf + PAGE_SIZE;
|
||
|
||
str += scnprintf(str, end - str, "---video timing---\n");
|
||
str += scnprintf(str, end - str, "PCLK:%d.%03dMHz\n", vid->clock / 1000,
|
||
vid->clock % 1000);
|
||
str += scnprintf(str, end - str, "HTotal:%d\n", vid->htotal);
|
||
str += scnprintf(str, end - str, "HActive:%d\n", vid->hdisplay);
|
||
str += scnprintf(str, end - str, "HFrontPorch:%d\n",
|
||
vid->hsync_start - vid->hdisplay);
|
||
str += scnprintf(str, end - str, "HSyncWidth:%d\n",
|
||
vid->hsync_end - vid->hsync_start);
|
||
str += scnprintf(str, end - str, "HBackPorch:%d\n",
|
||
vid->htotal - vid->hsync_end);
|
||
str += scnprintf(str, end - str, "VTotal:%d\n", vid->vtotal);
|
||
str += scnprintf(str, end - str, "VActive:%d\n", vid->vdisplay);
|
||
str += scnprintf(str, end - str, "VFrontPorch:%d\n",
|
||
vid->vsync_start - vid->vdisplay);
|
||
str += scnprintf(str, end - str, "VSyncWidth:%d\n",
|
||
vid->vsync_end - vid->vsync_start);
|
||
str += scnprintf(str, end - str, "VBackPorch:%d\n",
|
||
vid->vtotal - vid->vsync_end);
|
||
|
||
return str - buf;
|
||
}
|
||
|
||
static ssize_t sha_debug_show(struct device *dev, struct device_attribute *attr,
|
||
char *buf)
|
||
{
|
||
int i = 0;
|
||
char *str = buf, *end = buf + PAGE_SIZE;
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
|
||
str += scnprintf(str, end - str, "sha input:\n");
|
||
for (i = 0; i < ARRAY_SIZE(it6161->sha1_input); i += 16)
|
||
str += scnprintf(str, end - str, "%16ph\n",
|
||
it6161->sha1_input + i);
|
||
|
||
str += scnprintf(str, end - str, "av:\n");
|
||
for (i = 0; i < ARRAY_SIZE(it6161->av); i++)
|
||
str += scnprintf(str, end - str, "%4ph\n", it6161->av[i]);
|
||
|
||
str += scnprintf(str, end - str, "bv:\n");
|
||
for (i = 0; i < ARRAY_SIZE(it6161->bv); i++)
|
||
str += scnprintf(str, end - str, "%4ph\n", it6161->bv[i]);
|
||
|
||
return end - str;
|
||
}
|
||
|
||
static ssize_t enable_hdcp_show(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
|
||
return scnprintf(buf, PAGE_SIZE, "%d\n", it6161->enable_hdcp);
|
||
}
|
||
|
||
static ssize_t enable_hdcp_store(struct device *dev,
|
||
struct device_attribute *attr,
|
||
const char *buf, size_t count)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
unsigned int reg3f, hdcp;
|
||
|
||
if (kstrtoint(buf, 10, &hdcp) < 0)
|
||
return -EINVAL;
|
||
|
||
if (!it6161->powered || it6161->state == SYS_UNPLUG) {
|
||
DRM_DEV_DEBUG_DRIVER(dev,
|
||
"power down or unplug, can not fire HDCP");
|
||
return -EINVAL;
|
||
}
|
||
it6161->enable_hdcp = hdcp ? true : false;
|
||
|
||
if (it6161->enable_hdcp) {
|
||
if (it6161->cp_capable) {
|
||
dptx_sys_chg(it6161, SYS_HDCP);
|
||
dptx_sys_fsm(it6161);
|
||
} else {
|
||
DRM_DEV_ERROR(dev, "sink not support HDCP");
|
||
}
|
||
} else {
|
||
dptx_set_bits(it6161, 0x05, 0x10, 0x10);
|
||
dptx_set_bits(it6161, 0x05, 0x10, 0x00);
|
||
reg3f = dptx_read(it6161, 0x3F);
|
||
hdcp = (reg3f & BIT(7)) >> 7;
|
||
DRM_DEV_DEBUG_DRIVER(dev, "%s to disable hdcp",
|
||
hdcp ? "failed" : "succeeded");
|
||
}
|
||
return count;
|
||
}
|
||
|
||
static ssize_t force_pwronoff_store(struct device *dev,
|
||
struct device_attribute *attr,
|
||
const char *buf, size_t count)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
int pwr;
|
||
|
||
if (kstrtoint(buf, 10, &pwr) < 0)
|
||
return -EINVAL;
|
||
if (pwr)
|
||
it6161_poweron(it6161);
|
||
else
|
||
it6161_poweroff(it6161);
|
||
return count;
|
||
}
|
||
|
||
static ssize_t pwr_state_show(struct device *dev,
|
||
struct device_attribute *attr, char *buf)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(dev);
|
||
|
||
return scnprintf(buf, PAGE_SIZE, "%d\n", it6161->powered);
|
||
}
|
||
|
||
static DEVICE_ATTR_RO(print_timing);
|
||
static DEVICE_ATTR_RO(pwr_state);
|
||
static DEVICE_ATTR_RO(sha_debug);
|
||
static DEVICE_ATTR_WO(force_pwronoff);
|
||
static DEVICE_ATTR_RW(enable_hdcp);
|
||
|
||
static const struct attribute *it6161_attrs[] = {
|
||
&dev_attr_enable_drv_hold.attr,
|
||
&dev_attr_print_timing.attr,
|
||
&dev_attr_sha_debug.attr,
|
||
&dev_attr_enable_hdcp.attr,
|
||
&dev_attr_force_pwronoff.attr,
|
||
&dev_attr_pwr_state.attr,
|
||
NULL,
|
||
};
|
||
|
||
static void it6161_shutdown(struct i2c_client *i2c_mipi_rx)
|
||
{
|
||
struct it6161 *it6161 = dev_get_drvdata(&i2c_mipi_rx->dev);
|
||
|
||
dptx_sys_chg(it6161, SYS_UNPLUG);
|
||
}
|
||
|
||
#endif
|
||
|
||
#if 0
|
||
static DEVICE_ATTR_RW(enable_drv_hold);
|
||
static DEVICE_ATTR_RW(hdmi_output_color_space);
|
||
|
||
static const struct attribute *it6161_attrs[] = {
|
||
&dev_attr_enable_drv_hold.attr,
|
||
&dev_attr_hdmi_output_color_space.attr,
|
||
NULL,
|
||
};
|
||
#endif
|
||
static int it6161_parse_dt(struct it6161 *it6161, struct device_node *np)
|
||
{
|
||
//struct device *dev = &adv->i2c_mipi_rx->dev;
|
||
|
||
it6161->host_node = of_graph_get_remote_node(np, 0, 0);
|
||
if (!it6161->host_node) {
|
||
DRM_INFO("no host node");
|
||
return -ENODEV;
|
||
}
|
||
DRM_INFO("%s", __func__);
|
||
of_node_put(it6161->host_node);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int it6161_gpio_init(struct it6161 *it6161)
|
||
{
|
||
struct device *dev = it6161->dev;
|
||
|
||
it6161->enable_gpio = devm_gpiod_get_optional(dev, "enable",
|
||
GPIOD_OUT_LOW);
|
||
if (IS_ERR(it6161->enable_gpio)) {
|
||
dev_err(dev, "failed to acquire enable gpio\n");
|
||
return PTR_ERR(it6161->enable_gpio);
|
||
}
|
||
|
||
it6161->test_gpio = devm_gpiod_get_optional(dev, "test",
|
||
GPIOD_OUT_LOW);
|
||
if (IS_ERR(it6161->test_gpio)) {
|
||
dev_info(dev, "failed to acquire test gpio\n");
|
||
}
|
||
|
||
msleep(20);
|
||
gpiod_set_value_cansleep(it6161->enable_gpio, 1);
|
||
msleep(20);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int it6161_i2c_probe(struct i2c_client *i2c_mipi_rx,
|
||
const struct i2c_device_id *id)
|
||
{
|
||
//struct it6161 *it6161;
|
||
struct device *dev = &i2c_mipi_rx->dev;
|
||
int err, intp_irq;
|
||
|
||
it6161 = devm_kzalloc(dev, sizeof(*it6161), GFP_KERNEL);
|
||
if (!it6161)
|
||
return -ENOMEM;
|
||
|
||
it6161_bridge = devm_kzalloc(dev, sizeof(*it6161), GFP_KERNEL);
|
||
if (!it6161_bridge)
|
||
return -ENOMEM;
|
||
|
||
it6161->i2c_mipi_rx = i2c_mipi_rx;
|
||
it6161->dev = &i2c_mipi_rx->dev;
|
||
// mutex_init(&it6161->lock);
|
||
mutex_init(&it6161->mode_lock);
|
||
//init_completion(&it6161->wait_hdcp_event);
|
||
init_completion(&it6161->wait_edid_complete);
|
||
|
||
//INIT_DELAYED_WORK(&it6161->hdcp_work, hdmi_tx_hdcp_work);
|
||
//INIT_WORK(&it6161->wait_hdcp_ksv_list, hdmi_tx_hdcp_auth_part2_process);
|
||
// init_waitqueue_head(&it6161->edid_wait);
|
||
|
||
/* set up mipirx restart work*/
|
||
INIT_DELAYED_WORK(&it6161->restart, mipirx_restart);
|
||
|
||
it6161->bridge.of_node = i2c_mipi_rx->dev.of_node;
|
||
|
||
it6161_parse_dt(it6161, dev->of_node);
|
||
it6161_gpio_init(it6161);
|
||
|
||
it6161->regmap_mipi_rx =
|
||
devm_regmap_init_i2c(i2c_mipi_rx, &it6161_mipi_rx_bridge_regmap_config);
|
||
if (IS_ERR(it6161->regmap_mipi_rx)) {
|
||
DRM_DEV_ERROR(dev, "regmap_mipi_rx i2c init failed");
|
||
return PTR_ERR(it6161->regmap_mipi_rx);
|
||
}
|
||
|
||
if (device_property_read_u32(dev, "it6161-addr-hdmi-tx", &it6161->it6161_addr_hdmi_tx) < 0)
|
||
it6161->it6161_addr_hdmi_tx = 0x4c;
|
||
|
||
it6161->i2c_hdmi_tx = i2c_new_dummy_device(i2c_mipi_rx->adapter, it6161->it6161_addr_hdmi_tx);
|
||
if (IS_ERR(it6161->i2c_hdmi_tx)) {
|
||
DRM_DEV_ERROR(dev, "Failed to register it6161 I2C device\n");
|
||
return PTR_ERR(it6161->i2c_hdmi_tx);
|
||
}
|
||
|
||
it6161->regmap_hdmi_tx =
|
||
devm_regmap_init_i2c(it6161->i2c_hdmi_tx, &it6161_hdmi_tx_bridge_regmap_config);
|
||
|
||
if (IS_ERR(it6161->regmap_hdmi_tx)) {
|
||
DRM_DEV_ERROR(dev, "regmap_hdmi_tx i2c init failed");
|
||
err = PTR_ERR(it6161->regmap_hdmi_tx);
|
||
goto err_hdmitx;
|
||
}
|
||
|
||
if (device_property_read_u32(dev, "it6161-addr-cec", &it6161->it6161_addr_cec) < 0)
|
||
it6161->it6161_addr_cec = 0x4E;
|
||
|
||
it6161->i2c_cec = i2c_new_dummy_device(i2c_mipi_rx->adapter, it6161->it6161_addr_cec);
|
||
if (IS_ERR(it6161->i2c_cec)) {
|
||
DRM_DEV_ERROR(dev, "i2c_cec init failed");
|
||
err = PTR_ERR(it6161->i2c_cec);
|
||
goto err_hdmitx;
|
||
}
|
||
|
||
it6161->regmap_cec =
|
||
devm_regmap_init_i2c(it6161->i2c_cec, &it6161_cec_bridge_regmap_config);
|
||
|
||
if (IS_ERR(it6161->regmap_cec)) {
|
||
DRM_DEV_ERROR(dev, "regmap_cec i2c init failed");
|
||
err = PTR_ERR(it6161->regmap_cec);
|
||
goto err_cec;
|
||
}
|
||
|
||
if (!it6161_check_device_ready(it6161)) {
|
||
err = -ENODEV;
|
||
goto err_cec;
|
||
}
|
||
|
||
it6161->enable_drv_hold = DEFAULT_DRV_HOLD;
|
||
it6161_set_interrupts_active_level(HIGH);
|
||
|
||
intp_irq = i2c_mipi_rx->irq;
|
||
|
||
if (!intp_irq) {
|
||
DRM_DEV_ERROR(dev, "it6112 failed to get INTP IRQ");
|
||
err = -ENODEV;
|
||
goto err_cec;
|
||
}
|
||
|
||
err = devm_request_threaded_irq(&i2c_mipi_rx->dev, intp_irq, NULL,
|
||
/*it6161_intp_threaded_handler,*/it6161_intp_threaded_handler,
|
||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||
"it6161-intp", it6161);
|
||
if (err) {
|
||
DRM_DEV_ERROR(dev, "it6112 failed to request INTP threaded IRQ: %d",
|
||
err);
|
||
goto err_cec;
|
||
}
|
||
|
||
i2c_set_clientdata(i2c_mipi_rx, it6161);
|
||
it6161->bridge.funcs = &it6161_bridge_funcs;
|
||
drm_bridge_add(&it6161->bridge);
|
||
|
||
err = it6161_attach_dsi(it6161);
|
||
if (err) {
|
||
DRM_DEV_ERROR(dev, "failed to attach dsi, ret: %d", err);
|
||
goto err_cec;
|
||
}
|
||
|
||
return 0;
|
||
|
||
err_cec:
|
||
i2c_unregister_device(it6161->i2c_cec);
|
||
err_hdmitx:
|
||
i2c_unregister_device(it6161->i2c_hdmi_tx);
|
||
|
||
return err;
|
||
}
|
||
|
||
#if 0
|
||
static int it6161_remove(struct i2c_client *i2c_mipi_rx)
|
||
{
|
||
struct it6161 *it6161 = i2c_get_clientdata(i2c_mipi_rx);
|
||
|
||
drm_connector_unregister(&it6161->connector);
|
||
drm_connector_cleanup(&it6161->connector);
|
||
drm_bridge_remove(&it6161->bridge);
|
||
// sysfs_remove_files(&i2c_mipi_rx->dev.kobj, it6161_attrs);
|
||
// drm_dp_aux_unregister(&it6161->aux);
|
||
// it6161_poweroff(it6161);
|
||
return 0;
|
||
}
|
||
#endif
|
||
static const struct i2c_device_id it6161_id[] = {
|
||
{ "it6161", 0 },
|
||
{ }
|
||
};
|
||
|
||
MODULE_DEVICE_TABLE(i2c, it6161_id);
|
||
|
||
static const struct of_device_id it6161_of_match[] = {
|
||
{ .compatible = "ite,it6161" },
|
||
{ }
|
||
};
|
||
|
||
static struct i2c_driver it6161_i2c_driver = {
|
||
.driver = {
|
||
.name = "it6161_mipirx_hdmitx",
|
||
.of_match_table = it6161_of_match,
|
||
//.pm = &it6161_bridge_pm_ops,
|
||
},
|
||
.probe = it6161_i2c_probe,
|
||
//.remove = it6161_remove,
|
||
//.shutdown = it6161_shutdown,
|
||
.id_table = it6161_id,
|
||
};
|
||
|
||
module_i2c_driver(it6161_i2c_driver);
|
||
|
||
MODULE_AUTHOR("allen chen <allen.chen@ite.com.tw>");
|
||
MODULE_DESCRIPTION("it6161 HDMI Transmitter driver");
|
||
MODULE_LICENSE("GPL v2");
|