irqreturn_t hdmi_irq(int irq, void *priv) { char interrupt1 = 0, interrupt2 = 0, interrupt3 = 0, interrupt4 = 0; if(hdmi->pwr_mode == PWR_SAVE_MODE_A) { HDMIWrReg(SYS_CTRL, 0x20); hdmi->pwr_mode = PWR_SAVE_MODE_B; hdmi_dbg(hdmi->dev, "hdmi irq wake up\n"); // HDMI was inserted when system is sleeping, irq was triggered only once // when wake up. So we need to check hotplug status. if(HDMIRdReg(HPD_MENS_STA) & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) { queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); } } else { interrupt1 = HDMIRdReg(INTR_STATUS1); interrupt2 = HDMIRdReg(INTR_STATUS2); interrupt3 = HDMIRdReg(INTR_STATUS3); interrupt4 = HDMIRdReg(INTR_STATUS4); HDMIWrReg(INTR_STATUS1, interrupt1); // HDMIWrReg(INTR_STATUS2, interrupt2); // HDMIWrReg(INTR_STATUS3, interrupt3); // HDMIWrReg(INTR_STATUS4, interrupt4); #if 0 hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x interrupt3 %02x interrupt4 %02x\n",\ __FUNCTION__, interrupt1, interrupt2, interrupt3, interrupt4); #endif if(interrupt1 & (m_INT_HOTPLUG | m_INT_MSENS)) { if(hdmi->state == HDMI_SLEEP) hdmi->state = WAIT_HOTPLUG; interrupt1 &= ~(m_INT_HOTPLUG | m_INT_MSENS); queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); } else if(interrupt1 & (m_INT_EDID_READY | m_INT_EDID_ERR)) { spin_lock(&hdmi->irq_lock); edid_result = interrupt1; spin_unlock(&hdmi->irq_lock); } // else if(hdmi->state == HDMI_SLEEP) { // RK30DBG( "hdmi return to sleep mode\n"); // HDMIWrReg(SYS_CTRL, 0x10); // rk30_hdmi->pwr_mode = PWR_SAVE_MODE_A; // } if(hdmi->hdcp_irq_cb) hdmi->hdcp_irq_cb(interrupt2); } return IRQ_HANDLED; }
static int CecReadFrame(CEC_FrameData_t *Frame) { int i, length; char *data = Frame; if(Frame == NULL) return -1; length = HDMIRdReg(CEC_RX_LENGTH); HDMIWrReg(CEC_RX_OFFSET, 0); printk("%s length is %d\n", __FUNCTION__, length); for(i = 0; i < length; i++) { data[i] = HDMIRdReg(CEC_DATA); printk("%02x\n", data[i]); } return 0; }
static void rk30_hdmi_set_pwr_mode(int mode) { if(hdmi->pwr_mode == mode) return; hdmi_dbg(hdmi->dev, "[%s] mode %d\n", __FUNCTION__, mode); switch(mode) { case PWR_SAVE_MODE_A: HDMIWrReg(SYS_CTRL, 0x10); break; case PWR_SAVE_MODE_B: HDMIWrReg(SYS_CTRL, 0x20); break; case PWR_SAVE_MODE_D: // reset PLL A&B HDMIWrReg(SYS_CTRL, 0x4C); delay100us(); // release PLL A reset HDMIWrReg(SYS_CTRL, 0x48); delay100us(); // release PLL B reset HDMIWrReg(SYS_CTRL, 0x40); break; case PWR_SAVE_MODE_E: HDMIWrReg(SYS_CTRL, 0x80); break; } hdmi->pwr_mode = mode; if(mode != PWR_SAVE_MODE_A) msleep(10); hdmi_dbg(hdmi->dev, "[%s] curmode %02x\n", __FUNCTION__, HDMIRdReg(SYS_CTRL)); }
irqreturn_t hdmi_irq(int irq, void *priv) { char interrupt1 = 0; unsigned long flags; spin_lock_irqsave(&hdmi->irq_lock,flags); interrupt1 = HDMIRdReg(INTERRUPT_STATUS1); HDMIWrReg(INTERRUPT_STATUS1, interrupt1); #if 1 hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x \n",\ __FUNCTION__, interrupt1); #endif if(interrupt1 & m_INT_HOTPLUG ){ if(hdmi->state == HDMI_SLEEP) hdmi->state = WAIT_HOTPLUG; if(hdmi->pwr_mode == LOWER_PWR) rk2928_hdmi_set_pwr_mode(NORMAL); queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); }else if(interrupt1 & m_INT_EDID_READY) { edid_result = interrupt1; }else if(hdmi->state == HDMI_SLEEP) { hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n"); rk2928_hdmi_set_pwr_mode(LOWER_PWR); } #if 0 if(hdmi->hdcp_irq_cb) hdmi->hdcp_irq_cb(interrupt2); #endif spin_unlock_irqrestore(&hdmi->irq_lock,flags); return IRQ_HANDLED; }
int rk2928_hdmi_detect_hotplug(void) { int value = HDMIRdReg(HDMI_STATUS); hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value); value &= m_HOTPLUG; if(value == m_HOTPLUG) return HDMI_HPD_ACTIVED; else if(value) return HDMI_HPD_INSERT; else return HDMI_HPD_REMOVED; }
int rk30_hdmi_detect_hotplug(void) { int value = HDMIRdReg(HPD_MENS_STA); hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value); value &= m_HOTPLUG_STATUS | m_MSEN_STATUS; if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) ) return HDMI_HPD_ACTIVED; else if(value) return HDMI_HPD_INSERT; else return HDMI_HPD_REMOVED; }
void rk2928_hdmi_control_output(int enable) { char mutestatus = 0; if(enable) { mutestatus = HDMIRdReg(AV_MUTE); if(mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) { HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); rk2928_hdmi_sys_power_up(); rk2928_hdmi_sys_power_down(); rk2928_hdmi_sys_power_up(); if(analog_sync){ HDMIWrReg(0xce, 0x00); delay100us(); HDMIWrReg(0xce, 0x01); analog_sync = 0; } } } else { HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); } }
/*----------------------------------------------------------------------------- * Function: hdcp_irq_cb *----------------------------------------------------------------------------- */ static void hdcp_irq_cb(int interrupt) { int value; struct rk30_hdmi *rk30_hdmi = hdcp->hdmi->property->priv; DBG("%s 0x%x", __FUNCTION__, interrupt); if(interrupt & m_INT_HDCP_ERR) { value = HDMIRdReg(HDCP_ERROR); HDMIWrReg(HDCP_ERROR, value); printk(KERN_INFO "HDCP: Error 0x%02x\n", value); if( (hdcp->hdcp_state != HDCP_DISABLED) && (hdcp->hdcp_state != HDCP_ENABLE_PENDING) ) { hdcp_submit_work(HDCP_FAIL_EVENT, 0); } } else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY)) hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); else if(interrupt & m_INT_AUTH_DONE) hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0); }
int rk30_hdmi_detect_hotplug(void) { int value = HDMIRdReg(HPD_MENS_STA); hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value); #if 0 // When HPD and TMDS_CLK was high, HDMI is actived. value &= m_HOTPLUG_STATUS | m_MSEN_STATUS; if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) ) return HDMI_HPD_ACTIVED; else if(value) return HDMI_HPD_INSERT; else return HDMI_HPD_REMOVED; #else // When HPD was high, HDMI is actived. if(value & m_HOTPLUG_STATUS) return HDMI_HPD_ACTIVED; else if(value & m_MSEN_STATUS) return HDMI_HPD_INSERT; else return HDMI_HPD_REMOVED; #endif }
int rk30_hdmi_read_edid(int block, unsigned char *buff) { int value, ret = -1, ddc_bus_freq = 0; char interrupt = 0, trytime = 2; unsigned long flags; hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block); spin_lock_irqsave(&hdmi->irq_lock, flags); edid_result = 0; spin_unlock_irqrestore(&hdmi->irq_lock, flags); //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz. //Set DDC I2C CLK which devided from DDC_CLK to 100KHz. ddc_bus_freq = (30000000/HDMI_EDID_DDC_CLK)/4; HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); // Enable edid interrupt HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS | m_INT_EDID_ERR | m_INT_EDID_READY); while(trytime--) { // Config EDID block and segment addr HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80); HDMIWrReg(EDID_SEGMENT_POINTER, block/2); value = 100; while(value--) { spin_lock_irqsave(&hdmi->irq_lock, flags); interrupt = edid_result; edid_result = 0; spin_unlock_irqrestore(&hdmi->irq_lock, flags); if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY)) break; msleep(10); } hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value); if(interrupt & m_INT_EDID_READY) { for(value = 0; value < HDMI_EDID_BLOCK_SIZE; value++) buff[value] = HDMIRdReg(DDC_READ_FIFO_ADDR); ret = 0; hdmi_dbg(hdmi->dev, "[%s] edid read sucess\n", __FUNCTION__); #ifdef HDMI_DEBUG for(value = 0; value < 128; value++) { printk("%02x ,", buff[value]); if( (value + 1) % 16 == 0) printk("\n"); } #endif break; } if(interrupt & m_INT_EDID_ERR) hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__); hdmi_dbg(hdmi->dev, "[%s] edid try times %d\n", __FUNCTION__, trytime); msleep(100); } // Disable edid interrupt HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS); return ret; }