Loading drivers/video/sh_mobile_hdmi.c +45 −37 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; enum hotplug_state hp_state; /* hot-plug status */ bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; Loading @@ -227,7 +227,7 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) } /* External video parameter settings */ static void hdmi_external_video_param(struct sh_hdmi *hdmi) static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) { struct fb_var_screeninfo *var = &hdmi->var; u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; Loading Loading @@ -259,7 +259,7 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) if (var->sync & FB_SYNC_VERT_HIGH_ACT) sync |= 8; pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", htotal, hblank, hdelay, var->hsync_len, vtotal, vblank, vdelay, var->vsync_len, sync); Loading Loading @@ -476,9 +476,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); /* * C = No Data * M = 16:9 Picture Aspect Ratio * R = Same as picture aspect ratio * [7:6] C = Colorimetry: no data * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio */ hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); Loading Loading @@ -619,7 +619,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) u8 edid[128]; /* Read EDID */ pr_debug("Read back EDID code:"); dev_dbg(hdmi->dev, "Read back EDID code:"); for (i = 0; i < 128; i++) { edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); #ifdef DEBUG Loading @@ -635,7 +635,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) printk(KERN_CONT "\n"); #endif fb_parse_edid(edid, var); pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", var->left_margin, var->xres, var->right_margin, var->hsync_len, var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); Loading @@ -647,7 +647,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) else hdmi->preprogrammed_mode = false; hdmi_external_video_param(hdmi); sh_hdmi_external_video_param(hdmi); } static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) Loading Loading @@ -675,7 +675,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); if (printk_ratelimit()) pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", irq, status1, mask1, status2, mask2); if (!((status1 & mask1) | (status2 & mask2))) { Loading @@ -687,7 +687,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) udelay(500); msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); pr_debug("MSENS 0x%x\n", msens); dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ Loading Loading @@ -724,7 +724,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) } /* locking: called with info->lock held, or before register_framebuffer() */ static void hdmi_display_on(void *arg, struct fb_info *info) static void sh_hdmi_display_on(void *arg, struct fb_info *info) { /* * info is guaranteed to be valid, when we are called, because our Loading @@ -734,16 +734,23 @@ static void hdmi_display_on(void *arg, struct fb_info *info) struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; struct sh_mobile_lcdc_chan *ch = info->par; pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); /* No need to lock */ hdmi->info = info; /* * hp_state can be set to * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug * HDMI_HOTPLUG_CONNECTED: on monitor plug-in * HDMI_HOTPLUG_EDID_DONE: on EDID read completion */ switch (hdmi->hp_state) { case HDMI_HOTPLUG_EDID_DONE: /* PS mode d->e. All functions are active */ hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); pr_debug("HDMI running\n"); dev_dbg(hdmi->dev, "HDMI running\n"); break; case HDMI_HOTPLUG_DISCONNECTED: info->state = FBINFO_STATE_SUSPENDED; Loading @@ -753,24 +760,24 @@ static void hdmi_display_on(void *arg, struct fb_info *info) } /* locking: called with info->lock held */ static void hdmi_display_off(void *arg) static void sh_hdmi_display_off(void *arg) { struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); /* PS mode e->a */ hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); } /* Hotplug interrupt occurred, read EDID */ static void edid_work_fn(struct work_struct *work) static void sh_hdmi_edid_work_fn(struct work_struct *work) { struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; struct sh_mobile_lcdc_chan *ch; pr_debug("%s(%p): begin, hotplug status %d\n", __func__, dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, pdata->lcd_dev, hdmi->hp_state); if (!pdata->lcd_dev) Loading Loading @@ -800,7 +807,7 @@ static void edid_work_fn(struct work_struct *work) fb_set_suspend(hdmi->info, 0); } else { if (lock_fb_info(hdmi->info)) { hdmi_display_on(hdmi, hdmi->info); sh_hdmi_display_on(hdmi, hdmi->info); unlock_fb_info(hdmi->info); } } Loading @@ -822,7 +829,7 @@ static void edid_work_fn(struct work_struct *work) out: mutex_unlock(&hdmi->mutex); pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); } static int sh_hdmi_notify(struct notifier_block *nb, Loading @@ -846,18 +853,19 @@ static int sh_hdmi_notify(struct notifier_block *nb, switch(action) { case FB_EVENT_FB_REGISTERED: /* Unneeded, activation taken care by hdmi_display_on() */ /* Unneeded, activation taken care by sh_hdmi_display_on() */ break; case FB_EVENT_FB_UNREGISTERED: /* * We are called from unregister_framebuffer() with the * info->lock held. This is bad for us, because we can race with * the scheduled work, which has to call fb_set_suspend(), which * takes info->lock internally, so, edid_work_fn() cannot take * and hold info->lock for the whole function duration. Using an * additional lock creates a classical AB-BA lock up. Therefore, * we have to release the info->lock temporarily, synchronise * with the work queue and re-acquire the info->lock. * takes info->lock internally, so, sh_hdmi_edid_work_fn() * cannot take and hold info->lock for the whole function * duration. Using an additional lock creates a classical AB-BA * lock up. Therefore, we have to release the info->lock * temporarily, synchronise with the work queue and re-acquire * the info->lock. */ unlock_fb_info(hdmi->info); mutex_lock(&hdmi->mutex); Loading Loading @@ -913,7 +921,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto erate; } pr_debug("HDMI set frequency %lu\n", rate); dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); ret = clk_enable(hdmi->hdmi_clk); if (ret < 0) { Loading Loading @@ -948,10 +956,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; board_cfg->board_data = hdmi; board_cfg->display_on = hdmi_display_on; board_cfg->display_off = hdmi_display_off; board_cfg->display_on = sh_hdmi_display_on; board_cfg->display_off = sh_hdmi_display_off; INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); Loading Loading
drivers/video/sh_mobile_hdmi.c +45 −37 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; enum hotplug_state hp_state; /* hot-plug status */ bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; Loading @@ -227,7 +227,7 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) } /* External video parameter settings */ static void hdmi_external_video_param(struct sh_hdmi *hdmi) static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) { struct fb_var_screeninfo *var = &hdmi->var; u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; Loading Loading @@ -259,7 +259,7 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) if (var->sync & FB_SYNC_VERT_HIGH_ACT) sync |= 8; pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", htotal, hblank, hdelay, var->hsync_len, vtotal, vblank, vdelay, var->vsync_len, sync); Loading Loading @@ -476,9 +476,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); /* * C = No Data * M = 16:9 Picture Aspect Ratio * R = Same as picture aspect ratio * [7:6] C = Colorimetry: no data * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio */ hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); Loading Loading @@ -619,7 +619,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) u8 edid[128]; /* Read EDID */ pr_debug("Read back EDID code:"); dev_dbg(hdmi->dev, "Read back EDID code:"); for (i = 0; i < 128; i++) { edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); #ifdef DEBUG Loading @@ -635,7 +635,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) printk(KERN_CONT "\n"); #endif fb_parse_edid(edid, var); pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", var->left_margin, var->xres, var->right_margin, var->hsync_len, var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); Loading @@ -647,7 +647,7 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) else hdmi->preprogrammed_mode = false; hdmi_external_video_param(hdmi); sh_hdmi_external_video_param(hdmi); } static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) Loading Loading @@ -675,7 +675,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); if (printk_ratelimit()) pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", irq, status1, mask1, status2, mask2); if (!((status1 & mask1) | (status2 & mask2))) { Loading @@ -687,7 +687,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) udelay(500); msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); pr_debug("MSENS 0x%x\n", msens); dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ Loading Loading @@ -724,7 +724,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) } /* locking: called with info->lock held, or before register_framebuffer() */ static void hdmi_display_on(void *arg, struct fb_info *info) static void sh_hdmi_display_on(void *arg, struct fb_info *info) { /* * info is guaranteed to be valid, when we are called, because our Loading @@ -734,16 +734,23 @@ static void hdmi_display_on(void *arg, struct fb_info *info) struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; struct sh_mobile_lcdc_chan *ch = info->par; pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); /* No need to lock */ hdmi->info = info; /* * hp_state can be set to * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug * HDMI_HOTPLUG_CONNECTED: on monitor plug-in * HDMI_HOTPLUG_EDID_DONE: on EDID read completion */ switch (hdmi->hp_state) { case HDMI_HOTPLUG_EDID_DONE: /* PS mode d->e. All functions are active */ hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); pr_debug("HDMI running\n"); dev_dbg(hdmi->dev, "HDMI running\n"); break; case HDMI_HOTPLUG_DISCONNECTED: info->state = FBINFO_STATE_SUSPENDED; Loading @@ -753,24 +760,24 @@ static void hdmi_display_on(void *arg, struct fb_info *info) } /* locking: called with info->lock held */ static void hdmi_display_off(void *arg) static void sh_hdmi_display_off(void *arg) { struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); /* PS mode e->a */ hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); } /* Hotplug interrupt occurred, read EDID */ static void edid_work_fn(struct work_struct *work) static void sh_hdmi_edid_work_fn(struct work_struct *work) { struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; struct sh_mobile_lcdc_chan *ch; pr_debug("%s(%p): begin, hotplug status %d\n", __func__, dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, pdata->lcd_dev, hdmi->hp_state); if (!pdata->lcd_dev) Loading Loading @@ -800,7 +807,7 @@ static void edid_work_fn(struct work_struct *work) fb_set_suspend(hdmi->info, 0); } else { if (lock_fb_info(hdmi->info)) { hdmi_display_on(hdmi, hdmi->info); sh_hdmi_display_on(hdmi, hdmi->info); unlock_fb_info(hdmi->info); } } Loading @@ -822,7 +829,7 @@ static void edid_work_fn(struct work_struct *work) out: mutex_unlock(&hdmi->mutex); pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); } static int sh_hdmi_notify(struct notifier_block *nb, Loading @@ -846,18 +853,19 @@ static int sh_hdmi_notify(struct notifier_block *nb, switch(action) { case FB_EVENT_FB_REGISTERED: /* Unneeded, activation taken care by hdmi_display_on() */ /* Unneeded, activation taken care by sh_hdmi_display_on() */ break; case FB_EVENT_FB_UNREGISTERED: /* * We are called from unregister_framebuffer() with the * info->lock held. This is bad for us, because we can race with * the scheduled work, which has to call fb_set_suspend(), which * takes info->lock internally, so, edid_work_fn() cannot take * and hold info->lock for the whole function duration. Using an * additional lock creates a classical AB-BA lock up. Therefore, * we have to release the info->lock temporarily, synchronise * with the work queue and re-acquire the info->lock. * takes info->lock internally, so, sh_hdmi_edid_work_fn() * cannot take and hold info->lock for the whole function * duration. Using an additional lock creates a classical AB-BA * lock up. Therefore, we have to release the info->lock * temporarily, synchronise with the work queue and re-acquire * the info->lock. */ unlock_fb_info(hdmi->info); mutex_lock(&hdmi->mutex); Loading Loading @@ -913,7 +921,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto erate; } pr_debug("HDMI set frequency %lu\n", rate); dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); ret = clk_enable(hdmi->hdmi_clk); if (ret < 0) { Loading Loading @@ -948,10 +956,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; board_cfg->board_data = hdmi; board_cfg->display_on = hdmi_display_on; board_cfg->display_off = hdmi_display_off; board_cfg->display_on = sh_hdmi_display_on; board_cfg->display_off = sh_hdmi_display_off; INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); Loading