diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index e3b4456..5c3531e 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -58,7 +58,8 @@ typedef struct { } atom_exec_context; int atom_debug = 0; -static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); +static void atom_execute_table_prepared(struct atom_context *ctx, int index, uint32_t * params); +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 uint32_t atom_arg_mask[8] = @@ -606,7 +607,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 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); + atom_execute_table_prepared(ctx->ctx, idx, ctx->ps + ctx->ps_shift); } static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) @@ -1105,7 +1106,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 void atom_execute_table_prepared(struct atom_context *ctx, int index, uint32_t * params) { int base = CU16(ctx->cmd_table + 4 + 2 * index); int len, ws, ps, ptr; @@ -1155,15 +1156,21 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 kfree(ectx.ws); } -void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +void atom_execute_table_locked(struct atom_context *ctx, int index, + uint32_t *params) { - mutex_lock(&ctx->mutex); /* reset reg block */ ctx->reg_block = 0; /* reset fb window */ ctx->fb_base = 0; /* reset io mode */ ctx->io_mode = ATOM_IO_MM; + atom_execute_table_prepared(ctx, index, params); +} + +void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +{ + mutex_lock(&ctx->mutex); atom_execute_table_locked(ctx, index, params); mutex_unlock(&ctx->mutex); } diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index bc73781..a727113 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -140,6 +140,7 @@ struct atom_context { extern int atom_debug; struct atom_context *atom_parse(struct card_info *, void *); +void atom_execute_table_locked(struct atom_context *, int, uint32_t *); void atom_execute_table(struct atom_context *, int, uint32_t *); int atom_asic_init(struct atom_context *); void atom_destroy(struct atom_context *); diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 8e28842..60fcbf3 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -412,6 +412,25 @@ typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER { } DYNAMICE_ENGINE_SETTINGS_PARAMETER; /****************************************************************************/ +/* Structures used by MemoryRefreshConversionTable */ +/****************************************************************************/ +typedef struct _MEMORY_REFRESH_CONVERSION_PS_ALLOCATION { + ULONG ulTargetEngineClock; /* In 10Khz unit */ +} MEMORY_REFRESH_CONVERSION_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by DynamicMemorySettingsTable */ +/****************************************************************************/ +typedef struct _DYNAMIC_MEMORY_SETTINGS_PARAMETERS { + ULONG ulTargetEngineClock; /* In 10Khz unit */ +} DYNAMIC_MEMORY_SETTINGS_PARAMETERS; + +typedef struct _DYNAMIC_MEMORY_SETTINGS_PS_ALLOCATION { + ULONG ulTargetEngineClock; /* In 10Khz unit */ + ULONG ulTargetMemoryClock; /* In 10Khz unit */ +} DYNAMIC_MEMORY_SETTINGS_PS_ALLOCATION; + +/****************************************************************************/ /* Structures used by SetEngineClockTable */ /****************************************************************************/ typedef struct _SET_ENGINE_CLOCK_PARAMETERS { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 76d0cdb..875c1d3 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2858,6 +2858,109 @@ restart_ih: return IRQ_HANDLED; } +static void r600_engine_sync(struct radeon_device *rdev) +{ + u8 i; + udelay(2); + for (i = 0; i < 100; i++) { + if ((RREG32(0x600) >> 24) & 0x20) { + i = 0; + break; + } + udelay(1); + } + if (i) + DRM_ERROR("timeout when modifying engine\n"); +} + +void r600_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock) +{ + int index; + u8 reserved, fb_div, post_div; + u8 save; + u32 tmp; + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS args_compute_pll; + MEMORY_REFRESH_CONVERSION_PS_ALLOCATION args_mem_refresh; + DYNAMIC_MEMORY_SETTINGS_PS_ALLOCATION args_mem_settings; + + mutex_lock(&rdev->mode_info.atom_context->mutex); + + args_compute_pll.ulClock = eng_clock; + args_compute_pll.ucAction = COMPUTE_ENGINE_PLL_PARAM; + index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL); + atom_execute_table_locked(rdev->mode_info.atom_context, index, + (uint32_t *)&args_compute_pll); + reserved = args_compute_pll.ucReserved; + fb_div = args_compute_pll.ucFbDiv; + post_div = args_compute_pll.ucPostDiv; + + WREG32_P(0x608, 0x02, ~0x000000FF); + if ((eng_clock >> 24) & 0x01) + WREG32_P(0x608, 0x10, ~0x000000FF); + + tmp = RREG32(0x600); + WREG32(0x600, tmp | (0x02 << 24)); + r600_engine_sync(rdev); + + WREG32_P(0x600, 0, 0xFEFFFFFF); + r600_engine_sync(rdev); + + tmp = RREG32(0x60C); + WREG32(0x60C, tmp | 0x01); + + save = RREG32(0x600) & 0xFF; + + tmp = RREG32(0x600); + WREG32(0x600, tmp | 0x01); + + tmp = RREG32(0x600); + tmp &= 0xFF00E01F; + tmp |= (reserved << 5); + tmp &= 0xFF00FFFF; + tmp |= (post_div << 16); + WREG32_P(0x7D4, fb_div, ~0xFF); + WREG32(0x600, tmp); + udelay(5); + + WREG32_P(0x600, 0, 0xFFFFFFFE); + udelay(0x32); + + if (save & 0x01) { + DRM_INFO("[DBG] oh no :(\n"); + tmp = RREG32(0x600); + WREG32(0x600, tmp | 0x01); + udelay(0xC8); + + WREG32_P(0x600, 0, 0xFFFFFFFE); + udelay(0xC8); + } + + WREG32_P(0x60C, 0, 0xFFFFFFFE); + if (reserved & 0x01) { + tmp = RREG32(0x600); + WREG32(0x600, tmp | (0x01 << 24)); + udelay(2); + } else { + WREG32_P(0x600, 0, 0xFEFFFFFF); + } + r600_engine_sync(rdev); + + WREG32_P(0x600, 0, 0xFDFFFFFF); + r600_engine_sync(rdev); + + index = GetIndexIntoMasterTable(COMMAND, MemoryRefreshConversion); + atom_execute_table_locked(rdev->mode_info.atom_context, index, + (uint32_t *)&args_mem_refresh); + + args_mem_settings.ulTargetEngineClock = (eng_clock & 0x00FFFFFF); + args_mem_settings.ulTargetEngineClock |= (0x02 << 24); + index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); + atom_execute_table_locked(rdev->mode_info.atom_context, index, + (uint32_t *)&args_mem_settings); + + mutex_unlock(&rdev->mode_info.atom_context->mutex); +} + /* * Debugfs info */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index e7b3cac..15bcd51 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -513,6 +513,7 @@ void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +void r600_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock); static struct radeon_asic r600_asic = { .init = &r600_init, @@ -535,7 +536,7 @@ static struct radeon_asic r600_asic = { .copy_dma = &r600_copy_blit, .copy = &r600_copy_blit, .get_engine_clock = &radeon_atom_get_engine_clock, - .set_engine_clock = &radeon_atom_set_engine_clock, + .set_engine_clock = &r600_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, .get_pcie_lanes = NULL,