⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sii9031.c

📁 1. 8623L平台
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * Copyright (c) 2001-2007 Sigma Designs, Inc.  * All Rights Reserved. Proprietary and Confidential. * *//**  @file   SiI9031.c  @brief  Interface to access the SiI9031 HDMI capture chip    @author Christian Wolff, Sean.Sekwon.Choi  @date   2007-07-16*/// to enable or disable the debug messages of this source file, put 1 or 0 below#if 1#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif#include "common.h"#include "hdmi.h"#include "SiI9031.h"#include "i2c.h"struct cap_SiI9031_instance {	// Access	struct RUA *pRUA;	RMuint32 I2CModuleID;	struct EMhwlibI2CDeviceParameter I2CDevice;	RMuint8 BaseDevice;		// State	RMbool verbouse;	RMuint8 intr_mask[6];	RMbool intr_debug;	RMbool audio_enable;	RMuint32 mclk_factor; 	RMuint32 cable_eq;	RMbool upsample_from_422;	enum EMhwlibTVStandard TVStandard;	enum EMhwlibColorSpace InputColorSpace;	enum cap_hdmi_mode hdmi_mode;	RMbool last_auth;	RMbool last_crypt;	RMbool last_hdcp_ok;	RMbool break_hdcp;	RMbool last_power;	RMbool last_clock;	RMbool last_sync;	RMbool last_hotplug;	RMbool audio_pll_locked;	enum audio_state audio_state;	RMbool update_videomode;	RMuint64 audio_guard_time;};/* CEA 861-C/D subset of all EMhwlib video modes *//* translates VIC to enum EMhwlibTVStandard */extern const enum EMhwlibTVStandard cap_hdmi_cea861_modes[HDMI_CEA861_VIDEOMODES_N];// VESA/CVT subset of all EMhwlib video modesextern const enum EMhwlibTVStandard cap_hdmi_it_modes[];extern RMuint32 cap_hdmi_it_modes_n;RMstatus cap_SiI9031_open(	struct RUA *pRUA, 	struct cap_SiI9031_instance **ppSiI9031, 	RMuint32 I2CModuleID, 	struct EMhwlibI2CDeviceParameter *pI2CDevice){	struct cap_SiI9031_instance *pSiI9031;		RMDBGLOG((FUNCNAME, "%s\n",__func__));			// Sanity checks	if (ppSiI9031 == NULL) return RM_FATALINVALIDPOINTER;	*ppSiI9031 = NULL;	if (pRUA == NULL) return RM_FATALINVALIDPOINTER;	if (pI2CDevice == NULL) return RM_FATALINVALIDPOINTER;	// Allocate and clear local instance	pSiI9031 = (struct cap_SiI9031_instance *)RMMalloc(sizeof(struct cap_SiI9031_instance));	if (pSiI9031 == NULL) {		RMDBGLOG((ENABLE, "[SiI9031] FATAL! Not enough memory for struct cap_SiI9031_instance!\n"));		return RM_FATALOUTOFMEMORY;	}	RMMemset(pSiI9031, 0, sizeof(struct cap_SiI9031_instance));	*ppSiI9031 = pSiI9031;	pSiI9031->audio_state = audio_state_off;		// Set default and startup values	pSiI9031->pRUA = pRUA;	pSiI9031->I2CModuleID = I2CModuleID;	pSiI9031->I2CDevice = *pI2CDevice;	pSiI9031->BaseDevice = pI2CDevice->DevAddr;	pSiI9031->mclk_factor = 256;	pSiI9031->cable_eq = 0x0C;	pSiI9031->update_videomode = TRUE;	return RM_OK;}RMstatus cap_SiI9031_close(	struct cap_SiI9031_instance *pSiI9031){	RMDBGLOG((FUNCNAME, "%s\n",__func__));		// Sanity checks	if (pSiI9031 == NULL) return RM_OK;  // already closed		// Free all ressources	RMFree(pSiI9031);		return RM_OK;}/* tri-state all outputs and power down chip */RMstatus cap_SiI9031_tristate(	struct cap_SiI9031_instance *pSiI9031){	RMDBGLOG((FUNCNAME, "%s\n",__func__));		// Sanity checks	if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER;		cap_i2c_open(pSiI9031, pSiI9031->BaseDevice);	cap_i2c_write(pSiI9031, 0x08, 0x06); // power down SiI9031	cap_i2c_write(pSiI9031, 0x09, 0x00); // tri-state SiI9031	cap_i2c_close(pSiI9031);		cap_i2c_open(pSiI9031, pSiI9031->BaseDevice + 8);	cap_i2c_write(pSiI9031, 0x27, 0x01); // Disable I2S out and MClk	cap_i2c_write(pSiI9031, 0x29, 0x18); // Disable I2S signals	cap_i2c_write(pSiI9031, 0x3C, 0x00); // power down and tri-state chip.	cap_i2c_write(pSiI9031, 0x3E, 0x00); // power down and tri-state chip.	cap_i2c_write(pSiI9031, 0x3F, 0x00); // power down and tri-state chip.	cap_i2c_close(pSiI9031);		return RM_OK;}/* Compare two values and return a weighted match value.    Return value is 'weight' if both values are equal,    or 50% of 'weight' minus the percentage points 'a' is away from 'b'. */static inline RMuint32 comp_weight(RMuint32 a, RMuint32 b, RMuint32 weight) {	RMuint32 dist;	if (a == b) return weight;	dist = (a > b) ? a - b : b - a;//	weight /= 2;	dist = (dist * 100) / b;	return (weight > dist) ? weight - dist : 0;}/* detect video format from the line and pixel counter in the SiI9031 */RMstatus cap_SiI9031_measure_video_format(	struct cap_SiI9031_instance *pSiI9031, 	RMuint32 *pVIC, // VIC of the detected mode	RMbool *UseStandard, // TRUE: valid information in pTVStandard, FALSE: valid info only in pTVFormat	enum EMhwlibTVStandard *pTVStandard, 	struct EMhwlibTVFormatDigital *pTVFormat, 	RMuint32 *pAspX, RMuint32 *pAspY){	RMstatus err;	RMuint8 reg;	RMuint8 data[17];	RMuint32 h_res, v_res, de_pix, de_lin, vid_vtavl, vid_vfp, vid_hfp, vid_hswidth, vid_xpcnt, pixclk, pixel_rep, h_shift;	RMbool intrl, vspol, hspol;	RMuint32 i, best_match;	enum EMhwlibTVStandard selected, mode, old;		RMDBGLOG((FUNCNAME, "%s\n",__func__));			// Sanity checks	if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER;		if (UseStandard) *UseStandard = TRUE;	if (pVIC) *pVIC = 0;	selected = old = (pTVStandard) ? *pTVStandard : EMhwlibTVStandard_Custom;		/* read measurement registers from SiI9031 */	cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x06, &reg);	if ((reg & 0x03) != 0x03) {		RMDBGLOG((ENABLE, "[SiI9031] no %s%s%s!\n", 			(reg & 0x08) ? "" : "power", 			(reg & 0x02) ? "" : (reg & 0x08) ? "clock" : (reg & 0x01) ? " or clock" : ", clock", 			(reg & 0x01) ? "" : ((reg & 0x02) && (reg & 0x08)) ? "sync" : " or sync"));		return RM_ERROR;	}		cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x08, &reg);	pixel_rep = RMunshiftBits(reg, 2, 6);	h_shift = (pixel_rep > 1) ? 2 : pixel_rep;		cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice, 0x3A, &data[0], 4);	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice, 0x4E, &data[4], 8);	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice, 0x59, &data[12], 4);	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice, 0x6F, &data[16], 1);	h_res = (data[0] & 0xFF);	h_res |= ((data[1] & 0x1F) << 8);	v_res = (data[2] & 0xFF);	v_res |= ((data[3] & 0x07) << 8);	de_pix = (data[4] & 0xFF);	de_pix |= ((data[5] & 0x1F) << 8);	de_lin = (data[6] & 0xFF);	de_lin |= ((data[7] & 0x07) << 8);	vid_vtavl = (data[8] & 0x3F);	vid_vfp = (data[9] & 0x3F);	intrl = (data[11] & 0x04) ? TRUE : FALSE;	vspol = (data[11] & 0x02) ? TRUE : FALSE;	hspol = (data[11] & 0x01) ? TRUE : FALSE;	vid_hfp = (data[12] & 0xFF);	vid_hswidth = (data[14] & 0xFF);	vid_hswidth |= ((data[15] & 0x03) << 8);	vid_xpcnt = (data[16] & 0xFF);	pixclk = vid_xpcnt ? RM64mult32div32(28322000, 128, vid_xpcnt) : 0;		if (pixel_rep) {		h_res >>= h_shift;		de_pix >>= h_shift;		vid_hfp >>= h_shift;		vid_hswidth >>= h_shift;		vid_xpcnt >>= h_shift;		pixclk >>= h_shift;	}		RMDBGLOG((ENABLE, "[SiI9031] - %lux%lu%c, total:%lux%lu, vsync:%lu-%lu-x-%s., hsync:%lu-%lu-%lu-%s., xpcnt:%lu (%lu Hz)\n", 		de_pix, de_lin * (intrl ? 2 : 1), intrl ? 'i' : 'p', 		h_res, intrl ? v_res * 2 + 1 : v_res, 		vid_vfp, vid_vtavl, vspol ? "pos" : "neg", 		vid_hfp, vid_hswidth, h_res - de_pix - vid_hfp - vid_hswidth, hspol ? "pos" : "neg", 		vid_xpcnt, pixclk));		best_match = 0;		// match HDMI/CEA861 modes	i = 1;	for (i = 1; i < (sizeof(cap_hdmi_cea861_modes) / sizeof(enum EMhwlibTVStandard)); i++) {		struct EMhwlibTVFormatDigital dig;		RMuint32 match;		RMbool dig_Intrl;				// skip dual-aspect-ratio modes, checking for one is enough		if ((i > 1) && (cap_hdmi_cea861_modes[i - 1] == cap_hdmi_cea861_modes[i])) {			continue;		}		mode = cap_hdmi_cea861_modes[i];		err = RUAExchangeProperty(pSiI9031->pRUA, DisplayBlock, 			RMDisplayBlockPropertyID_TVFormatDigital, 			&mode, sizeof(mode), 			&dig, sizeof(dig));		if RMFAILED(err) {			RMDBGLOG((ENABLE, "[SiI9031] Could not get format!\n"));			return err;		}		dig_Intrl = (dig.TopFieldHeight != 0);		if (dig_Intrl) dig.VTotalSize = (dig.VTotalSize + 1) / 2;				match = 0;		match += comp_weight(h_res, dig.HTotalSize, 20);		match += comp_weight(v_res, dig.VTotalSize, 20);		match += comp_weight(de_pix, dig.ActiveWidth, 20);		match += comp_weight(de_lin, dig.ActiveHeight, 20);		//match += comp_weight(vid_vtavl, dig.YOffsetTop, 12);		//match += comp_weight(vid_vfp, dig.VTotalSize - dig.ActiveHeight - dig.YOffsetTop, 12);		//match += comp_weight(vid_hfp, dig.HTotalSize - dig.ActiveWidth - dig.XOffset, 12);		//match += comp_weight(vid_hswidth, dig.HSyncWidth, 12);		match += comp_weight(vid_xpcnt, RM64mult32div32(28322000, 128, dig.PixelClock), 20);		if (intrl == dig_Intrl) match += 32;		if (vspol == ! dig.VSyncActiveLow) match += 20;		if (hspol == ! dig.HSyncActiveLow) match += 20;				if (match > best_match) {			best_match = match;			selected = mode;			if (pVIC) *pVIC = i;  // TODO: aspect ratio!		}	}		// match VESA modes	for (i = 0; i < cap_hdmi_it_modes_n; i++) {		struct EMhwlibTVFormatDigital dig;		RMuint32 match;		RMbool dig_Intrl;				mode = cap_hdmi_it_modes[i];				err = RUAExchangeProperty(pSiI9031->pRUA, DisplayBlock, 			RMDisplayBlockPropertyID_TVFormatDigital, 			&mode, sizeof(mode), 			&dig, sizeof(dig));		if RMFAILED(err) {			RMDBGLOG((ENABLE, "[SiI9031] Could not get format!\n"));			return err;		}		dig_Intrl = (dig.TopFieldHeight != 0);		if (dig_Intrl) dig.VTotalSize = (dig.VTotalSize + 1) / 2;				match = 0;		match += comp_weight(h_res, dig.HTotalSize, 20);		match += comp_weight(v_res, dig.VTotalSize, 20);		match += comp_weight(de_pix, dig.ActiveWidth, 20);		match += comp_weight(de_lin, dig.ActiveHeight, 20);		//match += comp_weight(vid_vtavl, dig.YOffsetTop, 12);		//match += comp_weight(vid_vfp, dig.VTotalSize - dig.ActiveHeight - dig.YOffsetTop, 12);		//match += comp_weight(vid_hfp, dig.HTotalSize - dig.ActiveWidth - dig.XOffset, 12);		//match += comp_weight(vid_hswidth, dig.HSyncWidth, 12);		match += comp_weight(vid_xpcnt, RM64mult32div32(28322000, 128, dig.PixelClock), 20);		if (intrl == dig_Intrl) match += 32;		if (vspol == ! dig.VSyncActiveLow) match += 20;		if (hspol == ! dig.HSyncActiveLow) match += 20;				if (match > best_match) {			best_match = match;			selected = mode;			if (pVIC) *pVIC = 0;		}	}	//	if (selected != old) {//		GetTVStandardName(selected, &StandardName);//		RMDBGLOG((ENABLE, "[SiI9031] Detected new mode from timing: %s\n", StandardName));//	}	if (pTVStandard) *pTVStandard = selected;	if (pTVFormat) {		err = RUAExchangeProperty(pSiI9031->pRUA, DisplayBlock, 			RMDisplayBlockPropertyID_TVFormatDigital, 			&selected, sizeof(selected), 			pTVFormat, sizeof(*pTVFormat));	}	if (pAspX && pAspY) {		// TODO aspect ratio!		*pAspX = 0;		*pAspY = 0;	}		return RM_OK;}/* get current audio channel status from SiI9031 */RMstatus cap_SiI9031_get_audio_channel_status(	struct cap_SiI9031_instance *pSiI9031, 	RMuint8 ch_stat[5]){	RMDBGLOG((FUNCNAME, "%s\n",__func__));		// Sanity checks	if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER;	if (ch_stat == NULL) return RM_FATALINVALIDPOINTER;		cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, 0x2A, &ch_stat[0], 3);	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, 0x30, &ch_stat[3], 2);	RMDBGLOG((ENABLE, "[SiI9031] audio channel status [39:0]: %02X %02X %02X %02X %02X\n", 		ch_stat[4], ch_stat[3], ch_stat[2], ch_stat[1], ch_stat[0]));		return RM_OK;}/* get current audio clock divider values N/CTS from SiI9031 */RMstatus cap_SiI9031_get_audio_n_cts(	struct cap_SiI9031_instance *pSiI9031, 	RMuint32 *pN, 	RMuint32 *pCTS, 	RMuint32 *pApproxSamplingRate){	RMuint8 data[3];	RMuint32 n, cts;		RMDBGLOG((FUNCNAME, "%s\n",__func__));			// Sanity checks	if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER;		// read N/CTS pair, CTS = (f(TMDS clk) * N) / (128 * f(s))	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, 0x06, data, 3);	n = data[2];	n = (n << 8) | data[1];	n = (n << 8) | data[0];	cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, 0x0C, data, 3);	cts = data[2];	cts = (cts << 8) | data[1];	cts = (cts << 8) | data[0];	RMDBGLOG((ENABLE, "[SiI9031] N/CTS: %lu/%lu\n", n, cts));	if (pN) *pN = n;	if (pCTS) *pCTS = cts;		if (pApproxSamplingRate) {		if (n && cts) {			cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x6F, &data[0]);  // xpcnt			// TODO HDMI 1.3: DeepColor TMDS clock != Pixel clock			*pApproxSamplingRate = data[0] ? RM64mult32div32(28322000, n, data[0] * cts) : 0;		} else {			*pApproxSamplingRate = 0;		}	}		return RM_OK;}/* set cable equalisation value to compensate for cable length, 0..15 */RMstatus cap_SiI9031_set_cable_comp(	struct cap_SiI9031_instance *pSiI9031, 	RMuint32 cable_eq){	RMuint8 eq;		RMDBGLOG((FUNCNAME, "%s\n",__func__));			// Sanity checks	if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER;		eq = cable_eq & 0x0F;	eq = (eq << 4) | (0x0F - eq);	cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x81, eq);		return RM_OK;}/* TRUE: upsample 4:2:2 to 4:4:4, FALSE: pass through 4:4:4 */RMstatus cap_SiI9031_set_422_to_444_upsampling(	struct cap_SiI9031_instance *pSiI9031, 	RMbool upsampling){	RMuint8 reg;		RMDBGLOG((FUNCNAME, "%s\n",__func__));		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -