1commit 061f4ee6ee04553ec034298b12b8e7a301e5799f 2Author: zhaoxc0502 <zhaoxc0502@thundersoft.com> 3Date: Thu Jun 16 17:29:10 2022 +0800 4 5 linux_drivers_video 6 7 Change-Id: I90b98cd89f79c8a533f3d2554fbcf12b4c482fe8 8 9diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig 10index 427a993c7..df9bd4b45 100644 11--- a/drivers/video/Kconfig 12+++ b/drivers/video/Kconfig 13@@ -15,7 +15,7 @@ source "drivers/char/agp/Kconfig" 14 source "drivers/gpu/vga/Kconfig" 15 16 source "drivers/gpu/host1x/Kconfig" 17-source "drivers/gpu/ipu-v3/Kconfig" 18+source "drivers/gpu/imx/Kconfig" 19 20 source "drivers/gpu/drm/Kconfig" 21 22diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c 23index 1cf924f3a..7f2fe2913 100644 24--- a/drivers/video/backlight/pwm_bl.c 25+++ b/drivers/video/backlight/pwm_bl.c 26@@ -37,6 +37,7 @@ struct pwm_bl_data { 27 int brightness); 28 int (*check_fb)(struct device *, struct fb_info *); 29 void (*exit)(struct device *); 30+ char fb_id[16]; 31 }; 32 33 static void pwm_backlight_power_on(struct pwm_bl_data *pb) 34@@ -226,6 +227,17 @@ int pwm_backlight_brightness_default(struct device *dev, 35 return 0; 36 } 37 38+static int pwm_backlight_check_fb_name(struct device *dev, struct fb_info *info) 39+{ 40+ struct backlight_device *bl = dev_get_drvdata(dev); 41+ struct pwm_bl_data *pb = bl_get_data(bl); 42+ 43+ if (strcmp(info->fix.id, pb->fb_id) == 0) 44+ return true; 45+ 46+ return false; 47+} 48+ 49 static int pwm_backlight_parse_dt(struct device *dev, 50 struct platform_pwm_backlight_data *data) 51 { 52@@ -238,12 +250,18 @@ static int pwm_backlight_parse_dt(struct device *dev, 53 int length; 54 u32 value; 55 int ret; 56+ const char *names; 57 58 if (!node) 59 return -ENODEV; 60 61 memset(data, 0, sizeof(*data)); 62 63+ if (!of_property_read_string(node, "fb-names", &names)) { 64+ strncpy(data->fb_id, names, sizeof(data->fb_id)); 65+ data->check_fb = &pwm_backlight_check_fb_name; 66+ } 67+ 68 /* 69 * These values are optional and set as 0 by default, the out values 70 * are modified only if a valid u32 value can be decoded. 71@@ -363,7 +381,6 @@ static int pwm_backlight_parse_dt(struct device *dev, 72 73 data->max_brightness--; 74 } 75- 76 return 0; 77 } 78 79@@ -500,6 +517,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) 80 pb->enabled = false; 81 pb->post_pwm_on_delay = data->post_pwm_on_delay; 82 pb->pwm_off_delay = data->pwm_off_delay; 83+ strcpy(pb->fb_id, data->fb_id); 84 85 pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 86 GPIOD_ASIS); 87diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile 88index 477b9624b..13e4b74d8 100644 89--- a/drivers/video/fbdev/Makefile 90+++ b/drivers/video/fbdev/Makefile 91@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_VIA) += via/ 92 obj-$(CONFIG_FB_KYRO) += kyro/ 93 obj-$(CONFIG_FB_SAVAGE) += savage/ 94 obj-$(CONFIG_FB_GEODE) += geode/ 95+obj-$(CONFIG_FB_MXC) += mxc/ 96 obj-$(CONFIG_FB_NEOMAGIC) += neofb.o 97 obj-$(CONFIG_FB_3DFX) += tdfxfb.o 98 obj-$(CONFIG_FB_CONTROL) += controlfb.o 99diff --git a/drivers/video/fbdev/mxc/Kconfig b/drivers/video/fbdev/mxc/Kconfig 100new file mode 100644 101index 000000000..acba4261c 102--- /dev/null 103+++ b/drivers/video/fbdev/mxc/Kconfig 104@@ -0,0 +1,20 @@ 105+config FB_MXC 106+ tristate "MXC Framebuffer support" 107+ depends on FB 108+ select FB_CFB_FILLRECT 109+ select FB_CFB_COPYAREA 110+ select FB_CFB_IMAGEBLIT 111+ select FB_MODE_HELPERS 112+ default y 113+ help 114+ This is a framebuffer device for the MXC LCD Controller. 115+ See <http://www.linux-fbdev.org/> for information on framebuffer 116+ devices. 117+ 118+ If you plan to use the LCD display with your MXC system, say 119+ Y here. 120+config FB_MXC_EDID 121+ depends on FB_MXC && I2C 122+ tristate "MXC EDID support" 123+ default y 124+ 125diff --git a/drivers/video/fbdev/mxc/Makefile b/drivers/video/fbdev/mxc/Makefile 126new file mode 100644 127index 000000000..d9a1cbf68 128--- /dev/null 129+++ b/drivers/video/fbdev/mxc/Makefile 130@@ -0,0 +1 @@ 131+obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o 132diff --git a/drivers/video/fbdev/mxc/mxc_edid.c b/drivers/video/fbdev/mxc/mxc_edid.c 133new file mode 100644 134index 000000000..903172e6a 135--- /dev/null 136+++ b/drivers/video/fbdev/mxc/mxc_edid.c 137@@ -0,0 +1,770 @@ 138+/* 139+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved. 140+ */ 141+ 142+/* 143+ * The code contained herein is licensed under the GNU General Public 144+ * License. You may obtain a copy of the GNU General Public License 145+ * Version 2 or later at the following locations: 146+ * 147+ * http://www.opensource.org/licenses/gpl-license.html 148+ * http://www.gnu.org/copyleft/gpl.html 149+ */ 150+ 151+/*! 152+ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC. 153+ */ 154+ 155+/*! 156+ * @file mxc_edid.c 157+ * 158+ * @brief MXC EDID driver 159+ * 160+ * @ingroup Framebuffer 161+ */ 162+ 163+/*! 164+ * Include files 165+ */ 166+#include <linux/i2c.h> 167+#include <linux/fb.h> 168+#include <video/mxc_edid.h> 169+#include "../edid.h" 170+ 171+#undef DEBUG /* define this for verbose EDID parsing output */ 172+#ifdef DEBUG 173+#define DPRINTK(fmt, args...) printk(fmt, ## args) 174+#else 175+#define DPRINTK(fmt, args...) 176+#endif 177+ 178+const struct fb_videomode mxc_cea_mode[64] = { 179+ /* #1: 640x480p@59.94/60Hz 4:3 */ 180+ [1] = { 181+ NULL, 60, 640, 480, 39683, 48, 16, 33, 10, 96, 2, 0, 182+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 183+ }, 184+ /* #2: 720x480p@59.94/60Hz 4:3 */ 185+ [2] = { 186+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, 187+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 188+ }, 189+ /* #3: 720x480p@59.94/60Hz 16:9 */ 190+ [3] = { 191+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, 192+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 193+ }, 194+ /* #4: 1280x720p@59.94/60Hz 16:9 */ 195+ [4] = { 196+ NULL, 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5, 197+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 198+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0 199+ }, 200+ /* #5: 1920x1080i@59.94/60Hz 16:9 */ 201+ [5] = { 202+ NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, 203+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 204+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0, 205+ }, 206+ /* #6: 720(1440)x480iH@59.94/60Hz 4:3 */ 207+ [6] = { 208+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, 209+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_4_3, 0, 210+ }, 211+ /* #7: 720(1440)x480iH@59.94/60Hz 16:9 */ 212+ [7] = { 213+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, 214+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0, 215+ }, 216+ /* #8: 720(1440)x240pH@59.94/60Hz 4:3 */ 217+ [8] = { 218+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0, 219+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 220+ }, 221+ /* #9: 720(1440)x240pH@59.94/60Hz 16:9 */ 222+ [9] = { 223+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0, 224+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 225+ }, 226+ /* #14: 1440x480p@59.94/60Hz 4:3 */ 227+ [14] = { 228+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0, 229+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 230+ }, 231+ /* #15: 1440x480p@59.94/60Hz 16:9 */ 232+ [15] = { 233+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0, 234+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 235+ }, 236+ /* #16: 1920x1080p@60Hz 16:9 */ 237+ [16] = { 238+ NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, 239+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 240+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 241+ }, 242+ /* #17: 720x576pH@50Hz 4:3 */ 243+ [17] = { 244+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, 245+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 246+ }, 247+ /* #18: 720x576pH@50Hz 16:9 */ 248+ [18] = { 249+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, 250+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 251+ }, 252+ /* #19: 1280x720p@50Hz */ 253+ [19] = { 254+ NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, 255+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 256+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 257+ }, 258+ /* #20: 1920x1080i@50Hz */ 259+ [20] = { 260+ NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, 261+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 262+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0, 263+ }, 264+ /* #23: 720(1440)x288pH@50Hz 4:3 */ 265+ [23] = { 266+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0, 267+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 268+ }, 269+ /* #24: 720(1440)x288pH@50Hz 16:9 */ 270+ [24] = { 271+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0, 272+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 273+ }, 274+ /* #29: 720(1440)x576pH@50Hz 4:3 */ 275+ [29] = { 276+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0, 277+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0, 278+ }, 279+ /* #30: 720(1440)x576pH@50Hz 16:9 */ 280+ [30] = { 281+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0, 282+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 283+ }, 284+ /* #31: 1920x1080p@50Hz */ 285+ [31] = { 286+ NULL, 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5, 287+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 288+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 289+ }, 290+ /* #32: 1920x1080p@23.98/24Hz */ 291+ [32] = { 292+ NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, 293+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 294+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 295+ }, 296+ /* #33: 1920x1080p@25Hz */ 297+ [33] = { 298+ NULL, 25, 1920, 1080, 13468, 148, 528, 36, 4, 44, 5, 299+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 300+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 301+ }, 302+ /* #34: 1920x1080p@30Hz */ 303+ [34] = { 304+ NULL, 30, 1920, 1080, 13468, 148, 88, 36, 4, 44, 5, 305+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 306+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0, 307+ }, 308+ /* #41: 1280x720p@100Hz 16:9 */ 309+ [41] = { 310+ NULL, 100, 1280, 720, 6734, 220, 440, 20, 5, 40, 5, 311+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 312+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0 313+ }, 314+ /* #47: 1280x720p@119.88/120Hz 16:9 */ 315+ [47] = { 316+ NULL, 120, 1280, 720, 6734, 220, 110, 20, 5, 40, 5, 317+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 318+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0 319+ }, 320+}; 321+ 322+/* 323+ * We have a special version of fb_mode_is_equal that ignores 324+ * pixclock, since for many CEA modes, 2 frequencies are supported 325+ * e.g. 640x480 @ 60Hz or 59.94Hz 326+ */ 327+int mxc_edid_fb_mode_is_equal(bool use_aspect, 328+ const struct fb_videomode *mode1, 329+ const struct fb_videomode *mode2) 330+{ 331+ u32 mask; 332+ 333+ if (use_aspect) 334+ mask = ~0; 335+ else 336+ mask = ~FB_VMODE_ASPECT_MASK; 337+ 338+ return (mode1->xres == mode2->xres && 339+ mode1->yres == mode2->yres && 340+ mode1->hsync_len == mode2->hsync_len && 341+ mode1->vsync_len == mode2->vsync_len && 342+ mode1->left_margin == mode2->left_margin && 343+ mode1->right_margin == mode2->right_margin && 344+ mode1->upper_margin == mode2->upper_margin && 345+ mode1->lower_margin == mode2->lower_margin && 346+ mode1->sync == mode2->sync && 347+ /* refresh check, 59.94Hz and 60Hz have the same parameter 348+ * in struct of mxc_cea_mode */ 349+ abs(mode1->refresh - mode2->refresh) <= 1 && 350+ (mode1->vmode & mask) == (mode2->vmode & mask)); 351+} 352+ 353+static void get_detailed_timing(unsigned char *block, 354+ struct fb_videomode *mode) 355+{ 356+ mode->xres = H_ACTIVE; 357+ mode->yres = V_ACTIVE; 358+ mode->pixclock = PIXEL_CLOCK; 359+ mode->pixclock /= 1000; 360+ mode->pixclock = KHZ2PICOS(mode->pixclock); 361+ mode->right_margin = H_SYNC_OFFSET; 362+ mode->left_margin = (H_ACTIVE + H_BLANKING) - 363+ (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); 364+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 365+ V_SYNC_WIDTH; 366+ mode->lower_margin = V_SYNC_OFFSET; 367+ mode->hsync_len = H_SYNC_WIDTH; 368+ mode->vsync_len = V_SYNC_WIDTH; 369+ if (HSYNC_POSITIVE) 370+ mode->sync |= FB_SYNC_HOR_HIGH_ACT; 371+ if (VSYNC_POSITIVE) 372+ mode->sync |= FB_SYNC_VERT_HIGH_ACT; 373+ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * 374+ (V_ACTIVE + V_BLANKING)); 375+ if (INTERLACED) { 376+ mode->yres *= 2; 377+ mode->upper_margin *= 2; 378+ mode->lower_margin *= 2; 379+ mode->vsync_len *= 2; 380+ mode->vmode |= FB_VMODE_INTERLACED; 381+ } 382+ mode->flag = FB_MODE_IS_DETAILED; 383+ 384+ if ((H_SIZE / 16) == (V_SIZE / 9)) 385+ mode->vmode |= FB_VMODE_ASPECT_16_9; 386+ else if ((H_SIZE / 4) == (V_SIZE / 3)) 387+ mode->vmode |= FB_VMODE_ASPECT_4_3; 388+ else if ((mode->xres / 16) == (mode->yres / 9)) 389+ mode->vmode |= FB_VMODE_ASPECT_16_9; 390+ else if ((mode->xres / 4) == (mode->yres / 3)) 391+ mode->vmode |= FB_VMODE_ASPECT_4_3; 392+ 393+ if (mode->vmode & FB_VMODE_ASPECT_16_9) 394+ DPRINTK("Aspect ratio: 16:9\n"); 395+ if (mode->vmode & FB_VMODE_ASPECT_4_3) 396+ DPRINTK("Aspect ratio: 4:3\n"); 397+ DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); 398+ DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, 399+ H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); 400+ DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, 401+ V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); 402+ DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", 403+ (VSYNC_POSITIVE) ? "+" : "-"); 404+} 405+ 406+int mxc_edid_parse_ext_blk(unsigned char *edid, 407+ struct mxc_edid_cfg *cfg, 408+ struct fb_monspecs *specs) 409+{ 410+ char detail_timing_desc_offset; 411+ struct fb_videomode *mode, *m; 412+ unsigned char index = 0x0; 413+ unsigned char *block; 414+ int i, num = 0, revision; 415+ 416+ if (edid[index++] != 0x2) /* only support cea ext block now */ 417+ return 0; 418+ revision = edid[index++]; 419+ DPRINTK("cea extent revision %d\n", revision); 420+ mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); 421+ if (mode == NULL) 422+ return -1; 423+ 424+ detail_timing_desc_offset = edid[index++]; 425+ 426+ if (revision >= 2) { 427+ cfg->cea_underscan = (edid[index] >> 7) & 0x1; 428+ cfg->cea_basicaudio = (edid[index] >> 6) & 0x1; 429+ cfg->cea_ycbcr444 = (edid[index] >> 5) & 0x1; 430+ cfg->cea_ycbcr422 = (edid[index] >> 4) & 0x1; 431+ 432+ DPRINTK("CEA underscan %d\n", cfg->cea_underscan); 433+ DPRINTK("CEA basicaudio %d\n", cfg->cea_basicaudio); 434+ DPRINTK("CEA ycbcr444 %d\n", cfg->cea_ycbcr444); 435+ DPRINTK("CEA ycbcr422 %d\n", cfg->cea_ycbcr422); 436+ } 437+ 438+ if (revision >= 3) { 439+ /* short desc */ 440+ DPRINTK("CEA Short desc timmings\n"); 441+ index++; 442+ while (index < detail_timing_desc_offset) { 443+ unsigned char tagcode, blklen; 444+ 445+ tagcode = (edid[index] >> 5) & 0x7; 446+ blklen = (edid[index]) & 0x1f; 447+ 448+ DPRINTK("Tagcode %x Len %d\n", tagcode, blklen); 449+ 450+ switch (tagcode) { 451+ case 0x2: /*Video data block*/ 452+ { 453+ int cea_idx; 454+ i = 0; 455+ while (i < blklen) { 456+ index++; 457+ cea_idx = edid[index] & 0x7f; 458+ if (cea_idx < ARRAY_SIZE(mxc_cea_mode) && 459+ (mxc_cea_mode[cea_idx].xres)) { 460+ DPRINTK("Support CEA Format #%d\n", cea_idx); 461+ mode[num] = mxc_cea_mode[cea_idx]; 462+ mode[num].flag |= FB_MODE_IS_STANDARD; 463+ num++; 464+ } 465+ i++; 466+ } 467+ break; 468+ } 469+ case 0x3: /*Vendor specific data*/ 470+ { 471+ unsigned char IEEE_reg_iden[3]; 472+ unsigned char deep_color; 473+ unsigned char latency_present; 474+ unsigned char I_latency_present; 475+ unsigned char hdmi_video_present; 476+ unsigned char hdmi_3d_present; 477+ unsigned char hdmi_3d_multi_present; 478+ unsigned char hdmi_vic_len; 479+ unsigned char hdmi_3d_len; 480+ unsigned char index_inc = 0; 481+ unsigned char vsd_end; 482+ 483+ vsd_end = index + blklen; 484+ 485+ IEEE_reg_iden[0] = edid[index+1]; 486+ IEEE_reg_iden[1] = edid[index+2]; 487+ IEEE_reg_iden[2] = edid[index+3]; 488+ cfg->physical_address[0] = (edid[index+4] & 0xf0) >> 4; 489+ cfg->physical_address[1] = (edid[index+4] & 0x0f); 490+ cfg->physical_address[2] = (edid[index+5] & 0xf0) >> 4; 491+ cfg->physical_address[3] = (edid[index+5] & 0x0f); 492+ 493+ if ((IEEE_reg_iden[0] == 0x03) && 494+ (IEEE_reg_iden[1] == 0x0c) && 495+ (IEEE_reg_iden[2] == 0x00)) 496+ cfg->hdmi_cap = 1; 497+ 498+ if (blklen > 5) { 499+ deep_color = edid[index+6]; 500+ if (deep_color & 0x80) 501+ cfg->vsd_support_ai = true; 502+ if (deep_color & 0x40) 503+ cfg->vsd_dc_48bit = true; 504+ if (deep_color & 0x20) 505+ cfg->vsd_dc_36bit = true; 506+ if (deep_color & 0x10) 507+ cfg->vsd_dc_30bit = true; 508+ if (deep_color & 0x08) 509+ cfg->vsd_dc_y444 = true; 510+ if (deep_color & 0x01) 511+ cfg->vsd_dvi_dual = true; 512+ } 513+ 514+ DPRINTK("VSD hdmi capability %d\n", cfg->hdmi_cap); 515+ DPRINTK("VSD support ai %d\n", cfg->vsd_support_ai); 516+ DPRINTK("VSD support deep color 48bit %d\n", cfg->vsd_dc_48bit); 517+ DPRINTK("VSD support deep color 36bit %d\n", cfg->vsd_dc_36bit); 518+ DPRINTK("VSD support deep color 30bit %d\n", cfg->vsd_dc_30bit); 519+ DPRINTK("VSD support deep color y444 %d\n", cfg->vsd_dc_y444); 520+ DPRINTK("VSD support dvi dual %d\n", cfg->vsd_dvi_dual); 521+ 522+ if (blklen > 6) 523+ cfg->vsd_max_tmdsclk_rate = edid[index+7] * 5; 524+ DPRINTK("VSD MAX TMDS CLOCK RATE %d\n", cfg->vsd_max_tmdsclk_rate); 525+ 526+ if (blklen > 7) { 527+ latency_present = edid[index+8] >> 7; 528+ I_latency_present = (edid[index+8] & 0x40) >> 6; 529+ hdmi_video_present = (edid[index+8] & 0x20) >> 5; 530+ cfg->vsd_cnc3 = (edid[index+8] & 0x8) >> 3; 531+ cfg->vsd_cnc2 = (edid[index+8] & 0x4) >> 2; 532+ cfg->vsd_cnc1 = (edid[index+8] & 0x2) >> 1; 533+ cfg->vsd_cnc0 = edid[index+8] & 0x1; 534+ 535+ DPRINTK("VSD cnc0 %d\n", cfg->vsd_cnc0); 536+ DPRINTK("VSD cnc1 %d\n", cfg->vsd_cnc1); 537+ DPRINTK("VSD cnc2 %d\n", cfg->vsd_cnc2); 538+ DPRINTK("VSD cnc3 %d\n", cfg->vsd_cnc3); 539+ DPRINTK("latency_present %d\n", latency_present); 540+ DPRINTK("I_latency_present %d\n", I_latency_present); 541+ DPRINTK("hdmi_video_present %d\n", hdmi_video_present); 542+ 543+ } else { 544+ index += blklen; 545+ break; 546+ } 547+ 548+ index += 9; 549+ 550+ /*latency present */ 551+ if (latency_present) { 552+ cfg->vsd_video_latency = edid[index++]; 553+ cfg->vsd_audio_latency = edid[index++]; 554+ 555+ if (I_latency_present) { 556+ cfg->vsd_I_video_latency = edid[index++]; 557+ cfg->vsd_I_audio_latency = edid[index++]; 558+ } else { 559+ cfg->vsd_I_video_latency = cfg->vsd_video_latency; 560+ cfg->vsd_I_audio_latency = cfg->vsd_audio_latency; 561+ } 562+ 563+ DPRINTK("VSD latency video_latency %d\n", cfg->vsd_video_latency); 564+ DPRINTK("VSD latency audio_latency %d\n", cfg->vsd_audio_latency); 565+ DPRINTK("VSD latency I_video_latency %d\n", cfg->vsd_I_video_latency); 566+ DPRINTK("VSD latency I_audio_latency %d\n", cfg->vsd_I_audio_latency); 567+ } 568+ 569+ if (hdmi_video_present) { 570+ hdmi_3d_present = edid[index] >> 7; 571+ hdmi_3d_multi_present = (edid[index] & 0x60) >> 5; 572+ index++; 573+ hdmi_vic_len = (edid[index] & 0xe0) >> 5; 574+ hdmi_3d_len = edid[index] & 0x1f; 575+ index++; 576+ 577+ DPRINTK("hdmi_3d_present %d\n", hdmi_3d_present); 578+ DPRINTK("hdmi_3d_multi_present %d\n", hdmi_3d_multi_present); 579+ DPRINTK("hdmi_vic_len %d\n", hdmi_vic_len); 580+ DPRINTK("hdmi_3d_len %d\n", hdmi_3d_len); 581+ 582+ if (hdmi_vic_len > 0) { 583+ for (i = 0; i < hdmi_vic_len; i++) { 584+ cfg->hdmi_vic[i] = edid[index++]; 585+ DPRINTK("HDMI_vic=%d\n", cfg->hdmi_vic[i]); 586+ } 587+ } 588+ 589+ if (hdmi_3d_len > 0) { 590+ if (hdmi_3d_present) { 591+ if (hdmi_3d_multi_present == 0x1) { 592+ cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1]; 593+ index_inc = 2; 594+ } else if (hdmi_3d_multi_present == 0x2) { 595+ cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1]; 596+ cfg->hdmi_3d_mask_all = (edid[index+2] << 8) | edid[index+3]; 597+ index_inc = 4; 598+ } else 599+ index_inc = 0; 600+ } 601+ 602+ DPRINTK("HDMI 3d struct all =0x%x\n", cfg->hdmi_3d_struct_all); 603+ DPRINTK("HDMI 3d mask all =0x%x\n", cfg->hdmi_3d_mask_all); 604+ 605+ /* Read 2D vic 3D_struct */ 606+ if ((hdmi_3d_len - index_inc) > 0) { 607+ DPRINTK("Support 3D video format\n"); 608+ i = 0; 609+ while ((hdmi_3d_len - index_inc) > 0) { 610+ 611+ cfg->hdmi_3d_format[i].vic_order_2d = edid[index+index_inc] >> 4; 612+ cfg->hdmi_3d_format[i].struct_3d = edid[index+index_inc] & 0x0f; 613+ index_inc++; 614+ 615+ if (cfg->hdmi_3d_format[i].struct_3d == 8) { 616+ cfg->hdmi_3d_format[i].detail_3d = edid[index+index_inc] >> 4; 617+ index_inc++; 618+ } else if (cfg->hdmi_3d_format[i].struct_3d > 8) { 619+ cfg->hdmi_3d_format[i].detail_3d = 0; 620+ index_inc++; 621+ } 622+ 623+ DPRINTK("vic_order_2d=%d, 3d_struct=%d, 3d_detail=0x%x\n", 624+ cfg->hdmi_3d_format[i].vic_order_2d, 625+ cfg->hdmi_3d_format[i].struct_3d, 626+ cfg->hdmi_3d_format[i].detail_3d); 627+ i++; 628+ } 629+ } 630+ } 631+ } 632+ 633+ index = vsd_end; 634+ 635+ break; 636+ } 637+ case 0x1: /*Audio data block*/ 638+ { 639+ u8 audio_format, max_ch, byte1, byte2, byte3; 640+ 641+ i = 0; 642+ cfg->max_channels = 0; 643+ cfg->sample_rates = 0; 644+ cfg->sample_sizes = 0; 645+ 646+ while (i < blklen) { 647+ byte1 = edid[index + 1]; 648+ byte2 = edid[index + 2]; 649+ byte3 = edid[index + 3]; 650+ index += 3; 651+ i += 3; 652+ 653+ audio_format = byte1 >> 3; 654+ max_ch = (byte1 & 0x07) + 1; 655+ 656+ DPRINTK("Audio Format Descriptor : %2d\n", audio_format); 657+ DPRINTK("Max Number of Channels : %2d\n", max_ch); 658+ DPRINTK("Sample Rates : %02x\n", byte2); 659+ 660+ /* ALSA can't specify specific compressed 661+ * formats, so only care about PCM for now. */ 662+ if (audio_format == AUDIO_CODING_TYPE_LPCM) { 663+ if (max_ch > cfg->max_channels) 664+ cfg->max_channels = max_ch; 665+ 666+ cfg->sample_rates |= byte2; 667+ cfg->sample_sizes |= byte3 & 0x7; 668+ DPRINTK("Sample Sizes : %02x\n", 669+ byte3 & 0x7); 670+ } 671+ } 672+ break; 673+ } 674+ case 0x4: /*Speaker allocation block*/ 675+ { 676+ i = 0; 677+ while (i < blklen) { 678+ cfg->speaker_alloc = edid[index + 1]; 679+ index += 3; 680+ i += 3; 681+ DPRINTK("Speaker Alloc : %02x\n", cfg->speaker_alloc); 682+ } 683+ break; 684+ } 685+ case 0x7: /*User extended block*/ 686+ default: 687+ /* skip */ 688+ DPRINTK("Not handle block, tagcode = 0x%x\n", tagcode); 689+ index += blklen; 690+ break; 691+ } 692+ 693+ index++; 694+ } 695+ } 696+ 697+ /* long desc */ 698+ DPRINTK("CEA long desc timmings\n"); 699+ index = detail_timing_desc_offset; 700+ block = edid + index; 701+ while (index < (EDID_LENGTH - DETAILED_TIMING_DESCRIPTION_SIZE)) { 702+ if (!(block[0] == 0x00 && block[1] == 0x00)) { 703+ get_detailed_timing(block, &mode[num]); 704+ num++; 705+ } 706+ block += DETAILED_TIMING_DESCRIPTION_SIZE; 707+ index += DETAILED_TIMING_DESCRIPTION_SIZE; 708+ } 709+ 710+ if (!num) { 711+ kfree(mode); 712+ return 0; 713+ } 714+ 715+ m = kmalloc((num + specs->modedb_len) * 716+ sizeof(struct fb_videomode), GFP_KERNEL); 717+ if (!m) { 718+ kfree(mode); 719+ return 0; 720+ } 721+ 722+ if (specs->modedb_len) { 723+ memmove(m, specs->modedb, 724+ specs->modedb_len * sizeof(struct fb_videomode)); 725+ kfree(specs->modedb); 726+ } 727+ memmove(m+specs->modedb_len, mode, 728+ num * sizeof(struct fb_videomode)); 729+ kfree(mode); 730+ 731+ specs->modedb_len += num; 732+ specs->modedb = m; 733+ 734+ return 0; 735+} 736+EXPORT_SYMBOL(mxc_edid_parse_ext_blk); 737+ 738+static int mxc_edid_readblk(struct i2c_adapter *adp, 739+ unsigned short addr, unsigned char *edid) 740+{ 741+ int ret = 0, extblknum = 0; 742+ unsigned char regaddr = 0x0; 743+ struct i2c_msg msg[2] = { 744+ { 745+ .addr = addr, 746+ .flags = 0, 747+ .len = 1, 748+ .buf = ®addr, 749+ }, { 750+ .addr = addr, 751+ .flags = I2C_M_RD, 752+ .len = EDID_LENGTH, 753+ .buf = edid, 754+ }, 755+ }; 756+ 757+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg)); 758+ if (ret != ARRAY_SIZE(msg)) { 759+ DPRINTK("unable to read EDID block\n"); 760+ return -EIO; 761+ } 762+ 763+ if (edid[1] == 0x00) 764+ return -ENOENT; 765+ 766+ extblknum = edid[0x7E]; 767+ 768+ if (extblknum) { 769+ regaddr = 128; 770+ msg[1].buf = edid + EDID_LENGTH; 771+ 772+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg)); 773+ if (ret != ARRAY_SIZE(msg)) { 774+ DPRINTK("unable to read EDID ext block\n"); 775+ return -EIO; 776+ } 777+ } 778+ 779+ return extblknum; 780+} 781+ 782+static int mxc_edid_readsegblk(struct i2c_adapter *adp, unsigned short addr, 783+ unsigned char *edid, int seg_num) 784+{ 785+ int ret = 0; 786+ unsigned char segment = 0x1, regaddr = 0; 787+ struct i2c_msg msg[3] = { 788+ { 789+ .addr = 0x30, 790+ .flags = 0, 791+ .len = 1, 792+ .buf = &segment, 793+ }, { 794+ .addr = addr, 795+ .flags = 0, 796+ .len = 1, 797+ .buf = ®addr, 798+ }, { 799+ .addr = addr, 800+ .flags = I2C_M_RD, 801+ .len = EDID_LENGTH, 802+ .buf = edid, 803+ }, 804+ }; 805+ 806+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg)); 807+ if (ret != ARRAY_SIZE(msg)) { 808+ DPRINTK("unable to read EDID block\n"); 809+ return -EIO; 810+ } 811+ 812+ if (seg_num == 2) { 813+ regaddr = 128; 814+ msg[2].buf = edid + EDID_LENGTH; 815+ 816+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg)); 817+ if (ret != ARRAY_SIZE(msg)) { 818+ DPRINTK("unable to read EDID block\n"); 819+ return -EIO; 820+ } 821+ } 822+ 823+ return ret; 824+} 825+ 826+int mxc_edid_var_to_vic(struct fb_var_screeninfo *var) 827+{ 828+ int i; 829+ struct fb_videomode m; 830+ 831+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) { 832+ fb_var_to_videomode(&m, var); 833+ if (mxc_edid_fb_mode_is_equal(false, &m, &mxc_cea_mode[i])) 834+ break; 835+ } 836+ 837+ if (i == ARRAY_SIZE(mxc_cea_mode)) 838+ return 0; 839+ 840+ return i; 841+} 842+EXPORT_SYMBOL(mxc_edid_var_to_vic); 843+ 844+int mxc_edid_mode_to_vic(const struct fb_videomode *mode) 845+{ 846+ int i; 847+ bool use_aspect = (mode->vmode & FB_VMODE_ASPECT_MASK); 848+ 849+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) { 850+ if (mxc_edid_fb_mode_is_equal(use_aspect, mode, &mxc_cea_mode[i])) 851+ break; 852+ } 853+ 854+ if (i == ARRAY_SIZE(mxc_cea_mode)) 855+ return 0; 856+ 857+ return i; 858+} 859+EXPORT_SYMBOL(mxc_edid_mode_to_vic); 860+ 861+/* make sure edid has 512 bytes*/ 862+int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr, 863+ unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi) 864+{ 865+ int ret = 0, extblknum; 866+ if (!adp || !edid || !cfg || !fbi) 867+ return -EINVAL; 868+ 869+ memset(edid, 0, EDID_LENGTH*4); 870+ memset(cfg, 0, sizeof(struct mxc_edid_cfg)); 871+ 872+ extblknum = mxc_edid_readblk(adp, addr, edid); 873+ if (extblknum < 0) 874+ return extblknum; 875+ 876+ /* edid first block parsing */ 877+ memset(&fbi->monspecs, 0, sizeof(fbi->monspecs)); 878+ fb_edid_to_monspecs(edid, &fbi->monspecs); 879+ 880+ if (extblknum) { 881+ int i; 882+ 883+ /* FIXME: mxc_edid_readsegblk() won't read more than 2 blocks 884+ * and the for-loop will read past the end of the buffer! :-( */ 885+ if (extblknum > 3) { 886+ WARN_ON(true); 887+ return -EINVAL; 888+ } 889+ 890+ /* need read segment block? */ 891+ if (extblknum > 1) { 892+ ret = mxc_edid_readsegblk(adp, addr, 893+ edid + EDID_LENGTH*2, extblknum - 1); 894+ if (ret < 0) 895+ return ret; 896+ } 897+ 898+ for (i = 1; i <= extblknum; i++) 899+ /* edid ext block parsing */ 900+ mxc_edid_parse_ext_blk(edid + i*EDID_LENGTH, 901+ cfg, &fbi->monspecs); 902+ } 903+ 904+ return 0; 905+} 906+EXPORT_SYMBOL(mxc_edid_read); 907+ 908