📄 sii9031.c
字号:
// Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; pSiI9031->upsample_from_422 = upsampling; cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x4A, ®); if (upsampling) reg |= 0x04; else reg &= ~0x04; cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x4A, reg); return RM_OK;}/* select a blanking color which will result in "black" for the current input color space */RMstatus cap_SiI9031_set_blanking_color( struct cap_SiI9031_instance *pSiI9031, enum EMhwlibColorSpace InputColorSpace){ RMuint8 rgb[3]; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; pSiI9031->InputColorSpace = InputColorSpace; switch (InputColorSpace) { case EMhwlibColorSpace_RGB_0_255: rgb[1] = 0x00; if (0) case EMhwlibColorSpace_RGB_16_235: rgb[1] = 0x10; rgb[0] = rgb[2] = rgb[1]; break; case EMhwlibColorSpace_YUV_709_0_255: case EMhwlibColorSpace_xvYCC_709_0_255: case EMhwlibColorSpace_YUV_601_0_255: case EMhwlibColorSpace_xvYCC_601_0_255: rgb[1] = 0x00; if (0) case EMhwlibColorSpace_YUV_709: case EMhwlibColorSpace_xvYCC_709: case EMhwlibColorSpace_YUV_601: case EMhwlibColorSpace_xvYCC_601: rgb[1] = 0x10; rgb[0] = rgb[2] = 0x80; break; default: return RM_ERROR; } cap_i2c_write_data(pSiI9031, pSiI9031->BaseDevice, 0x4B, rgb, 3); return RM_OK;}/* set the pixel repetition value announced in the AVI info frame. This reduces the pixel clock and all horizontal timing values accordingly. */RMstatus cap_SiI9031_apply_pixelrep( struct cap_SiI9031_instance *pSiI9031, RMuint32 pixel_rep){ RMuint8 reg; cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x08, ®); if ((pixel_rep == 1) || (pixel_rep == 3)) { RMinsShiftBits(®, pixel_rep, 2, 6); // pixel clock reduction by factor 2 or 4 } else { RMinsShiftBits(®, 0, 2, 6); // no pixel clock reduction } cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x08, reg); return ((pixel_rep == 0) || (pixel_rep == 1) || (pixel_rep == 3)) ? RM_OK : RM_NOT_SUPPORTED;}/* initialize the audio clock and data outputs of the SiI9031 */RMstatus cap_SiI9031_init_audio_clock( struct cap_SiI9031_instance *pSiI9031, RMbool enable, RMuint32 mclk_f){ RMuint8 mclk; RMuint8 i2c_data_ext[][2] = {// {0x00, 0x85}, // init ACR in auto mode, no overrides {0x00, 0x01}, // init ACR in auto mode, no overrides, reuse CTS when not available {0x13, 0x03}, // recommended WINDIV value {0x14, 0x00}, // recommended LKTHRESH value {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x10}, // enable fs filter {0x18, 0x0C}, // enable MClk loop back {0x26, 0xC0}, // I2S: 32 bit frames, align 1 (philips format) {0x28, 0xE4}, // default FIFO mapping {0x2E, 0x00}, // no swap {0x32, 0x00}, // no mute }; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; cap_i2c_init(pSiI9031, pSiI9031->BaseDevice + 8, i2c_data_ext); pSiI9031->audio_enable = enable; pSiI9031->mclk_factor = mclk_f; switch (mclk_f) { case 128: mclk = 0x00; break; default: case 256: mclk = 0x50; break; case 384: mclk = 0xA0; break; case 512: mclk = 0xF0; break; } cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x02, 0x02 | mclk); // Set MClk factor if (enable) { //RMDBGLOG((ENABLE, "\n\n -- ENABLE SiI9031 Audio --\n\n\n")); cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x27, 0x19); // Enable I2S0 out and MClk, send PCM only on I2S cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x29, 0x35); // Enable I2S and SPDIF signals and HW-mute } else { //RMDBGLOG((ENABLE, "\n\n -- DISABLE SiI9031 Audio --\n\n\n")); cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x27, 0x01); // Disable I2S0 out and MClk, send PCM only on I2S cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x29, 0x30); // Disable I2S and SPDIF signals } cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x05, 0xD2); // reset of audio FIFO, put HDCP and ACR in auto-reset cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x05, 0xD0); // end reset return RM_OK;}/* translate info frame type to offset of SiI9031 receive area */RMstatus cap_SiI9031_get_info_frame_offset( struct cap_SiI9031_instance *pSiI9031, RMuint8 type, RMuint8 *pOffset){ RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pOffset == NULL) return RM_FATALINVALIDPOINTER; switch (type) { case 0x00: // no info frame type specified, reading generic info frame *pOffset = 0xC0; break; case 0x03: // General CP *pOffset = 0xDF; break; case 0x04: // Audio CP *pOffset = 0xE0; break; case 0x05: // ISRC1 *pOffset = 0xA0; // use MPEG area break; case 0x06: // ISRC2 *pOffset = 0xA0; // use MPEG area break; case 0x0A: // Gamut Metadata *pOffset = 0xC0; // use generic area break; case 0x81: // Vendor Specific *pOffset = 0xC0; // use generic area break; case 0x82: // AVI *pOffset = 0x40; break; case 0x83: // SPD *pOffset = 0x60; break; case 0x84: // Audio *pOffset = 0x80; break; case 0x85: // MPEG *pOffset = 0xA0; break; default: return RM_NOT_SUPPORTED; } return RM_OK;}/* read the info frame from the specified offset of the SiI9031 */RMstatus cap_SiI9031_read_info_frame( struct cap_SiI9031_instance *pSiI9031, RMuint8 offset, RMuint8 *header, RMuint8 *data, RMuint32 size, RMbool honor_checksum){ RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; switch (offset) { case 0x40: // AVI case 0x60: // SPD case 0x80: // Audio case 0xA0: // MPEG case 0xC0: // Generic (otherwise unrecognized packets) case 0xE0: // ACP cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, offset, header, 3); cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, offset + 3, data, (honor_checksum && (header[0] & 0x80)) ? RMmin((RMuint32)header[2] + 1, size) : size); break; case 0xDF: // General CP RMMemset(header, 0, 3); RMMemset(data, 0, size); header[0] = 0x03; cap_i2c_read_data(pSiI9031, pSiI9031->BaseDevice + 8, offset, data, 1); break; default: return RM_NOT_SUPPORTED; } return RM_OK;}/* select which packet type should be parsed into the register area specified by the offset */RMstatus cap_SiI9031_set_info_frame_receive_type( struct cap_SiI9031_instance *pSiI9031, RMuint8 offset, RMuint8 type){ RMuint8 reg; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; switch (offset) { case 0x40: // AVI if (type != 0x82) return RM_NOT_SUPPORTED; break; case 0x60: // SPD cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x7F, type); // force interrupt on next frame cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, ®); cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, reg | 0x02); break; case 0x80: // Audio if (type != 0x84) return RM_NOT_SUPPORTED; break; case 0xA0: // MPEG cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0xBF, type); // force interrupt on next frame cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, ®); cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, reg | 0x08); break; case 0xC0: // Generic (otherwise unrecognized packets) break; case 0xE0: // ACP cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0xFF, type); // force interrupt on next frame cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, ®); cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x7A, reg | 0x20); break; case 0xDF: // General CP if (type != 0x03) return RM_NOT_SUPPORTED; break; default: return RM_NOT_SUPPORTED; } return RM_OK;}RMstatus cap_SiI9031_detect_mode( struct cap_SiI9031_instance *pSiI9031, enum cap_hdmi_mode *pHDMIMode){ RMuint8 data; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; if (pHDMIMode == NULL) return RM_FATALINVALIDPOINTER; *pHDMIMode = cap_hdmi_mode_unknown; cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x34, &data); *pHDMIMode = (data & 0x02) ? cap_hdmi_mode_HDMI : cap_hdmi_mode_DVI; return RM_OK;}RMstatus cap_SiI9031_set_mode( struct cap_SiI9031_instance *pSiI9031, enum cap_hdmi_mode hdmi_mode){ RMuint8 data; RMDBGLOG((FUNCNAME, "%s\n",__func__)); // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0xD6, &data); if (hdmi_mode == cap_hdmi_mode_HDMI) { data |= 0x10; } else { data &= ~0x10; } cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0xD6, data | 0x10); return RM_OK;}RMstatus cap_SiI9031_init_capture( struct cap_SiI9031_instance *pSiI9031, RMuint32 input, // 0 or 1 RMbool intr_debug) // enable verbouse interrupt reporting{ // Silicon Image 9031 setup RMuint8 i2c_data[][2] = { {0x05, 0xD0}, // end reset, enable auto reset modes {0x08, 0x07}, // start chip, invert clock (setup on pos edge) {0x09, 0x11}, // select input 0 {0x4A, 0x01}, // CCIR601, RGB 4:4:4 24 bit {0x49, 0x01}, // RGB input {0x48, 0x00}, // BT601 output colorspace {0x7A, 0x3F}, // ip_ctrl: initially, intr on all frames {0x88, 0x88}, // ACR1 magic value {0x89, 0x16}, // ACR2 magic value {0xB5, 0x00}, // disable auto audio control incl. I2S outputs {0xB6, 0xF3}, // enable mute conditions {0xB7, 0xF0}, // " " " {0xB8, 0x07}, // " " " {0xBB, 0x01}, // enable clear of error counts }; RMuint8 i2c_data_ext[][2] = { //{0xBF, 0x85}, // default: receive MPEG frames in MPEG area {0xBF, 0x05}, // receive ISRC1 frames in MPEG area }; RMuint8 reg; RMDBGLOG((FUNCNAME, "%s\n",__func__)); if (intr_debug) { pSiI9031->intr_mask[0] = 0x7F; // intr1_mask: all but acrhwcts pSiI9031->intr_mask[1] = 0xB9; // intr2_mask: all but vsync, gotcts, gotaud pSiI9031->intr_mask[2] = 0x7F; // intr3_mask: all but new_cp pSiI9031->intr_mask[3] = 0x7F; // intr4_mask: all pSiI9031->intr_mask[4] = 0xFF; // intr5_mask: all pSiI9031->intr_mask[5] = 0x05; // intr6_mask: all } else { pSiI9031->intr_mask[0] = 0x1B; // intr1_mask: acrpllul, audferr, authstart, authdone pSiI9031->intr_mask[1] = 0x99; // intr2_mask: hdmimode, ckdt, scdt, vidchg// pSiI9031->intr_mask[2] = 0x3F; // intr3_mask: spdif_err, newunr, newmpeg, newaud, newspd, newavi pSiI9031->intr_mask[2] = 0x2F; // intr3_mask: spdif_err, newmpeg, newaud, newspd, newavi// pSiI9031->intr_mask[2] = 0x0F; // intr3_mask: newmpeg, newaud, newspd, newavi pSiI9031->intr_mask[3] = 0x1F; // intr4_mask: no_avi, cts_drop, cts_reuse, fifo_over, fifo_under// pSiI9031->intr_mask[3] = 0x1C; // intr4_mask: no_avi, cts_drop, cts_reuse pSiI9031->intr_mask[4] = 0xFF; // intr5_mask: fnchg, aac_mute, aul_err, vrchg, hrchg, pochg, ilchg, fschg pSiI9031->intr_mask[5] = 0x05; // intr6_mask: new_acp, unplug } pSiI9031->intr_debug = intr_debug; if (input == 1) { i2c_data[2][1] = 0x22; // select input 1 } cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x3C, 0x01); // power up chip. cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x3E, 0xFF); // power up chip. cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice + 8, 0x3F, 0xFF); // power up chip. cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x08, ®); i2c_data[1][1] = (i2c_data[1][1] & 0x3F) | (reg & 0xC0); // keep pixel_rep value cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x05, 0xC3); // reset of audio FIFO and chip, put HDCP and ACR in auto-reset// cap_i2c_write_dev(pSiI9031, pSiI9031->BaseDevice, 0x05, 0x0F); // reset cap_i2c_init(pSiI9031, pSiI9031->BaseDevice, i2c_data); cap_i2c_write_data(pSiI9031, pSiI9031->BaseDevice, 0x75, &(pSiI9031->intr_mask[0]), 4); cap_i2c_write_data(pSiI9031, pSiI9031->BaseDevice, 0x7D, &(pSiI9031->intr_mask[4]), 2); cap_i2c_init(pSiI9031, pSiI9031->BaseDevice + 8, i2c_data_ext); cap_SiI9031_detect_mode(pSiI9031, &(pSiI9031->hdmi_mode)); cap_SiI9031_init_audio_clock(pSiI9031, pSiI9031->hdmi_mode == cap_hdmi_mode_HDMI, pSiI9031->mclk_factor); cap_SiI9031_set_cable_comp(pSiI9031, pSiI9031->cable_eq); cap_SiI9031_set_blanking_color(pSiI9031, pSiI9031->InputColorSpace); cap_SiI9031_set_422_to_444_upsampling(pSiI9031, pSiI9031->upsample_from_422); return RM_OK;}/* Returns RM_OK if an interrupt is pending on the SiI9031 */RMstatus cap_SiI9031_check_int(struct cap_SiI9031_instance *pSiI9031){ RMuint8 reg; // Sanity checks if (pSiI9031 == NULL) return RM_FATALINVALIDPOINTER; cap_i2c_read_dev(pSiI9031, pSiI9031->BaseDevice, 0x70, ®); return (reg & 0x01) ? RM_OK : RM_PENDING;}static void cap_SiI9031_set_packet_update( RMuint8 type, struct cap_hdmi_update *pHDMIUpdate){ RMDBGLOG((FUNCNAME, "%s\n",__func__)); if (pHDMIUpdate && (pHDMIUpdate->APIVersion >= 1)) { switch (type) { case 0x04: // Audio CP pHDMIUpdate->AudioCPPacketUpdate = TRUE; break; case 0x05: // ISRC1 pHDMIUpdate->ISRC1PacketUpdate = TRUE; break; case 0x06: // ISRC2 pHDMIUpdate->ISRC2PacketUpdate = TRUE; break; case 0x0A: // Gamut Metadata pHDMIUpdate->GamutMetadataPacketUpdate = TRUE; break; case 0x81: // Vendor Specific pHDMIUpdate->VendorSpecificInfoFrameUpdate = TRUE; break; case 0x83: // SPD pHDMIUpdate->SPDInfoFrameUpdate = TRUE; break; case 0x84: // Audio pHDMIUpdate->AudioInfoFrameUpdate = TRUE; break; case 0x85: // MPEG pHDMIUpdate->MPEGInfoFrameUpdate = TRUE; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -