]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/gpu/drm/radeon/atombios_crtc.c
drm/radeon/kms: enable underscan option for digital connectors
[net-next-2.6.git] / drivers / gpu / drm / radeon / atombios_crtc.c
index 8c2d6478a2213d82637a4270b4215a676481896b..12ad512bd3d33ad316655400212626585126c6de 100644 (file)
@@ -44,10 +44,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
 
        memset(&args, 0, sizeof(args));
 
-       args.usOverscanRight = 0;
-       args.usOverscanLeft = 0;
-       args.usOverscanBottom = 0;
-       args.usOverscanTop = 0;
        args.ucCRTC = radeon_crtc->crtc_id;
 
        switch (radeon_crtc->rmx_type) {
@@ -56,7 +52,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
                args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
                args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
                args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
-               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
                break;
        case RMX_ASPECT:
                a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
@@ -69,17 +64,16 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
                        args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
                        args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
                }
-               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
                break;
        case RMX_FULL:
        default:
-               args.usOverscanRight = 0;
-               args.usOverscanLeft = 0;
-               args.usOverscanBottom = 0;
-               args.usOverscanTop = 0;
-               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+               args.usOverscanRight = radeon_crtc->h_border;
+               args.usOverscanLeft = radeon_crtc->h_border;
+               args.usOverscanBottom = radeon_crtc->v_border;
+               args.usOverscanTop = radeon_crtc->v_border;
                break;
        }
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
 static void atombios_scaler_setup(struct drm_crtc *crtc)
@@ -282,22 +276,22 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
        u16 misc = 0;
 
        memset(&args, 0, sizeof(args));
-       args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
+       args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
        args.usH_Blanking_Time =
-               cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
-       args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
+               cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
+       args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
        args.usV_Blanking_Time =
-           cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
+               cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
        args.usH_SyncOffset =
-               cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
+               cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
        args.usH_SyncWidth =
                cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
        args.usV_SyncOffset =
-               cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
+               cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
        args.usV_SyncWidth =
                cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
-       /*args.ucH_Border = mode->hborder;*/
-       /*args.ucV_Border = mode->vborder;*/
+       args.ucH_Border = radeon_crtc->h_border;
+       args.ucV_Border = radeon_crtc->v_border;
 
        if (mode->flags & DRM_MODE_FLAG_NVSYNC)
                misc |= ATOM_VSYNC_POLARITY;
@@ -669,56 +663,25 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+static void atombios_crtc_program_pll(struct drm_crtc *crtc,
+                                     int crtc_id,
+                                     int pll_id,
+                                     u32 encoder_mode,
+                                     u32 encoder_id,
+                                     u32 clock,
+                                     u32 ref_div,
+                                     u32 fb_div,
+                                     u32 frac_fb_div,
+                                     u32 post_div)
 {
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
-       struct drm_encoder *encoder = NULL;
-       struct radeon_encoder *radeon_encoder = NULL;
        u8 frev, crev;
-       int index;
+       int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
        union set_pixel_clock args;
-       u32 pll_clock = mode->clock;
-       u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
-       struct radeon_pll *pll;
-       u32 adjusted_clock;
-       int encoder_mode = 0;
 
        memset(&args, 0, sizeof(args));
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               if (encoder->crtc == crtc) {
-                       radeon_encoder = to_radeon_encoder(encoder);
-                       encoder_mode = atombios_get_encoder_mode(encoder);
-                       break;
-               }
-       }
-
-       if (!radeon_encoder)
-               return;
-
-       switch (radeon_crtc->pll_id) {
-       case ATOM_PPLL1:
-               pll = &rdev->clock.p1pll;
-               break;
-       case ATOM_PPLL2:
-               pll = &rdev->clock.p2pll;
-               break;
-       case ATOM_DCPLL:
-       case ATOM_PPLL_INVALID:
-       default:
-               pll = &rdev->clock.dcpll;
-               break;
-       }
-
-       /* adjust pixel clock as needed */
-       adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
-
-       radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
-                          &ref_div, &post_div);
-
-       index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
                                   &crev))
                return;
@@ -727,47 +690,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        case 1:
                switch (crev) {
                case 1:
-                       args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
+                       if (clock == ATOM_DISABLE)
+                               return;
+                       args.v1.usPixelClock = cpu_to_le16(clock / 10);
                        args.v1.usRefDiv = cpu_to_le16(ref_div);
                        args.v1.usFbDiv = cpu_to_le16(fb_div);
                        args.v1.ucFracFbDiv = frac_fb_div;
                        args.v1.ucPostDiv = post_div;
-                       args.v1.ucPpll = radeon_crtc->pll_id;
-                       args.v1.ucCRTC = radeon_crtc->crtc_id;
+                       args.v1.ucPpll = pll_id;
+                       args.v1.ucCRTC = crtc_id;
                        args.v1.ucRefDivSrc = 1;
                        break;
                case 2:
-                       args.v2.usPixelClock = cpu_to_le16(mode->clock / 10);
+                       args.v2.usPixelClock = cpu_to_le16(clock / 10);
                        args.v2.usRefDiv = cpu_to_le16(ref_div);
                        args.v2.usFbDiv = cpu_to_le16(fb_div);
                        args.v2.ucFracFbDiv = frac_fb_div;
                        args.v2.ucPostDiv = post_div;
-                       args.v2.ucPpll = radeon_crtc->pll_id;
-                       args.v2.ucCRTC = radeon_crtc->crtc_id;
+                       args.v2.ucPpll = pll_id;
+                       args.v2.ucCRTC = crtc_id;
                        args.v2.ucRefDivSrc = 1;
                        break;
                case 3:
-                       args.v3.usPixelClock = cpu_to_le16(mode->clock / 10);
+                       args.v3.usPixelClock = cpu_to_le16(clock / 10);
                        args.v3.usRefDiv = cpu_to_le16(ref_div);
                        args.v3.usFbDiv = cpu_to_le16(fb_div);
                        args.v3.ucFracFbDiv = frac_fb_div;
                        args.v3.ucPostDiv = post_div;
-                       args.v3.ucPpll = radeon_crtc->pll_id;
-                       args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2);
-                       args.v3.ucTransmitterId = radeon_encoder->encoder_id;
+                       args.v3.ucPpll = pll_id;
+                       args.v3.ucMiscInfo = (pll_id << 2);
+                       args.v3.ucTransmitterId = encoder_id;
                        args.v3.ucEncoderMode = encoder_mode;
                        break;
                case 5:
-                       args.v5.ucCRTC = radeon_crtc->crtc_id;
-                       args.v5.usPixelClock = cpu_to_le16(mode->clock / 10);
+                       args.v5.ucCRTC = crtc_id;
+                       args.v5.usPixelClock = cpu_to_le16(clock / 10);
                        args.v5.ucRefDiv = ref_div;
                        args.v5.usFbDiv = cpu_to_le16(fb_div);
                        args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
                        args.v5.ucPostDiv = post_div;
                        args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
-                       args.v5.ucTransmitterID = radeon_encoder->encoder_id;
+                       args.v5.ucTransmitterID = encoder_id;
                        args.v5.ucEncoderMode = encoder_mode;
-                       args.v5.ucPpll = radeon_crtc->pll_id;
+                       args.v5.ucPpll = pll_id;
                        break;
                default:
                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
@@ -782,6 +747,56 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_encoder *encoder = NULL;
+       struct radeon_encoder *radeon_encoder = NULL;
+       u32 pll_clock = mode->clock;
+       u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
+       struct radeon_pll *pll;
+       u32 adjusted_clock;
+       int encoder_mode = 0;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc == crtc) {
+                       radeon_encoder = to_radeon_encoder(encoder);
+                       encoder_mode = atombios_get_encoder_mode(encoder);
+                       break;
+               }
+       }
+
+       if (!radeon_encoder)
+               return;
+
+       switch (radeon_crtc->pll_id) {
+       case ATOM_PPLL1:
+               pll = &rdev->clock.p1pll;
+               break;
+       case ATOM_PPLL2:
+               pll = &rdev->clock.p2pll;
+               break;
+       case ATOM_DCPLL:
+       case ATOM_PPLL_INVALID:
+       default:
+               pll = &rdev->clock.dcpll;
+               break;
+       }
+
+       /* adjust pixel clock as needed */
+       adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+
+       radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                          &ref_div, &post_div);
+
+       atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
+                                 encoder_mode, radeon_encoder->encoder_id, mode->clock,
+                                 ref_div, fb_div, frac_fb_div, post_div);
+
+}
+
 static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                                   struct drm_framebuffer *old_fb)
 {
@@ -797,7 +812,7 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 
        /* no fb bound */
        if (!crtc->fb) {
-               DRM_DEBUG("No FB bound\n");
+               DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
 
@@ -841,6 +856,11 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                return -EINVAL;
        }
 
+       if (tiling_flags & RADEON_TILING_MACRO)
+               fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
+       else if (tiling_flags & RADEON_TILING_MICRO)
+               fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
+
        switch (radeon_crtc->crtc_id) {
        case 0:
                WREG32(AVIVO_D1VGA_CONTROL, 0);
@@ -931,7 +951,7 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 
        /* no fb bound */
        if (!crtc->fb) {
-               DRM_DEBUG("No FB bound\n");
+               DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
 
@@ -979,11 +999,18 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
                return -EINVAL;
        }
 
-       if (tiling_flags & RADEON_TILING_MACRO)
-               fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
+       if (rdev->family >= CHIP_R600) {
+               if (tiling_flags & RADEON_TILING_MACRO)
+                       fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1;
+               else if (tiling_flags & RADEON_TILING_MICRO)
+                       fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
+       } else {
+               if (tiling_flags & RADEON_TILING_MACRO)
+                       fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
 
-       if (tiling_flags & RADEON_TILING_MICRO)
-               fb_format |= AVIVO_D1GRPH_TILED;
+               if (tiling_flags & RADEON_TILING_MICRO)
+                       fb_format |= AVIVO_D1GRPH_TILED;
+       }
 
        if (radeon_crtc->crtc_id == 0)
                WREG32(AVIVO_D1VGA_CONTROL, 0);
@@ -1143,10 +1170,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
        atombios_crtc_set_pll(crtc, adjusted_mode);
        atombios_enable_ss(crtc);
 
-       if (ASIC_IS_DCE4(rdev))
+       if (ASIC_IS_AVIVO(rdev))
                atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
-       else if (ASIC_IS_AVIVO(rdev))
-               atombios_crtc_set_timing(crtc, adjusted_mode);
        else {
                atombios_crtc_set_timing(crtc, adjusted_mode);
                if (radeon_crtc->crtc_id == 0)
@@ -1191,6 +1216,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
        atombios_lock_crtc(crtc, ATOM_DISABLE);
 }
 
+static void atombios_crtc_disable(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+       switch (radeon_crtc->pll_id) {
+       case ATOM_PPLL1:
+       case ATOM_PPLL2:
+               /* disable the ppll */
+               atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
+                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0);
+               break;
+       default:
+               break;
+       }
+       radeon_crtc->pll_id = -1;
+}
+
 static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
        .dpms = atombios_crtc_dpms,
        .mode_fixup = atombios_crtc_mode_fixup,
@@ -1199,6 +1242,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
        .prepare = atombios_crtc_prepare,
        .commit = atombios_crtc_commit,
        .load_lut = radeon_crtc_load_lut,
+       .disable = atombios_crtc_disable,
 };
 
 void radeon_atombios_init_crtc(struct drm_device *dev,