Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1122 → Rev 1123

/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