drm/ast: add widescreen + rb modes from X.org driver (v2)
authorDave Airlie <airlied@redhat.com>
Fri, 17 Jan 2014 00:56:09 +0000 (10:56 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 19 May 2014 01:13:55 +0000 (11:13 +1000)
This syncs up the mode code from the X.org driver upstream,
and adds the mode validation step for hw that doesn't have
widescreen.

v2: (from Egbert Eich <eich@suse.de)
squash drm/ast: Use correct structure member for mode validation
to avoid bisect regression.

In struct drm_display_mode crtc_hdisplay and crtc_vdisplay are holding
the crtc parameters after mode fixup. For validation we need hdisplay and
vdisplay.

Signed-off-by: Egbert Eich <eich@suse.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_tables.h

index 9833a1b1acc140f36f0d248a026e43fee2b1ae33..fab4b173dc49bbfc81c6feae93b53c97a2fe88c8 100644 (file)
@@ -102,6 +102,7 @@ struct ast_private {
         * we have. */
        struct ttm_bo_kmap_obj cache_kmap;
        int next_cursor;
+       bool support_wide_screen;
 };
 
 int ast_driver_load(struct drm_device *dev, unsigned long flags);
index 50535fd5a88d258492b90ca9e9e9cebfaf2de563..cd0a791e76c5ba91141d2e40d224ec3418684102 100644 (file)
@@ -66,6 +66,7 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast,
 static int ast_detect_chip(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
+       uint32_t data, jreg;
 
        if (dev->pdev->device == PCI_CHIP_AST1180) {
                ast->chip = AST1100;
@@ -104,6 +105,33 @@ static int ast_detect_chip(struct drm_device *dev)
                        DRM_INFO("AST 2000 detected\n");
                }
        }
+
+       switch (ast->chip) {
+       case AST1180:
+               ast->support_wide_screen = true;
+               break;
+       case AST2000:
+               ast->support_wide_screen = false;
+               break;
+       default:
+               jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+               if (!(jreg & 0x80))
+                       ast->support_wide_screen = true;
+               else if (jreg & 0x01)
+                       ast->support_wide_screen = true;
+               else {
+                       ast->support_wide_screen = false;
+                       if (ast->chip == AST2300) {
+                               ast_write32(ast, 0xf004, 0x1e6e0000);
+                               ast_write32(ast, 0xf000, 0x1);
+                               data = ast_read32(ast, 0x1207c);
+                               if ((data & 0x300) == 0) /* ast1300 */
+                                       ast->support_wide_screen = true;
+                       }
+               }
+               break;
+       }
+
        return 0;
 }
 
index cca063b110831aa4d4fc2f46afd6e9cc35ac30b9..72bec23b66f40720c89baf7025bd388c268893c6 100644 (file)
@@ -115,11 +115,17 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
                else
                        vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
                break;
+       case 1360:
+               vbios_mode->enh_table = &res_1360x768[refresh_rate_index];
+               break;
        case 1440:
                vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
                break;
        case 1600:
-               vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
+               if (crtc->mode.crtc_vdisplay == 900)
+                       vbios_mode->enh_table = &res_1600x900[refresh_rate_index];
+               else
+                       vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
                break;
        case 1680:
                vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
@@ -175,14 +181,17 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff);
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
 
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00);
+               if (vbios_mode->enh_table->flags & NewModeInfo) {
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
 
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
+                       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
+               }
        }
 
        return true;
@@ -746,7 +755,56 @@ static int ast_get_modes(struct drm_connector *connector)
 static int ast_mode_valid(struct drm_connector *connector,
                          struct drm_display_mode *mode)
 {
-       return MODE_OK;
+       struct ast_private *ast = connector->dev->dev_private;
+       int flags = MODE_NOMODE;
+       uint32_t jtemp;
+
+       if (ast->support_wide_screen) {
+               if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050))
+                       return MODE_OK;
+               if ((mode->hdisplay == 1280) && (mode->vdisplay == 800))
+                       return MODE_OK;
+               if ((mode->hdisplay == 1440) && (mode->vdisplay == 900))
+                       return MODE_OK;
+               if ((mode->hdisplay == 1360) && (mode->vdisplay == 768))
+                       return MODE_OK;
+               if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
+                       return MODE_OK;
+
+               if ((ast->chip == AST2100) || (ast->chip == AST2200) || (ast->chip == AST2300) || (ast->chip == AST1180)) {
+                       if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
+                               return MODE_OK;
+
+                       if ((mode->hdisplay == 1920) && (mode->vdisplay == 1200)) {
+                               jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
+                               if (jtemp & 0x01)
+                                       return MODE_NOMODE;
+                               else
+                                       return MODE_OK;
+                       }
+               }
+       }
+       switch (mode->hdisplay) {
+       case 640:
+               if (mode->vdisplay == 480) flags = MODE_OK;
+               break;
+       case 800:
+               if (mode->vdisplay == 600) flags = MODE_OK;
+               break;
+       case 1024:
+               if (mode->vdisplay == 768) flags = MODE_OK;
+               break;
+       case 1280:
+               if (mode->vdisplay == 1024) flags = MODE_OK;
+               break;
+       case 1600:
+               if (mode->vdisplay == 1200) flags = MODE_OK;
+               break;
+       default:
+               return flags;
+       }
+
+       return flags;
 }
 
 static void ast_connector_destroy(struct drm_connector *connector)
index 95fa6aba26bc14bb3e8a27956cf8b39ea942b514..4c761dcea97217e9495ed16a6403250ac04a7ff3 100644 (file)
@@ -42,7 +42,7 @@
 #define HBorder                 0x00000020
 #define VBorder                 0x00000010
 #define WideScreenMode         0x00000100
-
+#define NewModeInfo            0x00000200
 
 /* DCLK Index */
 #define VCLK25_175                     0x00
 #define VCLK106_5              0x12
 #define VCLK146_25             0x13
 #define VCLK148_5              0x14
+#define VCLK71                 0x15
+#define VCLK88_75              0x16
+#define VCLK119                0x17
+#define VCLK85_5               0x18
+#define VCLK97_75              0x19
 
 static struct ast_vbios_dclk_info dclk_table[] = {
        {0x2C, 0xE7, 0x03},                                     /* 00: VCLK25_175       */
@@ -90,6 +95,10 @@ static struct ast_vbios_dclk_info dclk_table[] = {
        {0x28, 0x49, 0x80},                                     /* 12: VCLK106.5        */
        {0x37, 0x49, 0x80},                                     /* 13: VCLK146.25       */
        {0x1f, 0x45, 0x80},                                     /* 14: VCLK148.5        */
+       {0x47, 0x6c, 0x80},                                     /* 15: VCLK71       */
+       {0x25, 0x65, 0x80},                                     /* 16: VCLK88.75    */
+       {0x77, 0x58, 0x80},                                     /* 17: VCLK119      */
+       {0x32, 0x67, 0x80},                                 /* 18: VCLK85_5     */
 };
 
 static struct ast_vbios_stdtable vbios_stdtable[] = {
@@ -225,41 +234,63 @@ static struct ast_vbios_enhtable res_1600x1200[] = {
         (SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
 };
 
-static struct ast_vbios_enhtable res_1920x1200[] = {
-       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
-        (SyncNP | Charx8Dot), 60, 1, 0x34 },
-       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
-        (SyncNP | Charx8Dot), 0xFF, 1, 0x34 },
+/* 16:9 */
+static struct ast_vbios_enhtable res_1360x768[] = {
+       {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* 60Hz */
+        (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x39 },
+       {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* end */
+        (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x39 },
+};
+
+static struct ast_vbios_enhtable res_1600x900[] = {
+       {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* 60Hz CVT RB */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x3A },
+       {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* end */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x3A }
 };
 
+static struct ast_vbios_enhtable res_1920x1080[] = {
+       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x38 },
+       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x38 },
+};
+
+
 /* 16:10 */
 static struct ast_vbios_enhtable res_1280x800[] = {
+       {1440, 1280, 48, 32,  823,  800, 3, 6, VCLK71,  /* 60Hz RB */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 35 },
        {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x35 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x35 },
        {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x35 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x35 },
 
 };
 
 static struct ast_vbios_enhtable res_1440x900[] = {
+       {1600, 1440, 48, 32,  926,  900, 3, 6, VCLK88_75,       /* 60Hz RB */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
        {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x36 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
        {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x36 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x36 },
 };
 
 static struct ast_vbios_enhtable res_1680x1050[] = {
+       {1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
        {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x37 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
        {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x37 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x37 },
 };
 
-/* HDTV */
-static struct ast_vbios_enhtable res_1920x1080[] = {
-       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
-        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x38 },
-       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
-        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x38 },
+static struct ast_vbios_enhtable res_1920x1200[] = {
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x34 },
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x34 },
 };
+
 #endif