Commit bce95fe8 authored by Laurent Pinchart's avatar Laurent Pinchart

sh_mobile_hdmi: Use sh_mobile_lcdc_entity::channel to access fb_info

The fb_info parameter passed to the display_on operation will be
removed, don't use it.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
parent e34d0bbb
...@@ -219,16 +219,12 @@ struct sh_hdmi { ...@@ -219,16 +219,12 @@ struct sh_hdmi {
u8 edid_blocks; u8 edid_blocks;
struct clk *hdmi_clk; struct clk *hdmi_clk;
struct device *dev; struct device *dev;
struct fb_info *info;
struct mutex mutex; /* Protect the info pointer */
struct delayed_work edid_work; struct delayed_work edid_work;
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
struct fb_monspecs monspec; struct fb_monspecs monspec;
struct notifier_block notifier;
}; };
#define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity)
#define notifier_to_hdmi(n) container_of(n, struct sh_hdmi, notifier)
static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
{ {
...@@ -737,10 +733,11 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, ...@@ -737,10 +733,11 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
struct fb_info *info = hdmi->entity.lcdc
? hdmi->entity.lcdc->info : NULL;
struct fb_var_screeninfo tmpvar; struct fb_var_screeninfo tmpvar;
struct fb_var_screeninfo *var = &tmpvar; struct fb_var_screeninfo *var = &tmpvar;
const struct fb_videomode *mode, *found = NULL; const struct fb_videomode *mode, *found = NULL;
struct fb_info *info = hdmi->info;
struct fb_modelist *modelist = NULL; struct fb_modelist *modelist = NULL;
unsigned int f_width = 0, f_height = 0, f_refresh = 0; unsigned int f_width = 0, f_height = 0, f_refresh = 0;
unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
...@@ -1012,13 +1009,10 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity, ...@@ -1012,13 +1009,10 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity,
* FB_EVENT_FB_UNBIND notify is also called with info->lock held * FB_EVENT_FB_UNBIND notify is also called with info->lock held
*/ */
struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_chan *ch = entity->lcdc;
dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state); dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state);
/* No need to lock */
hdmi->info = info;
/* /*
* hp_state can be set to * hp_state can be set to
* HDMI_HOTPLUG_DISCONNECTED: on monitor unplug * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug
...@@ -1040,7 +1034,6 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity, ...@@ -1040,7 +1034,6 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity,
return 0; return 0;
} }
/* locking: called with info->lock held */
static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
{ {
struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
...@@ -1057,15 +1050,14 @@ static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { ...@@ -1057,15 +1050,14 @@ static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
{ {
struct fb_info *info = hdmi->info; struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
struct sh_mobile_lcdc_chan *ch = info->par;
struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var;
struct fb_videomode mode1, mode2; struct fb_videomode mode1, mode2;
fb_var_to_videomode(&mode1, old_var); fb_var_to_videomode(&mode1, old_var);
fb_var_to_videomode(&mode2, new_var); fb_var_to_videomode(&mode2, new_var);
dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", dev_dbg(hdmi->dev, "Old %ux%u, new %ux%u\n",
mode1.xres, mode1.yres, mode2.xres, mode2.yres); mode1.xres, mode1.yres, mode2.xres, mode2.yres);
if (fb_mode_is_equal(&mode1, &mode2)) { if (fb_mode_is_equal(&mode1, &mode2)) {
...@@ -1075,7 +1067,7 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) ...@@ -1075,7 +1067,7 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
return false; return false;
} }
dev_dbg(info->dev, "Switching %u -> %u lines\n", dev_dbg(hdmi->dev, "Switching %u -> %u lines\n",
mode1.yres, mode2.yres); mode1.yres, mode2.yres);
*old_var = *new_var; *old_var = *new_var;
...@@ -1121,17 +1113,13 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, ...@@ -1121,17 +1113,13 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
static void sh_hdmi_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_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
struct fb_info *info; struct fb_info *info;
struct sh_mobile_lcdc_chan *ch;
int ret; int ret;
dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi, dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
hdmi->hp_state); hdmi->hp_state);
mutex_lock(&hdmi->mutex);
info = hdmi->info;
if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
unsigned long parent_rate = 0, hdmi_rate; unsigned long parent_rate = 0, hdmi_rate;
...@@ -1151,10 +1139,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ...@@ -1151,10 +1139,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
/* Switched to another (d) power-save mode */ /* Switched to another (d) power-save mode */
msleep(10); msleep(10);
if (!info) if (ch == NULL)
goto out; goto out;
ch = info->par; info = ch->info;
if (lock_fb_info(info)) { if (lock_fb_info(info)) {
console_lock(); console_lock();
...@@ -1179,9 +1167,11 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ...@@ -1179,9 +1167,11 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
} }
} else { } else {
ret = 0; ret = 0;
if (!info) if (ch == NULL)
goto out; goto out;
info = ch->info;
hdmi->monspec.modedb_len = 0; hdmi->monspec.modedb_len = 0;
fb_destroy_modedb(hdmi->monspec.modedb); fb_destroy_modedb(hdmi->monspec.modedb);
hdmi->monspec.modedb = NULL; hdmi->monspec.modedb = NULL;
...@@ -1200,47 +1190,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ...@@ -1200,47 +1190,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
out: out:
if (ret < 0 && ret != -EAGAIN) if (ret < 0 && ret != -EAGAIN)
hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
mutex_unlock(&hdmi->mutex);
dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
} }
static int sh_hdmi_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct fb_event *event = data;
struct fb_info *info = event->info;
struct sh_hdmi *hdmi = notifier_to_hdmi(nb);
if (hdmi->info != info)
return NOTIFY_DONE;
switch(action) {
case FB_EVENT_FB_REGISTERED:
/* 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, 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(info);
mutex_lock(&hdmi->mutex);
hdmi->info = NULL;
mutex_unlock(&hdmi->mutex);
lock_fb_info(info);
return NOTIFY_OK;
}
return NOTIFY_DONE;
}
static int __init sh_hdmi_probe(struct platform_device *pdev) static int __init sh_hdmi_probe(struct platform_device *pdev)
{ {
struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
...@@ -1258,8 +1211,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) ...@@ -1258,8 +1211,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&hdmi->mutex);
hdmi->dev = &pdev->dev; hdmi->dev = &pdev->dev;
hdmi->entity.owner = THIS_MODULE; hdmi->entity.owner = THIS_MODULE;
hdmi->entity.ops = &sh_hdmi_ops; hdmi->entity.ops = &sh_hdmi_ops;
...@@ -1327,9 +1278,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) ...@@ -1327,9 +1278,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
goto ecodec; goto ecodec;
} }
hdmi->notifier.notifier_call = sh_hdmi_notify;
fb_register_client(&hdmi->notifier);
return 0; return 0;
ecodec: ecodec:
...@@ -1345,7 +1293,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) ...@@ -1345,7 +1293,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
erate: erate:
clk_put(hdmi->hdmi_clk); clk_put(hdmi->hdmi_clk);
egetclk: egetclk:
mutex_destroy(&hdmi->mutex);
kfree(hdmi); kfree(hdmi);
return ret; return ret;
...@@ -1359,8 +1306,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) ...@@ -1359,8 +1306,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
snd_soc_unregister_codec(&pdev->dev); snd_soc_unregister_codec(&pdev->dev);
fb_unregister_client(&hdmi->notifier);
/* No new work will be scheduled, wait for running ISR */ /* No new work will be scheduled, wait for running ISR */
free_irq(irq, hdmi); free_irq(irq, hdmi);
/* Wait for already scheduled work */ /* Wait for already scheduled work */
...@@ -1371,7 +1316,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) ...@@ -1371,7 +1316,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
clk_put(hdmi->hdmi_clk); clk_put(hdmi->hdmi_clk);
iounmap(hdmi->base); iounmap(hdmi->base);
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
mutex_destroy(&hdmi->mutex);
kfree(hdmi); kfree(hdmi);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment