/drivers/video/drm/radeon/atombios_crtc.c |
---|
0,0 → 1,697 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include <drmP.h> |
#include <drm_crtc_helper.h> |
#include "radeon_drm.h" |
#include "radeon_fixed.h" |
#include "radeon.h" |
#include "atom.h" |
#include "atom-bits.h" |
static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int index = |
GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); |
ENABLE_CRTC_PS_ALLOCATION args; |
memset(&args, 0, sizeof(args)); |
args.ucCRTC = radeon_crtc->crtc_id; |
args.ucEnable = lock; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
static void atombios_enable_crtc(struct drm_crtc *crtc, int state) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); |
ENABLE_CRTC_PS_ALLOCATION args; |
memset(&args, 0, sizeof(args)); |
args.ucCRTC = radeon_crtc->crtc_id; |
args.ucEnable = state; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); |
ENABLE_CRTC_PS_ALLOCATION args; |
memset(&args, 0, sizeof(args)); |
args.ucCRTC = radeon_crtc->crtc_id; |
args.ucEnable = state; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
static void atombios_blank_crtc(struct drm_crtc *crtc, int state) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); |
BLANK_CRTC_PS_ALLOCATION args; |
memset(&args, 0, sizeof(args)); |
args.ucCRTC = radeon_crtc->crtc_id; |
args.ucBlanking = state; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
if (ASIC_IS_DCE3(rdev)) |
atombios_enable_crtc_memreq(crtc, 1); |
atombios_enable_crtc(crtc, 1); |
atombios_blank_crtc(crtc, 0); |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
atombios_blank_crtc(crtc, 1); |
atombios_enable_crtc(crtc, 0); |
if (ASIC_IS_DCE3(rdev)) |
atombios_enable_crtc_memreq(crtc, 0); |
break; |
} |
if (mode != DRM_MODE_DPMS_OFF) { |
radeon_crtc_load_lut(crtc); |
} |
} |
static void |
atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, |
SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param; |
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); |
conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size); |
conv_param.usH_Blanking_Time = |
cpu_to_le16(crtc_param->usH_Blanking_Time); |
conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size); |
conv_param.usV_Blanking_Time = |
cpu_to_le16(crtc_param->usV_Blanking_Time); |
conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset); |
conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); |
conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset); |
conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); |
conv_param.susModeMiscInfo.usAccess = |
cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); |
conv_param.ucCRTC = crtc_param->ucCRTC; |
printk("executing set crtc dtd timing\n"); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); |
} |
void atombios_crtc_set_timing(struct drm_crtc *crtc, |
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION * |
crtc_param) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param; |
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); |
conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total); |
conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp); |
conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart); |
conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); |
conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total); |
conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp); |
conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart); |
conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); |
conv_param.susModeMiscInfo.usAccess = |
cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); |
conv_param.ucCRTC = crtc_param->ucCRTC; |
conv_param.ucOverscanRight = crtc_param->ucOverscanRight; |
conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft; |
conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom; |
conv_param.ucOverscanTop = crtc_param->ucOverscanTop; |
conv_param.ucReserved = crtc_param->ucReserved; |
printk("executing set crtc timing\n"); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); |
} |
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; |
uint8_t frev, crev; |
int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); |
SET_PIXEL_CLOCK_PS_ALLOCATION args; |
PIXEL_CLOCK_PARAMETERS *spc1_ptr; |
PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; |
PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; |
uint32_t sclock = mode->clock; |
uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; |
struct radeon_pll *pll; |
int pll_flags = 0; |
memset(&args, 0, sizeof(args)); |
if (ASIC_IS_AVIVO(rdev)) { |
uint32_t ss_cntl; |
if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ |
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
else |
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
/* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ |
if (radeon_crtc->crtc_id == 0) { |
ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); |
WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); |
} else { |
ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); |
WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); |
} |
} else { |
pll_flags |= RADEON_PLL_LEGACY; |
if (mode->clock > 200000) /* range limits??? */ |
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
else |
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
} |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc == crtc) { |
if (!ASIC_IS_AVIVO(rdev)) { |
if (encoder->encoder_type != |
DRM_MODE_ENCODER_DAC) |
pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; |
if (!ASIC_IS_AVIVO(rdev) |
&& (encoder->encoder_type == |
DRM_MODE_ENCODER_LVDS)) |
pll_flags |= RADEON_PLL_USE_REF_DIV; |
} |
radeon_encoder = to_radeon_encoder(encoder); |
} |
} |
if (radeon_crtc->crtc_id == 0) |
pll = &rdev->clock.p1pll; |
else |
pll = &rdev->clock.p2pll; |
radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div, |
&ref_div, &post_div, pll_flags); |
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, |
&crev); |
switch (frev) { |
case 1: |
switch (crev) { |
case 1: |
spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; |
spc1_ptr->usPixelClock = cpu_to_le16(sclock); |
spc1_ptr->usRefDiv = cpu_to_le16(ref_div); |
spc1_ptr->usFbDiv = cpu_to_le16(fb_div); |
spc1_ptr->ucFracFbDiv = frac_fb_div; |
spc1_ptr->ucPostDiv = post_div; |
spc1_ptr->ucPpll = |
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; |
spc1_ptr->ucCRTC = radeon_crtc->crtc_id; |
spc1_ptr->ucRefDivSrc = 1; |
break; |
case 2: |
spc2_ptr = |
(PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; |
spc2_ptr->usPixelClock = cpu_to_le16(sclock); |
spc2_ptr->usRefDiv = cpu_to_le16(ref_div); |
spc2_ptr->usFbDiv = cpu_to_le16(fb_div); |
spc2_ptr->ucFracFbDiv = frac_fb_div; |
spc2_ptr->ucPostDiv = post_div; |
spc2_ptr->ucPpll = |
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; |
spc2_ptr->ucCRTC = radeon_crtc->crtc_id; |
spc2_ptr->ucRefDivSrc = 1; |
break; |
case 3: |
if (!encoder) |
return; |
spc3_ptr = |
(PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; |
spc3_ptr->usPixelClock = cpu_to_le16(sclock); |
spc3_ptr->usRefDiv = cpu_to_le16(ref_div); |
spc3_ptr->usFbDiv = cpu_to_le16(fb_div); |
spc3_ptr->ucFracFbDiv = frac_fb_div; |
spc3_ptr->ucPostDiv = post_div; |
spc3_ptr->ucPpll = |
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; |
spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); |
spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id; |
spc3_ptr->ucEncoderMode = |
atombios_get_encoder_mode(encoder); |
break; |
default: |
DRM_ERROR("Unknown table version %d %d\n", frev, crev); |
return; |
} |
break; |
default: |
DRM_ERROR("Unknown table version %d %d\n", frev, crev); |
return; |
} |
printk("executing set pll\n"); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
struct drm_framebuffer *old_fb) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_framebuffer *radeon_fb; |
struct drm_gem_object *obj; |
struct drm_radeon_gem_object *obj_priv; |
uint64_t fb_location; |
uint32_t fb_format, fb_pitch_pixels; |
if (!crtc->fb) |
return -EINVAL; |
radeon_fb = to_radeon_framebuffer(crtc->fb); |
obj = radeon_fb->obj; |
obj_priv = obj->driver_private; |
// if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &fb_location)) { |
// return -EINVAL; |
// } |
switch (crtc->fb->bits_per_pixel) { |
case 15: |
fb_format = |
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | |
AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; |
break; |
case 16: |
fb_format = |
AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | |
AVIVO_D1GRPH_CONTROL_16BPP_RGB565; |
break; |
case 24: |
case 32: |
fb_format = |
AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | |
AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; |
break; |
default: |
DRM_ERROR("Unsupported screen depth %d\n", |
crtc->fb->bits_per_pixel); |
return -EINVAL; |
} |
/* TODO tiling */ |
if (radeon_crtc->crtc_id == 0) |
WREG32(AVIVO_D1VGA_CONTROL, 0); |
else |
WREG32(AVIVO_D2VGA_CONTROL, 0); |
WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, |
(u32) fb_location); |
WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + |
radeon_crtc->crtc_offset, (u32) fb_location); |
WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); |
WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); |
WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); |
fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); |
WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); |
WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); |
WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, |
crtc->mode.vdisplay); |
x &= ~3; |
y &= ~1; |
WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, |
(x << 16) | y); |
WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, |
(crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); |
if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) |
WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, |
AVIVO_D1MODE_INTERLEAVE_EN); |
else |
WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); |
if (old_fb && old_fb != crtc->fb) { |
radeon_fb = to_radeon_framebuffer(old_fb); |
// radeon_gem_object_unpin(radeon_fb->obj); |
} |
return 0; |
} |
int atombios_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, struct drm_framebuffer *old_fb) |
{ |
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; |
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; |
/* TODO color tiling */ |
memset(&crtc_timing, 0, sizeof(crtc_timing)); |
/* TODO tv */ |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
} |
crtc_timing.ucCRTC = radeon_crtc->crtc_id; |
crtc_timing.usH_Total = adjusted_mode->crtc_htotal; |
crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; |
crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; |
crtc_timing.usH_SyncWidth = |
adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; |
crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; |
crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; |
crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; |
crtc_timing.usV_SyncWidth = |
adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; |
if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) |
crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; |
if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) |
crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; |
if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) |
crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; |
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) |
crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; |
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; |
atombios_crtc_set_pll(crtc, adjusted_mode); |
atombios_crtc_set_timing(crtc, &crtc_timing); |
if (ASIC_IS_AVIVO(rdev)) |
atombios_crtc_set_base(crtc, x, y, old_fb); |
else { |
if (radeon_crtc->crtc_id == 0) { |
SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing; |
memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing)); |
/* setup FP shadow regs on R4xx */ |
crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id; |
crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay; |
crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay; |
crtc_dtd_timing.usH_Blanking_Time = |
adjusted_mode->crtc_hblank_end - |
adjusted_mode->crtc_hdisplay; |
crtc_dtd_timing.usV_Blanking_Time = |
adjusted_mode->crtc_vblank_end - |
adjusted_mode->crtc_vdisplay; |
crtc_dtd_timing.usH_SyncOffset = |
adjusted_mode->crtc_hsync_start - |
adjusted_mode->crtc_hdisplay; |
crtc_dtd_timing.usV_SyncOffset = |
adjusted_mode->crtc_vsync_start - |
adjusted_mode->crtc_vdisplay; |
crtc_dtd_timing.usH_SyncWidth = |
adjusted_mode->crtc_hsync_end - |
adjusted_mode->crtc_hsync_start; |
crtc_dtd_timing.usV_SyncWidth = |
adjusted_mode->crtc_vsync_end - |
adjusted_mode->crtc_vsync_start; |
/* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */ |
/* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */ |
if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) |
crtc_dtd_timing.susModeMiscInfo.usAccess |= |
ATOM_VSYNC_POLARITY; |
if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) |
crtc_dtd_timing.susModeMiscInfo.usAccess |= |
ATOM_HSYNC_POLARITY; |
if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) |
crtc_dtd_timing.susModeMiscInfo.usAccess |= |
ATOM_COMPOSITESYNC; |
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) |
crtc_dtd_timing.susModeMiscInfo.usAccess |= |
ATOM_INTERLACE; |
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
crtc_dtd_timing.susModeMiscInfo.usAccess |= |
ATOM_DOUBLE_CLOCK_MODE; |
atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing); |
} |
radeon_crtc_set_base(crtc, x, y, old_fb); |
radeon_legacy_atom_set_surface(crtc); |
} |
return 0; |
} |
static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
return true; |
} |
static void atombios_crtc_prepare(struct drm_crtc *crtc) |
{ |
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
atombios_lock_crtc(crtc, 1); |
} |
static void atombios_crtc_commit(struct drm_crtc *crtc) |
{ |
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); |
atombios_lock_crtc(crtc, 0); |
} |
static const struct drm_crtc_helper_funcs atombios_helper_funcs = { |
.dpms = atombios_crtc_dpms, |
.mode_fixup = atombios_crtc_mode_fixup, |
.mode_set = atombios_crtc_mode_set, |
.mode_set_base = atombios_crtc_set_base, |
.prepare = atombios_crtc_prepare, |
.commit = atombios_crtc_commit, |
}; |
void radeon_atombios_init_crtc(struct drm_device *dev, |
struct radeon_crtc *radeon_crtc) |
{ |
if (radeon_crtc->crtc_id == 1) |
radeon_crtc->crtc_offset = |
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; |
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); |
} |
void radeon_init_disp_bw_avivo(struct drm_device *dev, |
struct drm_display_mode *mode1, |
uint32_t pixel_bytes1, |
struct drm_display_mode *mode2, |
uint32_t pixel_bytes2) |
{ |
struct radeon_device *rdev = dev->dev_private; |
fixed20_12 min_mem_eff; |
fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; |
fixed20_12 sclk_ff, mclk_ff; |
uint32_t dc_lb_memory_split, temp; |
min_mem_eff.full = rfixed_const_8(0); |
if (rdev->disp_priority == 2) { |
uint32_t mc_init_misc_lat_timer = 0; |
if (rdev->family == CHIP_RV515) |
mc_init_misc_lat_timer = |
RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER); |
else if (rdev->family == CHIP_RS690) |
mc_init_misc_lat_timer = |
RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER); |
mc_init_misc_lat_timer &= |
~(R300_MC_DISP1R_INIT_LAT_MASK << |
R300_MC_DISP1R_INIT_LAT_SHIFT); |
mc_init_misc_lat_timer &= |
~(R300_MC_DISP0R_INIT_LAT_MASK << |
R300_MC_DISP0R_INIT_LAT_SHIFT); |
if (mode2) |
mc_init_misc_lat_timer |= |
(1 << R300_MC_DISP1R_INIT_LAT_SHIFT); |
if (mode1) |
mc_init_misc_lat_timer |= |
(1 << R300_MC_DISP0R_INIT_LAT_SHIFT); |
if (rdev->family == CHIP_RV515) |
WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER, |
mc_init_misc_lat_timer); |
else if (rdev->family == CHIP_RS690) |
WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER, |
mc_init_misc_lat_timer); |
} |
/* |
* determine is there is enough bw for current mode |
*/ |
temp_ff.full = rfixed_const(100); |
mclk_ff.full = rfixed_const(rdev->clock.default_mclk); |
mclk_ff.full = rfixed_div(mclk_ff, temp_ff); |
sclk_ff.full = rfixed_const(rdev->clock.default_sclk); |
sclk_ff.full = rfixed_div(sclk_ff, temp_ff); |
temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); |
temp_ff.full = rfixed_const(temp); |
mem_bw.full = rfixed_mul(mclk_ff, temp_ff); |
mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); |
pix_clk.full = 0; |
pix_clk2.full = 0; |
peak_disp_bw.full = 0; |
if (mode1) { |
temp_ff.full = rfixed_const(1000); |
pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ |
pix_clk.full = rfixed_div(pix_clk, temp_ff); |
temp_ff.full = rfixed_const(pixel_bytes1); |
peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); |
} |
if (mode2) { |
temp_ff.full = rfixed_const(1000); |
pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ |
pix_clk2.full = rfixed_div(pix_clk2, temp_ff); |
temp_ff.full = rfixed_const(pixel_bytes2); |
peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); |
} |
if (peak_disp_bw.full >= mem_bw.full) { |
DRM_ERROR |
("You may not have enough display bandwidth for current mode\n" |
"If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); |
printk("peak disp bw %d, mem_bw %d\n", |
rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw)); |
} |
/* |
* Line Buffer Setup |
* There is a single line buffer shared by both display controllers. |
* DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display |
* controllers. The paritioning can either be done manually or via one of four |
* preset allocations specified in bits 1:0: |
* 0 - line buffer is divided in half and shared between each display controller |
* 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 |
* 2 - D1 gets the whole buffer |
* 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 |
* Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode. |
* In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits |
* 14:4; D2 allocation follows D1. |
*/ |
/* is auto or manual better ? */ |
dc_lb_memory_split = |
RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK; |
dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; |
#if 1 |
/* auto */ |
if (mode1 && mode2) { |
if (mode1->hdisplay > mode2->hdisplay) { |
if (mode1->hdisplay > 2560) |
dc_lb_memory_split |= |
AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; |
else |
dc_lb_memory_split |= |
AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; |
} else if (mode2->hdisplay > mode1->hdisplay) { |
if (mode2->hdisplay > 2560) |
dc_lb_memory_split |= |
AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; |
else |
dc_lb_memory_split |= |
AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; |
} else |
dc_lb_memory_split |= |
AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; |
} else if (mode1) { |
dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY; |
} else if (mode2) { |
dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; |
} |
#else |
/* manual */ |
dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; |
dc_lb_memory_split &= |
~(AVIVO_DC_LB_DISP1_END_ADR_MASK << |
AVIVO_DC_LB_DISP1_END_ADR_SHIFT); |
if (mode1) { |
dc_lb_memory_split |= |
((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK) |
<< AVIVO_DC_LB_DISP1_END_ADR_SHIFT); |
} else if (mode2) { |
dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); |
} |
#endif |
WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split); |
} |
/drivers/video/drm/radeon/radeon.h |
---|
50,7 → 50,7 |
#include <pci.h> |
#include <errno-base.h> |
#include "drm_edid.h" |
#include "radeon_mode.h" |
#include "radeon_reg.h" |
#include "r300.h" |
57,11 → 57,12 |
#include <syscall.h> |
extern int radeon_modeset; |
extern int radeon_dynclks; |
extern int radeon_r4xx_atom; |
extern int radeon_gart_size; |
extern int radeon_r4xx_atom; |
extern int radeon_connector_table; |
/* |
* Copy from radeon_drv.h so we don't have to include both and have conflicting |
* symbol; |
212,8 → 213,23 |
unsigned wdomain; |
}; |
int radeon_object_init(struct radeon_device *rdev); |
void radeon_object_fini(struct radeon_device *rdev); |
int radeon_object_create(struct radeon_device *rdev, |
struct drm_gem_object *gobj, |
unsigned long size, |
bool kernel, |
uint32_t domain, |
bool interruptible, |
struct radeon_object **robj_ptr); |
/* |
* GEM objects. |
*/ |
struct radeon_gem { |
struct list_head objects; |
}; |
1040,40 → 1056,6 |
}; |
/** |
* DRM device structure. This structure represent a complete card that |
* may contain multiple heads. |
*/ |
struct drm_device { |
int irq_enabled; /**< True if irq handler is enabled */ |
__volatile__ long context_flag; /**< Context swapping flag */ |
__volatile__ long interrupt_flag; /**< Interruption handler flag */ |
__volatile__ long dma_flag; /**< DMA dispatch flag */ |
int last_checked; /**< Last context checked for DMA */ |
int last_context; /**< Last current context */ |
unsigned long last_switch; /**< jiffies at last context switch */ |
struct drm_agp_head *agp; /**< AGP data */ |
struct pci_dev *pdev; /**< PCI device structure */ |
int pci_vendor; /**< PCI vendor id */ |
int pci_device; /** PCI device id */ |
int num_crtcs; /**< Number of CRTCs on this device */ |
void *dev_private; /**< device private data */ |
void *mm_private; |
// struct address_space *dev_mapping; |
struct drm_mode_config mode_config; /**< Current mode config */ |
}; |
#define radeon_errata(rdev) (rdev)->asic->errata((rdev)) |
/drivers/video/drm/radeon/radeon_atombios.c |
---|
23,7 → 23,7 |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
//#include "drmP.h" |
#include "drmP.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
336,11 → 336,11 |
else |
linkb = false; |
// radeon_add_atom_encoder(dev, |
// enc_obj_id, |
// le16_to_cpu |
// (path-> |
// usDeviceTag)); |
radeon_add_atom_encoder(dev, |
enc_obj_id, |
le16_to_cpu |
(path-> |
usDeviceTag)); |
} |
} |
406,18 → 406,18 |
else |
ddc_bus = radeon_lookup_gpio(dev, line_mux); |
// radeon_add_atom_connector(dev, |
// le16_to_cpu(path-> |
// usConnObjectId), |
// le16_to_cpu(path-> |
// usDeviceTag), |
// connector_type, &ddc_bus, |
// linkb, igp_lane_info); |
radeon_add_atom_connector(dev, |
le16_to_cpu(path-> |
usConnObjectId), |
le16_to_cpu(path-> |
usDeviceTag), |
connector_type, &ddc_bus, |
linkb, igp_lane_info); |
} |
} |
// radeon_link_encoder_connector(dev); |
radeon_link_encoder_connector(dev); |
return true; |
} |
532,19 → 532,19 |
bios_connectors[i].valid = true; |
bios_connectors[i].devices = (1 << i); |
// if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) |
// radeon_add_atom_encoder(dev, |
// radeon_get_encoder_id(dev, |
// (1 << i), |
// dac), |
// (1 << i)); |
// else |
// radeon_add_legacy_encoder(dev, |
// radeon_get_encoder_id(dev, |
// (1 << |
// i), |
// dac), |
// (1 << i)); |
if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) |
radeon_add_atom_encoder(dev, |
radeon_get_encoder_id(dev, |
(1 << i), |
dac), |
(1 << i)); |
else |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
(1 << |
i), |
dac), |
(1 << i)); |
} |
/* combine shared connectors */ |
584,18 → 584,18 |
} |
/* add the connectors */ |
// for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { |
// if (bios_connectors[i].valid) |
// radeon_add_atom_connector(dev, |
// bios_connectors[i].line_mux, |
// bios_connectors[i].devices, |
// bios_connectors[i]. |
// connector_type, |
// &bios_connectors[i].ddc_bus, |
// false, 0); |
// } |
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { |
if (bios_connectors[i].valid) |
radeon_add_atom_connector(dev, |
bios_connectors[i].line_mux, |
bios_connectors[i].devices, |
bios_connectors[i]. |
connector_type, |
&bios_connectors[i].ddc_bus, |
false, 0); |
} |
// radeon_link_encoder_connector(dev); |
radeon_link_encoder_connector(dev); |
return true; |
} |
/drivers/video/drm/radeon/radeon_bios.c |
---|
25,7 → 25,7 |
* Alex Deucher |
* Jerome Glisse |
*/ |
//#include "drmP.h" |
#include "drmP.h" |
#include "radeon_reg.h" |
#include "radeon.h" |
#include "atom.h" |
/drivers/video/drm/radeon/radeon_clocks.c |
---|
25,7 → 25,7 |
* Alex Deucher |
* Jerome Glisse |
*/ |
//#include "drmP.h" |
#include "drmP.h" |
#include "radeon_drm.h" |
#include "radeon_reg.h" |
#include "radeon.h" |
/drivers/video/drm/radeon/radeon_combios.c |
---|
0,0 → 1,2490 |
/* |
* Copyright 2004 ATI Technologies Inc., Markham, Ontario |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
#include "atom.h" |
#ifdef CONFIG_PPC_PMAC |
/* not sure which of these are needed */ |
#include <asm/machdep.h> |
#include <asm/pmac_feature.h> |
#include <asm/prom.h> |
#include <asm/pci-bridge.h> |
#endif /* CONFIG_PPC_PMAC */ |
/* from radeon_encoder.c */ |
extern uint32_t |
radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, |
uint8_t dac); |
extern void radeon_link_encoder_connector(struct drm_device *dev); |
/* from radeon_connector.c */ |
extern void |
radeon_add_legacy_connector(struct drm_device *dev, |
uint32_t connector_id, |
uint32_t supported_device, |
int connector_type, |
struct radeon_i2c_bus_rec *i2c_bus); |
/* from radeon_legacy_encoder.c */ |
extern void |
radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, |
uint32_t supported_device); |
/* old legacy ATI BIOS routines */ |
/* COMBIOS table offsets */ |
enum radeon_combios_table_offset { |
/* absolute offset tables */ |
COMBIOS_ASIC_INIT_1_TABLE, |
COMBIOS_BIOS_SUPPORT_TABLE, |
COMBIOS_DAC_PROGRAMMING_TABLE, |
COMBIOS_MAX_COLOR_DEPTH_TABLE, |
COMBIOS_CRTC_INFO_TABLE, |
COMBIOS_PLL_INFO_TABLE, |
COMBIOS_TV_INFO_TABLE, |
COMBIOS_DFP_INFO_TABLE, |
COMBIOS_HW_CONFIG_INFO_TABLE, |
COMBIOS_MULTIMEDIA_INFO_TABLE, |
COMBIOS_TV_STD_PATCH_TABLE, |
COMBIOS_LCD_INFO_TABLE, |
COMBIOS_MOBILE_INFO_TABLE, |
COMBIOS_PLL_INIT_TABLE, |
COMBIOS_MEM_CONFIG_TABLE, |
COMBIOS_SAVE_MASK_TABLE, |
COMBIOS_HARDCODED_EDID_TABLE, |
COMBIOS_ASIC_INIT_2_TABLE, |
COMBIOS_CONNECTOR_INFO_TABLE, |
COMBIOS_DYN_CLK_1_TABLE, |
COMBIOS_RESERVED_MEM_TABLE, |
COMBIOS_EXT_TMDS_INFO_TABLE, |
COMBIOS_MEM_CLK_INFO_TABLE, |
COMBIOS_EXT_DAC_INFO_TABLE, |
COMBIOS_MISC_INFO_TABLE, |
COMBIOS_CRT_INFO_TABLE, |
COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE, |
COMBIOS_COMPONENT_VIDEO_INFO_TABLE, |
COMBIOS_FAN_SPEED_INFO_TABLE, |
COMBIOS_OVERDRIVE_INFO_TABLE, |
COMBIOS_OEM_INFO_TABLE, |
COMBIOS_DYN_CLK_2_TABLE, |
COMBIOS_POWER_CONNECTOR_INFO_TABLE, |
COMBIOS_I2C_INFO_TABLE, |
/* relative offset tables */ |
COMBIOS_ASIC_INIT_3_TABLE, /* offset from misc info */ |
COMBIOS_ASIC_INIT_4_TABLE, /* offset from misc info */ |
COMBIOS_DETECTED_MEM_TABLE, /* offset from misc info */ |
COMBIOS_ASIC_INIT_5_TABLE, /* offset from misc info */ |
COMBIOS_RAM_RESET_TABLE, /* offset from mem config */ |
COMBIOS_POWERPLAY_INFO_TABLE, /* offset from mobile info */ |
COMBIOS_GPIO_INFO_TABLE, /* offset from mobile info */ |
COMBIOS_LCD_DDC_INFO_TABLE, /* offset from mobile info */ |
COMBIOS_TMDS_POWER_TABLE, /* offset from mobile info */ |
COMBIOS_TMDS_POWER_ON_TABLE, /* offset from tmds power */ |
COMBIOS_TMDS_POWER_OFF_TABLE, /* offset from tmds power */ |
}; |
enum radeon_combios_ddc { |
DDC_NONE_DETECTED, |
DDC_MONID, |
DDC_DVI, |
DDC_VGA, |
DDC_CRT2, |
DDC_LCD, |
DDC_GPIO, |
}; |
enum radeon_combios_connector { |
CONNECTOR_NONE_LEGACY, |
CONNECTOR_PROPRIETARY_LEGACY, |
CONNECTOR_CRT_LEGACY, |
CONNECTOR_DVI_I_LEGACY, |
CONNECTOR_DVI_D_LEGACY, |
CONNECTOR_CTV_LEGACY, |
CONNECTOR_STV_LEGACY, |
CONNECTOR_UNSUPPORTED_LEGACY |
}; |
const int legacy_connector_convert[] = { |
DRM_MODE_CONNECTOR_Unknown, |
DRM_MODE_CONNECTOR_DVID, |
DRM_MODE_CONNECTOR_VGA, |
DRM_MODE_CONNECTOR_DVII, |
DRM_MODE_CONNECTOR_DVID, |
DRM_MODE_CONNECTOR_Composite, |
DRM_MODE_CONNECTOR_SVIDEO, |
DRM_MODE_CONNECTOR_Unknown, |
}; |
static uint16_t combios_get_table_offset(struct drm_device *dev, |
enum radeon_combios_table_offset table) |
{ |
struct radeon_device *rdev = dev->dev_private; |
int rev; |
uint16_t offset = 0, check_offset; |
switch (table) { |
/* absolute offset tables */ |
case COMBIOS_ASIC_INIT_1_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0xc); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_BIOS_SUPPORT_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x14); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_DAC_PROGRAMMING_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2a); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MAX_COLOR_DEPTH_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2c); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_CRTC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2e); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_PLL_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x30); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_TV_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x32); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_DFP_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x34); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_HW_CONFIG_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x36); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MULTIMEDIA_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x38); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_TV_STD_PATCH_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x3e); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_LCD_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x40); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MOBILE_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x42); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_PLL_INIT_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x46); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MEM_CONFIG_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x48); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_SAVE_MASK_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4a); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_HARDCODED_EDID_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4c); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_ASIC_INIT_2_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4e); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_CONNECTOR_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x50); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_DYN_CLK_1_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x52); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_RESERVED_MEM_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x54); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_EXT_TMDS_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x58); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MEM_CLK_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5a); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_EXT_DAC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5c); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_MISC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5e); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_CRT_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x60); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x62); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_COMPONENT_VIDEO_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x64); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_FAN_SPEED_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x66); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_OVERDRIVE_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x68); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_OEM_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6a); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_DYN_CLK_2_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6c); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_POWER_CONNECTOR_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6e); |
if (check_offset) |
offset = check_offset; |
break; |
case COMBIOS_I2C_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x70); |
if (check_offset) |
offset = check_offset; |
break; |
/* relative offset tables */ |
case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); |
if (check_offset) { |
rev = RBIOS8(check_offset); |
if (rev > 0) { |
check_offset = RBIOS16(check_offset + 0x3); |
if (check_offset) |
offset = check_offset; |
} |
} |
break; |
case COMBIOS_ASIC_INIT_4_TABLE: /* offset from misc info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); |
if (check_offset) { |
rev = RBIOS8(check_offset); |
if (rev > 0) { |
check_offset = RBIOS16(check_offset + 0x5); |
if (check_offset) |
offset = check_offset; |
} |
} |
break; |
case COMBIOS_DETECTED_MEM_TABLE: /* offset from misc info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); |
if (check_offset) { |
rev = RBIOS8(check_offset); |
if (rev > 0) { |
check_offset = RBIOS16(check_offset + 0x7); |
if (check_offset) |
offset = check_offset; |
} |
} |
break; |
case COMBIOS_ASIC_INIT_5_TABLE: /* offset from misc info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); |
if (check_offset) { |
rev = RBIOS8(check_offset); |
if (rev == 2) { |
check_offset = RBIOS16(check_offset + 0x9); |
if (check_offset) |
offset = check_offset; |
} |
} |
break; |
case COMBIOS_RAM_RESET_TABLE: /* offset from mem config */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); |
if (check_offset) { |
while (RBIOS8(check_offset++)); |
check_offset += 2; |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_POWERPLAY_INFO_TABLE: /* offset from mobile info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x11); |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_GPIO_INFO_TABLE: /* offset from mobile info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x13); |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_LCD_DDC_INFO_TABLE: /* offset from mobile info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x15); |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_TMDS_POWER_TABLE: /* offset from mobile info */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x17); |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_TMDS_POWER_ON_TABLE: /* offset from tmds power */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x2); |
if (check_offset) |
offset = check_offset; |
} |
break; |
case COMBIOS_TMDS_POWER_OFF_TABLE: /* offset from tmds power */ |
check_offset = |
combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); |
if (check_offset) { |
check_offset = RBIOS16(check_offset + 0x4); |
if (check_offset) |
offset = check_offset; |
} |
break; |
default: |
break; |
} |
return offset; |
} |
struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) |
{ |
struct radeon_i2c_bus_rec i2c; |
i2c.mask_clk_mask = RADEON_GPIO_EN_1; |
i2c.mask_data_mask = RADEON_GPIO_EN_0; |
i2c.a_clk_mask = RADEON_GPIO_A_1; |
i2c.a_data_mask = RADEON_GPIO_A_0; |
i2c.put_clk_mask = RADEON_GPIO_EN_1; |
i2c.put_data_mask = RADEON_GPIO_EN_0; |
i2c.get_clk_mask = RADEON_GPIO_Y_1; |
i2c.get_data_mask = RADEON_GPIO_Y_0; |
if ((ddc_line == RADEON_LCD_GPIO_MASK) || |
(ddc_line == RADEON_MDGPIO_EN_REG)) { |
i2c.mask_clk_reg = ddc_line; |
i2c.mask_data_reg = ddc_line; |
i2c.a_clk_reg = ddc_line; |
i2c.a_data_reg = ddc_line; |
i2c.put_clk_reg = ddc_line; |
i2c.put_data_reg = ddc_line; |
i2c.get_clk_reg = ddc_line + 4; |
i2c.get_data_reg = ddc_line + 4; |
} else { |
i2c.mask_clk_reg = ddc_line; |
i2c.mask_data_reg = ddc_line; |
i2c.a_clk_reg = ddc_line; |
i2c.a_data_reg = ddc_line; |
i2c.put_clk_reg = ddc_line; |
i2c.put_data_reg = ddc_line; |
i2c.get_clk_reg = ddc_line; |
i2c.get_data_reg = ddc_line; |
} |
if (ddc_line) |
i2c.valid = true; |
else |
i2c.valid = false; |
return i2c; |
} |
bool radeon_combios_get_clock_info(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint16_t pll_info; |
struct radeon_pll *p1pll = &rdev->clock.p1pll; |
struct radeon_pll *p2pll = &rdev->clock.p2pll; |
struct radeon_pll *spll = &rdev->clock.spll; |
struct radeon_pll *mpll = &rdev->clock.mpll; |
int8_t rev; |
uint16_t sclk, mclk; |
if (rdev->bios == NULL) |
return NULL; |
pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); |
if (pll_info) { |
rev = RBIOS8(pll_info); |
/* pixel clocks */ |
p1pll->reference_freq = RBIOS16(pll_info + 0xe); |
p1pll->reference_div = RBIOS16(pll_info + 0x10); |
p1pll->pll_out_min = RBIOS32(pll_info + 0x12); |
p1pll->pll_out_max = RBIOS32(pll_info + 0x16); |
if (rev > 9) { |
p1pll->pll_in_min = RBIOS32(pll_info + 0x36); |
p1pll->pll_in_max = RBIOS32(pll_info + 0x3a); |
} else { |
p1pll->pll_in_min = 40; |
p1pll->pll_in_max = 500; |
} |
*p2pll = *p1pll; |
/* system clock */ |
spll->reference_freq = RBIOS16(pll_info + 0x1a); |
spll->reference_div = RBIOS16(pll_info + 0x1c); |
spll->pll_out_min = RBIOS32(pll_info + 0x1e); |
spll->pll_out_max = RBIOS32(pll_info + 0x22); |
if (rev > 10) { |
spll->pll_in_min = RBIOS32(pll_info + 0x48); |
spll->pll_in_max = RBIOS32(pll_info + 0x4c); |
} else { |
/* ??? */ |
spll->pll_in_min = 40; |
spll->pll_in_max = 500; |
} |
/* memory clock */ |
mpll->reference_freq = RBIOS16(pll_info + 0x26); |
mpll->reference_div = RBIOS16(pll_info + 0x28); |
mpll->pll_out_min = RBIOS32(pll_info + 0x2a); |
mpll->pll_out_max = RBIOS32(pll_info + 0x2e); |
if (rev > 10) { |
mpll->pll_in_min = RBIOS32(pll_info + 0x5a); |
mpll->pll_in_max = RBIOS32(pll_info + 0x5e); |
} else { |
/* ??? */ |
mpll->pll_in_min = 40; |
mpll->pll_in_max = 500; |
} |
/* default sclk/mclk */ |
sclk = RBIOS16(pll_info + 0xa); |
mclk = RBIOS16(pll_info + 0x8); |
if (sclk == 0) |
sclk = 200 * 100; |
if (mclk == 0) |
mclk = 200 * 100; |
rdev->clock.default_sclk = sclk; |
rdev->clock.default_mclk = mclk; |
return true; |
} |
return false; |
} |
struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct |
radeon_encoder |
*encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t dac_info; |
uint8_t rev, bg, dac; |
struct radeon_encoder_primary_dac *p_dac = NULL; |
if (rdev->bios == NULL) |
return NULL; |
/* check CRT table */ |
dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); |
if (dac_info) { |
p_dac = |
kzalloc(sizeof(struct radeon_encoder_primary_dac), |
GFP_KERNEL); |
if (!p_dac) |
return NULL; |
rev = RBIOS8(dac_info) & 0x3; |
if (rev < 2) { |
bg = RBIOS8(dac_info + 0x2) & 0xf; |
dac = (RBIOS8(dac_info + 0x2) >> 4) & 0xf; |
p_dac->ps2_pdac_adj = (bg << 8) | (dac); |
} else { |
bg = RBIOS8(dac_info + 0x2) & 0xf; |
dac = RBIOS8(dac_info + 0x3) & 0xf; |
p_dac->ps2_pdac_adj = (bg << 8) | (dac); |
} |
} |
return p_dac; |
} |
static enum radeon_tv_std |
radeon_combios_get_tv_info(struct radeon_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t tv_info; |
enum radeon_tv_std tv_std = TV_STD_NTSC; |
tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); |
if (tv_info) { |
if (RBIOS8(tv_info + 6) == 'T') { |
switch (RBIOS8(tv_info + 7) & 0xf) { |
case 1: |
tv_std = TV_STD_NTSC; |
DRM_INFO("Default TV standard: NTSC\n"); |
break; |
case 2: |
tv_std = TV_STD_PAL; |
DRM_INFO("Default TV standard: PAL\n"); |
break; |
case 3: |
tv_std = TV_STD_PAL_M; |
DRM_INFO("Default TV standard: PAL-M\n"); |
break; |
case 4: |
tv_std = TV_STD_PAL_60; |
DRM_INFO("Default TV standard: PAL-60\n"); |
break; |
case 5: |
tv_std = TV_STD_NTSC_J; |
DRM_INFO("Default TV standard: NTSC-J\n"); |
break; |
case 6: |
tv_std = TV_STD_SCART_PAL; |
DRM_INFO("Default TV standard: SCART-PAL\n"); |
break; |
default: |
tv_std = TV_STD_NTSC; |
DRM_INFO |
("Unknown TV standard; defaulting to NTSC\n"); |
break; |
} |
switch ((RBIOS8(tv_info + 9) >> 2) & 0x3) { |
case 0: |
DRM_INFO("29.498928713 MHz TV ref clk\n"); |
break; |
case 1: |
DRM_INFO("28.636360000 MHz TV ref clk\n"); |
break; |
case 2: |
DRM_INFO("14.318180000 MHz TV ref clk\n"); |
break; |
case 3: |
DRM_INFO("27.000000000 MHz TV ref clk\n"); |
break; |
default: |
break; |
} |
} |
} |
return tv_std; |
} |
static const uint32_t default_tvdac_adj[CHIP_LAST] = { |
0x00000000, /* r100 */ |
0x00280000, /* rv100 */ |
0x00000000, /* rs100 */ |
0x00880000, /* rv200 */ |
0x00000000, /* rs200 */ |
0x00000000, /* r200 */ |
0x00770000, /* rv250 */ |
0x00290000, /* rs300 */ |
0x00560000, /* rv280 */ |
0x00780000, /* r300 */ |
0x00770000, /* r350 */ |
0x00780000, /* rv350 */ |
0x00780000, /* rv380 */ |
0x01080000, /* r420 */ |
0x01080000, /* r423 */ |
0x01080000, /* rv410 */ |
0x00780000, /* rs400 */ |
0x00780000, /* rs480 */ |
}; |
static struct radeon_encoder_tv_dac |
*radeon_legacy_get_tv_dac_info_from_table(struct radeon_device *rdev) |
{ |
struct radeon_encoder_tv_dac *tv_dac = NULL; |
tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); |
if (!tv_dac) |
return NULL; |
tv_dac->ps2_tvdac_adj = default_tvdac_adj[rdev->family]; |
if ((rdev->flags & RADEON_IS_MOBILITY) && (rdev->family == CHIP_RV250)) |
tv_dac->ps2_tvdac_adj = 0x00880000; |
tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; |
tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; |
return tv_dac; |
} |
struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct |
radeon_encoder |
*encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t dac_info; |
uint8_t rev, bg, dac; |
struct radeon_encoder_tv_dac *tv_dac = NULL; |
if (rdev->bios == NULL) |
return radeon_legacy_get_tv_dac_info_from_table(rdev); |
/* first check TV table */ |
dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); |
if (dac_info) { |
tv_dac = |
kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); |
if (!tv_dac) |
return NULL; |
rev = RBIOS8(dac_info + 0x3); |
if (rev > 4) { |
bg = RBIOS8(dac_info + 0xc) & 0xf; |
dac = RBIOS8(dac_info + 0xd) & 0xf; |
tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); |
bg = RBIOS8(dac_info + 0xe) & 0xf; |
dac = RBIOS8(dac_info + 0xf) & 0xf; |
tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); |
bg = RBIOS8(dac_info + 0x10) & 0xf; |
dac = RBIOS8(dac_info + 0x11) & 0xf; |
tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); |
} else if (rev > 1) { |
bg = RBIOS8(dac_info + 0xc) & 0xf; |
dac = (RBIOS8(dac_info + 0xc) >> 4) & 0xf; |
tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); |
bg = RBIOS8(dac_info + 0xd) & 0xf; |
dac = (RBIOS8(dac_info + 0xd) >> 4) & 0xf; |
tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); |
bg = RBIOS8(dac_info + 0xe) & 0xf; |
dac = (RBIOS8(dac_info + 0xe) >> 4) & 0xf; |
tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); |
} |
tv_dac->tv_std = radeon_combios_get_tv_info(encoder); |
} else { |
/* then check CRT table */ |
dac_info = |
combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); |
if (dac_info) { |
tv_dac = |
kzalloc(sizeof(struct radeon_encoder_tv_dac), |
GFP_KERNEL); |
if (!tv_dac) |
return NULL; |
rev = RBIOS8(dac_info) & 0x3; |
if (rev < 2) { |
bg = RBIOS8(dac_info + 0x3) & 0xf; |
dac = (RBIOS8(dac_info + 0x3) >> 4) & 0xf; |
tv_dac->ps2_tvdac_adj = |
(bg << 16) | (dac << 20); |
tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; |
tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; |
} else { |
bg = RBIOS8(dac_info + 0x4) & 0xf; |
dac = RBIOS8(dac_info + 0x5) & 0xf; |
tv_dac->ps2_tvdac_adj = |
(bg << 16) | (dac << 20); |
tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; |
tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; |
} |
} else { |
DRM_INFO("No TV DAC info found in BIOS\n"); |
return radeon_legacy_get_tv_dac_info_from_table(rdev); |
} |
} |
return tv_dac; |
} |
static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct |
radeon_device |
*rdev) |
{ |
struct radeon_encoder_lvds *lvds = NULL; |
uint32_t fp_vert_stretch, fp_horz_stretch; |
uint32_t ppll_div_sel, ppll_val; |
uint32_t lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); |
lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); |
if (!lvds) |
return NULL; |
fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH); |
fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH); |
/* These should be fail-safe defaults, fingers crossed */ |
lvds->panel_pwr_delay = 200; |
lvds->panel_vcc_delay = 2000; |
lvds->lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); |
lvds->panel_digon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) & 0xf; |
lvds->panel_blon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY2_SHIFT) & 0xf; |
if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) |
lvds->native_mode.panel_yres = |
((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> |
RADEON_VERT_PANEL_SHIFT) + 1; |
else |
lvds->native_mode.panel_yres = |
(RREG32(RADEON_CRTC_V_TOTAL_DISP) >> 16) + 1; |
if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) |
lvds->native_mode.panel_xres = |
(((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >> |
RADEON_HORZ_PANEL_SHIFT) + 1) * 8; |
else |
lvds->native_mode.panel_xres = |
((RREG32(RADEON_CRTC_H_TOTAL_DISP) >> 16) + 1) * 8; |
if ((lvds->native_mode.panel_xres < 640) || |
(lvds->native_mode.panel_yres < 480)) { |
lvds->native_mode.panel_xres = 640; |
lvds->native_mode.panel_yres = 480; |
} |
ppll_div_sel = RREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; |
ppll_val = RREG32_PLL(RADEON_PPLL_DIV_0 + ppll_div_sel); |
if ((ppll_val & 0x000707ff) == 0x1bb) |
lvds->use_bios_dividers = false; |
else { |
lvds->panel_ref_divider = |
RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; |
lvds->panel_post_divider = (ppll_val >> 16) & 0x7; |
lvds->panel_fb_divider = ppll_val & 0x7ff; |
if ((lvds->panel_ref_divider != 0) && |
(lvds->panel_fb_divider > 3)) |
lvds->use_bios_dividers = true; |
} |
lvds->panel_vcc_delay = 200; |
DRM_INFO("Panel info derived from registers\n"); |
DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, |
lvds->native_mode.panel_yres); |
return lvds; |
} |
struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder |
*encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t lcd_info; |
uint32_t panel_setup; |
char stmp[30]; |
int tmp, i; |
struct radeon_encoder_lvds *lvds = NULL; |
if (rdev->bios == NULL) |
return radeon_legacy_get_lvds_info_from_regs(rdev); |
lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); |
if (lcd_info) { |
lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); |
if (!lvds) |
return NULL; |
for (i = 0; i < 24; i++) |
stmp[i] = RBIOS8(lcd_info + i + 1); |
stmp[24] = 0; |
DRM_INFO("Panel ID String: %s\n", stmp); |
lvds->native_mode.panel_xres = RBIOS16(lcd_info + 0x19); |
lvds->native_mode.panel_yres = RBIOS16(lcd_info + 0x1b); |
DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, |
lvds->native_mode.panel_yres); |
lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c); |
if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) |
lvds->panel_vcc_delay = 2000; |
lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24); |
lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf; |
lvds->panel_blon_delay = (RBIOS16(lcd_info + 0x38) >> 4) & 0xf; |
lvds->panel_ref_divider = RBIOS16(lcd_info + 0x2e); |
lvds->panel_post_divider = RBIOS8(lcd_info + 0x30); |
lvds->panel_fb_divider = RBIOS16(lcd_info + 0x31); |
if ((lvds->panel_ref_divider != 0) && |
(lvds->panel_fb_divider > 3)) |
lvds->use_bios_dividers = true; |
panel_setup = RBIOS32(lcd_info + 0x39); |
lvds->lvds_gen_cntl = 0xff00; |
if (panel_setup & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT; |
if ((panel_setup >> 4) & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE; |
switch ((panel_setup >> 8) & 0x7) { |
case 0: |
lvds->lvds_gen_cntl |= RADEON_LVDS_NO_FM; |
break; |
case 1: |
lvds->lvds_gen_cntl |= RADEON_LVDS_2_GREY; |
break; |
case 2: |
lvds->lvds_gen_cntl |= RADEON_LVDS_4_GREY; |
break; |
default: |
break; |
} |
if ((panel_setup >> 16) & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_FP_POL_LOW; |
if ((panel_setup >> 17) & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_LP_POL_LOW; |
if ((panel_setup >> 18) & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_DTM_POL_LOW; |
if ((panel_setup >> 23) & 0x1) |
lvds->lvds_gen_cntl |= RADEON_LVDS_BL_CLK_SEL; |
lvds->lvds_gen_cntl |= (panel_setup & 0xf0000000); |
for (i = 0; i < 32; i++) { |
tmp = RBIOS16(lcd_info + 64 + i * 2); |
if (tmp == 0) |
break; |
if ((RBIOS16(tmp) == lvds->native_mode.panel_xres) && |
(RBIOS16(tmp + 2) == |
lvds->native_mode.panel_yres)) { |
lvds->native_mode.hblank = |
(RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; |
lvds->native_mode.hoverplus = |
(RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - |
1) * 8; |
lvds->native_mode.hsync_width = |
RBIOS8(tmp + 23) * 8; |
lvds->native_mode.vblank = (RBIOS16(tmp + 24) - |
RBIOS16(tmp + 26)); |
lvds->native_mode.voverplus = |
((RBIOS16(tmp + 28) & 0x7ff) - |
RBIOS16(tmp + 26)); |
lvds->native_mode.vsync_width = |
((RBIOS16(tmp + 28) & 0xf800) >> 11); |
lvds->native_mode.dotclock = |
RBIOS16(tmp + 9) * 10; |
lvds->native_mode.flags = 0; |
} |
} |
encoder->native_mode = lvds->native_mode; |
} else { |
DRM_INFO("No panel info found in BIOS\n"); |
return radeon_legacy_get_lvds_info_from_regs(rdev); |
} |
return lvds; |
} |
static const struct radeon_tmds_pll default_tmds_pll[CHIP_LAST][4] = { |
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_R100 */ |
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RV100 */ |
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RS100 */ |
{{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RV200 */ |
{{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RS200 */ |
{{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_R200 */ |
{{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /* CHIP_RV250 */ |
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RS300 */ |
{{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, /* CHIP_RV280 */ |
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R300 */ |
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R350 */ |
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RV350 */ |
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RV380 */ |
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R420 */ |
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R423 */ |
{{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RV410 */ |
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RS400 */ |
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RS480 */ |
}; |
static struct radeon_encoder_int_tmds |
*radeon_legacy_get_tmds_info_from_table(struct radeon_device *rdev) |
{ |
int i; |
struct radeon_encoder_int_tmds *tmds = NULL; |
tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); |
if (!tmds) |
return NULL; |
for (i = 0; i < 4; i++) { |
tmds->tmds_pll[i].value = |
default_tmds_pll[rdev->family][i].value; |
tmds->tmds_pll[i].freq = default_tmds_pll[rdev->family][i].freq; |
} |
return tmds; |
} |
struct radeon_encoder_int_tmds *radeon_combios_get_tmds_info(struct |
radeon_encoder |
*encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t tmds_info; |
int i, n; |
uint8_t ver; |
struct radeon_encoder_int_tmds *tmds = NULL; |
if (rdev->bios == NULL) |
return radeon_legacy_get_tmds_info_from_table(rdev); |
tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); |
if (tmds_info) { |
tmds = |
kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); |
if (!tmds) |
return NULL; |
ver = RBIOS8(tmds_info); |
DRM_INFO("DFP table revision: %d\n", ver); |
if (ver == 3) { |
n = RBIOS8(tmds_info + 5) + 1; |
if (n > 4) |
n = 4; |
for (i = 0; i < n; i++) { |
tmds->tmds_pll[i].value = |
RBIOS32(tmds_info + i * 10 + 0x08); |
tmds->tmds_pll[i].freq = |
RBIOS16(tmds_info + i * 10 + 0x10); |
DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", |
tmds->tmds_pll[i].freq, |
tmds->tmds_pll[i].value); |
} |
} else if (ver == 4) { |
int stride = 0; |
n = RBIOS8(tmds_info + 5) + 1; |
if (n > 4) |
n = 4; |
for (i = 0; i < n; i++) { |
tmds->tmds_pll[i].value = |
RBIOS32(tmds_info + stride + 0x08); |
tmds->tmds_pll[i].freq = |
RBIOS16(tmds_info + stride + 0x10); |
if (i == 0) |
stride += 10; |
else |
stride += 6; |
DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", |
tmds->tmds_pll[i].freq, |
tmds->tmds_pll[i].value); |
} |
} |
} else |
DRM_INFO("No TMDS info found in BIOS\n"); |
return tmds; |
} |
void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
uint16_t ext_tmds_info; |
uint8_t ver; |
if (rdev->bios == NULL) |
return; |
ext_tmds_info = |
combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE); |
if (ext_tmds_info) { |
ver = RBIOS8(ext_tmds_info); |
DRM_INFO("External TMDS Table revision: %d\n", ver); |
// TODO |
} |
} |
bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_i2c_bus_rec ddc_i2c; |
rdev->mode_info.connector_table = radeon_connector_table; |
if (rdev->mode_info.connector_table == CT_NONE) { |
#ifdef CONFIG_PPC_PMAC |
if (machine_is_compatible("PowerBook3,3")) { |
/* powerbook with VGA */ |
rdev->mode_info.connector_table = CT_POWERBOOK_VGA; |
} else if (machine_is_compatible("PowerBook3,4") || |
machine_is_compatible("PowerBook3,5")) { |
/* powerbook with internal tmds */ |
rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL; |
} else if (machine_is_compatible("PowerBook5,1") || |
machine_is_compatible("PowerBook5,2") || |
machine_is_compatible("PowerBook5,3") || |
machine_is_compatible("PowerBook5,4") || |
machine_is_compatible("PowerBook5,5")) { |
/* powerbook with external single link tmds (sil164) */ |
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; |
} else if (machine_is_compatible("PowerBook5,6")) { |
/* powerbook with external dual or single link tmds */ |
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; |
} else if (machine_is_compatible("PowerBook5,7") || |
machine_is_compatible("PowerBook5,8") || |
machine_is_compatible("PowerBook5,9")) { |
/* PowerBook6,2 ? */ |
/* powerbook with external dual link tmds (sil1178?) */ |
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; |
} else if (machine_is_compatible("PowerBook4,1") || |
machine_is_compatible("PowerBook4,2") || |
machine_is_compatible("PowerBook4,3") || |
machine_is_compatible("PowerBook6,3") || |
machine_is_compatible("PowerBook6,5") || |
machine_is_compatible("PowerBook6,7")) { |
/* ibook */ |
rdev->mode_info.connector_table = CT_IBOOK; |
} else if (machine_is_compatible("PowerMac4,4")) { |
/* emac */ |
rdev->mode_info.connector_table = CT_EMAC; |
} else if (machine_is_compatible("PowerMac10,1")) { |
/* mini with internal tmds */ |
rdev->mode_info.connector_table = CT_MINI_INTERNAL; |
} else if (machine_is_compatible("PowerMac10,2")) { |
/* mini with external tmds */ |
rdev->mode_info.connector_table = CT_MINI_EXTERNAL; |
} else if (machine_is_compatible("PowerMac12,1")) { |
/* PowerMac8,1 ? */ |
/* imac g5 isight */ |
rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT; |
} else |
#endif /* CONFIG_PPC_PMAC */ |
rdev->mode_info.connector_table = CT_GENERIC; |
} |
switch (rdev->mode_info.connector_table) { |
case CT_GENERIC: |
DRM_INFO("Connector Table: %d (generic)\n", |
rdev->mode_info.connector_table); |
/* these are the most common settings */ |
if (rdev->flags & RADEON_SINGLE_CRTC) { |
/* VGA - primary dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, |
ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, |
&ddc_i2c); |
} else if (rdev->flags & RADEON_IS_MOBILITY) { |
/* LVDS */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, |
ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, |
&ddc_i2c); |
/* VGA - primary dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, |
ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, |
&ddc_i2c); |
} else { |
/* DVI-I - tv dac, int tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 0, |
ATOM_DEVICE_DFP1_SUPPORT | |
ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, |
&ddc_i2c); |
/* VGA - primary dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, |
ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, |
&ddc_i2c); |
} |
if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) { |
/* TV - tv dac */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, |
ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
} |
break; |
case CT_IBOOK: |
DRM_INFO("Connector Table: %d (ibook)\n", |
rdev->mode_info.connector_table); |
/* LVDS */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); |
/* VGA - TV DAC */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_POWERBOOK_EXTERNAL: |
DRM_INFO("Connector Table: %d (powerbook external tmds)\n", |
rdev->mode_info.connector_table); |
/* LVDS */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); |
/* DVI-I - primary dac, ext tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP2_SUPPORT, |
0), |
ATOM_DEVICE_DFP2_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, |
ATOM_DEVICE_DFP2_SUPPORT | |
ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_POWERBOOK_INTERNAL: |
DRM_INFO("Connector Table: %d (powerbook internal tmds)\n", |
rdev->mode_info.connector_table); |
/* LVDS */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); |
/* DVI-I - primary dac, int tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, |
ATOM_DEVICE_DFP1_SUPPORT | |
ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_POWERBOOK_VGA: |
DRM_INFO("Connector Table: %d (powerbook vga)\n", |
rdev->mode_info.connector_table); |
/* LVDS */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); |
/* VGA - primary dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_MINI_EXTERNAL: |
DRM_INFO("Connector Table: %d (mini external tmds)\n", |
rdev->mode_info.connector_table); |
/* DVI-I - tv dac, ext tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP2_SUPPORT, |
0), |
ATOM_DEVICE_DFP2_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 0, |
ATOM_DEVICE_DFP2_SUPPORT | |
ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_MINI_INTERNAL: |
DRM_INFO("Connector Table: %d (mini internal tmds)\n", |
rdev->mode_info.connector_table); |
/* DVI-I - tv dac, int tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 0, |
ATOM_DEVICE_DFP1_SUPPORT | |
ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_IMAC_G5_ISIGHT: |
DRM_INFO("Connector Table: %d (imac g5 isight)\n", |
rdev->mode_info.connector_table); |
/* DVI-D - int tmds */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_DFP1_SUPPORT, |
DRM_MODE_CONNECTOR_DVID, &ddc_i2c); |
/* VGA - tv dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
case CT_EMAC: |
DRM_INFO("Connector Table: %d (emac)\n", |
rdev->mode_info.connector_table); |
/* VGA - primary dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, &ddc_i2c); |
/* VGA - tv dac */ |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, |
DRM_MODE_CONNECTOR_VGA, &ddc_i2c); |
/* TV - TV DAC */ |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
break; |
default: |
DRM_INFO("Connector table: %d (invalid)\n", |
rdev->mode_info.connector_table); |
return false; |
} |
radeon_link_encoder_connector(dev); |
return true; |
} |
static bool radeon_apply_legacy_quirks(struct drm_device *dev, |
int bios_index, |
enum radeon_combios_connector |
*legacy_connector, |
struct radeon_i2c_bus_rec *ddc_i2c) |
{ |
struct radeon_device *rdev = dev->dev_private; |
/* XPRESS DDC quirks */ |
if ((rdev->family == CHIP_RS400 || |
rdev->family == CHIP_RS480) && |
ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) |
*ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); |
else if ((rdev->family == CHIP_RS400 || |
rdev->family == CHIP_RS480) && |
ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) { |
ddc_i2c->valid = true; |
ddc_i2c->mask_clk_mask = (0x20 << 8); |
ddc_i2c->mask_data_mask = 0x80; |
ddc_i2c->a_clk_mask = (0x20 << 8); |
ddc_i2c->a_data_mask = 0x80; |
ddc_i2c->put_clk_mask = (0x20 << 8); |
ddc_i2c->put_data_mask = 0x80; |
ddc_i2c->get_clk_mask = (0x20 << 8); |
ddc_i2c->get_data_mask = 0x80; |
ddc_i2c->mask_clk_reg = RADEON_GPIOPAD_MASK; |
ddc_i2c->mask_data_reg = RADEON_GPIOPAD_MASK; |
ddc_i2c->a_clk_reg = RADEON_GPIOPAD_A; |
ddc_i2c->a_data_reg = RADEON_GPIOPAD_A; |
ddc_i2c->put_clk_reg = RADEON_GPIOPAD_EN; |
ddc_i2c->put_data_reg = RADEON_GPIOPAD_EN; |
ddc_i2c->get_clk_reg = RADEON_LCD_GPIO_Y_REG; |
ddc_i2c->get_data_reg = RADEON_LCD_GPIO_Y_REG; |
} |
/* Certain IBM chipset RN50s have a BIOS reporting two VGAs, |
one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */ |
if (dev->pdev->device == 0x515e && |
dev->pdev->subsystem_vendor == 0x1014) { |
if (*legacy_connector == CONNECTOR_CRT_LEGACY && |
ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) |
return false; |
} |
/* Some RV100 cards with 2 VGA ports show up with DVI+VGA */ |
if (dev->pdev->device == 0x5159 && |
dev->pdev->subsystem_vendor == 0x1002 && |
dev->pdev->subsystem_device == 0x013a) { |
if (*legacy_connector == CONNECTOR_DVI_I_LEGACY) |
*legacy_connector = CONNECTOR_CRT_LEGACY; |
} |
/* X300 card with extra non-existent DVI port */ |
if (dev->pdev->device == 0x5B60 && |
dev->pdev->subsystem_vendor == 0x17af && |
dev->pdev->subsystem_device == 0x201e && bios_index == 2) { |
if (*legacy_connector == CONNECTOR_DVI_I_LEGACY) |
return false; |
} |
return true; |
} |
bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint32_t conn_info, entry, devices; |
uint16_t tmp; |
enum radeon_combios_ddc ddc_type; |
enum radeon_combios_connector connector; |
int i = 0; |
struct radeon_i2c_bus_rec ddc_i2c; |
if (rdev->bios == NULL) |
return false; |
conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE); |
if (conn_info) { |
for (i = 0; i < 4; i++) { |
entry = conn_info + 2 + i * 2; |
if (!RBIOS16(entry)) |
break; |
tmp = RBIOS16(entry); |
connector = (tmp >> 12) & 0xf; |
ddc_type = (tmp >> 8) & 0xf; |
switch (ddc_type) { |
case DDC_MONID: |
ddc_i2c = |
combios_setup_i2c_bus(RADEON_GPIO_MONID); |
break; |
case DDC_DVI: |
ddc_i2c = |
combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
break; |
case DDC_VGA: |
ddc_i2c = |
combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); |
break; |
case DDC_CRT2: |
ddc_i2c = |
combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); |
break; |
default: |
break; |
} |
radeon_apply_legacy_quirks(dev, i, &connector, |
&ddc_i2c); |
switch (connector) { |
case CONNECTOR_PROPRIETARY_LEGACY: |
if ((tmp >> 4) & 0x1) |
devices = ATOM_DEVICE_DFP2_SUPPORT; |
else |
devices = ATOM_DEVICE_DFP1_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, devices, 0), |
devices); |
radeon_add_legacy_connector(dev, i, devices, |
legacy_connector_convert |
[connector], |
&ddc_i2c); |
break; |
case CONNECTOR_CRT_LEGACY: |
if (tmp & 0x1) { |
devices = ATOM_DEVICE_CRT2_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
} else { |
devices = ATOM_DEVICE_CRT1_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
} |
radeon_add_legacy_connector(dev, |
i, |
devices, |
legacy_connector_convert |
[connector], |
&ddc_i2c); |
break; |
case CONNECTOR_DVI_I_LEGACY: |
devices = 0; |
if (tmp & 0x1) { |
devices |= ATOM_DEVICE_CRT2_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_CRT2_SUPPORT, |
2), |
ATOM_DEVICE_CRT2_SUPPORT); |
} else { |
devices |= ATOM_DEVICE_CRT1_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
} |
if ((tmp >> 4) & 0x1) { |
devices |= ATOM_DEVICE_DFP2_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_DFP2_SUPPORT, |
0), |
ATOM_DEVICE_DFP2_SUPPORT); |
} else { |
devices |= ATOM_DEVICE_DFP1_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
} |
radeon_add_legacy_connector(dev, |
i, |
devices, |
legacy_connector_convert |
[connector], |
&ddc_i2c); |
break; |
case CONNECTOR_DVI_D_LEGACY: |
if ((tmp >> 4) & 0x1) |
devices = ATOM_DEVICE_DFP2_SUPPORT; |
else |
devices = ATOM_DEVICE_DFP1_SUPPORT; |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, devices, 0), |
devices); |
radeon_add_legacy_connector(dev, i, devices, |
legacy_connector_convert |
[connector], |
&ddc_i2c); |
break; |
case CONNECTOR_CTV_LEGACY: |
case CONNECTOR_STV_LEGACY: |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, i, |
ATOM_DEVICE_TV1_SUPPORT, |
legacy_connector_convert |
[connector], |
&ddc_i2c); |
break; |
default: |
DRM_ERROR("Unknown connector type: %d\n", |
connector); |
continue; |
} |
} |
} else { |
uint16_t tmds_info = |
combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); |
if (tmds_info) { |
DRM_DEBUG("Found DFP table, assuming DVI connector\n"); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_CRT1_SUPPORT, |
1), |
ATOM_DEVICE_CRT1_SUPPORT); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_DFP1_SUPPORT, |
0), |
ATOM_DEVICE_DFP1_SUPPORT); |
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); |
radeon_add_legacy_connector(dev, |
0, |
ATOM_DEVICE_CRT1_SUPPORT | |
ATOM_DEVICE_DFP1_SUPPORT, |
DRM_MODE_CONNECTOR_DVII, |
&ddc_i2c); |
} else { |
DRM_DEBUG("No connector info found\n"); |
return false; |
} |
} |
if (rdev->flags & RADEON_IS_MOBILITY || rdev->flags & RADEON_IS_IGP) { |
uint16_t lcd_info = |
combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); |
if (lcd_info) { |
uint16_t lcd_ddc_info = |
combios_get_table_offset(dev, |
COMBIOS_LCD_DDC_INFO_TABLE); |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id(dev, |
ATOM_DEVICE_LCD1_SUPPORT, |
0), |
ATOM_DEVICE_LCD1_SUPPORT); |
if (lcd_ddc_info) { |
ddc_type = RBIOS8(lcd_ddc_info + 2); |
switch (ddc_type) { |
case DDC_MONID: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_GPIO_MONID); |
break; |
case DDC_DVI: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_GPIO_DVI_DDC); |
break; |
case DDC_VGA: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_GPIO_VGA_DDC); |
break; |
case DDC_CRT2: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_GPIO_CRT2_DDC); |
break; |
case DDC_LCD: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_LCD_GPIO_MASK); |
ddc_i2c.mask_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.mask_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.a_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.a_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.put_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.put_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.get_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.get_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
break; |
case DDC_GPIO: |
ddc_i2c = |
combios_setup_i2c_bus |
(RADEON_MDGPIO_EN_REG); |
ddc_i2c.mask_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.mask_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.a_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.a_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.put_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.put_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
ddc_i2c.get_clk_mask = |
RBIOS32(lcd_ddc_info + 3); |
ddc_i2c.get_data_mask = |
RBIOS32(lcd_ddc_info + 7); |
break; |
default: |
ddc_i2c.valid = false; |
break; |
} |
DRM_DEBUG("LCD DDC Info Table found!\n"); |
} else |
ddc_i2c.valid = false; |
radeon_add_legacy_connector(dev, |
5, |
ATOM_DEVICE_LCD1_SUPPORT, |
DRM_MODE_CONNECTOR_LVDS, |
&ddc_i2c); |
} |
} |
/* check TV table */ |
if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) { |
uint32_t tv_info = |
combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); |
if (tv_info) { |
if (RBIOS8(tv_info + 6) == 'T') { |
radeon_add_legacy_encoder(dev, |
radeon_get_encoder_id |
(dev, |
ATOM_DEVICE_TV1_SUPPORT, |
2), |
ATOM_DEVICE_TV1_SUPPORT); |
radeon_add_legacy_connector(dev, 6, |
ATOM_DEVICE_TV1_SUPPORT, |
DRM_MODE_CONNECTOR_SVIDEO, |
&ddc_i2c); |
} |
} |
} |
radeon_link_encoder_connector(dev); |
return true; |
} |
static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset) |
{ |
struct radeon_device *rdev = dev->dev_private; |
if (offset) { |
while (RBIOS16(offset)) { |
uint16_t cmd = ((RBIOS16(offset) & 0xe000) >> 13); |
uint32_t addr = (RBIOS16(offset) & 0x1fff); |
uint32_t val, and_mask, or_mask; |
uint32_t tmp; |
offset += 2; |
switch (cmd) { |
case 0: |
val = RBIOS32(offset); |
offset += 4; |
WREG32(addr, val); |
break; |
case 1: |
val = RBIOS32(offset); |
offset += 4; |
WREG32(addr, val); |
break; |
case 2: |
and_mask = RBIOS32(offset); |
offset += 4; |
or_mask = RBIOS32(offset); |
offset += 4; |
tmp = RREG32(addr); |
tmp &= and_mask; |
tmp |= or_mask; |
WREG32(addr, tmp); |
break; |
case 3: |
and_mask = RBIOS32(offset); |
offset += 4; |
or_mask = RBIOS32(offset); |
offset += 4; |
tmp = RREG32(addr); |
tmp &= and_mask; |
tmp |= or_mask; |
WREG32(addr, tmp); |
break; |
case 4: |
val = RBIOS16(offset); |
offset += 2; |
udelay(val); |
break; |
case 5: |
val = RBIOS16(offset); |
offset += 2; |
switch (addr) { |
case 8: |
while (val--) { |
if (! |
(RREG32_PLL |
(RADEON_CLK_PWRMGT_CNTL) & |
RADEON_MC_BUSY)) |
break; |
} |
break; |
case 9: |
while (val--) { |
if ((RREG32(RADEON_MC_STATUS) & |
RADEON_MC_IDLE)) |
break; |
} |
break; |
default: |
break; |
} |
break; |
default: |
break; |
} |
} |
} |
} |
static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) |
{ |
struct radeon_device *rdev = dev->dev_private; |
if (offset) { |
while (RBIOS8(offset)) { |
uint8_t cmd = ((RBIOS8(offset) & 0xc0) >> 6); |
uint8_t addr = (RBIOS8(offset) & 0x3f); |
uint32_t val, shift, tmp; |
uint32_t and_mask, or_mask; |
offset++; |
switch (cmd) { |
case 0: |
val = RBIOS32(offset); |
offset += 4; |
WREG32_PLL(addr, val); |
break; |
case 1: |
shift = RBIOS8(offset) * 8; |
offset++; |
and_mask = RBIOS8(offset) << shift; |
and_mask |= ~(0xff << shift); |
offset++; |
or_mask = RBIOS8(offset) << shift; |
offset++; |
tmp = RREG32_PLL(addr); |
tmp &= and_mask; |
tmp |= or_mask; |
WREG32_PLL(addr, tmp); |
break; |
case 2: |
case 3: |
tmp = 1000; |
switch (addr) { |
case 1: |
udelay(150); |
break; |
case 2: |
udelay(1000); |
break; |
case 3: |
while (tmp--) { |
if (! |
(RREG32_PLL |
(RADEON_CLK_PWRMGT_CNTL) & |
RADEON_MC_BUSY)) |
break; |
} |
break; |
case 4: |
while (tmp--) { |
if (RREG32_PLL |
(RADEON_CLK_PWRMGT_CNTL) & |
RADEON_DLL_READY) |
break; |
} |
break; |
case 5: |
tmp = |
RREG32_PLL(RADEON_CLK_PWRMGT_CNTL); |
if (tmp & RADEON_CG_NO1_DEBUG_0) { |
#if 0 |
uint32_t mclk_cntl = |
RREG32_PLL |
(RADEON_MCLK_CNTL); |
mclk_cntl &= 0xffff0000; |
/*mclk_cntl |= 0x00001111;*//* ??? */ |
WREG32_PLL(RADEON_MCLK_CNTL, |
mclk_cntl); |
udelay(10000); |
#endif |
WREG32_PLL |
(RADEON_CLK_PWRMGT_CNTL, |
tmp & |
~RADEON_CG_NO1_DEBUG_0); |
udelay(10000); |
} |
break; |
default: |
break; |
} |
break; |
default: |
break; |
} |
} |
} |
} |
static void combios_parse_ram_reset_table(struct drm_device *dev, |
uint16_t offset) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint32_t tmp; |
if (offset) { |
uint8_t val = RBIOS8(offset); |
while (val != 0xff) { |
offset++; |
if (val == 0x0f) { |
uint32_t channel_complete_mask; |
if (ASIC_IS_R300(rdev)) |
channel_complete_mask = |
R300_MEM_PWRUP_COMPLETE; |
else |
channel_complete_mask = |
RADEON_MEM_PWRUP_COMPLETE; |
tmp = 20000; |
while (tmp--) { |
if ((RREG32(RADEON_MEM_STR_CNTL) & |
channel_complete_mask) == |
channel_complete_mask) |
break; |
} |
} else { |
uint32_t or_mask = RBIOS16(offset); |
offset += 2; |
tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG); |
tmp &= RADEON_SDRAM_MODE_MASK; |
tmp |= or_mask; |
WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp); |
or_mask = val << 24; |
tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG); |
tmp &= RADEON_B3MEM_RESET_MASK; |
tmp |= or_mask; |
WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp); |
} |
val = RBIOS8(offset); |
} |
} |
} |
static uint32_t combios_detect_ram(struct drm_device *dev, int ram, |
int mem_addr_mapping) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint32_t mem_cntl; |
uint32_t mem_size; |
uint32_t addr = 0; |
mem_cntl = RREG32(RADEON_MEM_CNTL); |
if (mem_cntl & RV100_HALF_MODE) |
ram /= 2; |
mem_size = ram; |
mem_cntl &= ~(0xff << 8); |
mem_cntl |= (mem_addr_mapping & 0xff) << 8; |
WREG32(RADEON_MEM_CNTL, mem_cntl); |
RREG32(RADEON_MEM_CNTL); |
/* sdram reset ? */ |
/* something like this???? */ |
while (ram--) { |
addr = ram * 1024 * 1024; |
/* write to each page */ |
WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); |
WREG32(RADEON_MM_DATA, 0xdeadbeef); |
/* read back and verify */ |
WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); |
if (RREG32(RADEON_MM_DATA) != 0xdeadbeef) |
return 0; |
} |
return mem_size; |
} |
static void combios_write_ram_size(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint8_t rev; |
uint16_t offset; |
uint32_t mem_size = 0; |
uint32_t mem_cntl = 0; |
/* should do something smarter here I guess... */ |
if (rdev->flags & RADEON_IS_IGP) |
return; |
/* first check detected mem table */ |
offset = combios_get_table_offset(dev, COMBIOS_DETECTED_MEM_TABLE); |
if (offset) { |
rev = RBIOS8(offset); |
if (rev < 3) { |
mem_cntl = RBIOS32(offset + 1); |
mem_size = RBIOS16(offset + 5); |
if (((rdev->flags & RADEON_FAMILY_MASK) < CHIP_R200) && |
((dev->pdev->device != 0x515e) |
&& (dev->pdev->device != 0x5969))) |
WREG32(RADEON_MEM_CNTL, mem_cntl); |
} |
} |
if (!mem_size) { |
offset = |
combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); |
if (offset) { |
rev = RBIOS8(offset - 1); |
if (rev < 1) { |
if (((rdev->flags & RADEON_FAMILY_MASK) < |
CHIP_R200) |
&& ((dev->pdev->device != 0x515e) |
&& (dev->pdev->device != 0x5969))) { |
int ram = 0; |
int mem_addr_mapping = 0; |
while (RBIOS8(offset)) { |
ram = RBIOS8(offset); |
mem_addr_mapping = |
RBIOS8(offset + 1); |
if (mem_addr_mapping != 0x25) |
ram *= 2; |
mem_size = |
combios_detect_ram(dev, ram, |
mem_addr_mapping); |
if (mem_size) |
break; |
offset += 2; |
} |
} else |
mem_size = RBIOS8(offset); |
} else { |
mem_size = RBIOS8(offset); |
mem_size *= 2; /* convert to MB */ |
} |
} |
} |
mem_size *= (1024 * 1024); /* convert to bytes */ |
WREG32(RADEON_CONFIG_MEMSIZE, mem_size); |
} |
void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) |
{ |
uint16_t dyn_clk_info = |
combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); |
if (dyn_clk_info) |
combios_parse_pll_table(dev, dyn_clk_info); |
} |
void radeon_combios_asic_init(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint16_t table; |
/* port hardcoded mac stuff from radeonfb */ |
if (rdev->bios == NULL) |
return; |
/* ASIC INIT 1 */ |
table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_1_TABLE); |
if (table) |
combios_parse_mmio_table(dev, table); |
/* PLL INIT */ |
table = combios_get_table_offset(dev, COMBIOS_PLL_INIT_TABLE); |
if (table) |
combios_parse_pll_table(dev, table); |
/* ASIC INIT 2 */ |
table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_2_TABLE); |
if (table) |
combios_parse_mmio_table(dev, table); |
if (!(rdev->flags & RADEON_IS_IGP)) { |
/* ASIC INIT 4 */ |
table = |
combios_get_table_offset(dev, COMBIOS_ASIC_INIT_4_TABLE); |
if (table) |
combios_parse_mmio_table(dev, table); |
/* RAM RESET */ |
table = combios_get_table_offset(dev, COMBIOS_RAM_RESET_TABLE); |
if (table) |
combios_parse_ram_reset_table(dev, table); |
/* ASIC INIT 3 */ |
table = |
combios_get_table_offset(dev, COMBIOS_ASIC_INIT_3_TABLE); |
if (table) |
combios_parse_mmio_table(dev, table); |
/* write CONFIG_MEMSIZE */ |
combios_write_ram_size(dev); |
} |
/* DYN CLK 1 */ |
table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); |
if (table) |
combios_parse_pll_table(dev, table); |
} |
void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
uint32_t bios_0_scratch, bios_6_scratch, bios_7_scratch; |
bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); |
bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); |
bios_7_scratch = RREG32(RADEON_BIOS_7_SCRATCH); |
/* let the bios control the backlight */ |
bios_0_scratch &= ~RADEON_DRIVER_BRIGHTNESS_EN; |
/* tell the bios not to handle mode switching */ |
bios_6_scratch |= (RADEON_DISPLAY_SWITCHING_DIS | |
RADEON_ACC_MODE_CHANGE); |
/* tell the bios a driver is loaded */ |
bios_7_scratch |= RADEON_DRV_LOADED; |
WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch); |
WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); |
WREG32(RADEON_BIOS_7_SCRATCH, bios_7_scratch); |
} |
void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t bios_6_scratch; |
bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); |
if (lock) |
bios_6_scratch |= RADEON_DRIVER_CRITICAL; |
else |
bios_6_scratch &= ~RADEON_DRIVER_CRITICAL; |
WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); |
} |
void |
radeon_combios_connected_scratch_regs(struct drm_connector *connector, |
struct drm_encoder *encoder, |
bool connected) |
{ |
struct drm_device *dev = connector->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = |
to_radeon_connector(connector); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t bios_4_scratch = RREG32(RADEON_BIOS_4_SCRATCH); |
uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH); |
if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("TV1 connected\n"); |
/* fix me */ |
bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO; |
/*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP; */ |
bios_5_scratch |= RADEON_TV1_ON; |
bios_5_scratch |= RADEON_ACC_REQ_TV1; |
} else { |
DRM_DEBUG("TV1 disconnected\n"); |
bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK; |
bios_5_scratch &= ~RADEON_TV1_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_TV1; |
} |
} |
if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("LCD1 connected\n"); |
bios_4_scratch |= RADEON_LCD1_ATTACHED; |
bios_5_scratch |= RADEON_LCD1_ON; |
bios_5_scratch |= RADEON_ACC_REQ_LCD1; |
} else { |
DRM_DEBUG("LCD1 disconnected\n"); |
bios_4_scratch &= ~RADEON_LCD1_ATTACHED; |
bios_5_scratch &= ~RADEON_LCD1_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_LCD1; |
} |
} |
if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("CRT1 connected\n"); |
bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR; |
bios_5_scratch |= RADEON_CRT1_ON; |
bios_5_scratch |= RADEON_ACC_REQ_CRT1; |
} else { |
DRM_DEBUG("CRT1 disconnected\n"); |
bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK; |
bios_5_scratch &= ~RADEON_CRT1_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_CRT1; |
} |
} |
if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("CRT2 connected\n"); |
bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR; |
bios_5_scratch |= RADEON_CRT2_ON; |
bios_5_scratch |= RADEON_ACC_REQ_CRT2; |
} else { |
DRM_DEBUG("CRT2 disconnected\n"); |
bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK; |
bios_5_scratch &= ~RADEON_CRT2_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_CRT2; |
} |
} |
if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("DFP1 connected\n"); |
bios_4_scratch |= RADEON_DFP1_ATTACHED; |
bios_5_scratch |= RADEON_DFP1_ON; |
bios_5_scratch |= RADEON_ACC_REQ_DFP1; |
} else { |
DRM_DEBUG("DFP1 disconnected\n"); |
bios_4_scratch &= ~RADEON_DFP1_ATTACHED; |
bios_5_scratch &= ~RADEON_DFP1_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_DFP1; |
} |
} |
if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && |
(radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { |
if (connected) { |
DRM_DEBUG("DFP2 connected\n"); |
bios_4_scratch |= RADEON_DFP2_ATTACHED; |
bios_5_scratch |= RADEON_DFP2_ON; |
bios_5_scratch |= RADEON_ACC_REQ_DFP2; |
} else { |
DRM_DEBUG("DFP2 disconnected\n"); |
bios_4_scratch &= ~RADEON_DFP2_ATTACHED; |
bios_5_scratch &= ~RADEON_DFP2_ON; |
bios_5_scratch &= ~RADEON_ACC_REQ_DFP2; |
} |
} |
WREG32(RADEON_BIOS_4_SCRATCH, bios_4_scratch); |
WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch); |
} |
void |
radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH); |
if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { |
bios_5_scratch &= ~RADEON_TV1_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_TV1_CRTC_SHIFT); |
} |
if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { |
bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_CRT1_CRTC_SHIFT); |
} |
if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { |
bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_CRT2_CRTC_SHIFT); |
} |
if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { |
bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_LCD1_CRTC_SHIFT); |
} |
if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { |
bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_DFP1_CRTC_SHIFT); |
} |
if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { |
bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK; |
bios_5_scratch |= (crtc << RADEON_DFP2_CRTC_SHIFT); |
} |
WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch); |
} |
void |
radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); |
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { |
if (on) |
bios_6_scratch |= RADEON_TV_DPMS_ON; |
else |
bios_6_scratch &= ~RADEON_TV_DPMS_ON; |
} |
if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { |
if (on) |
bios_6_scratch |= RADEON_CRT_DPMS_ON; |
else |
bios_6_scratch &= ~RADEON_CRT_DPMS_ON; |
} |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (on) |
bios_6_scratch |= RADEON_LCD_DPMS_ON; |
else |
bios_6_scratch &= ~RADEON_LCD_DPMS_ON; |
} |
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
if (on) |
bios_6_scratch |= RADEON_DFP_DPMS_ON; |
else |
bios_6_scratch &= ~RADEON_DFP_DPMS_ON; |
} |
WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); |
} |
/drivers/video/drm/radeon/radeon_connectors.c |
---|
0,0 → 1,604 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include "drmP.h" |
//#include "drm_edid.h" |
#include "drm_crtc.h" |
#include "drm_crtc_helper.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
extern void |
radeon_combios_connected_scratch_regs(struct drm_connector *connector, |
struct drm_encoder *encoder, |
bool connected); |
extern void |
radeon_atombios_connected_scratch_regs(struct drm_connector *connector, |
struct drm_encoder *encoder, |
bool connected); |
static void |
radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) |
{ |
struct drm_device *dev = connector->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *best_encoder = NULL; |
struct drm_encoder *encoder = NULL; |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
struct drm_mode_object *obj; |
bool connected; |
int i; |
best_encoder = connector_funcs->best_encoder(connector); |
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
continue; |
encoder = obj_to_encoder(obj); |
if ((encoder == best_encoder) && (status == connector_status_connected)) |
connected = true; |
else |
connected = false; |
if (rdev->is_atom_bios) |
radeon_atombios_connected_scratch_regs(connector, encoder, connected); |
else |
radeon_combios_connected_scratch_regs(connector, encoder, connected); |
} |
} |
struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) |
{ |
int enc_id = connector->encoder_ids[0]; |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
/* pick the encoder ids */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
} |
static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_display_mode *mode = NULL; |
struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; |
if (native_mode->panel_xres != 0 && |
native_mode->panel_yres != 0 && |
native_mode->dotclock != 0) { |
mode = drm_mode_create(dev); |
mode->hdisplay = native_mode->panel_xres; |
mode->vdisplay = native_mode->panel_yres; |
mode->htotal = mode->hdisplay + native_mode->hblank; |
mode->hsync_start = mode->hdisplay + native_mode->hoverplus; |
mode->hsync_end = mode->hsync_start + native_mode->hsync_width; |
mode->vtotal = mode->vdisplay + native_mode->vblank; |
mode->vsync_start = mode->vdisplay + native_mode->voverplus; |
mode->vsync_end = mode->vsync_start + native_mode->vsync_width; |
mode->clock = native_mode->dotclock; |
mode->flags = 0; |
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; |
drm_mode_set_name(mode); |
DRM_DEBUG("Adding native panel mode %s\n", mode->name); |
} |
return mode; |
} |
int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, |
uint64_t val) |
{ |
return 0; |
} |
static int radeon_lvds_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
int ret = 0; |
struct drm_display_mode *mode; |
if (radeon_connector->ddc_bus) { |
ret = radeon_ddc_get_modes(radeon_connector); |
if (ret > 0) { |
return ret; |
} |
} |
encoder = radeon_best_single_encoder(connector); |
if (!encoder) |
return 0; |
/* we have no EDID modes */ |
mode = radeon_fp_native_mode(encoder); |
if (mode) { |
ret = 1; |
drm_mode_probed_add(connector, mode); |
} |
return ret; |
} |
static int radeon_lvds_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
return MODE_OK; |
} |
static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) |
{ |
enum drm_connector_status ret = connector_status_connected; |
/* check acpi lid status ??? */ |
radeon_connector_update_scratch_regs(connector, ret); |
return ret; |
} |
static void radeon_connector_destroy(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->ddc_bus) |
radeon_i2c_destroy(radeon_connector->ddc_bus); |
kfree(radeon_connector->con_priv); |
// drm_sysfs_connector_remove(connector); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { |
.get_modes = radeon_lvds_get_modes, |
.mode_valid = radeon_lvds_mode_valid, |
.best_encoder = radeon_best_single_encoder, |
}; |
struct drm_connector_funcs radeon_lvds_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_lvds_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.destroy = radeon_connector_destroy, |
.set_property = radeon_connector_set_property, |
}; |
static int radeon_vga_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
ret = radeon_ddc_get_modes(radeon_connector); |
return ret; |
} |
static int radeon_vga_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
return MODE_OK; |
} |
static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
struct drm_encoder_helper_funcs *encoder_funcs; |
bool dret; |
enum drm_connector_status ret = connector_status_disconnected; |
radeon_i2c_do_lock(radeon_connector, 1); |
dret = radeon_ddc_probe(radeon_connector); |
radeon_i2c_do_lock(radeon_connector, 0); |
if (dret) |
ret = connector_status_connected; |
else { |
/* if EDID fails to a load detect */ |
encoder = radeon_best_single_encoder(connector); |
if (!encoder) |
ret = connector_status_disconnected; |
else { |
encoder_funcs = encoder->helper_private; |
ret = encoder_funcs->detect(encoder, connector); |
} |
} |
radeon_connector_update_scratch_regs(connector, ret); |
return ret; |
} |
struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { |
.get_modes = radeon_vga_get_modes, |
.mode_valid = radeon_vga_mode_valid, |
.best_encoder = radeon_best_single_encoder, |
}; |
struct drm_connector_funcs radeon_vga_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_vga_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.destroy = radeon_connector_destroy, |
.set_property = radeon_connector_set_property, |
}; |
static int radeon_dvi_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
ret = radeon_ddc_get_modes(radeon_connector); |
/* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */ |
radeon_connector_update_scratch_regs(connector, connector_status_connected); |
return ret; |
} |
static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
struct drm_encoder_helper_funcs *encoder_funcs; |
struct drm_mode_object *obj; |
int i; |
enum drm_connector_status ret = connector_status_disconnected; |
bool dret; |
radeon_i2c_do_lock(radeon_connector, 1); |
dret = radeon_ddc_probe(radeon_connector); |
radeon_i2c_do_lock(radeon_connector, 0); |
if (dret) |
ret = connector_status_connected; |
else { |
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
continue; |
encoder = obj_to_encoder(obj); |
encoder_funcs = encoder->helper_private; |
if (encoder_funcs->detect) { |
ret = encoder_funcs->detect(encoder, connector); |
if (ret == connector_status_connected) { |
radeon_connector->use_digital = 0; |
break; |
} |
} |
} |
} |
/* updated in get modes as well since we need to know if it's analog or digital */ |
radeon_connector_update_scratch_regs(connector, ret); |
return ret; |
} |
/* okay need to be smart in here about which encoder to pick */ |
struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) |
{ |
int enc_id = connector->encoder_ids[0]; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
int i; |
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
continue; |
encoder = obj_to_encoder(obj); |
if (radeon_connector->use_digital) { |
if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) |
return encoder; |
} else { |
if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || |
encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) |
return encoder; |
} |
} |
/* see if we have a default encoder TODO */ |
/* then check use digitial */ |
/* pick the first one */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
} |
struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { |
.get_modes = radeon_dvi_get_modes, |
.mode_valid = radeon_vga_mode_valid, |
.best_encoder = radeon_dvi_encoder, |
}; |
struct drm_connector_funcs radeon_dvi_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_dvi_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_connector_set_property, |
.destroy = radeon_connector_destroy, |
}; |
void |
radeon_add_atom_connector(struct drm_device *dev, |
uint32_t connector_id, |
uint32_t supported_device, |
int connector_type, |
struct radeon_i2c_bus_rec *i2c_bus, |
bool linkb, |
uint32_t igp_lane_info) |
{ |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
struct radeon_connector_atom_dig *radeon_dig_connector; |
uint32_t subpixel_order = SubPixelNone; |
/* fixme - tv/cv/din */ |
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || |
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) || |
(connector_type == DRM_MODE_CONNECTOR_Composite) || |
(connector_type == DRM_MODE_CONNECTOR_9PinDIN)) |
return; |
/* see if we already added it */ |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->connector_id == connector_id) { |
radeon_connector->devices |= supported_device; |
return; |
} |
} |
radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); |
if (!radeon_connector) |
return; |
connector = &radeon_connector->base; |
radeon_connector->connector_id = connector_id; |
radeon_connector->devices = supported_device; |
switch (connector_type) { |
case DRM_MODE_CONNECTOR_VGA: |
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
break; |
case DRM_MODE_CONNECTOR_DVIA: |
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
break; |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_DVID: |
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); |
if (!radeon_dig_connector) |
goto failed; |
radeon_dig_connector->linkb = linkb; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
case DRM_MODE_CONNECTOR_HDMIA: |
case DRM_MODE_CONNECTOR_HDMIB: |
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); |
if (!radeon_dig_connector) |
goto failed; |
radeon_dig_connector->linkb = linkb; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
case DRM_MODE_CONNECTOR_DisplayPort: |
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); |
if (!radeon_dig_connector) |
goto failed; |
radeon_dig_connector->linkb = linkb; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
case DRM_MODE_CONNECTOR_SVIDEO: |
case DRM_MODE_CONNECTOR_Composite: |
case DRM_MODE_CONNECTOR_9PinDIN: |
break; |
case DRM_MODE_CONNECTOR_LVDS: |
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); |
if (!radeon_dig_connector) |
goto failed; |
radeon_dig_connector->linkb = linkb; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
} |
connector->display_info.subpixel_order = subpixel_order; |
// drm_sysfs_connector_add(connector); |
return; |
failed: |
if (radeon_connector->ddc_bus) |
radeon_i2c_destroy(radeon_connector->ddc_bus); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
void |
radeon_add_legacy_connector(struct drm_device *dev, |
uint32_t connector_id, |
uint32_t supported_device, |
int connector_type, |
struct radeon_i2c_bus_rec *i2c_bus) |
{ |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
uint32_t subpixel_order = SubPixelNone; |
/* fixme - tv/cv/din */ |
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || |
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) || |
(connector_type == DRM_MODE_CONNECTOR_Composite) || |
(connector_type == DRM_MODE_CONNECTOR_9PinDIN)) |
return; |
/* see if we already added it */ |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->connector_id == connector_id) { |
radeon_connector->devices |= supported_device; |
return; |
} |
} |
radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); |
if (!radeon_connector) |
return; |
connector = &radeon_connector->base; |
radeon_connector->connector_id = connector_id; |
radeon_connector->devices = supported_device; |
switch (connector_type) { |
case DRM_MODE_CONNECTOR_VGA: |
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
break; |
case DRM_MODE_CONNECTOR_DVIA: |
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
break; |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_DVID: |
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
case DRM_MODE_CONNECTOR_SVIDEO: |
case DRM_MODE_CONNECTOR_Composite: |
case DRM_MODE_CONNECTOR_9PinDIN: |
break; |
case DRM_MODE_CONNECTOR_LVDS: |
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); |
if (i2c_bus->valid) { |
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); |
if (!radeon_connector->ddc_bus) |
goto failed; |
} |
subpixel_order = SubPixelHorizontalRGB; |
break; |
} |
connector->display_info.subpixel_order = subpixel_order; |
// drm_sysfs_connector_add(connector); |
return; |
failed: |
if (radeon_connector->ddc_bus) |
radeon_i2c_destroy(radeon_connector->ddc_bus); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
/drivers/video/drm/radeon/radeon_device.c |
---|
26,7 → 26,8 |
* Jerome Glisse |
*/ |
//#include <linux/console.h> |
//#include <drm/drmP.h> |
#include <drmP.h> |
//#include <drm/drm_crtc_helper.h> |
#include "radeon_drm.h" |
#include "radeon_reg.h" |
36,9 → 37,14 |
#include <syscall.h> |
int radeon_modeset = -1; |
int radeon_dynclks = -1; |
int radeon_agpmode = -1; |
int radeon_r4xx_atom = 0; |
int radeon_agpmode = 0; |
int radeon_vram_limit = 0; |
int radeon_gart_size = 512; /* default gart size */ |
int radeon_benchmarking = 0; |
int radeon_connector_table = 0; |
/* |
896,3 → 902,37 |
return pci_resource_len(dev->pdev, resource); |
} |
uint32_t __div64_32(uint64_t *n, uint32_t base) |
{ |
uint64_t rem = *n; |
uint64_t b = base; |
uint64_t res, d = 1; |
uint32_t high = rem >> 32; |
/* Reduce the thing a bit first */ |
res = 0; |
if (high >= base) { |
high /= base; |
res = (uint64_t) high << 32; |
rem -= (uint64_t) (high*base) << 32; |
} |
while ((int64_t)b > 0 && b < rem) { |
b = b+b; |
d = d+d; |
} |
do { |
if (rem >= b) { |
rem -= b; |
res += d; |
} |
b >>= 1; |
d >>= 1; |
} while (d); |
*n = res; |
return rem; |
} |
/drivers/video/drm/radeon/radeon_display.c |
---|
0,0 → 1,697 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
#include "atom.h" |
//#include <asm/div64.h> |
#include "drm_crtc_helper.h" |
#include "drm_edid.h" |
static int radeon_ddc_dump(struct drm_connector *connector); |
static void avivo_crtc_load_lut(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int i; |
DRM_DEBUG("%d\n", radeon_crtc->crtc_id); |
WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); |
WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); |
WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); |
WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); |
WREG32(AVIVO_DC_LUT_RW_SELECT, radeon_crtc->crtc_id); |
WREG32(AVIVO_DC_LUT_RW_MODE, 0); |
WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); |
WREG8(AVIVO_DC_LUT_RW_INDEX, 0); |
for (i = 0; i < 256; i++) { |
WREG32(AVIVO_DC_LUT_30_COLOR, |
(radeon_crtc->lut_r[i] << 20) | |
(radeon_crtc->lut_g[i] << 10) | |
(radeon_crtc->lut_b[i] << 0)); |
} |
WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); |
} |
static void legacy_crtc_load_lut(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int i; |
uint32_t dac2_cntl; |
dac2_cntl = RREG32(RADEON_DAC_CNTL2); |
if (radeon_crtc->crtc_id == 0) |
dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; |
else |
dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL; |
WREG32(RADEON_DAC_CNTL2, dac2_cntl); |
WREG8(RADEON_PALETTE_INDEX, 0); |
for (i = 0; i < 256; i++) { |
WREG32(RADEON_PALETTE_30_DATA, |
(radeon_crtc->lut_r[i] << 20) | |
(radeon_crtc->lut_g[i] << 10) | |
(radeon_crtc->lut_b[i] << 0)); |
} |
} |
void radeon_crtc_load_lut(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
if (!crtc->enabled) |
return; |
if (ASIC_IS_AVIVO(rdev)) |
avivo_crtc_load_lut(crtc); |
else |
legacy_crtc_load_lut(crtc); |
} |
/** Sets the color ramps on behalf of RandR */ |
void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, |
u16 blue, int regno) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
if (regno == 0) |
DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id); |
radeon_crtc->lut_r[regno] = red >> 6; |
radeon_crtc->lut_g[regno] = green >> 6; |
radeon_crtc->lut_b[regno] = blue >> 6; |
} |
static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, |
u16 *blue, uint32_t size) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
int i, j; |
if (size != 256) { |
return; |
} |
if (crtc->fb == NULL) { |
return; |
} |
if (crtc->fb->depth == 16) { |
for (i = 0; i < 64; i++) { |
if (i <= 31) { |
for (j = 0; j < 8; j++) { |
radeon_crtc->lut_r[i * 8 + j] = red[i] >> 6; |
radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 6; |
} |
} |
for (j = 0; j < 4; j++) |
radeon_crtc->lut_g[i * 4 + j] = green[i] >> 6; |
} |
} else { |
for (i = 0; i < 256; i++) { |
radeon_crtc->lut_r[i] = red[i] >> 6; |
radeon_crtc->lut_g[i] = green[i] >> 6; |
radeon_crtc->lut_b[i] = blue[i] >> 6; |
} |
} |
radeon_crtc_load_lut(crtc); |
} |
static void radeon_crtc_destroy(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
if (radeon_crtc->mode_set.mode) { |
drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode); |
} |
drm_crtc_cleanup(crtc); |
kfree(radeon_crtc); |
} |
static const struct drm_crtc_funcs radeon_crtc_funcs = { |
// .cursor_set = radeon_crtc_cursor_set, |
// .cursor_move = radeon_crtc_cursor_move, |
.gamma_set = radeon_crtc_gamma_set, |
// .set_config = drm_crtc_helper_set_config, |
.destroy = radeon_crtc_destroy, |
}; |
static void radeon_crtc_init(struct drm_device *dev, int index) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc; |
int i; |
radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); |
if (radeon_crtc == NULL) |
return; |
drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs); |
drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); |
radeon_crtc->crtc_id = index; |
radeon_crtc->mode_set.crtc = &radeon_crtc->base; |
radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); |
radeon_crtc->mode_set.num_connectors = 0; |
for (i = 0; i < 256; i++) { |
radeon_crtc->lut_r[i] = i << 2; |
radeon_crtc->lut_g[i] = i << 2; |
radeon_crtc->lut_b[i] = i << 2; |
} |
if (rdev->is_atom_bios && (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)) |
radeon_atombios_init_crtc(dev, radeon_crtc); |
else |
radeon_legacy_init_crtc(dev, radeon_crtc); |
} |
static const char *encoder_names[34] = { |
"NONE", |
"INTERNAL_LVDS", |
"INTERNAL_TMDS1", |
"INTERNAL_TMDS2", |
"INTERNAL_DAC1", |
"INTERNAL_DAC2", |
"INTERNAL_SDVOA", |
"INTERNAL_SDVOB", |
"SI170B", |
"CH7303", |
"CH7301", |
"INTERNAL_DVO1", |
"EXTERNAL_SDVOA", |
"EXTERNAL_SDVOB", |
"TITFP513", |
"INTERNAL_LVTM1", |
"VT1623", |
"HDMI_SI1930", |
"HDMI_INTERNAL", |
"INTERNAL_KLDSCP_TMDS1", |
"INTERNAL_KLDSCP_DVO1", |
"INTERNAL_KLDSCP_DAC1", |
"INTERNAL_KLDSCP_DAC2", |
"SI178", |
"MVPU_FPGA", |
"INTERNAL_DDI", |
"VT1625", |
"HDMI_SI1932", |
"DP_AN9801", |
"DP_DP501", |
"INTERNAL_UNIPHY", |
"INTERNAL_KLDSCP_LVTMA", |
"INTERNAL_UNIPHY1", |
"INTERNAL_UNIPHY2", |
}; |
static const char *connector_names[13] = { |
"Unknown", |
"VGA", |
"DVI-I", |
"DVI-D", |
"DVI-A", |
"Composite", |
"S-video", |
"LVDS", |
"Component", |
"DIN", |
"DisplayPort", |
"HDMI-A", |
"HDMI-B", |
}; |
static void radeon_print_display_setup(struct drm_device *dev) |
{ |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
uint32_t devices; |
int i = 0; |
DRM_INFO("Radeon Display Connectors\n"); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
radeon_connector = to_radeon_connector(connector); |
DRM_INFO("Connector %d:\n", i); |
DRM_INFO(" %s\n", connector_names[connector->connector_type]); |
if (radeon_connector->ddc_bus) |
DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
radeon_connector->ddc_bus->rec.mask_clk_reg, |
radeon_connector->ddc_bus->rec.mask_data_reg, |
radeon_connector->ddc_bus->rec.a_clk_reg, |
radeon_connector->ddc_bus->rec.a_data_reg, |
radeon_connector->ddc_bus->rec.put_clk_reg, |
radeon_connector->ddc_bus->rec.put_data_reg, |
radeon_connector->ddc_bus->rec.get_clk_reg, |
radeon_connector->ddc_bus->rec.get_data_reg); |
DRM_INFO(" Encoders:\n"); |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
radeon_encoder = to_radeon_encoder(encoder); |
devices = radeon_encoder->devices & radeon_connector->devices; |
if (devices) { |
if (devices & ATOM_DEVICE_CRT1_SUPPORT) |
DRM_INFO(" CRT1: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_CRT2_SUPPORT) |
DRM_INFO(" CRT2: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_LCD1_SUPPORT) |
DRM_INFO(" LCD1: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_DFP1_SUPPORT) |
DRM_INFO(" DFP1: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_DFP2_SUPPORT) |
DRM_INFO(" DFP2: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_DFP3_SUPPORT) |
DRM_INFO(" DFP3: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_DFP4_SUPPORT) |
DRM_INFO(" DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_DFP5_SUPPORT) |
DRM_INFO(" DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_TV1_SUPPORT) |
DRM_INFO(" TV1: %s\n", encoder_names[radeon_encoder->encoder_id]); |
if (devices & ATOM_DEVICE_CV_SUPPORT) |
DRM_INFO(" CV: %s\n", encoder_names[radeon_encoder->encoder_id]); |
} |
} |
i++; |
} |
} |
bool radeon_setup_enc_conn(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct drm_connector *drm_connector; |
bool ret = false; |
if (rdev->bios) { |
if (rdev->is_atom_bios) { |
if (rdev->family >= CHIP_R600) |
ret = radeon_get_atom_connector_info_from_object_table(dev); |
else |
ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); |
} else |
ret = radeon_get_legacy_connector_info_from_bios(dev); |
} else { |
if (!ASIC_IS_AVIVO(rdev)) |
ret = radeon_get_legacy_connector_info_from_table(dev); |
} |
if (ret) { |
radeon_print_display_setup(dev); |
list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) |
radeon_ddc_dump(drm_connector); |
} |
return ret; |
} |
int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) |
{ |
struct edid *edid; |
int ret = 0; |
if (!radeon_connector->ddc_bus) |
return -1; |
radeon_i2c_do_lock(radeon_connector, 1); |
edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
radeon_i2c_do_lock(radeon_connector, 0); |
if (edid) { |
/* update digital bits here */ |
if (edid->input & DRM_EDID_INPUT_DIGITAL) |
radeon_connector->use_digital = 1; |
else |
radeon_connector->use_digital = 0; |
drm_mode_connector_update_edid_property(&radeon_connector->base, edid); |
ret = drm_add_edid_modes(&radeon_connector->base, edid); |
kfree(edid); |
return ret; |
} |
drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); |
return -1; |
} |
static int radeon_ddc_dump(struct drm_connector *connector) |
{ |
struct edid *edid; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret = 0; |
if (!radeon_connector->ddc_bus) |
return -1; |
radeon_i2c_do_lock(radeon_connector, 1); |
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); |
radeon_i2c_do_lock(radeon_connector, 0); |
if (edid) { |
kfree(edid); |
} |
return ret; |
} |
static inline uint32_t radeon_div(uint64_t n, uint32_t d) |
{ |
uint64_t mod; |
n += d / 2; |
mod = do_div(n, d); |
return n; |
} |
void radeon_compute_pll(struct radeon_pll *pll, |
uint64_t freq, |
uint32_t *dot_clock_p, |
uint32_t *fb_div_p, |
uint32_t *frac_fb_div_p, |
uint32_t *ref_div_p, |
uint32_t *post_div_p, |
int flags) |
{ |
uint32_t min_ref_div = pll->min_ref_div; |
uint32_t max_ref_div = pll->max_ref_div; |
uint32_t min_fractional_feed_div = 0; |
uint32_t max_fractional_feed_div = 0; |
uint32_t best_vco = pll->best_vco; |
uint32_t best_post_div = 1; |
uint32_t best_ref_div = 1; |
uint32_t best_feedback_div = 1; |
uint32_t best_frac_feedback_div = 0; |
uint32_t best_freq = -1; |
uint32_t best_error = 0xffffffff; |
uint32_t best_vco_diff = 1; |
uint32_t post_div; |
DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); |
freq = freq * 1000; |
if (flags & RADEON_PLL_USE_REF_DIV) |
min_ref_div = max_ref_div = pll->reference_div; |
else { |
while (min_ref_div < max_ref_div-1) { |
uint32_t mid = (min_ref_div + max_ref_div) / 2; |
uint32_t pll_in = pll->reference_freq / mid; |
if (pll_in < pll->pll_in_min) |
max_ref_div = mid; |
else if (pll_in > pll->pll_in_max) |
min_ref_div = mid; |
else |
break; |
} |
} |
if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
min_fractional_feed_div = pll->min_frac_feedback_div; |
max_fractional_feed_div = pll->max_frac_feedback_div; |
} |
for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { |
uint32_t ref_div; |
if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) |
continue; |
/* legacy radeons only have a few post_divs */ |
if (flags & RADEON_PLL_LEGACY) { |
if ((post_div == 5) || |
(post_div == 7) || |
(post_div == 9) || |
(post_div == 10) || |
(post_div == 11) || |
(post_div == 13) || |
(post_div == 14) || |
(post_div == 15)) |
continue; |
} |
for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) { |
uint32_t feedback_div, current_freq = 0, error, vco_diff; |
uint32_t pll_in = pll->reference_freq / ref_div; |
uint32_t min_feed_div = pll->min_feedback_div; |
uint32_t max_feed_div = pll->max_feedback_div + 1; |
if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max) |
continue; |
while (min_feed_div < max_feed_div) { |
uint32_t vco; |
uint32_t min_frac_feed_div = min_fractional_feed_div; |
uint32_t max_frac_feed_div = max_fractional_feed_div + 1; |
uint32_t frac_feedback_div; |
uint64_t tmp; |
feedback_div = (min_feed_div + max_feed_div) / 2; |
tmp = (uint64_t)pll->reference_freq * feedback_div; |
vco = radeon_div(tmp, ref_div); |
if (vco < pll->pll_out_min) { |
min_feed_div = feedback_div + 1; |
continue; |
} else if (vco > pll->pll_out_max) { |
max_feed_div = feedback_div; |
continue; |
} |
while (min_frac_feed_div < max_frac_feed_div) { |
frac_feedback_div = (min_frac_feed_div + max_frac_feed_div) / 2; |
tmp = (uint64_t)pll->reference_freq * 10000 * feedback_div; |
tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; |
current_freq = radeon_div(tmp, ref_div * post_div); |
error = abs(current_freq - freq); |
vco_diff = abs(vco - best_vco); |
if ((best_vco == 0 && error < best_error) || |
(best_vco != 0 && |
(error < best_error - 100 || |
(abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) { |
best_post_div = post_div; |
best_ref_div = ref_div; |
best_feedback_div = feedback_div; |
best_frac_feedback_div = frac_feedback_div; |
best_freq = current_freq; |
best_error = error; |
best_vco_diff = vco_diff; |
} else if (current_freq == freq) { |
if (best_freq == -1) { |
best_post_div = post_div; |
best_ref_div = ref_div; |
best_feedback_div = feedback_div; |
best_frac_feedback_div = frac_feedback_div; |
best_freq = current_freq; |
best_error = error; |
best_vco_diff = vco_diff; |
} else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || |
((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || |
((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || |
((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || |
((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || |
((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { |
best_post_div = post_div; |
best_ref_div = ref_div; |
best_feedback_div = feedback_div; |
best_frac_feedback_div = frac_feedback_div; |
best_freq = current_freq; |
best_error = error; |
best_vco_diff = vco_diff; |
} |
} |
if (current_freq < freq) |
min_frac_feed_div = frac_feedback_div + 1; |
else |
max_frac_feed_div = frac_feedback_div; |
} |
if (current_freq < freq) |
min_feed_div = feedback_div + 1; |
else |
max_feed_div = feedback_div; |
} |
} |
} |
*dot_clock_p = best_freq / 10000; |
*fb_div_p = best_feedback_div; |
*frac_fb_div_p = best_frac_feedback_div; |
*ref_div_p = best_ref_div; |
*post_div_p = best_post_div; |
} |
#if 0 |
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) |
{ |
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
struct drm_device *dev = fb->dev; |
if (fb->fbdev) |
radeonfb_remove(dev, fb); |
// if (radeon_fb->obj) { |
// radeon_gem_object_unpin(radeon_fb->obj); |
// mutex_lock(&dev->struct_mutex); |
// drm_gem_object_unreference(radeon_fb->obj); |
// mutex_unlock(&dev->struct_mutex); |
// } |
drm_framebuffer_cleanup(fb); |
kfree(radeon_fb); |
} |
static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb, |
struct drm_file *file_priv, |
unsigned int *handle) |
{ |
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
return NULL; |
// return drm_gem_handle_create(file_priv, radeon_fb->obj, handle); |
} |
static const struct drm_framebuffer_funcs radeon_fb_funcs = { |
.destroy = radeon_user_framebuffer_destroy, |
.create_handle = radeon_user_framebuffer_create_handle, |
}; |
struct drm_framebuffer * |
radeon_framebuffer_create(struct drm_device *dev, |
struct drm_mode_fb_cmd *mode_cmd, |
struct drm_gem_object *obj) |
{ |
struct radeon_framebuffer *radeon_fb; |
radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); |
if (radeon_fb == NULL) { |
return NULL; |
} |
drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); |
drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); |
radeon_fb->obj = obj; |
return &radeon_fb->base; |
} |
static struct drm_framebuffer * |
radeon_user_framebuffer_create(struct drm_device *dev, |
struct drm_file *file_priv, |
struct drm_mode_fb_cmd *mode_cmd) |
{ |
struct drm_gem_object *obj; |
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); |
return radeon_framebuffer_create(dev, mode_cmd, obj); |
} |
static const struct drm_mode_config_funcs radeon_mode_funcs = { |
.fb_create = radeon_user_framebuffer_create, |
.fb_changed = radeonfb_probe, |
}; |
#endif |
int radeon_modeset_init(struct radeon_device *rdev) |
{ |
int num_crtc = 2, i; |
int ret; |
drm_mode_config_init(rdev->ddev); |
rdev->mode_info.mode_config_initialized = true; |
// rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs; |
if (ASIC_IS_AVIVO(rdev)) { |
rdev->ddev->mode_config.max_width = 8192; |
rdev->ddev->mode_config.max_height = 8192; |
} else { |
rdev->ddev->mode_config.max_width = 4096; |
rdev->ddev->mode_config.max_height = 4096; |
} |
rdev->ddev->mode_config.fb_base = rdev->mc.aper_base; |
/* allocate crtcs - TODO single crtc */ |
for (i = 0; i < num_crtc; i++) { |
radeon_crtc_init(rdev->ddev, i); |
} |
/* okay we should have all the bios connectors */ |
ret = radeon_setup_enc_conn(rdev->ddev); |
if (!ret) { |
return ret; |
} |
drm_helper_initial_config(rdev->ddev); |
return 0; |
} |
void radeon_modeset_fini(struct radeon_device *rdev) |
{ |
if (rdev->mode_info.mode_config_initialized) { |
drm_mode_config_cleanup(rdev->ddev); |
rdev->mode_info.mode_config_initialized = false; |
} |
} |
void radeon_init_disp_bandwidth(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct drm_display_mode *modes[2]; |
int pixel_bytes[2]; |
struct drm_crtc *crtc; |
pixel_bytes[0] = pixel_bytes[1] = 0; |
modes[0] = modes[1] = NULL; |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
if (crtc->enabled && crtc->fb) { |
modes[radeon_crtc->crtc_id] = &crtc->mode; |
pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8; |
} |
} |
if (ASIC_IS_AVIVO(rdev)) { |
radeon_init_disp_bw_avivo(dev, |
modes[0], |
pixel_bytes[0], |
modes[1], |
pixel_bytes[1]); |
} else { |
radeon_init_disp_bw_legacy(dev, |
modes[0], |
pixel_bytes[0], |
modes[1], |
pixel_bytes[1]); |
} |
} |
/drivers/video/drm/radeon/radeon_fixed.h |
---|
0,0 → 1,50 |
/* |
* Copyright 2009 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
*/ |
#ifndef RADEON_FIXED_H |
#define RADEON_FIXED_H |
typedef union rfixed { |
u32 full; |
} fixed20_12; |
#define rfixed_const(A) (u32)(((A) << 12))/* + ((B + 0.000122)*4096)) */ |
#define rfixed_const_half(A) (u32)(((A) << 12) + 2048) |
#define rfixed_const_666(A) (u32)(((A) << 12) + 2731) |
#define rfixed_const_8(A) (u32)(((A) << 12) + 3277) |
#define rfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12) |
#define fixed_init(A) { .full = rfixed_const((A)) } |
#define fixed_init_half(A) { .full = rfixed_const_half((A)) } |
#define rfixed_trunc(A) ((A).full >> 12) |
static inline u32 rfixed_div(fixed20_12 A, fixed20_12 B) |
{ |
u64 tmp = ((u64)A.full << 13); |
do_div(tmp, B.full); |
tmp += 1; |
tmp /= 2; |
return lower_32_bits(tmp); |
} |
#endif |
/drivers/video/drm/radeon/radeon_i2c.c |
---|
0,0 → 1,209 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
/** |
* radeon_ddc_probe |
* |
*/ |
bool radeon_ddc_probe(struct radeon_connector *radeon_connector) |
{ |
u8 out_buf[] = { 0x0, 0x0}; |
u8 buf[2]; |
int ret; |
struct i2c_msg msgs[] = { |
{ |
.addr = 0x50, |
.flags = 0, |
.len = 1, |
.buf = out_buf, |
}, |
{ |
.addr = 0x50, |
.flags = I2C_M_RD, |
.len = 1, |
.buf = buf, |
} |
}; |
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); |
if (ret == 2) |
return true; |
return false; |
} |
void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) |
{ |
struct radeon_device *rdev = radeon_connector->base.dev->dev_private; |
uint32_t temp; |
struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; |
/* RV410 appears to have a bug where the hw i2c in reset |
* holds the i2c port in a bad state - switch hw i2c away before |
* doing DDC - do this for all r200s/r300s/r400s for safety sake |
*/ |
if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) { |
if (rec->a_clk_reg == RADEON_GPIO_MONID) { |
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1))); |
} else { |
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3))); |
} |
} |
if (lock_state) { |
temp = RREG32(rec->a_clk_reg); |
temp &= ~(rec->a_clk_mask); |
WREG32(rec->a_clk_reg, temp); |
temp = RREG32(rec->a_data_reg); |
temp &= ~(rec->a_data_mask); |
WREG32(rec->a_data_reg, temp); |
} |
temp = RREG32(rec->mask_clk_reg); |
if (lock_state) |
temp |= rec->mask_clk_mask; |
else |
temp &= ~rec->mask_clk_mask; |
WREG32(rec->mask_clk_reg, temp); |
temp = RREG32(rec->mask_clk_reg); |
temp = RREG32(rec->mask_data_reg); |
if (lock_state) |
temp |= rec->mask_data_mask; |
else |
temp &= ~rec->mask_data_mask; |
WREG32(rec->mask_data_reg, temp); |
temp = RREG32(rec->mask_data_reg); |
} |
static int get_clock(void *i2c_priv) |
{ |
struct radeon_i2c_chan *i2c = i2c_priv; |
struct radeon_device *rdev = i2c->dev->dev_private; |
struct radeon_i2c_bus_rec *rec = &i2c->rec; |
uint32_t val; |
val = RREG32(rec->get_clk_reg); |
val &= rec->get_clk_mask; |
return (val != 0); |
} |
static int get_data(void *i2c_priv) |
{ |
struct radeon_i2c_chan *i2c = i2c_priv; |
struct radeon_device *rdev = i2c->dev->dev_private; |
struct radeon_i2c_bus_rec *rec = &i2c->rec; |
uint32_t val; |
val = RREG32(rec->get_data_reg); |
val &= rec->get_data_mask; |
return (val != 0); |
} |
static void set_clock(void *i2c_priv, int clock) |
{ |
struct radeon_i2c_chan *i2c = i2c_priv; |
struct radeon_device *rdev = i2c->dev->dev_private; |
struct radeon_i2c_bus_rec *rec = &i2c->rec; |
uint32_t val; |
val = RREG32(rec->put_clk_reg) & (uint32_t)~(rec->put_clk_mask); |
val |= clock ? 0 : rec->put_clk_mask; |
WREG32(rec->put_clk_reg, val); |
} |
static void set_data(void *i2c_priv, int data) |
{ |
struct radeon_i2c_chan *i2c = i2c_priv; |
struct radeon_device *rdev = i2c->dev->dev_private; |
struct radeon_i2c_bus_rec *rec = &i2c->rec; |
uint32_t val; |
val = RREG32(rec->put_data_reg) & (uint32_t)~(rec->put_data_mask); |
val |= data ? 0 : rec->put_data_mask; |
WREG32(rec->put_data_reg, val); |
} |
struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, |
struct radeon_i2c_bus_rec *rec, |
const char *name) |
{ |
struct radeon_i2c_chan *i2c; |
int ret; |
i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); |
if (i2c == NULL) |
return NULL; |
// i2c->adapter.owner = THIS_MODULE; |
i2c->adapter.algo_data = &i2c->algo; |
i2c->dev = dev; |
i2c->algo.setsda = set_data; |
i2c->algo.setscl = set_clock; |
i2c->algo.getsda = get_data; |
i2c->algo.getscl = get_clock; |
i2c->algo.udelay = 20; |
/* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always |
* make this, 2 jiffies is a lot more reliable */ |
i2c->algo.timeout = 2; |
i2c->algo.data = i2c; |
i2c->rec = *rec; |
i2c_set_adapdata(&i2c->adapter, i2c); |
ret = i2c_bit_add_bus(&i2c->adapter); |
if (ret) { |
DRM_INFO("Failed to register i2c %s\n", name); |
goto out_free; |
} |
return i2c; |
out_free: |
kfree(i2c); |
return NULL; |
} |
void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) |
{ |
if (!i2c) |
return; |
i2c_del_adapter(&i2c->adapter); |
kfree(i2c); |
} |
struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) |
{ |
return NULL; |
} |
/drivers/video/drm/radeon/radeon_legacy_crtc.c |
---|
0,0 → 1,1276 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include <drmP.h> |
#include <drm_crtc_helper.h> |
#include "radeon_drm.h" |
#include "radeon_fixed.h" |
#include "radeon.h" |
void radeon_restore_common_regs(struct drm_device *dev) |
{ |
/* don't need this yet */ |
} |
static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
int i = 0; |
/* FIXME: Certain revisions of R300 can't recover here. Not sure of |
the cause yet, but this workaround will mask the problem for now. |
Other chips usually will pass at the very first test, so the |
workaround shouldn't have any effect on them. */ |
for (i = 0; |
(i < 10000 && |
RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); |
i++); |
} |
static void radeon_pll_write_update(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); |
WREG32_PLL_P(RADEON_PPLL_REF_DIV, |
RADEON_PPLL_ATOMIC_UPDATE_W, |
~(RADEON_PPLL_ATOMIC_UPDATE_W)); |
} |
static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
int i = 0; |
/* FIXME: Certain revisions of R300 can't recover here. Not sure of |
the cause yet, but this workaround will mask the problem for now. |
Other chips usually will pass at the very first test, so the |
workaround shouldn't have any effect on them. */ |
for (i = 0; |
(i < 10000 && |
RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); |
i++); |
} |
static void radeon_pll2_write_update(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); |
WREG32_PLL_P(RADEON_P2PLL_REF_DIV, |
RADEON_P2PLL_ATOMIC_UPDATE_W, |
~(RADEON_P2PLL_ATOMIC_UPDATE_W)); |
} |
static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, |
uint16_t fb_div) |
{ |
unsigned int vcoFreq; |
if (!ref_div) |
return 1; |
vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div; |
/* |
* This is horribly crude: the VCO frequency range is divided into |
* 3 parts, each part having a fixed PLL gain value. |
*/ |
if (vcoFreq >= 30000) |
/* |
* [300..max] MHz : 7 |
*/ |
return 7; |
else if (vcoFreq >= 18000) |
/* |
* [180..300) MHz : 4 |
*/ |
return 4; |
else |
/* |
* [0..180) MHz : 1 |
*/ |
return 1; |
} |
void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t mask; |
if (radeon_crtc->crtc_id) |
mask = (RADEON_CRTC2_EN | |
RADEON_CRTC2_DISP_DIS | |
RADEON_CRTC2_VSYNC_DIS | |
RADEON_CRTC2_HSYNC_DIS | |
RADEON_CRTC2_DISP_REQ_EN_B); |
else |
mask = (RADEON_CRTC_DISPLAY_DIS | |
RADEON_CRTC_VSYNC_DIS | |
RADEON_CRTC_HSYNC_DIS); |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
if (radeon_crtc->crtc_id) |
WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~mask); |
else { |
WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | |
RADEON_CRTC_DISP_REQ_EN_B)); |
WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); |
} |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
if (radeon_crtc->crtc_id) |
WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask); |
else { |
WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | |
RADEON_CRTC_DISP_REQ_EN_B)); |
WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); |
} |
break; |
} |
if (mode != DRM_MODE_DPMS_OFF) { |
radeon_crtc_load_lut(crtc); |
} |
} |
/* properly set crtc bpp when using atombios */ |
void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
int format; |
uint32_t crtc_gen_cntl; |
uint32_t disp_merge_cntl; |
uint32_t crtc_pitch; |
switch (crtc->fb->bits_per_pixel) { |
case 15: /* 555 */ |
format = 3; |
break; |
case 16: /* 565 */ |
format = 4; |
break; |
case 24: /* RGB */ |
format = 5; |
break; |
case 32: /* xRGB */ |
format = 6; |
break; |
default: |
return; |
} |
crtc_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) + |
((crtc->fb->bits_per_pixel * 8) - 1)) / |
(crtc->fb->bits_per_pixel * 8)); |
crtc_pitch |= crtc_pitch << 16; |
WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); |
switch (radeon_crtc->crtc_id) { |
case 0: |
disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); |
disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; |
WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); |
crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff; |
crtc_gen_cntl |= (format << 8); |
crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN; |
WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); |
break; |
case 1: |
disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); |
disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; |
WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); |
crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; |
crtc_gen_cntl |= (format << 8); |
WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl); |
WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); |
WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); |
break; |
} |
} |
int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
struct drm_framebuffer *old_fb) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_framebuffer *radeon_fb; |
struct drm_gem_object *obj; |
uint64_t base; |
uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; |
uint32_t crtc_pitch, pitch_pixels; |
DRM_DEBUG("\n"); |
radeon_fb = to_radeon_framebuffer(crtc->fb); |
obj = radeon_fb->obj; |
// if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &base)) { |
// return -EINVAL; |
// } |
crtc_offset = (u32)base; |
crtc_offset_cntl = 0; |
pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); |
crtc_pitch = (((pitch_pixels * crtc->fb->bits_per_pixel) + |
((crtc->fb->bits_per_pixel * 8) - 1)) / |
(crtc->fb->bits_per_pixel * 8)); |
crtc_pitch |= crtc_pitch << 16; |
/* TODO tiling */ |
if (0) { |
if (ASIC_IS_R300(rdev)) |
crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | |
R300_CRTC_MICRO_TILE_BUFFER_DIS | |
R300_CRTC_MACRO_TILE_EN); |
else |
crtc_offset_cntl |= RADEON_CRTC_TILE_EN; |
} else { |
if (ASIC_IS_R300(rdev)) |
crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | |
R300_CRTC_MICRO_TILE_BUFFER_DIS | |
R300_CRTC_MACRO_TILE_EN); |
else |
crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; |
} |
/* TODO more tiling */ |
if (0) { |
if (ASIC_IS_R300(rdev)) { |
crtc_tile_x0_y0 = x | (y << 16); |
base &= ~0x7ff; |
} else { |
int byteshift = crtc->fb->bits_per_pixel >> 4; |
int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; |
base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); |
crtc_offset_cntl |= (y % 16); |
} |
} else { |
int offset = y * pitch_pixels + x; |
switch (crtc->fb->bits_per_pixel) { |
case 15: |
case 16: |
offset *= 2; |
break; |
case 24: |
offset *= 3; |
break; |
case 32: |
offset *= 4; |
break; |
default: |
return false; |
} |
base += offset; |
} |
base &= ~7; |
/* update sarea TODO */ |
crtc_offset = (u32)base; |
WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, rdev->mc.vram_location); |
if (ASIC_IS_R300(rdev)) { |
if (radeon_crtc->crtc_id) |
WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0); |
else |
WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); |
} |
WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl); |
WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); |
WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); |
if (old_fb && old_fb != crtc->fb) { |
radeon_fb = to_radeon_framebuffer(old_fb); |
// radeon_gem_object_unpin(radeon_fb->obj); |
} |
return 0; |
} |
static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
int format; |
int hsync_start; |
int hsync_wid; |
int vsync_wid; |
uint32_t crtc_h_total_disp; |
uint32_t crtc_h_sync_strt_wid; |
uint32_t crtc_v_total_disp; |
uint32_t crtc_v_sync_strt_wid; |
DRM_DEBUG("\n"); |
switch (crtc->fb->bits_per_pixel) { |
case 15: /* 555 */ |
format = 3; |
break; |
case 16: /* 565 */ |
format = 4; |
break; |
case 24: /* RGB */ |
format = 5; |
break; |
case 32: /* xRGB */ |
format = 6; |
break; |
default: |
return false; |
} |
crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) |
| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); |
hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; |
if (!hsync_wid) |
hsync_wid = 1; |
hsync_start = mode->crtc_hsync_start - 8; |
crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
| ((hsync_wid & 0x3f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NHSYNC) |
? RADEON_CRTC_H_SYNC_POL |
: 0)); |
/* This works for double scan mode. */ |
crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) |
| ((mode->crtc_vdisplay - 1) << 16)); |
vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; |
if (!vsync_wid) |
vsync_wid = 1; |
crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) |
| ((vsync_wid & 0x1f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NVSYNC) |
? RADEON_CRTC_V_SYNC_POL |
: 0)); |
/* TODO -> Dell Server */ |
if (0) { |
uint32_t disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); |
uint32_t tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); |
uint32_t dac2_cntl = RREG32(RADEON_DAC_CNTL2); |
uint32_t crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); |
dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; |
dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; |
/* For CRT on DAC2, don't turn it on if BIOS didn't |
enable it, even it's detected. |
*/ |
disp_hw_debug |= RADEON_CRT2_DISP1_SEL; |
tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); |
tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); |
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); |
WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); |
WREG32(RADEON_DAC_CNTL2, dac2_cntl); |
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); |
} |
if (radeon_crtc->crtc_id) { |
uint32_t crtc2_gen_cntl; |
uint32_t disp2_merge_cntl; |
/* check to see if TV DAC is enabled for another crtc and keep it enabled */ |
if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_CRT2_ON) |
crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; |
else |
crtc2_gen_cntl = 0; |
crtc2_gen_cntl |= ((format << 8) |
| RADEON_CRTC2_VSYNC_DIS |
| RADEON_CRTC2_HSYNC_DIS |
| RADEON_CRTC2_DISP_DIS |
| RADEON_CRTC2_DISP_REQ_EN_B |
| ((mode->flags & DRM_MODE_FLAG_DBLSCAN) |
? RADEON_CRTC2_DBL_SCAN_EN |
: 0) |
| ((mode->flags & DRM_MODE_FLAG_CSYNC) |
? RADEON_CRTC2_CSYNC_EN |
: 0) |
| ((mode->flags & DRM_MODE_FLAG_INTERLACE) |
? RADEON_CRTC2_INTERLACE_EN |
: 0)); |
disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); |
disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; |
WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); |
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); |
} else { |
uint32_t crtc_gen_cntl; |
uint32_t crtc_ext_cntl; |
uint32_t disp_merge_cntl; |
crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN |
| (format << 8) |
| RADEON_CRTC_DISP_REQ_EN_B |
| ((mode->flags & DRM_MODE_FLAG_DBLSCAN) |
? RADEON_CRTC_DBL_SCAN_EN |
: 0) |
| ((mode->flags & DRM_MODE_FLAG_CSYNC) |
? RADEON_CRTC_CSYNC_EN |
: 0) |
| ((mode->flags & DRM_MODE_FLAG_INTERLACE) |
? RADEON_CRTC_INTERLACE_EN |
: 0)); |
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); |
crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | |
RADEON_CRTC_VSYNC_DIS | |
RADEON_CRTC_HSYNC_DIS | |
RADEON_CRTC_DISPLAY_DIS); |
disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); |
disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; |
WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); |
WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); |
WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); |
} |
WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp); |
WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid); |
WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp); |
WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid); |
return true; |
} |
static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_encoder *encoder; |
uint32_t feedback_div = 0; |
uint32_t frac_fb_div = 0; |
uint32_t reference_div = 0; |
uint32_t post_divider = 0; |
uint32_t freq = 0; |
uint8_t pll_gain; |
int pll_flags = RADEON_PLL_LEGACY; |
bool use_bios_divs = false; |
/* PLL registers */ |
uint32_t pll_ref_div = 0; |
uint32_t pll_fb_post_div = 0; |
uint32_t htotal_cntl = 0; |
struct radeon_pll *pll; |
struct { |
int divider; |
int bitvalue; |
} *post_div, post_divs[] = { |
/* From RAGE 128 VR/RAGE 128 GL Register |
* Reference Manual (Technical Reference |
* Manual P/N RRG-G04100-C Rev. 0.04), page |
* 3-17 (PLL_DIV_[3:0]). |
*/ |
{ 1, 0 }, /* VCLK_SRC */ |
{ 2, 1 }, /* VCLK_SRC/2 */ |
{ 4, 2 }, /* VCLK_SRC/4 */ |
{ 8, 3 }, /* VCLK_SRC/8 */ |
{ 3, 4 }, /* VCLK_SRC/3 */ |
{ 16, 5 }, /* VCLK_SRC/16 */ |
{ 6, 6 }, /* VCLK_SRC/6 */ |
{ 12, 7 }, /* VCLK_SRC/12 */ |
{ 0, 0 } |
}; |
if (radeon_crtc->crtc_id) |
pll = &rdev->clock.p2pll; |
else |
pll = &rdev->clock.p1pll; |
if (mode->clock > 200000) /* range limits??? */ |
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
else |
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc == crtc) { |
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) |
pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; |
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; |
if (lvds) { |
if (lvds->use_bios_dividers) { |
pll_ref_div = lvds->panel_ref_divider; |
pll_fb_post_div = (lvds->panel_fb_divider | |
(lvds->panel_post_divider << 16)); |
htotal_cntl = 0; |
use_bios_divs = true; |
} |
} |
pll_flags |= RADEON_PLL_USE_REF_DIV; |
} |
} |
} |
DRM_DEBUG("\n"); |
if (!use_bios_divs) { |
radeon_compute_pll(pll, mode->clock, |
&freq, &feedback_div, &frac_fb_div, |
&reference_div, &post_divider, |
pll_flags); |
for (post_div = &post_divs[0]; post_div->divider; ++post_div) { |
if (post_div->divider == post_divider) |
break; |
} |
if (!post_div->divider) |
post_div = &post_divs[0]; |
DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", |
(unsigned)freq, |
feedback_div, |
reference_div, |
post_divider); |
pll_ref_div = reference_div; |
#if defined(__powerpc__) && (0) /* TODO */ |
/* apparently programming this otherwise causes a hang??? */ |
if (info->MacModel == RADEON_MAC_IBOOK) |
pll_fb_post_div = 0x000600ad; |
else |
#endif |
pll_fb_post_div = (feedback_div | (post_div->bitvalue << 16)); |
htotal_cntl = mode->htotal & 0x7; |
} |
pll_gain = radeon_compute_pll_gain(pll->reference_freq, |
pll_ref_div & 0x3ff, |
pll_fb_post_div & 0x7ff); |
if (radeon_crtc->crtc_id) { |
uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) & |
~(RADEON_PIX2CLK_SRC_SEL_MASK)) | |
RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); |
WREG32_PLL_P(RADEON_PIXCLKS_CNTL, |
RADEON_PIX2CLK_SRC_SEL_CPUCLK, |
~(RADEON_PIX2CLK_SRC_SEL_MASK)); |
WREG32_PLL_P(RADEON_P2PLL_CNTL, |
RADEON_P2PLL_RESET |
| RADEON_P2PLL_ATOMIC_UPDATE_EN |
| ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), |
~(RADEON_P2PLL_RESET |
| RADEON_P2PLL_ATOMIC_UPDATE_EN |
| RADEON_P2PLL_PVG_MASK)); |
WREG32_PLL_P(RADEON_P2PLL_REF_DIV, |
pll_ref_div, |
~RADEON_P2PLL_REF_DIV_MASK); |
WREG32_PLL_P(RADEON_P2PLL_DIV_0, |
pll_fb_post_div, |
~RADEON_P2PLL_FB0_DIV_MASK); |
WREG32_PLL_P(RADEON_P2PLL_DIV_0, |
pll_fb_post_div, |
~RADEON_P2PLL_POST0_DIV_MASK); |
radeon_pll2_write_update(dev); |
radeon_pll2_wait_for_read_update_complete(dev); |
WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl); |
WREG32_PLL_P(RADEON_P2PLL_CNTL, |
0, |
~(RADEON_P2PLL_RESET |
| RADEON_P2PLL_SLEEP |
| RADEON_P2PLL_ATOMIC_UPDATE_EN)); |
DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", |
(unsigned)pll_ref_div, |
(unsigned)pll_fb_post_div, |
(unsigned)htotal_cntl, |
RREG32_PLL(RADEON_P2PLL_CNTL)); |
DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", |
(unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, |
(unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK, |
(unsigned)((pll_fb_post_div & |
RADEON_P2PLL_POST0_DIV_MASK) >> 16)); |
mdelay(50); /* Let the clock to lock */ |
WREG32_PLL_P(RADEON_PIXCLKS_CNTL, |
RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, |
~(RADEON_PIX2CLK_SRC_SEL_MASK)); |
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); |
} else { |
if (rdev->flags & RADEON_IS_MOBILITY) { |
/* A temporal workaround for the occational blanking on certain laptop panels. |
This appears to related to the PLL divider registers (fail to lock?). |
It occurs even when all dividers are the same with their old settings. |
In this case we really don't need to fiddle with PLL registers. |
By doing this we can avoid the blanking problem with some panels. |
*/ |
if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && |
(pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) & |
(RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { |
WREG32_P(RADEON_CLOCK_CNTL_INDEX, |
RADEON_PLL_DIV_SEL, |
~(RADEON_PLL_DIV_SEL)); |
r100_pll_errata_after_index(rdev); |
return; |
} |
} |
WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, |
RADEON_VCLK_SRC_SEL_CPUCLK, |
~(RADEON_VCLK_SRC_SEL_MASK)); |
WREG32_PLL_P(RADEON_PPLL_CNTL, |
RADEON_PPLL_RESET |
| RADEON_PPLL_ATOMIC_UPDATE_EN |
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN |
| ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), |
~(RADEON_PPLL_RESET |
| RADEON_PPLL_ATOMIC_UPDATE_EN |
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN |
| RADEON_PPLL_PVG_MASK)); |
WREG32_P(RADEON_CLOCK_CNTL_INDEX, |
RADEON_PLL_DIV_SEL, |
~(RADEON_PLL_DIV_SEL)); |
r100_pll_errata_after_index(rdev); |
if (ASIC_IS_R300(rdev) || |
(rdev->family == CHIP_RS300) || |
(rdev->family == CHIP_RS400) || |
(rdev->family == CHIP_RS480)) { |
if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { |
/* When restoring console mode, use saved PPLL_REF_DIV |
* setting. |
*/ |
WREG32_PLL_P(RADEON_PPLL_REF_DIV, |
pll_ref_div, |
0); |
} else { |
/* R300 uses ref_div_acc field as real ref divider */ |
WREG32_PLL_P(RADEON_PPLL_REF_DIV, |
(pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), |
~R300_PPLL_REF_DIV_ACC_MASK); |
} |
} else |
WREG32_PLL_P(RADEON_PPLL_REF_DIV, |
pll_ref_div, |
~RADEON_PPLL_REF_DIV_MASK); |
WREG32_PLL_P(RADEON_PPLL_DIV_3, |
pll_fb_post_div, |
~RADEON_PPLL_FB3_DIV_MASK); |
WREG32_PLL_P(RADEON_PPLL_DIV_3, |
pll_fb_post_div, |
~RADEON_PPLL_POST3_DIV_MASK); |
radeon_pll_write_update(dev); |
radeon_pll_wait_for_read_update_complete(dev); |
WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl); |
WREG32_PLL_P(RADEON_PPLL_CNTL, |
0, |
~(RADEON_PPLL_RESET |
| RADEON_PPLL_SLEEP |
| RADEON_PPLL_ATOMIC_UPDATE_EN |
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); |
DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", |
pll_ref_div, |
pll_fb_post_div, |
(unsigned)htotal_cntl, |
RREG32_PLL(RADEON_PPLL_CNTL)); |
DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", |
pll_ref_div & RADEON_PPLL_REF_DIV_MASK, |
pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK, |
(pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16); |
mdelay(50); /* Let the clock to lock */ |
WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, |
RADEON_VCLK_SRC_SEL_PPLLCLK, |
~(RADEON_VCLK_SRC_SEL_MASK)); |
} |
} |
static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
return true; |
} |
static int radeon_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, struct drm_framebuffer *old_fb) |
{ |
DRM_DEBUG("\n"); |
/* TODO TV */ |
radeon_crtc_set_base(crtc, x, y, old_fb); |
radeon_set_crtc_timing(crtc, adjusted_mode); |
radeon_set_pll(crtc, adjusted_mode); |
radeon_init_disp_bandwidth(crtc->dev); |
return 0; |
} |
static void radeon_crtc_prepare(struct drm_crtc *crtc) |
{ |
radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
} |
static void radeon_crtc_commit(struct drm_crtc *crtc) |
{ |
radeon_crtc_dpms(crtc, DRM_MODE_DPMS_ON); |
} |
static const struct drm_crtc_helper_funcs legacy_helper_funcs = { |
.dpms = radeon_crtc_dpms, |
.mode_fixup = radeon_crtc_mode_fixup, |
.mode_set = radeon_crtc_mode_set, |
.mode_set_base = radeon_crtc_set_base, |
.prepare = radeon_crtc_prepare, |
.commit = radeon_crtc_commit, |
}; |
void radeon_legacy_init_crtc(struct drm_device *dev, |
struct radeon_crtc *radeon_crtc) |
{ |
if (radeon_crtc->crtc_id == 1) |
radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP; |
drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs); |
} |
void radeon_init_disp_bw_legacy(struct drm_device *dev, |
struct drm_display_mode *mode1, |
uint32_t pixel_bytes1, |
struct drm_display_mode *mode2, |
uint32_t pixel_bytes2) |
{ |
struct radeon_device *rdev = dev->dev_private; |
fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; |
fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; |
fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; |
uint32_t temp, data, mem_trcd, mem_trp, mem_tras; |
fixed20_12 memtcas_ff[8] = { |
fixed_init(1), |
fixed_init(2), |
fixed_init(3), |
fixed_init(0), |
fixed_init_half(1), |
fixed_init_half(2), |
fixed_init(0), |
}; |
fixed20_12 memtcas_rs480_ff[8] = { |
fixed_init(0), |
fixed_init(1), |
fixed_init(2), |
fixed_init(3), |
fixed_init(0), |
fixed_init_half(1), |
fixed_init_half(2), |
fixed_init_half(3), |
}; |
fixed20_12 memtcas2_ff[8] = { |
fixed_init(0), |
fixed_init(1), |
fixed_init(2), |
fixed_init(3), |
fixed_init(4), |
fixed_init(5), |
fixed_init(6), |
fixed_init(7), |
}; |
fixed20_12 memtrbs[8] = { |
fixed_init(1), |
fixed_init_half(1), |
fixed_init(2), |
fixed_init_half(2), |
fixed_init(3), |
fixed_init_half(3), |
fixed_init(4), |
fixed_init_half(4) |
}; |
fixed20_12 memtrbs_r4xx[8] = { |
fixed_init(4), |
fixed_init(5), |
fixed_init(6), |
fixed_init(7), |
fixed_init(8), |
fixed_init(9), |
fixed_init(10), |
fixed_init(11) |
}; |
fixed20_12 min_mem_eff; |
fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; |
fixed20_12 cur_latency_mclk, cur_latency_sclk; |
fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, |
disp_drain_rate2, read_return_rate; |
fixed20_12 time_disp1_drop_priority; |
int c; |
int cur_size = 16; /* in octawords */ |
int critical_point = 0, critical_point2; |
/* uint32_t read_return_rate, time_disp1_drop_priority; */ |
int stop_req, max_stop_req; |
min_mem_eff.full = rfixed_const_8(0); |
/* get modes */ |
if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { |
uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); |
mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); |
mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); |
/* check crtc enables */ |
if (mode2) |
mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); |
if (mode1) |
mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); |
WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); |
} |
/* |
* determine is there is enough bw for current mode |
*/ |
mclk_ff.full = rfixed_const(rdev->clock.default_mclk); |
temp_ff.full = rfixed_const(100); |
mclk_ff.full = rfixed_div(mclk_ff, temp_ff); |
sclk_ff.full = rfixed_const(rdev->clock.default_sclk); |
sclk_ff.full = rfixed_div(sclk_ff, temp_ff); |
temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); |
temp_ff.full = rfixed_const(temp); |
mem_bw.full = rfixed_mul(mclk_ff, temp_ff); |
pix_clk.full = 0; |
pix_clk2.full = 0; |
peak_disp_bw.full = 0; |
if (mode1) { |
temp_ff.full = rfixed_const(1000); |
pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ |
pix_clk.full = rfixed_div(pix_clk, temp_ff); |
temp_ff.full = rfixed_const(pixel_bytes1); |
peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); |
} |
if (mode2) { |
temp_ff.full = rfixed_const(1000); |
pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ |
pix_clk2.full = rfixed_div(pix_clk2, temp_ff); |
temp_ff.full = rfixed_const(pixel_bytes2); |
peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); |
} |
mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); |
if (peak_disp_bw.full >= mem_bw.full) { |
DRM_ERROR("You may not have enough display bandwidth for current mode\n" |
"If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); |
} |
/* Get values from the EXT_MEM_CNTL register...converting its contents. */ |
temp = RREG32(RADEON_MEM_TIMING_CNTL); |
if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ |
mem_trcd = ((temp >> 2) & 0x3) + 1; |
mem_trp = ((temp & 0x3)) + 1; |
mem_tras = ((temp & 0x70) >> 4) + 1; |
} else if (rdev->family == CHIP_R300 || |
rdev->family == CHIP_R350) { /* r300, r350 */ |
mem_trcd = (temp & 0x7) + 1; |
mem_trp = ((temp >> 8) & 0x7) + 1; |
mem_tras = ((temp >> 11) & 0xf) + 4; |
} else if (rdev->family == CHIP_RV350 || |
rdev->family <= CHIP_RV380) { |
/* rv3x0 */ |
mem_trcd = (temp & 0x7) + 3; |
mem_trp = ((temp >> 8) & 0x7) + 3; |
mem_tras = ((temp >> 11) & 0xf) + 6; |
} else if (rdev->family == CHIP_R420 || |
rdev->family == CHIP_R423 || |
rdev->family == CHIP_RV410) { |
/* r4xx */ |
mem_trcd = (temp & 0xf) + 3; |
if (mem_trcd > 15) |
mem_trcd = 15; |
mem_trp = ((temp >> 8) & 0xf) + 3; |
if (mem_trp > 15) |
mem_trp = 15; |
mem_tras = ((temp >> 12) & 0x1f) + 6; |
if (mem_tras > 31) |
mem_tras = 31; |
} else { /* RV200, R200 */ |
mem_trcd = (temp & 0x7) + 1; |
mem_trp = ((temp >> 8) & 0x7) + 1; |
mem_tras = ((temp >> 12) & 0xf) + 4; |
} |
/* convert to FF */ |
trcd_ff.full = rfixed_const(mem_trcd); |
trp_ff.full = rfixed_const(mem_trp); |
tras_ff.full = rfixed_const(mem_tras); |
/* Get values from the MEM_SDRAM_MODE_REG register...converting its */ |
temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); |
data = (temp & (7 << 20)) >> 20; |
if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { |
if (rdev->family == CHIP_RS480) /* don't think rs400 */ |
tcas_ff = memtcas_rs480_ff[data]; |
else |
tcas_ff = memtcas_ff[data]; |
} else |
tcas_ff = memtcas2_ff[data]; |
if (rdev->family == CHIP_RS400 || |
rdev->family == CHIP_RS480) { |
/* extra cas latency stored in bits 23-25 0-4 clocks */ |
data = (temp >> 23) & 0x7; |
if (data < 5) |
tcas_ff.full += rfixed_const(data); |
} |
if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { |
/* on the R300, Tcas is included in Trbs. |
*/ |
temp = RREG32(RADEON_MEM_CNTL); |
data = (R300_MEM_NUM_CHANNELS_MASK & temp); |
if (data == 1) { |
if (R300_MEM_USE_CD_CH_ONLY & temp) { |
temp = RREG32(R300_MC_IND_INDEX); |
temp &= ~R300_MC_IND_ADDR_MASK; |
temp |= R300_MC_READ_CNTL_CD_mcind; |
WREG32(R300_MC_IND_INDEX, temp); |
temp = RREG32(R300_MC_IND_DATA); |
data = (R300_MEM_RBS_POSITION_C_MASK & temp); |
} else { |
temp = RREG32(R300_MC_READ_CNTL_AB); |
data = (R300_MEM_RBS_POSITION_A_MASK & temp); |
} |
} else { |
temp = RREG32(R300_MC_READ_CNTL_AB); |
data = (R300_MEM_RBS_POSITION_A_MASK & temp); |
} |
if (rdev->family == CHIP_RV410 || |
rdev->family == CHIP_R420 || |
rdev->family == CHIP_R423) |
trbs_ff = memtrbs_r4xx[data]; |
else |
trbs_ff = memtrbs[data]; |
tcas_ff.full += trbs_ff.full; |
} |
sclk_eff_ff.full = sclk_ff.full; |
// if (rdev->flags & RADEON_IS_AGP) { |
// fixed20_12 agpmode_ff; |
// agpmode_ff.full = rfixed_const(radeon_agpmode); |
// temp_ff.full = rfixed_const_666(16); |
// sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); |
// } |
/* TODO PCIE lanes may affect this - agpmode == 16?? */ |
if (ASIC_IS_R300(rdev)) { |
sclk_delay_ff.full = rfixed_const(250); |
} else { |
if ((rdev->family == CHIP_RV100) || |
rdev->flags & RADEON_IS_IGP) { |
if (rdev->mc.vram_is_ddr) |
sclk_delay_ff.full = rfixed_const(41); |
else |
sclk_delay_ff.full = rfixed_const(33); |
} else { |
if (rdev->mc.vram_width == 128) |
sclk_delay_ff.full = rfixed_const(57); |
else |
sclk_delay_ff.full = rfixed_const(41); |
} |
} |
mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); |
if (rdev->mc.vram_is_ddr) { |
if (rdev->mc.vram_width == 32) { |
k1.full = rfixed_const(40); |
c = 3; |
} else { |
k1.full = rfixed_const(20); |
c = 1; |
} |
} else { |
k1.full = rfixed_const(40); |
c = 3; |
} |
temp_ff.full = rfixed_const(2); |
mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); |
temp_ff.full = rfixed_const(c); |
mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); |
temp_ff.full = rfixed_const(4); |
mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); |
mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); |
mc_latency_mclk.full += k1.full; |
mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); |
mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); |
/* |
HW cursor time assuming worst case of full size colour cursor. |
*/ |
temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); |
temp_ff.full += trcd_ff.full; |
if (temp_ff.full < tras_ff.full) |
temp_ff.full = tras_ff.full; |
cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); |
temp_ff.full = rfixed_const(cur_size); |
cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); |
/* |
Find the total latency for the display data. |
*/ |
disp_latency_overhead.full = rfixed_const(80); |
disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); |
mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; |
mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; |
if (mc_latency_mclk.full > mc_latency_sclk.full) |
disp_latency.full = mc_latency_mclk.full; |
else |
disp_latency.full = mc_latency_sclk.full; |
/* setup Max GRPH_STOP_REQ default value */ |
if (ASIC_IS_RV100(rdev)) |
max_stop_req = 0x5c; |
else |
max_stop_req = 0x7c; |
if (mode1) { |
/* CRTC1 |
Set GRPH_BUFFER_CNTL register using h/w defined optimal values. |
GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] |
*/ |
stop_req = mode1->hdisplay * pixel_bytes1 / 16; |
if (stop_req > max_stop_req) |
stop_req = max_stop_req; |
/* |
Find the drain rate of the display buffer. |
*/ |
temp_ff.full = rfixed_const((16/pixel_bytes1)); |
disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); |
/* |
Find the critical point of the display buffer. |
*/ |
crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); |
crit_point_ff.full += rfixed_const_half(0); |
critical_point = rfixed_trunc(crit_point_ff); |
if (rdev->disp_priority == 2) { |
critical_point = 0; |
} |
/* |
The critical point should never be above max_stop_req-4. Setting |
GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. |
*/ |
if (max_stop_req - critical_point < 4) |
critical_point = 0; |
if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { |
/* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ |
critical_point = 0x10; |
} |
temp = RREG32(RADEON_GRPH_BUFFER_CNTL); |
temp &= ~(RADEON_GRPH_STOP_REQ_MASK); |
temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); |
temp &= ~(RADEON_GRPH_START_REQ_MASK); |
if ((rdev->family == CHIP_R350) && |
(stop_req > 0x15)) { |
stop_req -= 0x10; |
} |
temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); |
temp |= RADEON_GRPH_BUFFER_SIZE; |
temp &= ~(RADEON_GRPH_CRITICAL_CNTL | |
RADEON_GRPH_CRITICAL_AT_SOF | |
RADEON_GRPH_STOP_CNTL); |
/* |
Write the result into the register. |
*/ |
WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | |
(critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); |
#if 0 |
if ((rdev->family == CHIP_RS400) || |
(rdev->family == CHIP_RS480)) { |
/* attempt to program RS400 disp regs correctly ??? */ |
temp = RREG32(RS400_DISP1_REG_CNTL); |
temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | |
RS400_DISP1_STOP_REQ_LEVEL_MASK); |
WREG32(RS400_DISP1_REQ_CNTL1, (temp | |
(critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | |
(critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); |
temp = RREG32(RS400_DMIF_MEM_CNTL1); |
temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | |
RS400_DISP1_CRITICAL_POINT_STOP_MASK); |
WREG32(RS400_DMIF_MEM_CNTL1, (temp | |
(critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | |
(critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); |
} |
#endif |
DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", |
/* (unsigned int)info->SavedReg->grph_buffer_cntl, */ |
(unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); |
} |
if (mode2) { |
u32 grph2_cntl; |
stop_req = mode2->hdisplay * pixel_bytes2 / 16; |
if (stop_req > max_stop_req) |
stop_req = max_stop_req; |
/* |
Find the drain rate of the display buffer. |
*/ |
temp_ff.full = rfixed_const((16/pixel_bytes2)); |
disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); |
grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); |
grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); |
grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); |
grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); |
if ((rdev->family == CHIP_R350) && |
(stop_req > 0x15)) { |
stop_req -= 0x10; |
} |
grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); |
grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; |
grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL | |
RADEON_GRPH_CRITICAL_AT_SOF | |
RADEON_GRPH_STOP_CNTL); |
if ((rdev->family == CHIP_RS100) || |
(rdev->family == CHIP_RS200)) |
critical_point2 = 0; |
else { |
temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; |
temp_ff.full = rfixed_const(temp); |
temp_ff.full = rfixed_mul(mclk_ff, temp_ff); |
if (sclk_ff.full < temp_ff.full) |
temp_ff.full = sclk_ff.full; |
read_return_rate.full = temp_ff.full; |
if (mode1) { |
temp_ff.full = read_return_rate.full - disp_drain_rate.full; |
time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); |
} else { |
time_disp1_drop_priority.full = 0; |
} |
crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; |
crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); |
crit_point_ff.full += rfixed_const_half(0); |
critical_point2 = rfixed_trunc(crit_point_ff); |
if (rdev->disp_priority == 2) { |
critical_point2 = 0; |
} |
if (max_stop_req - critical_point2 < 4) |
critical_point2 = 0; |
} |
if (critical_point2 == 0 && rdev->family == CHIP_R300) { |
/* some R300 cards have problem with this set to 0 */ |
critical_point2 = 0x10; |
} |
WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | |
(critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); |
if ((rdev->family == CHIP_RS400) || |
(rdev->family == CHIP_RS480)) { |
#if 0 |
/* attempt to program RS400 disp2 regs correctly ??? */ |
temp = RREG32(RS400_DISP2_REQ_CNTL1); |
temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | |
RS400_DISP2_STOP_REQ_LEVEL_MASK); |
WREG32(RS400_DISP2_REQ_CNTL1, (temp | |
(critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | |
(critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); |
temp = RREG32(RS400_DISP2_REQ_CNTL2); |
temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | |
RS400_DISP2_CRITICAL_POINT_STOP_MASK); |
WREG32(RS400_DISP2_REQ_CNTL2, (temp | |
(critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | |
(critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); |
#endif |
WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); |
WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); |
WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC); |
WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); |
} |
DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", |
(unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); |
} |
} |
/drivers/video/drm/radeon/radeon_legacy_encoders.c |
---|
0,0 → 1,1288 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include "drmP.h" |
#include "drm_crtc_helper.h" |
#include "radeon_drm.h" |
#include "radeon.h" |
#include "atom.h" |
static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
int xres = mode->hdisplay; |
int yres = mode->vdisplay; |
bool hscale = true, vscale = true; |
int hsync_wid; |
int vsync_wid; |
int hsync_start; |
uint32_t scale, inc; |
uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active; |
uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp; |
struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; |
DRM_DEBUG("\n"); |
fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & |
(RADEON_VERT_STRETCH_RESERVED | |
RADEON_VERT_AUTO_RATIO_INC); |
fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) & |
(RADEON_HORZ_FP_LOOP_STRETCH | |
RADEON_HORZ_AUTO_RATIO_INC); |
crtc_more_cntl = 0; |
if ((rdev->family == CHIP_RS100) || |
(rdev->family == CHIP_RS200)) { |
/* This is to workaround the asic bug for RMX, some versions |
of BIOS dosen't have this register initialized correctly. */ |
crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; |
} |
fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) |
| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); |
hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; |
if (!hsync_wid) |
hsync_wid = 1; |
hsync_start = mode->crtc_hsync_start - 8; |
fp_h_sync_strt_wid = ((hsync_start & 0x1fff) |
| ((hsync_wid & 0x3f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NHSYNC) |
? RADEON_CRTC_H_SYNC_POL |
: 0)); |
fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) |
| ((mode->crtc_vdisplay - 1) << 16)); |
vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; |
if (!vsync_wid) |
vsync_wid = 1; |
fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) |
| ((vsync_wid & 0x1f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NVSYNC) |
? RADEON_CRTC_V_SYNC_POL |
: 0)); |
fp_horz_vert_active = 0; |
if (native_mode->panel_xres == 0 || |
native_mode->panel_yres == 0) { |
hscale = false; |
vscale = false; |
} else { |
if (xres > native_mode->panel_xres) |
xres = native_mode->panel_xres; |
if (yres > native_mode->panel_yres) |
yres = native_mode->panel_yres; |
if (xres == native_mode->panel_xres) |
hscale = false; |
if (yres == native_mode->panel_yres) |
vscale = false; |
} |
if (radeon_encoder->flags & RADEON_USE_RMX) { |
if (radeon_encoder->rmx_type != RMX_CENTER) { |
if (!hscale) |
fp_horz_stretch |= ((xres/8-1) << 16); |
else { |
inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; |
scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) |
/ native_mode->panel_xres + 1; |
fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | |
RADEON_HORZ_STRETCH_BLEND | |
RADEON_HORZ_STRETCH_ENABLE | |
((native_mode->panel_xres/8-1) << 16)); |
} |
if (!vscale) |
fp_vert_stretch |= ((yres-1) << 12); |
else { |
inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; |
scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) |
/ native_mode->panel_yres + 1; |
fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | |
RADEON_VERT_STRETCH_ENABLE | |
RADEON_VERT_STRETCH_BLEND | |
((native_mode->panel_yres-1) << 12)); |
} |
} else if (radeon_encoder->rmx_type == RMX_CENTER) { |
int blank_width; |
fp_horz_stretch |= ((xres/8-1) << 16); |
fp_vert_stretch |= ((yres-1) << 12); |
crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | |
RADEON_CRTC_AUTO_VERT_CENTER_EN); |
blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; |
if (blank_width > 110) |
blank_width = 110; |
fp_crtc_h_total_disp = (((blank_width) & 0x3ff) |
| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); |
hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; |
if (!hsync_wid) |
hsync_wid = 1; |
fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) |
| ((hsync_wid & 0x3f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NHSYNC) |
? RADEON_CRTC_H_SYNC_POL |
: 0)); |
fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) |
| ((mode->crtc_vdisplay - 1) << 16)); |
vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; |
if (!vsync_wid) |
vsync_wid = 1; |
fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) |
| ((vsync_wid & 0x1f) << 16) |
| ((mode->flags & DRM_MODE_FLAG_NVSYNC) |
? RADEON_CRTC_V_SYNC_POL |
: 0))); |
fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) | |
(((native_mode->panel_xres / 8) & 0x1ff) << 16)); |
} |
} else { |
fp_horz_stretch |= ((xres/8-1) << 16); |
fp_vert_stretch |= ((yres-1) << 12); |
} |
WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch); |
WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch); |
WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl); |
WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active); |
WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid); |
WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid); |
WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); |
WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); |
} |
static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; |
int panel_pwr_delay = 2000; |
DRM_DEBUG("\n"); |
if (radeon_encoder->enc_priv) { |
if (rdev->is_atom_bios) { |
struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; |
panel_pwr_delay = lvds->panel_pwr_delay; |
} else { |
struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; |
panel_pwr_delay = lvds->panel_pwr_delay; |
} |
} |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN); |
disp_pwr_man |= RADEON_AUTO_PWRUP_EN; |
WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man); |
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); |
lvds_pll_cntl |= RADEON_LVDS_PLL_EN; |
WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); |
udelay(1000); |
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); |
lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; |
WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); |
lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); |
lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); |
lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); |
udelay(panel_pwr_delay * 1000); |
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); |
lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); |
lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; |
lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); |
udelay(panel_pwr_delay * 1000); |
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); |
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); |
break; |
} |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
else |
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
} |
static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, false); |
else |
radeon_combios_output_lock(encoder, false); |
} |
static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; |
DRM_DEBUG("\n"); |
if (radeon_crtc->crtc_id == 0) |
radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); |
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); |
lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; |
lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); |
if ((!rdev->is_atom_bios)) { |
struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; |
if (lvds) { |
DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); |
lvds_gen_cntl = lvds->lvds_gen_cntl; |
lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | |
(0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); |
lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | |
(lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); |
} else |
lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); |
} else |
lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); |
lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; |
lvds_gen_cntl &= ~(RADEON_LVDS_ON | |
RADEON_LVDS_BLON | |
RADEON_LVDS_EN | |
RADEON_LVDS_RST_FM); |
if (ASIC_IS_R300(rdev)) |
lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); |
if (radeon_crtc->crtc_id == 0) { |
if (ASIC_IS_R300(rdev)) { |
if (radeon_encoder->flags & RADEON_USE_RMX) |
lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX; |
} else |
lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; |
} else { |
if (ASIC_IS_R300(rdev)) |
lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; |
else |
lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; |
} |
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); |
WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); |
WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); |
if (rdev->family == CHIP_RV410) |
WREG32(RADEON_CLOCK_CNTL_INDEX, 0); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
else |
radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
radeon_encoder->flags &= ~RADEON_USE_RMX; |
if (radeon_encoder->rmx_type != RMX_OFF) |
radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); |
return true; |
} |
static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { |
.dpms = radeon_legacy_lvds_dpms, |
.mode_fixup = radeon_legacy_lvds_mode_fixup, |
.prepare = radeon_legacy_lvds_prepare, |
.mode_set = radeon_legacy_lvds_mode_set, |
.commit = radeon_legacy_lvds_commit, |
}; |
static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { |
.destroy = radeon_enc_destroy, |
}; |
static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
return true; |
} |
static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); |
uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL); |
uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); |
DRM_DEBUG("\n"); |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
crtc_ext_cntl |= RADEON_CRTC_CRT_ON; |
dac_cntl &= ~RADEON_DAC_PDWN; |
dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | |
RADEON_DAC_PDWN_G | |
RADEON_DAC_PDWN_B); |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; |
dac_cntl |= RADEON_DAC_PDWN; |
dac_macro_cntl |= (RADEON_DAC_PDWN_R | |
RADEON_DAC_PDWN_G | |
RADEON_DAC_PDWN_B); |
break; |
} |
WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); |
WREG32(RADEON_DAC_CNTL, dac_cntl); |
WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
else |
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
} |
static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, false); |
else |
radeon_combios_output_lock(encoder, false); |
} |
static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; |
DRM_DEBUG("\n"); |
if (radeon_crtc->crtc_id == 0) |
radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); |
if (radeon_crtc->crtc_id == 0) { |
if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { |
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & |
~(RADEON_DISP_DAC_SOURCE_MASK); |
WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); |
} else { |
dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); |
WREG32(RADEON_DAC_CNTL2, dac2_cntl); |
} |
} else { |
if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { |
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & |
~(RADEON_DISP_DAC_SOURCE_MASK); |
disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; |
WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); |
} else { |
dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; |
WREG32(RADEON_DAC_CNTL2, dac2_cntl); |
} |
} |
dac_cntl = (RADEON_DAC_MASK_ALL | |
RADEON_DAC_VGA_ADR_EN | |
/* TODO 6-bits */ |
RADEON_DAC_8BIT_EN); |
WREG32_P(RADEON_DAC_CNTL, |
dac_cntl, |
RADEON_DAC_RANGE_CNTL | |
RADEON_DAC_BLANKING); |
if (radeon_encoder->enc_priv) { |
struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; |
dac_macro_cntl = p_dac->ps2_pdac_adj; |
} else |
dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); |
dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B; |
WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
else |
radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t vclk_ecp_cntl, crtc_ext_cntl; |
uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp; |
enum drm_connector_status found = connector_status_disconnected; |
bool color = true; |
/* save the regs we need */ |
vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); |
dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); |
dac_cntl = RREG32(RADEON_DAC_CNTL); |
dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); |
tmp = vclk_ecp_cntl & |
~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); |
WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; |
WREG32(RADEON_CRTC_EXT_CNTL, tmp); |
tmp = RADEON_DAC_FORCE_BLANK_OFF_EN | |
RADEON_DAC_FORCE_DATA_EN; |
if (color) |
tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; |
else |
tmp |= RADEON_DAC_FORCE_DATA_SEL_G; |
if (ASIC_IS_R300(rdev)) |
tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); |
else |
tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); |
WREG32(RADEON_DAC_EXT_CNTL, tmp); |
tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); |
tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; |
WREG32(RADEON_DAC_CNTL, tmp); |
tmp &= ~(RADEON_DAC_PDWN_R | |
RADEON_DAC_PDWN_G | |
RADEON_DAC_PDWN_B); |
WREG32(RADEON_DAC_MACRO_CNTL, tmp); |
udelay(2000); |
if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) |
found = connector_status_connected; |
/* restore the regs we used */ |
WREG32(RADEON_DAC_CNTL, dac_cntl); |
WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); |
WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); |
WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); |
WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); |
return found; |
} |
static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { |
.dpms = radeon_legacy_primary_dac_dpms, |
.mode_fixup = radeon_legacy_primary_dac_mode_fixup, |
.prepare = radeon_legacy_primary_dac_prepare, |
.mode_set = radeon_legacy_primary_dac_mode_set, |
.commit = radeon_legacy_primary_dac_commit, |
.detect = radeon_legacy_primary_dac_detect, |
}; |
static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { |
.destroy = radeon_enc_destroy, |
}; |
static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
return true; |
} |
static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL); |
DRM_DEBUG("\n"); |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); |
break; |
} |
WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
else |
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
} |
static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
} |
static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; |
int i; |
DRM_DEBUG("\n"); |
if (radeon_crtc->crtc_id == 0) |
radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); |
tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL); |
tmp &= 0xfffff; |
if (rdev->family == CHIP_RV280) { |
/* bit 22 of TMDS_PLL_CNTL is read-back inverted */ |
tmp ^= (1 << 22); |
tmds_pll_cntl ^= (1 << 22); |
} |
if (radeon_encoder->enc_priv) { |
struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv; |
for (i = 0; i < 4; i++) { |
if (tmds->tmds_pll[i].freq == 0) |
break; |
if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) { |
tmp = tmds->tmds_pll[i].value ; |
break; |
} |
} |
} |
if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) { |
if (tmp & 0xfff00000) |
tmds_pll_cntl = tmp; |
else { |
tmds_pll_cntl &= 0xfff00000; |
tmds_pll_cntl |= tmp; |
} |
} else |
tmds_pll_cntl = tmp; |
tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) & |
~(RADEON_TMDS_TRANSMITTER_PLLRST); |
if (rdev->family == CHIP_R200 || |
rdev->family == CHIP_R100 || |
ASIC_IS_R300(rdev)) |
tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); |
else /* RV chips got this bit reversed */ |
tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN; |
fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) | |
(RADEON_FP_CRTC_DONT_SHADOW_VPAR | |
RADEON_FP_CRTC_DONT_SHADOW_HEND)); |
fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); |
if (1) /* FIXME rgbBits == 8 */ |
fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ |
else |
fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ |
if (radeon_crtc->crtc_id == 0) { |
if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { |
fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; |
if (radeon_encoder->flags & RADEON_USE_RMX) |
fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; |
else |
fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; |
} else |
fp_gen_cntl |= RADEON_FP_SEL_CRTC1; |
} else { |
if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { |
fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; |
fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; |
} else |
fp_gen_cntl |= RADEON_FP_SEL_CRTC2; |
} |
WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl); |
WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl); |
WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
else |
radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { |
.dpms = radeon_legacy_tmds_int_dpms, |
.mode_fixup = radeon_legacy_tmds_int_mode_fixup, |
.prepare = radeon_legacy_tmds_int_prepare, |
.mode_set = radeon_legacy_tmds_int_mode_set, |
.commit = radeon_legacy_tmds_int_commit, |
}; |
static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { |
.destroy = radeon_enc_destroy, |
}; |
static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
return true; |
} |
static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); |
DRM_DEBUG("\n"); |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; |
fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
fp2_gen_cntl |= RADEON_FP2_BLANK_EN; |
fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); |
break; |
} |
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
else |
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
} |
static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, false); |
else |
radeon_combios_output_lock(encoder, false); |
} |
static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t fp2_gen_cntl; |
DRM_DEBUG("\n"); |
if (radeon_crtc->crtc_id == 0) |
radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); |
if (rdev->is_atom_bios) { |
radeon_encoder->pixel_clock = adjusted_mode->clock; |
atombios_external_tmds_setup(encoder, ATOM_ENABLE); |
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); |
} else { |
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); |
if (1) /* FIXME rgbBits == 8 */ |
fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ |
else |
fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ |
fp2_gen_cntl &= ~(RADEON_FP2_ON | |
RADEON_FP2_DVO_EN | |
RADEON_FP2_DVO_RATE_SEL_SDR); |
/* XXX: these are oem specific */ |
if (ASIC_IS_R300(rdev)) { |
if ((dev->pdev->device == 0x4850) && |
(dev->pdev->subsystem_vendor == 0x1028) && |
(dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ |
fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; |
else |
fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; |
/*if (mode->clock > 165000) |
fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ |
} |
} |
if (radeon_crtc->crtc_id == 0) { |
if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { |
fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; |
if (radeon_encoder->flags & RADEON_USE_RMX) |
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; |
else |
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; |
} else |
fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; |
} else { |
if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { |
fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; |
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; |
} else |
fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; |
} |
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
else |
radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = { |
.dpms = radeon_legacy_tmds_ext_dpms, |
.mode_fixup = radeon_legacy_tmds_ext_mode_fixup, |
.prepare = radeon_legacy_tmds_ext_prepare, |
.mode_set = radeon_legacy_tmds_ext_mode_set, |
.commit = radeon_legacy_tmds_ext_commit, |
}; |
static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { |
.destroy = radeon_enc_destroy, |
}; |
static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
return true; |
} |
static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; |
/* uint32_t tv_master_cntl = 0; */ |
DRM_DEBUG("\n"); |
if (rdev->family == CHIP_R200) |
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); |
else { |
crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); |
/* FIXME TV */ |
/* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */ |
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); |
} |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
if (rdev->family == CHIP_R200) { |
fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); |
} else { |
crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; |
/* tv_master_cntl |= RADEON_TV_ON; */ |
if (rdev->family == CHIP_R420 || |
rdev->family == CHIP_R423 || |
rdev->family == CHIP_RV410) |
tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | |
R420_TV_DAC_GDACPD | |
R420_TV_DAC_BDACPD | |
RADEON_TV_DAC_BGSLEEP); |
else |
tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | |
RADEON_TV_DAC_GDACPD | |
RADEON_TV_DAC_BDACPD | |
RADEON_TV_DAC_BGSLEEP); |
} |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
if (rdev->family == CHIP_R200) |
fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); |
else { |
crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; |
/* tv_master_cntl &= ~RADEON_TV_ON; */ |
if (rdev->family == CHIP_R420 || |
rdev->family == CHIP_R423 || |
rdev->family == CHIP_RV410) |
tv_dac_cntl |= (R420_TV_DAC_RDACPD | |
R420_TV_DAC_GDACPD | |
R420_TV_DAC_BDACPD | |
RADEON_TV_DAC_BGSLEEP); |
else |
tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | |
RADEON_TV_DAC_GDACPD | |
RADEON_TV_DAC_BDACPD | |
RADEON_TV_DAC_BGSLEEP); |
} |
break; |
} |
if (rdev->family == CHIP_R200) { |
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); |
} else { |
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); |
/* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */ |
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); |
} |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
else |
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
} |
static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); |
if (rdev->is_atom_bios) |
radeon_atom_output_lock(encoder, true); |
else |
radeon_combios_output_lock(encoder, true); |
} |
static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; |
uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; |
DRM_DEBUG("\n"); |
if (radeon_crtc->crtc_id == 0) |
radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); |
if (rdev->family != CHIP_R200) { |
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); |
if (rdev->family == CHIP_R420 || |
rdev->family == CHIP_R423 || |
rdev->family == CHIP_RV410) { |
tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | |
RADEON_TV_DAC_BGADJ_MASK | |
R420_TV_DAC_DACADJ_MASK | |
R420_TV_DAC_RDACPD | |
R420_TV_DAC_GDACPD | |
R420_TV_DAC_GDACPD | |
R420_TV_DAC_TVENABLE); |
} else { |
tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | |
RADEON_TV_DAC_BGADJ_MASK | |
RADEON_TV_DAC_DACADJ_MASK | |
RADEON_TV_DAC_RDACPD | |
RADEON_TV_DAC_GDACPD | |
RADEON_TV_DAC_GDACPD); |
} |
/* FIXME TV */ |
if (radeon_encoder->enc_priv) { |
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; |
tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | |
RADEON_TV_DAC_NHOLD | |
RADEON_TV_DAC_STD_PS2 | |
tv_dac->ps2_tvdac_adj); |
} else |
tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | |
RADEON_TV_DAC_NHOLD | |
RADEON_TV_DAC_STD_PS2); |
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); |
} |
if (ASIC_IS_R300(rdev)) { |
gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; |
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); |
} else if (rdev->family == CHIP_R200) |
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); |
else |
disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); |
dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; |
if (radeon_crtc->crtc_id == 0) { |
if (ASIC_IS_R300(rdev)) { |
disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; |
disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; |
} else if (rdev->family == CHIP_R200) { |
fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | |
RADEON_FP2_DVO_RATE_SEL_SDR); |
} else |
disp_hw_debug |= RADEON_CRT2_DISP1_SEL; |
} else { |
if (ASIC_IS_R300(rdev)) { |
disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; |
disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; |
} else if (rdev->family == CHIP_R200) { |
fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | |
RADEON_FP2_DVO_RATE_SEL_SDR); |
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; |
} else |
disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; |
} |
WREG32(RADEON_DAC_CNTL2, dac2_cntl); |
if (ASIC_IS_R300(rdev)) { |
WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); |
WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl); |
} else if (rdev->family == CHIP_R200) |
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); |
else |
WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); |
if (rdev->is_atom_bios) |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
else |
radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; |
uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; |
enum drm_connector_status found = connector_status_disconnected; |
bool color = true; |
/* FIXME tv */ |
/* save the regs we need */ |
pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0; |
disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0; |
disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG); |
crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); |
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); |
dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); |
dac_cntl2 = RREG32(RADEON_DAC_CNTL2); |
tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb); |
WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
if (ASIC_IS_R300(rdev)) |
WREG32_P(RADEON_GPIOPAD_A, 1, ~1); |
tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; |
tmp |= RADEON_CRTC2_CRT2_ON | |
(2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); |
WREG32(RADEON_CRTC2_GEN_CNTL, tmp); |
if (ASIC_IS_R300(rdev)) { |
tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; |
tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; |
WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); |
} else { |
tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; |
WREG32(RADEON_DISP_HW_DEBUG, tmp); |
} |
tmp = RADEON_TV_DAC_NBLANK | |
RADEON_TV_DAC_NHOLD | |
RADEON_TV_MONITOR_DETECT_EN | |
RADEON_TV_DAC_STD_PS2; |
WREG32(RADEON_TV_DAC_CNTL, tmp); |
tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | |
RADEON_DAC2_FORCE_DATA_EN; |
if (color) |
tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; |
else |
tmp |= RADEON_DAC_FORCE_DATA_SEL_G; |
if (ASIC_IS_R300(rdev)) |
tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); |
else |
tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); |
WREG32(RADEON_DAC_EXT_CNTL, tmp); |
tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; |
WREG32(RADEON_DAC_CNTL2, tmp); |
udelay(10000); |
if (ASIC_IS_R300(rdev)) { |
if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) |
found = connector_status_connected; |
} else { |
if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) |
found = connector_status_connected; |
} |
/* restore regs we used */ |
WREG32(RADEON_DAC_CNTL2, dac_cntl2); |
WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); |
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); |
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); |
if (ASIC_IS_R300(rdev)) { |
WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); |
WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); |
} else { |
WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); |
} |
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); |
/* return found; */ |
return connector_status_disconnected; |
} |
static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { |
.dpms = radeon_legacy_tv_dac_dpms, |
.mode_fixup = radeon_legacy_tv_dac_mode_fixup, |
.prepare = radeon_legacy_tv_dac_prepare, |
.mode_set = radeon_legacy_tv_dac_mode_set, |
.commit = radeon_legacy_tv_dac_commit, |
.detect = radeon_legacy_tv_dac_detect, |
}; |
static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { |
.destroy = radeon_enc_destroy, |
}; |
void |
radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
/* see if we already added it */ |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
radeon_encoder = to_radeon_encoder(encoder); |
if (radeon_encoder->encoder_id == encoder_id) { |
radeon_encoder->devices |= supported_device; |
return; |
} |
} |
/* add a new one */ |
radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); |
if (!radeon_encoder) |
return; |
encoder = &radeon_encoder->base; |
encoder->possible_crtcs = 0x3; |
encoder->possible_clones = 0; |
radeon_encoder->enc_priv = NULL; |
radeon_encoder->encoder_id = encoder_id; |
radeon_encoder->devices = supported_device; |
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_LVDS: |
drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); |
drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); |
if (rdev->is_atom_bios) |
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); |
else |
radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder); |
radeon_encoder->rmx_type = RMX_FULL; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_TMDS1: |
drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); |
if (rdev->is_atom_bios) |
radeon_encoder->enc_priv = radeon_atombios_get_tmds_info(radeon_encoder); |
else |
radeon_encoder->enc_priv = radeon_combios_get_tmds_info(radeon_encoder); |
break; |
case ENCODER_OBJECT_ID_INTERNAL_DAC1: |
drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, DRM_MODE_ENCODER_DAC); |
drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); |
if (rdev->is_atom_bios) |
radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder); |
else |
radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder); |
break; |
case ENCODER_OBJECT_ID_INTERNAL_DAC2: |
drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC); |
drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); |
if (rdev->is_atom_bios) |
radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder); |
else |
radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder); |
break; |
case ENCODER_OBJECT_ID_INTERNAL_DVO1: |
drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); |
if (!rdev->is_atom_bios) |
radeon_combios_get_ext_tmds_info(radeon_encoder); |
break; |
} |
} |
/drivers/video/drm/radeon/radeon_mode.h |
---|
32,8 → 32,8 |
#include "drm_mode.h" |
#include "drm_crtc.h" |
#include <drm_edid.h> |
//#include <drm_edid.h> |
//#include <linux/i2c.h> |
//#include <linux/i2c-id.h> |
//#include <linux/i2c-algo-bit.h> |
148,8 → 148,8 |
struct radeon_i2c_chan { |
struct drm_device *dev; |
// struct i2c_adapter adapter; |
// struct i2c_algo_bit_data algo; |
struct i2c_adapter adapter; |
struct i2c_algo_bit_data algo; |
struct radeon_i2c_bus_rec rec; |
}; |
174,7 → 174,7 |
}; |
struct radeon_crtc { |
// struct drm_crtc base; |
struct drm_crtc base; |
int crtc_id; |
u16_t lut_r[256], lut_g[256], lut_b[256]; |
bool enabled; |
181,7 → 181,7 |
bool can_tile; |
uint32_t crtc_offset; |
struct radeon_framebuffer *fbdev_fb; |
// struct drm_mode_set mode_set; |
struct drm_mode_set mode_set; |
// struct drm_gem_object *cursor_bo; |
uint64_t cursor_addr; |
int cursor_width; |
272,8 → 272,8 |
}; |
struct radeon_framebuffer { |
// struct drm_framebuffer base; |
// struct drm_gem_object *obj; |
struct drm_framebuffer base; |
struct drm_gem_object *obj; |
}; |
extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, |
283,7 → 283,7 |
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); |
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); |
//extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); |
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); |
extern void radeon_compute_pll(struct radeon_pll *pll, |
uint64_t freq, |
302,7 → 302,6 |
extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); |
extern int atombios_get_encoder_mode(struct drm_encoder *encoder); |
/* |
extern void radeon_crtc_load_lut(struct drm_crtc *crtc); |
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
struct drm_framebuffer *old_fb); |
396,5 → 395,5 |
struct drm_display_mode *mode2, |
uint32_t pixel_bytes2); |
void radeon_init_disp_bandwidth(struct drm_device *dev); |
*/ |
#endif |