aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sh_mobile_hdmi.c')
-rw-r--r--drivers/video/sh_mobile_hdmi.c297
1 files changed, 74 insertions, 223 deletions
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 647ba984f00f..eafb19da2c07 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -208,6 +208,8 @@ enum hotplug_state {
208}; 208};
209 209
210struct sh_hdmi { 210struct sh_hdmi {
211 struct sh_mobile_lcdc_entity entity;
212
211 void __iomem *base; 213 void __iomem *base;
212 enum hotplug_state hp_state; /* hot-plug status */ 214 enum hotplug_state hp_state; /* hot-plug status */
213 u8 preprogrammed_vic; /* use a pre-programmed VIC or 215 u8 preprogrammed_vic; /* use a pre-programmed VIC or
@@ -217,14 +219,13 @@ struct sh_hdmi {
217 u8 edid_blocks; 219 u8 edid_blocks;
218 struct clk *hdmi_clk; 220 struct clk *hdmi_clk;
219 struct device *dev; 221 struct device *dev;
220 struct fb_info *info;
221 struct mutex mutex; /* Protect the info pointer */
222 struct delayed_work edid_work; 222 struct delayed_work edid_work;
223 struct fb_var_screeninfo var; 223 struct fb_videomode mode;
224 struct fb_monspecs monspec; 224 struct fb_monspecs monspec;
225 struct notifier_block notifier;
226}; 225};
227 226
227#define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity)
228
228static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) 229static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
229{ 230{
230 iowrite8(data, hdmi->base + reg); 231 iowrite8(data, hdmi->base + reg);
@@ -290,24 +291,24 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
290/* External video parameter settings */ 291/* External video parameter settings */
291static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) 292static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
292{ 293{
293 struct fb_var_screeninfo *var = &hdmi->var; 294 struct fb_videomode *mode = &hdmi->mode;
294 u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; 295 u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset;
295 u8 sync = 0; 296 u8 sync = 0;
296 297
297 htotal = var->xres + var->right_margin + var->left_margin + var->hsync_len; 298 htotal = mode->xres + mode->right_margin + mode->left_margin
298 299 + mode->hsync_len;
299 hdelay = var->hsync_len + var->left_margin; 300 hdelay = mode->hsync_len + mode->left_margin;
300 hblank = var->right_margin + hdelay; 301 hblank = mode->right_margin + hdelay;
301 302
302 /* 303 /*
303 * Vertical timing looks a bit different in Figure 18, 304 * Vertical timing looks a bit different in Figure 18,
304 * but let's try the same first by setting offset = 0 305 * but let's try the same first by setting offset = 0
305 */ 306 */
306 vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; 307 vtotal = mode->yres + mode->upper_margin + mode->lower_margin
307 308 + mode->vsync_len;
308 vdelay = var->vsync_len + var->upper_margin; 309 vdelay = mode->vsync_len + mode->upper_margin;
309 vblank = var->lower_margin + vdelay; 310 vblank = mode->lower_margin + vdelay;
310 voffset = min(var->upper_margin / 2, 6U); 311 voffset = min(mode->upper_margin / 2, 6U);
311 312
312 /* 313 /*
313 * [3]: VSYNC polarity: Positive 314 * [3]: VSYNC polarity: Positive
@@ -315,14 +316,14 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
315 * [1]: Interlace/Progressive: Progressive 316 * [1]: Interlace/Progressive: Progressive
316 * [0]: External video settings enable: used. 317 * [0]: External video settings enable: used.
317 */ 318 */
318 if (var->sync & FB_SYNC_HOR_HIGH_ACT) 319 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
319 sync |= 4; 320 sync |= 4;
320 if (var->sync & FB_SYNC_VERT_HIGH_ACT) 321 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
321 sync |= 8; 322 sync |= 8;
322 323
323 dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", 324 dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n",
324 htotal, hblank, hdelay, var->hsync_len, 325 htotal, hblank, hdelay, mode->hsync_len,
325 vtotal, vblank, vdelay, var->vsync_len, sync); 326 vtotal, vblank, vdelay, mode->vsync_len, sync);
326 327
327 hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); 328 hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
328 329
@@ -335,8 +336,8 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
335 hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0); 336 hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0);
336 hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8); 337 hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8);
337 338
338 hdmi_write(hdmi, var->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0); 339 hdmi_write(hdmi, mode->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0);
339 hdmi_write(hdmi, var->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8); 340 hdmi_write(hdmi, mode->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8);
340 341
341 hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0); 342 hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0);
342 hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8); 343 hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8);
@@ -345,7 +346,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
345 346
346 hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY); 347 hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY);
347 348
348 hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); 349 hdmi_write(hdmi, mode->vsync_len, HDMI_EXTERNAL_V_DURATION);
349 350
350 /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ 351 /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
351 if (!hdmi->preprogrammed_vic) 352 if (!hdmi->preprogrammed_vic)
@@ -472,7 +473,7 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
472 */ 473 */
473static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) 474static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
474{ 475{
475 if (hdmi->var.pixclock < 10000) { 476 if (hdmi->mode.pixclock < 10000) {
476 /* for 1080p8bit 148MHz */ 477 /* for 1080p8bit 148MHz */
477 hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); 478 hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
478 hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); 479 hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
@@ -483,7 +484,7 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
483 hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); 484 hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
484 hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); 485 hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
485 hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); 486 hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
486 } else if (hdmi->var.pixclock < 30000) { 487 } else if (hdmi->mode.pixclock < 30000) {
487 /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ 488 /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
488 /* 489 /*
489 * [1:0] Speed_A 490 * [1:0] Speed_A
@@ -732,14 +733,12 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
732static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, 733static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
733 unsigned long *parent_rate) 734 unsigned long *parent_rate)
734{ 735{
735 struct fb_var_screeninfo tmpvar; 736 struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
736 struct fb_var_screeninfo *var = &tmpvar;
737 const struct fb_videomode *mode, *found = NULL; 737 const struct fb_videomode *mode, *found = NULL;
738 struct fb_info *info = hdmi->info;
739 struct fb_modelist *modelist = NULL;
740 unsigned int f_width = 0, f_height = 0, f_refresh = 0; 738 unsigned int f_width = 0, f_height = 0, f_refresh = 0;
741 unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ 739 unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
742 bool scanning = false, preferred_bad = false; 740 bool scanning = false, preferred_bad = false;
741 bool use_edid_mode = false;
743 u8 edid[128]; 742 u8 edid[128];
744 char *forced; 743 char *forced;
745 int i; 744 int i;
@@ -854,12 +853,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
854 } 853 }
855 854
856 /* Check if supported: sufficient fb memory, supported clock-rate */ 855 /* Check if supported: sufficient fb memory, supported clock-rate */
857 fb_videomode_to_var(var, mode); 856 if (ch && ch->notify &&
858 857 ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, mode,
859 var->bits_per_pixel = info->var.bits_per_pixel; 858 NULL)) {
860
861 if (info && info->fbops->fb_check_var &&
862 info->fbops->fb_check_var(var, info)) {
863 scanning = true; 859 scanning = true;
864 preferred_bad = true; 860 preferred_bad = true;
865 continue; 861 continue;
@@ -867,28 +863,19 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
867 863
868 found = mode; 864 found = mode;
869 found_rate_error = rate_error; 865 found_rate_error = rate_error;
866 use_edid_mode = true;
870 } 867 }
871 868
872 hdmi->var.width = hdmi->monspec.max_x * 10;
873 hdmi->var.height = hdmi->monspec.max_y * 10;
874
875 /* 869 /*
876 * TODO 1: if no ->info is present, postpone running the config until 870 * TODO 1: if no default mode is present, postpone running the config
877 * after ->info first gets registered. 871 * until after the LCDC channel is initialized.
878 * TODO 2: consider registering the HDMI platform device from the LCDC 872 * TODO 2: consider registering the HDMI platform device from the LCDC
879 * driver, and passing ->info with HDMI platform data. 873 * driver.
880 */ 874 */
881 if (info && !found) { 875 if (!found && hdmi->entity.def_mode.xres != 0) {
882 modelist = info->modelist.next && 876 found = &hdmi->entity.def_mode;
883 !list_empty(&info->modelist) ? 877 found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate,
884 list_entry(info->modelist.next, 878 parent_rate);
885 struct fb_modelist, list) :
886 NULL;
887
888 if (modelist) {
889 found = &modelist->mode;
890 found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate);
891 }
892 } 879 }
893 880
894 /* No cookie today */ 881 /* No cookie today */
@@ -912,12 +899,13 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
912 else 899 else
913 hdmi->preprogrammed_vic = 0; 900 hdmi->preprogrammed_vic = 0;
914 901
915 dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", 902 dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), "
916 modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", 903 "clock error %luHz\n", use_edid_mode ? "EDID" : "default",
917 found->xres, found->yres, found->refresh, 904 hdmi->preprogrammed_vic ? "VIC" : "external", found->xres,
918 PICOS2KHZ(found->pixclock) * 1000, found_rate_error); 905 found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000,
906 found_rate_error);
919 907
920 fb_videomode_to_var(&hdmi->var, found); 908 hdmi->mode = *found;
921 sh_hdmi_external_video_param(hdmi); 909 sh_hdmi_external_video_param(hdmi);
922 910
923 return 0; 911 return 0;
@@ -998,22 +986,12 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
998 return IRQ_HANDLED; 986 return IRQ_HANDLED;
999} 987}
1000 988
1001/* locking: called with info->lock held, or before register_framebuffer() */ 989static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
1002static void sh_hdmi_display_on(void *arg, struct fb_info *info)
1003{ 990{
1004 /* 991 struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
1005 * info is guaranteed to be valid, when we are called, because our
1006 * FB_EVENT_FB_UNBIND notify is also called with info->lock held
1007 */
1008 struct sh_hdmi *hdmi = arg;
1009 struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
1010 struct sh_mobile_lcdc_chan *ch = info->par;
1011 992
1012 dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, 993 dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi,
1013 pdata->lcd_dev, info->state); 994 hdmi->hp_state);
1014
1015 /* No need to lock */
1016 hdmi->info = info;
1017 995
1018 /* 996 /*
1019 * hp_state can be set to 997 * hp_state can be set to
@@ -1021,56 +999,30 @@ static void sh_hdmi_display_on(void *arg, struct fb_info *info)
1021 * HDMI_HOTPLUG_CONNECTED: on monitor plug-in 999 * HDMI_HOTPLUG_CONNECTED: on monitor plug-in
1022 * HDMI_HOTPLUG_EDID_DONE: on EDID read completion 1000 * HDMI_HOTPLUG_EDID_DONE: on EDID read completion
1023 */ 1001 */
1024 switch (hdmi->hp_state) { 1002 if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
1025 case HDMI_HOTPLUG_EDID_DONE:
1026 /* PS mode d->e. All functions are active */ 1003 /* PS mode d->e. All functions are active */
1027 hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); 1004 hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL);
1028 dev_dbg(hdmi->dev, "HDMI running\n"); 1005 dev_dbg(hdmi->dev, "HDMI running\n");
1029 break;
1030 case HDMI_HOTPLUG_DISCONNECTED:
1031 info->state = FBINFO_STATE_SUSPENDED;
1032 default:
1033 hdmi->var = ch->display_var;
1034 } 1006 }
1007
1008 return hdmi->hp_state == HDMI_HOTPLUG_DISCONNECTED
1009 ? SH_MOBILE_LCDC_DISPLAY_DISCONNECTED
1010 : SH_MOBILE_LCDC_DISPLAY_CONNECTED;
1035} 1011}
1036 1012
1037/* locking: called with info->lock held */ 1013static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
1038static void sh_hdmi_display_off(void *arg)
1039{ 1014{
1040 struct sh_hdmi *hdmi = arg; 1015 struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
1041 struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
1042 1016
1043 dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); 1017 dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi);
1044 /* PS mode e->a */ 1018 /* PS mode e->a */
1045 hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); 1019 hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL);
1046} 1020}
1047 1021
1048static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) 1022static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
1049{ 1023 .display_on = sh_hdmi_display_on,
1050 struct fb_info *info = hdmi->info; 1024 .display_off = sh_hdmi_display_off,
1051 struct sh_mobile_lcdc_chan *ch = info->par; 1025};
1052 struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var;
1053 struct fb_videomode mode1, mode2;
1054
1055 fb_var_to_videomode(&mode1, old_var);
1056 fb_var_to_videomode(&mode2, new_var);
1057
1058 dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
1059 mode1.xres, mode1.yres, mode2.xres, mode2.yres);
1060
1061 if (fb_mode_is_equal(&mode1, &mode2)) {
1062 /* It can be a different monitor with an equal video-mode */
1063 old_var->width = new_var->width;
1064 old_var->height = new_var->height;
1065 return false;
1066 }
1067
1068 dev_dbg(info->dev, "Switching %u -> %u lines\n",
1069 mode1.yres, mode2.yres);
1070 *old_var = *new_var;
1071
1072 return true;
1073}
1074 1026
1075/** 1027/**
1076 * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock 1028 * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
@@ -1111,20 +1063,11 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
1111static void sh_hdmi_edid_work_fn(struct work_struct *work) 1063static void sh_hdmi_edid_work_fn(struct work_struct *work)
1112{ 1064{
1113 struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); 1065 struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
1114 struct fb_info *info; 1066 struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
1115 struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
1116 struct sh_mobile_lcdc_chan *ch;
1117 int ret; 1067 int ret;
1118 1068
1119 dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, 1069 dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
1120 pdata->lcd_dev, hdmi->hp_state); 1070 hdmi->hp_state);
1121
1122 if (!pdata->lcd_dev)
1123 return;
1124
1125 mutex_lock(&hdmi->mutex);
1126
1127 info = hdmi->info;
1128 1071
1129 if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { 1072 if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
1130 unsigned long parent_rate = 0, hdmi_rate; 1073 unsigned long parent_rate = 0, hdmi_rate;
@@ -1145,103 +1088,32 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1145 /* Switched to another (d) power-save mode */ 1088 /* Switched to another (d) power-save mode */
1146 msleep(10); 1089 msleep(10);
1147 1090
1148 if (!info) 1091 if (ch && ch->notify)
1149 goto out; 1092 ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
1150 1093 &hdmi->mode, &hdmi->monspec);
1151 ch = info->par;
1152
1153 if (lock_fb_info(info)) {
1154 console_lock();
1155
1156 /* HDMI plug in */
1157 if (!sh_hdmi_must_reconfigure(hdmi) &&
1158 info->state == FBINFO_STATE_RUNNING) {
1159 /*
1160 * First activation with the default monitor - just turn
1161 * on, if we run a resume here, the logo disappears
1162 */
1163 info->var.width = hdmi->var.width;
1164 info->var.height = hdmi->var.height;
1165 sh_hdmi_display_on(hdmi, info);
1166 } else {
1167 /* New monitor or have to wake up */
1168 fb_set_suspend(info, 0);
1169 }
1170
1171 console_unlock();
1172 unlock_fb_info(info);
1173 }
1174 } else { 1094 } else {
1175 ret = 0;
1176 if (!info)
1177 goto out;
1178
1179 hdmi->monspec.modedb_len = 0; 1095 hdmi->monspec.modedb_len = 0;
1180 fb_destroy_modedb(hdmi->monspec.modedb); 1096 fb_destroy_modedb(hdmi->monspec.modedb);
1181 hdmi->monspec.modedb = NULL; 1097 hdmi->monspec.modedb = NULL;
1182 1098
1183 if (lock_fb_info(info)) { 1099 if (ch && ch->notify)
1184 console_lock(); 1100 ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
1101 NULL, NULL);
1185 1102
1186 /* HDMI disconnect */ 1103 ret = 0;
1187 fb_set_suspend(info, 1);
1188
1189 console_unlock();
1190 unlock_fb_info(info);
1191 }
1192 } 1104 }
1193 1105
1194out: 1106out:
1195 if (ret < 0 && ret != -EAGAIN) 1107 if (ret < 0 && ret != -EAGAIN)
1196 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; 1108 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
1197 mutex_unlock(&hdmi->mutex);
1198 1109
1199 dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); 1110 dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
1200}
1201
1202static int sh_hdmi_notify(struct notifier_block *nb,
1203 unsigned long action, void *data)
1204{
1205 struct fb_event *event = data;
1206 struct fb_info *info = event->info;
1207 struct sh_mobile_lcdc_chan *ch = info->par;
1208 struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
1209 struct sh_hdmi *hdmi = board_cfg->board_data;
1210
1211 if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
1212 return NOTIFY_DONE;
1213
1214 switch(action) {
1215 case FB_EVENT_FB_REGISTERED:
1216 /* Unneeded, activation taken care by sh_hdmi_display_on() */
1217 break;
1218 case FB_EVENT_FB_UNREGISTERED:
1219 /*
1220 * We are called from unregister_framebuffer() with the
1221 * info->lock held. This is bad for us, because we can race with
1222 * the scheduled work, which has to call fb_set_suspend(), which
1223 * takes info->lock internally, so, sh_hdmi_edid_work_fn()
1224 * cannot take and hold info->lock for the whole function
1225 * duration. Using an additional lock creates a classical AB-BA
1226 * lock up. Therefore, we have to release the info->lock
1227 * temporarily, synchronise with the work queue and re-acquire
1228 * the info->lock.
1229 */
1230 unlock_fb_info(info);
1231 mutex_lock(&hdmi->mutex);
1232 hdmi->info = NULL;
1233 mutex_unlock(&hdmi->mutex);
1234 lock_fb_info(info);
1235 return NOTIFY_OK;
1236 }
1237 return NOTIFY_DONE;
1238} 1111}
1239 1112
1240static int __init sh_hdmi_probe(struct platform_device *pdev) 1113static int __init sh_hdmi_probe(struct platform_device *pdev)
1241{ 1114{
1242 struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; 1115 struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
1243 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1116 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1244 struct sh_mobile_lcdc_board_cfg *board_cfg;
1245 int irq = platform_get_irq(pdev, 0), ret; 1117 int irq = platform_get_irq(pdev, 0), ret;
1246 struct sh_hdmi *hdmi; 1118 struct sh_hdmi *hdmi;
1247 long rate; 1119 long rate;
@@ -1255,9 +1127,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
1255 return -ENOMEM; 1127 return -ENOMEM;
1256 } 1128 }
1257 1129
1258 mutex_init(&hdmi->mutex);
1259
1260 hdmi->dev = &pdev->dev; 1130 hdmi->dev = &pdev->dev;
1131 hdmi->entity.owner = THIS_MODULE;
1132 hdmi->entity.ops = &sh_hdmi_ops;
1261 1133
1262 hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); 1134 hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
1263 if (IS_ERR(hdmi->hdmi_clk)) { 1135 if (IS_ERR(hdmi->hdmi_clk)) {
@@ -1297,14 +1169,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
1297 goto emap; 1169 goto emap;
1298 } 1170 }
1299 1171
1300 platform_set_drvdata(pdev, hdmi); 1172 platform_set_drvdata(pdev, &hdmi->entity);
1301
1302 /* Set up LCDC callbacks */
1303 board_cfg = &pdata->lcd_chan->board_cfg;
1304 board_cfg->owner = THIS_MODULE;
1305 board_cfg->board_data = hdmi;
1306 board_cfg->display_on = sh_hdmi_display_on;
1307 board_cfg->display_off = sh_hdmi_display_off;
1308 1173
1309 INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); 1174 INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn);
1310 1175
@@ -1329,9 +1194,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
1329 goto ecodec; 1194 goto ecodec;
1330 } 1195 }
1331 1196
1332 hdmi->notifier.notifier_call = sh_hdmi_notify;
1333 fb_register_client(&hdmi->notifier);
1334
1335 return 0; 1197 return 0;
1336 1198
1337ecodec: 1199ecodec:
@@ -1347,7 +1209,6 @@ ereqreg:
1347erate: 1209erate:
1348 clk_put(hdmi->hdmi_clk); 1210 clk_put(hdmi->hdmi_clk);
1349egetclk: 1211egetclk:
1350 mutex_destroy(&hdmi->mutex);
1351 kfree(hdmi); 1212 kfree(hdmi);
1352 1213
1353 return ret; 1214 return ret;
@@ -1355,21 +1216,12 @@ egetclk:
1355 1216
1356static int __exit sh_hdmi_remove(struct platform_device *pdev) 1217static int __exit sh_hdmi_remove(struct platform_device *pdev)
1357{ 1218{
1358 struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; 1219 struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
1359 struct sh_hdmi *hdmi = platform_get_drvdata(pdev);
1360 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1220 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1361 struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg;
1362 int irq = platform_get_irq(pdev, 0); 1221 int irq = platform_get_irq(pdev, 0);
1363 1222
1364 snd_soc_unregister_codec(&pdev->dev); 1223 snd_soc_unregister_codec(&pdev->dev);
1365 1224
1366 fb_unregister_client(&hdmi->notifier);
1367
1368 board_cfg->display_on = NULL;
1369 board_cfg->display_off = NULL;
1370 board_cfg->board_data = NULL;
1371 board_cfg->owner = NULL;
1372
1373 /* No new work will be scheduled, wait for running ISR */ 1225 /* No new work will be scheduled, wait for running ISR */
1374 free_irq(irq, hdmi); 1226 free_irq(irq, hdmi);
1375 /* Wait for already scheduled work */ 1227 /* Wait for already scheduled work */
@@ -1380,7 +1232,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
1380 clk_put(hdmi->hdmi_clk); 1232 clk_put(hdmi->hdmi_clk);
1381 iounmap(hdmi->base); 1233 iounmap(hdmi->base);
1382 release_mem_region(res->start, resource_size(res)); 1234 release_mem_region(res->start, resource_size(res));
1383 mutex_destroy(&hdmi->mutex);
1384 kfree(hdmi); 1235 kfree(hdmi);
1385 1236
1386 return 0; 1237 return 0;