aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_hdmi.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2010-11-11 09:45:09 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-11-15 01:01:27 -0500
commit4232f60791d12a5156c3e1c9b04ae08b873a2920 (patch)
tree11995d45e6582aa8c99bdf201354b4ef31e126ae /drivers/video/sh_mobile_hdmi.c
parentd8d776f3fb1ff19c37d43b600fc8c128ff172deb (diff)
fbdev: sh_mobile_hdmi: add support for E-EDID parsing
Many HDMI clients implement enhanced EDID blocks, which often contain additional supported video modes. This patch implements parsing of such E-EDID blocks. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video/sh_mobile_hdmi.c')
-rw-r--r--drivers/video/sh_mobile_hdmi.c60
1 files changed, 49 insertions, 11 deletions
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 3b4cf987fb43..76f9fac9020f 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -211,6 +211,9 @@ struct sh_hdmi {
211 enum hotplug_state hp_state; /* hot-plug status */ 211 enum hotplug_state hp_state; /* hot-plug status */
212 u8 preprogrammed_vic; /* use a pre-programmed VIC or 212 u8 preprogrammed_vic; /* use a pre-programmed VIC or
213 the external mode */ 213 the external mode */
214 u8 edid_block_addr;
215 u8 edid_segment_nr;
216 u8 edid_blocks;
214 struct clk *hdmi_clk; 217 struct clk *hdmi_clk;
215 struct device *dev; 218 struct device *dev;
216 struct fb_info *info; 219 struct fb_info *info;
@@ -756,7 +759,38 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
756 printk(KERN_CONT "\n"); 759 printk(KERN_CONT "\n");
757#endif 760#endif
758 761
759 fb_edid_to_monspecs(edid, &hdmi->monspec); 762 if (!hdmi->edid_blocks) {
763 fb_edid_to_monspecs(edid, &hdmi->monspec);
764 hdmi->edid_blocks = edid[126] + 1;
765
766 dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n",
767 hdmi->monspec.modedb_len, hdmi->edid_blocks - 1);
768 } else {
769 dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n",
770 edid[0], edid[2]);
771 fb_edid_add_monspecs(edid, &hdmi->monspec);
772 }
773
774 if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 +
775 (hdmi->edid_block_addr >> 7) + 1) {
776 /* More blocks to read */
777 if (hdmi->edid_block_addr) {
778 hdmi->edid_block_addr = 0;
779 hdmi->edid_segment_nr++;
780 } else {
781 hdmi->edid_block_addr = 0x80;
782 }
783 /* Set EDID word address */
784 hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
785 /* Enable EDID interrupt */
786 hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
787 /* Set EDID segment pointer - starts reading EDID */
788 hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
789 return -EAGAIN;
790 }
791
792 /* All E-EDID blocks ready */
793 dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len);
760 794
761 fb_get_options("sh_mobile_lcdc", &forced); 795 fb_get_options("sh_mobile_lcdc", &forced);
762 if (forced && *forced) { 796 if (forced && *forced) {
@@ -903,32 +937,34 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
903 /* Check, if hot plug & MSENS pin status are both high */ 937 /* Check, if hot plug & MSENS pin status are both high */
904 if ((msens & 0xC0) == 0xC0) { 938 if ((msens & 0xC0) == 0xC0) {
905 /* Display plug in */ 939 /* Display plug in */
940 hdmi->edid_segment_nr = 0;
941 hdmi->edid_block_addr = 0;
942 hdmi->edid_blocks = 0;
906 hdmi->hp_state = HDMI_HOTPLUG_CONNECTED; 943 hdmi->hp_state = HDMI_HOTPLUG_CONNECTED;
907 944
908 /* Set EDID word address */ 945 /* Set EDID word address */
909 hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); 946 hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
910 /* Set EDID segment pointer */
911 hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
912 /* Enable EDID interrupt */ 947 /* Enable EDID interrupt */
913 hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); 948 hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
949 /* Set EDID segment pointer - starts reading EDID */
950 hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
914 } else if (!(status1 & 0x80)) { 951 } else if (!(status1 & 0x80)) {
915 /* Display unplug, beware multiple interrupts */ 952 /* Display unplug, beware multiple interrupts */
916 if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) 953 if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) {
954 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
917 schedule_delayed_work(&hdmi->edid_work, 0); 955 schedule_delayed_work(&hdmi->edid_work, 0);
918 956 }
919 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
920 /* display_off will switch back to mode_a */ 957 /* display_off will switch back to mode_a */
921 } 958 }
922 } else if (status1 & 2) { 959 } else if (status1 & 2) {
923 /* EDID error interrupt: retry */ 960 /* EDID error interrupt: retry */
924 /* Set EDID word address */ 961 /* Set EDID word address */
925 hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); 962 hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
926 /* Set EDID segment pointer */ 963 /* Set EDID segment pointer */
927 hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); 964 hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
928 } else if (status1 & 4) { 965 } else if (status1 & 4) {
929 /* Disable EDID interrupt */ 966 /* Disable EDID interrupt */
930 hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1); 967 hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1);
931 hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
932 schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10)); 968 schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10));
933 } 969 }
934 970
@@ -1056,7 +1092,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1056 1092
1057 mutex_lock(&hdmi->mutex); 1093 mutex_lock(&hdmi->mutex);
1058 1094
1059 if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { 1095 if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
1060 unsigned long parent_rate = 0, hdmi_rate; 1096 unsigned long parent_rate = 0, hdmi_rate;
1061 1097
1062 /* A device has been plugged in */ 1098 /* A device has been plugged in */
@@ -1066,6 +1102,8 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1066 if (ret < 0) 1102 if (ret < 0)
1067 goto out; 1103 goto out;
1068 1104
1105 hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
1106
1069 /* Reconfigure the clock */ 1107 /* Reconfigure the clock */
1070 ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); 1108 ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
1071 if (ret < 0) 1109 if (ret < 0)
@@ -1119,7 +1157,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
1119 } 1157 }
1120 1158
1121out: 1159out:
1122 if (ret < 0) 1160 if (ret < 0 && ret != -EAGAIN)
1123 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; 1161 hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
1124 mutex_unlock(&hdmi->mutex); 1162 mutex_unlock(&hdmi->mutex);
1125 1163