Merge branch 'radeon-for-airlied' of ../linux-2.6 into drm-linus
* 'radeon-for-airlied' of ../linux-2.6: drm/radeon/kms: prepare for more reclocking operations drm/radeon/kms: switch to condition waiting for reclocking drm/radeon/r600: add missing license and comments to r600_blit_shaders.c drm/radeon/kms: improve coding style a little drm/radeon/kms: remove dead audio/HDMI code drm/radeon/kms: enable audio engine on DCE32 drm/radeon/kms: add HDMI code for pre-DCE3 R6xx GPUs drm/radeon/kms: clean assigning HDMI blocks to encoders drm/radeon/kms: clean HDMI definitions drm/radeon/kms/rs4xx: make sure crtcs are enabled when setting timing drm/radeon/kms/r1xx: enable hw i2c drm/radeon/kms: fix i2c prescale calc on older radeons drm/radeon/kms: fix for hw i2c drm/radeon/kms: fix pal tv-out support on legacy IGP chips drm/radeon/kms: further spread spectrum fixes drm/radeon/kms: use lcd pll limits when available drm/radeon/kms/atom: spread spectrum fix drm/radeon/kms: catch atombios infinite loop and break out of it drm/radeon: add new RS880 pci id
This commit is contained in:
commit
1fc59eda33
|
@ -52,15 +52,17 @@
|
|||
|
||||
typedef struct {
|
||||
struct atom_context *ctx;
|
||||
|
||||
uint32_t *ps, *ws;
|
||||
int ps_shift;
|
||||
uint16_t start;
|
||||
unsigned last_jump;
|
||||
unsigned long last_jump_jiffies;
|
||||
bool abort;
|
||||
} atom_exec_context;
|
||||
|
||||
int atom_debug = 0;
|
||||
static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
|
||||
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
|
||||
static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
|
||||
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
|
||||
|
||||
static uint32_t atom_arg_mask[8] =
|
||||
{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
|
||||
|
@ -604,12 +606,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
|
|||
static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
|
||||
{
|
||||
int idx = U8((*ptr)++);
|
||||
int r = 0;
|
||||
|
||||
if (idx < ATOM_TABLE_NAMES_CNT)
|
||||
SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
|
||||
else
|
||||
SDEBUG(" table: %d\n", idx);
|
||||
if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
|
||||
atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
|
||||
r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
|
||||
if (r) {
|
||||
ctx->abort = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
|
||||
|
@ -673,6 +680,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
|
|||
static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
|
||||
{
|
||||
int execute = 0, target = U16(*ptr);
|
||||
unsigned long cjiffies;
|
||||
|
||||
(*ptr) += 2;
|
||||
switch (arg) {
|
||||
case ATOM_COND_ABOVE:
|
||||
|
@ -700,8 +709,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
|
|||
if (arg != ATOM_COND_ALWAYS)
|
||||
SDEBUG(" taken: %s\n", execute ? "yes" : "no");
|
||||
SDEBUG(" target: 0x%04X\n", target);
|
||||
if (execute)
|
||||
if (execute) {
|
||||
if (ctx->last_jump == (ctx->start + target)) {
|
||||
cjiffies = jiffies;
|
||||
if (time_after(cjiffies, ctx->last_jump_jiffies)) {
|
||||
cjiffies -= ctx->last_jump_jiffies;
|
||||
if ((jiffies_to_msecs(cjiffies) > 1000)) {
|
||||
DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n");
|
||||
ctx->abort = true;
|
||||
}
|
||||
} else {
|
||||
/* jiffies wrap around we will just wait a little longer */
|
||||
ctx->last_jump_jiffies = jiffies;
|
||||
}
|
||||
} else {
|
||||
ctx->last_jump = ctx->start + target;
|
||||
ctx->last_jump_jiffies = jiffies;
|
||||
}
|
||||
*ptr = ctx->start + target;
|
||||
}
|
||||
}
|
||||
|
||||
static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
|
||||
|
@ -1104,7 +1130,7 @@ static struct {
|
|||
atom_op_shr, ATOM_ARG_MC}, {
|
||||
atom_op_debug, 0},};
|
||||
|
||||
static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
|
||||
static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
|
||||
{
|
||||
int base = CU16(ctx->cmd_table + 4 + 2 * index);
|
||||
int len, ws, ps, ptr;
|
||||
|
@ -1112,7 +1138,7 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|||
atom_exec_context ectx;
|
||||
|
||||
if (!base)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
len = CU16(base + ATOM_CT_SIZE_PTR);
|
||||
ws = CU8(base + ATOM_CT_WS_PTR);
|
||||
|
@ -1125,6 +1151,8 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|||
ectx.ps_shift = ps / 4;
|
||||
ectx.start = base;
|
||||
ectx.ps = params;
|
||||
ectx.abort = false;
|
||||
ectx.last_jump = 0;
|
||||
if (ws)
|
||||
ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
|
||||
else
|
||||
|
@ -1137,6 +1165,11 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|||
SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
|
||||
else
|
||||
SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
|
||||
if (ectx.abort) {
|
||||
DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
|
||||
base, len, ws, ps, ptr - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (op < ATOM_OP_CNT && op > 0)
|
||||
opcode_table[op].func(&ectx, &ptr,
|
||||
|
@ -1152,10 +1185,13 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
|
|||
|
||||
if (ws)
|
||||
kfree(ectx.ws);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
||||
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&ctx->mutex);
|
||||
/* reset reg block */
|
||||
ctx->reg_block = 0;
|
||||
|
@ -1163,8 +1199,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
|
|||
ctx->fb_base = 0;
|
||||
/* reset io mode */
|
||||
ctx->io_mode = ATOM_IO_MM;
|
||||
atom_execute_table_locked(ctx, index, params);
|
||||
r = atom_execute_table_locked(ctx, index, params);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
|
||||
|
@ -1248,9 +1285,7 @@ int atom_asic_init(struct atom_context *ctx)
|
|||
|
||||
if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
|
||||
return 1;
|
||||
atom_execute_table(ctx, ATOM_CMD_INIT, ps);
|
||||
|
||||
return 0;
|
||||
return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
|
||||
}
|
||||
|
||||
void atom_destroy(struct atom_context *ctx)
|
||||
|
|
|
@ -140,7 +140,7 @@ struct atom_context {
|
|||
extern int atom_debug;
|
||||
|
||||
struct atom_context *atom_parse(struct card_info *, void *);
|
||||
void atom_execute_table(struct atom_context *, int, uint32_t *);
|
||||
int atom_execute_table(struct atom_context *, int, uint32_t *);
|
||||
int atom_asic_init(struct atom_context *);
|
||||
void atom_destroy(struct atom_context *);
|
||||
void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start);
|
||||
|
|
|
@ -353,12 +353,55 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
|
|||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
}
|
||||
|
||||
static void atombios_disable_ss(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;
|
||||
u32 ss_cntl;
|
||||
|
||||
if (ASIC_IS_DCE4(rdev)) {
|
||||
switch (radeon_crtc->pll_id) {
|
||||
case ATOM_PPLL1:
|
||||
ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL);
|
||||
ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
|
||||
WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl);
|
||||
break;
|
||||
case ATOM_PPLL2:
|
||||
ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL);
|
||||
ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
|
||||
WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl);
|
||||
break;
|
||||
case ATOM_DCPLL:
|
||||
case ATOM_PPLL_INVALID:
|
||||
return;
|
||||
}
|
||||
} else if (ASIC_IS_AVIVO(rdev)) {
|
||||
switch (radeon_crtc->pll_id) {
|
||||
case ATOM_PPLL1:
|
||||
ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
|
||||
ss_cntl &= ~1;
|
||||
WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl);
|
||||
break;
|
||||
case ATOM_PPLL2:
|
||||
ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
|
||||
ss_cntl &= ~1;
|
||||
WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl);
|
||||
break;
|
||||
case ATOM_DCPLL:
|
||||
case ATOM_PPLL_INVALID:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
union atom_enable_ss {
|
||||
ENABLE_LVDS_SS_PARAMETERS legacy;
|
||||
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
|
||||
};
|
||||
|
||||
static void atombios_set_ss(struct drm_crtc *crtc, int enable)
|
||||
static void atombios_enable_ss(struct drm_crtc *crtc)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
@ -387,9 +430,9 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
|
|||
step = dig->ss->step;
|
||||
delay = dig->ss->delay;
|
||||
range = dig->ss->range;
|
||||
} else if (enable)
|
||||
} else
|
||||
return;
|
||||
} else if (enable)
|
||||
} else
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
@ -406,13 +449,13 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
|
|||
args.v1.ucSpreadSpectrumDelay = delay;
|
||||
args.v1.ucSpreadSpectrumRange = range;
|
||||
args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
|
||||
args.v1.ucEnable = enable;
|
||||
args.v1.ucEnable = ATOM_ENABLE;
|
||||
} else {
|
||||
args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
|
||||
args.legacy.ucSpreadSpectrumType = type;
|
||||
args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
|
||||
args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
|
||||
args.legacy.ucEnable = enable;
|
||||
args.legacy.ucEnable = ATOM_ENABLE;
|
||||
}
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
}
|
||||
|
@ -482,6 +525,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
pll->algo = dig->pll_algo;
|
||||
pll->flags |= RADEON_PLL_IS_LCD;
|
||||
}
|
||||
} else {
|
||||
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
|
||||
|
@ -1083,15 +1127,12 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
|
|||
|
||||
/* TODO color tiling */
|
||||
|
||||
/* pick pll */
|
||||
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
|
||||
|
||||
atombios_set_ss(crtc, 0);
|
||||
atombios_disable_ss(crtc);
|
||||
/* always set DCPLL */
|
||||
if (ASIC_IS_DCE4(rdev))
|
||||
atombios_crtc_set_dcpll(crtc);
|
||||
atombios_crtc_set_pll(crtc, adjusted_mode);
|
||||
atombios_set_ss(crtc, 1);
|
||||
atombios_enable_ss(crtc);
|
||||
|
||||
if (ASIC_IS_DCE4(rdev))
|
||||
atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
|
||||
|
@ -1120,6 +1161,11 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
|
|||
|
||||
static void atombios_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
|
||||
/* pick pll */
|
||||
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
|
||||
|
||||
atombios_lock_crtc(crtc, ATOM_ENABLE);
|
||||
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
|
|
@ -312,10 +312,12 @@ int r100_irq_process(struct radeon_device *rdev)
|
|||
/* Vertical blank interrupts */
|
||||
if (status & RADEON_CRTC_VBLANK_STAT) {
|
||||
drm_handle_vblank(rdev->ddev, 0);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (status & RADEON_CRTC2_VBLANK_STAT) {
|
||||
drm_handle_vblank(rdev->ddev, 1);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (status & RADEON_FP_DETECT_STAT) {
|
||||
|
|
|
@ -2765,6 +2765,7 @@ restart_ih:
|
|||
case 0: /* D1 vblank */
|
||||
if (disp_int & LB_D1_VBLANK_INTERRUPT) {
|
||||
drm_handle_vblank(rdev->ddev, 0);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
disp_int &= ~LB_D1_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D1 vblank\n");
|
||||
|
@ -2786,6 +2787,7 @@ restart_ih:
|
|||
case 0: /* D2 vblank */
|
||||
if (disp_int & LB_D2_VBLANK_INTERRUPT) {
|
||||
drm_handle_vblank(rdev->ddev, 1);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
disp_int &= ~LB_D2_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D2 vblank\n");
|
||||
|
|
|
@ -181,41 +181,6 @@ int r600_audio_init(struct radeon_device *rdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* determin how the encoders and audio interface is wired together
|
||||
*/
|
||||
int r600_audio_tmds_index(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
struct drm_encoder *other;
|
||||
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||||
return 0;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
/* special case check if an TMDS1 is present */
|
||||
list_for_each_entry(other, &dev->mode_config.encoder_list, head) {
|
||||
if (to_radeon_encoder(other)->encoder_id ==
|
||||
ENCODER_OBJECT_ID_INTERNAL_TMDS1)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
DRM_ERROR("Unsupported encoder type 0x%02X\n",
|
||||
radeon_encoder->encoder_id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* atach the audio codec to the clock source of the encoder
|
||||
*/
|
||||
|
@ -224,6 +189,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
|
|||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
int base_rate = 48000;
|
||||
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
|
@ -231,32 +197,34 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
|
|||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
|
||||
break;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
|
||||
WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
|
||||
break;
|
||||
|
||||
default:
|
||||
DRM_ERROR("Unsupported encoder type 0x%02X\n",
|
||||
radeon_encoder->encoder_id);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (r600_audio_tmds_index(encoder)) {
|
||||
switch (dig->dig_encoder) {
|
||||
case 0:
|
||||
WREG32(R600_AUDIO_PLL1_MUL, base_rate*50);
|
||||
WREG32(R600_AUDIO_PLL1_DIV, clock*100);
|
||||
WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
|
||||
WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
|
||||
WREG32(R600_AUDIO_CLK_SRCSEL, 0);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
WREG32(R600_AUDIO_PLL2_MUL, base_rate*50);
|
||||
WREG32(R600_AUDIO_PLL2_DIV, clock*100);
|
||||
WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
|
||||
WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
|
||||
WREG32(R600_AUDIO_CLK_SRCSEL, 1);
|
||||
break;
|
||||
default:
|
||||
dev_err(rdev->dev, "Unsupported DIG on encoder 0x%02X\n",
|
||||
radeon_encoder->encoder_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,42 @@
|
|||
/*
|
||||
* Copyright 2009 Advanced Micro Devices, 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 (including the next
|
||||
* paragraph) 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) AND/OR ITS SUPPLIERS 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:
|
||||
* Alex Deucher <alexander.deucher@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/*
|
||||
* R6xx+ cards need to use the 3D engine to blit data which requires
|
||||
* quite a bit of hw state setup. Rather than pull the whole 3D driver
|
||||
* (which normally generates the 3D state) into the DRM, we opt to use
|
||||
* statically generated state tables. The regsiter state and shaders
|
||||
* were hand generated to support blitting functionality. See the 3D
|
||||
* driver or documentation for descriptions of the registers and
|
||||
* shader instructions.
|
||||
*/
|
||||
|
||||
const u32 r6xx_default_state[] =
|
||||
{
|
||||
0xc0002400,
|
||||
|
|
|
@ -42,13 +42,13 @@ enum r600_hdmi_color_format {
|
|||
*/
|
||||
enum r600_hdmi_iec_status_bits {
|
||||
AUDIO_STATUS_DIG_ENABLE = 0x01,
|
||||
AUDIO_STATUS_V = 0x02,
|
||||
AUDIO_STATUS_VCFG = 0x04,
|
||||
AUDIO_STATUS_V = 0x02,
|
||||
AUDIO_STATUS_VCFG = 0x04,
|
||||
AUDIO_STATUS_EMPHASIS = 0x08,
|
||||
AUDIO_STATUS_COPYRIGHT = 0x10,
|
||||
AUDIO_STATUS_NONAUDIO = 0x20,
|
||||
AUDIO_STATUS_PROFESSIONAL = 0x40,
|
||||
AUDIO_STATUS_LEVEL = 0x80
|
||||
AUDIO_STATUS_LEVEL = 0x80
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -85,7 +85,7 @@ struct {
|
|||
static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
|
||||
{
|
||||
if (*CTS == 0)
|
||||
*CTS = clock*N/(128*freq)*1000;
|
||||
*CTS = clock * N / (128 * freq) * 1000;
|
||||
DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
|
||||
N, *CTS, freq);
|
||||
}
|
||||
|
@ -131,11 +131,11 @@ static void r600_hdmi_infoframe_checksum(uint8_t packetType,
|
|||
uint8_t length,
|
||||
uint8_t *frame)
|
||||
{
|
||||
int i;
|
||||
frame[0] = packetType + versionNumber + length;
|
||||
for (i = 1; i <= length; i++)
|
||||
frame[0] += frame[i];
|
||||
frame[0] = 0x100 - frame[0];
|
||||
int i;
|
||||
frame[0] = packetType + versionNumber + length;
|
||||
for (i = 1; i <= length; i++)
|
||||
frame[0] += frame[i];
|
||||
frame[0] = 0x100 - frame[0];
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -417,90 +417,141 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
|
|||
WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000);
|
||||
}
|
||||
|
||||
/*
|
||||
* enable/disable the HDMI engine
|
||||
*/
|
||||
void r600_hdmi_enable(struct drm_encoder *encoder, int enable)
|
||||
static int r600_hdmi_find_free_block(struct drm_device *dev)
|
||||
{
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct drm_encoder *encoder;
|
||||
struct radeon_encoder *radeon_encoder;
|
||||
bool free_blocks[3] = { true, true, true };
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
radeon_encoder = to_radeon_encoder(encoder);
|
||||
switch (radeon_encoder->hdmi_offset) {
|
||||
case R600_HDMI_BLOCK1:
|
||||
free_blocks[0] = false;
|
||||
break;
|
||||
case R600_HDMI_BLOCK2:
|
||||
free_blocks[1] = false;
|
||||
break;
|
||||
case R600_HDMI_BLOCK3:
|
||||
free_blocks[2] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690) {
|
||||
return free_blocks[0] ? R600_HDMI_BLOCK1 : 0;
|
||||
} else if (rdev->family >= CHIP_R600) {
|
||||
if (free_blocks[0])
|
||||
return R600_HDMI_BLOCK1;
|
||||
else if (free_blocks[1])
|
||||
return R600_HDMI_BLOCK2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void r600_hdmi_assign_block(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
|
||||
if (!offset)
|
||||
if (!dig) {
|
||||
dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset);
|
||||
|
||||
/* some version of atombios ignore the enable HDMI flag
|
||||
* so enabling/disabling HDMI was moved here for TMDS1+2 */
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||||
WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4);
|
||||
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0);
|
||||
break;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
WREG32_P(AVIVO_LVTMA_CNTL, enable ? 0x4 : 0x0, ~0x4);
|
||||
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x105 : 0x0);
|
||||
break;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
|
||||
/* This part is doubtfull in my opinion */
|
||||
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x110 : 0x0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DRM_ERROR("unknown HDMI output type\n");
|
||||
break;
|
||||
if (ASIC_IS_DCE4(rdev)) {
|
||||
/* TODO */
|
||||
} else if (ASIC_IS_DCE3(rdev)) {
|
||||
radeon_encoder->hdmi_offset = dig->dig_encoder ?
|
||||
R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1;
|
||||
if (ASIC_IS_DCE32(rdev))
|
||||
radeon_encoder->hdmi_config_offset = dig->dig_encoder ?
|
||||
R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1;
|
||||
} else if (rdev->family >= CHIP_R600) {
|
||||
radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* determin at which register offset the HDMI encoder is
|
||||
* enable the HDMI engine
|
||||
*/
|
||||
void r600_hdmi_init(struct drm_encoder *encoder)
|
||||
void r600_hdmi_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||||
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
|
||||
break;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
switch (r600_audio_tmds_index(encoder)) {
|
||||
case 0:
|
||||
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
|
||||
break;
|
||||
case 1:
|
||||
radeon_encoder->hdmi_offset = R600_HDMI_TMDS2;
|
||||
break;
|
||||
default:
|
||||
radeon_encoder->hdmi_offset = 0;
|
||||
break;
|
||||
if (!radeon_encoder->hdmi_offset) {
|
||||
r600_hdmi_assign_block(encoder);
|
||||
if (!radeon_encoder->hdmi_offset) {
|
||||
dev_warn(rdev->dev, "Could not find HDMI block for "
|
||||
"0x%x encoder\n", radeon_encoder->encoder_id);
|
||||
return;
|
||||
}
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
|
||||
radeon_encoder->hdmi_offset = R600_HDMI_TMDS2;
|
||||
break;
|
||||
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
|
||||
radeon_encoder->hdmi_offset = R600_HDMI_DIG;
|
||||
break;
|
||||
|
||||
default:
|
||||
radeon_encoder->hdmi_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_DEBUG("using HDMI engine at offset 0x%04X for encoder 0x%x\n",
|
||||
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
|
||||
if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
|
||||
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
|
||||
} else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
|
||||
int offset = radeon_encoder->hdmi_offset;
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||||
WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4);
|
||||
WREG32(offset + R600_HDMI_ENABLE, 0x101);
|
||||
break;
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4);
|
||||
WREG32(offset + R600_HDMI_ENABLE, 0x105);
|
||||
break;
|
||||
default:
|
||||
dev_err(rdev->dev, "Unknown HDMI output type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: make this configureable */
|
||||
radeon_encoder->hdmi_audio_workaround = 0;
|
||||
DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
|
||||
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable the HDMI engine
|
||||
*/
|
||||
void r600_hdmi_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
|
||||
if (!radeon_encoder->hdmi_offset) {
|
||||
dev_err(rdev->dev, "Disabling not enabled HDMI\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n",
|
||||
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
|
||||
|
||||
if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
|
||||
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
|
||||
} else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
|
||||
int offset = radeon_encoder->hdmi_offset;
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
|
||||
WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4);
|
||||
WREG32(offset + R600_HDMI_ENABLE, 0);
|
||||
break;
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
|
||||
WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4);
|
||||
WREG32(offset + R600_HDMI_ENABLE, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(rdev->dev, "Unknown HDMI output type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
radeon_encoder->hdmi_offset = 0;
|
||||
radeon_encoder->hdmi_config_offset = 0;
|
||||
}
|
||||
|
|
|
@ -152,9 +152,9 @@
|
|||
#define R600_AUDIO_STATUS_BITS 0x73d8
|
||||
|
||||
/* HDMI base register addresses */
|
||||
#define R600_HDMI_TMDS1 0x7400
|
||||
#define R600_HDMI_TMDS2 0x7700
|
||||
#define R600_HDMI_DIG 0x7800
|
||||
#define R600_HDMI_BLOCK1 0x7400
|
||||
#define R600_HDMI_BLOCK2 0x7700
|
||||
#define R600_HDMI_BLOCK3 0x7800
|
||||
|
||||
/* HDMI registers */
|
||||
#define R600_HDMI_ENABLE 0x00
|
||||
|
@ -185,4 +185,8 @@
|
|||
#define R600_HDMI_AUDIO_DEBUG_2 0xe8
|
||||
#define R600_HDMI_AUDIO_DEBUG_3 0xec
|
||||
|
||||
/* HDMI additional config base register addresses */
|
||||
#define R600_HDMI_CONFIG1 0x7600
|
||||
#define R600_HDMI_CONFIG2 0x7a00
|
||||
|
||||
#endif
|
||||
|
|
|
@ -687,6 +687,7 @@ struct radeon_pm {
|
|||
bool downclocked;
|
||||
int active_crtcs;
|
||||
int req_vblank;
|
||||
bool vblank_sync;
|
||||
fixed20_12 max_bandwidth;
|
||||
fixed20_12 igp_sideport_mclk;
|
||||
fixed20_12 igp_system_mclk;
|
||||
|
@ -1322,7 +1323,8 @@ extern int r600_audio_tmds_index(struct drm_encoder *encoder);
|
|||
extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
|
||||
extern void r600_audio_fini(struct radeon_device *rdev);
|
||||
extern void r600_hdmi_init(struct drm_encoder *encoder);
|
||||
extern void r600_hdmi_enable(struct drm_encoder *encoder, int enable);
|
||||
extern void r600_hdmi_enable(struct drm_encoder *encoder);
|
||||
extern void r600_hdmi_disable(struct drm_encoder *encoder);
|
||||
extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
|
||||
extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
|
||||
extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
|
||||
|
|
|
@ -887,6 +887,20 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
|
|||
p1pll->pll_out_max =
|
||||
le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
|
||||
|
||||
if (crev >= 4) {
|
||||
p1pll->lcd_pll_out_min =
|
||||
le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
|
||||
if (p1pll->lcd_pll_out_min == 0)
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max =
|
||||
le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
|
||||
if (p1pll->lcd_pll_out_max == 0)
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
} else {
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
}
|
||||
|
||||
if (p1pll->pll_out_min == 0) {
|
||||
if (ASIC_IS_AVIVO(rdev))
|
||||
p1pll->pll_out_min = 64800;
|
||||
|
|
|
@ -531,10 +531,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
|
|||
case CHIP_RS300:
|
||||
switch (ddc_line) {
|
||||
case RADEON_GPIO_DVI_DDC:
|
||||
/* in theory this should be hw capable,
|
||||
* but it doesn't seem to work
|
||||
*/
|
||||
i2c.hw_capable = false;
|
||||
i2c.hw_capable = true;
|
||||
break;
|
||||
default:
|
||||
i2c.hw_capable = false;
|
||||
|
@ -633,6 +630,8 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
|
|||
p1pll->reference_div = RBIOS16(pll_info + 0x10);
|
||||
p1pll->pll_out_min = RBIOS32(pll_info + 0x12);
|
||||
p1pll->pll_out_max = RBIOS32(pll_info + 0x16);
|
||||
p1pll->lcd_pll_out_min = p1pll->pll_out_min;
|
||||
p1pll->lcd_pll_out_max = p1pll->pll_out_max;
|
||||
|
||||
if (rev > 9) {
|
||||
p1pll->pll_in_min = RBIOS32(pll_info + 0x36);
|
||||
|
|
|
@ -469,10 +469,19 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
|||
uint32_t best_error = 0xffffffff;
|
||||
uint32_t best_vco_diff = 1;
|
||||
uint32_t post_div;
|
||||
u32 pll_out_min, pll_out_max;
|
||||
|
||||
DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
|
||||
freq = freq * 1000;
|
||||
|
||||
if (pll->flags & RADEON_PLL_IS_LCD) {
|
||||
pll_out_min = pll->lcd_pll_out_min;
|
||||
pll_out_max = pll->lcd_pll_out_max;
|
||||
} else {
|
||||
pll_out_min = pll->pll_out_min;
|
||||
pll_out_max = pll->pll_out_max;
|
||||
}
|
||||
|
||||
if (pll->flags & RADEON_PLL_USE_REF_DIV)
|
||||
min_ref_div = max_ref_div = pll->reference_div;
|
||||
else {
|
||||
|
@ -536,10 +545,10 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
|||
tmp = (uint64_t)pll->reference_freq * feedback_div;
|
||||
vco = radeon_div(tmp, ref_div);
|
||||
|
||||
if (vco < pll->pll_out_min) {
|
||||
if (vco < pll_out_min) {
|
||||
min_feed_div = feedback_div + 1;
|
||||
continue;
|
||||
} else if (vco > pll->pll_out_max) {
|
||||
} else if (vco > pll_out_max) {
|
||||
max_feed_div = feedback_div;
|
||||
continue;
|
||||
}
|
||||
|
@ -675,6 +684,15 @@ calc_fb_ref_div(struct radeon_pll *pll,
|
|||
{
|
||||
fixed20_12 ffreq, max_error, error, pll_out, a;
|
||||
u32 vco;
|
||||
u32 pll_out_min, pll_out_max;
|
||||
|
||||
if (pll->flags & RADEON_PLL_IS_LCD) {
|
||||
pll_out_min = pll->lcd_pll_out_min;
|
||||
pll_out_max = pll->lcd_pll_out_max;
|
||||
} else {
|
||||
pll_out_min = pll->pll_out_min;
|
||||
pll_out_max = pll->pll_out_max;
|
||||
}
|
||||
|
||||
ffreq.full = rfixed_const(freq);
|
||||
/* max_error = ffreq * 0.0025; */
|
||||
|
@ -686,7 +704,7 @@ calc_fb_ref_div(struct radeon_pll *pll,
|
|||
vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
|
||||
vco = vco / ((*ref_div) * 10);
|
||||
|
||||
if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max))
|
||||
if ((vco < pll_out_min) || (vco > pll_out_max))
|
||||
continue;
|
||||
|
||||
/* pll_out = vco / post_div; */
|
||||
|
@ -714,6 +732,15 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
|||
{
|
||||
u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
|
||||
u32 best_freq = 0, vco_frequency;
|
||||
u32 pll_out_min, pll_out_max;
|
||||
|
||||
if (pll->flags & RADEON_PLL_IS_LCD) {
|
||||
pll_out_min = pll->lcd_pll_out_min;
|
||||
pll_out_max = pll->lcd_pll_out_max;
|
||||
} else {
|
||||
pll_out_min = pll->pll_out_min;
|
||||
pll_out_max = pll->pll_out_max;
|
||||
}
|
||||
|
||||
/* freq = freq / 10; */
|
||||
do_div(freq, 10);
|
||||
|
@ -724,7 +751,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
|||
goto done;
|
||||
|
||||
vco_frequency = freq * post_div;
|
||||
if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
|
||||
if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
|
||||
goto done;
|
||||
|
||||
if (pll->flags & RADEON_PLL_USE_REF_DIV) {
|
||||
|
@ -749,7 +776,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
|
|||
continue;
|
||||
|
||||
vco_frequency = freq * post_div;
|
||||
if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
|
||||
if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
|
||||
continue;
|
||||
if (pll->flags & RADEON_PLL_USE_REF_DIV) {
|
||||
ref_div = pll->reference_div;
|
||||
|
|
|
@ -593,7 +593,6 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
|
|||
}
|
||||
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
r600_hdmi_enable(encoder, hdmi_detected);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1216,6 +1215,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
|
|||
}
|
||||
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
|
||||
/* update scratch regs with new routing */
|
||||
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1326,19 +1328,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
|
|||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
|
||||
|
||||
if (radeon_encoder->active_device &
|
||||
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
if (dig)
|
||||
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
|
||||
}
|
||||
radeon_encoder->pixel_clock = adjusted_mode->clock;
|
||||
|
||||
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
|
||||
atombios_set_encoder_crtc_source(encoder);
|
||||
|
||||
if (ASIC_IS_AVIVO(rdev)) {
|
||||
if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
|
||||
atombios_yuv_setup(encoder, true);
|
||||
|
@ -1396,9 +1388,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
|
|||
}
|
||||
atombios_apply_encoder_quirks(encoder, adjusted_mode);
|
||||
|
||||
/* XXX */
|
||||
if (!ASIC_IS_DCE4(rdev))
|
||||
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
|
||||
r600_hdmi_enable(encoder);
|
||||
r600_hdmi_setmode(encoder, adjusted_mode);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1492,8 +1485,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
|
|||
|
||||
static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
|
||||
if (radeon_encoder->active_device &
|
||||
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
if (dig)
|
||||
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
|
||||
}
|
||||
|
||||
radeon_atom_output_lock(encoder, true);
|
||||
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
/* this is needed for the pll/ss setup to work correctly in some cases */
|
||||
atombios_set_encoder_crtc_source(encoder);
|
||||
}
|
||||
|
||||
static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
|
||||
|
@ -1509,6 +1514,8 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
|
|||
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
if (radeon_encoder_is_digital(encoder)) {
|
||||
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
|
||||
r600_hdmi_disable(encoder);
|
||||
dig = radeon_encoder->enc_priv;
|
||||
dig->dig_encoder = -1;
|
||||
}
|
||||
|
@ -1659,6 +1666,4 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
|
|||
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
|
||||
break;
|
||||
}
|
||||
|
||||
r600_hdmi_init(encoder);
|
||||
}
|
||||
|
|
|
@ -183,11 +183,10 @@ static void set_data(void *i2c_priv, int data)
|
|||
|
||||
static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
|
||||
{
|
||||
struct radeon_pll *spll = &rdev->clock.spll;
|
||||
u32 sclk = radeon_get_engine_clock(rdev);
|
||||
u32 prescale = 0;
|
||||
u32 n, m;
|
||||
u8 loop;
|
||||
u32 nm;
|
||||
u8 n, m, loop;
|
||||
int i2c_clock;
|
||||
|
||||
switch (rdev->family) {
|
||||
|
@ -203,13 +202,15 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
|
|||
case CHIP_R300:
|
||||
case CHIP_R350:
|
||||
case CHIP_RV350:
|
||||
n = (spll->reference_freq) / (4 * 6);
|
||||
i2c_clock = 60;
|
||||
nm = (sclk * 10) / (i2c_clock * 4);
|
||||
for (loop = 1; loop < 255; loop++) {
|
||||
if ((loop * (loop - 1)) > n)
|
||||
if ((nm / loop) < loop)
|
||||
break;
|
||||
}
|
||||
m = loop - 1;
|
||||
prescale = m | (loop << 8);
|
||||
n = loop - 1;
|
||||
m = loop - 2;
|
||||
prescale = m | (n << 8);
|
||||
break;
|
||||
case CHIP_RV380:
|
||||
case CHIP_RS400:
|
||||
|
@ -217,7 +218,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
|
|||
case CHIP_R420:
|
||||
case CHIP_R423:
|
||||
case CHIP_RV410:
|
||||
sclk = radeon_get_engine_clock(rdev);
|
||||
prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
|
||||
break;
|
||||
case CHIP_RS600:
|
||||
|
@ -232,7 +232,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
|
|||
case CHIP_RV570:
|
||||
case CHIP_R580:
|
||||
i2c_clock = 50;
|
||||
sclk = radeon_get_engine_clock(rdev);
|
||||
if (rdev->family == CHIP_R520)
|
||||
prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
|
||||
else
|
||||
|
@ -291,6 +290,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
prescale = radeon_get_i2c_prescale(rdev);
|
||||
|
||||
reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
|
||||
RADEON_I2C_DRIVE_EN |
|
||||
RADEON_I2C_START |
|
||||
RADEON_I2C_STOP |
|
||||
RADEON_I2C_GO);
|
||||
|
|
|
@ -603,6 +603,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
|
|||
? RADEON_CRTC2_INTERLACE_EN
|
||||
: 0));
|
||||
|
||||
/* rs4xx chips seem to like to have the crtc enabled when the timing is set */
|
||||
if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
|
||||
crtc2_gen_cntl |= RADEON_CRTC2_EN;
|
||||
|
||||
disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
|
||||
disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
|
||||
|
||||
|
@ -630,6 +634,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
|
|||
? RADEON_CRTC_INTERLACE_EN
|
||||
: 0));
|
||||
|
||||
/* rs4xx chips seem to like to have the crtc enabled when the timing is set */
|
||||
if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
|
||||
crtc_gen_cntl |= RADEON_CRTC_EN;
|
||||
|
||||
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
|
||||
crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
|
||||
RADEON_CRTC_VSYNC_DIS |
|
||||
|
|
|
@ -57,6 +57,10 @@
|
|||
#define NTSC_TV_PLL_N_14 693
|
||||
#define NTSC_TV_PLL_P_14 7
|
||||
|
||||
#define PAL_TV_PLL_M_14 19
|
||||
#define PAL_TV_PLL_N_14 353
|
||||
#define PAL_TV_PLL_P_14 5
|
||||
|
||||
#define VERT_LEAD_IN_LINES 2
|
||||
#define FRAC_BITS 0xe
|
||||
#define FRAC_MASK 0x3fff
|
||||
|
@ -205,9 +209,24 @@ static const struct radeon_tv_mode_constants available_tv_modes[] = {
|
|||
630627, /* defRestart */
|
||||
347, /* crtcPLL_N */
|
||||
14, /* crtcPLL_M */
|
||||
8, /* crtcPLL_postDiv */
|
||||
8, /* crtcPLL_postDiv */
|
||||
1022, /* pixToTV */
|
||||
},
|
||||
{ /* PAL timing for 14 Mhz ref clk */
|
||||
800, /* horResolution */
|
||||
600, /* verResolution */
|
||||
TV_STD_PAL, /* standard */
|
||||
1131, /* horTotal */
|
||||
742, /* verTotal */
|
||||
813, /* horStart */
|
||||
840, /* horSyncStart */
|
||||
633, /* verSyncStart */
|
||||
708369, /* defRestart */
|
||||
211, /* crtcPLL_N */
|
||||
9, /* crtcPLL_M */
|
||||
8, /* crtcPLL_postDiv */
|
||||
759, /* pixToTV */
|
||||
},
|
||||
};
|
||||
|
||||
#define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes)
|
||||
|
@ -242,7 +261,7 @@ static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(stru
|
|||
if (pll->reference_freq == 2700)
|
||||
const_ptr = &available_tv_modes[1];
|
||||
else
|
||||
const_ptr = &available_tv_modes[1]; /* FIX ME */
|
||||
const_ptr = &available_tv_modes[3];
|
||||
}
|
||||
return const_ptr;
|
||||
}
|
||||
|
@ -685,9 +704,9 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
|
|||
n = PAL_TV_PLL_N_27;
|
||||
p = PAL_TV_PLL_P_27;
|
||||
} else {
|
||||
m = PAL_TV_PLL_M_27;
|
||||
n = PAL_TV_PLL_N_27;
|
||||
p = PAL_TV_PLL_P_27;
|
||||
m = PAL_TV_PLL_M_14;
|
||||
n = PAL_TV_PLL_N_14;
|
||||
p = PAL_TV_PLL_P_14;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ struct radeon_tmds_pll {
|
|||
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
|
||||
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
|
||||
#define RADEON_PLL_USE_POST_DIV (1 << 12)
|
||||
#define RADEON_PLL_IS_LCD (1 << 13)
|
||||
|
||||
/* pll algo */
|
||||
enum radeon_pll_algo {
|
||||
|
@ -149,6 +150,8 @@ struct radeon_pll {
|
|||
uint32_t pll_in_max;
|
||||
uint32_t pll_out_min;
|
||||
uint32_t pll_out_max;
|
||||
uint32_t lcd_pll_out_min;
|
||||
uint32_t lcd_pll_out_max;
|
||||
uint32_t best_vco;
|
||||
|
||||
/* divider limits */
|
||||
|
@ -342,6 +345,7 @@ struct radeon_encoder {
|
|||
struct drm_display_mode native_mode;
|
||||
void *enc_priv;
|
||||
int hdmi_offset;
|
||||
int hdmi_config_offset;
|
||||
int hdmi_audio_workaround;
|
||||
int hdmi_buffer_status;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define RADEON_RECLOCK_DELAY_MS 200
|
||||
#define RADEON_WAIT_VBLANK_TIMEOUT 200
|
||||
|
||||
static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
|
||||
static void radeon_pm_set_clocks_locked(struct radeon_device *rdev);
|
||||
static void radeon_pm_set_clocks(struct radeon_device *rdev);
|
||||
static void radeon_pm_idle_work_handler(struct work_struct *work);
|
||||
|
@ -179,6 +180,16 @@ static void radeon_get_power_state(struct radeon_device *rdev,
|
|||
rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
|
||||
}
|
||||
|
||||
static inline void radeon_sync_with_vblank(struct radeon_device *rdev)
|
||||
{
|
||||
if (rdev->pm.active_crtcs) {
|
||||
rdev->pm.vblank_sync = false;
|
||||
wait_event_timeout(
|
||||
rdev->irq.vblank_queue, rdev->pm.vblank_sync,
|
||||
msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
|
||||
}
|
||||
}
|
||||
|
||||
static void radeon_set_power_state(struct radeon_device *rdev)
|
||||
{
|
||||
/* if *_clock_mode are the same, *_power_state are as well */
|
||||
|
@ -189,11 +200,28 @@ static void radeon_set_power_state(struct radeon_device *rdev)
|
|||
rdev->pm.requested_clock_mode->sclk,
|
||||
rdev->pm.requested_clock_mode->mclk,
|
||||
rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
|
||||
|
||||
/* set pcie lanes */
|
||||
/* TODO */
|
||||
|
||||
/* set voltage */
|
||||
/* TODO */
|
||||
|
||||
/* set engine clock */
|
||||
radeon_sync_with_vblank(rdev);
|
||||
radeon_pm_debug_check_in_vbl(rdev, false);
|
||||
radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
|
||||
radeon_pm_debug_check_in_vbl(rdev, true);
|
||||
|
||||
#if 0
|
||||
/* set memory clock */
|
||||
if (rdev->asic->set_memory_clock) {
|
||||
radeon_sync_with_vblank(rdev);
|
||||
radeon_pm_debug_check_in_vbl(rdev, false);
|
||||
radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk);
|
||||
radeon_pm_debug_check_in_vbl(rdev, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
rdev->pm.current_power_state = rdev->pm.requested_power_state;
|
||||
rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode;
|
||||
|
@ -333,10 +361,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
|
|||
break;
|
||||
}
|
||||
|
||||
/* check if we are in vblank */
|
||||
radeon_pm_debug_check_in_vbl(rdev, false);
|
||||
radeon_set_power_state(rdev);
|
||||
radeon_pm_debug_check_in_vbl(rdev, true);
|
||||
rdev->pm.planned_action = PM_ACTION_NONE;
|
||||
}
|
||||
|
||||
|
@ -353,10 +378,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
|
|||
rdev->pm.req_vblank |= (1 << 1);
|
||||
drm_vblank_get(rdev->ddev, 1);
|
||||
}
|
||||
if (rdev->pm.active_crtcs)
|
||||
wait_event_interruptible_timeout(
|
||||
rdev->irq.vblank_queue, 0,
|
||||
msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
|
||||
radeon_pm_set_clocks_locked(rdev);
|
||||
if (rdev->pm.req_vblank & (1 << 0)) {
|
||||
rdev->pm.req_vblank &= ~(1 << 0);
|
||||
drm_vblank_put(rdev->ddev, 0);
|
||||
|
@ -366,7 +388,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
|
|||
drm_vblank_put(rdev->ddev, 1);
|
||||
}
|
||||
|
||||
radeon_pm_set_clocks_locked(rdev);
|
||||
mutex_unlock(&rdev->cp.mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -392,10 +392,12 @@ int rs600_irq_process(struct radeon_device *rdev)
|
|||
/* Vertical blank interrupts */
|
||||
if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
|
||||
drm_handle_vblank(rdev->ddev, 0);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
|
||||
drm_handle_vblank(rdev->ddev, 1);
|
||||
rdev->pm.vblank_sync = true;
|
||||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
|
||||
|
|
|
@ -1013,6 +1013,13 @@ int rv770_resume(struct radeon_device *rdev)
|
|||
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = r600_audio_init(rdev);
|
||||
if (r) {
|
||||
dev_err(rdev->dev, "radeon: audio init failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
@ -1021,6 +1028,7 @@ int rv770_suspend(struct radeon_device *rdev)
|
|||
{
|
||||
int r;
|
||||
|
||||
r600_audio_fini(rdev);
|
||||
/* FIXME: we should wait for ring to be empty */
|
||||
r700_cp_stop(rdev);
|
||||
rdev->cp.ready = false;
|
||||
|
@ -1144,6 +1152,13 @@ int rv770_init(struct radeon_device *rdev)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = r600_audio_init(rdev);
|
||||
if (r) {
|
||||
dev_err(rdev->dev, "radeon: audio init failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -410,6 +410,7 @@
|
|||
{0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define r128_PCI_IDS \
|
||||
|
|
Loading…
Reference in a new issue