Commit 1fc59eda authored by Dave Airlie's avatar Dave Airlie

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
parents d5e5dedd d0d6cb81
...@@ -52,15 +52,17 @@ ...@@ -52,15 +52,17 @@
typedef struct { typedef struct {
struct atom_context *ctx; struct atom_context *ctx;
uint32_t *ps, *ws; uint32_t *ps, *ws;
int ps_shift; int ps_shift;
uint16_t start; uint16_t start;
unsigned last_jump;
unsigned long last_jump_jiffies;
bool abort;
} atom_exec_context; } atom_exec_context;
int atom_debug = 0; int atom_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);
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);
static uint32_t atom_arg_mask[8] = static uint32_t atom_arg_mask[8] =
{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
...@@ -604,12 +606,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) ...@@ -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) static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
{ {
int idx = U8((*ptr)++); int idx = U8((*ptr)++);
int r = 0;
if (idx < ATOM_TABLE_NAMES_CNT) if (idx < ATOM_TABLE_NAMES_CNT)
SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
else else
SDEBUG(" table: %d\n", idx); SDEBUG(" table: %d\n", idx);
if (U16(ctx->ctx->cmd_table + 4 + 2 * 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) 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) ...@@ -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) static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
{ {
int execute = 0, target = U16(*ptr); int execute = 0, target = U16(*ptr);
unsigned long cjiffies;
(*ptr) += 2; (*ptr) += 2;
switch (arg) { switch (arg) {
case ATOM_COND_ABOVE: case ATOM_COND_ABOVE:
...@@ -700,8 +709,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) ...@@ -700,8 +709,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
if (arg != ATOM_COND_ALWAYS) if (arg != ATOM_COND_ALWAYS)
SDEBUG(" taken: %s\n", execute ? "yes" : "no"); SDEBUG(" taken: %s\n", execute ? "yes" : "no");
SDEBUG(" target: 0x%04X\n", target); 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; *ptr = ctx->start + target;
}
} }
static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
...@@ -1104,7 +1130,7 @@ static struct { ...@@ -1104,7 +1130,7 @@ static struct {
atom_op_shr, ATOM_ARG_MC}, { atom_op_shr, ATOM_ARG_MC}, {
atom_op_debug, 0},}; 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 base = CU16(ctx->cmd_table + 4 + 2 * index);
int len, ws, ps, ptr; int len, ws, ps, ptr;
...@@ -1112,7 +1138,7 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 ...@@ -1112,7 +1138,7 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
atom_exec_context ectx; atom_exec_context ectx;
if (!base) if (!base)
return; return -EINVAL;
len = CU16(base + ATOM_CT_SIZE_PTR); len = CU16(base + ATOM_CT_SIZE_PTR);
ws = CU8(base + ATOM_CT_WS_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 ...@@ -1125,6 +1151,8 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
ectx.ps_shift = ps / 4; ectx.ps_shift = ps / 4;
ectx.start = base; ectx.start = base;
ectx.ps = params; ectx.ps = params;
ectx.abort = false;
ectx.last_jump = 0;
if (ws) if (ws)
ectx.ws = kzalloc(4 * ws, GFP_KERNEL); ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
else else
...@@ -1137,6 +1165,11 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 ...@@ -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); SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
else else
SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); 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) if (op < ATOM_OP_CNT && op > 0)
opcode_table[op].func(&ectx, &ptr, opcode_table[op].func(&ectx, &ptr,
...@@ -1152,10 +1185,13 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 ...@@ -1152,10 +1185,13 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
if (ws) if (ws)
kfree(ectx.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); mutex_lock(&ctx->mutex);
/* reset reg block */ /* reset reg block */
ctx->reg_block = 0; ctx->reg_block = 0;
...@@ -1163,8 +1199,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) ...@@ -1163,8 +1199,9 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
ctx->fb_base = 0; ctx->fb_base = 0;
/* reset io mode */ /* reset io mode */
ctx->io_mode = ATOM_IO_MM; 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); mutex_unlock(&ctx->mutex);
return r;
} }
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 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) ...@@ -1248,9 +1285,7 @@ int atom_asic_init(struct atom_context *ctx)
if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
return 1; return 1;
atom_execute_table(ctx, ATOM_CMD_INIT, ps); return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
return 0;
} }
void atom_destroy(struct atom_context *ctx) void atom_destroy(struct atom_context *ctx)
......
...@@ -140,7 +140,7 @@ struct atom_context { ...@@ -140,7 +140,7 @@ struct atom_context {
extern int atom_debug; extern int atom_debug;
struct atom_context *atom_parse(struct card_info *, void *); 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 *); int atom_asic_init(struct atom_context *);
void atom_destroy(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); 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, ...@@ -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); 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 { union atom_enable_ss {
ENABLE_LVDS_SS_PARAMETERS legacy; ENABLE_LVDS_SS_PARAMETERS legacy;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 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 radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
...@@ -387,9 +430,9 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) ...@@ -387,9 +430,9 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
step = dig->ss->step; step = dig->ss->step;
delay = dig->ss->delay; delay = dig->ss->delay;
range = dig->ss->range; range = dig->ss->range;
} else if (enable) } else
return; return;
} else if (enable) } else
return; return;
break; break;
} }
...@@ -406,13 +449,13 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) ...@@ -406,13 +449,13 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
args.v1.ucSpreadSpectrumDelay = delay; args.v1.ucSpreadSpectrumDelay = delay;
args.v1.ucSpreadSpectrumRange = range; args.v1.ucSpreadSpectrumRange = range;
args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
args.v1.ucEnable = enable; args.v1.ucEnable = ATOM_ENABLE;
} else { } else {
args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage); args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
args.legacy.ucSpreadSpectrumType = type; args.legacy.ucSpreadSpectrumType = type;
args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; 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); 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, ...@@ -482,6 +525,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
pll->algo = dig->pll_algo; pll->algo = dig->pll_algo;
pll->flags |= RADEON_PLL_IS_LCD;
} }
} else { } else {
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
...@@ -1083,15 +1127,12 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, ...@@ -1083,15 +1127,12 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
/* TODO color tiling */ /* TODO color tiling */
/* pick pll */ atombios_disable_ss(crtc);
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
atombios_set_ss(crtc, 0);
/* always set DCPLL */ /* always set DCPLL */
if (ASIC_IS_DCE4(rdev)) if (ASIC_IS_DCE4(rdev))
atombios_crtc_set_dcpll(crtc); atombios_crtc_set_dcpll(crtc);
atombios_crtc_set_pll(crtc, adjusted_mode); atombios_crtc_set_pll(crtc, adjusted_mode);
atombios_set_ss(crtc, 1); atombios_enable_ss(crtc);
if (ASIC_IS_DCE4(rdev)) if (ASIC_IS_DCE4(rdev))
atombios_set_crtc_dtd_timing(crtc, adjusted_mode); atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
...@@ -1120,6 +1161,11 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, ...@@ -1120,6 +1161,11 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
static void atombios_crtc_prepare(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_lock_crtc(crtc, ATOM_ENABLE);
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
} }
......
...@@ -312,10 +312,12 @@ int r100_irq_process(struct radeon_device *rdev) ...@@ -312,10 +312,12 @@ int r100_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */ /* Vertical blank interrupts */
if (status & RADEON_CRTC_VBLANK_STAT) { if (status & RADEON_CRTC_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 0); drm_handle_vblank(rdev->ddev, 0);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
} }
if (status & RADEON_CRTC2_VBLANK_STAT) { if (status & RADEON_CRTC2_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 1); drm_handle_vblank(rdev->ddev, 1);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
} }
if (status & RADEON_FP_DETECT_STAT) { if (status & RADEON_FP_DETECT_STAT) {
......
...@@ -2765,6 +2765,7 @@ int r600_irq_process(struct radeon_device *rdev) ...@@ -2765,6 +2765,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D1 vblank */ case 0: /* D1 vblank */
if (disp_int & LB_D1_VBLANK_INTERRUPT) { if (disp_int & LB_D1_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 0); drm_handle_vblank(rdev->ddev, 0);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D1_VBLANK_INTERRUPT; disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n"); DRM_DEBUG("IH: D1 vblank\n");
...@@ -2786,6 +2787,7 @@ int r600_irq_process(struct radeon_device *rdev) ...@@ -2786,6 +2787,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D2 vblank */ case 0: /* D2 vblank */
if (disp_int & LB_D2_VBLANK_INTERRUPT) { if (disp_int & LB_D2_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 1); drm_handle_vblank(rdev->ddev, 1);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D2_VBLANK_INTERRUPT; disp_int &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n"); DRM_DEBUG("IH: D2 vblank\n");
......
...@@ -181,41 +181,6 @@ int r600_audio_init(struct radeon_device *rdev) ...@@ -181,41 +181,6 @@ int r600_audio_init(struct radeon_device *rdev)
return 0; 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 * 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) ...@@ -224,6 +189,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
int base_rate = 48000; int base_rate = 48000;
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
...@@ -231,32 +197,34 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) ...@@ -231,32 +197,34 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
case ENCODER_OBJECT_ID_INTERNAL_LVTM1: case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(R600_AUDIO_TIMING, 0, ~0x301); WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301); WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
break; break;
default: default:
DRM_ERROR("Unsupported encoder type 0x%02X\n", DRM_ERROR("Unsupported encoder type 0x%02X\n",
radeon_encoder->encoder_id); radeon_encoder->encoder_id);
return; return;
} }
switch (r600_audio_tmds_index(encoder)) { switch (dig->dig_encoder) {
case 0: case 0:
WREG32(R600_AUDIO_PLL1_MUL, base_rate*50); WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
WREG32(R600_AUDIO_PLL1_DIV, clock*100); WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
WREG32(R600_AUDIO_CLK_SRCSEL, 0); WREG32(R600_AUDIO_CLK_SRCSEL, 0);
break; break;
case 1: case 1:
WREG32(R600_AUDIO_PLL2_MUL, base_rate*50); WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
WREG32(R600_AUDIO_PLL2_DIV, clock*100); WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
WREG32(R600_AUDIO_CLK_SRCSEL, 1); WREG32(R600_AUDIO_CLK_SRCSEL, 1);
break; break;
default:
dev_err(rdev->dev, "Unsupported DIG on encoder 0x%02X\n",
radeon_encoder->encoder_id);
return;
} }
} }
......
/*
* 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/types.h>
#include <linux/kernel.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[] = const u32 r6xx_default_state[] =
{ {
0xc0002400, 0xc0002400,
......
...@@ -85,7 +85,7 @@ struct { ...@@ -85,7 +85,7 @@ struct {
static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq) static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
{ {
if (*CTS == 0) 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", DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
N, *CTS, freq); N, *CTS, freq);
} }
...@@ -417,90 +417,141 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, ...@@ -417,90 +417,141 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000);
} }
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);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig) {
dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n");
return;
}
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);
}
}
/* /*
* enable/disable the HDMI engine * enable the HDMI engine
*/ */
void r600_hdmi_enable(struct drm_encoder *encoder, int enable) void r600_hdmi_enable(struct drm_encoder *encoder)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
if (!offset) 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; return;
}
}
DRM_DEBUG("%s HDMI interface @ 0x%04X\n", enable ? "Enabling" : "Disabling", offset); if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
/* some version of atombios ignore the enable HDMI flag } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
* so enabling/disabling HDMI was moved here for TMDS1+2 */ int offset = radeon_encoder->hdmi_offset;
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, enable ? 0x4 : 0x0, ~0x4); WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4);
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x101 : 0x0); WREG32(offset + R600_HDMI_ENABLE, 0x101);
break; break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1: case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, enable ? 0x4 : 0x0, ~0x4); WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4);
WREG32(offset+R600_HDMI_ENABLE, enable ? 0x105 : 0x0); WREG32(offset + R600_HDMI_ENABLE, 0x105);
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; break;
default: default:
DRM_ERROR("unknown HDMI output type\n"); dev_err(rdev->dev, "Unknown HDMI output type\n");
break; break;
} }
}
DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
} }
/* /*
* determin at which register offset the HDMI encoder is * disable the HDMI engine
*/ */
void r600_hdmi_init(struct drm_encoder *encoder) 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); 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) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4);
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: WREG32(offset + R600_HDMI_ENABLE, 0);
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1: case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
switch (r600_audio_tmds_index(encoder)) { WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4);
case 0: WREG32(offset + R600_HDMI_ENABLE, 0);
radeon_encoder->hdmi_offset = R600_HDMI_TMDS1;
break;
case 1:
radeon_encoder->hdmi_offset = R600_HDMI_TMDS2;
break; break;
default: default:
radeon_encoder->hdmi_offset = 0; dev_err(rdev->dev, "Unknown HDMI output type\n");
break; break;
} }
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 = 0;
radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); radeon_encoder->hdmi_config_offset = 0;
/* TODO: make this configureable */
radeon_encoder->hdmi_audio_workaround = 0;
} }
...@@ -152,9 +152,9 @@ ...@@ -152,9 +152,9 @@
#define R600_AUDIO_STATUS_BITS 0x73d8 #define R600_AUDIO_STATUS_BITS 0x73d8
/* HDMI base register addresses */ /* HDMI base register addresses */
#define R600_HDMI_TMDS1 0x7400 #define R600_HDMI_BLOCK1 0x7400
#define R600_HDMI_TMDS2 0x7700 #define R600_HDMI_BLOCK2 0x7700
#define R600_HDMI_DIG 0x7800 #define R600_HDMI_BLOCK3 0x7800
/* HDMI registers */ /* HDMI registers */
#define R600_HDMI_ENABLE 0x00 #define R600_HDMI_ENABLE 0x00
...@@ -185,4 +185,8 @@ ...@@ -185,4 +185,8 @@
#define R600_HDMI_AUDIO_DEBUG_2 0xe8 #define R600_HDMI_AUDIO_DEBUG_2 0xe8
#define R600_HDMI_AUDIO_DEBUG_3 0xec #define R600_HDMI_AUDIO_DEBUG_3 0xec
/* HDMI additional config base register addresses */
#define R600_HDMI_CONFIG1 0x7600
#define R600_HDMI_CONFIG2 0x7a00
#endif #endif
...@@ -687,6 +687,7 @@ struct radeon_pm { ...@@ -687,6 +687,7 @@ struct radeon_pm {
bool downclocked; bool downclocked;
int active_crtcs; int active_crtcs;
int req_vblank; int req_vblank;
bool vblank_sync;
fixed20_12 max_bandwidth; fixed20_12 max_bandwidth;
fixed20_12 igp_sideport_mclk; fixed20_12 igp_sideport_mclk;
fixed20_12 igp_system_mclk; fixed20_12 igp_system_mclk;
...@@ -1322,7 +1323,8 @@ extern int r600_audio_tmds_index(struct drm_encoder *encoder); ...@@ -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_set_clock(struct drm_encoder *encoder, int clock);
extern void r600_audio_fini(struct radeon_device *rdev); extern void r600_audio_fini(struct radeon_device *rdev);
extern void r600_hdmi_init(struct drm_encoder *encoder); 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 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 int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
extern void r600_hdmi_update_audio_settings(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) ...@@ -887,6 +887,20 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
p1pll->pll_out_max = p1pll->pll_out_max =
le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); 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 (p1pll->pll_out_min == 0) {
if (ASIC_IS_AVIVO(rdev)) if (ASIC_IS_AVIVO(rdev))
p1pll->pll_out_min = 64800; p1pll->pll_out_min = 64800;
......
...@@ -531,10 +531,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde ...@@ -531,10 +531,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
case CHIP_RS300: case CHIP_RS300:
switch (ddc_line) { switch (ddc_line) {
case RADEON_GPIO_DVI_DDC: case RADEON_GPIO_DVI_DDC:
/* in theory this should be hw capable, i2c.hw_capable = true;
* but it doesn't seem to work
*/
i2c.hw_capable = false;
break; break;
default: default:
i2c.hw_capable = false; i2c.hw_capable = false;
...@@ -633,6 +630,8 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) ...@@ -633,6 +630,8 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
p1pll->reference_div = RBIOS16(pll_info + 0x10); p1pll->reference_div = RBIOS16(pll_info + 0x10);
p1pll->pll_out_min = RBIOS32(pll_info + 0x12); p1pll->pll_out_min = RBIOS32(pll_info + 0x12);
p1pll->pll_out_max = RBIOS32(pll_info + 0x16); 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) { if (rev > 9) {
p1pll->pll_in_min = RBIOS32(pll_info + 0x36); p1pll->pll_in_min = RBIOS32(pll_info + 0x36);
......
...@@ -469,10 +469,19 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, ...@@ -469,10 +469,19 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
uint32_t best_error = 0xffffffff; uint32_t best_error = 0xffffffff;
uint32_t best_vco_diff = 1; uint32_t best_vco_diff = 1;
uint32_t post_div; 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); DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
freq = freq * 1000; 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) if (pll->flags & RADEON_PLL_USE_REF_DIV)
min_ref_div = max_ref_div = pll->reference_div; min_ref_div = max_ref_div = pll->reference_div;
else { else {
...@@ -536,10 +545,10 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, ...@@ -536,10 +545,10 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
tmp = (uint64_t)pll->reference_freq * feedback_div; tmp = (uint64_t)pll->reference_freq * feedback_div;
vco = radeon_div(tmp, ref_div); vco = radeon_div(tmp, ref_div);
if (vco < pll->pll_out_min) { if (vco < pll_out_min) {
min_feed_div = feedback_div + 1; min_feed_div = feedback_div + 1;
continue; continue;
} else if (vco > pll->pll_out_max) { } else if (vco > pll_out_max) {
max_feed_div = feedback_div; max_feed_div = feedback_div;
continue; continue;
} }
...@@ -675,6 +684,15 @@ calc_fb_ref_div(struct radeon_pll *pll, ...@@ -675,6 +684,15 @@ calc_fb_ref_div(struct radeon_pll *pll,
{ {
fixed20_12 ffreq, max_error, error, pll_out, a; fixed20_12 ffreq, max_error, error, pll_out, a;
u32 vco; 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); ffreq.full = rfixed_const(freq);
/* max_error = ffreq * 0.0025; */ /* max_error = ffreq * 0.0025; */
...@@ -686,7 +704,7 @@ calc_fb_ref_div(struct radeon_pll *pll, ...@@ -686,7 +704,7 @@ calc_fb_ref_div(struct radeon_pll *pll,
vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac)); vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
vco = vco / ((*ref_div) * 10); 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; continue;
/* pll_out = vco / post_div; */ /* pll_out = vco / post_div; */
...@@ -714,6 +732,15 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, ...@@ -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 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
u32 best_freq = 0, vco_frequency; 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; */ /* freq = freq / 10; */
do_div(freq, 10); do_div(freq, 10);
...@@ -724,7 +751,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, ...@@ -724,7 +751,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
goto done; goto done;
vco_frequency = freq * post_div; 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; goto done;
if (pll->flags & RADEON_PLL_USE_REF_DIV) { if (pll->flags & RADEON_PLL_USE_REF_DIV) {
...@@ -749,7 +776,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll, ...@@ -749,7 +776,7 @@ static void radeon_compute_pll_new(struct radeon_pll *pll,
continue; continue;
vco_frequency = freq * post_div; 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; continue;
if (pll->flags & RADEON_PLL_USE_REF_DIV) { if (pll->flags & RADEON_PLL_USE_REF_DIV) {
ref_div = pll->reference_div; ref_div = pll->reference_div;
......
...@@ -593,7 +593,6 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) ...@@ -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); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
r600_hdmi_enable(encoder, hdmi_detected);
} }
int int
...@@ -1216,6 +1215,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) ...@@ -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); 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 static void
...@@ -1326,19 +1328,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -1326,19 +1328,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 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_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 (ASIC_IS_AVIVO(rdev)) {
if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
atombios_yuv_setup(encoder, true); atombios_yuv_setup(encoder, true);
...@@ -1396,9 +1388,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -1396,9 +1388,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
} }
atombios_apply_encoder_quirks(encoder, adjusted_mode); atombios_apply_encoder_quirks(encoder, adjusted_mode);
/* XXX */ if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
if (!ASIC_IS_DCE4(rdev)) r600_hdmi_enable(encoder);
r600_hdmi_setmode(encoder, adjusted_mode); r600_hdmi_setmode(encoder, adjusted_mode);
}
} }
static bool static bool
...@@ -1492,8 +1485,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec ...@@ -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) 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_output_lock(encoder, true);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 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) static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
...@@ -1509,6 +1514,8 @@ static void radeon_atom_encoder_disable(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); radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
if (radeon_encoder_is_digital(encoder)) { 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 = radeon_encoder->enc_priv;
dig->dig_encoder = -1; dig->dig_encoder = -1;
} }
...@@ -1659,6 +1666,4 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su ...@@ -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); drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break; break;
} }
r600_hdmi_init(encoder);
} }
...@@ -183,11 +183,10 @@ static void set_data(void *i2c_priv, int data) ...@@ -183,11 +183,10 @@ static void set_data(void *i2c_priv, int data)
static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) 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 sclk = radeon_get_engine_clock(rdev);
u32 prescale = 0; u32 prescale = 0;
u32 n, m; u32 nm;
u8 loop; u8 n, m, loop;
int i2c_clock; int i2c_clock;
switch (rdev->family) { switch (rdev->family) {
...@@ -203,13 +202,15 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) ...@@ -203,13 +202,15 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
case CHIP_R300: case CHIP_R300:
case CHIP_R350: case CHIP_R350:
case CHIP_RV350: case CHIP_RV350:
n = (spll->reference_freq) / (4 * 6); i2c_clock = 60;
nm = (sclk * 10) / (i2c_clock * 4);
for (loop = 1; loop < 255; loop++) { for (loop = 1; loop < 255; loop++) {
if ((loop * (loop - 1)) > n) if ((nm / loop) < loop)
break; break;
} }
m = loop - 1; n = loop - 1;
prescale = m | (loop << 8); m = loop - 2;
prescale = m | (n << 8);
break; break;
case CHIP_RV380: case CHIP_RV380:
case CHIP_RS400: case CHIP_RS400:
...@@ -217,7 +218,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) ...@@ -217,7 +218,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
case CHIP_R420: case CHIP_R420:
case CHIP_R423: case CHIP_R423:
case CHIP_RV410: case CHIP_RV410:
sclk = radeon_get_engine_clock(rdev);
prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
break; break;
case CHIP_RS600: case CHIP_RS600:
...@@ -232,7 +232,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) ...@@ -232,7 +232,6 @@ static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
case CHIP_RV570: case CHIP_RV570:
case CHIP_R580: case CHIP_R580:
i2c_clock = 50; i2c_clock = 50;
sclk = radeon_get_engine_clock(rdev);
if (rdev->family == CHIP_R520) if (rdev->family == CHIP_R520)
prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock)); prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
else else
...@@ -291,6 +290,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -291,6 +290,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
prescale = radeon_get_i2c_prescale(rdev); prescale = radeon_get_i2c_prescale(rdev);
reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) | reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
RADEON_I2C_DRIVE_EN |
RADEON_I2C_START | RADEON_I2C_START |
RADEON_I2C_STOP | RADEON_I2C_STOP |
RADEON_I2C_GO); RADEON_I2C_GO);
......
...@@ -603,6 +603,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ...@@ -603,6 +603,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
? RADEON_CRTC2_INTERLACE_EN ? RADEON_CRTC2_INTERLACE_EN
: 0)); : 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 = RREG32(RADEON_DISP2_MERGE_CNTL);
disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 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 ...@@ -630,6 +634,10 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
? RADEON_CRTC_INTERLACE_EN ? RADEON_CRTC_INTERLACE_EN
: 0)); : 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 = RREG32(RADEON_CRTC_EXT_CNTL);
crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_VSYNC_DIS |
......
...@@ -57,6 +57,10 @@ ...@@ -57,6 +57,10 @@
#define NTSC_TV_PLL_N_14 693 #define NTSC_TV_PLL_N_14 693
#define NTSC_TV_PLL_P_14 7 #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 VERT_LEAD_IN_LINES 2
#define FRAC_BITS 0xe #define FRAC_BITS 0xe
#define FRAC_MASK 0x3fff #define FRAC_MASK 0x3fff
...@@ -208,6 +212,21 @@ static const struct radeon_tv_mode_constants available_tv_modes[] = { ...@@ -208,6 +212,21 @@ static const struct radeon_tv_mode_constants available_tv_modes[] = {
8, /* crtcPLL_postDiv */ 8, /* crtcPLL_postDiv */
1022, /* pixToTV */ 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) #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 ...@@ -242,7 +261,7 @@ static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(stru
if (pll->reference_freq == 2700) if (pll->reference_freq == 2700)
const_ptr = &available_tv_modes[1]; const_ptr = &available_tv_modes[1];
else else
const_ptr = &available_tv_modes[1]; /* FIX ME */ const_ptr = &available_tv_modes[3];
} }
return const_ptr; return const_ptr;
} }
...@@ -685,9 +704,9 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, ...@@ -685,9 +704,9 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
n = PAL_TV_PLL_N_27; n = PAL_TV_PLL_N_27;
p = PAL_TV_PLL_P_27; p = PAL_TV_PLL_P_27;
} else { } else {
m = PAL_TV_PLL_M_27; m = PAL_TV_PLL_M_14;
n = PAL_TV_PLL_N_27; n = PAL_TV_PLL_N_14;
p = PAL_TV_PLL_P_27; p = PAL_TV_PLL_P_14;
} }
} }
......
...@@ -129,6 +129,7 @@ struct radeon_tmds_pll { ...@@ -129,6 +129,7 @@ struct radeon_tmds_pll {
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10) #define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
#define RADEON_PLL_USE_POST_DIV (1 << 12) #define RADEON_PLL_USE_POST_DIV (1 << 12)
#define RADEON_PLL_IS_LCD (1 << 13)
/* pll algo */ /* pll algo */
enum radeon_pll_algo { enum radeon_pll_algo {
...@@ -149,6 +150,8 @@ struct radeon_pll { ...@@ -149,6 +150,8 @@ struct radeon_pll {
uint32_t pll_in_max; uint32_t pll_in_max;
uint32_t pll_out_min; uint32_t pll_out_min;
uint32_t pll_out_max; uint32_t pll_out_max;
uint32_t lcd_pll_out_min;
uint32_t lcd_pll_out_max;
uint32_t best_vco; uint32_t best_vco;
/* divider limits */ /* divider limits */
...@@ -342,6 +345,7 @@ struct radeon_encoder { ...@@ -342,6 +345,7 @@ struct radeon_encoder {
struct drm_display_mode native_mode; struct drm_display_mode native_mode;
void *enc_priv; void *enc_priv;
int hdmi_offset; int hdmi_offset;
int hdmi_config_offset;
int hdmi_audio_workaround; int hdmi_audio_workaround;
int hdmi_buffer_status; int hdmi_buffer_status;
}; };
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_RECLOCK_DELAY_MS 200
#define RADEON_WAIT_VBLANK_TIMEOUT 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_locked(struct radeon_device *rdev);
static void radeon_pm_set_clocks(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); 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, ...@@ -179,6 +180,16 @@ static void radeon_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_power_state->non_clock_info.pcie_lanes); 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) static void radeon_set_power_state(struct radeon_device *rdev)
{ {
/* if *_clock_mode are the same, *_power_state are as well */ /* 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) ...@@ -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->sclk,
rdev->pm.requested_clock_mode->mclk, rdev->pm.requested_clock_mode->mclk,
rdev->pm.requested_power_state->non_clock_info.pcie_lanes); rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
/* set pcie lanes */ /* set pcie lanes */
/* TODO */
/* set voltage */ /* set voltage */
/* TODO */
/* set engine clock */ /* 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_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
#if 0
/* set memory clock */ /* 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_power_state = rdev->pm.requested_power_state;
rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; 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) ...@@ -333,10 +361,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
break; break;
} }
/* check if we are in vblank */
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_power_state(rdev); radeon_set_power_state(rdev);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.planned_action = PM_ACTION_NONE; rdev->pm.planned_action = PM_ACTION_NONE;
} }
...@@ -353,10 +378,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) ...@@ -353,10 +378,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
rdev->pm.req_vblank |= (1 << 1); rdev->pm.req_vblank |= (1 << 1);
drm_vblank_get(rdev->ddev, 1); drm_vblank_get(rdev->ddev, 1);
} }
if (rdev->pm.active_crtcs) radeon_pm_set_clocks_locked(rdev);
wait_event_interruptible_timeout(
rdev->irq.vblank_queue, 0,
msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
if (rdev->pm.req_vblank & (1 << 0)) { if (rdev->pm.req_vblank & (1 << 0)) {
rdev->pm.req_vblank &= ~(1 << 0); rdev->pm.req_vblank &= ~(1 << 0);
drm_vblank_put(rdev->ddev, 0); drm_vblank_put(rdev->ddev, 0);
...@@ -366,7 +388,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) ...@@ -366,7 +388,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
drm_vblank_put(rdev->ddev, 1); drm_vblank_put(rdev->ddev, 1);
} }
radeon_pm_set_clocks_locked(rdev);
mutex_unlock(&rdev->cp.mutex); mutex_unlock(&rdev->cp.mutex);
} }
......
...@@ -392,10 +392,12 @@ int rs600_irq_process(struct radeon_device *rdev) ...@@ -392,10 +392,12 @@ int rs600_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */ /* Vertical blank interrupts */
if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 0); drm_handle_vblank(rdev->ddev, 0);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
} }
if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) { if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 1); drm_handle_vblank(rdev->ddev, 1);
rdev->pm.vblank_sync = true;
wake_up(&rdev->irq.vblank_queue); wake_up(&rdev->irq.vblank_queue);
} }
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
......
...@@ -1013,6 +1013,13 @@ int rv770_resume(struct radeon_device *rdev) ...@@ -1013,6 +1013,13 @@ int rv770_resume(struct radeon_device *rdev)
DRM_ERROR("radeon: failled testing IB (%d).\n", r); DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r; return r;
} }
r = r600_audio_init(rdev);
if (r) {
dev_err(rdev->dev, "radeon: audio init failed\n");
return r;
}
return r; return r;
} }
...@@ -1021,6 +1028,7 @@ int rv770_suspend(struct radeon_device *rdev) ...@@ -1021,6 +1028,7 @@ int rv770_suspend(struct radeon_device *rdev)
{ {
int r; int r;
r600_audio_fini(rdev);
/* FIXME: we should wait for ring to be empty */ /* FIXME: we should wait for ring to be empty */
r700_cp_stop(rdev); r700_cp_stop(rdev);
rdev->cp.ready = false; rdev->cp.ready = false;
...@@ -1144,6 +1152,13 @@ int rv770_init(struct radeon_device *rdev) ...@@ -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; return 0;
} }
......
...@@ -410,6 +410,7 @@ ...@@ -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, 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, 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, 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} {0, 0, 0}
#define r128_PCI_IDS \ #define r128_PCI_IDS \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment