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.c97
1 files changed, 59 insertions, 38 deletions
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index e7594e145c9..74d9f546a2e 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -222,6 +222,7 @@ struct sh_hdmi {
222 struct delayed_work edid_work; 222 struct delayed_work edid_work;
223 struct fb_var_screeninfo var; 223 struct fb_var_screeninfo var;
224 struct fb_monspecs monspec; 224 struct fb_monspecs monspec;
225 struct notifier_block notifier;
225}; 226};
226 227
227static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) 228static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
@@ -738,7 +739,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
738 struct fb_modelist *modelist = NULL; 739 struct fb_modelist *modelist = NULL;
739 unsigned int f_width = 0, f_height = 0, f_refresh = 0; 740 unsigned int f_width = 0, f_height = 0, f_refresh = 0;
740 unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ 741 unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
741 bool exact_match = false; 742 bool scanning = false, preferred_bad = false;
742 u8 edid[128]; 743 u8 edid[128];
743 char *forced; 744 char *forced;
744 int i; 745 int i;
@@ -801,6 +802,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
801 if (i < 2) { 802 if (i < 2) {
802 f_width = 0; 803 f_width = 0;
803 f_height = 0; 804 f_height = 0;
805 } else {
806 /* The user wants us to use the EDID data */
807 scanning = true;
804 } 808 }
805 dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", 809 dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n",
806 f_width, f_height, f_refresh); 810 f_width, f_height, f_refresh);
@@ -808,37 +812,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
808 812
809 /* Walk monitor modes to find the best or the exact match */ 813 /* Walk monitor modes to find the best or the exact match */
810 for (i = 0, mode = hdmi->monspec.modedb; 814 for (i = 0, mode = hdmi->monspec.modedb;
811 f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; 815 i < hdmi->monspec.modedb_len && scanning;
812 i++, mode++) { 816 i++, mode++) {
813 unsigned long rate_error; 817 unsigned long rate_error;
814 818
815 /* No interest in unmatching modes */ 819 if (!f_width && !f_height) {
816 if (f_width != mode->xres || f_height != mode->yres) 820 /*
821 * A parameter string "video=sh_mobile_lcdc:0x0" means
822 * use the preferred EDID mode. If it is rejected by
823 * .fb_check_var(), keep looking, until an acceptable
824 * one is found.
825 */
826 if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad)
827 scanning = false;
828 else
829 continue;
830 } else if (f_width != mode->xres || f_height != mode->yres) {
831 /* No interest in unmatching modes */
817 continue; 832 continue;
833 }
818 834
819 rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); 835 rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate);
820 836
821 if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) 837 if (scanning) {
822 /* 838 if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
823 * Exact match if either the refresh rate matches or it 839 /*
824 * hasn't been specified and we've found a mode, for 840 * Exact match if either the refresh rate
825 * which we can configure the clock precisely 841 * matches or it hasn't been specified and we've
826 */ 842 * found a mode, for which we can configure the
827 exact_match = true; 843 * clock precisely
828 else if (found && found_rate_error <= rate_error) 844 */
829 /* 845 scanning = false;
830 * We otherwise search for the closest matching clock 846 else if (found && found_rate_error <= rate_error)
831 * rate - either if no refresh rate has been specified 847 /*
832 * or we cannot find an exactly matching one 848 * We otherwise search for the closest matching
833 */ 849 * clock rate - either if no refresh rate has
834 continue; 850 * been specified or we cannot find an exactly
851 * matching one
852 */
853 continue;
854 }
835 855
836 /* Check if supported: sufficient fb memory, supported clock-rate */ 856 /* Check if supported: sufficient fb memory, supported clock-rate */
837 fb_videomode_to_var(var, mode); 857 fb_videomode_to_var(var, mode);
838 858
859 var->bits_per_pixel = info->var.bits_per_pixel;
860
839 if (info && info->fbops->fb_check_var && 861 if (info && info->fbops->fb_check_var &&
840 info->fbops->fb_check_var(var, info)) { 862 info->fbops->fb_check_var(var, info)) {
841 exact_match = false; 863 scanning = true;
864 preferred_bad = true;
842 continue; 865 continue;
843 } 866 }
844 867
@@ -856,9 +879,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
856 * driver, and passing ->info with HDMI platform data. 879 * driver, and passing ->info with HDMI platform data.
857 */ 880 */
858 if (info && !found) { 881 if (info && !found) {
859 modelist = hdmi->info->modelist.next && 882 modelist = info->modelist.next &&
860 !list_empty(&hdmi->info->modelist) ? 883 !list_empty(&info->modelist) ?
861 list_entry(hdmi->info->modelist.next, 884 list_entry(info->modelist.next,
862 struct fb_modelist, list) : 885 struct fb_modelist, list) :
863 NULL; 886 NULL;
864 887
@@ -1101,6 +1124,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1101 mutex_lock(&hdmi->mutex); 1124 mutex_lock(&hdmi->mutex);
1102 1125
1103 if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { 1126 if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
1127 struct fb_info *info = hdmi->info;
1104 unsigned long parent_rate = 0, hdmi_rate; 1128 unsigned long parent_rate = 0, hdmi_rate;
1105 1129
1106 /* A device has been plugged in */ 1130 /* A device has been plugged in */
@@ -1122,22 +1146,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1122 /* Switched to another (d) power-save mode */ 1146 /* Switched to another (d) power-save mode */
1123 msleep(10); 1147 msleep(10);
1124 1148
1125 if (!hdmi->info) 1149 if (!info)
1126 goto out; 1150 goto out;
1127 1151
1128 ch = hdmi->info->par; 1152 ch = info->par;
1129 1153
1130 acquire_console_sem(); 1154 acquire_console_sem();
1131 1155
1132 /* HDMI plug in */ 1156 /* HDMI plug in */
1133 if (!sh_hdmi_must_reconfigure(hdmi) && 1157 if (!sh_hdmi_must_reconfigure(hdmi) &&
1134 hdmi->info->state == FBINFO_STATE_RUNNING) { 1158 info->state == FBINFO_STATE_RUNNING) {
1135 /* 1159 /*
1136 * First activation with the default monitor - just turn 1160 * First activation with the default monitor - just turn
1137 * on, if we run a resume here, the logo disappears 1161 * on, if we run a resume here, the logo disappears
1138 */ 1162 */
1139 if (lock_fb_info(hdmi->info)) { 1163 if (lock_fb_info(info)) {
1140 struct fb_info *info = hdmi->info;
1141 info->var.width = hdmi->var.width; 1164 info->var.width = hdmi->var.width;
1142 info->var.height = hdmi->var.height; 1165 info->var.height = hdmi->var.height;
1143 sh_hdmi_display_on(hdmi, info); 1166 sh_hdmi_display_on(hdmi, info);
@@ -1145,7 +1168,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1145 } 1168 }
1146 } else { 1169 } else {
1147 /* New monitor or have to wake up */ 1170 /* New monitor or have to wake up */
1148 fb_set_suspend(hdmi->info, 0); 1171 fb_set_suspend(info, 0);
1149 } 1172 }
1150 1173
1151 release_console_sem(); 1174 release_console_sem();
@@ -1176,13 +1199,6 @@ out:
1176} 1199}
1177 1200
1178static int sh_hdmi_notify(struct notifier_block *nb, 1201static int sh_hdmi_notify(struct notifier_block *nb,
1179 unsigned long action, void *data);
1180
1181static struct notifier_block sh_hdmi_notifier = {
1182 .notifier_call = sh_hdmi_notify,
1183};
1184
1185static int sh_hdmi_notify(struct notifier_block *nb,
1186 unsigned long action, void *data) 1202 unsigned long action, void *data)
1187{ 1203{
1188 struct fb_event *event = data; 1204 struct fb_event *event = data;
@@ -1191,7 +1207,7 @@ static int sh_hdmi_notify(struct notifier_block *nb,
1191 struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; 1207 struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
1192 struct sh_hdmi *hdmi = board_cfg->board_data; 1208 struct sh_hdmi *hdmi = board_cfg->board_data;
1193 1209
1194 if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) 1210 if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
1195 return NOTIFY_DONE; 1211 return NOTIFY_DONE;
1196 1212
1197 switch(action) { 1213 switch(action) {
@@ -1210,11 +1226,11 @@ static int sh_hdmi_notify(struct notifier_block *nb,
1210 * temporarily, synchronise with the work queue and re-acquire 1226 * temporarily, synchronise with the work queue and re-acquire
1211 * the info->lock. 1227 * the info->lock.
1212 */ 1228 */
1213 unlock_fb_info(hdmi->info); 1229 unlock_fb_info(info);
1214 mutex_lock(&hdmi->mutex); 1230 mutex_lock(&hdmi->mutex);
1215 hdmi->info = NULL; 1231 hdmi->info = NULL;
1216 mutex_unlock(&hdmi->mutex); 1232 mutex_unlock(&hdmi->mutex);
1217 lock_fb_info(hdmi->info); 1233 lock_fb_info(info);
1218 return NOTIFY_OK; 1234 return NOTIFY_OK;
1219 } 1235 }
1220 return NOTIFY_DONE; 1236 return NOTIFY_DONE;
@@ -1312,6 +1328,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
1312 goto ecodec; 1328 goto ecodec;
1313 } 1329 }
1314 1330
1331 hdmi->notifier.notifier_call = sh_hdmi_notify;
1332 fb_register_client(&hdmi->notifier);
1333
1315 return 0; 1334 return 0;
1316 1335
1317ecodec: 1336ecodec:
@@ -1342,6 +1361,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
1342 1361
1343 snd_soc_unregister_codec(&pdev->dev); 1362 snd_soc_unregister_codec(&pdev->dev);
1344 1363
1364 fb_unregister_client(&hdmi->notifier);
1365
1345 board_cfg->display_on = NULL; 1366 board_cfg->display_on = NULL;
1346 board_cfg->display_off = NULL; 1367 board_cfg->display_off = NULL;
1347 board_cfg->board_data = NULL; 1368 board_cfg->board_data = NULL;