Skip to content

Commit

Permalink
Add support for DVI monitors
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Winkler <robert.winkler@boundarydevices.com>
  • Loading branch information
Robert Winkler committed Jul 20, 2013
1 parent 9a25a36 commit 7d87529
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 57 deletions.
7 changes: 7 additions & 0 deletions arch/arm/plat-mxc/include/mach/mxc_hdmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,10 @@ enum {
HDMI_IH_MUTE_PHY_STAT0_TX_PHY_LOCK = 0x2,
HDMI_IH_MUTE_PHY_STAT0_HPD = 0x1,

/* IH and IH_MUTE convenience macro RX_SENSE | HPD*/
HDMI_DVI_IH_STAT = 0x3D,


/* IH_AHBDMAAUD_STAT0 field values */
HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
Expand Down Expand Up @@ -903,6 +907,9 @@ enum {
HDMI_PHY_HPD = 0x02,
HDMI_PHY_TX_PHY_LOCK = 0x01,

/* HDMI STAT convenience RX_SENSE | HPD */
HDMI_DVI_STAT = 0xF2,

/* PHY_I2CM_SLAVE_ADDR field values */
HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
Expand Down
100 changes: 43 additions & 57 deletions drivers/video/mxc_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ struct mxc_hdmi {
bool dft_mode_set;
char *dft_mode_str;
int default_bpp;
u8 latest_intr_stat;
bool irq_enabled;
spinlock_t irq_lock;
bool phy_enabled;
Expand Down Expand Up @@ -1784,71 +1783,61 @@ static void hotplug_worker(struct work_struct *work)
struct delayed_work *delay_work = to_delayed_work(work);
struct mxc_hdmi *hdmi =
container_of(delay_work, struct mxc_hdmi, hotplug_work);
u32 phy_int_stat, phy_int_pol, phy_int_mask;
u8 val;
u32 hdmi_phy_stat0, hdmi_phy_pol0, hdmi_phy_mask0;
unsigned long flags;
char event_string[16];
char *envp[] = { event_string, NULL };

phy_int_stat = hdmi->latest_intr_stat;
phy_int_pol = hdmi_readb(HDMI_PHY_POL0);

dev_dbg(&hdmi->pdev->dev, "phy_int_stat=0x%x, phy_int_pol=0x%x\n",
phy_int_stat, phy_int_pol);
hdmi_phy_stat0 = hdmi_readb(HDMI_PHY_STAT0);
hdmi_phy_pol0 = hdmi_readb(HDMI_PHY_POL0);

dev_dbg(&hdmi->pdev->dev, "hdmi_phy_stat0=0x%x, hdmi_phy_pol0=0x%x\n",
hdmi_phy_stat0, hdmi_phy_pol0);

/* Make HPD intr active low to capture unplug event or
* active high to capture plugin event */
hdmi_writeb((HDMI_DVI_STAT & ~hdmi_phy_stat0), HDMI_PHY_POL0);

/* check cable status */
if (phy_int_stat & HDMI_IH_PHY_STAT0_HPD) {
/* cable connection changes */
if (phy_int_pol & HDMI_PHY_HPD) {
/* Plugin event */
dev_dbg(&hdmi->pdev->dev, "EVENT=plugin\n");
mxc_hdmi_cable_connected(hdmi);

/* Make HPD intr active low to capture unplug event */
val = hdmi_readb(HDMI_PHY_POL0);
val &= ~HDMI_PHY_HPD;
hdmi_writeb(val, HDMI_PHY_POL0);

sprintf(event_string, "EVENT=plugin");
kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
if (hdmi_phy_stat0 & HDMI_DVI_STAT) {
/* Plugin event */
dev_dbg(&hdmi->pdev->dev, "EVENT=plugin\n");
mxc_hdmi_cable_connected(hdmi);

sprintf(event_string, "EVENT=plugin");
kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
#ifdef CONFIG_MXC_HDMI_CEC
mxc_hdmi_cec_handle(0x80);
mxc_hdmi_cec_handle(0x80);
#endif
hdmi_set_cable_state(1);

} else if (!(phy_int_pol & HDMI_PHY_HPD)) {
/* Plugout event */
dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n");
hdmi_set_cable_state(0);
mxc_hdmi_abort_stream();
mxc_hdmi_cable_disconnected(hdmi);
hdmi_set_cable_state(1);

/* Make HPD intr active high to capture plugin event */
val = hdmi_readb(HDMI_PHY_POL0);
val |= HDMI_PHY_HPD;
hdmi_writeb(val, HDMI_PHY_POL0);

sprintf(event_string, "EVENT=plugout");
kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
} else {
/* Plugout event */
dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n");
hdmi_set_cable_state(0);
mxc_hdmi_abort_stream();
mxc_hdmi_cable_disconnected(hdmi);

sprintf(event_string, "EVENT=plugout");
kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
#ifdef CONFIG_MXC_HDMI_CEC
mxc_hdmi_cec_handle(0x100);
mxc_hdmi_cec_handle(0x100);
#endif

} else
dev_dbg(&hdmi->pdev->dev, "EVENT=none?\n");
}

/* Lock here to ensure full powerdown sequence
* completed before next interrupt processed */
spin_lock_irqsave(&hdmi->irq_lock, flags);

/* Re-enable HPD interrupts */
phy_int_mask = hdmi_readb(HDMI_PHY_MASK0);
phy_int_mask &= ~HDMI_PHY_HPD;
hdmi_writeb(phy_int_mask, HDMI_PHY_MASK0);
hdmi_phy_mask0 = hdmi_readb(HDMI_PHY_MASK0);
hdmi_phy_mask0 &= ~HDMI_DVI_STAT;
hdmi_writeb(hdmi_phy_mask0, HDMI_PHY_MASK0);

/* Unmute interrupts */
hdmi_writeb(~HDMI_IH_MUTE_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
hdmi_writeb(~HDMI_DVI_IH_STAT, HDMI_IH_MUTE_PHY_STAT0);

if (hdmi_readb(HDMI_IH_FC_STAT2) & HDMI_IH_FC_STAT2_OVERFLOW_MASK)
mxc_hdmi_clear_overflow();
Expand All @@ -1859,7 +1848,7 @@ static void hotplug_worker(struct work_struct *work)
static irqreturn_t mxc_hdmi_hotplug(int irq, void *data)
{
struct mxc_hdmi *hdmi = data;
u8 val, intr_stat;
u8 val;
unsigned long flags;

spin_lock_irqsave(&hdmi->irq_lock, flags);
Expand All @@ -1881,25 +1870,22 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data)
* HDMI registers.
*/
/* Capture status - used in hotplug_worker ISR */
intr_stat = hdmi_readb(HDMI_IH_PHY_STAT0);

if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
if (hdmi_readb(HDMI_IH_PHY_STAT0) & HDMI_DVI_IH_STAT) {

dev_dbg(&hdmi->pdev->dev, "Hotplug interrupt received\n");
hdmi->latest_intr_stat = intr_stat;

/* Mute interrupts until handled */

val = hdmi_readb(HDMI_IH_MUTE_PHY_STAT0);
val |= HDMI_IH_MUTE_PHY_STAT0_HPD;
val |= HDMI_DVI_IH_STAT;
hdmi_writeb(val, HDMI_IH_MUTE_PHY_STAT0);

val = hdmi_readb(HDMI_PHY_MASK0);
val |= HDMI_PHY_HPD;
val |= HDMI_DVI_STAT;
hdmi_writeb(val, HDMI_PHY_MASK0);

/* Clear Hotplug interrupts */
hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
hdmi_writeb(HDMI_DVI_IH_STAT, HDMI_IH_PHY_STAT0);

schedule_delayed_work(&(hdmi->hotplug_work), msecs_to_jiffies(20));
}
Expand Down Expand Up @@ -2059,13 +2045,13 @@ static void mxc_hdmi_fb_registered(struct mxc_hdmi *hdmi)
HDMI_PHY_I2CM_CTLINT_ADDR);

/* enable cable hot plug irq */
hdmi_writeb((u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
hdmi_writeb((u8)~HDMI_DVI_STAT, HDMI_PHY_MASK0);

/* Clear Hotplug interrupts */
hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
hdmi_writeb(HDMI_DVI_IH_STAT, HDMI_IH_PHY_STAT0);

/* Unmute interrupts */
hdmi_writeb(~HDMI_IH_MUTE_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
hdmi_writeb(~HDMI_DVI_IH_STAT, HDMI_IH_MUTE_PHY_STAT0);

hdmi->fb_reg = true;

Expand Down Expand Up @@ -2298,10 +2284,10 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp,

/* Configure registers related to HDMI interrupt
* generation before registering IRQ. */
hdmi_writeb(HDMI_PHY_HPD, HDMI_PHY_POL0);
hdmi_writeb(HDMI_DVI_STAT, HDMI_PHY_POL0);

/* Clear Hotplug interrupts */
hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
hdmi_writeb(HDMI_DVI_IH_STAT, HDMI_IH_PHY_STAT0);

hdmi->nb.notifier_call = mxc_hdmi_fb_event;
ret = fb_register_client(&hdmi->nb);
Expand Down

0 comments on commit 7d87529

Please sign in to comment.