mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
rk30 hdmi:
1. fix sometimes hdmi crash when system wakeup from sleep; 2. fix sometimes hotplug interrupt was disabled when disable EDID interrupt.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
config HDMI_RK30
|
||||
bool "hdmi support"
|
||||
bool "rk30 hdmi support"
|
||||
depends on LCDC_RK30
|
||||
select FB_MODE_HELPERS
|
||||
# default y
|
||||
|
||||
@@ -29,7 +29,7 @@ extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
static void hdmi_early_suspend(struct early_suspend *h)
|
||||
{
|
||||
hdmi_dbg(hdmi->dev, "hdmi enter early suspend\n");
|
||||
hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);
|
||||
disable_irq(hdmi->irq);
|
||||
hdmi->enable = 0;
|
||||
hdmi->command = HDMI_CONFIG_ENABLE;
|
||||
@@ -71,7 +71,7 @@ static inline void hdmi_io_remap(void)
|
||||
value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);
|
||||
writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);
|
||||
|
||||
// internal hclk = hdmi_hclk/32
|
||||
// internal hclk = hdmi_hclk/20
|
||||
HDMIWrReg(0x800, 19);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ struct hdmi {
|
||||
int state; // hdmi state machine status
|
||||
int autoconfig; // if true, auto config hdmi output mode according to EDID.
|
||||
int command; // HDMI configuration command
|
||||
|
||||
int display; // HDMI display status
|
||||
};
|
||||
|
||||
extern struct hdmi *hdmi;
|
||||
|
||||
@@ -39,7 +39,8 @@ static void rk30_hdmi_set_pwr_mode(int mode)
|
||||
break;
|
||||
}
|
||||
hdmi->pwr_mode = mode;
|
||||
msleep(10);
|
||||
if(mode != PWR_SAVE_MODE_A)
|
||||
msleep(10);
|
||||
hdmi_dbg(hdmi->dev, "[%s] curmode %02x\n", __FUNCTION__, HDMIRdReg(SYS_CTRL));
|
||||
}
|
||||
|
||||
@@ -48,7 +49,10 @@ int rk30_hdmi_detect_hotplug(void)
|
||||
int value = HDMIRdReg(HPD_MENS_STA);
|
||||
|
||||
hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value);
|
||||
if( (value & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) == (m_HOTPLUG_STATUS | m_MSEN_STATUS) )
|
||||
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;
|
||||
@@ -61,7 +65,6 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
|
||||
char interrupt = 0, trytime = 2;
|
||||
|
||||
hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block);
|
||||
// disable_irq(hdmi->irq);
|
||||
spin_lock(&hdmi->irq_lock);
|
||||
edid_result = 0;
|
||||
spin_unlock(&hdmi->irq_lock);
|
||||
@@ -72,8 +75,8 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
|
||||
HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
|
||||
|
||||
// Enable edid interrupt
|
||||
HDMIMskReg(value, INTR_MASK1, (m_INT_EDID_ERR | m_INT_EDID_READY), (m_INT_EDID_ERR | m_INT_EDID_READY));
|
||||
|
||||
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);
|
||||
@@ -84,7 +87,6 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
|
||||
{
|
||||
spin_lock(&hdmi->irq_lock);
|
||||
interrupt = edid_result;
|
||||
// interrupt = HDMIRdReg(INTR_STATUS1);
|
||||
spin_unlock(&hdmi->irq_lock);
|
||||
// hdmi_dbg(hdmi->dev, "[%s] interrupt %02x value %d\n", __FUNCTION__, interrupt, value);
|
||||
if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY))
|
||||
@@ -113,9 +115,8 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
|
||||
|
||||
}
|
||||
// Disable edid interrupt
|
||||
HDMIMskReg(value, INTR_MASK1, (m_INT_EDID_ERR|m_INT_EDID_READY), 0);
|
||||
HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
|
||||
msleep(100);
|
||||
// enable_irq(hdmi->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -130,7 +131,6 @@ static inline void rk30_hdmi_config_phy_reg(int reg, int value)
|
||||
|
||||
static void rk30_hdmi_config_phy(unsigned char vic)
|
||||
{
|
||||
hdmi_dbg(hdmi->dev, "[%s] line %d\n", __FUNCTION__, __LINE__);
|
||||
HDMIWrReg(DEEP_COLOR_MODE, 0x22); // tmds frequency same as input dlck
|
||||
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
|
||||
switch(vic)
|
||||
@@ -436,7 +436,7 @@ int rk30_hdmi_removed(void)
|
||||
}
|
||||
if(hdmi->pwr_mode == PWR_SAVE_MODE_D)
|
||||
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
|
||||
if(hdmi->pwr_mode == PWR_SAVE_MODE_B)
|
||||
if(hdmi->pwr_mode == PWR_SAVE_MODE_B && hdmi->state == HDMI_SLEEP)
|
||||
{
|
||||
HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
|
||||
HDMIWrReg(INTR_MASK2, 0);
|
||||
@@ -461,7 +461,7 @@ irqreturn_t hdmi_irq(int irq, void *priv)
|
||||
|
||||
// HDMI was inserted when system is sleeping, irq was triggered only once
|
||||
// when wake up. So we need to check hotplug status.
|
||||
if((rk30_hdmi_detect_hotplug() == HDMI_HPD_INSERT)) {
|
||||
if(HDMIRdReg(HPD_MENS_STA) & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) {
|
||||
queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ static void hdmi_sys_show_state(int state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case HDMI_SLEEP:
|
||||
dev_printk(KERN_INFO, hdmi->dev, "HDMI_SLEEP\n");
|
||||
break;
|
||||
case HDMI_INITIAL:
|
||||
dev_printk(KERN_INFO, hdmi->dev, "HDMI_INITIAL\n");
|
||||
break;
|
||||
@@ -37,7 +40,7 @@ static void hdmi_sys_show_state(int state)
|
||||
dev_printk(KERN_INFO, hdmi->dev, "PLAY_BACK\n");
|
||||
break;
|
||||
default:
|
||||
dev_printk(KERN_INFO, hdmi->dev, "Unkown State\n");
|
||||
dev_printk(KERN_INFO, hdmi->dev, "Unkown State %d\n", state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -49,6 +52,7 @@ int hdmi_sys_init(void)
|
||||
hdmi->state = HDMI_SLEEP;
|
||||
hdmi->enable = HDMI_ENABLE;
|
||||
hdmi->autoconfig = HDMI_AUTO_CONFIGURE;
|
||||
hdmi->display = HDMI_DISABLE;
|
||||
|
||||
hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
|
||||
hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
|
||||
@@ -62,7 +66,6 @@ int hdmi_sys_init(void)
|
||||
|
||||
void hdmi_sys_remove(void)
|
||||
{
|
||||
rk30_hdmi_removed();
|
||||
fb_destroy_modelist(&hdmi->edid.modelist);
|
||||
if(hdmi->edid.audio)
|
||||
kfree(hdmi->edid.audio);
|
||||
@@ -74,8 +77,17 @@ void hdmi_sys_remove(void)
|
||||
}
|
||||
memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
|
||||
INIT_LIST_HEAD(&hdmi->edid.modelist);
|
||||
hdmi->display = HDMI_DISABLE;
|
||||
}
|
||||
|
||||
static void hdmi_sys_sleep(void)
|
||||
{
|
||||
if(hdmi->enable)
|
||||
disable_irq(hdmi->irq);
|
||||
hdmi->state = HDMI_SLEEP;
|
||||
hdmi->hotplug = HDMI_HPD_REMOVED;
|
||||
rk30_hdmi_removed();
|
||||
if(hdmi->enable)
|
||||
enable_irq(hdmi->irq);
|
||||
}
|
||||
|
||||
static int hdmi_process_command(void)
|
||||
@@ -94,6 +106,9 @@ static int hdmi_process_command(void)
|
||||
{
|
||||
if(hdmi->hotplug)
|
||||
hdmi_sys_remove();
|
||||
hdmi->state = HDMI_SLEEP;
|
||||
hdmi->hotplug = HDMI_HPD_REMOVED;
|
||||
rk30_hdmi_removed();
|
||||
state = HDMI_SLEEP;
|
||||
}
|
||||
if(hdmi->wait == 1) {
|
||||
@@ -145,22 +160,35 @@ void hdmi_work(struct work_struct *work)
|
||||
hotplug = rk30_hdmi_detect_hotplug();
|
||||
hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
|
||||
|
||||
if(hotplug == HDMI_HPD_REMOVED) {
|
||||
hdmi_sys_remove();
|
||||
if(hotplug != hdmi->hotplug) {
|
||||
if(hotplug != hdmi->hotplug)
|
||||
{
|
||||
if(hotplug == HDMI_HPD_ACTIVED){
|
||||
hdmi->hotplug = hotplug;
|
||||
hdmi->state = READ_PARSE_EDID;
|
||||
}
|
||||
else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
|
||||
hdmi_sys_remove();
|
||||
hdmi->hotplug = hotplug;
|
||||
if(hotplug == HDMI_HPD_REMOVED)
|
||||
hdmi_sys_sleep();
|
||||
else {
|
||||
hdmi->state = WAIT_HOTPLUG;
|
||||
rk30_hdmi_removed();
|
||||
}
|
||||
if(hdmi->wait == 1) {
|
||||
complete(&hdmi->complete);
|
||||
hdmi->wait = 0;
|
||||
}
|
||||
kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
|
||||
}
|
||||
if(hdmi->wait == 1) {
|
||||
complete(&hdmi->complete);
|
||||
hdmi->wait = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(hotplug != hdmi->hotplug) {
|
||||
hdmi->hotplug = hotplug;
|
||||
hdmi->state = READ_PARSE_EDID;
|
||||
}
|
||||
else if(hotplug == HDMI_HPD_REMOVED) {
|
||||
hdmi->state = HDMI_SLEEP;
|
||||
rk30_hdmi_removed();
|
||||
}
|
||||
}
|
||||
else if(hotplug == HDMI_HPD_REMOVED)
|
||||
hdmi_sys_sleep();
|
||||
|
||||
do {
|
||||
state_last = hdmi->state;
|
||||
@@ -200,7 +228,10 @@ void hdmi_work(struct work_struct *work)
|
||||
hdmi->state = PLAY_BACK;
|
||||
break;
|
||||
case PLAY_BACK:
|
||||
rk30_hdmi_control_output(1);
|
||||
if(hdmi->display != HDMI_ENABLE) {
|
||||
rk30_hdmi_control_output(HDMI_ENABLE);
|
||||
hdmi->display = HDMI_ENABLE;
|
||||
}
|
||||
if(hdmi->wait == 1) {
|
||||
complete(&hdmi->complete);
|
||||
hdmi->wait = 0;
|
||||
@@ -222,7 +253,12 @@ void hdmi_work(struct work_struct *work)
|
||||
|
||||
if(trytimes == HDMI_MAX_TRY_TIMES)
|
||||
{
|
||||
if(hdmi->hotplug)
|
||||
if(hdmi->hotplug) {
|
||||
hdmi_sys_remove();
|
||||
hdmi->hotplug = HDMI_HPD_REMOVED;
|
||||
hdmi_sys_sleep();
|
||||
|
||||
}
|
||||
}
|
||||
hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
|
||||
}
|
||||
@@ -148,7 +148,8 @@ enum hdmi_change {
|
||||
// HDMI Hotplug status
|
||||
enum {
|
||||
HDMI_HPD_REMOVED = 0,
|
||||
HDMI_HPD_INSERT
|
||||
HDMI_HPD_INSERT,
|
||||
HDMI_HPD_ACTIVED
|
||||
};
|
||||
|
||||
/* HDMI STATUS */
|
||||
|
||||
Reference in New Issue
Block a user